unexpected behavior http.MaxBytesReader & streaming response

360 views
Skip to first unread message

Jérôme LAFORGE

unread,
Jun 18, 2021, 10:32:11 AM6/18/21
to golang-nuts
Hello,
I am facing to unexpected behavior when I want to limit the maximum body request and managing the request/response as streaming way.

With this code https://play.golang.org/p/eN2XEpiPdhn, when I send the request, I have this unexpected error (whatever the max size):

```
2021/06/18 15:48:49 http: panic serving 127.0.0.1:39024: http: invalid Read on closed Body
goroutine 6 [running]:
net/http.(*conn).serve.func1(0xc000110960)
        net/http/server.go:1824 +0x153
panic(0x671b60, 0xc000012af0)
        runtime/panic.go:971 +0x499
main.serve(0x713cd0, 0xc0001480e0, 0xc000164000)
        autodebit/service/order/cmd/main.go:32 +0x3b7
net/http.HandlerFunc.ServeHTTP(0x6d2608, 0x713cd0, 0xc0001480e0, 0xc000164000)
        net/http/server.go:2069 +0x44
net/http.serverHandler.ServeHTTP(0xc000148000, 0x713cd0, 0xc0001480e0, 0xc000164000)
        net/http/server.go:2887 +0xa3
net/http.(*conn).serve(0xc000110960, 0x714180, 0xc000028280)
        net/http/server.go:1952 +0x8cd
created by net/http.(*Server).Serve
        net/http/server.go:3013 +0x39b
```

But if I discard the response (via io.Discard) that works as expected https://play.golang.org/p/ZOJQz6EC--V

I don't understand what it is going wrong. Can I use http.MaxBytesReader when I send response as streaming way?

Thanks for your help
Jérôme

the body file seems too big to be in attach, I put it on https://sharetext.me/iveuebzrfq
the curl cmd:
curl POST 'http://127.0.0.1:8081' --data-binary '@body.jsonl'

Sean Liao

unread,
Jun 18, 2021, 2:37:11 PM6/18/21
to golang-nuts
I think it's working as expected?
The panic originates in your code:

```
err := decoder.Decode(&el)
if err != nil {
panic(err)
}
```

What you should be doing is to break out of the loop and handle the error (client sending more than you want to read) gracefully

Jérôme LAFORGE

unread,
Jun 18, 2021, 3:15:54 PM6/18/21
to golang-nuts
Sorry, I wasn't clear enough. 
I know that panic comes from my code. It throws it. 
But I wanted to show that error on Decode must not occur because the body is smaller than 8kB. 
The 2nd example works like this. 
The only difference between the two examples is just the response is discarded. 

Jérôme LAFORGE

unread,
Jun 19, 2021, 1:19:22 AM6/19/21
to golang-nuts

Brian Candler

unread,
Jun 19, 2021, 6:15:34 AM6/19/21
to golang-nuts
Here is a variation on your program, removing json.Encoder from the equation:

It works as shown, but if you uncomment the commented-out fmt.Fprintf, it fails.  (macOS, go1.16.5)

This is indeed weird. As far as I can see, the only way MaxBytesReader interacts with its Writer (w) argument is to call w.requestTooLarge() if the limit is exceeded *and* w has that method.  But I've checked and it doesn't.

Brian Candler

unread,
Jun 19, 2021, 6:19:11 AM6/19/21
to golang-nuts
Ah I get it now: it's due to application starting to send a response before the request has been completely received, as per the response to your ticket which links to https://github.com/golang/go/issues/15527

Jérôme LAFORGE

unread,
Jun 21, 2021, 11:23:46 AM6/21/21
to golang-nuts
Thanks all for your support.
As workaround, I buffer the response until I read completely the request.
In order to limit the GC and consumption of resource, I recycle the the bytes.Buffer with sync.Pool that is in charge of create bytes.Buffer with initial capacity.
Reply all
Reply to author
Forward
0 new messages