// 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 }