github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/api/uaa/uaa_connection.go (about) 1 package uaa 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "crypto/x509" 7 "encoding/json" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "net/url" 12 "time" 13 ) 14 15 // UAAConnection represents the connection to UAA 16 type UAAConnection struct { 17 HTTPClient *http.Client 18 } 19 20 // NewConnection returns a pointer to a new UAA Connection 21 func NewConnection(skipSSLValidation bool, disableKeepAlives bool, dialTimeout time.Duration) *UAAConnection { 22 tr := &http.Transport{ 23 DialContext: (&net.Dialer{ 24 KeepAlive: 30 * time.Second, 25 Timeout: dialTimeout, 26 }).DialContext, 27 DisableKeepAlives: disableKeepAlives, 28 Proxy: http.ProxyFromEnvironment, 29 TLSClientConfig: &tls.Config{ 30 InsecureSkipVerify: skipSSLValidation, 31 }, 32 } 33 34 return &UAAConnection{ 35 HTTPClient: &http.Client{ 36 Transport: tr, 37 CheckRedirect: func(_ *http.Request, _ []*http.Request) error { 38 // This prevents redirects. When making a request to /oauth/authorize, 39 // the client should not follow redirects in order to obtain the ssh 40 // passcode. 41 return http.ErrUseLastResponse 42 }, 43 }, 44 } 45 } 46 47 // Make takes a passedRequest, converts it into an HTTP request and then 48 // executes it. The response is then injected into passedResponse. 49 func (connection *UAAConnection) Make(request *http.Request, passedResponse *Response) error { 50 // In case this function is called from a retry, passedResponse may already 51 // be populated with a previous response. We reset in case there's an HTTP 52 // error and we don't repopulate it in populateResponse. 53 passedResponse.reset() 54 55 response, err := connection.HTTPClient.Do(request) 56 if err != nil { 57 return connection.processRequestErrors(request, err) 58 } 59 60 return connection.populateResponse(response, passedResponse) 61 } 62 63 func (*UAAConnection) handleStatusCodes(response *http.Response, passedResponse *Response) error { 64 if response.StatusCode >= 400 { 65 return RawHTTPStatusError{ 66 StatusCode: response.StatusCode, 67 RawResponse: passedResponse.RawResponse, 68 } 69 } 70 71 return nil 72 } 73 74 func (connection *UAAConnection) populateResponse(response *http.Response, passedResponse *Response) error { 75 passedResponse.HTTPResponse = response 76 77 rawBytes, err := ioutil.ReadAll(response.Body) 78 defer response.Body.Close() 79 if err != nil { 80 return err 81 } 82 passedResponse.RawResponse = rawBytes 83 84 err = connection.handleStatusCodes(response, passedResponse) 85 if err != nil { 86 return err 87 } 88 89 if passedResponse.Result != nil { 90 decoder := json.NewDecoder(bytes.NewBuffer(passedResponse.RawResponse)) 91 decoder.UseNumber() 92 err = decoder.Decode(passedResponse.Result) 93 if err != nil { 94 return err 95 } 96 } 97 98 return nil 99 } 100 101 func (connection *UAAConnection) processRequestErrors(request *http.Request, err error) error { 102 switch e := err.(type) { 103 case *url.Error: 104 if _, ok := e.Err.(x509.UnknownAuthorityError); ok { 105 return UnverifiedServerError{ 106 URL: request.URL.String(), 107 } 108 } 109 return RequestError{Err: e} 110 default: 111 return err 112 } 113 }