diff --git a/caddyhttp/httpserver/replacer.go b/caddyhttp/httpserver/replacer.go index 958758da6..f07c25cc6 100644 --- a/caddyhttp/httpserver/replacer.go +++ b/caddyhttp/httpserver/replacer.go @@ -2,8 +2,8 @@ package httpserver import ( "bytes" + "io" "io/ioutil" - "log" "net" "net/http" "net/http/httputil" @@ -127,13 +127,12 @@ func NewReplacer(r *http.Request, rr *ResponseRecorder, emptyValue string) Repla return "" } - body, err := readRequestBody(r) + body, err := readRequestBody(r, maxLogBodySize) if err != nil { - log.Printf("[WARNING] Cannot copy request body %v", err) return "" } - return string(body) + return requestReplacer.Replace(string(body)) }, }, emptyValue: emptyValue, @@ -163,13 +162,18 @@ func canLogRequest(r *http.Request) (canLog bool) { // readRequestBody reads the request body and sets a // new io.ReadCloser that has not yet been read. -func readRequestBody(r *http.Request) ([]byte, error) { - body, err := ioutil.ReadAll(r.Body) +func readRequestBody(r *http.Request, n int64) ([]byte, error) { + body, err := ioutil.ReadAll(io.LimitReader(r.Body, n)) if err != nil { return nil, err } - // Create a new ReadCloser to keep the body from being drained. - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + + mr := io.MultiReader( + bytes.NewBuffer(body), + r.Body, + ) + + r.Body = ioutil.NopCloser(mr) return body, nil } @@ -272,4 +276,5 @@ const ( headerContentType = "Content-Type" contentTypeJSON = "application/json" contentTypeXML = "application/xml" + maxLogBodySize = 100 * 1000 ) diff --git a/caddyhttp/httpserver/replacer_test.go b/caddyhttp/httpserver/replacer_test.go index be87d582c..e07d29321 100644 --- a/caddyhttp/httpserver/replacer_test.go +++ b/caddyhttp/httpserver/replacer_test.go @@ -2,6 +2,7 @@ package httpserver import ( "bytes" + "io/ioutil" "net/http" "net/http/httptest" "os" @@ -164,23 +165,26 @@ func TestRound(t *testing.T) { } func TestReadRequestBody(t *testing.T) { - r, err := http.NewRequest("POST", "/", strings.NewReader(`null`)) + payload := []byte(`{ "foo": "bar" }`) + var readSize int64 = 5 + r, err := http.NewRequest("POST", "/", bytes.NewReader(payload)) if err != nil { t.Error(err) } defer r.Body.Close() - body, err := readRequestBody(r) + logBody, err := readRequestBody(r, readSize) if err != nil { t.Error("readRequestBody failed", err) + } else if !bytes.EqualFold(payload[0:readSize], logBody) { + t.Error("Expected log comparison failed") } - var data = make([]byte, len(body)) - _, err = r.Body.Read(data) - + // Ensure the Request body is the same as the original. + reqBody, err := ioutil.ReadAll(r.Body) if err != nil { - t.Error(err) - } else if !bytes.Equal(body, data) { - t.Error("Expceted equal bytes.") + t.Error("Unable to read request body", err) + } else if !bytes.EqualFold(payload, reqBody) { + t.Error("Expected request body comparison failed") } }