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