Skip to content

Commit 321eb5f

Browse files
committed
*: drop goproxy dependency
Assuming go-git is a library and so it's better to use minimal dependencies. github.com/elazarl/goproxy is only used by tests, adding a tiny implementation enables us to drop it. Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
1 parent 22c365f commit 321eb5f

File tree

3 files changed

+122
-35
lines changed

3 files changed

+122
-35
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ require (
77
github.com/Microsoft/go-winio v0.6.2
88
github.com/ProtonMail/go-crypto v1.3.0
99
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
10-
github.com/elazarl/goproxy v1.7.2
1110
github.com/emirpasic/gods v1.18.1
1211
github.com/gliderlabs/ssh v0.3.8
1312
github.com/go-git/gcfg/v2 v2.0.2

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1
1414
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1515
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1616
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
17-
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
18-
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
1917
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
2018
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
2119
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=

plumbing/transport/http/proxy_test.go

Lines changed: 122 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import (
1010
"net"
1111
"net/http"
1212
"strings"
13+
"sync"
1314
"sync/atomic"
1415
"testing"
1516

16-
"github.com/elazarl/goproxy"
1717
fixtures "github.com/go-git/go-git-fixtures/v5"
1818
"github.com/stretchr/testify/assert"
1919
"github.com/stretchr/testify/require"
@@ -39,9 +39,7 @@ type ProxySuite struct {
3939
func (s *ProxySuite) TestAdvertisedReferencesHTTP() {
4040
var proxiedRequests int32
4141

42-
proxy := goproxy.NewProxyHttpServer()
43-
44-
setupHTTPProxy(proxy, &proxiedRequests)
42+
proxy := newTestProxy(&proxiedRequests)
4543

4644
httpProxyAddr := setupProxyServer(s.T(), proxy, false, true)
4745

@@ -76,8 +74,7 @@ func (s *ProxySuite) TestAdvertisedReferencesHTTP() {
7674
func (s *ProxySuite) TestAdvertisedReferencesHTTPS() {
7775
var proxiedRequests int32
7876

79-
proxy := goproxy.NewProxyHttpServer()
80-
setupHTTPSProxy(proxy, &proxiedRequests)
77+
proxy := newTestProxy(&proxiedRequests)
8178

8279
httpsProxyAddr := setupProxyServer(s.T(), proxy, true, true)
8380

@@ -179,37 +176,130 @@ func setupProxyServer(t testing.TB, handler http.Handler, isTLS, schemaAddr bool
179176
return httpProxyAddr
180177
}
181178

182-
func setupHTTPProxy(proxy *goproxy.ProxyHttpServer, proxiedRequests *int32) {
183-
// The request is being forwarded to the local test git server in this handler.
184-
var proxyHandler goproxy.FuncReqHandler = func(req *http.Request, _ *goproxy.ProxyCtx) (*http.Request, *http.Response) {
185-
if strings.Contains(req.Host, "localhost") {
186-
user, pass, _ := parseBasicAuth(req.Header.Get("Proxy-Authorization"))
187-
if user != "user" || pass != "pass" {
188-
return req, goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusUnauthorized, "")
189-
}
190-
atomic.AddInt32(proxiedRequests, 1)
191-
return req, nil
192-
}
193-
// Reject if it isn't our request.
194-
return req, goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusForbidden, "")
179+
// testProxy is a minimal HTTP/HTTPS proxy for testing.
180+
type testProxy struct {
181+
proxiedRequests *int32
182+
}
183+
184+
func newTestProxy(proxiedRequests *int32) *testProxy {
185+
return &testProxy{proxiedRequests: proxiedRequests}
186+
}
187+
188+
func (p *testProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
189+
// Check proxy authentication
190+
user, pass, _ := parseBasicAuth(r.Header.Get("Proxy-Authorization"))
191+
if user != "user" || pass != "pass" {
192+
http.Error(w, "Proxy Authentication Required", http.StatusProxyAuthRequired)
193+
return
194+
}
195+
196+
if r.Method == http.MethodConnect {
197+
// HTTPS proxy: handle CONNECT requests
198+
p.handleConnect(w, r)
199+
} else {
200+
// HTTP proxy: forward the request
201+
p.handleHTTP(w, r)
195202
}
196-
proxy.OnRequest().Do(proxyHandler)
197203
}
198204

199-
func setupHTTPSProxy(proxy *goproxy.ProxyHttpServer, proxiedRequests *int32) {
200-
var proxyHandler goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
201-
if strings.Contains(host, "github.com") {
202-
user, pass, _ := parseBasicAuth(ctx.Req.Header.Get("Proxy-Authorization"))
203-
if user != "user" || pass != "pass" {
204-
return goproxy.RejectConnect, host
205-
}
206-
atomic.AddInt32(proxiedRequests, 1)
207-
return goproxy.OkConnect, host
205+
func (p *testProxy) handleConnect(w http.ResponseWriter, r *http.Request) {
206+
// Only allow connections to github.com for HTTPS tests
207+
if !strings.Contains(r.Host, "github.com") && !strings.Contains(r.Host, "localhost") {
208+
http.Error(w, "Forbidden", http.StatusForbidden)
209+
return
210+
}
211+
212+
atomic.AddInt32(p.proxiedRequests, 1)
213+
214+
// Establish connection to the target
215+
targetConn, err := net.Dial("tcp", r.Host)
216+
if err != nil {
217+
http.Error(w, err.Error(), http.StatusServiceUnavailable)
218+
return
219+
}
220+
221+
// Hijack the connection first
222+
hijacker, ok := w.(http.Hijacker)
223+
if !ok {
224+
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
225+
targetConn.Close()
226+
return
227+
}
228+
229+
clientConn, _, err := hijacker.Hijack()
230+
if err != nil {
231+
http.Error(w, err.Error(), http.StatusServiceUnavailable)
232+
targetConn.Close()
233+
return
234+
}
235+
236+
// Send 200 Connection Established response manually after hijacking
237+
_, err = clientConn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
238+
if err != nil {
239+
targetConn.Close()
240+
clientConn.Close()
241+
return
242+
}
243+
244+
// Tunnel data between client and target.
245+
// Use one goroutine for client->target, current goroutine for target->client.
246+
var wg sync.WaitGroup
247+
wg.Add(1)
248+
go func() {
249+
defer wg.Done()
250+
_, _ = io.Copy(targetConn, clientConn)
251+
targetConn.Close() // Signal EOF to the other direction
252+
}()
253+
254+
_, _ = io.Copy(clientConn, targetConn)
255+
clientConn.Close() // Signal EOF to the other direction
256+
257+
wg.Wait()
258+
}
259+
260+
func (p *testProxy) handleHTTP(w http.ResponseWriter, r *http.Request) {
261+
// Only allow requests to localhost for HTTP tests
262+
if !strings.Contains(r.Host, "localhost") {
263+
http.Error(w, "Forbidden", http.StatusForbidden)
264+
return
265+
}
266+
267+
atomic.AddInt32(p.proxiedRequests, 1)
268+
269+
// Create a new request to the target
270+
outReq := r.Clone(r.Context())
271+
outReq.RequestURI = ""
272+
273+
// Remove hop-by-hop headers
274+
hopHeaders := []string{
275+
"Connection",
276+
"Proxy-Connection", // non-standard but still sent by some proxies
277+
"Keep-Alive",
278+
"Proxy-Authorization",
279+
"TE",
280+
"Trailer",
281+
"Transfer-Encoding",
282+
"Upgrade",
283+
}
284+
for _, h := range hopHeaders {
285+
outReq.Header.Del(h)
286+
}
287+
288+
resp, err := http.DefaultTransport.RoundTrip(outReq)
289+
if err != nil {
290+
http.Error(w, err.Error(), http.StatusBadGateway)
291+
return
292+
}
293+
defer resp.Body.Close()
294+
295+
// Copy response headers
296+
for key, values := range resp.Header {
297+
for _, value := range values {
298+
w.Header().Add(key, value)
208299
}
209-
// Reject if it isn't our request.
210-
return goproxy.RejectConnect, host
211300
}
212-
proxy.OnRequest().HandleConnect(proxyHandler)
301+
w.WriteHeader(resp.StatusCode)
302+
_, _ = io.Copy(w, resp.Body)
213303
}
214304

215305
// adapted from https://github.com/golang/go/blob/2ef70d9d0f98832c8103a7968b195e560a8bb262/src/net/http/request.go#L959

0 commit comments

Comments
 (0)