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: expose streams as net.Conn #26574

Closed
iaguis opened this issue Jul 24, 2018 · 4 comments
Closed

x/net/http2: expose streams as net.Conn #26574

iaguis opened this issue Jul 24, 2018 · 4 comments

Comments

@iaguis
Copy link

@iaguis iaguis commented Jul 24, 2018

I’d like to have a way to expose individual streams as a net.Conn so I can implement a proxy that keeps a persistent HTTP/2 tunnel to an endpoint, receives HTTP/1 connections, and sends them to the remote endpoint through the HTTP/2 tunnel. In this way I can share 1 tcp connection with several streams.

Background

I’m trying to implement something like this:

client <-----> E1 <-----------------> E2 <-----> server
        HTTP/1     HTTP/2 connection      HTTP/1

So E1 would be a proxy server that keeps a connection to E2. Ideally, clients would send a regular CONNECT request to E1 and then the rest of the connection would be relayed through the HTTP/2 tunnel to E2 as HTTP/2 streams.

In regular proxies, I’d open a new TCP connection to E2 per CONNECT request and then just copy data between req.Body and the new TCP connection and vice-versa. In this case I want the HTTP/2 connection to be established already and just use a new stream per CONNECT request.

I tried implementing a custom ClientConnectionPool so I can get a ClientConn still in the pool but that only exposes RoundTrip() which I’m not sure how to use in this case: I have the r.Body from the client but how do I create a new Request with it so it gets sent via RoundTrip()? I saw this #17227 (comment) saying this feature would be kinda useless but I’m not sure I understand how to apply that to my use case, maybe I’m missing something obvious.

@andybons andybons added this to the Unplanned milestone Jul 24, 2018
@andybons

This comment has been minimized.

Copy link
Member

@andybons andybons commented Jul 24, 2018

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Jul 24, 2018

You already can:

Client:
#17227 (comment)

Server: e.g.

type flushWriter struct {  
        w io.Writer  
}  
  
func (fw flushWriter) Write(p []byte) (n int, err error) {  
        n, err = fw.w.Write(p)  
        if f, ok := fw.w.(http.Flusher); ok {  
                f.Flush()  
        }  
        return  
}  
  
func echoCapitalHandler(w http.ResponseWriter, r *http.Request) {  
        if r.Method != "PUT" {  
                http.Error(w, "PUT required.", 400)  
                return  
        }  
        if f, ok := w.(http.Flusher); ok {  
                f.Flush()  
        }  
        io.Copy(flushWriter{w}, capitalizeReader{r.Body})  
}  

What you describe is basically what https://www.backplane.io/ does (also in Go, but closed source).

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Jul 24, 2018

Anything to do here or can we close this?

@iaguis

This comment has been minimized.

Copy link
Author

@iaguis iaguis commented Jul 25, 2018

Thanks! I'll give it a go and reopen if anything is missing.

@iaguis iaguis closed this Jul 25, 2018
@golang golang locked and limited conversation to collaborators Jul 25, 2019
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.