25

In a middleware, I want to read request body to perform some checks. Then, the request is passed to the next middleware where the body will be read again. Here's what I do:

bodyBytes, _ := ioutil.ReadAll(req.Body)
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
// use bodyBytes
// pass to next middleware

Now, req.Body.Close will do nothing. Will it break since the previous req.Body.Close implementation did some connection handling?

Denis Fetinin
  • 1,746
  • 1
  • 9
  • 15
Sergey
  • 1,168
  • 2
  • 13
  • 28
  • Related / possible duplicate of [Golang read request body](https://stackoverflow.com/questions/43021058/golang-read-request-body/43021236#43021236). – icza Oct 26 '17 at 07:58
  • I read it. In the answer, the original body is not closed which is confusing. – Sergey Oct 26 '17 at 08:06
  • 2
    At the server side you do not need to close the request body. [`Request.Body`](https://golang.org/pkg/net/http/#Request): _"The Server will close the request body. The ServeHTTP Handler does not need to."_ – icza Oct 26 '17 at 08:06
  • But the original close from the original body is lost once ioutil.NopCloser is applied. – Sergey Oct 26 '17 at 08:09
  • 1
    No, the original "close" is not lost. You merely assign a new value to the exported `Request.Body` field. This is not the only reference to the original body reader that needs to be closed. – icza Oct 26 '17 at 09:40
  • 2
    the title is misleading, it should be reading request body instead – wilsont Jan 03 '19 at 15:55

1 Answers1

54

Will it break since the previous req.Body.Close implementation did some connection handling?

No.

But your code is buggy: You should close the req.Body once you are done reading all of it. Then you construct a new ReadCloser as you did and hand this to the next middleware (which itself or stuff further down is responsible for closing is.)

bodyBytes, _ := ioutil.ReadAll(req.Body)
req.Body.Close()  //  must close
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
Volker
  • 40,468
  • 7
  • 81
  • 87
  • Thanks. Perhaps, I should've rephrased my question since I'd like to get some understanding. In golang client, I close response body to get connection back into the pool for subsequent reuse in other request (correct me if I'm wrong). What does req.body.close do in the server at all? – Sergey Oct 26 '17 at 07:30
  • I doubt that there is a simple answer. First it might not do anything in the server. On the client it is difficult too whether a connection is reused depends more on what client and server agree to do and less on you closing the body. But: of course you *must* close the original body. I'll update my answer. – Volker Oct 26 '17 at 07:40
  • In your code, shouldn't the body be closed only if err is nil? – Sergey Oct 26 '17 at 07:57
  • 15
    At the server side you do not need to close the request body. [`Request.Body`](https://golang.org/pkg/net/http/#Request): _"The Server will close the request body. The ServeHTTP Handler does not need to."_ – icza Oct 26 '17 at 08:03
  • 1
    @Sergey I do not understand. You should close req.Body, even if reading from it produced an error. This is unrelated. Are you thinking of not closing of the request itself produces an error? – Volker Oct 26 '17 at 08:08
  • @Volker, yeah, it should be closed regardless of an error. – Sergey Oct 26 '17 at 08:16
  • 1
    Upon looking at server code, the server keeps its own pointer to the Body, so it will always close the original body itself, at least that's how it seemed. Hence, does it matter that we close it here? – Luka Govedič Jul 13 '21 at 00:20
  • @Volker the Close is not needed from what I can tell. The server will close the "real" body even if you override the req.Body. I ran a test by passing the body from a req over a chan and checked it after the request was done, and it was closed by the server. – masebase Apr 13 '22 at 20:48