spdy.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package spdy
  15. import (
  16. "crypto/tls"
  17. "fmt"
  18. "net/http"
  19. "net/url"
  20. "yunion.io/x/onecloud/pkg/util/httpstream"
  21. "yunion.io/x/onecloud/pkg/util/httpstream/spdy"
  22. )
  23. // Upgrader validates a response from the server after a SPDY upgrade.
  24. type Upgrader interface {
  25. // NewConnection validates the response and creates a new Connection.
  26. NewConnection(resp *http.Response) (httpstream.Connection, error)
  27. }
  28. // RoundTripperFor returns a round tripper and upgrader to use with SPDY.
  29. func RoundTripperFor() (http.RoundTripper, Upgrader, error) {
  30. // TODO: implement: k8s.io/kubernetes/staging/src/k8s.io/client-go/transport/spdy/spdy.go
  31. tlsConfig := &tls.Config{
  32. InsecureSkipVerify: true,
  33. }
  34. upgradeRoundRipper := spdy.NewRoundTripper(tlsConfig, true, false)
  35. //return nil, upgradeRoundRipper, nil
  36. return upgradeRoundRipper, upgradeRoundRipper, nil
  37. }
  38. // dialer implements the httpstream.Dialer interface.
  39. type dialer struct {
  40. client *http.Client
  41. upgrader Upgrader
  42. method string
  43. url *url.URL
  44. }
  45. var _ httpstream.Dialer = &dialer{}
  46. // NewDialer will create a dialer that connects to the provided URL and upgrades the connection to SPDY.
  47. func NewDialer(upgrader Upgrader, client *http.Client, method string, url *url.URL) httpstream.Dialer {
  48. return &dialer{
  49. client: client,
  50. upgrader: upgrader,
  51. method: method,
  52. url: url,
  53. }
  54. }
  55. func (d dialer) Dial(protocols ...string) (httpstream.Connection, string, error) {
  56. req, err := http.NewRequest(d.method, d.url.String(), nil)
  57. if err != nil {
  58. return nil, "", fmt.Errorf("error creating request: %v", err)
  59. }
  60. return Negotiate(d.upgrader, d.client, req, protocols...)
  61. }
  62. // Negotiate opens a connection to a remote server and attempts to negotiate
  63. // a SPDY connection. Upon success, it returns the connection and the protocol selected by
  64. // the server. The client transport must use the upgradeRoundTripper - see RoundTripperFor.
  65. func Negotiate(upgrader Upgrader, client *http.Client, req *http.Request, protocols ...string) (httpstream.Connection, string, error) {
  66. for i := range protocols {
  67. req.Header.Add(httpstream.HeaderProtocolVersion, protocols[i])
  68. }
  69. resp, err := client.Do(req)
  70. if err != nil {
  71. return nil, "", fmt.Errorf("error sending request: %v", err)
  72. }
  73. defer resp.Body.Close()
  74. conn, err := upgrader.NewConnection(resp)
  75. if err != nil {
  76. return nil, "", err
  77. }
  78. return conn, resp.Header.Get(httpstream.HeaderProtocolVersion), nil
  79. }