func (p *Proxy) forward(req *heat.Request) (*heat.Response, error) { if req.Body != nil { defer req.Body.Close() } // Enable keep-alive connections for outgoing requests. isKeepAlive := !heat.Closing(req.Major, req.Minor, req.Fields) req.Fields.Set("Connection", "keep-alive") // Issue the request. resp, err := p.RoundTrip(req) if err != nil { return nil, err } // Does the client expect the connection to be closed? if !isKeepAlive { resp.Fields.Set("Connection", "close") } else { resp.Fields.Set("Connection", "keep-alive") } return resp, nil }
func (p *Proxy) serveHTTPS(conn net.Conn, addr string) error { rw := xo.NewReadWriter( xo.NewReader(conn, make([]byte, 4096)), xo.NewWriter(conn, make([]byte, 4096)), ) for { req, body, err := readRequest(rw) if err != nil { switch err { case heat.ErrRequestHeader: resp := statusResponse(404, "Malformed HTTP request header.") return writeResponse(rw, resp, req.Method) case heat.ErrRequestVersion: resp := statusResponse(505, "Unsupported HTTP version number.") return writeResponse(rw, resp, req.Method) // If the connection terminated cleanly, stop. case io.EOF: return nil // Any other error would be from the underlying connection, and // should be propagated. default: return err } } // Populate the scheme and remote address. req.Scheme = "https" req.Remote = addr // Will the client close this connection after receiving a response? closing := heat.Closing(req.Major, req.Minor, req.Fields) // Forward the request to the upstream server. resp, err := p.forward(req) if err != nil { resp = statusResponse(500, "Round-trip to upstream failed: %s.", err) } // Are we closing the connection after sending the response? if !closing && (body == nil || body.LastError() == io.EOF) { resp.Fields.Set("Connection", "keep-alive") } else { resp.Fields.Set("Connection", "close") closing = true } // Write the response. err = writeResponse(rw, resp, req.Method) if err != nil { return err } // Stop if the connection isn't keep-alive. if closing { return nil } } }
func (p *Proxy) serveHTTP(conn net.Conn) error { rw := xo.NewReadWriter( xo.NewReader(conn, make([]byte, 4096)), xo.NewWriter(conn, make([]byte, 4096)), ) for { // Read the next request. req, body, err := readRequest(rw) if err != nil { switch err { case heat.ErrRequestHeader: resp := statusResponse(404, "Malformed HTTP request header.") return writeResponse(rw, resp, req.Method) case heat.ErrRequestVersion: resp := statusResponse(505, "Unsupported HTTP version number.") return writeResponse(rw, resp, req.Method) // If the connection terminated cleanly, stop. case io.EOF: return nil // Any other error would be from the underlying connection, and // should be propagated. default: return err } } // Support CONNECT tunneling. if req.Method == "CONNECT" { return p.connect(conn, rw, req) } // Will the client close this connection after receiving a response? closing := heat.Closing(req.Major, req.Minor, req.Fields) // Fetch the actual response from the upstream server. resp, err := p.proxy(req) if err != nil { resp := statusResponse(500, "Unknown error: %s.", err) return writeResponse(rw, resp, req.Method) } // Are we closing the connection after sending the response? if !closing && (body == nil || body.LastError() == io.EOF) { resp.Fields.Set("Connection", "keep-alive") } else { resp.Fields.Set("Connection", "close") closing = true } // Write the response. err = writeResponse(rw, resp, req.Method) if err != nil { return err } // Stop if the connection isn't keep-alive. if closing { return nil } } }