github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/cf/net/http_client.go (about) 1 package net 2 3 import ( 4 _ "crypto/sha512" // #82254112: http://bridge.grumpy-troll.org/2014/05/golang-tls-comodo/ 5 "crypto/x509" 6 "fmt" 7 "net" 8 "net/http" 9 "net/url" 10 "strings" 11 12 "code.cloudfoundry.org/cli/cf/errors" 13 . "code.cloudfoundry.org/cli/cf/i18n" 14 "golang.org/x/net/websocket" 15 ) 16 17 //go:generate counterfeiter . HTTPClientInterface 18 19 type HTTPClientInterface interface { 20 RequestDumperInterface 21 22 Do(*http.Request) (*http.Response, error) 23 ExecuteCheckRedirect(req *http.Request, via []*http.Request) error 24 } 25 26 type client struct { 27 *http.Client 28 dumper RequestDumper 29 } 30 31 var NewHTTPClient = func(tr *http.Transport, dumper RequestDumper) HTTPClientInterface { 32 c := client{ 33 &http.Client{ 34 Transport: tr, 35 }, 36 dumper, 37 } 38 c.CheckRedirect = c.checkRedirect 39 40 return &c 41 } 42 43 func (cl *client) ExecuteCheckRedirect(req *http.Request, via []*http.Request) error { 44 return cl.CheckRedirect(req, via) 45 } 46 47 func (cl *client) checkRedirect(req *http.Request, via []*http.Request) error { 48 if len(via) > 1 { 49 return errors.New(T("stopped after 1 redirect")) 50 } 51 52 prevReq := via[len(via)-1] 53 cl.copyHeaders(prevReq, req, getBaseDomain(req.URL.String()) == getBaseDomain(via[0].URL.String())) 54 cl.dumper.DumpRequest(req) 55 56 return nil 57 } 58 59 func (cl *client) copyHeaders(from *http.Request, to *http.Request, sameDomain bool) { 60 for key, values := range from.Header { 61 // do not copy POST-specific headers 62 if key != "Content-Type" && key != "Content-Length" && !(!sameDomain && key == "Authorization") { 63 to.Header.Set(key, strings.Join(values, ",")) 64 } 65 } 66 } 67 68 func (cl *client) DumpRequest(req *http.Request) { 69 cl.dumper.DumpRequest(req) 70 } 71 72 func (cl *client) DumpResponse(res *http.Response) { 73 cl.dumper.DumpResponse(res) 74 } 75 76 func WrapNetworkErrors(host string, err error) error { 77 var innerErr error 78 switch typedErr := err.(type) { 79 case *url.Error: 80 innerErr = typedErr.Err 81 case *websocket.DialError: 82 innerErr = typedErr.Err 83 } 84 85 if innerErr != nil { 86 switch typedInnerErr := innerErr.(type) { 87 case x509.UnknownAuthorityError: 88 return errors.NewInvalidSSLCert(host, T("unknown authority")) 89 case x509.HostnameError: 90 return errors.NewInvalidSSLCert(host, T("not valid for the requested host")) 91 case x509.CertificateInvalidError: 92 return errors.NewInvalidSSLCert(host, "") 93 case *net.OpError: 94 if typedInnerErr.Op == "dial" { 95 return fmt.Errorf("%s: %s\n%s", T("Error performing request"), err.Error(), T("TIP: If you are behind a firewall and require an HTTP proxy, verify the https_proxy environment variable is correctly set. Else, check your network connection.")) 96 } 97 } 98 } 99 100 return fmt.Errorf("%s: %s", T("Error performing request"), err.Error()) 101 } 102 103 func getBaseDomain(host string) string { 104 hostURL, _ := url.Parse(host) 105 hostStrs := strings.Split(hostURL.Host, ".") 106 return hostStrs[len(hostStrs)-2] + "." + hostStrs[len(hostStrs)-1] 107 }