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