golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
120.73k stars 17.33k forks source link

x/net/http2: support http2 proxy connections #26479

Open iaguis opened 5 years ago

iaguis commented 5 years ago

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.10.3 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="..."
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="..."
GORACE=""
GOROOT="/usr/lib/go"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build612803013=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I have an HTTP/2 proxy (I tested a custom one and https://github.com/caddyserver/forwardproxy) and when trying to connect through it from a client using HTTP/2 I get an error. This does not happen if I don't use HTTP/2.

Here's my code:

package main

import (
    "crypto/tls"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"

    "golang.org/x/net/http2"
)

func main() {
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        Proxy:           http.ProxyFromEnvironment,
    }

    if err := http2.ConfigureTransport(tr); err != nil {
        fmt.Fprintf(os.Stderr, "error configuring transport: %v\n", err)
        os.Exit(1)
    }

    client := &http.Client{Transport: tr}
    rsp, err := client.Get("https://google.com")
    if err != nil {
        fmt.Fprintf(os.Stderr, "error getting: %v\n", err)
        os.Exit(1)
    }
    defer rsp.Body.Close()

    buf, err := ioutil.ReadAll(rsp.Body)
    if err != nil {
        fmt.Fprintf(os.Stderr, "error reading response: %v\n", err)
        os.Exit(1)
    }

    fmt.Printf("Response: %s\n", string(buf))
}

If I comment out the http2.ConfigureTransport() call (so it will use HTTP/1.1) it works fine.

What did you expect to see?

A successful connection.

What did you see instead?

On the proxy server:

2018/07/19 18:30:25 http2: server connection from 127.0.0.1:54850 on 0xc420174b60
2018/07/19 18:30:25 http2: server: error reading preface from client 127.0.0.1:54850: bogus greeting "CONNECT google.com:443 H"

On the client:

2018/07/19 18:30:25 http2: Transport failed to get client conn for google.com:443: http2: no cached connection was available
error getting: Get https://google.com: malformed HTTP response "\x00\x00\x18\x04\x00\x00\x00\x00\x00\x00\x05\x00\x10\x00\x00\x00\x03\x00\x00\x00\xfa\x00\x06\x00\x10\x01@\x00\x04\x00\x10\x00\x00"
agnivade commented 5 years ago

Seems like a duplicate of https://github.com/golang/go/issues/21336 ?

/cc @bradfitz

bradfitz commented 5 years ago

I think they're different bugs.

This is more of a documentation or feature request to support http2 proxies. We only support http1 proxies currently.

shivakumargn commented 3 years ago

Is there any plan to support http2 proxy?

crowfrog commented 3 years ago

same question about plan for this feature. :)

g00nix commented 3 years ago

Currently most people implement HTTPS proxies in Go with http.Hijacker which does not support http2, which mostly means you have to disable http2 completely with TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)).

We can start to do some tricks and hack our way into getting it working, but official support from GoLang into this direction would be a lot better for everybody.

anupamasok commented 3 years ago

Currently most people implement HTTPS proxies in Go with http.Hijacker which does not support http2, which mostly means you have to disable http2 completely with TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)).

We can start to do some tricks and hack our way into getting it working, but official support from GoLang into this direction would be a lot better for everybody.

I was looking for a way to Achieve HTTP2 with proxy added. Details. Could you elaborate the "We can start to do some tricks and hack our way into getting it working" @g00nix

g00nix commented 3 years ago

I was looking for a way to Achieve HTTP2 with proxy added. Details. Could you elaborate the "We can start to do some tricks and hack our way into getting it working" @g00nix

We should be able to get a http2 proxy working by avoiding net/http completely and just going at a lower level to create the TCP connection and the TLS handshake. I managed to get it working for a transparent proxy, but never invested the time to get this done for a normal proxy.

However it would be better if this was just supported by the official lib, than having to completely rewrite the proxy functionality of net/http.

chew351 commented 2 years ago

Is there any plan to support http2 proxy?

Guys, Is there any plan to support http2 proxy? It’s helpfull for using net/http2 in a cluster

Thanks zcy

elgohr commented 2 years ago

I guess this dialer would be a good workaround for now https://github.com/mwitkow/go-http-dialer

fbuetler commented 3 months ago

This is still an issue with go 1.21. What is the roadmap for this feature? Is it a tricky one to implement?

We should be able to get a http2 proxy working by avoiding net/http completely and just going at a lower level to create the TCP connection and the TLS handshake.

We did the same for an explicit forward proxy.