fix(server): limit allowed body size in server requests (#5561)

Rationale: avoid unbounded resource consumption.
This commit is contained in:
Julio López authored and GitHub committed 2026-08-17 17:03:23 -07:00
1 parent b6bd722484
commit b0138a6e40
2 files changed
+45 -2

No files matched your search

+32
View File
@@ -1,6 +1,8 @@
package server_test
import (
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/require"
@@ -36,3 +38,33 @@ func TestPathsAPI(t *testing.T) {
require.Equal(t, env.LocalPathSourceInfo(dir0), resp.SourceInfo)
}
func TestPathsAPI_RequestBodyTooLarge(t *testing.T) {
ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant)
srvInfo := servertesting.StartServer(t, env, false)
cli, err := apiclient.NewKopiaAPIClient(apiclient.Options{
BaseURL: srvInfo.BaseURL,
TrustedServerCertificateFingerprint: srvInfo.TrustedServerCertificateFingerprint,
Username: servertesting.TestUIUsername,
Password: servertesting.TestUIPassword,
})
require.NoError(t, err)
require.NoError(t, cli.FetchCSRFTokenForTesting(ctx))
// the request body limit is 100_000 bytes, so a path much longer than that
// must be rejected before it reaches the handler.
req := &serverapi.ResolvePathRequest{
Path: strings.Repeat("a", 105_000),
}
resp := &serverapi.ResolvePathResponse{}
err = cli.Post(ctx, "paths/resolve", req, resp)
require.Error(t, err)
var hsr apiclient.HTTPStatusError
require.ErrorAs(t, err, &hsr)
require.Equal(t, http.StatusRequestEntityTooLarge, hsr.HTTPStatusCode)
}
+13 -2
View File
@@ -358,13 +358,24 @@ func (s *Server) handleUIPossiblyNotConnected(f apiRequestFunc) http.HandlerFunc
}
func (s *Server) handleRequestPossiblyNotConnected(isAuthorized isAuthorizedFunc, checkCSRFToken csrfTokenOption, f apiRequestFunc) http.HandlerFunc {
const maxRequestBodySizeBytes = 100_000
return s.requireAuth(checkCSRFToken, func(ctx context.Context, rc requestContext) {
// we must pre-read request body before acquiring the lock as it sometimes leads to deadlock
// in HTTP/2 server.
// See https://github.com/golang/go/issues/40816
body, berr := io.ReadAll(rc.req.Body)
body, berr := io.ReadAll(http.MaxBytesReader(rc.w, rc.req.Body, maxRequestBodySizeBytes))
if berr != nil {
http.Error(rc.w, "error reading request body", http.StatusInternalServerError)
errCode := http.StatusInternalServerError
var mbe *http.MaxBytesError
if errors.As(berr, &mbe) {
errCode = http.StatusRequestEntityTooLarge
}
http.Error(rc.w, "error reading request body", errCode)
return
}