// Write writes resp in response to req. To close the connection gracefully, set the // Response.Close field to true. Write should be considered operational until // it returns an error, regardless of any errors returned on the Read side. func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error { // Retrieve the pipeline ID of this request/response pair sc.lk.Lock() id, ok := sc.pipereq[req] delete(sc.pipereq, req) if !ok { sc.lk.Unlock() return ErrPipeline } sc.lk.Unlock() // Ensure pipeline order sc.pipe.StartResponse(id) defer sc.pipe.EndResponse(id) sc.lk.Lock() if sc.we != nil { defer sc.lk.Unlock() return sc.we } if sc.c == nil { // connection closed by user in the meantime defer sc.lk.Unlock() return ErrClosed } c := sc.c if sc.nread <= sc.nwritten { defer sc.lk.Unlock() return errors.New("persist server pipe count") } if resp.Close { // After signaling a keep-alive close, any pipelined unread // requests will be lost. It is up to the user to drain them // before signaling. sc.re = ErrPersistEOF } sc.lk.Unlock() err := resp.Write(c) sc.lk.Lock() defer sc.lk.Unlock() if err != nil { sc.we = err return err } sc.nwritten++ return nil }
func (logger *HttpLogger) LogResp(resp *http.Response, ctx *goproxy.ProxyCtx) { body := path.Join(logger.path, fmt.Sprintf("%d_resp", ctx.Session)) from := "" if ctx.UserData != nil { from = ctx.UserData.(*transport.RoundTripDetails).TCPAddr.String() } if resp == nil { resp = emptyResp } else { resp.Body = NewTeeReadCloser(resp.Body, NewFileStream(body)) } logger.LogMeta(&Meta{ resp: resp, err: ctx.Error, t: time.Now(), sess: ctx.Session, from: from}) }