Skip to content
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

x/net/http2: support CONNECT method #13717

Closed
ayanamist opened this issue Dec 23, 2015 · 10 comments
Closed

x/net/http2: support CONNECT method #13717

ayanamist opened this issue Dec 23, 2015 · 10 comments
Assignees
Milestone

Comments

@ayanamist
Copy link

@ayanamist ayanamist commented Dec 23, 2015

According to h2 spec https://httpwg.github.io/specs/rfc7540.html#CONNECT
If i want to implement a h2 proxy like nghttpx in golang, i have to use low-level h2 stream to send and receive data frame while multiplexing other normal get/post requests, but i found it can not be archieved in current h2 support.
Is there a way to expose such thing?

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Dec 23, 2015

See #13444 (comment)

I think that's all you have to do. You can stay in high-level Go and not think about frames.

We don't have any tests that Go's http2 server even accepts such CONNECT requests, though. It sounds like it could just work, though.

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Dec 23, 2015

Assigning to me to write a test for receiving and correctly mapping h2 CONNECT requests into *http.Requests.

@bradfitz bradfitz self-assigned this Dec 23, 2015
@bradfitz bradfitz added this to the Go1.6 milestone Dec 23, 2015
@gopherbot

This comment has been minimized.

Copy link

@gopherbot gopherbot commented Jan 5, 2016

CL https://golang.org/cl/18266 mentions this issue.

bradfitz added a commit to golang/net that referenced this issue Jan 6, 2016
Support CONNECT requests in both the server & transport.

See https://httpwg.github.io/specs/rfc7540.html#CONNECT

When I bundle this into the main Go repo I will also add h1-vs-h2
compatibility tests there, making sure they match behavior. (I now
expect that they do match)

Updates golang/go#13717

Change-Id: I0c65ad47b029419027efb616fed3d8e0e2a363f4
Reviewed-on: https://go-review.googlesource.com/18266
Reviewed-by: Andrew Gerrand <adg@golang.org>
@gopherbot

This comment has been minimized.

Copy link

@gopherbot gopherbot commented Jan 6, 2016

CL https://golang.org/cl/18269 mentions this issue.

@bradfitz bradfitz closed this in a4f27c4 Jan 6, 2016
@ayanamist

This comment has been minimized.

Copy link
Author

@ayanamist ayanamist commented Jan 6, 2016

@bradfitz I see changes, but i still can not use h2 client to proceed CONNECT request, when such request get a response, it needs to behave as a net.Conn to send & receive data like a socket. When used in http 1.1, we can use Hijacker to archive this, but i don't see such implementation in h2 client.

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Jan 6, 2016

With h2 you don't need to hijack. Just read and write from the provided ResponseWriter. See the first link I provided above for an example.

@ayanamist

This comment has been minimized.

Copy link
Author

@ayanamist ayanamist commented Jan 6, 2016

Oh i see the example which use io.Pipe, thank you!

@lysu

This comment has been minimized.

Copy link

@lysu lysu commented Apr 14, 2016

Hi~ @bradfitz I meet some problem like ayanamist, and want to implement a h2 proxy, too.... - -!

base on http://httpwg.org/specs/rfc7540.html#CONNECT and above comment..maybe we should do something like this? (without something like hijack????)

handler := func(rw http.ResponseWriter, req *http.Request) {
    if req.Method == "CONNECT" {
        // 1. receive CONNECT request..
        fmt.Println("Handle https")

        // 2. establishes a TCP connection to the server identified in the :authority
        remoteConn, err := net.Dial("tcp", req.Host)
        if err != nil {
            panic(err)
        }

        // 3. sends a HEADERS frame containing a 2xx series status code to the client, as defined in [RFC7231], Section 4.3.6
        rw.WriteHeader(http.StatusOK)

        // 4. transmitted DATA between client and TCP server
        go Pipe(&clientConn{Reader: req.Body, Writer: rw}, remoteConn)
    } else {
        fmt.Println("Handle as http")
        //...
    }
}

