Reading body of http.Request without modifying request state?
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
.
Related videos on Youtube
Christopher Orr
☕️ If I helped you out, feel free to buy me a coffee… 🙂 You can find my email on my website, GitHub or LinkedIn. Some Jenkins plugins I've created: Android: Emulator — Lint — Google Play Publisher Others: GCM — Git Tag Message — Go(lang) Some Android apps I've built: Clue: Popular menstruation tracker and education app Migros: The largest retailer in Switzerland Snow Report: Ski conditions, also via Android Wear Best Swiss Hotels: Fun UI for finding hotels SumUp: Accept card payments Telekom Voicemail: Visual voicemail Telekom MyWallet: Early NFC payments app Some talks I've given: Droidcon Berlin 2012: Preventing Privacy Problems Droidcon London 2012: CI and app quality with Jenkins (slides, video) FOSDEM 2013: Building, testing and deploying mobile apps (slides) Dutch Android User Group, June 2013: Better Builds Jenkins User Conference Berlin 2014: Building, testing and deploying Android apps with Jenkins Advanced git with Jenkins San Francisco Android User Group 2015: Automating Android Build, Test & CD with Jenkins Google GDG DevFest NL 2015: Getting Started with CD for Android Jenkins World 2016, Santa Clara Day of Jenkins 2017, Gothenburg & Oslo: Keynote Berlindroid Meetup 2018: Command line magic for Android devs
Updated on February 15, 2020Comments
-
Christopher Orr over 4 years
I have a type implementing the
http.Handler
interface where, in itsServeHTTP
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 thereq.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()
andbufio.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?-
nemo about 10 yearsHave you tried replacing the
Body
with a seekable reader likebytes.Reader
? You can setBody
to every value that implementsReadCloser
. -
Volker about 10 yearsUntested (but worth a try): Make a deep copy of the Request as needed, i.e. all but not Body and .*Form. Then use io.TeeReader to clone Request.Body, wrap it in an NopCloser and stuff into the deepcopy of the request. Pass the deep copy to the reverse proxy.
-
-
joshlf about 10 yearsYep, np! And good catch on the Close signature. I guess reading the documentation is important after all ;)
-
Lars Wiegman over 9 yearsYou can get a
io.ReadCloser
from a buffer using theio.NopCloser
function, e.g.io.NopCloser(buf)
. See golang.org/src/pkg/io/ioutil/ioutil.go?s=3623:3664#L111 -
danmux over 9 yearsperhaps a TeeReader would be usefull
-
Joppe over 7 yearsThis works nicely, but only for bounded bodies that you can hold in memory or on disk.
-
joshlf over 7 years@Joppe, that's a good point. You'd need something much more subtle and complicated if you wanted to gracefully handle unbounded or too-large-for-memory requests.
-
mattes over 6 years
GetBody()
is only used for client requests. For server requests it is unused. -
mattes over 6 years
drainBody
in golang.org/src/net/http/httputil/dump.go#L26 offers a similar solution, but takinghttp.NoBody
into account.