Home | History | Annotate | Download | only in 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 keepalive sense. If req.Close equals true, the
    296 // keepalive 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