@@ -50,12 +50,11 @@ import (
5050 "errors"
5151 "fmt"
5252 "io"
53- "net"
5453 "net/http"
5554 "net/url"
5655 "sync"
57- "time"
5856
57+ pool "github.com/fluxcd/source-controller/internal/transport"
5958 git2go "github.com/libgit2/git2go/v33"
6059)
6160
@@ -73,15 +72,18 @@ func registerManagedHTTP() error {
7372}
7473
7574func httpSmartSubtransportFactory (remote * git2go.Remote , transport * git2go.Transport ) (git2go.SmartSubtransport , error ) {
75+ traceLog .Info ("[http]: httpSmartSubtransportFactory" )
7676 sst := & httpSmartSubtransport {
77- transport : transport ,
77+ transport : transport ,
78+ httpTransport : pool .NewOrIdle (nil ),
7879 }
7980
8081 return sst , nil
8182}
8283
8384type httpSmartSubtransport struct {
84- transport * git2go.Transport
85+ transport * git2go.Transport
86+ httpTransport * http.Transport
8587}
8688
8789func (t * httpSmartSubtransport ) Action (targetUrl string , action git2go.SmartServiceAction ) (git2go.SmartSubtransportStream , error ) {
@@ -104,25 +106,10 @@ func (t *httpSmartSubtransport) Action(targetUrl string, action git2go.SmartServ
104106 proxyFn = http .ProxyURL (parsedUrl )
105107 }
106108
107- httpTransport := & http.Transport {
108- // Add the proxy to the http transport.
109- Proxy : proxyFn ,
110-
111- // Set reasonable timeouts to ensure connections are not
112- // left open in an idle state, nor they hang indefinitely.
113- //
114- // These are based on the official go http.DefaultTransport:
115- DialContext : (& net.Dialer {
116- Timeout : 30 * time .Second ,
117- KeepAlive : 30 * time .Second ,
118- }).DialContext ,
119- MaxIdleConns : 100 ,
120- IdleConnTimeout : 90 * time .Second ,
121- TLSHandshakeTimeout : 10 * time .Second ,
122- ExpectContinueTimeout : 1 * time .Second ,
123- }
109+ t .httpTransport .Proxy = proxyFn
110+ t .httpTransport .DisableCompression = false
124111
125- client , req , err := createClientRequest (targetUrl , action , httpTransport )
112+ client , req , err := createClientRequest (targetUrl , action , t . httpTransport )
126113 if err != nil {
127114 return nil , err
128115 }
@@ -223,10 +210,18 @@ func createClientRequest(targetUrl string, action git2go.SmartServiceAction, t *
223210}
224211
225212func (t * httpSmartSubtransport ) Close () error {
213+ traceLog .Info ("[http]: httpSmartSubtransport.Close()" )
226214 return nil
227215}
228216
229217func (t * httpSmartSubtransport ) Free () {
218+ traceLog .Info ("[http]: httpSmartSubtransport.Free()" )
219+
220+ if t .httpTransport != nil {
221+ traceLog .Info ("[http]: release http transport back to pool" )
222+ pool .Release (t .httpTransport )
223+ t .httpTransport = nil
224+ }
230225}
231226
232227type httpSmartSubtransportStream struct {
@@ -291,7 +286,15 @@ func (self *httpSmartSubtransportStream) Write(buf []byte) (int, error) {
291286
292287func (self * httpSmartSubtransportStream ) Free () {
293288 if self .resp != nil {
294- self .resp .Body .Close ()
289+ traceLog .Info ("[http]: httpSmartSubtransportStream.Free()" )
290+
291+ if self .resp .Body != nil {
292+ // ensure body is fully processed and closed
293+ // for increased likelihood of transport reuse in HTTP/1.x.
294+ // it should not be a problem to do this more than once.
295+ _ , _ = io .Copy (io .Discard , self .resp .Body ) // errors can be safely ignored
296+ _ = self .resp .Body .Close () // errors can be safely ignored
297+ }
295298 }
296299}
297300
@@ -354,6 +357,7 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
354357 }
355358
356359 req .SetBasicAuth (userName , password )
360+ traceLog .Info ("[http]: new request" , "method" , req .Method , "URL" , req .URL )
357361 resp , err = self .client .Do (req )
358362 if err != nil {
359363 return err
@@ -362,21 +366,36 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
362366 // GET requests will be automatically redirected.
363367 // POST require the new destination, and also the body content.
364368 if req .Method == "POST" && resp .StatusCode >= 301 && resp .StatusCode <= 308 {
369+ // ensure body is fully processed and closed
370+ // for increased likelihood of transport reuse in HTTP/1.x.
371+ _ , _ = io .Copy (io .Discard , resp .Body ) // errors can be safely ignored
372+
373+ if err := resp .Body .Close (); err != nil {
374+ return err
375+ }
376+
365377 // The next try will go against the new destination
366378 self .req .URL , err = resp .Location ()
367379 if err != nil {
368380 return err
369381 }
370382
383+ traceLog .Info ("[http]: POST redirect" , "URL" , self .req .URL )
371384 continue
372385 }
373386
387+ // for HTTP 200, the response will be cleared up by Free()
374388 if resp .StatusCode == http .StatusOK {
375389 break
376390 }
377391
378- io .Copy (io .Discard , resp .Body )
379- defer resp .Body .Close ()
392+ // ensure body is fully processed and closed
393+ // for increased likelihood of transport reuse in HTTP/1.x.
394+ _ , _ = io .Copy (io .Discard , resp .Body ) // errors can be safely ignored
395+ if err := resp .Body .Close (); err != nil {
396+ return err
397+ }
398+
380399 return fmt .Errorf ("Unhandled HTTP error %s" , resp .Status )
381400 }
382401
0 commit comments