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