mirror of
https://github.com/golang/net.git
synced 2026-04-01 02:47:08 +09:00
If the Transport got a stream error on the response headers, it was never unblocking the client. Previously, Response.Body reads would be aborted with the stream error, but RoundTrip itself would never unblock. The Transport now also sends a RST_STREAM to the server when we encounter a stream error. Also, add a "Cause" field to StreamError with additional detail. The old code was just returning the detail, without the stream error header. Fixes golang/go#16572 Change-Id: Ibecedb5779f17bf98c32787b68eb8a9b850833b3 Reviewed-on: https://go-review.googlesource.com/25402 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Andrew Gerrand <adg@golang.org>
131 lines
4.0 KiB
Go
131 lines
4.0 KiB
Go
// Copyright 2014 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 http2
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
|
|
type ErrCode uint32
|
|
|
|
const (
|
|
ErrCodeNo ErrCode = 0x0
|
|
ErrCodeProtocol ErrCode = 0x1
|
|
ErrCodeInternal ErrCode = 0x2
|
|
ErrCodeFlowControl ErrCode = 0x3
|
|
ErrCodeSettingsTimeout ErrCode = 0x4
|
|
ErrCodeStreamClosed ErrCode = 0x5
|
|
ErrCodeFrameSize ErrCode = 0x6
|
|
ErrCodeRefusedStream ErrCode = 0x7
|
|
ErrCodeCancel ErrCode = 0x8
|
|
ErrCodeCompression ErrCode = 0x9
|
|
ErrCodeConnect ErrCode = 0xa
|
|
ErrCodeEnhanceYourCalm ErrCode = 0xb
|
|
ErrCodeInadequateSecurity ErrCode = 0xc
|
|
ErrCodeHTTP11Required ErrCode = 0xd
|
|
)
|
|
|
|
var errCodeName = map[ErrCode]string{
|
|
ErrCodeNo: "NO_ERROR",
|
|
ErrCodeProtocol: "PROTOCOL_ERROR",
|
|
ErrCodeInternal: "INTERNAL_ERROR",
|
|
ErrCodeFlowControl: "FLOW_CONTROL_ERROR",
|
|
ErrCodeSettingsTimeout: "SETTINGS_TIMEOUT",
|
|
ErrCodeStreamClosed: "STREAM_CLOSED",
|
|
ErrCodeFrameSize: "FRAME_SIZE_ERROR",
|
|
ErrCodeRefusedStream: "REFUSED_STREAM",
|
|
ErrCodeCancel: "CANCEL",
|
|
ErrCodeCompression: "COMPRESSION_ERROR",
|
|
ErrCodeConnect: "CONNECT_ERROR",
|
|
ErrCodeEnhanceYourCalm: "ENHANCE_YOUR_CALM",
|
|
ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
|
|
ErrCodeHTTP11Required: "HTTP_1_1_REQUIRED",
|
|
}
|
|
|
|
func (e ErrCode) String() string {
|
|
if s, ok := errCodeName[e]; ok {
|
|
return s
|
|
}
|
|
return fmt.Sprintf("unknown error code 0x%x", uint32(e))
|
|
}
|
|
|
|
// ConnectionError is an error that results in the termination of the
|
|
// entire connection.
|
|
type ConnectionError ErrCode
|
|
|
|
func (e ConnectionError) Error() string { return fmt.Sprintf("connection error: %s", ErrCode(e)) }
|
|
|
|
// StreamError is an error that only affects one stream within an
|
|
// HTTP/2 connection.
|
|
type StreamError struct {
|
|
StreamID uint32
|
|
Code ErrCode
|
|
Cause error // optional additional detail
|
|
}
|
|
|
|
func streamError(id uint32, code ErrCode) StreamError {
|
|
return StreamError{StreamID: id, Code: code}
|
|
}
|
|
|
|
func (e StreamError) Error() string {
|
|
if e.Cause != nil {
|
|
return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
|
|
}
|
|
return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
|
|
}
|
|
|
|
// 6.9.1 The Flow Control Window
|
|
// "If a sender receives a WINDOW_UPDATE that causes a flow control
|
|
// window to exceed this maximum it MUST terminate either the stream
|
|
// or the connection, as appropriate. For streams, [...]; for the
|
|
// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
|
|
type goAwayFlowError struct{}
|
|
|
|
func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
|
|
|
|
// connErrorReason wraps a ConnectionError with an informative error about why it occurs.
|
|
|
|
// Errors of this type are only returned by the frame parser functions
|
|
// and converted into ConnectionError(ErrCodeProtocol).
|
|
type connError struct {
|
|
Code ErrCode
|
|
Reason string
|
|
}
|
|
|
|
func (e connError) Error() string {
|
|
return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
|
|
}
|
|
|
|
type pseudoHeaderError string
|
|
|
|
func (e pseudoHeaderError) Error() string {
|
|
return fmt.Sprintf("invalid pseudo-header %q", string(e))
|
|
}
|
|
|
|
type duplicatePseudoHeaderError string
|
|
|
|
func (e duplicatePseudoHeaderError) Error() string {
|
|
return fmt.Sprintf("duplicate pseudo-header %q", string(e))
|
|
}
|
|
|
|
type headerFieldNameError string
|
|
|
|
func (e headerFieldNameError) Error() string {
|
|
return fmt.Sprintf("invalid header field name %q", string(e))
|
|
}
|
|
|
|
type headerFieldValueError string
|
|
|
|
func (e headerFieldValueError) Error() string {
|
|
return fmt.Sprintf("invalid header field value %q", string(e))
|
|
}
|
|
|
|
var (
|
|
errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
|
|
errPseudoAfterRegular = errors.New("pseudo header field after regular")
|
|
)
|