// Round trips the request to one of the upstreams, returns the streamed // request body length in bytes and the upstream reply. func (p *ReverseProxy) proxyRequest( w http.ResponseWriter, req *http.Request, cmd *command.Forward, endpoints []loadbalance.Endpoint) (int64, error) { // We are allowed to fallback in case of upstream failure, // record the request body so we can replay it on errors. body, err := netutils.NewBodyBuffer(req.Body) if err != nil { glog.Errorf("Request read error %s", err) return 0, netutils.NewHttpError(http.StatusBadRequest) } requestLength, err := body.TotalSize() if err != nil { glog.Errorf("Failed to read stored body length: %s", err) return 0, netutils.NewHttpError(http.StatusInternalServerError) } p.metrics.RequestBodySize.Update(requestLength) req.Body = body defer body.Close() for i := 0; i < len(endpoints); i++ { _, err := body.Seek(0, 0) if err != nil { return 0, err } endpoint, err := p.nextEndpoint(endpoints) if err != nil { glog.Errorf("Load Balancer failure: %s", err) return 0, err } glog.Infof("With failover, proxy to upstream: %s", endpoint.Upstream) err = p.proxyToUpstream(w, req, cmd, endpoint.Upstream) if err != nil { if cmd.Failover == nil || !cmd.Failover.Active { return 0, err } glog.Errorf("Upstream: %s error: %s, falling back to another", endpoint.Upstream, err) // Mark the endpoint as inactive for the next round of the load balance iteration endpoint.Active = false } else { return 0, nil } } glog.Errorf("All upstreams failed!") return requestLength, netutils.NewHttpError(http.StatusBadGateway) }
// Accepts requests, round trips it to the endpoint, and writes back the response. func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Record the request body so we can replay it on errors. body, err := netutils.NewBodyBuffer(r.Body) if err != nil || body == nil { log.Errorf("Request read error %s", err) if netErr, ok := err.(net.Error); ok && netErr.Timeout() { p.replyError(errors.FromStatus(http.StatusRequestTimeout), w, r) } else { p.replyError(errors.FromStatus(http.StatusBadRequest), w, r) } return } defer body.Close() r.Body = body req := request.NewBaseRequest(r, atomic.AddInt64(&p.lastRequestId, 1), body) err = p.proxyRequest(w, req) if err != nil { log.Errorf("%s failed: %s", req, err) p.replyError(err, w, r) } }
// Accepts requests, round trips it to the endpoint and writes backe the response. func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Record the request body so we can replay it on errors. body, err := netutils.NewBodyBuffer(r.Body) if err != nil || body == nil { log.Errorf("Request read error %s", err) p.replyError(errors.FromStatus(http.StatusBadRequest), w, r) return } defer body.Close() r.Body = body req := &request.BaseRequest{ HttpRequest: r, Id: atomic.AddInt64(&p.lastRequestId, 1), Body: body, } err = p.proxyRequest(w, req) if err != nil { log.Errorf("%s failed: %s", req, err) p.replyError(err, w, r) } }