| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package http | |
| import ( | |
| "bufio" | |
| "container/list" | |
| "io" | |
| "net" | |
| "os" | |
| "sync" | |
| ) | |
| var ErrPersistEOF = &ProtocolError{"persistent connection closed"} | |
| // A ServerConn reads requests and sends responses over an underlying | |
| // connection, until the HTTP keepalive logic commands an end. ServerConn | |
| // does not close the underlying connection. Instead, the user calls Close | |
| // and regains control over the connection. ServerConn supports pipe-lining, | |
| // i.e. requests can be read out of sync (but in the same order) while the | |
| // respective responses are sent. | |
| type ServerConn struct { | |
| c net.Conn | |
| r *bufio.Reader | |
| clsd bool // indicates a graceful close | |
| re, we os.Error // read/write errors | |
| lastBody io.ReadCloser | |
| nread, nwritten int | |
| lk sync.Mutex // protected read/write to re,we | |
| } | |
| // NewServerConn returns a new ServerConn reading and writing c. If r is not | |
| // nil, it is the buffer to use when reading c. | |
| func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn { | |
| if r == nil { | |
| r = bufio.NewReader(c) | |
| } | |
| return &ServerConn{c: c, r: r} | |
| } | |
| // Close detaches the ServerConn and returns the underlying connection as well | |
| // as the read-side bufio which may have some left over data. Close may be | |
| // called before Read has signaled the end of the keep-alive logic. The user | |
| // should not call Close while Read or Write is in progress. | |
| func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) { | |
| sc.lk.Lock() | |
| defer sc.lk.Unlock() | |
| c = sc.c | |
| r = sc.r | |
| sc.c = nil | |
| sc.r = nil | |
| return | |
| } | |
| // Read returns the next request on the wire. An ErrPersistEOF is returned if | |
| // it is gracefully determined that there are no more requests (e.g. after the | |
| // first request on an HTTP/1.0 connection, or after a Connection:close on a | |
| // HTTP/1.1 connection). Read can be called concurrently with Write, but not | |
| // with another Read. | |
| func (sc *ServerConn) Read() (req *Request, err os.Error) { | |
| sc.lk.Lock() | |
| if sc.we != nil { // no point receiving if write-side broken or closed | |
| defer sc.lk.Unlock() | |
| return nil, sc.we | |
| } | |
| if sc.re != nil { | |
| defer sc.lk.Unlock() | |
| return nil, sc.re | |
| } | |
| sc.lk.Unlock() | |
| // Make sure body is fully consumed, even if user does not call body.Close | |
| if sc.lastBody != nil { | |
| // body.Close is assumed to be idempotent and multiple calls to | |
| // it should return the error that its first invokation | |
| // returned. | |
| err = sc.lastBody.Close() | |
| sc.lastBody = nil | |
| if err != nil { | |
| sc.lk.Lock() | |
| defer sc.lk.Unlock() | |
| sc.re = err | |
| return nil, err | |
| } | |
| } | |
| req, err = ReadRequest(sc.r) | |
| if err != nil { | |
| sc.lk.Lock() | |
| defer sc.lk.Unlock() | |
| if err == io.ErrUnexpectedEOF { | |
| // A close from the opposing client is treated as a | |
| // graceful close, even if there was some unparse-able | |
| // data before the close. | |
| sc.re = ErrPersistEOF | |
| return nil, sc.re | |
| } else { | |
| sc.re = err | |
| return | |
| } | |
| } | |
| sc.lastBody = req.Body | |
| sc.nread++ | |
| if req.Close { | |
| sc.lk.Lock() | |
| defer sc.lk.Unlock() | |
| sc.re = ErrPersistEOF | |
| return req, sc.re | |
| } | |
| return | |
| } | |
| // Pending returns the number of unanswered requests | |
| // that have been received on the connection. | |
| func (sc *ServerConn) Pending() int { | |
| sc.lk.Lock() | |
| defer sc.lk.Unlock() | |
| return sc.nread - sc.nwritten | |
| } | |
| // Write writes a repsonse. 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. | |
| // Write can be called concurrently with Read, but not with another Write. | |
| func (sc *ServerConn) Write(resp *Response) os.Error { | |
| sc.lk.Lock() | |
| if sc.we != nil { | |
| defer sc.lk.Unlock() | |
| return sc.we | |
| } | |
| sc.lk.Unlock() | |
| if sc.nread <= sc.nwritten { | |
| return os.NewError("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.lk.Lock() | |
| sc.re = ErrPersistEOF | |
| sc.lk.Unlock() | |
| } | |
| err := resp.Write(sc.c) | |
| if err != nil { | |
| sc.lk.Lock() | |
| defer sc.lk.Unlock() | |
| sc.we = err | |
| return err | |
| } | |
| sc.nwritten++ | |
| return nil | |
| } | |
| // A ClientConn sends request and receives headers over an underlying | |
| // connection, while respecting the HTTP keepalive logic. ClientConn is not | |
| // responsible for closing the underlying connection. One must call Close to | |
| // regain control of that connection and deal with it as desired. | |
| type ClientConn struct { | |
| c net.Conn | |
| r *bufio.Reader | |
| re, we os.Error // read/write errors | |
| lastBody io.ReadCloser | |
| nread, nwritten int | |
| reqm list.List // request methods in order of execution | |
| lk sync.Mutex // protects read/write to reqm,re,we | |
| } | |
| // NewClientConn returns a new ClientConn reading and writing c. If r is not | |
| // nil, it is the buffer to use when reading c. | |
| func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn { | |
| if r == nil { | |
| r = bufio.NewReader(c) | |
| } | |
| return &ClientConn{c: c, r: r} | |
| } | |
| // Close detaches the ClientConn and returns the underlying connection as well | |
| // as the read-side bufio which may have some left over data. Close may be | |
| // called before the user or Read have signaled the end of the keep-alive | |
| // logic. The user should not call Close while Read or Write is in progress. | |
| func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) { | |
| cc.lk.Lock() | |
| c = cc.c | |
| r = cc.r | |
| cc.c = nil | |
| cc.r = nil | |
| cc.reqm.Init() | |
| cc.lk.Unlock() | |
| return | |
| } | |
| // Write writes a request. An ErrPersistEOF error is returned if the connection | |
| // has been closed in an HTTP keepalive sense. If req.Close equals true, the | |
| // keepalive connection is logically closed after this request and the opposing | |
| // server is informed. An ErrUnexpectedEOF indicates the remote closed the | |
| // underlying TCP connection, which is usually considered as graceful close. | |
| // Write can be called concurrently with Read, but not with another Write. | |
| func (cc *ClientConn) Write(req *Request) os.Error { | |
| cc.lk.Lock() | |
| if cc.re != nil { // no point sending if read-side closed or broken | |
| defer cc.lk.Unlock() | |
| return cc.re | |
| } | |
| if cc.we != nil { | |
| defer cc.lk.Unlock() | |
| return cc.we | |
| } | |
| cc.lk.Unlock() | |
| if req.Close { | |
| // We write the EOF to the write-side error, because there | |
| // still might be some pipelined reads | |
| cc.lk.Lock() | |
| cc.we = ErrPersistEOF | |
| cc.lk.Unlock() | |
| } | |
| err := req.Write(cc.c) | |
| if err != nil { | |
| cc.lk.Lock() | |
| defer cc.lk.Unlock() | |
| cc.we = err | |
| return err | |
| } | |
| cc.nwritten++ | |
| cc.lk.Lock() | |
| cc.reqm.PushBack(req.Method) | |
| cc.lk.Unlock() | |
| return nil | |
| } | |
| // Pending returns the number of unanswered requests | |
| // that have been sent on the connection. | |
| func (cc *ClientConn) Pending() int { | |
| cc.lk.Lock() | |
| defer cc.lk.Unlock() | |
| return cc.nwritten - cc.nread | |
| } | |
| // Read reads the next response from the wire. A valid response might be | |
| // returned together with an ErrPersistEOF, which means that the remote | |
| // requested that this be the last request serviced. Read can be called | |
| // concurrently with Write, but not with another Read. | |
| func (cc *ClientConn) Read() (resp *Response, err os.Error) { | |
| cc.lk.Lock() | |
| if cc.re != nil { | |
| defer cc.lk.Unlock() | |
| return nil, cc.re | |
| } | |
| cc.lk.Unlock() | |
| if cc.nread >= cc.nwritten { | |
| return nil, os.NewError("persist client pipe count") | |
| } | |
| // Make sure body is fully consumed, even if user does not call body.Close | |
| if cc.lastBody != nil { | |
| // body.Close is assumed to be idempotent and multiple calls to | |
| // it should return the error that its first invokation | |
| // returned. | |
| err = cc.lastBody.Close() | |
| cc.lastBody = nil | |
| if err != nil { | |
| cc.lk.Lock() | |
| defer cc.lk.Unlock() | |
| cc.re = err | |
| return nil, err | |
| } | |
| } | |
| cc.lk.Lock() | |
| m := cc.reqm.Front() | |
| cc.reqm.Remove(m) | |
| cc.lk.Unlock() | |
| resp, err = ReadResponse(cc.r, m.Value.(string)) | |
| if err != nil { | |
| cc.lk.Lock() | |
| defer cc.lk.Unlock() | |
| cc.re = err | |
| return | |
| } | |
| cc.lastBody = resp.Body | |
| cc.nread++ | |
| if resp.Close { | |
| cc.lk.Lock() | |
| defer cc.lk.Unlock() | |
| cc.re = ErrPersistEOF // don't send any more requests | |
| return resp, cc.re | |
| } | |
| return | |
| } |