diff options
author | Sanskar Jaiswal <jaiswalsanskar078@gmail.com> | 2023-04-28 17:17:00 +0530 |
---|---|---|
committer | Sanskar Jaiswal <jaiswalsanskar078@gmail.com> | 2023-05-04 11:53:09 +0530 |
commit | a830187d90a6bc36f9466c075ed49076f591efa9 (patch) | |
tree | 52c3450287073b3d8f65b2c001f9c7150cc66b9d /plumbing/transport/http/internal/test | |
parent | 399b1ec2d598b7950816727b8d92e8580553372c (diff) | |
download | go-git-a830187d90a6bc36f9466c075ed49076f591efa9.tar.gz |
plumbing: transport/http, add support for custom proxy URLs
Add support for custom HTTP and HTTPS proxies for each session.
The tests require server certificate and a matching private key to be
able to run a TLS server and test HTTPS proxy functionality. The cert
and the key are stored in `plumbing/transport/http/testdata/certs` and
were generated using the following command:
`openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt`
Note: All details were left empty, except for the FQDN for which
example.com was used.
Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
Diffstat (limited to 'plumbing/transport/http/internal/test')
-rw-r--r-- | plumbing/transport/http/internal/test/proxy_test.go | 72 | ||||
-rw-r--r-- | plumbing/transport/http/internal/test/test_utils.go | 43 |
2 files changed, 115 insertions, 0 deletions
diff --git a/plumbing/transport/http/internal/test/proxy_test.go b/plumbing/transport/http/internal/test/proxy_test.go new file mode 100644 index 0000000..6ae2943 --- /dev/null +++ b/plumbing/transport/http/internal/test/proxy_test.go @@ -0,0 +1,72 @@ +package test + +import ( + "context" + "crypto/tls" + "fmt" + "net" + nethttp "net/http" + "os" + "sync/atomic" + "testing" + + "github.com/elazarl/goproxy" + + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/plumbing/transport/http" + + . "gopkg.in/check.v1" +) + +// Hook up gocheck into the "go test" runner. +func Test(t *testing.T) { TestingT(t) } + +type ProxySuite struct{} + +var _ = Suite(&ProxySuite{}) + +var proxiedRequests int32 + +// This test tests proxy support via an env var, i.e. `HTTPS_PROXY`. +// Its located in a separate package because golang caches the value +// of proxy env vars leading to misleading/unexpected test results. +func (s *ProxySuite) TestAdvertisedReferences(c *C) { + proxy := goproxy.NewProxyHttpServer() + proxy.Verbose = true + SetupHTTPSProxy(proxy, &proxiedRequests) + httpsListener, err := net.Listen("tcp", ":0") + c.Assert(err, IsNil) + defer httpsListener.Close() + httpProxyAddr := fmt.Sprintf("localhost:%d", httpsListener.Addr().(*net.TCPAddr).Port) + + proxyServer := nethttp.Server{ + Addr: httpProxyAddr, + Handler: proxy, + // Due to how golang manages http/2 when provided with custom TLS config, + // servers and clients running in the same process leads to issues. + // Ref: https://github.com/golang/go/issues/21336 + TLSConfig: &tls.Config{ + NextProtos: []string{"http/1.1"}, + }, + } + go proxyServer.ServeTLS(httpsListener, "../../testdata/certs/server.crt", "../../testdata/certs/server.key") + defer proxyServer.Close() + os.Setenv("HTTPS_PROXY", fmt.Sprintf("https://user:pass@%s", httpProxyAddr)) + defer os.Unsetenv("HTTPS_PROXY") + + endpoint, err := transport.NewEndpoint("https://github.com/git-fixtures/basic.git") + c.Assert(err, IsNil) + endpoint.InsecureSkipTLS = true + + client := http.DefaultClient + session, err := client.NewUploadPackSession(endpoint, nil) + c.Assert(err, IsNil) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + info, err := session.AdvertisedReferencesContext(ctx) + c.Assert(err, IsNil) + c.Assert(info, NotNil) + proxyUsed := atomic.LoadInt32(&proxiedRequests) > 0 + c.Assert(proxyUsed, Equals, true) +} diff --git a/plumbing/transport/http/internal/test/test_utils.go b/plumbing/transport/http/internal/test/test_utils.go new file mode 100644 index 0000000..6665fb3 --- /dev/null +++ b/plumbing/transport/http/internal/test/test_utils.go @@ -0,0 +1,43 @@ +package test + +import ( + "encoding/base64" + "strings" + "sync/atomic" + + "github.com/elazarl/goproxy" +) + +func SetupHTTPSProxy(proxy *goproxy.ProxyHttpServer, proxiedRequests *int32) { + var proxyHandler goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { + if strings.Contains(host, "github.com") { + user, pass, _ := ParseBasicAuth(ctx.Req.Header.Get("Proxy-Authorization")) + if user != "user" || pass != "pass" { + return goproxy.RejectConnect, host + } + atomic.AddInt32(proxiedRequests, 1) + return goproxy.OkConnect, host + } + // Reject if it isn't our request. + return goproxy.RejectConnect, host + } + proxy.OnRequest().HandleConnect(proxyHandler) +} + +// adapted from https://github.com/golang/go/blob/2ef70d9d0f98832c8103a7968b195e560a8bb262/src/net/http/request.go#L959 +func ParseBasicAuth(auth string) (username, password string, ok bool) { + const prefix = "Basic " + if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) { + return "", "", false + } + c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) + if err != nil { + return "", "", false + } + cs := string(c) + username, password, ok = strings.Cut(cs, ":") + if !ok { + return "", "", false + } + return username, password, true +} |