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