Reading body of http.Request without modifying request state?
I have a type implementing the http.Handler
interface where, in its ServeHTTP
method, incoming HTTP requests are inspected, some action is taken, and then the requests are forwarded to a reverse proxy handler (httputil.NewSingleHostReverseProxy
).
This works fine, so long as I'm only inspecting the basic request properties, such as the URL or headers.
When I want to inspect the body of an incoming POST request, e.g. by calling req.ParseForm()
and then using the req.Form
property, I run into an error once the request is passed onto the reverse proxy:
http: proxy error: http: Request.ContentLength=687 with Body length 0
I imagine this happens because looking at the body of the HTTP request causes the req.Body.Reader
stream to be drained, meaning it cannot be read again by the proxy handler.
I've been playing with things like io.Copy()
and bufio.Peek()
, but I'm not really getting anywhere.
Is there a way to peek at the HTTP request body (and use the built-in parsing of req.ParseForm
etc.), while leaving the original request object in its original state, so that it can be passed to the reverse proxy?
Solution 1:
Try reading into a buffer and then using the buffer to back two new readers, one for you to use, and one for subsequent consumers to use. For example, imagine that we want to modify the following code:
doStuff(r.Body) // r is an http.Request
We could do:
buf, _ := ioutil.ReadAll(r.Body)
rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf))
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))
doStuff(rdr1)
r.Body = rdr2 // OK since rdr2 implements the io.ReadCloser interface
// Now the program can continue oblivious to the fact that
// r.Body was ever touched.
Note that *bytes.Buffer
does not have a Close() error
method, so it doesn't implement the io.ReadCloser
interface. Thus, we have to wrap our *bytes.Buffer
values in calls to ioutil.NopCloser
.