@@ -13,7 +13,6 @@ import (
1313 "sync/atomic"
1414 "testing"
1515
16- "github.com/elazarl/goproxy"
1716 fixtures "github.com/go-git/go-git-fixtures/v5"
1817 "github.com/stretchr/testify/assert"
1918 "github.com/stretchr/testify/require"
@@ -39,9 +38,7 @@ type ProxySuite struct {
3938func (s * ProxySuite ) TestAdvertisedReferencesHTTP () {
4039 var proxiedRequests int32
4140
42- proxy := goproxy .NewProxyHttpServer ()
43-
44- setupHTTPProxy (proxy , & proxiedRequests )
41+ proxy := newTestProxy (& proxiedRequests )
4542
4643 httpProxyAddr := setupProxyServer (s .T (), proxy , false , true )
4744
@@ -76,8 +73,7 @@ func (s *ProxySuite) TestAdvertisedReferencesHTTP() {
7673func (s * ProxySuite ) TestAdvertisedReferencesHTTPS () {
7774 var proxiedRequests int32
7875
79- proxy := goproxy .NewProxyHttpServer ()
80- setupHTTPSProxy (proxy , & proxiedRequests )
76+ proxy := newTestProxy (& proxiedRequests )
8177
8278 httpsProxyAddr := setupProxyServer (s .T (), proxy , true , true )
8379
@@ -179,37 +175,111 @@ func setupProxyServer(t testing.TB, handler http.Handler, isTLS, schemaAddr bool
179175 return httpProxyAddr
180176}
181177
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 , "" )
178+ // testProxy is a minimal HTTP/HTTPS proxy for testing.
179+ type testProxy struct {
180+ proxiedRequests * int32
181+ }
182+
183+ func newTestProxy (proxiedRequests * int32 ) * testProxy {
184+ return & testProxy {proxiedRequests : proxiedRequests }
185+ }
186+
187+ func (p * testProxy ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
188+ // Check proxy authentication
189+ user , pass , _ := parseBasicAuth (r .Header .Get ("Proxy-Authorization" ))
190+ if user != "user" || pass != "pass" {
191+ http .Error (w , "Proxy Authentication Required" , http .StatusProxyAuthRequired )
192+ return
193+ }
194+
195+ if r .Method == http .MethodConnect {
196+ // HTTPS proxy: handle CONNECT requests
197+ p .handleConnect (w , r )
198+ } else {
199+ // HTTP proxy: forward the request
200+ p .handleHTTP (w , r )
195201 }
196- proxy .OnRequest ().Do (proxyHandler )
197202}
198203
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
204+ func (p * testProxy ) handleConnect (w http.ResponseWriter , r * http.Request ) {
205+ // Only allow connections to github.com for HTTPS tests
206+ if ! strings .Contains (r .Host , "github.com" ) && ! strings .Contains (r .Host , "localhost" ) {
207+ http .Error (w , "Forbidden" , http .StatusForbidden )
208+ return
209+ }
210+
211+ atomic .AddInt32 (p .proxiedRequests , 1 )
212+
213+ // Establish connection to the target
214+ targetConn , err := net .Dial ("tcp" , r .Host )
215+ if err != nil {
216+ http .Error (w , err .Error (), http .StatusServiceUnavailable )
217+ return
218+ }
219+
220+ // Send 200 Connection Established
221+ w .WriteHeader (http .StatusOK )
222+
223+ // Hijack the connection
224+ hijacker , ok := w .(http.Hijacker )
225+ if ! ok {
226+ http .Error (w , "Hijacking not supported" , http .StatusInternalServerError )
227+ targetConn .Close ()
228+ return
229+ }
230+
231+ clientConn , _ , err := hijacker .Hijack ()
232+ if err != nil {
233+ http .Error (w , err .Error (), http .StatusServiceUnavailable )
234+ targetConn .Close ()
235+ return
236+ }
237+
238+ // Tunnel data between client and target
239+ go func () {
240+ defer targetConn .Close ()
241+ defer clientConn .Close ()
242+ io .Copy (targetConn , clientConn )
243+ }()
244+ go func () {
245+ defer targetConn .Close ()
246+ defer clientConn .Close ()
247+ io .Copy (clientConn , targetConn )
248+ }()
249+ }
250+
251+ func (p * testProxy ) handleHTTP (w http.ResponseWriter , r * http.Request ) {
252+ // Only allow requests to localhost for HTTP tests
253+ if ! strings .Contains (r .Host , "localhost" ) {
254+ http .Error (w , "Forbidden" , http .StatusForbidden )
255+ return
256+ }
257+
258+ atomic .AddInt32 (p .proxiedRequests , 1 )
259+
260+ // Create a new request to the target
261+ outReq := r .Clone (r .Context ())
262+ outReq .RequestURI = ""
263+
264+ // Remove hop-by-hop headers
265+ outReq .Header .Del ("Proxy-Connection" )
266+ outReq .Header .Del ("Proxy-Authorization" )
267+
268+ resp , err := http .DefaultTransport .RoundTrip (outReq )
269+ if err != nil {
270+ http .Error (w , err .Error (), http .StatusBadGateway )
271+ return
272+ }
273+ defer resp .Body .Close ()
274+
275+ // Copy response headers
276+ for key , values := range resp .Header {
277+ for _ , value := range values {
278+ w .Header ().Add (key , value )
208279 }
209- // Reject if it isn't our request.
210- return goproxy .RejectConnect , host
211280 }
212- proxy .OnRequest ().HandleConnect (proxyHandler )
281+ w .WriteHeader (resp .StatusCode )
282+ io .Copy (w , resp .Body )
213283}
214284
215285// adapted from https://github.com/golang/go/blob/2ef70d9d0f98832c8103a7968b195e560a8bb262/src/net/http/request.go#L959
0 commit comments