-
Notifications
You must be signed in to change notification settings - Fork 18k
x/net/http2: Transport interop issue against Apache mod_h2? #16519
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
Just tried above code with |
Ubuntu 14.04.4 LTS (amd64) /etc/apache2/sites-enabled/wohlford.co.conf:
Server Module List:
|
@icing, we might have an interop problem. @songgao, there's no obvious place to fallback here. There's no great way to distinguish between an interop problem (if that's what it is... some bug on either side, or both), or an actual slow response hitting your timeout. Falling back h2 to h1 whenever an h2 response was legitimately slow doesn't work. Especially for general http retry reasons. (non-idempotent methods, etc) I'll work on a preparing a Docker container with mod_h2 so I can reproduce this, unless somebody already has one. @songgao, do you have a minimal repro? |
@bradfitz I see hanging request with my go 1.6.2. In order to check against my local test server, how do i disable the cert verification? :-D |
@icing, you can write code like: import (
"crypto/tls"
"log"
"net/http"
"os"
"golang.org/x/net/http2"
)
func main() {
c := &http.Client{
Transport: &http2.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
res, err := c.Get("https://localhost:1234/foo.txt")
if err != nil { log.Fatal(err) }
res.Write(os.Stdout)
} And if you run it with Thanks for looking! I'll investigate more when I'm home. |
@bradfitz thanks! I think you are running into the issue fixed in v1.5.12: when the client waits on a SETTINGS ACK without anything else going on, it might get stuck in h2's output buffers. As nghttp and curl always open stream 1 without waiting for the ack, this was not noticed. Have to add go tests some day... |
Perhaps Go could send a dummy OPTIONS request if no settings response is On Jul 29, 2016 11:12 AM, "Stefan Eissing" notifications@github.com wrote:
|
Or send the first request right away? Save your client 1 RTT.. |
@bradfitz Thanks for the explanation. I don't have a minimal repro yet; sorry! |
So, out of curiosity, I was wondering why go1.6 works with the same server. Does go1.6 always open stream 1 without waiting for the ack like nghttp/curl? If so, was the reason for changing that "compliance with standard"? |
@songgao, Go 1.6 had a bug where HTTP/2 was enabled by default on all HTTP clients except the default one, embarrassingly. It was a bug introduced almost immediately before Go 1.6 was released, in the process of fixing a different bug, embarrassingly. It was fixed in Go 1.6.2 (Go 1.6.1 was a security-only release). So you weren't using Go's http2 stack with Go 1.6 probably. @icing, yeah, I suppose I could do that too. But would a PING frame force a flush of your buffers? That might be lower-risk at this stage of our release, which is just around the corner. |
If I understand my code, only a request will bring it out of that embarrassing state of not flushing its buffers then. It could be any request, really. Maybe insert a dummy one? Sorry about that. |
Started adding go tests into my test suite. Seeing other interop issues, e.g. where Apache sends response HEADER + DATA (eof set) and the go client hangs. No flow involved. And go on http1 works fine. Does it makes sense to test with 1.6.2? Will have a closer look next week... |
I thought about sending a dummy OPTIONS request, but then I found it was easier to just not wait for the peer's settings & settings ACK instead. I hacked that up on the plane ride home. It might be too late for Go 1.7.
File a new Go bug and post details? I need to setup mod_h2 interop tests on my side too, but do share any Go snippet you find that hangs.
Either use Go 1.6.2, or use Go 1.6 and just make sure you create your own c:= &http.Client{Transport: &http.Transport{}}
c.Get(....) |
I've been tracking this issue and I'm afraid some of the technical details are over me head. Pardon if I ask questions that don't really make all that much sense. ;-) The original symptom came up with my use of keybase.io. It would validate my identity on my website over https, but not http. I mentioned it to @maxtaco. I believe he followed up with @songgao, and now there's this issue on GitHub. And frankly all that is so damn cool! I love open source! :-) If I follow everything above, it breaks when using http2. I've disabled my http2 module in apache and restarted the daemon. So why can't I still validate? Works: https://wohlford.co/.well-known/keybase.txt Doesn't work: http://wohlford.co/.well-known/keybase.txt I'm thinking there is something else going on here besides h2/h2c issues. Don't want us to miss that if true. |
Thanks for looking into it @wohlford (Also thanks @bradfitz for the fantastic explanation!) Jason, I think this thread is more for Go's |
CL https://golang.org/cl/25362 mentions this issue. |
@bradfitz Thanks for the fix! Any chance the patch will make it into go1.7? |
@songgao, it's pretty late in the cycle, but it's pretty crappy for users as-is so we probably should. I verified that this makes Go work with the latest Debian squeeze apache2, which doesn't yet have the upstream mod_h2 fix yet. @adg, @broady, @quentinmit, @ianlancetaylor... thoughts? |
My vote is to put it in 1.7. It's pretty annoying if we enable HTTP2 by default and we can't interoperate with Apache. |
Where do we draw the line for these changes? |
There aren't many http2 implementations. I think it's pretty bad for users if they don't interop, even if it's temporary. Plus I think the proposed change is how we want things anyway. |
OK On 1 August 2016 at 11:04, Brad Fitzpatrick notifications@github.com
|
CL https://golang.org/cl/25388 mentions this issue. |
Updates bundled http2 to x/net/http2 rev 28d1bd4f for: http2: make Transport work around mod_h2 bug https://golang.org/cl/25362 http2: don't ignore DATA padding in flow control https://golang.org/cl/25382 Updates #16519 Updates #16556 Updates #16481 Change-Id: I51f5696e977c91bdb2d80d2d56b8a78e3222da3f Reviewed-on: https://go-review.googlesource.com/25388 Reviewed-by: Chris Broadfoot <cbro@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Thanks for getting this in before 1.7 release! |
Thanks for the quick fix! |
CL https://golang.org/cl/25508 mentions this issue. |
The http2 spec says: > When the value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver > MUST adjust the size of all stream flow-control windows that it > maintains by the difference between the new value and the old value. We didn't do this before, and it never mattered until https://golang.org/cl/25362 for golang/go#16519 because we always knew the peer's initial window size. Once we started writing request bodies before hearing the peer's setting (and thus assuming 64KB), it became very important that this TODO was done. Should've done it earlier. More details in the bug. Updates golang/go#16612 (fixes after bundle into std) Change-Id: I0ac0280bdd5f6e933ad82f8c9df3c4528295bac2 Reviewed-on: https://go-review.googlesource.com/25508 Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Chris Broadfoot <cbro@golang.org>
The http2 server implementation in Apache (mod_http2, aka mod_h2) had a bug where it didn't reply to the initial SETTINGS frame until it had received a request. Apache 2.4.17 was the first Apache version to include mod_http2 and has the bug. The bug was fixed 20 days ago (apache/httpd@de4e303) for Apache 2.5.0 and included in the out-of-tree mod_h2 1.5.12 (https://github.com/icing/mod_h2/releases/tag/v1.5.12) but most Apache sites are running older versions making them incompatible with Go's client. (At least Debian Stretch and Ubuntu Xenial, currently.) Chrome, curl, Firefox et al don't wait for the initial SETTINGS response & ACK before sending their first request, which is why mod_http2 didn't notice their bug for some time. This change makes Go's http2.Transport act like other common HTTP/2 clients and not wait for the peer's SETTINGS frame & ACK before sending the first request. As a bonus, this reduces the latency for the first request on connections by one RTT. The reason we waited for the initial settings is purely historical. Andrew and I just wrote it that way when initially developing the client on video (https://www.youtube.com/watch?v=yG-UaBJXZ80) because we were working top-down through the protocol and didn't get back to optimizing the RTT away. It also seemed more compliant to wait for the peer's SETTINGS to know the frame size and such, but as as spec says, it's permitted for clients to not wait: http://httpwg.org/specs/rfc7540.html#rfc.section.3.5 > To avoid unnecessary latency, clients are permitted to send > additional frames to the server immediately after sending the client > connection preface, without waiting to receive the server connection > preface. It is important to note, however, that the server > connection preface SETTINGS frame might include parameters that > necessarily alter how a client is expected to communicate with the > server. Upon receiving the SETTINGS frame, the client is expected to > honor any parameters established. In some configurations, it is > possible for the server to transmit SETTINGS before the client sends > additional frames, providing an opportunity to avoid this issue. So, don't wait. Fixes golang/go#16519 Change-Id: I916827e49829f7f107a51838512816916fb553fc Reviewed-on: https://go-review.googlesource.com/25362 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Please answer these questions before submitting your issue. Thanks!
go version
)?go env
)?Falls back to HTTP/1.1 or errors
Hangs until timeout
The text was updated successfully, but these errors were encountered: