-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Fixed HTTP/2 support for the proxy middleware #1300
Conversation
http.Transport instances whose TLSClientConfig, Dial, or DialTLS field is non-nil will be configured without HTTP/2 support by default. This commit adds the proper calls to http2.ConfigureTransport() everywhere a http.Transport is created and thus fixes HTTP/2 in the proxy middleware whenever insecure_skip_verify or keepalive is provided.
Are you sure? I read:
(net/http docs) To me this says that unless we specify TLSNextProto manually to something that doesn't include "h2", http/2 will be enabled automatically. |
Yes 100% sure. That statement is not true anymore since Go 1.7 due to golang/go#14275. I noticed this bug, because I was trying to proxy gRPC calls, which for some reason simply didn't work. At all. I then used |
@mholt One more thing (partially off topic): Shouldn't we also possibly switch from using |
Oh wow, I hadn't seen that code change. Thanks for finding that. I guess the docs are lagging behind a little bit (Caddy's do too, so ... haha oh well).
I don't see that Dial() is deprecated, but I do plan on introducing Context to Caddy very soon, like for identifying HTTP requests. I think we could switch to using DialContext any time to just have the context available, I'm okay with that. |
Is there an easy way to test HTTP/2 is working? In the proxy tests, we have a "fake" upstream that responds to requests (like this one) -- we could add a test case that checks the protocol on the request to make sure that it's HTTP/2 I think. If that's doable, would you please add that to this PR? Then I'll merge it in. |
Holy... What the heck is that? I did not fetch upstream commits into my fork and still... There they are. My fork contains 2 new commits from you guys I've never seen before. How did you do that @mholt? Or was that "GitHub's" doing? Anyways: I modified the proxy test accordingly. It took me far too long to figure out why my modifications to that "httptest" package don't work/apply, until I noticed that "httptest" is a Go-package. 😐 I thus added a simple wrapper which overwrites the |
Sorry, I've updated your branch with upstream changes via Github "Update branch" (out of habit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great - thank you!! Going out in a release today I hope.
@mholt I fear I might have broken something inadvertently. Since connections are now made using HTTP/2, WebSockets won't work anymore. In my case my backend logs:
I thought I did it correctly, because for WebSockets your code calls
Edit: Nope. I broke shit. Confirmed. ✅ |
@lhecker Strange, the tests are passing... what kind of configuration breaks web sockets? |
@mholt None of your WebSocket proxy tests use a HTTP/2 enabled backend, which is why the tests pass. You can try it yourself by replacing all occurrences of |
@lhecker I can perhaps help guide you :) The first step would be to get the tests to fail, as you've explained how to do (add a test case instead of replacing one, though). I just remembered there's a However, this'll disable HTTP/2 entirely but users may want HTTP/2 for client connections still. You'll need to find a way to disable HTTP/2 for the ReverseProxy for websocket connections. Maybe the |
Hm… I'm not entirely sure if I understood that… @mholt
|
|
@mholt Alright I figured out how to modify the fake WS upstream to proxy a self-signed wss:// stream. And it does fail with the above http2 bogus greeting error! I hope I'll be done by tomorrow. |
@mholt I'm stuck again. I added support for switching off HTTP/2 using The error is:
(Only the first dozen or so bytes consistently stay the same though.) To me this looks like a raw TLS 1.2 handshake (which AFAIK starts with |
Ahh, you may be right! Can you investigate that further and see if you can find a simple change to fix it? (And if you come to my neck of the woods sometime, lunch is on me.) |
@mholt Thanks! 🙂 I didn't make any further progress today though… As far as I understand this it's trying to cleverly "replay" the response (headers) from the backend to the client, right? I can't for my life figure out why it doesn't properly handle the TLS data though. If you have some time left today it'd be nice if you could take a look ¹, since it proved to be a bit more complex for me personally than I thought initially (I'm new to Go! 😭). Otherwise I'll try to further debug it in the coming days, but of course I don't know how much time I can spend on it (due to Christmas). ¹ You can check out the new quick & dirty |
@lhecker Sorry, been a bit occupied with the holidays as well. :) Hope you're having a Merry Christmas! Yes, your understanding of the replay seems right, I think. The replay is there to avoid multiple/duplicate connections to the websocket backend. See #763 and #987. I'll take a look after the holidays as well, thanks so much for looking at this! I think you're making great progress. Definitely faster than I would have... |
@mholt After I submitted my other comment just now I immediately had a hunch how to solve this one. It's now fixed. lol A PR is coming soon. |
http.Transport instances whose
TLSClientConfig
,Dial
, orDialTLS
field is non-nil will be configured without HTTP/2 support by default.This PR adds the proper calls to
http2.ConfigureTransport()
everywhere a http.Transport is created and thus fixes HTTP/2 in the proxy middleware wheneverinsecure_skip_verify
orkeepalive
is provided.