func (m *HttpTampererSymptom) MuckRequest(ctx *muxy.Context) { // Body if m.Request.Body != "" { newreq, err := http.NewRequest(ctx.Request.Method, ctx.Request.URL.String(), bytes.NewBuffer([]byte(m.Request.Body))) if err != nil { log.Error(err.Error()) } *ctx.Request = *newreq log.Debug("Spoofing HTTP Request Body with %s", log.Colorize(log.BLUE, m.Request.Body)) } // Set Cookies for _, c := range m.Request.Cookies { c.Expires = stringToDate(c.RawExpires) log.Debug("Spoofing Request Cookie %s => %s", log.Colorize(log.LIGHTMAGENTA, c.Name), c.String()) ctx.Request.Header.Add("Cookie", c.String()) } // Set Headers for k, v := range m.Request.Headers { key := strings.ToTitle(strings.Replace(k, "_", "-", -1)) log.Debug("Spoofing Request Header %s => %s", log.Colorize(log.LIGHTMAGENTA, key), v) ctx.Request.Header.Set(key, v) } // This Writes all headers, setting status code - so call this last if m.Request.Method != "" { ctx.Request.Method = m.Request.Method } }
func (p *proxy) pipe(src io.Reader, dst io.Writer) { // Direction islocal := src == p.lconn buff := make([]byte, p.packetsize) done := false for !done { n, readErr := src.Read(buff) if readErr != nil || n == 0 { if !islocal { p.err("Read failed '%s'\n", readErr) } done = true } b := buff[:n] ctx := &muxy.Context{Bytes: b} for _, middleware := range p.middleware { if islocal { middleware.HandleEvent(muxy.EVENT_PRE_DISPATCH, ctx) } else { middleware.HandleEvent(muxy.EVENT_POST_DISPATCH, ctx) } } n, err := dst.Write(b) if err != nil { log.Error("Write failed: %s", err.Error()) p.err("Write failed '%s'\n", err) return } if islocal { p.sentBytes += uint64(n) } else { p.receivedBytes += uint64(n) } } }
func checkHttpServerError(err error) { if err != nil { log.Error("ListenAndServe error: ", err.Error()) } }
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 if closeNotifier, ok := rw.(http.CloseNotifier); ok { if requestCanceler, ok := transport.(requestCanceler); 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: requestCanceler.CancelRequest(outreq) case <-reqDone: } }() }, }, Closer: outreq.Body, } } } 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) } // Fire Pre-dispatch middleware event ctx := &muxy.Context{Request: req} for _, middleware := range p.Middleware { middleware.HandleEvent(muxy.EVENT_PRE_DISPATCH, ctx) } res, err := transport.RoundTrip(outreq) if err != nil { log.Error("http: proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } defer res.Body.Close() // Fire Post-dispatch middleware event ctx = &muxy.Context{req, res, rw, nil} for _, middleware := range p.Middleware { middleware.HandleEvent(muxy.EVENT_POST_DISPATCH, ctx) } copyHeader(rw.Header(), res.Header) // The "Trailer" header isn't included in the Transport's response, // at least for *http.Transport. Build it up from Trailer. if len(res.Trailer) > 0 { var trailerKeys []string for k := range res.Trailer { trailerKeys = append(trailerKeys, k) } rw.Header().Add("Trailer", strings.Join(trailerKeys, ", ")) } rw.WriteHeader(res.StatusCode) if len(res.Trailer) > 0 { // Force chunking if we saw a response trailer. // This prevents net/http from calculating the length for short // bodies and adding a Content-Length. if fl, ok := rw.(http.Flusher); ok { fl.Flush() } } p.copyResponse(rw, res.Body) res.Body.Close() // close now, instead of defer, to populate res.Trailer copyHeader(rw.Header(), res.Trailer) }