forked from TykTechnologies/tyk
-
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.
Add max_content_length, max_request_body_size (TykTechnologies#5043)
<!-- Provide a general summary of your changes in the Title above --> ## Description The PR implements a `max_content_length` addition in the area of `max_request_body_size`. The check for `max_content_length` responds with HTTP 411 Length Required if the content-length header is not present. A handled exception to this is `Transfer-Encoding: chunked`, which doesn't provide a content length header and thus can't handle before reading the full request body. Per-API middleware has access to the body and can validate length. The `max_request_body_size` limits the amount of bytes read for the request if the content-length is unknown or unset. Because there are exceptions that bypass `max_content_length`, this has a separate flag. Depending on wanted behaviour, one or the other option may be configured. Both flags issue a response with HTTP 413 Entity too big, based on the content-length header value only. <!-- Describe your changes in detail --> ## Related Issue https://tyktech.atlassian.net/browse/TT-5186 <!-- This project only accepts pull requests related to open issues. --> <!-- If suggesting a new feature or change, please discuss it in an issue first. --> <!-- If fixing a bug, there should be an issue describing it with steps to reproduce. --> <!-- OSS: Please link to the issue here. Tyk: please create/link the JIRA ticket. --> ## Motivation and Context <!-- Why is this change required? What problem does it solve? --> ## How This Has Been Tested <!-- Please describe in detail how you tested your changes --> <!-- Include details of your testing environment, and the tests --> <!-- you ran to see how your change affects other areas of the code, etc. --> <!-- This information is helpful for reviewers and QA. --> ## Screenshots (if appropriate) ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Refactoring or add test (improvements in base code or adds test coverage to functionality) ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply --> <!-- If there are no documentation updates required, mark the item as checked. --> <!-- Raise up any additional concerns not covered by the checklist. --> - [ ] I ensured that the documentation is up to date - [ ] I explained why this PR updates go.mod in detail with reasoning why it's required - [ ] I would like a code coverage CI quality gate exception and have explained why --------- Co-authored-by: Tit Petric <[email protected]>
- Loading branch information
Showing
12 changed files
with
276 additions
and
34 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,10 @@ | ||
--- | ||
version: "3" | ||
|
||
tasks: | ||
default: | ||
desc: "Run tests" | ||
cmds: | ||
- go fmt ./... | ||
- goimports -w . | ||
- go test -race -count=100 -cover . |
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,50 @@ | ||
package httputil | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"net/http" | ||
) | ||
|
||
// ErrContentTooLong is an internal error to handle limit overflows. | ||
var ErrContentTooLong = errors.New("content size over the declared limit") | ||
|
||
// LimitReader replaces the request body with a reader designed to | ||
// error out when the size limit has been exceeded. | ||
func LimitReader(r *http.Request, limit int64) { | ||
r.Body = &limitedRequestBody{ | ||
body: r.Body, | ||
limit: limit, | ||
err: nil, | ||
} | ||
} | ||
|
||
type limitedRequestBody struct { | ||
body io.Reader | ||
limit int64 | ||
err error | ||
} | ||
|
||
// Read implements io.Reader. | ||
func (l *limitedRequestBody) Read(p []byte) (n int, err error) { | ||
n, err = l.body.Read(p) | ||
if l.err != nil { | ||
return n, l.err | ||
} | ||
|
||
if n > 0 { | ||
l.limit -= int64(n) | ||
if l.limit < 0 { | ||
l.err = errors.New("request entity too large") | ||
return n, ErrContentTooLong | ||
} | ||
} | ||
|
||
return n, err | ||
} | ||
|
||
// Close implements io.Closer. | ||
func (l *limitedRequestBody) Close() error { | ||
l.err = nil | ||
return nil | ||
} |
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,47 @@ | ||
package httputil_test | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"net/http" | ||
"net/http/httptest" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
. "github.com/TykTechnologies/tyk/internal/httputil" | ||
) | ||
|
||
func TestLimitReader(t *testing.T) { | ||
loremIpsum := "Lorem Ipsum dolor sit amet" | ||
|
||
// Create a test request with a request body larger than the limit | ||
req := httptest.NewRequest(http.MethodPost, "/test", strings.NewReader(loremIpsum)) | ||
|
||
// Create a test response recorder | ||
w := httptest.NewRecorder() | ||
|
||
// Call the LimitReader function | ||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
LimitReader(r, 10) | ||
|
||
// Read the request body | ||
body, err := io.ReadAll(r.Body) | ||
if err != nil { | ||
if errors.Is(err, ErrContentTooLong) { | ||
EntityTooLarge(w, r) | ||
return | ||
} | ||
t.Errorf("Failed to read request body: %v", err) | ||
} | ||
|
||
// Check if the body matches the expected value | ||
expectedBody := "Lorem Ipsu" | ||
assert.Equal(t, expectedBody, body) | ||
}) | ||
handler.ServeHTTP(w, req) | ||
|
||
// Check the response status code | ||
assert.Equal(t, http.StatusRequestEntityTooLarge, w.Result().StatusCode) | ||
} |
Oops, something went wrong.