func (f *Forwarder) ServeHTTP(w http.ResponseWriter, req *http.Request) { start := time.Now().UTC() response, err := f.roundTripper.RoundTrip(f.copyRequest(req, req.URL)) if err != nil { f.log.Errorf("Error forwarding to %v, err: %v", req.URL, err) f.errHandler.ServeHTTP(w, req, err) return } if req.TLS != nil { f.log.Infof("Round trip: %v, code: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v", req.URL, response.StatusCode, time.Now().UTC().Sub(start), req.TLS.Version, req.TLS.DidResume, req.TLS.CipherSuite, req.TLS.ServerName) } else { f.log.Infof("Round trip: %v, code: %v, duration: %v", req.URL, response.StatusCode, time.Now().UTC().Sub(start)) } utils.CopyHeaders(w.Header(), response.Header) w.WriteHeader(response.StatusCode) written, _ := io.Copy(w, response.Body) if written != 0 { w.Header().Set(ContentLength, strconv.FormatInt(written, 10)) } response.Body.Close() }
func (f *Forwarder) copyRequest(req *http.Request, u *url.URL) *http.Request { outReq := new(http.Request) *outReq = *req // includes shallow copies of maps, but we handle this below outReq.URL = utils.CopyURL(req.URL) outReq.URL.Scheme = u.Scheme outReq.URL.Host = u.Host outReq.URL.Opaque = req.RequestURI // raw query is already included in RequestURI, so ignore it to avoid dupes outReq.URL.RawQuery = "" // Do not pass client Host header unless optsetter PassHostHeader is set. if f.passHost != true { outReq.Host = u.Host } outReq.Proto = "HTTP/1.1" outReq.ProtoMajor = 1 outReq.ProtoMinor = 1 // Overwrite close flag so we can keep persistent connection for the backend servers outReq.Close = false outReq.Header = make(http.Header) utils.CopyHeaders(outReq.Header, req.Header) if f.rewriter != nil { f.rewriter.Rewrite(outReq) } return outReq }
func Headers(h http.Header) ReqOption { return func(o *ReqOpts) error { if o.Headers == nil { o.Headers = make(http.Header) } utils.CopyHeaders(o.Headers, h) return nil } }
func MakeRequest(url string, opts ...ReqOption) (*http.Response, []byte, error) { o := &ReqOpts{} for _, s := range opts { if err := s(o); err != nil { return nil, nil, err } } if o.Method == "" { o.Method = "GET" } request, _ := http.NewRequest(o.Method, url, strings.NewReader(o.Body)) if o.Headers != nil { utils.CopyHeaders(request.Header, o.Headers) } if o.Auth != nil { request.Header.Set("Authorization", o.Auth.String()) } if len(o.Host) != 0 { request.Host = o.Host } var tr *http.Transport if strings.HasPrefix(url, "https") { tr = &http.Transport{ DisableKeepAlives: true, TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } } else { tr = &http.Transport{ DisableKeepAlives: true, } } client := &http.Client{ Transport: tr, CheckRedirect: func(req *http.Request, via []*http.Request) error { return fmt.Errorf("No redirects") }, } response, err := client.Do(request) if err == nil { bodyBytes, err := ioutil.ReadAll(response.Body) return response, bodyBytes, err } return response, nil, err }