@@ -50,12 +50,11 @@ import (
50
50
"errors"
51
51
"fmt"
52
52
"io"
53
- "net"
54
53
"net/http"
55
54
"net/url"
56
55
"sync"
57
- "time"
58
56
57
+ "github.com/fluxcd/source-controller/internal/transport"
59
58
git2go "github.com/libgit2/git2go/v33"
60
59
)
61
60
@@ -81,7 +80,8 @@ func httpSmartSubtransportFactory(remote *git2go.Remote, transport *git2go.Trans
81
80
}
82
81
83
82
type httpSmartSubtransport struct {
84
- transport * git2go.Transport
83
+ transport * git2go.Transport
84
+ httpTransport * http.Transport
85
85
}
86
86
87
87
func (t * httpSmartSubtransport ) Action (targetUrl string , action git2go.SmartServiceAction ) (git2go.SmartSubtransportStream , error ) {
@@ -104,25 +104,11 @@ func (t *httpSmartSubtransport) Action(targetUrl string, action git2go.SmartServ
104
104
proxyFn = http .ProxyURL (parsedUrl )
105
105
}
106
106
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
- }
107
+ // reuses the http transport from a pool, or create new one on demand.
108
+ t .httpTransport = transport .NewOrIdle (nil )
109
+ t .httpTransport .Proxy = proxyFn
124
110
125
- client , req , err := createClientRequest (targetUrl , action , httpTransport )
111
+ client , req , err := createClientRequest (targetUrl , action , t . httpTransport )
126
112
if err != nil {
127
113
return nil , err
128
114
}
@@ -291,6 +277,10 @@ func (self *httpSmartSubtransportStream) Write(buf []byte) (int, error) {
291
277
292
278
func (self * httpSmartSubtransportStream ) Free () {
293
279
if self .resp != nil {
280
+ // ensure body is fully processed and closed
281
+ // for increased likelihood of transport reuse in HTTP/1.x.
282
+ // it should not be a problem to do this more than once.
283
+ io .Copy (io .Discard , self .resp .Body )
294
284
self .resp .Body .Close ()
295
285
}
296
286
}
@@ -362,6 +352,11 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
362
352
// GET requests will be automatically redirected.
363
353
// POST require the new destination, and also the body content.
364
354
if req .Method == "POST" && resp .StatusCode >= 301 && resp .StatusCode <= 308 {
355
+ // ensure body is fully processed and closed
356
+ // for increased likelihood of transport reuse in HTTP/1.x.
357
+ io .Copy (io .Discard , resp .Body )
358
+ resp .Body .Close ()
359
+
365
360
// The next try will go against the new destination
366
361
self .req .URL , err = resp .Location ()
367
362
if err != nil {
@@ -371,15 +366,24 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
371
366
continue
372
367
}
373
368
369
+ // for HTTP 200, the response will be cleared up by Free()
374
370
if resp .StatusCode == http .StatusOK {
375
371
break
376
372
}
377
373
374
+ // ensure body is fully processed and closed
375
+ // for increased likelihood of transport reuse in HTTP/1.x.
378
376
io .Copy (io .Discard , resp .Body )
379
- defer resp .Body .Close ()
377
+ resp .Body .Close ()
378
+
380
379
return fmt .Errorf ("Unhandled HTTP error %s" , resp .Status )
381
380
}
382
381
382
+ if self .owner .httpTransport != nil {
383
+ transport .Release (self .owner .httpTransport )
384
+ self .owner .httpTransport = nil
385
+ }
386
+
383
387
self .resp = resp
384
388
self .sentRequest = true
385
389
return nil
0 commit comments