From d56ac28beccd811fac3d871240e500da1d2b2cde Mon Sep 17 00:00:00 2001
From: Carter <definitelycarter@users.noreply.github.com>
Date: Wed, 10 Aug 2016 22:43:26 -0400
Subject: [PATCH] Using a LimitReader and fixed test and log format.

---
 caddyhttp/httpserver/replacer.go      | 21 +++++++++++++--------
 caddyhttp/httpserver/replacer_test.go | 20 ++++++++++++--------
 2 files changed, 25 insertions(+), 16 deletions(-)

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")
 	}
 }