github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/http2/configure_transport.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build go1.6
     6  
     7  package http2
     8  
     9  import (
    10  	"crypto/tls"
    11  	"fmt"
    12  	"net/http"
    13  )
    14  
    15  func configureTransport(t1 *http.Transport) error {
    16  	connPool := new(clientConnPool)
    17  	t2 := &Transport{ConnPool: noDialClientConnPool{connPool}}
    18  	if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
    19  		return err
    20  	}
    21  	if t1.TLSClientConfig == nil {
    22  		t1.TLSClientConfig = new(tls.Config)
    23  	}
    24  	if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
    25  		t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
    26  	}
    27  	if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
    28  		t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
    29  	}
    30  	upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
    31  		cc, err := t2.NewClientConn(c)
    32  		if err != nil {
    33  			c.Close()
    34  			return erringRoundTripper{err}
    35  		}
    36  		connPool.addConn(authorityAddr(authority), cc)
    37  		return t2
    38  	}
    39  	if m := t1.TLSNextProto; len(m) == 0 {
    40  		t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
    41  			"h2": upgradeFn,
    42  		}
    43  	} else {
    44  		m["h2"] = upgradeFn
    45  	}
    46  	return nil
    47  }
    48  
    49  // registerHTTPSProtocol calls Transport.RegisterProtocol but
    50  // convering panics into errors.
    51  func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error) {
    52  	defer func() {
    53  		if e := recover(); e != nil {
    54  			err = fmt.Errorf("%v", e)
    55  		}
    56  	}()
    57  	t.RegisterProtocol("https", rt)
    58  	return nil
    59  }
    60  
    61  // noDialClientConnPool is an implementation of http2.ClientConnPool
    62  // which never dials.  We let the HTTP/1.1 client dial and use its TLS
    63  // connection instead.
    64  type noDialClientConnPool struct{ *clientConnPool }
    65  
    66  func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
    67  	const doDial = false
    68  	return p.getClientConn(req, addr, doDial)
    69  }
    70  
    71  // noDialH2RoundTripper is a RoundTripper which only tries to complete the request
    72  // if there's already has a cached connection to the host.
    73  type noDialH2RoundTripper struct{ t *Transport }
    74  
    75  func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
    76  	res, err := rt.t.RoundTrip(req)
    77  	if err == ErrNoCachedConn {
    78  		return nil, http.ErrSkipAltProtocol
    79  	}
    80  	return res, err
    81  }