...

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

Documentation: net/http/httputil

		 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 Read or 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 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 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 Read or 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 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 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