Source file src/net/http/httputil/persist.go

     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 [ServerConn.Read] or [ServerConn.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 [ServerConn.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 [ServerConn.Read] side.
   175  func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
   176  
   177  	// Retrieve the pipeline ID of this request/response pair
   178  	sc.mu.Lock()
   179  	id, ok := sc.pipereq[req]
   180  	delete(sc.pipereq, req)
   181  	if !ok {
   182  		sc.mu.Unlock()
   183  		return ErrPipeline
   184  	}
   185  	sc.mu.Unlock()
   186  
   187  	// Ensure pipeline order
   188  	sc.pipe.StartResponse(id)
   189  	defer sc.pipe.EndResponse(id)
   190  
   191  	sc.mu.Lock()
   192  	if sc.we != nil {
   193  		defer sc.mu.Unlock()
   194  		return sc.we
   195  	}
   196  	if sc.c == nil { // connection closed by user in the meantime
   197  		defer sc.mu.Unlock()
   198  		return ErrClosed
   199  	}
   200  	c := sc.c
   201  	if sc.nread <= sc.nwritten {
   202  		defer sc.mu.Unlock()
   203  		return errors.New("persist server pipe count")
   204  	}
   205  	if resp.Close {
   206  		// After signaling a keep-alive close, any pipelined unread
   207  		// requests will be lost. It is up to the user to drain them
   208  		// before signaling.
   209  		sc.re = ErrPersistEOF
   210  	}
   211  	sc.mu.Unlock()
   212  
   213  	err := resp.Write(c)
   214  	sc.mu.Lock()
   215  	defer sc.mu.Unlock()
   216  	if err != nil {
   217  		sc.we = err
   218  		return err
   219  	}
   220  	sc.nwritten++
   221  
   222  	return nil
   223  }
   224  
   225  // ClientConn is an artifact of Go's early HTTP implementation.
   226  // It is low-level, old, and unused by Go's current HTTP stack.
   227  // We should have deleted it before Go 1.
   228  //
   229  // Deprecated: Use Client or Transport in package [net/http] instead.
   230  type ClientConn struct {
   231  	mu              sync.Mutex // read-write protects the following fields
   232  	c               net.Conn
   233  	r               *bufio.Reader
   234  	re, we          error // read/write errors
   235  	lastbody        io.ReadCloser
   236  	nread, nwritten int
   237  	pipereq         map[*http.Request]uint
   238  
   239  	pipe     textproto.Pipeline
   240  	writeReq func(*http.Request, io.Writer) error
   241  }
   242  
   243  // NewClientConn is an artifact of Go's early HTTP implementation.
   244  // It is low-level, old, and unused by Go's current HTTP stack.
   245  // We should have deleted it before Go 1.
   246  //
   247  // Deprecated: Use the Client or Transport in package [net/http] instead.
   248  func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
   249  	if r == nil {
   250  		r = bufio.NewReader(c)
   251  	}
   252  	return &ClientConn{
   253  		c:        c,
   254  		r:        r,
   255  		pipereq:  make(map[*http.Request]uint),
   256  		writeReq: (*http.Request).Write,
   257  	}
   258  }
   259  
   260  // NewProxyClientConn is an artifact of Go's early HTTP implementation.
   261  // It is low-level, old, and unused by Go's current HTTP stack.
   262  // We should have deleted it before Go 1.
   263  //
   264  // Deprecated: Use the Client or Transport in package [net/http] instead.
   265  func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
   266  	cc := NewClientConn(c, r)
   267  	cc.writeReq = (*http.Request).WriteProxy
   268  	return cc
   269  }
   270  
   271  // Hijack detaches the [ClientConn] and returns the underlying connection as well
   272  // as the read-side bufio which may have some left over data. Hijack may be
   273  // called before the user or Read have signaled the end of the keep-alive
   274  // logic. The user should not call Hijack while [ClientConn.Read] or ClientConn.Write is in progress.
   275  func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
   276  	cc.mu.Lock()
   277  	defer cc.mu.Unlock()
   278  	c = cc.c
   279  	r = cc.r
   280  	cc.c = nil
   281  	cc.r = nil
   282  	return
   283  }
   284  
   285  // Close calls [ClientConn.Hijack] and then also closes the underlying connection.
   286  func (cc *ClientConn) Close() error {
   287  	c, _ := cc.Hijack()
   288  	if c != nil {
   289  		return c.Close()
   290  	}
   291  	return nil
   292  }
   293  
   294  // Write writes a request. An [ErrPersistEOF] error is returned if the connection
   295  // has been closed in an HTTP keep-alive sense. If req.Close equals true, the
   296  // keep-alive connection is logically closed after this request and the opposing
   297  // server is informed. An ErrUnexpectedEOF indicates the remote closed the
   298  // underlying TCP connection, which is usually considered as graceful close.
   299  func (cc *ClientConn) Write(req *http.Request) error {
   300  	var err error
   301  
   302  	// Ensure ordered execution of Writes
   303  	id := cc.pipe.Next()
   304  	cc.pipe.StartRequest(id)
   305  	defer func() {
   306  		cc.pipe.EndRequest(id)
   307  		if err != nil {
   308  			cc.pipe.StartResponse(id)
   309  			cc.pipe.EndResponse(id)
   310  		} else {
   311  			// Remember the pipeline id of this request
   312  			cc.mu.Lock()
   313  			cc.pipereq[req] = id
   314  			cc.mu.Unlock()
   315  		}
   316  	}()
   317  
   318  	cc.mu.Lock()
   319  	if cc.re != nil { // no point sending if read-side closed or broken
   320  		defer cc.mu.Unlock()
   321  		return cc.re
   322  	}
   323  	if cc.we != nil {
   324  		defer cc.mu.Unlock()
   325  		return cc.we
   326  	}
   327  	if cc.c == nil { // connection closed by user in the meantime
   328  		defer cc.mu.Unlock()
   329  		return errClosed
   330  	}
   331  	c := cc.c
   332  	if req.Close {
   333  		// We write the EOF to the write-side error, because there
   334  		// still might be some pipelined reads
   335  		cc.we = ErrPersistEOF
   336  	}
   337  	cc.mu.Unlock()
   338  
   339  	err = cc.writeReq(req, c)
   340  	cc.mu.Lock()
   341  	defer cc.mu.Unlock()
   342  	if err != nil {
   343  		cc.we = err
   344  		return err
   345  	}
   346  	cc.nwritten++
   347  
   348  	return nil
   349  }
   350  
   351  // Pending returns the number of unanswered requests
   352  // that have been sent on the connection.
   353  func (cc *ClientConn) Pending() int {
   354  	cc.mu.Lock()
   355  	defer cc.mu.Unlock()
   356  	return cc.nwritten - cc.nread
   357  }
   358  
   359  // Read reads the next response from the wire. A valid response might be
   360  // returned together with an [ErrPersistEOF], which means that the remote
   361  // requested that this be the last request serviced. Read can be called
   362  // concurrently with [ClientConn.Write], but not with another Read.
   363  func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
   364  	// Retrieve the pipeline ID of this request/response pair
   365  	cc.mu.Lock()
   366  	id, ok := cc.pipereq[req]
   367  	delete(cc.pipereq, req)
   368  	if !ok {
   369  		cc.mu.Unlock()
   370  		return nil, ErrPipeline
   371  	}
   372  	cc.mu.Unlock()
   373  
   374  	// Ensure pipeline order
   375  	cc.pipe.StartResponse(id)
   376  	defer cc.pipe.EndResponse(id)
   377  
   378  	cc.mu.Lock()
   379  	if cc.re != nil {
   380  		defer cc.mu.Unlock()
   381  		return nil, cc.re
   382  	}
   383  	if cc.r == nil { // connection closed by user in the meantime
   384  		defer cc.mu.Unlock()
   385  		return nil, errClosed
   386  	}
   387  	r := cc.r
   388  	lastbody := cc.lastbody
   389  	cc.lastbody = nil
   390  	cc.mu.Unlock()
   391  
   392  	// Make sure body is fully consumed, even if user does not call body.Close
   393  	if lastbody != nil {
   394  		// body.Close is assumed to be idempotent and multiple calls to
   395  		// it should return the error that its first invocation
   396  		// returned.
   397  		err = lastbody.Close()
   398  		if err != nil {
   399  			cc.mu.Lock()
   400  			defer cc.mu.Unlock()
   401  			cc.re = err
   402  			return nil, err
   403  		}
   404  	}
   405  
   406  	resp, err = http.ReadResponse(r, req)
   407  	cc.mu.Lock()
   408  	defer cc.mu.Unlock()
   409  	if err != nil {
   410  		cc.re = err
   411  		return resp, err
   412  	}
   413  	cc.lastbody = resp.Body
   414  
   415  	cc.nread++
   416  
   417  	if resp.Close {
   418  		cc.re = ErrPersistEOF // don't send any more requests
   419  		return resp, cc.re
   420  	}
   421  	return resp, err
   422  }
   423  
   424  // Do is convenience method that writes a request and reads a response.
   425  func (cc *ClientConn) Do(req *http.Request) (*http.Response, error) {
   426  	err := cc.Write(req)
   427  	if err != nil {
   428  		return nil, err
   429  	}
   430  	return cc.Read(req)
   431  }
   432  

View as plain text