vendor: revendor for gRPC
This commit is contained in:
14
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
14
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
@@ -52,7 +52,16 @@ const (
|
||||
noDialOnMiss = false
|
||||
)
|
||||
|
||||
func (p *clientConnPool) getClientConn(_ *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
|
||||
func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
|
||||
if isConnectionCloseRequest(req) && dialOnMiss {
|
||||
// It gets its own connection.
|
||||
const singleUse = true
|
||||
cc, err := p.t.dialClientConn(addr, singleUse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
p.mu.Lock()
|
||||
for _, cc := range p.conns[addr] {
|
||||
if cc.CanTakeNewRequest() {
|
||||
@@ -95,7 +104,8 @@ func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
|
||||
|
||||
// run in its own goroutine.
|
||||
func (c *dialCall) dial(addr string) {
|
||||
c.res, c.err = c.p.t.dialClientConn(addr)
|
||||
const singleUse = false // shared conn
|
||||
c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
|
||||
close(c.done)
|
||||
|
||||
c.p.mu.Lock()
|
||||
|
2
vendor/golang.org/x/net/http2/frame.go
generated
vendored
2
vendor/golang.org/x/net/http2/frame.go
generated
vendored
@@ -454,7 +454,7 @@ func terminalReadFrameError(err error) bool {
|
||||
//
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize, the
|
||||
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||
// ConnectionError, StreamError, or anything else from from the underlying
|
||||
// ConnectionError, StreamError, or anything else from the underlying
|
||||
// reader.
|
||||
func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
fr.errDetail = nil
|
||||
|
27
vendor/golang.org/x/net/http2/go16.go
generated
vendored
27
vendor/golang.org/x/net/http2/go16.go
generated
vendored
@@ -7,6 +7,7 @@
|
||||
package http2
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -14,3 +15,29 @@ import (
|
||||
func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
|
||||
return t1.ExpectContinueTimeout
|
||||
}
|
||||
|
||||
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
|
||||
func isBadCipher(cipher uint16) bool {
|
||||
switch cipher {
|
||||
case tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
// Reject cipher suites from Appendix A.
|
||||
// "This list includes those cipher suites that do not
|
||||
// offer an ephemeral key exchange and those that are
|
||||
// based on the TLS null, stream or block cipher type"
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
26
vendor/golang.org/x/net/http2/not_go16.go
generated
vendored
26
vendor/golang.org/x/net/http2/not_go16.go
generated
vendored
@@ -7,6 +7,7 @@
|
||||
package http2
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -17,4 +18,29 @@ func configureTransport(t1 *http.Transport) (*Transport, error) {
|
||||
|
||||
func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
|
||||
func isBadCipher(cipher uint16) bool {
|
||||
switch cipher {
|
||||
case tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
// Reject cipher suites from Appendix A.
|
||||
// "This list includes those cipher suites that do not
|
||||
// offer an ephemeral key exchange and those that are
|
||||
// based on the TLS null, stream or block cipher type"
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
45
vendor/golang.org/x/net/http2/server.go
generated
vendored
45
vendor/golang.org/x/net/http2/server.go
generated
vendored
@@ -339,30 +339,6 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
||||
sc.serve()
|
||||
}
|
||||
|
||||
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
|
||||
func isBadCipher(cipher uint16) bool {
|
||||
switch cipher {
|
||||
case tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
// Reject cipher suites from Appendix A.
|
||||
// "This list includes those cipher suites that do not
|
||||
// offer an ephemeral key exchange and those that are
|
||||
// based on the TLS null, stream or block cipher type"
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *serverConn) rejectConn(err ErrCode, debug string) {
|
||||
sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
|
||||
// ignoring errors. hanging up anyway.
|
||||
@@ -1200,6 +1176,10 @@ func (sc *serverConn) closeStream(st *stream, err error) {
|
||||
}
|
||||
delete(sc.streams, st.id)
|
||||
if p := st.body; p != nil {
|
||||
// Return any buffered unread bytes worth of conn-level flow control.
|
||||
// See golang.org/issue/16481
|
||||
sc.sendWindowUpdate(nil, p.Len())
|
||||
|
||||
p.CloseWithError(err)
|
||||
}
|
||||
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
|
||||
@@ -1301,6 +1281,8 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
|
||||
|
||||
func (sc *serverConn) processData(f *DataFrame) error {
|
||||
sc.serveG.check()
|
||||
data := f.Data()
|
||||
|
||||
// "If a DATA frame is received whose stream is not in "open"
|
||||
// or "half closed (local)" state, the recipient MUST respond
|
||||
// with a stream error (Section 5.4.2) of type STREAM_CLOSED."
|
||||
@@ -1312,12 +1294,25 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
||||
// the http.Handler returned, so it's done reading &
|
||||
// done writing). Try to stop the client from sending
|
||||
// more DATA.
|
||||
|
||||
// But still enforce their connection-level flow control,
|
||||
// and return any flow control bytes since we're not going
|
||||
// to consume them.
|
||||
if int(sc.inflow.available()) < len(data) {
|
||||
return StreamError{id, ErrCodeFlowControl}
|
||||
}
|
||||
// Deduct the flow control from inflow, since we're
|
||||
// going to immediately add it back in
|
||||
// sendWindowUpdate, which also schedules sending the
|
||||
// frames.
|
||||
sc.inflow.take(int32(len(data)))
|
||||
sc.sendWindowUpdate(nil, len(data)) // conn-level
|
||||
|
||||
return StreamError{id, ErrCodeStreamClosed}
|
||||
}
|
||||
if st.body == nil {
|
||||
panic("internal error: should have a body in this state")
|
||||
}
|
||||
data := f.Data()
|
||||
|
||||
// Sender sending more than they'd declared?
|
||||
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
|
||||
|
45
vendor/golang.org/x/net/http2/server_test.go
generated
vendored
45
vendor/golang.org/x/net/http2/server_test.go
generated
vendored
@@ -104,6 +104,8 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
|
||||
case optQuiet:
|
||||
quiet = true
|
||||
}
|
||||
case func(net.Conn, http.ConnState):
|
||||
ts.Config.ConnState = v
|
||||
default:
|
||||
t.Fatalf("unknown newServerTester option type %T", v)
|
||||
}
|
||||
@@ -2165,6 +2167,9 @@ func TestServer_NoCrash_HandlerClose_Then_ClientClose(t *testing.T) {
|
||||
// it did before.
|
||||
st.writeData(1, true, []byte("foo"))
|
||||
|
||||
// Get our flow control bytes back, since the handler didn't get them.
|
||||
st.wantWindowUpdate(0, uint32(len("foo")))
|
||||
|
||||
// Sent after a peer sends data anyway (admittedly the
|
||||
// previous RST_STREAM might've still been in-flight),
|
||||
// but they'll get the more friendly 'cancel' code
|
||||
@@ -3299,3 +3304,43 @@ func TestExpect100ContinueAfterHandlerWrites(t *testing.T) {
|
||||
t.Fatalf("second msg = %q; want %q", buf, msg2)
|
||||
}
|
||||
}
|
||||
|
||||
type funcReader func([]byte) (n int, err error)
|
||||
|
||||
func (f funcReader) Read(p []byte) (n int, err error) { return f(p) }
|
||||
|
||||
// golang.org/issue/16481 -- return flow control when streams close with unread data.
|
||||
// (The Server version of the bug. See also TestUnreadFlowControlReturned_Transport)
|
||||
func TestUnreadFlowControlReturned_Server(t *testing.T) {
|
||||
unblock := make(chan bool, 1)
|
||||
defer close(unblock)
|
||||
|
||||
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
// Don't read the 16KB request body. Wait until the client's
|
||||
// done sending it and then return. This should cause the Server
|
||||
// to then return those 16KB of flow control to the client.
|
||||
<-unblock
|
||||
}, optOnlyServer)
|
||||
defer st.Close()
|
||||
|
||||
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
||||
defer tr.CloseIdleConnections()
|
||||
|
||||
// This previously hung on the 4th iteration.
|
||||
for i := 0; i < 6; i++ {
|
||||
body := io.MultiReader(
|
||||
io.LimitReader(neverEnding('A'), 16<<10),
|
||||
funcReader(func([]byte) (n int, err error) {
|
||||
unblock <- true
|
||||
return 0, io.EOF
|
||||
}),
|
||||
)
|
||||
req, _ := http.NewRequest("POST", st.ts.URL, body)
|
||||
res, err := tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
}
|
||||
|
||||
}
|
||||
|
159
vendor/golang.org/x/net/http2/transport.go
generated
vendored
159
vendor/golang.org/x/net/http2/transport.go
generated
vendored
@@ -139,9 +139,10 @@ func (t *Transport) initConnPool() {
|
||||
// ClientConn is the state of a single HTTP/2 client connection to an
|
||||
// HTTP/2 server.
|
||||
type ClientConn struct {
|
||||
t *Transport
|
||||
tconn net.Conn // usually *tls.Conn, except specialized impls
|
||||
tlsState *tls.ConnectionState // nil only for specialized impls
|
||||
t *Transport
|
||||
tconn net.Conn // usually *tls.Conn, except specialized impls
|
||||
tlsState *tls.ConnectionState // nil only for specialized impls
|
||||
singleUse bool // whether being used for a single http.Request
|
||||
|
||||
// readLoop goroutine fields:
|
||||
readerDone chan struct{} // closed on error
|
||||
@@ -153,6 +154,7 @@ type ClientConn struct {
|
||||
inflow flow // peer's conn-level flow control
|
||||
closed bool
|
||||
goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received
|
||||
goAwayDebug string // goAway frame's debug data, retained as a string
|
||||
streams map[uint32]*clientStream // client-initiated
|
||||
nextStreamID uint32
|
||||
bw *bufio.Writer
|
||||
@@ -337,7 +339,7 @@ func shouldRetryRequest(req *http.Request, err error) bool {
|
||||
return err == errClientConnUnusable
|
||||
}
|
||||
|
||||
func (t *Transport) dialClientConn(addr string) (*ClientConn, error) {
|
||||
func (t *Transport) dialClientConn(addr string, singleUse bool) (*ClientConn, error) {
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -346,7 +348,7 @@ func (t *Transport) dialClientConn(addr string) (*ClientConn, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.NewClientConn(tconn)
|
||||
return t.newClientConn(tconn, singleUse)
|
||||
}
|
||||
|
||||
func (t *Transport) newTLSConfig(host string) *tls.Config {
|
||||
@@ -407,6 +409,10 @@ func (t *Transport) expectContinueTimeout() time.Duration {
|
||||
}
|
||||
|
||||
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
return t.newClientConn(c, false)
|
||||
}
|
||||
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
|
||||
if VerboseLogs {
|
||||
t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
|
||||
}
|
||||
@@ -424,6 +430,7 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
initialWindowSize: 65535, // spec default
|
||||
maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough.
|
||||
streams: make(map[uint32]*clientStream),
|
||||
singleUse: singleUse,
|
||||
}
|
||||
cc.cond = sync.NewCond(&cc.mu)
|
||||
cc.flow.add(int32(initialWindowSize))
|
||||
@@ -494,7 +501,17 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
func (cc *ClientConn) setGoAway(f *GoAwayFrame) {
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
|
||||
old := cc.goAway
|
||||
cc.goAway = f
|
||||
|
||||
// Merge the previous and current GoAway error frames.
|
||||
if cc.goAwayDebug == "" {
|
||||
cc.goAwayDebug = string(f.DebugData())
|
||||
}
|
||||
if old != nil && old.ErrCode != ErrCodeNo {
|
||||
cc.goAway.ErrCode = old.ErrCode
|
||||
}
|
||||
}
|
||||
|
||||
func (cc *ClientConn) CanTakeNewRequest() bool {
|
||||
@@ -504,6 +521,9 @@ func (cc *ClientConn) CanTakeNewRequest() bool {
|
||||
}
|
||||
|
||||
func (cc *ClientConn) canTakeNewRequestLocked() bool {
|
||||
if cc.singleUse && cc.nextStreamID > 1 {
|
||||
return false
|
||||
}
|
||||
return cc.goAway == nil && !cc.closed &&
|
||||
int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
|
||||
cc.nextStreamID < 2147483647
|
||||
@@ -732,30 +752,34 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
bodyWritten := false
|
||||
ctx := reqContext(req)
|
||||
|
||||
handleReadLoopResponse := func(re resAndError) (*http.Response, error) {
|
||||
res := re.res
|
||||
if re.err != nil || res.StatusCode > 299 {
|
||||
// On error or status code 3xx, 4xx, 5xx, etc abort any
|
||||
// ongoing write, assuming that the server doesn't care
|
||||
// about our request body. If the server replied with 1xx or
|
||||
// 2xx, however, then assume the server DOES potentially
|
||||
// want our body (e.g. full-duplex streaming:
|
||||
// golang.org/issue/13444). If it turns out the server
|
||||
// doesn't, they'll RST_STREAM us soon enough. This is a
|
||||
// heuristic to avoid adding knobs to Transport. Hopefully
|
||||
// we can keep it.
|
||||
bodyWriter.cancel()
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWrite)
|
||||
}
|
||||
if re.err != nil {
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, re.err
|
||||
}
|
||||
res.Request = req
|
||||
res.TLS = cc.tlsState
|
||||
return res, nil
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case re := <-readLoopResCh:
|
||||
res := re.res
|
||||
if re.err != nil || res.StatusCode > 299 {
|
||||
// On error or status code 3xx, 4xx, 5xx, etc abort any
|
||||
// ongoing write, assuming that the server doesn't care
|
||||
// about our request body. If the server replied with 1xx or
|
||||
// 2xx, however, then assume the server DOES potentially
|
||||
// want our body (e.g. full-duplex streaming:
|
||||
// golang.org/issue/13444). If it turns out the server
|
||||
// doesn't, they'll RST_STREAM us soon enough. This is a
|
||||
// heuristic to avoid adding knobs to Transport. Hopefully
|
||||
// we can keep it.
|
||||
bodyWriter.cancel()
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWrite)
|
||||
}
|
||||
if re.err != nil {
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, re.err
|
||||
}
|
||||
res.Request = req
|
||||
res.TLS = cc.tlsState
|
||||
return res, nil
|
||||
return handleReadLoopResponse(re)
|
||||
case <-respHeaderTimer:
|
||||
cc.forgetStreamID(cs.ID)
|
||||
if !hasBody || bodyWritten {
|
||||
@@ -789,6 +813,12 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// forgetStreamID.
|
||||
return nil, cs.resetErr
|
||||
case err := <-bodyWriter.resc:
|
||||
// Prefer the read loop's response, if available. Issue 16102.
|
||||
select {
|
||||
case re := <-readLoopResCh:
|
||||
return handleReadLoopResponse(re)
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1160,6 +1190,19 @@ func (cc *ClientConn) readLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
// GoAwayError is returned by the Transport when the server closes the
|
||||
// TCP connection after sending a GOAWAY frame.
|
||||
type GoAwayError struct {
|
||||
LastStreamID uint32
|
||||
ErrCode ErrCode
|
||||
DebugData string
|
||||
}
|
||||
|
||||
func (e GoAwayError) Error() string {
|
||||
return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
|
||||
e.LastStreamID, e.ErrCode, e.DebugData)
|
||||
}
|
||||
|
||||
func (rl *clientConnReadLoop) cleanup() {
|
||||
cc := rl.cc
|
||||
defer cc.tconn.Close()
|
||||
@@ -1170,10 +1213,18 @@ func (rl *clientConnReadLoop) cleanup() {
|
||||
// TODO: also do this if we've written the headers but not
|
||||
// gotten a response yet.
|
||||
err := cc.readerErr
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
cc.mu.Lock()
|
||||
if err == io.EOF {
|
||||
if cc.goAway != nil {
|
||||
err = GoAwayError{
|
||||
LastStreamID: cc.goAway.LastStreamID,
|
||||
ErrCode: cc.goAway.ErrCode,
|
||||
DebugData: cc.goAwayDebug,
|
||||
}
|
||||
} else {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
for _, cs := range rl.activeRes {
|
||||
cs.bufPipe.CloseWithError(err)
|
||||
}
|
||||
@@ -1191,7 +1242,7 @@ func (rl *clientConnReadLoop) cleanup() {
|
||||
|
||||
func (rl *clientConnReadLoop) run() error {
|
||||
cc := rl.cc
|
||||
rl.closeWhenIdle = cc.t.disableKeepAlives()
|
||||
rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
|
||||
gotReply := false // ever saw a reply
|
||||
for {
|
||||
f, err := cc.fr.ReadFrame()
|
||||
@@ -1486,10 +1537,27 @@ var errClosedResponseBody = errors.New("http2: response body closed")
|
||||
|
||||
func (b transportResponseBody) Close() error {
|
||||
cs := b.cs
|
||||
if cs.bufPipe.Err() != io.EOF {
|
||||
// TODO: write test for this
|
||||
cs.cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
|
||||
cc := cs.cc
|
||||
|
||||
serverSentStreamEnd := cs.bufPipe.Err() == io.EOF
|
||||
unread := cs.bufPipe.Len()
|
||||
|
||||
if unread > 0 || !serverSentStreamEnd {
|
||||
cc.mu.Lock()
|
||||
cc.wmu.Lock()
|
||||
if !serverSentStreamEnd {
|
||||
cc.fr.WriteRSTStream(cs.ID, ErrCodeCancel)
|
||||
}
|
||||
// Return connection-level flow control.
|
||||
if unread > 0 {
|
||||
cc.inflow.add(int32(unread))
|
||||
cc.fr.WriteWindowUpdate(0, uint32(unread))
|
||||
}
|
||||
cc.bw.Flush()
|
||||
cc.wmu.Unlock()
|
||||
cc.mu.Unlock()
|
||||
}
|
||||
|
||||
cs.bufPipe.BreakWithError(errClosedResponseBody)
|
||||
return nil
|
||||
}
|
||||
@@ -1497,6 +1565,7 @@ func (b transportResponseBody) Close() error {
|
||||
func (rl *clientConnReadLoop) processData(f *DataFrame) error {
|
||||
cc := rl.cc
|
||||
cs := cc.streamByID(f.StreamID, f.StreamEnded())
|
||||
data := f.Data()
|
||||
if cs == nil {
|
||||
cc.mu.Lock()
|
||||
neverSent := cc.nextStreamID
|
||||
@@ -1510,9 +1579,17 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
|
||||
// TODO: be stricter here? only silently ignore things which
|
||||
// we canceled, but not things which were closed normally
|
||||
// by the peer? Tough without accumulating too much state.
|
||||
|
||||
// But at least return their flow control:
|
||||
if len(data) > 0 {
|
||||
cc.wmu.Lock()
|
||||
cc.fr.WriteWindowUpdate(0, uint32(len(data)))
|
||||
cc.bw.Flush()
|
||||
cc.wmu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if data := f.Data(); len(data) > 0 {
|
||||
if len(data) > 0 {
|
||||
if cs.bufPipe.b == nil {
|
||||
// Data frame after it's already closed?
|
||||
cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
|
||||
@@ -1557,7 +1634,7 @@ func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
|
||||
}
|
||||
cs.bufPipe.closeWithErrorAndCode(err, code)
|
||||
delete(rl.activeRes, cs.ID)
|
||||
if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
|
||||
if isConnectionCloseRequest(cs.req) {
|
||||
rl.closeWhenIdle = true
|
||||
}
|
||||
}
|
||||
@@ -1679,8 +1756,10 @@ func (rl *clientConnReadLoop) processPushPromise(f *PushPromiseFrame) error {
|
||||
}
|
||||
|
||||
func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, err error) {
|
||||
// TODO: do something with err? send it as a debug frame to the peer?
|
||||
// But that's only in GOAWAY. Invent a new frame type? Is there one already?
|
||||
// TODO: map err to more interesting error codes, once the
|
||||
// HTTP community comes up with some. But currently for
|
||||
// RST_STREAM there's no equivalent to GOAWAY frame's debug
|
||||
// data, and the error codes are all pretty vague ("cancel").
|
||||
cc.wmu.Lock()
|
||||
cc.fr.WriteRSTStream(streamID, code)
|
||||
cc.bw.Flush()
|
||||
@@ -1830,3 +1909,9 @@ func (s bodyWriterState) scheduleBodyWrite() {
|
||||
s.timer.Reset(s.delay)
|
||||
}
|
||||
}
|
||||
|
||||
// isConnectionCloseRequest reports whether req should use its own
|
||||
// connection for a single request and then close the connection.
|
||||
func isConnectionCloseRequest(req *http.Request) bool {
|
||||
return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
|
||||
}
|
||||
|
252
vendor/golang.org/x/net/http2/transport_test.go
generated
vendored
252
vendor/golang.org/x/net/http2/transport_test.go
generated
vendored
@@ -150,7 +150,9 @@ func TestTransport(t *testing.T) {
|
||||
func onSameConn(t *testing.T, modReq func(*http.Request)) bool {
|
||||
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
io.WriteString(w, r.RemoteAddr)
|
||||
}, optOnlyServer)
|
||||
}, optOnlyServer, func(c net.Conn, st http.ConnState) {
|
||||
t.Logf("conn %v is now state %v", c.RemoteAddr(), st)
|
||||
})
|
||||
defer st.Close()
|
||||
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
||||
defer tr.CloseIdleConnections()
|
||||
@@ -755,18 +757,18 @@ func testTransportReqBodyAfterResponse(t *testing.T, status int) {
|
||||
if f.StreamEnded() {
|
||||
return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f)
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond) // let client send body
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: false,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
case *DataFrame:
|
||||
dataLen := len(f.Data())
|
||||
dataRecv += int64(dataLen)
|
||||
if dataLen > 0 {
|
||||
if dataRecv == 0 {
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: false,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
}
|
||||
if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -774,6 +776,8 @@ func testTransportReqBodyAfterResponse(t *testing.T, status int) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dataRecv += int64(dataLen)
|
||||
|
||||
if !closed && ((status != 200 && dataRecv > 0) ||
|
||||
(status == 200 && dataRecv == bodySize)) {
|
||||
closed = true
|
||||
@@ -1013,41 +1017,38 @@ func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerTy
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
endStream := false
|
||||
send := func(mode headerType) {
|
||||
hbf := buf.Bytes()
|
||||
switch mode {
|
||||
case oneHeader:
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.Header().StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: endStream,
|
||||
BlockFragment: hbf,
|
||||
})
|
||||
case splitHeader:
|
||||
if len(hbf) < 2 {
|
||||
panic("too small")
|
||||
}
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.Header().StreamID,
|
||||
EndHeaders: false,
|
||||
EndStream: endStream,
|
||||
BlockFragment: hbf[:1],
|
||||
})
|
||||
ct.fr.WriteContinuation(f.Header().StreamID, true, hbf[1:])
|
||||
default:
|
||||
panic("bogus mode")
|
||||
}
|
||||
}
|
||||
switch f := f.(type) {
|
||||
case *WindowUpdateFrame, *SettingsFrame:
|
||||
case *DataFrame:
|
||||
// ignore for now.
|
||||
case *HeadersFrame:
|
||||
endStream := false
|
||||
send := func(mode headerType) {
|
||||
hbf := buf.Bytes()
|
||||
switch mode {
|
||||
case oneHeader:
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: endStream,
|
||||
BlockFragment: hbf,
|
||||
})
|
||||
case splitHeader:
|
||||
if len(hbf) < 2 {
|
||||
panic("too small")
|
||||
}
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.StreamID,
|
||||
EndHeaders: false,
|
||||
EndStream: endStream,
|
||||
BlockFragment: hbf[:1],
|
||||
})
|
||||
ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
|
||||
default:
|
||||
panic("bogus mode")
|
||||
}
|
||||
}
|
||||
if expect100Continue != noHeader {
|
||||
buf.Reset()
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
|
||||
send(expect100Continue)
|
||||
if !f.StreamEnded() {
|
||||
// No need to send flow control tokens. The test request body is tiny.
|
||||
continue
|
||||
}
|
||||
// Response headers (1+ frames; 1 or 2 in this test, but never 0)
|
||||
{
|
||||
@@ -1071,7 +1072,15 @@ func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerTy
|
||||
enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"})
|
||||
send(trailers)
|
||||
}
|
||||
return nil
|
||||
if endStream {
|
||||
return nil
|
||||
}
|
||||
case *HeadersFrame:
|
||||
if expect100Continue != noHeader {
|
||||
buf.Reset()
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
|
||||
send(expect100Continue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2011,3 +2020,160 @@ func TestTransportFlowControl(t *testing.T) {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// golang.org/issue/14627 -- if the server sends a GOAWAY frame, make
|
||||
// the Transport remember it and return it back to users (via
|
||||
// RoundTrip or request body reads) if needed (e.g. if the server
|
||||
// proceeds to close the TCP connection before the client gets its
|
||||
// response)
|
||||
func TestTransportUsesGoAwayDebugError_RoundTrip(t *testing.T) {
|
||||
testTransportUsesGoAwayDebugError(t, false)
|
||||
}
|
||||
|
||||
func TestTransportUsesGoAwayDebugError_Body(t *testing.T) {
|
||||
testTransportUsesGoAwayDebugError(t, true)
|
||||
}
|
||||
|
||||
func testTransportUsesGoAwayDebugError(t *testing.T, failMidBody bool) {
|
||||
ct := newClientTester(t)
|
||||
clientDone := make(chan struct{})
|
||||
|
||||
const goAwayErrCode = ErrCodeHTTP11Required // arbitrary
|
||||
const goAwayDebugData = "some debug data"
|
||||
|
||||
ct.client = func() error {
|
||||
defer close(clientDone)
|
||||
req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
|
||||
res, err := ct.tr.RoundTrip(req)
|
||||
if failMidBody {
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected client RoundTrip error: %v", err)
|
||||
}
|
||||
_, err = io.Copy(ioutil.Discard, res.Body)
|
||||
res.Body.Close()
|
||||
}
|
||||
want := GoAwayError{
|
||||
LastStreamID: 5,
|
||||
ErrCode: goAwayErrCode,
|
||||
DebugData: goAwayDebugData,
|
||||
}
|
||||
if !reflect.DeepEqual(err, want) {
|
||||
t.Errorf("RoundTrip error = %T: %#v, want %T (%#T)", err, err, want, want)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ct.server = func() error {
|
||||
ct.greet()
|
||||
for {
|
||||
f, err := ct.fr.ReadFrame()
|
||||
if err != nil {
|
||||
t.Logf("ReadFrame: %v", err)
|
||||
return nil
|
||||
}
|
||||
hf, ok := f.(*HeadersFrame)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if failMidBody {
|
||||
var buf bytes.Buffer
|
||||
enc := hpack.NewEncoder(&buf)
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
|
||||
enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: hf.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: false,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
}
|
||||
// Write two GOAWAY frames, to test that the Transport takes
|
||||
// the interesting parts of both.
|
||||
ct.fr.WriteGoAway(5, ErrCodeNo, []byte(goAwayDebugData))
|
||||
ct.fr.WriteGoAway(5, goAwayErrCode, nil)
|
||||
ct.sc.Close()
|
||||
<-clientDone
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ct.run()
|
||||
}
|
||||
|
||||
// See golang.org/issue/16481
|
||||
func TestTransportReturnsUnusedFlowControl(t *testing.T) {
|
||||
ct := newClientTester(t)
|
||||
|
||||
clientClosed := make(chan bool, 1)
|
||||
serverWroteBody := make(chan bool, 1)
|
||||
|
||||
ct.client = func() error {
|
||||
req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
|
||||
res, err := ct.tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
<-serverWroteBody
|
||||
|
||||
if n, err := res.Body.Read(make([]byte, 1)); err != nil || n != 1 {
|
||||
return fmt.Errorf("body read = %v, %v; want 1, nil", n, err)
|
||||
}
|
||||
res.Body.Close() // leaving 4999 bytes unread
|
||||
clientClosed <- true
|
||||
|
||||
return nil
|
||||
}
|
||||
ct.server = func() error {
|
||||
ct.greet()
|
||||
|
||||
var hf *HeadersFrame
|
||||
for {
|
||||
f, err := ct.fr.ReadFrame()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
|
||||
}
|
||||
switch f.(type) {
|
||||
case *WindowUpdateFrame, *SettingsFrame:
|
||||
continue
|
||||
}
|
||||
var ok bool
|
||||
hf, ok = f.(*HeadersFrame)
|
||||
if !ok {
|
||||
return fmt.Errorf("Got %T; want HeadersFrame", f)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := hpack.NewEncoder(&buf)
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
|
||||
enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"})
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: hf.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: false,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
ct.fr.WriteData(hf.StreamID, false, make([]byte, 5000)) // without ending stream
|
||||
serverWroteBody <- true
|
||||
|
||||
<-clientClosed
|
||||
|
||||
f, err := ct.fr.ReadFrame()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadFrame while waiting for RSTStreamFrame: %v", err)
|
||||
}
|
||||
if rf, ok := f.(*RSTStreamFrame); !ok || rf.ErrCode != ErrCodeCancel {
|
||||
return fmt.Errorf("Expected a WindowUpdateFrame with code cancel; got %v", summarizeFrame(f))
|
||||
}
|
||||
|
||||
// And wait for our flow control tokens back:
|
||||
f, err = ct.fr.ReadFrame()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadFrame while waiting for WindowUpdateFrame: %v", err)
|
||||
}
|
||||
if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != 4999 {
|
||||
return fmt.Errorf("Expected WindowUpdateFrame for 4999 bytes; got %v", summarizeFrame(f))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ct.run()
|
||||
}
|
||||
|
Reference in New Issue
Block a user