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 // workaround for https://github.com/golang/go/issues/10433 outReq.URL.Opaque = mergeStartingSlashes(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 }
// NewFastHTTPHandler wraps net/http handler to fasthttp request handler, // so it can be passed to fasthttp server. // // While this function may be used for easy switching from net/http to fasthttp, // it has the following drawbacks comparing to using manually written fasthttp // request handler: // // * A lot of useful functionality provided by fasthttp is missing // from net/http handler. // * net/http -> fasthttp handler conversion has some overhead, // so the returned handler will be always slower than manually written // fasthttp handler. // // So it is advisable using this function only for quick net/http -> fasthttp // switching. Then manually convert net/http handlers to fasthttp handlers // according to https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp . func NewFastHTTPHandler(h http.Handler) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { var r http.Request body := ctx.PostBody() r.Method = string(ctx.Method()) r.Proto = "HTTP/1.1" r.ProtoMajor = 1 r.ProtoMinor = 1 r.RequestURI = string(ctx.RequestURI()) r.ContentLength = int64(len(body)) r.Host = string(ctx.Host()) r.RemoteAddr = ctx.RemoteAddr().String() hdr := make(http.Header) ctx.Request.Header.VisitAll(func(k, v []byte) { hdr.Set(string(k), string(v)) }) r.Header = hdr r.Body = &netHTTPBody{body} var w netHTTPResponseWriter h.ServeHTTP(&w, &r) ctx.SetStatusCode(w.StatusCode()) for k, vv := range w.Header() { for _, v := range vv { ctx.Response.Header.Set(k, v) } } ctx.Write(w.body) } }
func post(url_ string, oauthHeaders map[string]string) (r *http.Response, err error) { var req http.Request req.Method = "POST" req.ProtoMajor = 1 req.ProtoMinor = 1 req.Close = true req.Header = map[string][]string{ "Authorization": {"OAuth "}, } req.TransferEncoding = []string{"chunked"} first := true for k, v := range oauthHeaders { if first { first = false } else { req.Header["Authorization"][0] += ",\n " } req.Header["Authorization"][0] += k + "=\"" + v + "\"" } req.URL, err = url.Parse(url_) if err != nil { return nil, err } return send(&req) }
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 = "" // Go doesn't implicitly pass the host header unless you set Host on the request 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 (proxy *Proxy) copyRequest(r *http.Request) *http.Request { proxyRequest := new(http.Request) *proxyRequest = *r proxyRequest.Proto = "HTTP/1.1" proxyRequest.ProtoMajor = 1 proxyRequest.ProtoMinor = 1 proxyRequest.Close = false proxyRequest.Header = make(http.Header) proxyRequest.URL.Scheme = "http" proxyRequest.URL.Path = r.URL.Path for key, values := range r.Header { for _, value := range values { proxyRequest.Header.Add(key, value) } } for _, headerName := range ignoredHeaderNames { proxyRequest.Header.Del(headerName) } if requestHost, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { if values, ok := proxyRequest.Header["X-Forwarded-For"]; ok { requestHost = strings.Join(values, ", ") + ", " + requestHost } proxyRequest.Header.Set("X-Forwarded-For", requestHost) } return proxyRequest }
func (l *HttpLocation) copyRequest(req *http.Request, body netutils.MultiReader, endpoint endpoint.Endpoint) *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 endpointURL := endpoint.GetUrl() 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) netutils.CopyHeaders(outReq.Header, req.Header) return outReq }
// This function alters the original request - adds/removes headers, removes hop headers, // changes the request path. func rewriteRequest(req *http.Request, cmd *command.Forward, upstream *command.Upstream) *http.Request { outReq := new(http.Request) *outReq = *req // includes shallow copies of maps, but we handle this below outReq.URL.Scheme = upstream.Scheme outReq.URL.Host = fmt.Sprintf("%s:%d", upstream.Host, upstream.Port) if len(cmd.RewritePath) != 0 { outReq.URL.Path = cmd.RewritePath } outReq.URL.RawQuery = req.URL.RawQuery outReq.Proto = "HTTP/1.1" outReq.ProtoMajor = 1 outReq.ProtoMinor = 1 outReq.Close = false glog.Infof("Proxying request to: %v", outReq) outReq.Header = make(http.Header) netutils.CopyHeaders(outReq.Header, req.Header) if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { // TODO(pquerna): configure this? Not all backends properly parse the header.. if TRUST_FORWARD_HEADER { if prior, ok := outReq.Header["X-Forwarded-For"]; ok { clientIP = strings.Join(prior, ", ") + ", " + clientIP } } outReq.Header.Set("X-Forwarded-For", clientIP) } if req.TLS != nil { outReq.Header.Set("X-Forwarded-Proto", "https") } else { outReq.Header.Set("X-Forwarded-Proto", "http") } if req.Host != "" { outReq.Header.Set("X-Forwarded-Host", req.Host) } outReq.Header.Set("X-Forwarded-Server", vulcanHostname) if len(cmd.RemoveHeaders) != 0 { netutils.RemoveHeaders(cmd.RemoveHeaders, outReq.Header) } // Add generic instructions headers to the request if len(cmd.AddHeaders) != 0 { glog.Info("Proxying instructions headers:", cmd.AddHeaders) netutils.CopyHeaders(outReq.Header, cmd.AddHeaders) } // Remove hop-by-hop headers to the backend. Especially // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. netutils.RemoveHeaders(hopHeaders, outReq.Header) return outReq }
// copyRequest creates a new proxy request with some modifications from an original request. func copyRequest(originalRequest *http.Request) *http.Request { pr := new(http.Request) *pr = *originalRequest pr.Proto = "HTTP/1.1" pr.ProtoMajor = 1 pr.ProtoMinor = 1 pr.Close = false pr.Header = make(http.Header) pr.URL.Scheme = "http" pr.URL.Path = originalRequest.URL.Path // Copy all header fields. for key, values := range originalRequest.Header { for _, value := range values { pr.Header.Add(key, value) } } // Remove ignored header fields. for _, header := range ignoredHeaderNames { pr.Header.Del(header) } // Append this machine's host name into X-Forwarded-For. if requestHost, _, err := net.SplitHostPort(originalRequest.RemoteAddr); err == nil { if originalValues, ok := pr.Header["X-Forwarded-For"]; ok { requestHost = strings.Join(originalValues, ", ") + ", " + requestHost } pr.Header.Set("X-Forwarded-For", requestHost) } return pr }
func (p *ReverseProxy) ServeHTTP(req *http.Request) (*http.Response, error) { transport := p.Transport if transport == nil { transport = http.DefaultTransport } outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove hop-by-hop headers to the backend. Especially // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. This // is modifying the same underlying map from req (shallow // copied above) so we only copy it if necessary. copiedHeaders := false for _, h := range hopHeaders { if outreq.Header.Get(h) != "" { if !copiedHeaders { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) copiedHeaders = true } outreq.Header.Del(h) } } 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) } res, err := transport.RoundTrip(outreq) if err != nil { return res, err } for _, p := range *p.Plugins { p.Outbound(res) } for _, h := range hopHeaders { res.Header.Del(h) } return res, nil }
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request, respUpdateFn respUpdateFn) error { transport := p.Transport if transport == nil { transport = http.DefaultTransport } p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false res, err := transport.RoundTrip(outreq) if err != nil { return err } else if respUpdateFn != nil { respUpdateFn(res) } if res.StatusCode == http.StatusSwitchingProtocols && strings.ToLower(res.Header.Get("Upgrade")) == "websocket" { res.Body.Close() hj, ok := rw.(http.Hijacker) if !ok { return nil } conn, _, err := hj.Hijack() if err != nil { return err } defer conn.Close() backendConn, err := net.Dial("tcp", outreq.URL.Host) if err != nil { return err } defer backendConn.Close() outreq.Write(backendConn) go func() { io.Copy(backendConn, conn) // write tcp stream to backend. }() io.Copy(conn, backendConn) // read tcp stream from backend. } else { defer res.Body.Close() for _, h := range hopHeaders { res.Header.Del(h) } copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) p.copyResponse(rw, res.Body) } return nil }
func prepareRequest(req *http.Request) *http.Request { outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay // Pass the Request-URI verbatim without any modifications. // // NOTE: An exception must be made if the Request-URI is a path // beginning with "//" (e.g. "//foo/bar") because then // req.URL.RequestURI() would interpret req.URL.Opaque as being a URI // with the scheme stripped and so generate a URI like scheme:opaque // (e.g. "http://foo/bar") which would be incorrect, see: // https://github.com/golang/go/blob/f75aafd/src/net/url/url.go#L913-L931 // // It is ok to make this exception because the fallback to // req.URL.EscapedPath will generate the correct Request-URI. if !strings.HasPrefix(req.RequestURI, "//") { outreq.URL.Opaque = strings.Split(strings.TrimPrefix(req.RequestURI, req.URL.Scheme+":"), "?")[0] } outreq.URL.Scheme = "http" outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove hop-by-hop headers to the backend. outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) for _, h := range hopHeaders { outreq.Header.Del(h) } // remove the Upgrade header and headers referenced in the Connection // header if HTTP < 1.1 or if Connection header didn't contain "upgrade": // https://tools.ietf.org/html/rfc7230#section-6.7 if !req.ProtoAtLeast(1, 1) || !isConnectionUpgrade(req.Header) { outreq.Header.Del("Upgrade") // Especially important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. outreq.Header.Del("Connection") // A proxy or gateway MUST parse a received Connection header field before a // message is forwarded and, for each connection-option in this field, remove // any header field(s) from the message with the same name as the // connection-option, and then remove the Connection header field itself (or // replace it with the intermediary's own connection options for the // forwarded message): https://tools.ietf.org/html/rfc7230#section-6.1 tokens := strings.Split(req.Header.Get("Connection"), ",") for _, hdr := range tokens { outreq.Header.Del(hdr) } } return outreq }
func reverseProxy(w http.ResponseWriter, req *http.Request) { logRequest(req) if rSensitivePath.MatchString(req.URL.Path) { w.WriteHeader(http.StatusForbidden) return } outReq := new(http.Request) outReq.Method = req.Method outReq.URL = &url.URL{ Scheme: "http", Host: host, Path: req.URL.Path, RawQuery: req.URL.RawQuery, } outReq.Proto = "HTTP/1.1" outReq.ProtoMajor = 1 outReq.ProtoMinor = 1 outReq.Header = make(http.Header) outReq.Body = req.Body outReq.ContentLength = req.ContentLength outReq.Host = host for _, h := range removeHeaders { req.Header.Del(h) } copyHeader(outReq.Header, req.Header) outReq.Header.Set("Host", host) outReq.Header.Set("Referer", baseURL) outReq.Header.Set("Origin", baseURL) resp, err := send(outReq) if err != nil { log.Printf("proxy error: %v", err) w.WriteHeader(http.StatusInternalServerError) return } defer resp.Body.Close() for _, h := range removeHeaders { resp.Header.Del(h) } if loc := resp.Header.Get("Location"); loc != "" { if u, err := url.Parse(loc); err == nil && u.Host == host { u.Scheme = "http" u.Host = req.Host resp.Header.Set("Location", u.String()) } } copyHeader(w.Header(), resp.Header) w.WriteHeader(resp.StatusCode) io.Copy(w, resp.Body) }
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request, location string) { transport := p.Transport if transport == nil { transport = http.DefaultTransport } outreq := new(http.Request) p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove hop-by-hop headers to the backend. Especially // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. This // is modifying the same underlying map from req (shallow // copied above) so we only copy it if necessary. copiedHeaders := false for _, h := range hopHeaders { if outreq.Header.Get(h) != "" { if !copiedHeaders { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) copiedHeaders = true } outreq.Header.Del(h) } } 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) } res, err := transport.RoundTrip(outreq) if err != nil { log.Printf("http: proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } defer res.Body.Close() copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) p.copyResponse(rw, res.Body) }
func (client *RPCClient) RPCCall(methodName string, args ...interface{}) (interface{}, *rpc.Fault, *rpc.Error) { buf := bytes.NewBufferString("") berr := Marshal(buf, methodName, args) if berr != nil { return nil, nil, berr } var req http.Request req.URL = client.url req.Method = "POST" req.ProtoMajor = 1 req.ProtoMinor = 1 req.Close = false req.Body = nopCloser{buf} req.Header = map[string][]string{ "Content-Type": {"text/xml"}, } req.RawURL = "/RPC" req.ContentLength = int64(buf.Len()) if client.conn == nil { var cerr *rpc.Error if client.conn, cerr = rpc.Open(client.url); cerr != nil { return nil, nil, cerr } } if werr := req.Write(client.conn); werr != nil { client.conn.Close() return nil, nil, &rpc.Error{Msg: werr.String()} } reader := bufio.NewReader(client.conn) resp, rerr := http.ReadResponse(reader, &req) if rerr != nil { client.conn.Close() return nil, nil, &rpc.Error{Msg: rerr.String()} } else if resp == nil { rrerr := fmt.Sprintf("ReadResponse for %s returned nil response\n", methodName) return nil, nil, &rpc.Error{Msg: rrerr} } _, pval, perr, pfault := Unmarshal(resp.Body) if resp.Close { resp.Body.Close() client.conn = nil } return pval, pfault, perr }
func httpProxy(writer http.ResponseWriter, request *http.Request) { proxyRequest := new(http.Request) *proxyRequest = *request log.Printf("request = %s %s", request.Method, request.URL.Host) if strings.ToUpper(proxyRequest.Method) == "CONNECT" { hostPort := request.URL.Host pandora, err := dialer.Dial("tcp", hostPort) // tuner.pandora.com:443 if err != nil { log.Printf("pianobarproxy: error: %v", err) writer.WriteHeader(http.StatusInternalServerError) return } client, writer, err := writer.(http.Hijacker).Hijack() writer.WriteString("HTTP/1.0 200 Connection Established\r\n\r\n") writer.Flush() go pipe(client, pandora) go pipe(pandora, client) return } proxyRequest.Proto = "HTTP/1.1" proxyRequest.ProtoMajor = 1 proxyRequest.ProtoMinor = 1 proxyRequest.Close = false // Remove the connection header to the backend. We want a // persistent connection, regardless of what the client sent // to us. if proxyRequest.Header.Get("Connection") != "" { proxyRequest.Header = make(http.Header) copyHeader(proxyRequest.Header, request.Header) proxyRequest.Header.Del("Connection") } response, err := transport.RoundTrip(proxyRequest) if err != nil { log.Printf("pianobarproxy: error: %v", err) writer.WriteHeader(http.StatusInternalServerError) return } copyHeader(writer.Header(), response.Header) writer.WriteHeader(response.StatusCode) if response.Body != nil { io.Copy(io.Writer(writer), response.Body) } }
func CopyRequest(req *http.Request) *http.Request { outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove hop-by-hop headers to the backend. Especially // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. This // is modifying the same underlying map from req (shallow // copied above) so we only copy it if necessary. copiedHeaders := false for _, h := range hopHeaders { if outreq.Header.Get(h) != "" { if !copiedHeaders { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) copiedHeaders = true } outreq.Header.Del(h) } } 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) } // If the request body is not chunked, tee it into the // proxy request's body & and replace it with a buffered // copy of the request body (it will be fully read by // the proxy request). if !isChunked(req) { bodyBuffer := bytes.NewBuffer(make([]byte, 0, req.ContentLength)) bodyReader := io.TeeReader(req.Body, bodyBuffer) outreq.Body = ioutil.NopCloser(bodyReader) req.Body = ioutil.NopCloser(bodyBuffer) } else { outreq.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) } return outreq }
func (h *HTTPSender) buildBaseRequest(contextPath string, method string, headers map[string][]string, bodyReader *bytes.Reader) *http.Request { var req http.Request req.Method = h.method req.ProtoMajor = 1 req.ProtoMinor = 1 req.Close = false req.Header = h.headers req.URL = h.parsedContextPath req.URL.Host = h.hosts[h.currentHost] req.Body = ioutil.NopCloser(bodyReader) req.ContentLength = int64(bodyReader.Len()) return &req }
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { transport := p.Transport if transport == nil { transport = http.DefaultTransport } outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove the connection header to the backend. We want a // persistent connection, regardless of what the client sent // to us. This is modifying the same underlying map from req // (shallow copied above) so we only copy it if necessary. if outreq.Header.Get("Connection") != "" { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) outreq.Header.Del("Connection") } if clientIp, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { outreq.Header.Set("X-Forwarded-For", clientIp) } res, err := transport.RoundTrip(outreq) if err != nil { log.Printf("http: proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) if res.Body != nil { var dst io.Writer = rw if p.FlushInterval != 0 { if wf, ok := rw.(writeFlusher); ok { dst = &maxLatencyWriter{dst: wf, latency: p.FlushInterval} } } io.Copy(dst, res.Body) } }
func TestTransportConnectionCloseOnRequest(t *testing.T) { ts := httptest.NewServer(hostPortHandler) defer ts.Close() connSet, testDial := makeTestDial(t) for _, connectionClose := range []bool{false, true} { tr := &Transport{ Dial: testDial, } c := &http.Client{Transport: tr} fetch := func(n int) string { req := new(http.Request) var err error req.URL, err = url.Parse(ts.URL) if err != nil { t.Fatalf("URL parse error: %v", err) } req.Method = "GET" req.Proto = "HTTP/1.1" req.ProtoMajor = 1 req.ProtoMinor = 1 req.Close = connectionClose res, err := c.Do(req) if err != nil { t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) } body, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) } return string(body) } body1 := fetch(1) body2 := fetch(2) bodiesDiffer := body1 != body2 if bodiesDiffer != connectionClose { t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q", connectionClose, bodiesDiffer, body1, body2) } tr.CloseIdleConnections() } connSet.check(t) }
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { transport := p.Transport if transport == nil { transport = http.DefaultTransport } outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove the connection header to the backend. We want a // persistent connection, regardless of what the client sent // to us. This is modifying the same underlying map from req // (shallow copied above) so we only copy it if necessary. if outreq.Header.Get("Connection") != "" { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) outreq.Header.Del("Connection") } 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) } res, err := transport.RoundTrip(outreq) if err != nil { log.Printf("http: proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } defer res.Body.Close() copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) p.copyResponse(rw, res.Body) }
// NewFastHTTPHandler wraps net/http handler to fasthttp request handler, // so it can be passed to fasthttp server. // // While this function may be used for easy switching from net/http to fasthttp, // it has the following drawbacks comparing to using manually written fasthttp // request handler: // // * A lot of useful functionality provided by fasthttp is missing // from net/http handler. // * net/http -> fasthttp handler conversion has some overhead, // so the returned handler will be always slower than manually written // fasthttp handler. // // So it is advisable using this function only for quick net/http -> fasthttp // switching. Then manually convert net/http handlers to fasthttp handlers // according to https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp . func NewFastHTTPHandler(h http.Handler) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { var r http.Request body := ctx.PostBody() r.Method = string(ctx.Method()) r.Proto = "HTTP/1.1" r.ProtoMajor = 1 r.ProtoMinor = 1 r.RequestURI = string(ctx.RequestURI()) r.ContentLength = int64(len(body)) r.Host = string(ctx.Host()) r.RemoteAddr = ctx.RemoteAddr().String() hdr := make(http.Header) ctx.Request.Header.VisitAll(func(k, v []byte) { sk := string(k) sv := string(v) switch sk { case "Transfer-Encoding": r.TransferEncoding = append(r.TransferEncoding, sv) default: hdr.Set(sk, sv) } }) r.Header = hdr r.Body = &netHTTPBody{body} rURL, err := url.ParseRequestURI(r.RequestURI) if err != nil { ctx.Logger().Printf("cannot parse requestURI %q: %s", r.RequestURI, err) ctx.Error("Internal Server Error", fasthttp.StatusInternalServerError) return } r.URL = rURL var w netHTTPResponseWriter h.ServeHTTP(&w, &r) ctx.SetStatusCode(w.StatusCode()) for k, vv := range w.Header() { for _, v := range vv { ctx.Response.Header.Set(k, v) } } ctx.Write(w.body) } }
func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { node := p.lookup(req) if node == nil { rw.WriteHeader(http.StatusNotFound) return } p.increaseConn(node) defer p.decreaseConn(node) outreq := new(http.Request) *outreq = *req outreq.URL.Scheme = "http" outreq.URL.Host = node.Host outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false if outreq.Header.Get("Connection") != "" { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) outreq.Header.Del("Connection") } if clientIp, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { outreq.Header.Set("X-Forwarded-For", clientIp) } res, err := http.DefaultTransport.RoundTrip(outreq) if err != nil { log.Printf("proxy round trip error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) if res.Body != nil { var dst io.Writer = rw io.Copy(dst, res.Body) } }
func relay(w http.ResponseWriter, req *http.Request) { defer func() { if err := recover(); err != nil { http.Error(w, fmt.Sprint(err), 200) } }() c, proxy, err := buildProxy() if err != nil { panic(err) } defer c.Close() _ = proxy outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove the connection header to the backend. We want a // persistent connection, regardless of what the client sent // to us. This is modifying the same underlying map from req // (shallow copied above) so we only copy it if necessary. if outreq.Header.Get("Connection") != "" { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) outreq.Header.Del("Connection") } outreq.Write(c) br := bufio.NewReader(c) resp, err := http.ReadResponse(br, outreq) if err != nil { panic(err) } copyHeader(w.Header(), resp.Header) w.WriteHeader(resp.StatusCode) if resp.Body != nil { io.Copy(w, resp.Body) } }
// Issue a request to an internal handler. This duplicates some logic found in // net.http.serve http://golang.org/src/net/http/server.go?#L1124 and // net.http.readRequest http://golang.org/src/net/http/server.go?#L func (t *WSTunnelClient) finishInternalRequest(id int16, req *http.Request) { log := t.Log.New("id", id, "verb", req.Method, "uri", req.RequestURI) log.Info("HTTP issuing internal request") // Remove hop-by-hop headers for _, h := range hopHeaders { req.Header.Del(h) } // Add fake protocol version req.Proto = "HTTP/1.0" req.ProtoMajor = 1 req.ProtoMinor = 0 // Dump the request into a buffer in case we want to log it dump, _ := httputil.DumpRequest(req, false) log.Debug("dump", "req", strings.Replace(string(dump), "\r\n", " || ", -1)) // Make sure we don't die if a panic occurs in the handler defer func() { if err := recover(); err != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] log.Error("HTTP panic in handler", "err", err, "stack", string(buf)) } }() // Concoct Response rw := newResponseWriter(req) // Issue the request to the HTTP server t.InternalServer.ServeHTTP(rw, req) err := rw.finishResponse() if err != nil { //dump2, _ := httputil.DumpResponse(resp, true) //log15.Info("handleWsRequests: request error", "err", err.Error(), // "req", string(dump), "resp", string(dump2)) log.Info("HTTP request error", "err", err.Error()) writeResponseMessage(t, id, concoctResponse(req, err.Error(), 502)) return } log.Info("HTTP responded", "status", rw.resp.Status) writeResponseMessage(t, id, rw.resp) }
/* no matter what request, we update and forward it to web server instance */ func defaultHandler(w http.ResponseWriter, r *http.Request) { outreq := new(http.Request) *outreq = *r client := selectClient() outreq.URL.Scheme = client.Scheme outreq.URL.Host = client.Addr outreq.Host = outreq.URL.Host outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false if outreq.Header.Get("Connectoin") != "" { outreq.Header = make(http.Header) copyHeader(outreq.Header, r.Header) delete(outreq.Header, "Connection") } if clientIp, _, err := net.SplitHostPort(outreq.RemoteAddr); err != nil { outreq.Header.Add("X-Forwarded-For", clientIp) } dmp, _ := httputil.DumpRequest(outreq, false) log.Println(string(dmp)) transport := http.DefaultTransport res, err := transport.RoundTrip(outreq) if err != nil { log.Printf("proxy error: %v\n", err) w.WriteHeader(http.StatusInternalServerError) return } copyHeader(w.Header(), res.Header) dmp2, _ := httputil.DumpResponse(res, false) log.Println(string(dmp2)) w.WriteHeader(res.StatusCode) if res.Body != nil { var rw io.Writer = w io.Copy(rw, res.Body) } }
// hello world, the web server func helloServer(rw http.ResponseWriter, req *http.Request) { fmt.Println(req.Host) fmt.Println(req.Method) fmt.Println(req.RequestURI) outreq := new(http.Request) *outreq = *req outreq.URL.Scheme = "http" outreq.URL.Host = ":3000" outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = true res, err := http.DefaultTransport.RoundTrip(outreq) if err != nil { log.Printf("http: proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) if res.Body != nil { //var dst io.Writer = rw var fname string n, err := fmt.Fscan(res.Body, &fname) if n != 1 || err != nil { log.Printf("http: couldn't find URL in body, found %v: %v", n, err) return } res.Body.Close() renderf, err := ioutil.ReadFile(fname) if err != nil { log.Printf("http: couldn't read %v", fname) } rw.Header().Add("Content-Type", "image/png") rw.Write(renderf) //io.Copy(dst, res.Body) } }
// NewFastHTTPVodkaAdaptor is responsible for adapting vodka requests through fasthttp interfaces to net/http requests. // // Based on valyala/fasthttp implementation. // Available here: https://github.com/valyala/fasthttp/blob/master/fasthttpadaptor/adaptor.go func NewFastHTTPVodkaAdaptor(h http.Handler) vodka.HandlerFunc { return func(c vodka.Context) error { var r http.Request ctx := c.Request().(*fasthttp.Request).RequestCtx body := ctx.PostBody() r.Method = string(ctx.Method()) r.Proto = "HTTP/1.1" r.ProtoMajor = 1 r.ProtoMinor = 1 r.RequestURI = string(ctx.RequestURI()) r.ContentLength = int64(len(body)) r.Host = string(ctx.Host()) r.RemoteAddr = ctx.RemoteAddr().String() hdr := make(http.Header) ctx.Request.Header.VisitAll(func(k, v []byte) { hdr.Set(string(k), string(v)) }) r.Header = hdr r.Body = &netHTTPBody{body} rURL, err := url.ParseRequestURI(r.RequestURI) if err != nil { ctx.Logger().Printf("cannot parse requestURI %q: %s", r.RequestURI, err) return fmt.Errorf("Internal Server Error") } r.URL = rURL var w netHTTPResponseWriter h.ServeHTTP(&w, &r) ctx.SetStatusCode(w.StatusCode()) for k, vv := range w.Header() { for _, v := range vv { c.Response().Header().Set(k, v) } } if strings.Contains(c.Response().Header().Get(vodka.HeaderContentType), textPlainContentType) { c.Response().Header().Set(vodka.HeaderContentType, http.DetectContentType(w.body)) } c.Response().Write(w.body) return nil } }
// General Request method used by the specialized request methods to create a request func (client *Client) newRequest(method string, id string) (*http.Request, error) { request := new(http.Request) var err error request.ProtoMajor = 1 request.ProtoMinor = 1 request.TransferEncoding = []string{"chunked"} request.Method = method // Generate Resource-URI and parse it targeturl := client.resource.String() + id if request.URL, err = url.Parse(targeturl); err != nil { return nil, err } return request, nil }
// General Request method used by the specialized request methods to create a request func (c *client) newRequest(method string, id string) (*http.Request, error) { request := new(http.Request) var err error fmt.Println(c) request.ProtoMajor = 1 request.ProtoMinor = 1 request.TransferEncoding = []string{"chunked"} request.Method = method // Generate Resource-URI and parse it uri := c.resource.String() + id fmt.Println(uri) if request.URL, err = url.Parse(uri); err != nil { return nil, err } return request, nil }
func YadisRequest(url_ string, method string) (resp *http.Response, err error) { resp = nil var request = new(http.Request) var client = http.DefaultClient var Header = make(http.Header) request.Method = method request.URL, err = url.Parse(url_) if err != nil { return } // Common parameters request.Proto = "HTTP/1.0" request.ProtoMajor = 1 request.ProtoMinor = 0 request.ContentLength = 0 request.Close = true Header.Add("Accept", "application/xrds+xml") request.Header = Header // Follow a maximum of 5 redirections for i := 0; i < 5; i++ { response, err := client.Do(request) if err != nil { return nil, err } if response.StatusCode == 301 || response.StatusCode == 302 || response.StatusCode == 303 || response.StatusCode == 307 { location := response.Header.Get("Location") request.URL, err = url.Parse(location) response.Body.Close() if err != nil { return nil, err } } else { return response, nil } } return nil, errors.New("Too many redirections") }