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  }