go: net/http/httputil: Proxy terminates HTTP/2 stream before reading response body.

Please answer these questions before submitting your issue. Thanks!

1. What version of Go are you using (go version)?

go version go1.7 darwin/amd64

2. What operating system and processor architecture are you using (go env)?

GOHOSTARCH="amd64"
GOHOSTOS="darwin"

3. What did you do?

  • Running a reverse proxy using https://golang.org/pkg/net/http/httputil/
  • Proxies HTTP on host:port to a target server defined by the -proxy flag.
  • Sending POST data through the proxy (the proxy manipulates CORS headers)

4. What did you expect to see?

  • A HTTP 200 (or other successful status code).

5. What did you see instead?

  • A HTTP 502 and a proxy error due to premature termination of the HTTP/2 stream.
go run simple.go -proxy=https://repeater.getattest.io/post/data -port=8001
curl http://localhost:8001/post/data -d "gophers=yes;"
ts="2016/08/18 06:40:38" msg="http: proxy error: stream error: stream ID 3; STREAM_CLOSED"
ts=2016-08-18T06:40:38-07:00 status=502 method=POST uri=https://repeater.getattest.io/post/data duration=20.74786ms bytes=0 from=127.0.0.1:56479
  • The proxy I’m running (single file): https://gist.github.com/elithrar/a47af11adb818571d364cc5797ce0fb6 - run it, then hit with the curl above. Updated with simpler code
  • The upstream, in this case, is nginx (CloudFlare; HTTP/2), fronting my test server (Go on Heroku HTTP/1.1).
  • Running binaryname -proxy=https://post.workwithgo.com/post/data (Caddy, HTTP/2, proxying the same origin application) and running the same curl does not cause the same error.
  • To be tested: nginx mainline over HTTP/2, which appears to be the last remaining variable.

Note: Disabling HTTP/2 via a custom transport on the upstream leg avoids the issue (as you would expect, given the error). I have yet to test on another HTTP/2 origin (I’ll spin up a raw Caddy instance shortly).

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 1
  • Comments: 19 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Whoa, this is messed up:

2016/08/18 14:19:22 http2: Framer 0xc4200fccc0: wrote DATA flags=END_STREAM stream=13 len=12 data="gophers=yes;"
2016/08/18 14:19:22 http2: Framer 0xc4200fccc0: wrote DATA flags=END_STREAM stream=13 len=0 data=""

Two END_STREAM bits for the same stream ID (13).

No wonder the server on the other side is telling us RST_STREAM. I’m surprised it’s not just hanging up on us for a protocol error violation.

(To be clear, because your comment looks backwards, @elithrar: the Go HTTP/2 client appears to be writing bogus frames, and then the server is writing RST_STREAM stream=13 len=4 ErrCode=STREAM_CLOSED, which the proxy’s HTTP client then reads.)