k8s.io/client-go@v0.22.2/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 := spdy.NewRoundTripperWithConfig(spdy.RoundTripperConfig{ 47 TLS: tlsConfig, 48 FollowRedirects: true, 49 RequireSameHostRedirects: false, 50 Proxier: proxy, 51 PingPeriod: time.Second * 5, 52 }) 53 wrapper, err := restclient.HTTPWrappersForConfig(config, upgradeRoundTripper) 54 if err != nil { 55 return nil, nil, err 56 } 57 return wrapper, upgradeRoundTripper, nil 58 } 59 60 // dialer implements the httpstream.Dialer interface. 61 type dialer struct { 62 client *http.Client 63 upgrader Upgrader 64 method string 65 url *url.URL 66 } 67 68 var _ httpstream.Dialer = &dialer{} 69 70 // NewDialer will create a dialer that connects to the provided URL and upgrades the connection to SPDY. 71 func NewDialer(upgrader Upgrader, client *http.Client, method string, url *url.URL) httpstream.Dialer { 72 return &dialer{ 73 client: client, 74 upgrader: upgrader, 75 method: method, 76 url: url, 77 } 78 } 79 80 func (d *dialer) Dial(protocols ...string) (httpstream.Connection, string, error) { 81 req, err := http.NewRequest(d.method, d.url.String(), nil) 82 if err != nil { 83 return nil, "", fmt.Errorf("error creating request: %v", err) 84 } 85 return Negotiate(d.upgrader, d.client, req, protocols...) 86 } 87 88 // Negotiate opens a connection to a remote server and attempts to negotiate 89 // a SPDY connection. Upon success, it returns the connection and the protocol selected by 90 // the server. The client transport must use the upgradeRoundTripper - see RoundTripperFor. 91 func Negotiate(upgrader Upgrader, client *http.Client, req *http.Request, protocols ...string) (httpstream.Connection, string, error) { 92 for i := range protocols { 93 req.Header.Add(httpstream.HeaderProtocolVersion, protocols[i]) 94 } 95 resp, err := client.Do(req) 96 if err != nil { 97 return nil, "", fmt.Errorf("error sending request: %v", err) 98 } 99 defer resp.Body.Close() 100 conn, err := upgrader.NewConnection(resp) 101 if err != nil { 102 return nil, "", err 103 } 104 return conn, resp.Header.Get(httpstream.HeaderProtocolVersion), nil 105 }