github.com/rakutentech/cli@v6.12.5-0.20151006231303-24468b65536e+incompatible/cf/net/http_client.go (about) 1 package net 2 3 import ( 4 _ "crypto/sha512" 5 "crypto/x509" 6 "net/http" 7 "net/http/httputil" 8 "net/url" 9 "strings" 10 "time" 11 12 "github.com/cloudfoundry/cli/cf/errors" 13 . "github.com/cloudfoundry/cli/cf/i18n" 14 "github.com/cloudfoundry/cli/cf/terminal" 15 "github.com/cloudfoundry/cli/cf/trace" 16 "golang.org/x/net/websocket" 17 ) 18 19 type HttpClientInterface interface { 20 Do(req *http.Request) (resp *http.Response, err error) 21 } 22 23 var NewHttpClient = func(tr *http.Transport) HttpClientInterface { 24 return &http.Client{ 25 Transport: tr, 26 CheckRedirect: PrepareRedirect, 27 } 28 } 29 30 func PrepareRedirect(req *http.Request, via []*http.Request) error { 31 if len(via) > 1 { 32 return errors.New(T("stopped after 1 redirect")) 33 } 34 35 prevReq := via[len(via)-1] 36 copyHeaders(prevReq, req, getBaseDomain(req.URL.String()) == getBaseDomain(via[0].URL.String())) 37 dumpRequest(req) 38 39 return nil 40 } 41 42 func copyHeaders(from *http.Request, to *http.Request, sameDomain bool) { 43 for key, values := range from.Header { 44 // do not copy POST-specific headers 45 if key != "Content-Type" && key != "Content-Length" && !(!sameDomain && key == "Authorization") { 46 to.Header.Set(key, strings.Join(values, ",")) 47 } 48 } 49 } 50 51 func dumpRequest(req *http.Request) { 52 shouldDisplayBody := !strings.Contains(req.Header.Get("Content-Type"), "multipart/form-data") 53 dumpedRequest, err := httputil.DumpRequest(req, shouldDisplayBody) 54 if err != nil { 55 trace.Logger.Printf(T("Error dumping request\n{{.Err}}\n", map[string]interface{}{"Err": err})) 56 } else { 57 trace.Logger.Printf("\n%s [%s]\n%s\n", terminal.HeaderColor(T("REQUEST:")), time.Now().Format(time.RFC3339), trace.Sanitize(string(dumpedRequest))) 58 if !shouldDisplayBody { 59 trace.Logger.Println(T("[MULTIPART/FORM-DATA CONTENT HIDDEN]")) 60 } 61 } 62 } 63 64 func dumpResponse(res *http.Response) { 65 dumpedResponse, err := httputil.DumpResponse(res, true) 66 if err != nil { 67 trace.Logger.Printf(T("Error dumping response\n{{.Err}}\n", map[string]interface{}{"Err": err})) 68 } else { 69 trace.Logger.Printf("\n%s [%s]\n%s\n", terminal.HeaderColor(T("RESPONSE:")), time.Now().Format(time.RFC3339), trace.Sanitize(string(dumpedResponse))) 70 } 71 } 72 73 func WrapNetworkErrors(host string, err error) error { 74 var innerErr error 75 switch typedErr := err.(type) { 76 case *url.Error: 77 innerErr = typedErr.Err 78 case *websocket.DialError: 79 innerErr = typedErr.Err 80 } 81 82 if innerErr != nil { 83 switch innerErr.(type) { 84 case x509.UnknownAuthorityError: 85 return errors.NewInvalidSSLCert(host, T("unknown authority")) 86 case x509.HostnameError: 87 return errors.NewInvalidSSLCert(host, T("not valid for the requested host")) 88 case x509.CertificateInvalidError: 89 return errors.NewInvalidSSLCert(host, "") 90 } 91 } 92 93 return errors.NewWithError(T("Error performing request"), err) 94 95 } 96 97 func getBaseDomain(host string) string { 98 hostUrl, _ := url.Parse(host) 99 hostStrs := strings.Split(hostUrl.Host, ".") 100 return hostStrs[len(hostStrs)-2] + "." + hostStrs[len(hostStrs)-1] 101 }