func (p *ReverseProxy) doRequestFor(rw http.ResponseWriter, req *http.Request, upstream types.Upstream) (*http.Response, error) { outreq, err := p.getOutRequest(rw, req, upstream) if err != nil { return nil, err } return upstream.RoundTrip(outreq) }
func (p *ReverseProxy) getOutRequest(rw http.ResponseWriter, req *http.Request, upstream types.Upstream) (*http.Request, error) { outreq := new(http.Request) *outreq = *req url := *req.URL outreq.URL = &url outreq.Header = http.Header{} httputils.CopyHeadersWithout(req.Header, outreq.Header, hopHeaders...) outreq.Header.Set("User-Agent", p.Settings.UserAgent) // If we don't set it, Go sets it for us to something stupid... outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false upAddr, err := upstream.GetAddress(p.Settings.UpstreamHashPrefix + req.URL.RequestURI()) if err != nil { return nil, fmt.Errorf("[%p] Proxy handler could not get an upstream address: %v", req, err) } p.Logger.Debugf("[%p] Using upstream %s (%s) to proxy request", req, upAddr, upAddr.OriginalURL) outreq.URL.Scheme = upAddr.Scheme outreq.URL.Host = upAddr.Host // Set the correct host if p.Settings.HostHeader != "" { outreq.Host = p.Settings.HostHeader } else if p.Settings.HostHeaderKeepOriginal { if req.Host != "" { outreq.Host = req.Host } else { outreq.Host = req.URL.Host } } else { outreq.Host = upAddr.OriginalURL.Host } if closeNotifier, ok := rw.(http.CloseNotifier); ok { reqDone := make(chan struct{}) defer close(reqDone) clientGone := closeNotifier.CloseNotify() outreq.Body = struct { io.Reader io.Closer }{ Reader: &runOnFirstRead{ Reader: outreq.Body, fn: func() { go func() { select { case <-clientGone: upstream.CancelRequest(outreq) case <-reqDone: } }() }, }, Closer: outreq.Body, } } if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { // If we aren't the first proxy retain prior // X-Forwarded-For information as a comma+space // separated list and fold multiple headers into one. if prior, ok := outreq.Header["X-Forwarded-For"]; ok { clientIP = strings.Join(prior, ", ") + ", " + clientIP } outreq.Header.Set("X-Forwarded-For", clientIP) } return outreq, nil }