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