mirror of
				https://github.com/traefik/traefik.git
				synced 2025-10-31 16:31:16 +01:00 
			
		
		
		
	Co-authored-by: Romain <rtribotte@users.noreply.github.com> Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
		
			
				
	
	
		
			79 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			79 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package service
 | |
| 
 | |
| import (
 | |
| 	"crypto/tls"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/traefik/traefik/v3/pkg/config/dynamic"
 | |
| 	"golang.org/x/net/http/httpguts"
 | |
| 	"golang.org/x/net/http2"
 | |
| )
 | |
| 
 | |
| type h2cTransportWrapper struct {
 | |
| 	*http2.Transport
 | |
| }
 | |
| 
 | |
| func (t *h2cTransportWrapper) RoundTrip(req *http.Request) (*http.Response, error) {
 | |
| 	req.URL.Scheme = "http"
 | |
| 	return t.Transport.RoundTrip(req)
 | |
| }
 | |
| 
 | |
| func newSmartRoundTripper(transport *http.Transport, forwardingTimeouts *dynamic.ForwardingTimeouts) (*smartRoundTripper, error) {
 | |
| 	transportHTTP1 := transport.Clone()
 | |
| 
 | |
| 	transportHTTP2, err := http2.ConfigureTransports(transport)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if forwardingTimeouts != nil {
 | |
| 		transportHTTP2.ReadIdleTimeout = time.Duration(forwardingTimeouts.ReadIdleTimeout)
 | |
| 		transportHTTP2.PingTimeout = time.Duration(forwardingTimeouts.PingTimeout)
 | |
| 	}
 | |
| 
 | |
| 	transportH2C := &h2cTransportWrapper{
 | |
| 		Transport: &http2.Transport{
 | |
| 			DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
 | |
| 				return net.Dial(network, addr)
 | |
| 			},
 | |
| 			AllowHTTP: true,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	if forwardingTimeouts != nil {
 | |
| 		transportH2C.ReadIdleTimeout = time.Duration(forwardingTimeouts.ReadIdleTimeout)
 | |
| 		transportH2C.PingTimeout = time.Duration(forwardingTimeouts.PingTimeout)
 | |
| 	}
 | |
| 
 | |
| 	transport.RegisterProtocol("h2c", transportH2C)
 | |
| 
 | |
| 	return &smartRoundTripper{
 | |
| 		http2: transport,
 | |
| 		http:  transportHTTP1,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // smartRoundTripper implements RoundTrip while making sure that HTTP/2 is not used
 | |
| // with protocols that start with a Connection Upgrade, such as SPDY or Websocket.
 | |
| type smartRoundTripper struct {
 | |
| 	http2 *http.Transport
 | |
| 	http  *http.Transport
 | |
| }
 | |
| 
 | |
| func (m *smartRoundTripper) Clone() http.RoundTripper {
 | |
| 	h := m.http.Clone()
 | |
| 	h2 := m.http2.Clone()
 | |
| 	return &smartRoundTripper{http: h, http2: h2}
 | |
| }
 | |
| 
 | |
| func (m *smartRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
 | |
| 	// If we have a connection upgrade, we don't use HTTP/2
 | |
| 	if httpguts.HeaderValuesContainsToken(req.Header["Connection"], "Upgrade") {
 | |
| 		return m.http.RoundTrip(req)
 | |
| 	}
 | |
| 
 | |
| 	return m.http2.RoundTrip(req)
 | |
| }
 |