-
Notifications
You must be signed in to change notification settings - Fork 18k
x/net/http2: zero-length payload HEADERS frame causes PROTOCOL_ERROR #47851
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
As per [RFC7540 Section 6.2](https://httpwg.org/specs/rfc7540.html#HEADERS): > Padding that *exceeds* the size remaining for the header block fragment MUST be treated as a PROTOCOL_ERROR. (emphasis added) Hence the existing check `if len(p)-int(padLength) <= 0` is incorrect since `=` would have flagged paddings that is *exactly* the size remaining. The existing check also triggers false positives when the HEADERS frame has a payload size of 0 and no padding (0 - 0 <= 0). Fixes golang/go#47851
CC @neild |
Nice analysis. The fix looks correct to me. If you'd rather not deal with the CLA and code review in Gerrit, let me know and I can make the fix instead. |
Change https://golang.org/cl/344029 mentions this issue: |
Thanks @zliu5! This bug was impacting us too when communicating with a proxy we'd written that was receiving http/2 requests and making http/1.1 requests, using akka-http which actually exposes the chunked protocol, and since http/1.1 responses always have an empty chunk at the end of them whether there's trailers or not because that indicates end of stream, our code was forwarding that last chunk message with empty trailers as an empty trailers message downstream to the http/2 connection, which caused go clients to choke. |
When ending the stream without any payload, use a DATA frame rather than a HEADERS frame to work around golang/go#47851. Tested with https://github.com/raboof/http2-from-go-to-akka-http
When ending the stream without any payload, use a DATA frame rather than a HEADERS frame to work around golang/go#47851. Tested with https://github.com/raboof/http2-from-go-to-akka-http
Fix a fencepost error which rejects HEADERS frames with neither payload nor padding, but accepts ones with padding and no payload. Fixes golang/go#47851. Change-Id: Ic6ed65571366e86980a5ec69e7f9e6ab958f3b07 Reviewed-on: https://go-review.googlesource.com/c/net/+/344029 Trust: Damien Neil <dneil@google.com> Run-TryBot: Damien Neil <dneil@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
Making an HTTP/2 request to server, which returns a zero-length payload trailer (HEADERS frame) as part of the response.
Zero-length payload HEADERS
We encountered this issue while proxying a
gprc-web
request to an upstream which uses thegrpc-web
filter from Envoy. Among other things,grpc-web
appends gRPC trailers as part of the response body. When Envoy does it, it clears out the trailers, leaving a zero-length trailer (HEADERS) frame.What did you expect to see?
Be able to handle the zero-length payload trailer.
For instance,
nghttp
handles it just fine:What did you see instead?
ERROR_PROTOCOL
being returned.Analysis
We traced it down to this line:
https://github.com/golang/net/blob/60bc85c4be6d32924bcfddb728394cb8713f2c78/http2/frame.go#L1021
if len(p)-int(padLength) <= 0 {
for a HEADERS frame with zero-length payload,
p
is of size zero. As a result even thoughpadLength
is also0
(as a matter of fact, this frame does not have any padding flag set, this is simply default value ofuint8
), this check fails due to<=
instead of<
.We believe the existing check is incorrect, as per RFC7540 Section 6.2:
(emphasis added)
The existing behavior is inconsistent with the RFC as it incorrectly returns
PROTOCOL_ERROR
when the padding (None /0
) does NOT exceed the size remaining (0
)Proposed Fix (PR to follow)
This should be a
<
instead of<=
check.Changing this check to
<
is also consistent with existing code in methods such asparseDataFrame
:https://github.com/golang/net/blob/60bc85c4be6d32924bcfddb728394cb8713f2c78/http2/frame.go#L611
The text was updated successfully, but these errors were encountered: