// This downgrades an http.Response object to HTTP 1.0, which is necessary in the case where the // original client request was 1.0. func DowngradeResponse(resp *http.Response, req *http.Request) { resp.Proto = "HTTP/1.0" resp.ProtoMajor = 1 resp.ProtoMinor = 0 if strings.Contains(strings.ToLower(req.Header.Get("Connection")), "keep-alive") { resp.Header.Set("Connection", "keep-alive") resp.Close = false } else { resp.Close = true } }
// handleRequest runs the request and response modifiers and performs the roundtrip to the destination server. func (p *Proxy) handleRequest(ctx *Context, rw *bufio.ReadWriter, req *http.Request) (closing bool) { if err := proxyutil.FixBadFraming(req.Header); err != nil { Errorf("proxyutil.FixBadFraming(): %v", err) proxyutil.NewErrorResponse(400, err, req).Write(rw) } proxyutil.SetForwardedHeaders(req) proxyutil.SetViaHeader(req.Header, "1.1 martian") if err := p.ModifyRequest(ctx, req); err != nil { Errorf("martian.ModifyRequest(): %v", err) proxyutil.NewErrorResponse(400, err, req).Write(rw) return } if shouldCloseAfterReply(req.Header) { Debugf("closing after reply") closing = true } proxyutil.RemoveHopByHopHeaders(req.Header) var res *http.Response var err error if !ctx.SkipRoundTrip { Debugf("proceed to round trip for %s", req.URL) res, err = p.RoundTripper.RoundTrip(req) if err != nil { Errorf("RoundTripper.RoundTrip(%s): %v", req.URL, err) proxyutil.NewErrorResponse(502, err, req).Write(rw) return } } else { Debugf("skipped round trip for %s", req.URL) res = proxyutil.NewResponse(200, nil, req) } proxyutil.RemoveHopByHopHeaders(res.Header) if err := p.ModifyResponse(ctx, res); err != nil { Errorf("martian.ModifyResponse(): %v", err) proxyutil.NewErrorResponse(400, err, req).Write(rw) return } if closing { res.Header.Set("Connection", "close") res.Close = true } if err := res.Write(rw); err != nil { Errorf("res.Write(): %v", err) } return }
func (r *response) Response() *http.Response { if r.Data == nil { r.Data = new(bytes.Buffer) } out := new(http.Response) out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode)) out.StatusCode = r.StatusCode out.Proto = "HTTP/1.1" out.ProtoMajor = 1 out.ProtoMinor = 1 out.Header = r.Header out.Body = &readCloser{r.Data} out.ContentLength = int64(r.Data.Len()) out.TransferEncoding = nil out.Close = true out.Trailer = make(http.Header) out.Request = r.Request return out }
func (p *MockResponseWriter) String() string { resp := new(http.Response) resp.StatusCode = p.StatusCode resp.Proto = "HTTP/1.1" resp.ProtoMajor = 1 resp.ProtoMinor = 1 resp.Header = p.Headers resp.Body = ioutil.NopCloser(bytes.NewBuffer(p.Buffer.Bytes())) resp.ContentLength = int64(p.Buffer.Len()) if p.Headers.Get("Transfer-Encoding") != "" { resp.TransferEncoding = []string{p.Headers.Get("Transfer-Encoding")} } else { resp.TransferEncoding = nil } resp.Close = p.Headers.Get("Connection") == "close" resp.Trailer = make(http.Header) resp.Request = p.Request b, _ := httputil.DumpResponse(resp, true) return string(b) }
func (srv *Server) handler(c net.Conn) { startTime := time.Now() bpe := srv.bufferPool.take(c) defer srv.bufferPool.give(bpe) var closeSentinelChan = make(chan int) go srv.sentinel(c, closeSentinelChan) defer srv.connectionFinished(c, closeSentinelChan) var err error var req *http.Request // no keepalive (for now) reqCount := 0 keepAlive := true for err == nil && keepAlive { if req, err = http.ReadRequest(bpe.br); err == nil { if req.Header.Get("Connection") != "Keep-Alive" { keepAlive = false } request := newRequest(req, c, startTime) reqCount++ var res *http.Response pssInit := new(PipelineStageStat) pssInit.Name = "server.Init" pssInit.StartTime = startTime pssInit.EndTime = time.Now() request.appendPipelineStage(pssInit) // execute the pipeline if res = srv.Pipeline.execute(request); res == nil { res = SimpleResponse(req, 404, nil, "Not Found") } // cleanup request.startPipelineStage("server.ResponseWrite") req.Body.Close() // shutting down? select { case <-srv.stopAccepting: keepAlive = false res.Close = true default: } // The res.Write omits Content-length on 0 length bodies, and by spec, // it SHOULD. While this is not MUST, it's kinda broken. See sec 4.4 // of rfc2616 and a 200 with a zero length does not satisfy any of the // 5 conditions if Connection: keep-alive is set :( // I'm forcing chunked which seems to work because I couldn't get the // content length to write if it was 0. // Specifically, the android http client waits forever if there's no // content-length instead of assuming zero at the end of headers. der. if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) { res.TransferEncoding = []string{"identity"} } if res.ContentLength < 0 { res.TransferEncoding = []string{"chunked"} } // For HTTP/1.0 and Keep-Alive, sending the Connection: Keep-Alive response header is required // because close is default (opposite of 1.1) if keepAlive && !req.ProtoAtLeast(1, 1) { res.Header.Add("Connection", "Keep-Alive") } // write response if srv.sendfile { res.Write(c) srv.cycleNonBlock(c) } else { wbuf := bufio.NewWriter(c) res.Write(wbuf) wbuf.Flush() } if res.Body != nil { res.Body.Close() } request.finishPipelineStage() request.finishRequest() srv.requestFinished(request) if res.Close { keepAlive = false } // Reset the startTime // this isn't great since there may be lag between requests; but it's the best we've got startTime = time.Now() } else { // EOF is socket closed if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) { Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err) } } } //Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr()) }
func CloseConnection(resp *http.Response) { time.Sleep(5 * time.Second) resp.Close = true resp.Body.Close() }
func (srv *Server) handler(c net.Conn) { startTime := time.Now() bpe := srv.bufferPool.take(c) defer srv.bufferPool.give(bpe) var closeSentinelChan = make(chan int) go srv.sentinel(c, closeSentinelChan) defer srv.connectionFinished(c, closeSentinelChan) var err error var req *http.Request // no keepalive (for now) reqCount := 0 keepAlive := true for err == nil && keepAlive { if req, err = http.ReadRequest(bpe.br); err == nil { if req.Header.Get("Connection") != "Keep-Alive" { keepAlive = false } request := newRequest(req, c, startTime) reqCount++ var res *http.Response pssInit := new(PipelineStageStat) pssInit.Name = "server.Init" pssInit.StartTime = startTime pssInit.EndTime = time.Now() request.appendPipelineStage(pssInit) // execute the pipeline if res = srv.Pipeline.execute(request); res == nil { res = SimpleResponse(req, 404, nil, "Not Found") } // cleanup request.startPipelineStage("server.ResponseWrite") req.Body.Close() // shutting down? select { case <-srv.stopAccepting: keepAlive = false res.Close = true default: } // write response if srv.sendfile { res.Write(c) } else { wbuf := bufio.NewWriter(c) res.Write(wbuf) wbuf.Flush() } if res.Body != nil { res.Body.Close() } request.finishPipelineStage() request.finishRequest() srv.requestFinished(request) // Reset the startTime // this isn't great since there may be lag between requests; but it's the best we've got startTime = time.Now() } else { // EOF is socket closed if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) { Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err) } } } //Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr()) }
// ReadResponse reads an HTTP response. The header is taken from h, // which must include the SPDY-specific fields starting with ':'. // If r is not nil, the body will be read from r. If t is not nil, // the trailer will be taken from t after the body is finished. func ReadResponse(h, t http.Header, r io.Reader, req *http.Request) (*http.Response, error) { for _, s := range badRespHeaderFields { if _, ok := h[s]; ok { return nil, &badStringError{"invalid header field", s} } } var err error resp := new(http.Response) resp.Request = req resp.Close = true resp.Header = make(http.Header) copyHeader(resp.Header, h) f := strings.SplitN(h.Get(":status"), " ", 2) var s string if len(f) > 1 { s = f[1] } resp.Status = f[0] + " " + s resp.StatusCode, err = strconv.Atoi(f[0]) if err != nil { return nil, &badStringError{"malformed HTTP status code", f[0]} } resp.Proto = h.Get(":version") var ok bool resp.ProtoMajor, resp.ProtoMinor, ok = http.ParseHTTPVersion(resp.Proto) if !ok { return nil, &badStringError{"malformed HTTP version", resp.Proto} } realLength, err := fixLength(true, resp.StatusCode, req.Method, resp.Header) if err != nil { return nil, err } if req.Method == "HEAD" { if n, err := parseContentLength(h.Get("Content-Length")); err != nil { return nil, err } else { resp.ContentLength = n } } else { resp.ContentLength = realLength } switch { case realLength == 0: r = eofReader case realLength > 0: if r == nil { // TODO(kr): return error } r = io.LimitReader(r, realLength) } if r == nil { r = eofReader } body := &body{r: r} resp.Body = body if t != nil { body.hdr = resp body.trailer = t } return resp, nil }
func (r *Response) Response() *http.Response { out := new(http.Response) r.headerM.Lock() out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode)) out.StatusCode = r.StatusCode out.Header = r.Header r.headerM.Unlock() out.Proto = "HTTP/1.1" out.ProtoMajor = 1 out.ProtoMinor = 1 r.dataM.Lock() if r.data == nil { out.Body = &ReadCloser{new(bytes.Buffer)} } else if unrequestedGzip(r) { // User-agents MUST support gzip compression. // Regardless of the Accept-Encoding sent by the user-agent, the server may // always send content encoded with gzip or deflate encoding. r.data.Prep() out.Header.Del("Content-Encoding") out.Header.Del("Content-Length") out.ContentLength = -1 out.Body = &gzipReader{body: r.data} } else { r.data.Prep() out.Body = r.data out.ContentLength = r.data.written } r.dataM.Unlock() out.TransferEncoding = nil out.Close = true out.Trailer = make(http.Header) out.Request = r.Request return out }