-
Notifications
You must be signed in to change notification settings - Fork 18k
x/net/http2: requests with absolute URIs in URL.Opaque produce incorrect :path header #16847
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
Worth noting that the Google-API generated clients can not be currently generated in Go1.7 due to this bug. The generated code will always call SetOpaque (via Expand or directly) https://github.com/google/google-api-go-client/blob/master/google-api-go-generator/gen.go#L1909-L1918 and this results in the "stream ID 1; PROTOCOL_ERROR" at runtime. However this is not necessarily a google-api generator bug, as it affects all use of Opaque with http/2 when an absolute URI is used. |
/cc @bradfitz |
This seems like it's potentially a regression in 1.7. @bradfitz to weigh in on whether this belongs in a 1.7.1 |
Go 1.6 has the same behavior. @saljam, @buro9, are either of you implying this is a regression from Go 1.6? @buro9, I'm not sure why you're talking about problems "generating" the code ("can not be currently generated in Go1.7 due to this bug"). This is purely a runtime issue. Why didn't we hear about it during Go 1.6 if it affects google-api-go-client? |
@bradfitz this has been the behaviour in http2 for a while, and go1.6.2 exhibits this as well. I wouldn't call it a regression. So far I've only managed to reproduce it with nginx as the server. A Go http2 server is more lenient in how it parses :path and the request wouldn't fail. Maybe this is why it slipped past. |
Well, we're definitely violating the protocol:
Where RFC 3986 says:
|
Definitely interesting that this hasn't come up with google-api-go-client. I don't know how that happened. Maybe the Google HTTP servers don't have a problem with this. I can't recommend this for 1.7.1, but don't feel strongly about it. If I'm reading correctly, the workaround is to not use Opaque. Instead, use a combination of Host/RawPath/RawQuery. |
When I use google-api-go-client's SetOpaque function, func SetOpaque(u *url.URL) {
u.Opaque = "//" + u.Host + u.Path
} on, req, _ := http.NewRequest("GET", "https://www.google.com/humans.txt", nil)
SetOpaque(req.URL) What happens is that http2 package uses Google GFE surprisingly accepts that:
... no clue why. Maybe for compatibility for broken people like us. I'll ask. So @buro9, what issue are you talking about? google-api-go-client seems to work. Or are you using it against non-Google hosts for things like go-endpoints? |
(Note to self: I filed internal bug http://b/31037249 to ask why the Google GFE accepts this.) |
I'm included to do nothing here. Or at least wait until Go 1.8 for any fix. There's no good place to document this, so I could just fix it in the common case: if we would send a @broady opened googleapis/google-api-go-client#161 to update google-api-go-client using the Go 1.5 API added to replace Opaque. |
Yes :) The generator that is part of the google API go client project is used by other companies to generate their own Go clients. At CloudFlare we use it to generate a Go client for a 3rd party system that is documented by JSON Schema, and so we are then using Go http/2 to call a Nginx http/2 server that fronts a Glassfish of the 3rd party API. This specific project has been stuck on Go1.6.1 for a while not knowing where the root cause of the issue was. Salman and I finally looked into it and got to the bottom of it... Opaque handling in http/2. |
Okay, good to know what's happening. You two can follow along at googleapis/google-api-go-client#161 for a short-term fix for go-endpoints. I'll do a low-priority fix for Go 1.8. |
CL https://golang.org/cl/27632 mentions this issue. |
Historically the google-api-go-client has had trouble sending certain characters in paths without the Go standard library (net/url and net/http packages) double escaping or escaping in an unexpected manner (for example, space encoding in issue #64). As a workaround, we started escaping the URL manually and using url.Opaque (for example, 02cfcab and 5c258d4). This mostly works but has problems with HTTP/2 (golang/go#16847). In Go 1.5, the URL struct introduced the RawPath field which was more suitable for this task: if RawPath is provided and is a valid escaping of Path, then the url package will use it as the value of EscapedPath (and EscapedPath is then subsequently used when constructing HTTP requests etc.). This commit changes uritemplates.Expand to return both the unescaped and escaped forms of the the template expansion. This allows us to fill in both url.Path and url.RawPath in a way that satisfies the criteria for url.EscapedPath to function correctly. Issue #161. Change-Id: I51e54e18f198b6465a6d032b1072282bf3d2f9ce Reviewed-on: https://code-review.googlesource.com/7110 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
CL https://golang.org/cl/29110 mentions this issue. |
Updates x/net/http2 (and x/net/lex/httplex) to git rev 749a502 for: http2: don't sniff first Request.Body byte in Transport until we have a conn https://golang.org/cl/29074 Fixes #17071 http2: add Transport support for unicode domain names https://golang.org/cl/29071 Updates #13835 http2: don't send bogus :path pseudo headers if Request.URL.Opaque is set https://golang.org/cl/27632 + http2: fix bug where '*' as a valid :path value in Transport https://golang.org/cl/29070 Updates #16847 http2: fix all vet warnings https://golang.org/cl/28344 Updates #16228 Updates #11041 Also uses the new -underscore flag to x/tools/cmd/bundle from https://golang.org/cl/29086 Change-Id: Ica0f6bf6e33266237e37527a166a783d78c059c4 Reviewed-on: https://go-review.googlesource.com/29110 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Chris Broadfoot <cbro@golang.org>
Hit golang/go#16847 while cloning the kernel sources. whee. Signed-off-by: Eric Myhre <hash@exultant.us>
It was discovered the bug golang/go#16847 prevents usage of AWS services using HTTP 2, such as AWS X-Ray with the AWS SDK for Go because Go 1.6.2 - 1.7.4 does not correctly build HTTP2 request when the URL uses Opaque to set the escaped version of the URL path. This has been fixed int he Go 1.8 branch, but this change will ensure users using the current version of Go will be able to connect to AWS services using HTTP2. With this change the SDK will no longer with with the unsupported Go version 1.4.
… set Fixes golang/go#16847 Change-Id: I1e6ae1e0746051fd4cf7afc9beae7853293d5b68 Reviewed-on: https://go-review.googlesource.com/27632 Reviewed-by: Chris Broadfoot <cbro@golang.org>
If one sets URL.Opaque in a request to an absolute URI or a scheme-relative one (e.g. "//example.com/foo"), that request would work over HTTP/1.1, but fail over HTTP/2 on some servers (e.g. NGINX) with a PROTOCOL_ERROR.
That's because x/net/http2 uses URL.Opaque (if present) for the :path header. And while HTTP/1.1 allows a Request-URI to be an absolute URI, HTTP/2 expects the :path header to be just the path part. URL.Opaque now has two slightly different meanings in the context of http.
I'm happy to write a CL to for http2 to ignore URL.Opaque for :path, or maybe parse it and use its path part. That would make existing packages that use Opaque (e.g. googleapi) not break on the upgrade to http2.
But perhaps just documenting this Opaque caveat is sufficient.
http2debug=1 output:
The text was updated successfully, but these errors were encountered: