// Transfer accepts connection on provided listener and eventually proxies them
// to the connections dialed on Proxy.UpstreamNetwork and Proxy.UpstreamAddr.
//
// It is designed to primarily work with TCP connections with HTTP requests on
// the accepting connections, as it sniffs for the type of data flowing through
// the proxied connections.
//
// If upstream server does not support TLS then the downstream request is
// directly proxied to upstream.
//
// If upstream server supports TLS and if downstream request starts with HTTPS
// connect byte (22), it is directly proxied to the upstream.
//
// If upstream server supports TLS and if downstream request is a valid HTTP
// request, with Upgrade-Insecure-Requests header set with value 1 then, it
// responds with http.StatusTemporaryRedirect with an appropriate Location
// header pointing to secure HTTPS resource. Whereas if the downstream request
// does not have header Upgrade-Insecure-Requests with value 1, then the request
// is directly proxied to upstream.
//
// If the upstream server supports TLS, and the downstream request is not a
// valid HTTP request, it is still transparently proxied to the upstream.
//
// When the proxy shutdown completes successfully, ie. all the listeners and
// all connections are closed then it returns ErrClosed.
Transfer accepts connection on provided listener and eventually proxies them
to the connections dialed on Proxy.UpstreamNetwork and Proxy.UpstreamAddr.

It is designed to primarily work with TCP connections with HTTP requests on
the accepting connections, as it sniffs for the type of data flowing through
the proxied connections.

If upstream server does not support TLS then the downstream request is
directly proxied to upstream.

If upstream server supports TLS and if downstream request starts with HTTPS
connect byte (22), it is directly proxied to the upstream.

If upstream server supports TLS and if downstream request is a valid HTTP
request, with Upgrade-Insecure-Requests header set with value 1 then, it
responds with http.StatusTemporaryRedirect with an appropriate Location
header pointing to secure HTTPS resource. Whereas if the downstream request
does not have header Upgrade-Insecure-Requests with value 1, then the request
is directly proxied to upstream.

If the upstream server supports TLS, and the downstream request is not a
valid HTTP request, it is still transparently proxied to the upstream.

When the proxy shutdown completes successfully, ie. all the listeners and
all connections are closed then it returns ErrClosed.
// Transfer accepts connection on provided listener and eventually proxies them // to the connections dialed on Proxy . UpstreamNetwork and Proxy . UpstreamAddr . // // It is designed to primarily work with TCP connections with HTTP requests on // the accepting connections as it sniffs for the type of data flowing through // the proxied connections . // // If upstream server does not support TLS then the downstream request is // directly proxied to upstream . // // If upstream server supports TLS and if downstream request starts with HTTPS // connect byte ( 22 ) it is directly proxied to the upstream . // // If upstream server supports TLS and if downstream request is a valid HTTP // request with Upgrade - Insecure - Requests header set with value 1 then it // responds with http . StatusTemporaryRedirect with an appropriate Location // header pointing to secure HTTPS resource . Whereas if the downstream request // does not have header Upgrade - Insecure - Requests with value 1 then the request // is directly proxied to upstream . // // If the upstream server supports TLS and the downstream request is not a // valid HTTP request it is still transparently proxied to the upstream . // // When the proxy shutdown completes successfully ie . all the listeners and // all connections are closed then it returns ErrClosed .
func (p *Proxy) Transfer(ln net.Listener) error {
	ctx := p.start()
	defer p.end()
	atomic.AddInt32(&p.running, 1)
	defer atomic.AddInt32(&p.running, -1)
	var wg sync.WaitGroup
	defer wg.Wait()
	ln = &onceCloseListener{Listener: ln}
	defer func() {
		if err := ln.Close(); err != nil {
			p.logErrf("proxy: upstream: listener close: %v", err)
		}
	}()
	if ok := p.trackListener(&ln); !ok {
		return ErrShuttingDown
	}
	defer p.unTrackListener(&ln)
	for {
		conn, err := ln.Accept()
		if err != nil {
			break
		}
		p.trackConn(&conn)
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer p.unTrackConn(&conn)
			ctx, cancel := context.WithCancel(ctx)
			defer cancel()
			if err := p.proxy(ctx, conn); err != nil {
				p.logErrf("proxy: %v", err)
			}
		}()
	}
	return ErrClosed
}
func ( p * Proxy ) Transfer ( ln net . Listener ) error { ctx := p . start ( ) defer p . end ( ) atomic . AddInt32 ( & p . running , 1 ) defer atomic . AddInt32 ( & p . running , - 1 ) var wg sync . WaitGroup defer wg . Wait ( ) ln = & onceCloseListener { Listener : ln } defer func ( ) { if err := ln . Close ( ) ; err != nil { p . logErrf ( " " , err ) } } ( ) if ok := p . trackListener ( & ln ) ; ! ok { return ErrShuttingDown } defer p . unTrackListener ( & ln ) for { conn , err := ln . Accept ( ) if err != nil { break } p . trackConn ( & conn ) wg . Add ( 1 ) go func ( ) { defer wg . Done ( ) defer p . unTrackConn ( & conn ) ctx , cancel := context . WithCancel ( ctx ) defer cancel ( ) if err := p . proxy ( ctx , conn ) ; err != nil { p . logErrf ( " " , err ) } } ( ) } return ErrClosed }
Transfer accepts connection on provided listener and eventually proxies them
to the connections dialed on Proxy.UpstreamNetwork and Proxy.UpstreamAddr.
Transfer accepts connection on provided listener and eventually proxies them to the connections dialed on Proxy . UpstreamNetwork and Proxy . UpstreamAddr .