github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/uaa/uaa_connection.go (about) 1 package uaa 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 "errors" 13 14 "code.cloudfoundry.org/cli/util" 15 ) 16 17 // UAAConnection represents the connection to UAA 18 type UAAConnection struct { 19 HTTPClient *http.Client 20 } 21 22 // NewConnection returns a pointer to a new UAA Connection 23 func NewConnection(skipSSLValidation bool, disableKeepAlives bool, dialTimeout time.Duration) *UAAConnection { 24 tr := &http.Transport{ 25 DialContext: (&net.Dialer{ 26 KeepAlive: 30 * time.Second, 27 Timeout: dialTimeout, 28 }).DialContext, 29 DisableKeepAlives: disableKeepAlives, 30 Proxy: http.ProxyFromEnvironment, 31 TLSClientConfig: util.NewTLSConfig(nil, skipSSLValidation), 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 errors.As(err, &x509.UnknownAuthorityError{}) { 105 return UnverifiedServerError{ 106 URL: request.URL.String(), 107 } 108 } 109 return RequestError{Err: e} 110 default: 111 return err 112 } 113 }