src/pkg/net/http/httputil/persist.go - The Go Programming Language

Golang

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