k8s.io/client-go@v0.31.1/transport/spdy/spdy.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package spdy 18 19 import ( 20 "fmt" 21 "net/http" 22 "net/url" 23 "time" 24 25 "k8s.io/apimachinery/pkg/util/httpstream" 26 "k8s.io/apimachinery/pkg/util/httpstream/spdy" 27 restclient "k8s.io/client-go/rest" 28 ) 29 30 // Upgrader validates a response from the server after a SPDY upgrade. 31 type Upgrader interface { 32 // NewConnection validates the response and creates a new Connection. 33 NewConnection(resp *http.Response) (httpstream.Connection, error) 34 } 35 36 // RoundTripperFor returns a round tripper and upgrader to use with SPDY. 37 func RoundTripperFor(config *restclient.Config) (http.RoundTripper, Upgrader, error) { 38 tlsConfig, err := restclient.TLSConfigFor(config) 39 if err != nil { 40 return nil, nil, err 41 } 42 proxy := http.ProxyFromEnvironment 43 if config.Proxy != nil { 44 proxy = config.Proxy 45 } 46 upgradeRoundTripper, err := spdy.NewRoundTripperWithConfig(spdy.RoundTripperConfig{ 47 TLS: tlsConfig, 48 Proxier: proxy, 49 PingPeriod: time.Second * 5, 50 UpgradeTransport: nil, 51 }) 52 if err != nil { 53 return nil, nil, err 54 } 55 wrapper, err := restclient.HTTPWrappersForConfig(config, upgradeRoundTripper) 56 if err != nil { 57 return nil, nil, err 58 } 59 return wrapper, upgradeRoundTripper, nil 60 } 61 62 // dialer implements the httpstream.Dialer interface. 63 type dialer struct { 64 client *http.Client 65 upgrader Upgrader 66 method string 67 url *url.URL 68 } 69 70 var _ httpstream.Dialer = &dialer{} 71 72 // NewDialer will create a dialer that connects to the provided URL and upgrades the connection to SPDY. 73 func NewDialer(upgrader Upgrader, client *http.Client, method string, url *url.URL) httpstream.Dialer { 74 return &dialer{ 75 client: client, 76 upgrader: upgrader, 77 method: method, 78 url: url, 79 } 80 } 81 82 func (d *dialer) Dial(protocols ...string) (httpstream.Connection, string, error) { 83 req, err := http.NewRequest(d.method, d.url.String(), nil) 84 if err != nil { 85 return nil, "", fmt.Errorf("error creating request: %v", err) 86 } 87 return Negotiate(d.upgrader, d.client, req, protocols...) 88 } 89 90 // Negotiate opens a connection to a remote server and attempts to negotiate 91 // a SPDY connection. Upon success, it returns the connection and the protocol selected by 92 // the server. The client transport must use the upgradeRoundTripper - see RoundTripperFor. 93 func Negotiate(upgrader Upgrader, client *http.Client, req *http.Request, protocols ...string) (httpstream.Connection, string, error) { 94 for i := range protocols { 95 req.Header.Add(httpstream.HeaderProtocolVersion, protocols[i]) 96 } 97 resp, err := client.Do(req) 98 if err != nil { 99 return nil, "", fmt.Errorf("error sending request: %v", err) 100 } 101 defer resp.Body.Close() 102 conn, err := upgrader.NewConnection(resp) 103 if err != nil { 104 return nil, "", err 105 } 106 return conn, resp.Header.Get(httpstream.HeaderProtocolVersion), nil 107 }