but, when we try proxy Chrome to this code using h2...it doesn't work

in chrome://net-internals see some log like this..

t=   27 [st=    0] +HTTP2_SESSION  [dt=42430]
                    --> host = "www.sulicc.com:443"
                    --> proxy = "DIRECT"
t=   27 [st=    0]    HTTP2_SESSION_INITIALIZED
                      --> protocol = "h2"
                      --> source_dependency = 546424 (SOCKET)
t=   27 [st=    0]    HTTP2_SESSION_SEND_SETTINGS
                      --> settings = ["[id:3 flags:0 value:1000]","[id:4 flags:0 value:6291456]"]
t=   27 [st=    0]    HTTP2_STREAM_UPDATE_RECV_WINDOW
                      --> delta = 15663105
                      --> window_size = 15728640
t=   27 [st=    0]    HTTP2_SESSION_SENT_WINDOW_UPDATE_FRAME
                      --> delta = 15663105
                      --> stream_id = 0
t=   27 [st=    0]    HTTP2_SESSION_SEND_HEADERS
                      --> fin = false
                      --> :method: CONNECT
                          :authority: imququ.com:443
                          user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
                      --> priority = 4
                      --> stream_id = 1
                      --> unidirectional = false
t=   27 [st=    0]    HTTP2_SESSION_RECV_SETTINGS
                      --> clear_persisted = false
                      --> host = "www.sulicc.com:443"
t=   27 [st=    0]    HTTP2_SESSION_RECV_SETTING
                      --> flags = 0
                      --> id = 5
                      --> value = 1048576
t=   27 [st=    0]    HTTP2_SESSION_RECV_SETTING
                      --> flags = 0
                      --> id = 3
                      --> value = 250
t=   27 [st=    0]    HTTP2_SESSION_RECV_SETTING
                      --> flags = 0
                      --> id = 6
                      --> value = 1048896
t= 1056 [st= 1029]    HTTP2_SESSION_RECV_HEADERS
                      --> fin = true
                      --> :status: 200
                          content-type: text/plain; charset=utf-8
                          content-length: 0
                          date: Thu, 14 Apr 2016 17:34:28 GMT
                      --> stream_id = 1
t= 1056 [st= 1029]    HTTP2_SESSION_RECV_DATA
                      --> fin = true
                      --> size = 0
                      --> stream_id = 1
t= 1056 [st= 1029]    HTTP2_SESSION_RST_STREAM
                      --> description = ""
                      --> status = 5
                      --> stream_id = 1
t= 1056 [st= 1029]    HTTP2_STREAM_ERROR
                      --> description = "SPDY stream closed with status: 5"
                      --> status = -337
                      --> stream_id = 1 

After CONNECT, it receive HEADERS

t= 1056 [st= 1029]    HTTP2_SESSION_RECV_HEADERS
                      --> fin = true
                      --> :status: 200
                          content-type: text/plain; charset=utf-8
                          content-length: 0
                          date: Thu, 14 Apr 2016 17:34:28 GMT
                      --> stream_id = 1 

then HTTP2_SESSION_RECV_DATA...and browser doesn't send any more data....

In http://httpwg.org/specs/rfc7231.html#CONNECT, it said

A server MUST NOT send any Transfer-Encoding or Content-Length header fields in a 2xx (Successful) response to CONNECT. A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT.

but rw.WriteHeader(http.StatusOK) still write a header content-length: 0... maybe it's a question?

without hijack, how can we write only httpcode and without header... just "HTTP/1.0 200 Connection established\r\n\r\n"?

thank you~

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Apr 14, 2016

Sorry, this bug is closed. If you have a bug report, please file a new bug with a complete repro and a description of the bug. General questions should go to https://golang.org/wiki/Questions.

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Sep 27, 2016

In #17227 (comment), @ayanamist thinks this bug still isn't solved. That was not my impression.

Can you not use http.Transport to do a CONNECT request with a io.Pipe Request.Body and simultaneously write to it while reading from the Response.Body?

@golang golang locked and limited conversation to collaborators Sep 27, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.