mirror of
				https://github.com/traefik/traefik.git
				synced 2025-10-31 08:21:27 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			127 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package fast
 | |
| 
 | |
| import (
 | |
| 	"crypto/tls"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"reflect"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/traefik/traefik/v3/pkg/config/dynamic"
 | |
| 	"github.com/traefik/traefik/v3/pkg/config/static"
 | |
| )
 | |
| 
 | |
| // TransportManager manages transport used for backend communications.
 | |
| type TransportManager interface {
 | |
| 	Get(name string) (*dynamic.ServersTransport, error)
 | |
| 	GetTLSConfig(name string) (*tls.Config, error)
 | |
| }
 | |
| 
 | |
| // ProxyBuilder handles the connection pools for the FastProxy proxies.
 | |
| type ProxyBuilder struct {
 | |
| 	debug            bool
 | |
| 	transportManager TransportManager
 | |
| 
 | |
| 	// lock isn't needed because ProxyBuilder is not called concurrently.
 | |
| 	pools map[string]map[string]*connPool
 | |
| 	proxy func(*http.Request) (*url.URL, error)
 | |
| 
 | |
| 	// not goroutine safe.
 | |
| 	configs map[string]*dynamic.ServersTransport
 | |
| }
 | |
| 
 | |
| // NewProxyBuilder creates a new ProxyBuilder.
 | |
| func NewProxyBuilder(transportManager TransportManager, config static.FastProxyConfig) *ProxyBuilder {
 | |
| 	return &ProxyBuilder{
 | |
| 		debug:            config.Debug,
 | |
| 		transportManager: transportManager,
 | |
| 		pools:            make(map[string]map[string]*connPool),
 | |
| 		proxy:            http.ProxyFromEnvironment,
 | |
| 		configs:          make(map[string]*dynamic.ServersTransport),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Update updates all the round-tripper corresponding to the given configs.
 | |
| // This method must not be used concurrently.
 | |
| func (r *ProxyBuilder) Update(newConfigs map[string]*dynamic.ServersTransport) {
 | |
| 	for configName := range r.configs {
 | |
| 		if _, ok := newConfigs[configName]; !ok {
 | |
| 			for _, c := range r.pools[configName] {
 | |
| 				c.Close()
 | |
| 			}
 | |
| 			delete(r.pools, configName)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for newConfigName, newConfig := range newConfigs {
 | |
| 		if !reflect.DeepEqual(newConfig, r.configs[newConfigName]) {
 | |
| 			for _, c := range r.pools[newConfigName] {
 | |
| 				c.Close()
 | |
| 			}
 | |
| 			delete(r.pools, newConfigName)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	r.configs = newConfigs
 | |
| }
 | |
| 
 | |
| // Build builds a new ReverseProxy with the given configuration.
 | |
| func (r *ProxyBuilder) Build(cfgName string, targetURL *url.URL, passHostHeader, preservePath bool) (http.Handler, error) {
 | |
| 	proxyURL, err := r.proxy(&http.Request{URL: targetURL})
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("getting proxy: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	cfg, err := r.transportManager.Get(cfgName)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("getting ServersTransport: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	tlsConfig, err := r.transportManager.GetTLSConfig(cfgName)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("getting TLS config: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	pool := r.getPool(cfgName, cfg, tlsConfig, targetURL, proxyURL)
 | |
| 	return NewReverseProxy(targetURL, proxyURL, r.debug, passHostHeader, preservePath, pool)
 | |
| }
 | |
| 
 | |
| func (r *ProxyBuilder) getPool(cfgName string, config *dynamic.ServersTransport, tlsConfig *tls.Config, targetURL *url.URL, proxyURL *url.URL) *connPool {
 | |
| 	pool, ok := r.pools[cfgName]
 | |
| 	if !ok {
 | |
| 		pool = make(map[string]*connPool)
 | |
| 		r.pools[cfgName] = pool
 | |
| 	}
 | |
| 
 | |
| 	if connPool, ok := pool[targetURL.String()]; ok {
 | |
| 		return connPool
 | |
| 	}
 | |
| 
 | |
| 	idleConnTimeout := 90 * time.Second
 | |
| 	dialTimeout := 30 * time.Second
 | |
| 	var responseHeaderTimeout time.Duration
 | |
| 	if config.ForwardingTimeouts != nil {
 | |
| 		idleConnTimeout = time.Duration(config.ForwardingTimeouts.IdleConnTimeout)
 | |
| 		dialTimeout = time.Duration(config.ForwardingTimeouts.DialTimeout)
 | |
| 		responseHeaderTimeout = time.Duration(config.ForwardingTimeouts.ResponseHeaderTimeout)
 | |
| 	}
 | |
| 
 | |
| 	proxyDialer := newDialer(dialerConfig{
 | |
| 		DialKeepAlive: 0,
 | |
| 		DialTimeout:   dialTimeout,
 | |
| 		HTTP:          true,
 | |
| 		TLS:           targetURL.Scheme == "https",
 | |
| 		ProxyURL:      proxyURL,
 | |
| 	}, tlsConfig)
 | |
| 
 | |
| 	connPool := newConnPool(config.MaxIdleConnsPerHost, idleConnTimeout, responseHeaderTimeout, func() (net.Conn, error) {
 | |
| 		return proxyDialer.Dial("tcp", addrFromURL(targetURL))
 | |
| 	})
 | |
| 
 | |
| 	r.pools[cfgName][targetURL.String()] = connPool
 | |
| 
 | |
| 	return connPool
 | |
| }
 |