forked from caddyserver/caddy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1. Replace original `maxrequestbody` directive. 2. Add request header limit. fix issue caddyserver#1587 Signed-off-by: Tw <[email protected]>
- Loading branch information
Showing
11 changed files
with
363 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package limits | ||
|
||
import ( | ||
"io" | ||
"net/http" | ||
|
||
"github.com/mholt/caddy/caddyhttp/httpserver" | ||
) | ||
|
||
// Limit is a middleware to control request body size | ||
type Limit struct { | ||
Next httpserver.Handler | ||
BodyLimits []httpserver.PathLimit | ||
} | ||
|
||
func (l Limit) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { | ||
if r.Body == nil { | ||
return l.Next.ServeHTTP(w, r) | ||
} | ||
|
||
// apply the path-based request body size limit. | ||
for _, bl := range l.BodyLimits { | ||
if httpserver.Path(r.URL.Path).Matches(bl.Path) { | ||
r.Body = MaxBytesReader(w, r.Body, bl.Limit) | ||
break | ||
} | ||
} | ||
|
||
return l.Next.ServeHTTP(w, r) | ||
} | ||
|
||
// MaxBytesReader and its associated methods are borrowed from the | ||
// Go Standard library (comments intact). The only difference is that | ||
// it returns a MaxBytesExceeded error instead of a generic error message | ||
// when the request body has exceeded the requested limit | ||
func MaxBytesReader(w http.ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser { | ||
return &maxBytesReader{w: w, r: r, n: n} | ||
} | ||
|
||
type maxBytesReader struct { | ||
w http.ResponseWriter | ||
r io.ReadCloser // underlying reader | ||
n int64 // max bytes remaining | ||
err error // sticky error | ||
} | ||
|
||
func (l *maxBytesReader) Read(p []byte) (n int, err error) { | ||
if l.err != nil { | ||
return 0, l.err | ||
} | ||
if len(p) == 0 { | ||
return 0, nil | ||
} | ||
// If they asked for a 32KB byte read but only 5 bytes are | ||
// remaining, no need to read 32KB. 6 bytes will answer the | ||
// question of the whether we hit the limit or go past it. | ||
if int64(len(p)) > l.n+1 { | ||
p = p[:l.n+1] | ||
} | ||
n, err = l.r.Read(p) | ||
|
||
if int64(n) <= l.n { | ||
l.n -= int64(n) | ||
l.err = err | ||
return n, err | ||
} | ||
|
||
n = int(l.n) | ||
l.n = 0 | ||
|
||
// The server code and client code both use | ||
// maxBytesReader. This "requestTooLarge" check is | ||
// only used by the server code. To prevent binaries | ||
// which only using the HTTP Client code (such as | ||
// cmd/go) from also linking in the HTTP server, don't | ||
// use a static type assertion to the server | ||
// "*response" type. Check this interface instead: | ||
type requestTooLarger interface { | ||
requestTooLarge() | ||
} | ||
if res, ok := l.w.(requestTooLarger); ok { | ||
res.requestTooLarge() | ||
} | ||
l.err = httpserver.MaxBytesExceededErr | ||
return n, l.err | ||
} | ||
|
||
func (l *maxBytesReader) Close() error { | ||
return l.r.Close() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package limits | ||
|
||
import ( | ||
"io/ioutil" | ||
"net/http" | ||
"net/http/httptest" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/mholt/caddy/caddyhttp/httpserver" | ||
) | ||
|
||
func TestBodySizeLimit(t *testing.T) { | ||
var ( | ||
gotContent []byte | ||
gotError error | ||
expectContent = "hello" | ||
) | ||
l := Limit{ | ||
Next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { | ||
gotContent, gotError = ioutil.ReadAll(r.Body) | ||
return 0, nil | ||
}), | ||
BodyLimits: []httpserver.PathLimit{{Path: "/", Limit: int64(len(expectContent))}}, | ||
} | ||
|
||
r := httptest.NewRequest("GET", "/", strings.NewReader(expectContent+expectContent)) | ||
l.ServeHTTP(httptest.NewRecorder(), r) | ||
if got := string(gotContent); got != expectContent { | ||
t.Errorf("expected content[%s], got[%s]", expectContent, got) | ||
} | ||
if gotError != httpserver.MaxBytesExceededErr { | ||
t.Errorf("expect error %v, got %v", httpserver.MaxBytesExceededErr, gotError) | ||
} | ||
} |
Oops, something went wrong.