// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package httputilimport ()var (// Deprecated: No longer used.ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}// Deprecated: No longer used.ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}// Deprecated: No longer used.ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"})// This is an API usage error - the local side is closed.// ErrPersistEOF (above) reports that the remote side is closed.var errClosed = errors.New("i/o operation on closed connection")// ServerConn is an artifact of Go's early HTTP implementation.// It is low-level, old, and unused by Go's current HTTP stack.// We should have deleted it before Go 1.//// Deprecated: Use the Server in package [net/http] instead.typeServerConnstruct { mu sync.Mutex// read-write protects the following fields c net.Conn r *bufio.Reader re, we error// read/write errors lastbody io.ReadCloser nread, nwritten int pipereq map[*http.Request]uint pipe textproto.Pipeline}// NewServerConn is an artifact of Go's early HTTP implementation.// It is low-level, old, and unused by Go's current HTTP stack.// We should have deleted it before Go 1.//// Deprecated: Use the Server in package [net/http] instead.func ( net.Conn, *bufio.Reader) *ServerConn {if == nil { = bufio.NewReader() }return &ServerConn{c: , r: , pipereq: make(map[*http.Request]uint)}}// Hijack detaches the [ServerConn] and returns the underlying connection as well// as the read-side bufio which may have some left over data. Hijack may be// called before Read has signaled the end of the keep-alive logic. The user// should not call Hijack while [ServerConn.Read] or [ServerConn.Write] is in progress.func ( *ServerConn) () (net.Conn, *bufio.Reader) { .mu.Lock()defer .mu.Unlock() := .c := .r .c = nil .r = nilreturn , }// Close calls [ServerConn.Hijack] and then also closes the underlying connection.func ( *ServerConn) () error { , := .Hijack()if != nil {return .Close() }returnnil}// Read returns the next request on the wire. An [ErrPersistEOF] is returned if// it is gracefully determined that there are no more requests (e.g. after the// first request on an HTTP/1.0 connection, or after a Connection:close on a// HTTP/1.1 connection).func ( *ServerConn) () (*http.Request, error) {var *http.Requestvarerror// Ensure ordered execution of Reads and Writes := .pipe.Next() .pipe.StartRequest()deferfunc() { .pipe.EndRequest()if == nil { .pipe.StartResponse() .pipe.EndResponse() } else {// Remember the pipeline id of this request .mu.Lock() .pipereq[] = .mu.Unlock() } }() .mu.Lock()if .we != nil { // no point receiving if write-side broken or closeddefer .mu.Unlock()returnnil, .we }if .re != nil {defer .mu.Unlock()returnnil, .re }if .r == nil { // connection closed by user in the meantimedefer .mu.Unlock()returnnil, errClosed } := .r := .lastbody .lastbody = nil .mu.Unlock()// Make sure body is fully consumed, even if user does not call body.Closeif != nil {// body.Close is assumed to be idempotent and multiple calls to // it should return the error that its first invocation // returned. = .Close()if != nil { .mu.Lock()defer .mu.Unlock() .re = returnnil, } } , = http.ReadRequest() .mu.Lock()defer .mu.Unlock()if != nil {if == io.ErrUnexpectedEOF {// A close from the opposing client is treated as a // graceful close, even if there was some unparse-able // data before the close. .re = ErrPersistEOFreturnnil, .re } else { .re = return , } } .lastbody = .Body .nread++if .Close { .re = ErrPersistEOFreturn , .re }return , }// Pending returns the number of unanswered requests// that have been received on the connection.func ( *ServerConn) () int { .mu.Lock()defer .mu.Unlock()return .nread - .nwritten}// Write writes resp in response to req. To close the connection gracefully, set the// Response.Close field to true. Write should be considered operational until// it returns an error, regardless of any errors returned on the [ServerConn.Read] side.func ( *ServerConn) ( *http.Request, *http.Response) error {// Retrieve the pipeline ID of this request/response pair .mu.Lock() , := .pipereq[]delete(.pipereq, )if ! { .mu.Unlock()returnErrPipeline } .mu.Unlock()// Ensure pipeline order .pipe.StartResponse()defer .pipe.EndResponse() .mu.Lock()if .we != nil {defer .mu.Unlock()return .we }if .c == nil { // connection closed by user in the meantimedefer .mu.Unlock()returnErrClosed } := .cif .nread <= .nwritten {defer .mu.Unlock()returnerrors.New("persist server pipe count") }if .Close {// After signaling a keep-alive close, any pipelined unread // requests will be lost. It is up to the user to drain them // before signaling. .re = ErrPersistEOF } .mu.Unlock() := .Write() .mu.Lock()defer .mu.Unlock()if != nil { .we = return } .nwritten++returnnil}// ClientConn is an artifact of Go's early HTTP implementation.// It is low-level, old, and unused by Go's current HTTP stack.// We should have deleted it before Go 1.//// Deprecated: Use Client or Transport in package [net/http] instead.typeClientConnstruct { mu sync.Mutex// read-write protects the following fields c net.Conn r *bufio.Reader re, we error// read/write errors lastbody io.ReadCloser nread, nwritten int pipereq map[*http.Request]uint pipe textproto.Pipeline writeReq func(*http.Request, io.Writer) error}// NewClientConn is an artifact of Go's early HTTP implementation.// It is low-level, old, and unused by Go's current HTTP stack.// We should have deleted it before Go 1.//// Deprecated: Use the Client or Transport in package [net/http] instead.func ( net.Conn, *bufio.Reader) *ClientConn {if == nil { = bufio.NewReader() }return &ClientConn{c: ,r: ,pipereq: make(map[*http.Request]uint),writeReq: (*http.Request).Write, }}// NewProxyClientConn is an artifact of Go's early HTTP implementation.// It is low-level, old, and unused by Go's current HTTP stack.// We should have deleted it before Go 1.//// Deprecated: Use the Client or Transport in package [net/http] instead.func ( net.Conn, *bufio.Reader) *ClientConn { := NewClientConn(, ) .writeReq = (*http.Request).WriteProxyreturn}// Hijack detaches the [ClientConn] and returns the underlying connection as well// as the read-side bufio which may have some left over data. Hijack may be// called before the user or Read have signaled the end of the keep-alive// logic. The user should not call Hijack while [ClientConn.Read] or ClientConn.Write is in progress.func ( *ClientConn) () ( net.Conn, *bufio.Reader) { .mu.Lock()defer .mu.Unlock() = .c = .r .c = nil .r = nilreturn}// Close calls [ClientConn.Hijack] and then also closes the underlying connection.func ( *ClientConn) () error { , := .Hijack()if != nil {return .Close() }returnnil}// Write writes a request. An [ErrPersistEOF] error is returned if the connection// has been closed in an HTTP keep-alive sense. If req.Close equals true, the// keep-alive connection is logically closed after this request and the opposing// server is informed. An ErrUnexpectedEOF indicates the remote closed the// underlying TCP connection, which is usually considered as graceful close.func ( *ClientConn) ( *http.Request) error {varerror// Ensure ordered execution of Writes := .pipe.Next() .pipe.StartRequest()deferfunc() { .pipe.EndRequest()if != nil { .pipe.StartResponse() .pipe.EndResponse() } else {// Remember the pipeline id of this request .mu.Lock() .pipereq[] = .mu.Unlock() } }() .mu.Lock()if .re != nil { // no point sending if read-side closed or brokendefer .mu.Unlock()return .re }if .we != nil {defer .mu.Unlock()return .we }if .c == nil { // connection closed by user in the meantimedefer .mu.Unlock()returnerrClosed } := .cif .Close {// We write the EOF to the write-side error, because there // still might be some pipelined reads .we = ErrPersistEOF } .mu.Unlock() = .writeReq(, ) .mu.Lock()defer .mu.Unlock()if != nil { .we = return } .nwritten++returnnil}// Pending returns the number of unanswered requests// that have been sent on the connection.func ( *ClientConn) () int { .mu.Lock()defer .mu.Unlock()return .nwritten - .nread}// Read reads the next response from the wire. A valid response might be// returned together with an [ErrPersistEOF], which means that the remote// requested that this be the last request serviced. Read can be called// concurrently with [ClientConn.Write], but not with another Read.func ( *ClientConn) ( *http.Request) ( *http.Response, error) {// Retrieve the pipeline ID of this request/response pair .mu.Lock() , := .pipereq[]delete(.pipereq, )if ! { .mu.Unlock()returnnil, ErrPipeline } .mu.Unlock()// Ensure pipeline order .pipe.StartResponse()defer .pipe.EndResponse() .mu.Lock()if .re != nil {defer .mu.Unlock()returnnil, .re }if .r == nil { // connection closed by user in the meantimedefer .mu.Unlock()returnnil, errClosed } := .r := .lastbody .lastbody = nil .mu.Unlock()// Make sure body is fully consumed, even if user does not call body.Closeif != nil {// body.Close is assumed to be idempotent and multiple calls to // it should return the error that its first invocation // returned. = .Close()if != nil { .mu.Lock()defer .mu.Unlock() .re = returnnil, } } , = http.ReadResponse(, ) .mu.Lock()defer .mu.Unlock()if != nil { .re = return , } .lastbody = .Body .nread++if .Close { .re = ErrPersistEOF// don't send any more requestsreturn , .re }return , }// Do is convenience method that writes a request and reads a response.func ( *ClientConn) ( *http.Request) (*http.Response, error) { := .Write()if != nil {returnnil, }return .Read()}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.