github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/api/router/router_connection.go (about) 1 package router 2 3 import ( 4 "bytes" 5 "crypto/x509" 6 "encoding/json" 7 "io/ioutil" 8 "net" 9 "net/http" 10 "net/url" 11 "time" 12 13 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 14 "code.cloudfoundry.org/cli/api/router/routererror" 15 "code.cloudfoundry.org/cli/util" 16 ) 17 18 // ConnectionConfig is for configuring the RouterConnection 19 type ConnectionConfig struct { 20 DialTimeout time.Duration 21 SkipSSLValidation bool 22 } 23 24 // RouterConnection represents the connection to Router 25 type RouterConnection struct { 26 HTTPClient *http.Client 27 } 28 29 // NewConnection returns a pointer to a new RouterConnection with the provided configuration 30 func NewConnection(config ConnectionConfig) *RouterConnection { 31 tr := &http.Transport{ 32 TLSClientConfig: util.NewTLSConfig(nil, config.SkipSSLValidation), 33 Proxy: http.ProxyFromEnvironment, 34 DialContext: (&net.Dialer{ 35 KeepAlive: 30 * time.Second, 36 Timeout: config.DialTimeout, 37 }).DialContext, 38 } 39 40 return &RouterConnection{ 41 HTTPClient: &http.Client{Transport: tr}, 42 } 43 } 44 45 // Make performs the request and parses the response. 46 func (connection *RouterConnection) Make(request *Request, responseToPopulate *Response) error { 47 // In case this function is called from a retry, passedResponse may already 48 // be populated with a previous response. We reset in case there's an HTTP 49 // error and we don't repopulate it in populateResponse. 50 responseToPopulate.reset() 51 52 httpResponse, err := connection.HTTPClient.Do(request.Request) 53 if err != nil { 54 // request could not be made, e.g., ssl handshake or tcp dial timeout 55 return connection.processRequestErrors(request.Request, err) 56 } 57 58 return connection.populateResponse(httpResponse, responseToPopulate) 59 } 60 61 func (*RouterConnection) handleStatusCodes(httpResponse *http.Response, responseToPopulate *Response) error { 62 if httpResponse.StatusCode >= 400 { 63 return routererror.RawHTTPStatusError{ 64 StatusCode: httpResponse.StatusCode, 65 RawResponse: responseToPopulate.RawResponse, 66 } 67 } 68 return nil 69 } 70 71 func (connection *RouterConnection) populateResponse(httpResponse *http.Response, responseToPopulate *Response) error { 72 responseToPopulate.HTTPResponse = httpResponse 73 74 rawBytes, err := ioutil.ReadAll(httpResponse.Body) 75 defer httpResponse.Body.Close() 76 if err != nil { 77 return err 78 } 79 responseToPopulate.RawResponse = rawBytes 80 81 err = connection.handleStatusCodes(httpResponse, responseToPopulate) 82 if err != nil { 83 return err 84 } 85 86 if responseToPopulate.Result != nil { 87 decoder := json.NewDecoder(bytes.NewBuffer(responseToPopulate.RawResponse)) 88 decoder.UseNumber() 89 err = decoder.Decode(responseToPopulate.Result) 90 if err != nil { 91 return err 92 } 93 } 94 95 return nil 96 } 97 98 func (*RouterConnection) processRequestErrors(request *http.Request, err error) error { 99 switch e := err.(type) { 100 case *url.Error: 101 switch urlErr := e.Err.(type) { 102 case x509.UnknownAuthorityError: 103 return ccerror.UnverifiedServerError{ 104 URL: request.URL.String(), 105 } 106 case x509.HostnameError: 107 return ccerror.SSLValidationHostnameError{ 108 Message: urlErr.Error(), 109 } 110 default: 111 return ccerror.RequestError{Err: e} 112 } 113 default: 114 return err 115 } 116 }