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