Say at the receiver route where its 1 MB body cap lives (closes #173) #429
@@ -150,7 +150,9 @@ func (h *Handlers) lookupEntrypoint(
|
||||
return entrypoint, true
|
||||
}
|
||||
|
||||
// readWebhookBody reads and validates the request body size.
|
||||
// readWebhookBody reads and validates the request body size. This is
|
||||
// the receiver's only body cap: /h/{uuid} has no MaxBodySize
|
||||
// middleware (see Server.setupWebhookRoutes).
|
||||
func (h *Handlers) readWebhookBody(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
|
||||
@@ -304,6 +304,12 @@ func (s *Server) setupSourceRoutes() {
|
||||
}
|
||||
|
||||
func (s *Server) setupWebhookRoutes() {
|
||||
// No MaxBodySize here, unlike the page groups. The receiver's 1 MB
|
||||
// body cap is in Handlers.readWebhookBody, because the handler
|
||||
// owns the response a sender gets for an oversized body and
|
||||
// MaxBodySize would change it. That cap is the only bound on this
|
||||
// unauthenticated endpoint's body; TestReceiver_OversizeBodyRefused
|
||||
// pins it.
|
||||
s.router.With(s.mw.ReceiverRateLimit()).HandleFunc(
|
||||
"/h/{uuid}",
|
||||
s.h.HandleWebhook(),
|
||||
|
||||
@@ -1422,6 +1422,53 @@ func TestReceiver_EntrypointURLIsRateLimited(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
// TestReceiver_OversizeBodyRefused pins the receiver's 1 MB body
|
||||
// cap, which lives in the handler rather than in a MaxBodySize
|
||||
// middleware. A body exactly at the cap is accepted; one byte over is
|
||||
// refused with the handler's own 413.
|
||||
func TestReceiver_OversizeBodyRefused(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const bodyCap = 1 << 20 // 1 MB
|
||||
|
||||
env := newTestEnvWithConfig(t, &config.Config{
|
||||
DataDir: t.TempDir(),
|
||||
Environment: config.EnvironmentDev,
|
||||
ReceiverRateLimit: 10,
|
||||
})
|
||||
|
||||
userID, _ := env.seedUser(t, "receiver", "somepassword")
|
||||
wh := env.seedWebhook(t, userID)
|
||||
require.NoError(t, env.db.DB().Omit(clause.Associations).Create(
|
||||
&database.Entrypoint{
|
||||
WebhookID: wh.ID,
|
||||
Path: "0b7c3e5a-2d9f-4a61-8e4b-7c1d6f2a9e35",
|
||||
Active: true,
|
||||
},
|
||||
).Error)
|
||||
|
||||
send := func(size int) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequestWithContext(
|
||||
context.Background(), http.MethodPost,
|
||||
"/h/0b7c3e5a-2d9f-4a61-8e4b-7c1d6f2a9e35",
|
||||
strings.NewReader(strings.Repeat("a", size)),
|
||||
)
|
||||
w := httptest.NewRecorder()
|
||||
env.router.ServeHTTP(w, req)
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
assert.Equal(
|
||||
t, http.StatusOK, send(bodyCap).Code,
|
||||
"a body exactly at the cap must be accepted",
|
||||
)
|
||||
|
||||
w := send(bodyCap + 1)
|
||||
assert.Equal(t, http.StatusRequestEntityTooLarge, w.Code)
|
||||
assert.Equal(t, "Request body too large\n", w.Body.String())
|
||||
}
|
||||
|
||||
// metricsConfig is a Config differing from the routing default only
|
||||
// in the two /metrics credentials.
|
||||
func metricsConfig(
|
||||
|
||||
Reference in New Issue
Block a user