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