Example #1
0
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)
}
Example #2
0
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
}