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 }