145
vendor/golang.org/x/net/http2/server.go
generated
vendored
145
vendor/golang.org/x/net/http2/server.go
generated
vendored
@@ -52,10 +52,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
prefaceTimeout = 10 * time.Second
|
||||
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
|
||||
handlerChunkWriteSize = 4 << 10
|
||||
defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
|
||||
prefaceTimeout = 10 * time.Second
|
||||
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
|
||||
handlerChunkWriteSize = 4 << 10
|
||||
defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
|
||||
maxQueuedControlFrames = 10000
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -163,6 +164,15 @@ func (s *Server) maxConcurrentStreams() uint32 {
|
||||
return defaultMaxStreams
|
||||
}
|
||||
|
||||
// maxQueuedControlFrames is the maximum number of control frames like
|
||||
// SETTINGS, PING and RST_STREAM that will be queued for writing before
|
||||
// the connection is closed to prevent memory exhaustion attacks.
|
||||
func (s *Server) maxQueuedControlFrames() int {
|
||||
// TODO: if anybody asks, add a Server field, and remember to define the
|
||||
// behavior of negative values.
|
||||
return maxQueuedControlFrames
|
||||
}
|
||||
|
||||
type serverInternalState struct {
|
||||
mu sync.Mutex
|
||||
activeConns map[*serverConn]struct{}
|
||||
@@ -221,13 +231,12 @@ func ConfigureServer(s *http.Server, conf *Server) error {
|
||||
|
||||
if s.TLSConfig == nil {
|
||||
s.TLSConfig = new(tls.Config)
|
||||
} else if s.TLSConfig.CipherSuites != nil {
|
||||
// If they already provided a CipherSuite list, return
|
||||
// an error if it has a bad order or is missing
|
||||
// ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
|
||||
} else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 {
|
||||
// If they already provided a TLS 1.0–1.2 CipherSuite list, return an
|
||||
// error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or
|
||||
// ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
|
||||
haveRequired := false
|
||||
sawBad := false
|
||||
for i, cs := range s.TLSConfig.CipherSuites {
|
||||
for _, cs := range s.TLSConfig.CipherSuites {
|
||||
switch cs {
|
||||
case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
// Alternative MTI cipher to not discourage ECDSA-only servers.
|
||||
@@ -235,14 +244,9 @@ func ConfigureServer(s *http.Server, conf *Server) error {
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||
haveRequired = true
|
||||
}
|
||||
if isBadCipher(cs) {
|
||||
sawBad = true
|
||||
} else if sawBad {
|
||||
return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs)
|
||||
}
|
||||
}
|
||||
if !haveRequired {
|
||||
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.")
|
||||
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +316,7 @@ type ServeConnOpts struct {
|
||||
}
|
||||
|
||||
func (o *ServeConnOpts) context() context.Context {
|
||||
if o.Context != nil {
|
||||
if o != nil && o.Context != nil {
|
||||
return o.Context
|
||||
}
|
||||
return context.Background()
|
||||
@@ -506,6 +510,7 @@ type serverConn struct {
|
||||
sawFirstSettings bool // got the initial SETTINGS frame after the preface
|
||||
needToSendSettingsAck bool
|
||||
unackedSettings int // how many SETTINGS have we sent without ACKs?
|
||||
queuedControlFrames int // control frames in the writeSched queue
|
||||
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
|
||||
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
|
||||
curClientStreams uint32 // number of open streams initiated by the client
|
||||
@@ -570,13 +575,10 @@ type stream struct {
|
||||
cancelCtx func()
|
||||
|
||||
// owned by serverConn's serve loop:
|
||||
bodyBytes int64 // body bytes seen so far
|
||||
declBodyBytes int64 // or -1 if undeclared
|
||||
flow flow // limits writing from Handler to client
|
||||
inflow flow // what the client is allowed to POST/etc to us
|
||||
parent *stream // or nil
|
||||
numTrailerValues int64
|
||||
weight uint8
|
||||
bodyBytes int64 // body bytes seen so far
|
||||
declBodyBytes int64 // or -1 if undeclared
|
||||
flow flow // limits writing from Handler to client
|
||||
inflow flow // what the client is allowed to POST/etc to us
|
||||
state streamState
|
||||
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
|
||||
gotTrailerHeader bool // HEADER frame for trailers was seen
|
||||
@@ -753,6 +755,7 @@ func (sc *serverConn) readFrames() {
|
||||
|
||||
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
|
||||
type frameWriteResult struct {
|
||||
_ incomparable
|
||||
wr FrameWriteRequest // what was written (or attempted)
|
||||
err error // result of the writeFrame call
|
||||
}
|
||||
@@ -763,7 +766,7 @@ type frameWriteResult struct {
|
||||
// serverConn.
|
||||
func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest) {
|
||||
err := wr.write.writeFrame(sc)
|
||||
sc.wroteFrameCh <- frameWriteResult{wr, err}
|
||||
sc.wroteFrameCh <- frameWriteResult{wr: wr, err: err}
|
||||
}
|
||||
|
||||
func (sc *serverConn) closeAllStreamsOnConnClose() {
|
||||
@@ -894,6 +897,14 @@ func (sc *serverConn) serve() {
|
||||
}
|
||||
}
|
||||
|
||||
// If the peer is causing us to generate a lot of control frames,
|
||||
// but not reading them from us, assume they are trying to make us
|
||||
// run out of memory.
|
||||
if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
|
||||
sc.vlogf("http2: too many control frames in send queue, closing connection")
|
||||
return
|
||||
}
|
||||
|
||||
// Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
|
||||
// with no error code (graceful shutdown), don't start the timer until
|
||||
// all open streams have been completed.
|
||||
@@ -1093,6 +1104,14 @@ func (sc *serverConn) writeFrame(wr FrameWriteRequest) {
|
||||
}
|
||||
|
||||
if !ignoreWrite {
|
||||
if wr.isControl() {
|
||||
sc.queuedControlFrames++
|
||||
// For extra safety, detect wraparounds, which should not happen,
|
||||
// and pull the plug.
|
||||
if sc.queuedControlFrames < 0 {
|
||||
sc.conn.Close()
|
||||
}
|
||||
}
|
||||
sc.writeSched.Push(wr)
|
||||
}
|
||||
sc.scheduleFrameWrite()
|
||||
@@ -1137,7 +1156,7 @@ func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
|
||||
if wr.write.staysWithinBuffer(sc.bw.Available()) {
|
||||
sc.writingFrameAsync = false
|
||||
err := wr.write.writeFrame(sc)
|
||||
sc.wroteFrame(frameWriteResult{wr, err})
|
||||
sc.wroteFrame(frameWriteResult{wr: wr, err: err})
|
||||
} else {
|
||||
sc.writingFrameAsync = true
|
||||
go sc.writeFrameAsync(wr)
|
||||
@@ -1210,10 +1229,8 @@ func (sc *serverConn) wroteFrame(res frameWriteResult) {
|
||||
// If a frame is already being written, nothing happens. This will be called again
|
||||
// when the frame is done being written.
|
||||
//
|
||||
// If a frame isn't being written we need to send one, the best frame
|
||||
// to send is selected, preferring first things that aren't
|
||||
// stream-specific (e.g. ACKing settings), and then finding the
|
||||
// highest priority stream.
|
||||
// If a frame isn't being written and we need to send one, the best frame
|
||||
// to send is selected by writeSched.
|
||||
//
|
||||
// If a frame isn't being written and there's nothing else to send, we
|
||||
// flush the write buffer.
|
||||
@@ -1241,6 +1258,9 @@ func (sc *serverConn) scheduleFrameWrite() {
|
||||
}
|
||||
if !sc.inGoAway || sc.goAwayCode == ErrCodeNo {
|
||||
if wr, ok := sc.writeSched.Pop(); ok {
|
||||
if wr.isControl() {
|
||||
sc.queuedControlFrames--
|
||||
}
|
||||
sc.startFrameWrite(wr)
|
||||
continue
|
||||
}
|
||||
@@ -1267,7 +1287,9 @@ func (sc *serverConn) startGracefulShutdown() {
|
||||
sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) })
|
||||
}
|
||||
|
||||
// After sending GOAWAY, the connection will close after goAwayTimeout.
|
||||
// After sending GOAWAY with an error code (non-graceful shutdown), the
|
||||
// connection will close after goAwayTimeout.
|
||||
//
|
||||
// If we close the connection immediately after sending GOAWAY, there may
|
||||
// be unsent data in our kernel receive buffer, which will cause the kernel
|
||||
// to send a TCP RST on close() instead of a FIN. This RST will abort the
|
||||
@@ -1533,6 +1555,8 @@ func (sc *serverConn) processSettings(f *SettingsFrame) error {
|
||||
if err := f.ForeachSetting(sc.processSetting); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
|
||||
// acknowledged individually, even if multiple are received before the ACK.
|
||||
sc.needToSendSettingsAck = true
|
||||
sc.scheduleFrameWrite()
|
||||
return nil
|
||||
@@ -1601,23 +1625,37 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
|
||||
|
||||
func (sc *serverConn) processData(f *DataFrame) error {
|
||||
sc.serveG.check()
|
||||
if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
|
||||
id := f.Header().StreamID
|
||||
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || id > sc.maxClientStreamID) {
|
||||
// Discard all DATA frames if the GOAWAY is due to an
|
||||
// error, or:
|
||||
//
|
||||
// Section 6.8: After sending a GOAWAY frame, the sender
|
||||
// can discard frames for streams initiated by the
|
||||
// receiver with identifiers higher than the identified
|
||||
// last stream.
|
||||
return nil
|
||||
}
|
||||
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."
|
||||
id := f.Header().StreamID
|
||||
data := f.Data()
|
||||
state, st := sc.state(id)
|
||||
if id == 0 || state == stateIdle {
|
||||
// Section 6.1: "DATA frames MUST be associated with a
|
||||
// stream. If a DATA frame is received whose stream
|
||||
// identifier field is 0x0, the recipient MUST respond
|
||||
// with a connection error (Section 5.4.1) of type
|
||||
// PROTOCOL_ERROR."
|
||||
//
|
||||
// Section 5.1: "Receiving any frame other than HEADERS
|
||||
// or PRIORITY on a stream in this state MUST be
|
||||
// treated as a connection error (Section 5.4.1) of
|
||||
// type PROTOCOL_ERROR."
|
||||
return ConnectionError(ErrCodeProtocol)
|
||||
}
|
||||
|
||||
// "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."
|
||||
if st == nil || state != stateOpen || st.gotTrailerHeader || st.resetQueued {
|
||||
// This includes sending a RST_STREAM if the stream is
|
||||
// in stateHalfClosedLocal (which currently means that
|
||||
@@ -1666,6 +1704,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
||||
if len(data) > 0 {
|
||||
wrote, err := st.body.Write(data)
|
||||
if err != nil {
|
||||
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
|
||||
return streamError(id, ErrCodeStreamClosed)
|
||||
}
|
||||
if wrote != len(data) {
|
||||
@@ -1992,7 +2031,11 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
|
||||
}
|
||||
if bodyOpen {
|
||||
if vv, ok := rp.header["Content-Length"]; ok {
|
||||
req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
|
||||
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
|
||||
req.ContentLength = int64(cl)
|
||||
} else {
|
||||
req.ContentLength = 0
|
||||
}
|
||||
} else {
|
||||
req.ContentLength = -1
|
||||
}
|
||||
@@ -2030,7 +2073,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
|
||||
var trailer http.Header
|
||||
for _, v := range rp.header["Trailer"] {
|
||||
for _, key := range strings.Split(v, ",") {
|
||||
key = http.CanonicalHeaderKey(strings.TrimSpace(key))
|
||||
key = http.CanonicalHeaderKey(textproto.TrimString(key))
|
||||
switch key {
|
||||
case "Transfer-Encoding", "Trailer", "Content-Length":
|
||||
// Bogus. (copy of http1 rules)
|
||||
@@ -2248,6 +2291,7 @@ func (sc *serverConn) sendWindowUpdate32(st *stream, n int32) {
|
||||
// requestBody is the Handler's Request.Body type.
|
||||
// Read and Close may be called concurrently.
|
||||
type requestBody struct {
|
||||
_ incomparable
|
||||
stream *stream
|
||||
conn *serverConn
|
||||
closed bool // for use by Close only
|
||||
@@ -2374,9 +2418,8 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||
var ctype, clen string
|
||||
if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
|
||||
rws.snapHeader.Del("Content-Length")
|
||||
clen64, err := strconv.ParseInt(clen, 10, 64)
|
||||
if err == nil && clen64 >= 0 {
|
||||
rws.sentContentLen = clen64
|
||||
if cl, err := strconv.ParseUint(clen, 10, 63); err == nil {
|
||||
rws.sentContentLen = int64(cl)
|
||||
} else {
|
||||
clen = ""
|
||||
}
|
||||
@@ -2385,7 +2428,11 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||
clen = strconv.Itoa(len(p))
|
||||
}
|
||||
_, hasContentType := rws.snapHeader["Content-Type"]
|
||||
if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
|
||||
// If the Content-Encoding is non-blank, we shouldn't
|
||||
// sniff the body. See Issue golang.org/issue/31753.
|
||||
ce := rws.snapHeader.Get("Content-Encoding")
|
||||
hasCE := len(ce) > 0
|
||||
if !hasCE && !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
|
||||
ctype = http.DetectContentType(p)
|
||||
}
|
||||
var date string
|
||||
@@ -2494,7 +2541,7 @@ const TrailerPrefix = "Trailer:"
|
||||
// trailers. That worked for a while, until we found the first major
|
||||
// user of Trailers in the wild: gRPC (using them only over http2),
|
||||
// and gRPC libraries permit setting trailers mid-stream without
|
||||
// predeclarnig them. So: change of plans. We still permit the old
|
||||
// predeclaring them. So: change of plans. We still permit the old
|
||||
// way, but we also permit this hack: if a Header() key begins with
|
||||
// "Trailer:", the suffix of that key is a Trailer. Because ':' is an
|
||||
// invalid token byte anyway, there is no ambiguity. (And it's already
|
||||
@@ -2736,8 +2783,12 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
|
||||
// but PUSH_PROMISE requests cannot have a body.
|
||||
// http://tools.ietf.org/html/rfc7540#section-8.2
|
||||
// Also disallow Host, since the promised URL must be absolute.
|
||||
switch strings.ToLower(k) {
|
||||
case "content-length", "content-encoding", "trailer", "te", "expect", "host":
|
||||
if asciiEqualFold(k, "content-length") ||
|
||||
asciiEqualFold(k, "content-encoding") ||
|
||||
asciiEqualFold(k, "trailer") ||
|
||||
asciiEqualFold(k, "te") ||
|
||||
asciiEqualFold(k, "expect") ||
|
||||
asciiEqualFold(k, "host") {
|
||||
return fmt.Errorf("promised request headers cannot include %q", k)
|
||||
}
|
||||
}
|
||||
@@ -2794,7 +2845,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
|
||||
// PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that
|
||||
// is in either the "open" or "half-closed (remote)" state.
|
||||
if msg.parent.state != stateOpen && msg.parent.state != stateHalfClosedRemote {
|
||||
// responseWriter.Push checks that the stream is peer-initiaed.
|
||||
// responseWriter.Push checks that the stream is peer-initiated.
|
||||
msg.done <- errStreamClosed
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user