// Round trips the request to the selected proxy and writes back the response func (p *Handler) proxyRequest(w http.ResponseWriter, r *http.Request) error { // Lookup the Proxy registered for the given pair: method, path. proxy, params, _ := p.GetRouter().Lookup(r.Method, r.URL.Path) if len(params) > 0 { // fmt.Printf("params: %+v \n", params) r.URL.RawQuery = url.Values(params).Encode() + "&" + r.URL.RawQuery } if proxy == nil { p.logger.Warn("Handler failed to route: %s ", r.URL.Path) return errors.FromStatus(http.StatusBadGateway) } // Create a unique request with sequential ids that will be passed to all interfaces. fctx := context.NewFlowContext(r, w, atomic.AddInt64(&p.lastRequestId, 1), nil) // The roundtrip thru the whole pipeline of modules response, err := proxy.ProcessChain(fctx) // Preparing the response back to the client if applicable if response != nil { httputils.CopyHeaders(w.Header(), response.Header) w.WriteHeader(response.StatusCode) if response.Body == nil { logutils.FileLogger.Warn("Empty body contained on the response") } else { io.Copy(w, response.Body) defer response.Body.Close() } return nil } else { return err } }
// Adds all the headers and change the url to point to the endpoint. func copyRequest(req *http.Request, body httputils.MultiReader, endpointURL *url.URL) *http.Request { outReq := new(http.Request) *outReq = *req // includes shallow copies of maps, but we handle this below // Set the body to the enhanced body that can be re-read multiple times and buffered to disk outReq.Body = body outReq.URL.Scheme = endpointURL.Scheme outReq.URL.Host = endpointURL.Host outReq.URL.Opaque = req.RequestURI // raw query is already included in RequestURI, so ignore it to avoid dupes outReq.URL.RawQuery = "" 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) httputils.CopyHeaders(outReq.Header, req.Header) return outReq }