1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package httputil provides HTTP utility functions, complementing the
6 // more common ones in the net/http package.
21 ErrPersistEOF = &http.ProtocolError{"persistent connection closed"}
22 ErrPipeline = &http.ProtocolError{"pipeline error"}
25 // A ServerConn reads requests and sends responses over an underlying
26 // connection, until the HTTP keepalive logic commands an end. ServerConn
27 // also allows hijacking the underlying connection by calling Hijack
28 // to regain control over the connection. ServerConn supports pipe-lining,
29 // i.e. requests can be read out of sync (but in the same order) while the
30 // respective responses are sent.
32 // ServerConn is low-level and should not be needed by most applications.
34 type ServerConn struct {
35 lk sync.Mutex // read-write protects the following fields
38 re, we error // read/write errors
39 lastbody io.ReadCloser
41 pipereq map[*http.Request]uint
43 pipe textproto.Pipeline
46 // NewServerConn returns a new ServerConn reading and writing c. If r is not
47 // nil, it is the buffer to use when reading c.
48 func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
50 r = bufio.NewReader(c)
52 return &ServerConn{c: c, r: r, pipereq: make(map[*http.Request]uint)}
55 // Hijack detaches the ServerConn and returns the underlying connection as well
56 // as the read-side bufio which may have some left over data. Hijack may be
57 // called before Read has signaled the end of the keep-alive logic. The user
58 // should not call Hijack while Read or Write is in progress.
59 func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
69 // Close calls Hijack and then also closes the underlying connection
70 func (sc *ServerConn) Close() error {
78 // Read returns the next request on the wire. An ErrPersistEOF is returned if
79 // it is gracefully determined that there are no more requests (e.g. after the
80 // first request on an HTTP/1.0 connection, or after a Connection:close on a
81 // HTTP/1.1 connection).
82 func (sc *ServerConn) Read() (req *http.Request, err error) {
84 // Ensure ordered execution of Reads and Writes
86 sc.pipe.StartRequest(id)
88 sc.pipe.EndRequest(id)
90 sc.pipe.StartResponse(id)
91 sc.pipe.EndResponse(id)
93 // Remember the pipeline id of this request
101 if sc.we != nil { // no point receiving if write-side broken or closed
109 if sc.r == nil { // connection closed by user in the meantime
114 lastbody := sc.lastbody
118 // Make sure body is fully consumed, even if user does not call body.Close
120 // body.Close is assumed to be idempotent and multiple calls to
121 // it should return the error that its first invocation
123 err = lastbody.Close()
132 req, err = http.ReadRequest(r)
136 if err == io.ErrUnexpectedEOF {
137 // A close from the opposing client is treated as a
138 // graceful close, even if there was some unparse-able
139 // data before the close.
140 sc.re = ErrPersistEOF
147 sc.lastbody = req.Body
150 sc.re = ErrPersistEOF
156 // Pending returns the number of unanswered requests
157 // that have been received on the connection.
158 func (sc *ServerConn) Pending() int {
161 return sc.nread - sc.nwritten
164 // Write writes resp in response to req. To close the connection gracefully, set the
165 // Response.Close field to true. Write should be considered operational until
166 // it returns an error, regardless of any errors returned on the Read side.
167 func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
169 // Retrieve the pipeline ID of this request/response pair
171 id, ok := sc.pipereq[req]
172 delete(sc.pipereq, req)
179 // Ensure pipeline order
180 sc.pipe.StartResponse(id)
181 defer sc.pipe.EndResponse(id)
188 if sc.c == nil { // connection closed by user in the meantime
193 if sc.nread <= sc.nwritten {
195 return errors.New("persist server pipe count")
198 // After signaling a keep-alive close, any pipelined unread
199 // requests will be lost. It is up to the user to drain them
201 sc.re = ErrPersistEOF
217 // A ClientConn sends request and receives headers over an underlying
218 // connection, while respecting the HTTP keepalive logic. ClientConn
219 // supports hijacking the connection calling Hijack to
220 // regain control of the underlying net.Conn and deal with it as desired.
222 // ClientConn is low-level and should not be needed by most applications.
224 type ClientConn struct {
225 lk sync.Mutex // read-write protects the following fields
228 re, we error // read/write errors
229 lastbody io.ReadCloser
231 pipereq map[*http.Request]uint
233 pipe textproto.Pipeline
234 writeReq func(*http.Request, io.Writer) error
237 // NewClientConn returns a new ClientConn reading and writing c. If r is not
238 // nil, it is the buffer to use when reading c.
239 func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
241 r = bufio.NewReader(c)
246 pipereq: make(map[*http.Request]uint),
247 writeReq: (*http.Request).Write,
251 // NewProxyClientConn works like NewClientConn but writes Requests
252 // using Request's WriteProxy method.
253 func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
254 cc := NewClientConn(c, r)
255 cc.writeReq = (*http.Request).WriteProxy
259 // Hijack detaches the ClientConn and returns the underlying connection as well
260 // as the read-side bufio which may have some left over data. Hijack may be
261 // called before the user or Read have signaled the end of the keep-alive
262 // logic. The user should not call Hijack while Read or Write is in progress.
263 func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
273 // Close calls Hijack and then also closes the underlying connection
274 func (cc *ClientConn) Close() error {
282 // Write writes a request. An ErrPersistEOF error is returned if the connection
283 // has been closed in an HTTP keepalive sense. If req.Close equals true, the
284 // keepalive connection is logically closed after this request and the opposing
285 // server is informed. An ErrUnexpectedEOF indicates the remote closed the
286 // underlying TCP connection, which is usually considered as graceful close.
287 func (cc *ClientConn) Write(req *http.Request) (err error) {
289 // Ensure ordered execution of Writes
291 cc.pipe.StartRequest(id)
293 cc.pipe.EndRequest(id)
295 cc.pipe.StartResponse(id)
296 cc.pipe.EndResponse(id)
298 // Remember the pipeline id of this request
306 if cc.re != nil { // no point sending if read-side closed or broken
314 if cc.c == nil { // connection closed by user in the meantime
320 // We write the EOF to the write-side error, because there
321 // still might be some pipelined reads
322 cc.we = ErrPersistEOF
326 err = cc.writeReq(req, c)
338 // Pending returns the number of unanswered requests
339 // that have been sent on the connection.
340 func (cc *ClientConn) Pending() int {
343 return cc.nwritten - cc.nread
346 // Read reads the next response from the wire. A valid response might be
347 // returned together with an ErrPersistEOF, which means that the remote
348 // requested that this be the last request serviced. Read can be called
349 // concurrently with Write, but not with another Read.
350 func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
351 // Retrieve the pipeline ID of this request/response pair
353 id, ok := cc.pipereq[req]
354 delete(cc.pipereq, req)
357 return nil, ErrPipeline
361 // Ensure pipeline order
362 cc.pipe.StartResponse(id)
363 defer cc.pipe.EndResponse(id)
370 if cc.r == nil { // connection closed by user in the meantime
375 lastbody := cc.lastbody
379 // Make sure body is fully consumed, even if user does not call body.Close
381 // body.Close is assumed to be idempotent and multiple calls to
382 // it should return the error that its first invokation
384 err = lastbody.Close()
393 resp, err = http.ReadResponse(r, req)
400 cc.lastbody = resp.Body
405 cc.re = ErrPersistEOF // don't send any more requests
411 // Do is convenience method that writes a request and reads a response.
412 func (cc *ClientConn) Do(req *http.Request) (resp *http.Response, err error) {