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