@marcel91200 / caddy Mirror · read-only / commits / 3d616e8c
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 13, 21:45 UTC

requestbody: Return HTTP 413 (fix #4558)

Matthew Holt committed Mar 11, 2022 at 12:34 UTC 3d616e8c6d65e5617f5a918d72fb1514c9c7144e
4 files changed +25 -8
modules/caddyhttp/errors.go
+3
@@ -82,6 +82,9 @@ func (e HandlerError) Error() string {
82 return strings.TrimSpace(s)
83 }
84
85 +// Unwrap returns the underlying error value. See the `errors` package for info.
86 +func (e HandlerError) Unwrap() error { return e.Err }
87 +
88 // randString returns a string of n random characters.
89 // It is not even remotely secure OR a proper distribution.
90 // But it's good enough for some things. It excludes certain
modules/caddyhttp/replacer.go
+2 -6
@@ -162,12 +162,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
162 // read the request body into a buffer (can't pool because we
163 // don't know its lifetime and would have to make a copy anyway)
164 buf := new(bytes.Buffer)
165 - _, err := io.Copy(buf, req.Body)
166 - if err != nil {
167 - return "", true
168 - }
169 - // replace real body with buffered data
170 - req.Body = io.NopCloser(buf)
165 + _, _ = io.Copy(buf, req.Body) // can't handle error, so just ignore it
166 + req.Body = io.NopCloser(buf) // replace real body with buffered data
167 return buf.String(), true
168
169 // original request, before any internal changes
modules/caddyhttp/requestbody/requestbody.go
+17 -1
@@ -15,6 +15,7 @@
15 package requestbody
16
17 import (
18 + "io"
19 "net/http"
20
21 "github.com/caddyserver/caddy/v2"
@@ -28,6 +29,7 @@ func init() {
29 // RequestBody is a middleware for manipulating the request body.
30 type RequestBody struct {
31 // The maximum number of bytes to allow reading from the body by a later handler.
32 + // If more bytes are read, an error with HTTP status 413 is returned.
33 MaxSize int64 `json:"max_size,omitempty"`
34 }
35
@@ -44,10 +46,24 @@ func (rb RequestBody) ServeHTTP(w http.ResponseWriter, r *http.Request, next cad
46 return next.ServeHTTP(w, r)
47 }
48 if rb.MaxSize > 0 {
47 - r.Body = http.MaxBytesReader(w, r.Body, rb.MaxSize)
49 + r.Body = errorWrapper{http.MaxBytesReader(w, r.Body, rb.MaxSize)}
50 }
51 return next.ServeHTTP(w, r)
52 }
53
54 +// errorWrapper wraps errors that are returned from Read()
55 +// so that they can be associated with a proper status code.
56 +type errorWrapper struct {
57 + io.ReadCloser
58 +}
59 +
60 +func (ew errorWrapper) Read(p []byte) (n int, err error) {
61 + n, err = ew.ReadCloser.Read(p)
62 + if err != nil && err.Error() == "http: request body too large" {
63 + err = caddyhttp.Error(http.StatusRequestEntityTooLarge, err)
64 + }
65 + return
66 +}
67 +
68 // Interface guard
69 var _ caddyhttp.MiddlewareHandler = (*RequestBody)(nil)
modules/caddyhttp/server.go
+3 -1
@@ -17,6 +17,7 @@ package caddyhttp
17 import (
18 "context"
19 "encoding/json"
20 + "errors"
21 "fmt"
22 "net"
23 "net/http"
@@ -600,7 +601,8 @@ func PrepareRequest(r *http.Request, repl *caddy.Replacer, w http.ResponseWriter
601 // If err is a HandlerError, the returned values will
602 // have richer information.
603 func errLogValues(err error) (status int, msg string, fields []zapcore.Field) {
603 - if handlerErr, ok := err.(HandlerError); ok {
604 + var handlerErr HandlerError
605 + if errors.As(err, &handlerErr) {
606 status = handlerErr.StatusCode
607 if handlerErr.Err == nil {
608 msg = err.Error()