github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/net/http/httputil/persist.go (about)

     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.
     4  
     5  package httputil
     6  
     7  import (
     8  	"bufio"
     9  	"errors"
    10  	"io"
    11  	"net"
    12  	"net/http"
    13  	"net/textproto"
    14  	"sync"
    15  )
    16  
    17  var (
    18  	ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
    19  	ErrClosed     = &http.ProtocolError{ErrorString: "connection closed by user"}
    20  	ErrPipeline   = &http.ProtocolError{ErrorString: "pipeline error"}
    21  )
    22  
    23  // This is an API usage error - the local side is closed.
    24  // ErrPersistEOF (above) reports that the remote side is closed.
    25  var errClosed = errors.New("i/o operation on closed connection")
    26  
    27  // A ServerConn reads requests and sends responses over an underlying
    28  // connection, until the HTTP keepalive logic commands an end. ServerConn
    29  // also allows hijacking the underlying connection by calling Hijack
    30  // to regain control over the connection. ServerConn supports pipe-lining,
    31  // i.e. requests can be read out of sync (but in the same order) while the
    32  // respective responses are sent.
    33  //
    34  // ServerConn is low-level and old. Applications should instead use Server
    35  // in the net/http package.
    36  type ServerConn struct {
    37  	lk              sync.Mutex // read-write protects the following fields
    38  	c               net.Conn
    39  	r               *bufio.Reader
    40  	re, we          error // read/write errors
    41  	lastbody        io.ReadCloser
    42  	nread, nwritten int
    43  	pipereq         map[*http.Request]uint
    44  
    45  	pipe textproto.Pipeline
    46  }
    47  
    48  // NewServerConn returns a new ServerConn reading and writing c. If r is not
    49  // nil, it is the buffer to use when reading c.
    50  //
    51  // ServerConn is low-level and old. Applications should instead use Server
    52  // in the net/http package.
    53  func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
    54  	if r == nil {
    55  		r = bufio.NewReader(c)
    56  	}
    57  	return &ServerConn{c: c, r: r, pipereq: make(map[*http.Request]uint)}
    58  }
    59  
    60  // Hijack detaches the ServerConn and returns the underlying connection as well
    61  // as the read-side bufio which may have some left over data. Hijack may be
    62  // called before Read has signaled the end of the keep-alive logic. The user
    63  // should not call Hijack while Read or Write is in progress.
    64  func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
    65  	sc.lk.Lock()
    66  	defer sc.lk.Unlock()
    67  	c = sc.c
    68  	r = sc.r
    69  	sc.c = nil
    70  	sc.r = nil
    71  	return
    72  }
    73  
    74  // Close calls Hijack and then also closes the underlying connection
    75  func (sc *ServerConn) Close() error {
    76  	c, _ := sc.Hijack()
    77  	if c != nil {
    78  		return c.Close()
    79  	}
    80  	return nil
    81  }
    82  
    83  // Read returns the next request on the wire. An ErrPersistEOF is returned if
    84  // it is gracefully determined that there are no more requests (e.g. after the
    85  // first request on an HTTP/1.0 connection, or after a Connection:close on a
    86  // HTTP/1.1 connection).
    87  func (sc *ServerConn) Read() (req *http.Request, err error) {
    88  
    89  	// Ensure ordered execution of Reads and Writes
    90  	id := sc.pipe.Next()
    91  	sc.pipe.StartRequest(id)
    92  	defer func() {
    93  		sc.pipe.EndRequest(id)
    94  		if req == nil {
    95  			sc.pipe.StartResponse(id)
    96  			sc.pipe.EndResponse(id)
    97  		} else {
    98  			// Remember the pipeline id of this request
    99  			sc.lk.Lock()
   100  			sc.pipereq[req] = id
   101  			sc.lk.Unlock()
   102  		}
   103  	}()
   104  
   105  	sc.lk.Lock()
   106  	if sc.we != nil { // no point receiving if write-side broken or closed
   107  		defer sc.lk.Unlock()
   108  		return nil, sc.we
   109  	}
   110  	if sc.re != nil {
   111  		defer sc.lk.Unlock()
   112  		return nil, sc.re
   113  	}
   114  	if sc.r == nil { // connection closed by user in the meantime
   115  		defer sc.lk.Unlock()
   116  		return nil, errClosed
   117  	}
   118  	r := sc.r
   119  	lastbody := sc.lastbody
   120  	sc.lastbody = nil
   121  	sc.lk.Unlock()
   122  
   123  	// Make sure body is fully consumed, even if user does not call body.Close
   124  	if lastbody != nil {
   125  		// body.Close is assumed to be idempotent and multiple calls to
   126  		// it should return the error that its first invocation
   127  		// returned.
   128  		err = lastbody.Close()
   129  		if err != nil {
   130  			sc.lk.Lock()
   131  			defer sc.lk.Unlock()
   132  			sc.re = err
   133  			return nil, err
   134  		}
   135  	}
   136  
   137  	req, err = http.ReadRequest(r)
   138  	sc.lk.Lock()
   139  	defer sc.lk.Unlock()
   140  	if err != nil {
   141  		if err == io.ErrUnexpectedEOF {
   142  			// A close from the opposing client is treated as a
   143  			// graceful close, even if there was some unparse-able
   144  			// data before the close.
   145  			sc.re = ErrPersistEOF
   146  			return nil, sc.re
   147  		} else {
   148  			sc.re = err
   149  			return req, err
   150  		}
   151  	}
   152  	sc.lastbody = req.Body
   153  	sc.nread++
   154  	if req.Close {
   155  		sc.re = ErrPersistEOF
   156  		return req, sc.re
   157  	}
   158  	return req, err
   159  }
   160  
   161  // Pending returns the number of unanswered requests
   162  // that have been received on the connection.
   163  func (sc *ServerConn) Pending() int {
   164  	sc.lk.Lock()
   165  	defer sc.lk.Unlock()
   166  	return sc.nread - sc.nwritten
   167  }
   168  
   169  // Write writes resp in response to req. To close the connection gracefully, set the
   170  // Response.Close field to true. Write should be considered operational until
   171  // it returns an error, regardless of any errors returned on the Read side.
   172  func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
   173  
   174  	// Retrieve the pipeline ID of this request/response pair
   175  	sc.lk.Lock()
   176  	id, ok := sc.pipereq[req]
   177  	delete(sc.pipereq, req)
   178  	if !ok {
   179  		sc.lk.Unlock()
   180  		return ErrPipeline
   181  	}
   182  	sc.lk.Unlock()
   183  
   184  	// Ensure pipeline order
   185  	sc.pipe.StartResponse(id)
   186  	defer sc.pipe.EndResponse(id)
   187  
   188  	sc.lk.Lock()
   189  	if sc.we != nil {
   190  		defer sc.lk.Unlock()
   191  		return sc.we
   192  	}
   193  	if sc.c == nil { // connection closed by user in the meantime
   194  		defer sc.lk.Unlock()
   195  		return ErrClosed
   196  	}
   197  	c := sc.c
   198  	if sc.nread <= sc.nwritten {
   199  		defer sc.lk.Unlock()
   200  		return errors.New("persist server pipe count")
   201  	}
   202  	if resp.Close {
   203  		// After signaling a keep-alive close, any pipelined unread
   204  		// requests will be lost. It is up to the user to drain them
   205  		// before signaling.
   206  		sc.re = ErrPersistEOF
   207  	}
   208  	sc.lk.Unlock()
   209  
   210  	err := resp.Write(c)
   211  	sc.lk.Lock()
   212  	defer sc.lk.Unlock()
   213  	if err != nil {
   214  		sc.we = err
   215  		return err
   216  	}
   217  	sc.nwritten++
   218  
   219  	return nil
   220  }
   221  
   222  // A ClientConn sends request and receives headers over an underlying
   223  // connection, while respecting the HTTP keepalive logic. ClientConn
   224  // supports hijacking the connection calling Hijack to
   225  // regain control of the underlying net.Conn and deal with it as desired.
   226  //
   227  // ClientConn is low-level and old. Applications should instead use
   228  // Client or Transport in the net/http package.
   229  type ClientConn struct {
   230  	lk              sync.Mutex // read-write protects the following fields
   231  	c               net.Conn
   232  	r               *bufio.Reader
   233  	re, we          error // read/write errors
   234  	lastbody        io.ReadCloser
   235  	nread, nwritten int
   236  	pipereq         map[*http.Request]uint
   237  
   238  	pipe     textproto.Pipeline
   239  	writeReq func(*http.Request, io.Writer) error
   240  }
   241  
   242  // NewClientConn returns a new ClientConn reading and writing c.  If r is not
   243  // nil, it is the buffer to use when reading c.
   244  //
   245  // ClientConn is low-level and old. Applications should use Client or
   246  // Transport in the net/http package.
   247  func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
   248  	if r == nil {
   249  		r = bufio.NewReader(c)
   250  	}
   251  	return &ClientConn{
   252  		c:        c,
   253  		r:        r,
   254  		pipereq:  make(map[*http.Request]uint),
   255  		writeReq: (*http.Request).Write,
   256  	}
   257  }
   258  
   259  // NewProxyClientConn works like NewClientConn but writes Requests
   260  // using Request's WriteProxy method.
   261  //
   262  // New code should not use NewProxyClientConn. See Client or
   263  // Transport in the net/http package instead.
   264  func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
   265  	cc := NewClientConn(c, r)
   266  	cc.writeReq = (*http.Request).WriteProxy
   267  	return cc
   268  }
   269  
   270  // Hijack detaches the ClientConn and returns the underlying connection as well
   271  // as the read-side bufio which may have some left over data. Hijack may be
   272  // called before the user or Read have signaled the end of the keep-alive
   273  // logic. The user should not call Hijack while Read or Write is in progress.
   274  func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
   275  	cc.lk.Lock()
   276  	defer cc.lk.Unlock()
   277  	c = cc.c
   278  	r = cc.r
   279  	cc.c = nil
   280  	cc.r = nil
   281  	return
   282  }
   283  
   284  // Close calls Hijack and then also closes the underlying connection
   285  func (cc *ClientConn) Close() error {
   286  	c, _ := cc.Hijack()
   287  	if c != nil {
   288  		return c.Close()
   289  	}
   290  	return nil
   291  }
   292  
   293  // Write writes a request. An ErrPersistEOF error is returned if the connection
   294  // has been closed in an HTTP keepalive sense. If req.Close equals true, the
   295  // keepalive connection is logically closed after this request and the opposing
   296  // server is informed. An ErrUnexpectedEOF indicates the remote closed the
   297  // underlying TCP connection, which is usually considered as graceful close.
   298  func (cc *ClientConn) Write(req *http.Request) (err error) {
   299  
   300  	// Ensure ordered execution of Writes
   301  	id := cc.pipe.Next()
   302  	cc.pipe.StartRequest(id)
   303  	defer func() {
   304  		cc.pipe.EndRequest(id)
   305  		if err != nil {
   306  			cc.pipe.StartResponse(id)
   307  			cc.pipe.EndResponse(id)
   308  		} else {
   309  			// Remember the pipeline id of this request
   310  			cc.lk.Lock()
   311  			cc.pipereq[req] = id
   312  			cc.lk.Unlock()
   313  		}
   314  	}()
   315  
   316  	cc.lk.Lock()
   317  	if cc.re != nil { // no point sending if read-side closed or broken
   318  		defer cc.lk.Unlock()
   319  		return cc.re
   320  	}
   321  	if cc.we != nil {
   322  		defer cc.lk.Unlock()
   323  		return cc.we
   324  	}
   325  	if cc.c == nil { // connection closed by user in the meantime
   326  		defer cc.lk.Unlock()
   327  		return errClosed
   328  	}
   329  	c := cc.c
   330  	if req.Close {
   331  		// We write the EOF to the write-side error, because there
   332  		// still might be some pipelined reads
   333  		cc.we = ErrPersistEOF
   334  	}
   335  	cc.lk.Unlock()
   336  
   337  	err = cc.writeReq(req, c)
   338  	cc.lk.Lock()
   339  	defer cc.lk.Unlock()
   340  	if err != nil {
   341  		cc.we = err
   342  		return err
   343  	}
   344  	cc.nwritten++
   345  
   346  	return nil
   347  }
   348  
   349  // Pending returns the number of unanswered requests
   350  // that have been sent on the connection.
   351  func (cc *ClientConn) Pending() int {
   352  	cc.lk.Lock()
   353  	defer cc.lk.Unlock()
   354  	return cc.nwritten - cc.nread
   355  }
   356  
   357  // Read reads the next response from the wire. A valid response might be
   358  // returned together with an ErrPersistEOF, which means that the remote
   359  // requested that this be the last request serviced. Read can be called
   360  // concurrently with Write, but not with another Read.
   361  func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
   362  	// Retrieve the pipeline ID of this request/response pair
   363  	cc.lk.Lock()
   364  	id, ok := cc.pipereq[req]
   365  	delete(cc.pipereq, req)
   366  	if !ok {
   367  		cc.lk.Unlock()
   368  		return nil, ErrPipeline
   369  	}
   370  	cc.lk.Unlock()
   371  
   372  	// Ensure pipeline order
   373  	cc.pipe.StartResponse(id)
   374  	defer cc.pipe.EndResponse(id)
   375  
   376  	cc.lk.Lock()
   377  	if cc.re != nil {
   378  		defer cc.lk.Unlock()
   379  		return nil, cc.re
   380  	}
   381  	if cc.r == nil { // connection closed by user in the meantime
   382  		defer cc.lk.Unlock()
   383  		return nil, errClosed
   384  	}
   385  	r := cc.r
   386  	lastbody := cc.lastbody
   387  	cc.lastbody = nil
   388  	cc.lk.Unlock()
   389  
   390  	// Make sure body is fully consumed, even if user does not call body.Close
   391  	if lastbody != nil {
   392  		// body.Close is assumed to be idempotent and multiple calls to
   393  		// it should return the error that its first invocation
   394  		// returned.
   395  		err = lastbody.Close()
   396  		if err != nil {
   397  			cc.lk.Lock()
   398  			defer cc.lk.Unlock()
   399  			cc.re = err
   400  			return nil, err
   401  		}
   402  	}
   403  
   404  	resp, err = http.ReadResponse(r, req)
   405  	cc.lk.Lock()
   406  	defer cc.lk.Unlock()
   407  	if err != nil {
   408  		cc.re = err
   409  		return resp, err
   410  	}
   411  	cc.lastbody = resp.Body
   412  
   413  	cc.nread++
   414  
   415  	if resp.Close {
   416  		cc.re = ErrPersistEOF // don't send any more requests
   417  		return resp, cc.re
   418  	}
   419  	return resp, err
   420  }
   421  
   422  // Do is convenience method that writes a request and reads a response.
   423  func (cc *ClientConn) Do(req *http.Request) (resp *http.Response, err error) {
   424  	err = cc.Write(req)
   425  	if err != nil {
   426  		return
   427  	}
   428  	return cc.Read(req)
   429  }