Reading body of http.Request without modifying request state?

22,954

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.

Share:
22,954

Related videos on Youtube

Christopher Orr
Author by

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, 2020

Comments

  • Christopher Orr
    Christopher Orr over 4 years

    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?

    • nemo
      nemo about 10 years
      Have you tried replacing the Body with a seekable reader like bytes.Reader? You can set Body to every value that implements ReadCloser.
    • Volker
      Volker about 10 years
      Untested (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
    joshlf about 10 years
    Yep, np! And good catch on the Close signature. I guess reading the documentation is important after all ;)
  • Lars Wiegman
    Lars Wiegman over 9 years
    You can get a io.ReadCloser from a buffer using the io.NopCloser function, e.g. io.NopCloser(buf). See golang.org/src/pkg/io/ioutil/ioutil.go?s=3623:3664#L111
  • danmux
    danmux over 9 years
    perhaps a TeeReader would be usefull
  • Joppe
    Joppe over 7 years
    This works nicely, but only for bounded bodies that you can hold in memory or on disk.
  • joshlf
    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
    mattes over 6 years
    GetBody() is only used for client requests. For server requests it is unused.
  • mattes
    mattes over 6 years
    drainBody in golang.org/src/net/http/httputil/dump.go#L26 offers a similar solution, but taking http.NoBody into account.