elixir-mint / mint

Functional HTTP client for Elixir with support for HTTP/1 and HTTP/2 🌱
Apache License 2.0
1.36k stars 106 forks source link

omit :scheme and :path pseudo-headers in HTTP/2 CONNECT #322

Closed the-mikedavis closed 3 years ago

the-mikedavis commented 3 years ago

Hi again :slightly_smiling_face:

Like #321, this PR is for the sake of HTTP/2 bootstrap for WebSockets.

This PR makes two changes:

For the first part, I was skimming around rfc7540's section on the CONNECT method and found a MUST for CONNECT requests:

The ":scheme" and ":path" pseudo-header fields MUST be omitted.

The second part is for the sake of the WebSocket bootstrap: rfc8441's section on extending the CONNECT method adds "A new pseudo-header field :protocol..." and also says

On requests that contain the :protocol pseudo-header field, the :scheme and :path pseudo-header fields of the target URI (see Section 5) MUST also be included.

The difficulty is that with the current request/5 implementation, the user-agent header gets interspersed between any headers explicitly passed. For example:

headers = [{":protocol", "websocket"}]
Mint.HTTP.request(conn, "CONNECT", "/", headers, :stream)

Would end up with a set of headers like so:

:method CONNECT
:path /
:scheme http
:authority h2server:7070
user-agent mint/1.3.0
:protocol websocket

Which conflicts with rfc7540 section 8.1.2.1 on pseudo-header fields:

All pseudo-header fields MUST appear in the header block before regular header fields.

With these changes I'm getting some good results sending/receiving frames against an example h2 WebSocket fixture! :tada:

whatyouhide commented 3 years ago

Thanks @the-mikedavis! 💟