diff options
author | Martin Polden <mpolden@mpolden.no> | 2023-04-04 14:10:24 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2023-04-11 10:27:09 +0200 |
commit | 0784bd1d2b2c887897b7750281a54ab57cb6badf (patch) | |
tree | a990a265a41ed23d5ca2df1c19b375a37641722c | |
parent | 572c7aca0aa865fb9ae3c211156dfa9efb8e548f (diff) |
Always use HTTP/2 when feeding
-rw-r--r-- | client/go/internal/cli/cmd/feed.go | 1 | ||||
-rw-r--r-- | client/go/internal/util/http.go | 66 | ||||
-rw-r--r-- | client/go/internal/vespa/target.go | 9 |
3 files changed, 46 insertions, 30 deletions
diff --git a/client/go/internal/cli/cmd/feed.go b/client/go/internal/cli/cmd/feed.go index c8e032929b8..97bee293077 100644 --- a/client/go/internal/cli/cmd/feed.go +++ b/client/go/internal/cli/cmd/feed.go @@ -56,6 +56,7 @@ func feed(r io.Reader, cli *CLI, concurrency int) error { if err != nil { return err } + service.ForceHTTP2() // Feeding should always use HTTP/2 client := document.NewClient(document.ClientOptions{ BaseURL: service.BaseURL, }, service) diff --git a/client/go/internal/util/http.go b/client/go/internal/util/http.go index cb35932c8e7..b1646b06a80 100644 --- a/client/go/internal/util/http.go +++ b/client/go/internal/util/http.go @@ -2,9 +2,10 @@ package util import ( - "bytes" + "context" "crypto/tls" "fmt" + "net" "net/http" "time" @@ -36,45 +37,50 @@ func SetCertificate(client HTTPClient, certificates []tls.Certificate) { if !ok { return } - // Use HTTP/2 transport explicitly. Connection reuse does not work properly when using regular http.Transport, even - // though it upgrades to HTTP/2 automatically - // https://github.com/golang/go/issues/16582 - // https://github.com/golang/go/issues/22091 - var transport *http2.Transport - if _, ok := c.client.Transport.(*http.Transport); ok { - transport = &http2.Transport{} - c.client.Transport = transport - } else if t, ok := c.client.Transport.(*http2.Transport); ok { - transport = t - } else { - panic(fmt.Sprintf("unknown transport type: %T", c.client.Transport)) - } - if ok && !c.hasCertificates(transport.TLSClientConfig, certificates) { - transport.TLSClientConfig = &tls.Config{ + var tlsConfig *tls.Config = nil + if certificates != nil { + tlsConfig = &tls.Config{ Certificates: certificates, MinVersion: tls.VersionTLS12, } } + if tr, ok := c.client.Transport.(*http.Transport); ok { + tr.TLSClientConfig = tlsConfig + } else if tr, ok := c.client.Transport.(*http2.Transport); ok { + tr.TLSClientConfig = tlsConfig + } else { + panic(fmt.Sprintf("unknown transport type: %T", c.client.Transport)) + } } -func (c *defaultHTTPClient) hasCertificates(tlsConfig *tls.Config, certs []tls.Certificate) bool { - if tlsConfig == nil { - return false - } - if len(tlsConfig.Certificates) != len(certs) { - return false +func ForceHTTP2(client HTTPClient, certificates []tls.Certificate) { + c, ok := client.(*defaultHTTPClient) + if !ok { + return } - for i := 0; i < len(certs); i++ { - if len(tlsConfig.Certificates[i].Certificate) != len(certs[i].Certificate) { - return false + var tlsConfig *tls.Config = nil + var dialFunc func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) + if certificates != nil { + tlsConfig = &tls.Config{ + Certificates: certificates, + MinVersion: tls.VersionTLS12, } - for j := 0; j < len(certs[i].Certificate); j++ { - if !bytes.Equal(tlsConfig.Certificates[i].Certificate[j], certs[i].Certificate[j]) { - return false - } + } else { + // No certificate, so force H2C (HTTP/2 over clear-text) by using a non-TLS Dialer + dialer := net.Dialer{} + dialFunc = func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { + return dialer.DialContext(ctx, network, addr) } } - return true + // Use HTTP/2 transport explicitly. Connection reuse does not work properly when using regular http.Transport, even + // though it upgrades to HTTP/2 automatically + // https://github.com/golang/go/issues/16582 + // https://github.com/golang/go/issues/22091 + c.client.Transport = &http2.Transport{ + AllowHTTP: true, + TLSClientConfig: tlsConfig, + DialTLSContext: dialFunc, + } } func CreateClient(timeout time.Duration) HTTPClient { diff --git a/client/go/internal/vespa/target.go b/client/go/internal/vespa/target.go index 51861eb12ab..1ad36b1d799 100644 --- a/client/go/internal/vespa/target.go +++ b/client/go/internal/vespa/target.go @@ -119,6 +119,15 @@ func (s *Service) Wait(timeout time.Duration) (int, error) { return waitForOK(s.httpClient, url, s.TLSOptions.KeyPair, timeout) } +// ForceHTTP2 forces the underlying HTTP client to use HTTP/2. +func (s *Service) ForceHTTP2() { + var certs []tls.Certificate + if s.TLSOptions.KeyPair != nil { + certs = []tls.Certificate{*s.TLSOptions.KeyPair} + } + util.ForceHTTP2(s.httpClient, certs) +} + func (s *Service) Description() string { switch s.Name { case QueryService: |