]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blobdiff - vendor/golang.org/x/net/http2/server.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / golang.org / x / net / http2 / server.go
index eae143ddff1084c3932dbe18a64bc1edb271ad60..d4abeb2b998c79b23c5fd31d4a283d8cdfd251e7 100644 (file)
@@ -28,6 +28,7 @@ package http2
 import (
        "bufio"
        "bytes"
+       "context"
        "crypto/tls"
        "errors"
        "fmt"
@@ -46,6 +47,7 @@ import (
        "sync"
        "time"
 
+       "golang.org/x/net/http/httpguts"
        "golang.org/x/net/http2/hpack"
 )
 
@@ -208,24 +210,29 @@ func ConfigureServer(s *http.Server, conf *Server) error {
                conf = new(Server)
        }
        conf.state = &serverInternalState{activeConns: make(map[*serverConn]struct{})}
-       if err := configureServer18(s, conf); err != nil {
-               return err
-       }
-       if err := configureServer19(s, conf); err != nil {
-               return err
+       if h1, h2 := s, conf; h2.IdleTimeout == 0 {
+               if h1.IdleTimeout != 0 {
+                       h2.IdleTimeout = h1.IdleTimeout
+               } else {
+                       h2.IdleTimeout = h1.ReadTimeout
+               }
        }
+       s.RegisterOnShutdown(conf.state.startGracefulShutdown)
 
        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.
-               const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+               // 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 {
-                       if cs == requiredCipher {
+                       switch cs {
+                       case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                               // Alternative MTI cipher to not discourage ECDSA-only servers.
+                               // See http://golang.org/cl/30721 for further information.
+                               tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
                                haveRequired = true
                        }
                        if isBadCipher(cs) {
@@ -235,7 +242,7 @@ func ConfigureServer(s *http.Server, conf *Server) error {
                        }
                }
                if !haveRequired {
-                       return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
+                       return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.")
                }
        }
 
@@ -403,7 +410,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
                        // addresses during development.
                        //
                        // TODO: optionally enforce? Or enforce at the time we receive
-                       // a new request, and verify the the ServerName matches the :authority?
+                       // a new request, and verify the ServerName matches the :authority?
                        // But that precludes proxy situations, perhaps.
                        //
                        // So for now, do nothing here again.
@@ -431,6 +438,15 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
        sc.serve()
 }
 
+func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
+       ctx, cancel = context.WithCancel(context.Background())
+       ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
+       if hs := opts.baseConfig(); hs != nil {
+               ctx = context.WithValue(ctx, http.ServerContextKey, hs)
+       }
+       return
+}
+
 func (sc *serverConn) rejectConn(err ErrCode, debug string) {
        sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
        // ignoring errors. hanging up anyway.
@@ -446,7 +462,7 @@ type serverConn struct {
        conn             net.Conn
        bw               *bufferedWriter // writing to conn
        handler          http.Handler
-       baseCtx          contextContext
+       baseCtx          context.Context
        framer           *Framer
        doneServing      chan struct{}          // closed when serverConn.serve ends
        readFrameCh      chan readFrameResult   // written by serverConn.readFrames
@@ -526,7 +542,7 @@ type stream struct {
        id        uint32
        body      *pipe       // non-nil if expecting DATA frames
        cw        closeWaiter // closed wait stream transitions to closed state
-       ctx       contextContext
+       ctx       context.Context
        cancelCtx func()
 
        // owned by serverConn's serve loop:
@@ -649,7 +665,7 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
        if err == nil {
                return
        }
-       if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) {
+       if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) || err == errPrefaceTimeout {
                // Boring, expected errors.
                sc.vlogf(format, args...)
        } else {
@@ -659,6 +675,7 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
 
 func (sc *serverConn) canonicalHeader(v string) string {
        sc.serveG.check()
+       buildCommonHeaderMapsOnce()
        cv, ok := commonCanonHeader[v]
        if ok {
                return cv
@@ -853,8 +870,13 @@ func (sc *serverConn) serve() {
                        }
                }
 
-               if sc.inGoAway && sc.curOpenStreams() == 0 && !sc.needToSendGoAway && !sc.writingFrame {
-                       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.
+               sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame
+               gracefulShutdownComplete := sc.goAwayCode == ErrCodeNo && sc.curOpenStreams() == 0
+               if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != ErrCodeNo || gracefulShutdownComplete) {
+                       sc.shutDownIn(goAwayTimeout)
                }
        }
 }
@@ -889,8 +911,11 @@ func (sc *serverConn) sendServeMsg(msg interface{}) {
        }
 }
 
-// readPreface reads the ClientPreface greeting from the peer
-// or returns an error on timeout or an invalid greeting.
+var errPrefaceTimeout = errors.New("timeout waiting for client preface")
+
+// readPreface reads the ClientPreface greeting from the peer or
+// returns errPrefaceTimeout on timeout, or an error if the greeting
+// is invalid.
 func (sc *serverConn) readPreface() error {
        errc := make(chan error, 1)
        go func() {
@@ -908,7 +933,7 @@ func (sc *serverConn) readPreface() error {
        defer timer.Stop()
        select {
        case <-timer.C:
-               return errors.New("timeout waiting for client preface")
+               return errPrefaceTimeout
        case err := <-errc:
                if err == nil {
                        if VerboseLogs {
@@ -1097,7 +1122,7 @@ func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
 
 // errHandlerPanicked is the error given to any callers blocked in a read from
 // Request.Body when the main goroutine panics. Since most handlers read in the
-// the main ServeHTTP goroutine, this will show up rarely.
+// main ServeHTTP goroutine, this will show up rarely.
 var errHandlerPanicked = errors.New("http2: handler panicked")
 
 // wroteFrame is called on the serve goroutine with the result of
@@ -1218,30 +1243,31 @@ func (sc *serverConn) startGracefulShutdown() {
        sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) })
 }
 
+// After sending GOAWAY, 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
+// connection immediately, whether or not the client had received the GOAWAY.
+//
+// Ideally we should delay for at least 1 RTT + epsilon so the client has
+// a chance to read the GOAWAY and stop sending messages. Measuring RTT
+// is hard, so we approximate with 1 second. See golang.org/issue/18701.
+//
+// This is a var so it can be shorter in tests, where all requests uses the
+// loopback interface making the expected RTT very small.
+//
+// TODO: configurable?
+var goAwayTimeout = 1 * time.Second
+
 func (sc *serverConn) startGracefulShutdownInternal() {
-       sc.goAwayIn(ErrCodeNo, 0)
+       sc.goAway(ErrCodeNo)
 }
 
 func (sc *serverConn) goAway(code ErrCode) {
-       sc.serveG.check()
-       var forceCloseIn time.Duration
-       if code != ErrCodeNo {
-               forceCloseIn = 250 * time.Millisecond
-       } else {
-               // TODO: configurable
-               forceCloseIn = 1 * time.Second
-       }
-       sc.goAwayIn(code, forceCloseIn)
-}
-
-func (sc *serverConn) goAwayIn(code ErrCode, forceCloseIn time.Duration) {
        sc.serveG.check()
        if sc.inGoAway {
                return
        }
-       if forceCloseIn != 0 {
-               sc.shutDownIn(forceCloseIn)
-       }
        sc.inGoAway = true
        sc.needToSendGoAway = true
        sc.goAwayCode = code
@@ -1474,6 +1500,12 @@ func (sc *serverConn) processSettings(f *SettingsFrame) error {
                }
                return nil
        }
+       if f.NumSettings() > 100 || f.HasDuplicates() {
+               // This isn't actually in the spec, but hang up on
+               // suspiciously large settings frames or those with
+               // duplicate entries.
+               return ConnectionError(ErrCodeProtocol)
+       }
        if err := f.ForeachSetting(sc.processSetting); err != nil {
                return err
        }
@@ -1595,7 +1627,10 @@ func (sc *serverConn) processData(f *DataFrame) error {
        // Sender sending more than they'd declared?
        if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
                st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
-               return streamError(id, ErrCodeStreamClosed)
+               // RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
+               // value of a content-length header field does not equal the sum of the
+               // DATA frame payload lengths that form the body.
+               return streamError(id, ErrCodeProtocol)
        }
        if f.Length > 0 {
                // Check whether the client has flow control quota.
@@ -1705,6 +1740,13 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
                        // processing this frame.
                        return nil
                }
+               // RFC 7540, sec 5.1: If an endpoint receives additional frames, other than
+               // WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream that is in
+               // this state, it MUST respond with a stream error (Section 5.4.2) of
+               // type STREAM_CLOSED.
+               if st.state == stateHalfClosedRemote {
+                       return streamError(id, ErrCodeStreamClosed)
+               }
                return st.processTrailerHeaders(f)
        }
 
@@ -1805,7 +1847,7 @@ func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
        if st.trailer != nil {
                for _, hf := range f.RegularFields() {
                        key := sc.canonicalHeader(hf.Name)
-                       if !ValidTrailerHeader(key) {
+                       if !httpguts.ValidTrailerHeader(key) {
                                // TODO: send more details to the peer somehow. But http2 has
                                // no way to send debug data at a stream level. Discuss with
                                // HTTP folk.
@@ -1846,7 +1888,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
                panic("internal error: cannot create stream with id 0")
        }
 
-       ctx, cancelCtx := contextWithCancel(sc.baseCtx)
+       ctx, cancelCtx := context.WithCancel(sc.baseCtx)
        st := &stream{
                sc:        sc,
                id:        id,
@@ -2012,7 +2054,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
                Body:       body,
                Trailer:    trailer,
        }
-       req = requestWithContext(req, st.ctx)
+       req = req.WithContext(st.ctx)
 
        rws := responseWriterStatePool.Get().(*responseWriterState)
        bwSave := rws.bw
@@ -2040,7 +2082,7 @@ func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler
                                stream: rw.rws.stream,
                        })
                        // Same as net/http:
-                       if shouldLogPanic(e) {
+                       if e != nil && e != http.ErrAbortHandler {
                                const size = 64 << 10
                                buf := make([]byte, size)
                                buf = buf[:runtime.Stack(buf, false)]
@@ -2265,15 +2307,24 @@ type chunkWriter struct{ rws *responseWriterState }
 
 func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
 
-func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) != 0 }
+func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
+
+func (rws *responseWriterState) hasNonemptyTrailers() bool {
+       for _, trailer := range rws.trailers {
+               if _, ok := rws.handlerHeader[trailer]; ok {
+                       return true
+               }
+       }
+       return false
+}
 
 // declareTrailer is called for each Trailer header when the
 // response header is written. It notes that a header will need to be
 // written in the trailers at the end of the response.
 func (rws *responseWriterState) declareTrailer(k string) {
        k = http.CanonicalHeaderKey(k)
-       if !ValidTrailerHeader(k) {
-               // Forbidden by RFC 2616 14.40.
+       if !httpguts.ValidTrailerHeader(k) {
+               // Forbidden by RFC 7230, section 4.1.2.
                rws.conn.logf("ignoring invalid trailer %q", k)
                return
        }
@@ -2310,7 +2361,7 @@ 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) {
+               if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
                        ctype = http.DetectContentType(p)
                }
                var date string
@@ -2323,6 +2374,19 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
                        foreachHeaderElement(v, rws.declareTrailer)
                }
 
+               // "Connection" headers aren't allowed in HTTP/2 (RFC 7540, 8.1.2.2),
+               // but respect "Connection" == "close" to mean sending a GOAWAY and tearing
+               // down the TCP connection when idle, like we do for HTTP/1.
+               // TODO: remove more Connection-specific header fields here, in addition
+               // to "Connection".
+               if _, ok := rws.snapHeader["Connection"]; ok {
+                       v := rws.snapHeader.Get("Connection")
+                       delete(rws.snapHeader, "Connection")
+                       if v == "close" {
+                               rws.conn.startGracefulShutdown()
+                       }
+               }
+
                endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp
                err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
                        streamID:      rws.stream.id,
@@ -2352,7 +2416,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
                rws.promoteUndeclaredTrailers()
        }
 
-       endStream := rws.handlerDone && !rws.hasTrailers()
+       // only send trailers if they have actually been defined by the
+       // server handler.
+       hasNonemptyTrailers := rws.hasNonemptyTrailers()
+       endStream := rws.handlerDone && !hasNonemptyTrailers
        if len(p) > 0 || endStream {
                // only send a 0 byte DATA frame if we're ending the stream.
                if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
@@ -2361,7 +2428,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
                }
        }
 
-       if rws.handlerDone && rws.hasTrailers() {
+       if rws.handlerDone && hasNonemptyTrailers {
                err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
                        streamID:  rws.stream.id,
                        h:         rws.handlerHeader,
@@ -2394,7 +2461,7 @@ const TrailerPrefix = "Trailer:"
 // after the header has already been flushed. Because the Go
 // ResponseWriter interface has no way to set Trailers (only the
 // Header), and because we didn't want to expand the ResponseWriter
-// interface, and because nobody used trailers, and because RFC 2616
+// interface, and because nobody used trailers, and because RFC 7230
 // says you SHOULD (but not must) predeclare any trailers in the
 // header, the official ResponseWriter rules said trailers in Go must
 // be predeclared, and then we reuse the same ResponseWriter.Header()
@@ -2478,6 +2545,24 @@ func (w *responseWriter) Header() http.Header {
        return rws.handlerHeader
 }
 
+// checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode.
+func checkWriteHeaderCode(code int) {
+       // Issue 22880: require valid WriteHeader status codes.
+       // For now we only enforce that it's three digits.
+       // In the future we might block things over 599 (600 and above aren't defined
+       // at http://httpwg.org/specs/rfc7231.html#status.codes)
+       // and we might block under 200 (once we have more mature 1xx support).
+       // But for now any three digits.
+       //
+       // We used to send "HTTP/1.1 000 0" on the wire in responses but there's
+       // no equivalent bogus thing we can realistically send in HTTP/2,
+       // so we'll consistently panic instead and help people find their bugs
+       // early. (We can't return an error from WriteHeader even if we wanted to.)
+       if code < 100 || code > 999 {
+               panic(fmt.Sprintf("invalid WriteHeader code %v", code))
+       }
+}
+
 func (w *responseWriter) WriteHeader(code int) {
        rws := w.rws
        if rws == nil {
@@ -2488,6 +2573,7 @@ func (w *responseWriter) WriteHeader(code int) {
 
 func (rws *responseWriterState) writeHeader(code int) {
        if !rws.wroteHeader {
+               checkWriteHeaderCode(code)
                rws.wroteHeader = true
                rws.status = code
                if len(rws.handlerHeader) > 0 {
@@ -2570,14 +2656,9 @@ var (
        ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
 )
 
-// pushOptions is the internal version of http.PushOptions, which we
-// cannot include here because it's only defined in Go 1.8 and later.
-type pushOptions struct {
-       Method string
-       Header http.Header
-}
+var _ http.Pusher = (*responseWriter)(nil)
 
-func (w *responseWriter) push(target string, opts pushOptions) error {
+func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
        st := w.rws.stream
        sc := st.sc
        sc.serveG.checkNotOn()
@@ -2588,6 +2669,10 @@ func (w *responseWriter) push(target string, opts pushOptions) error {
                return ErrRecursivePush
        }
 
+       if opts == nil {
+               opts = new(http.PushOptions)
+       }
+
        // Default options.
        if opts.Method == "" {
                opts.Method = "GET"
@@ -2759,7 +2844,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
 }
 
 // foreachHeaderElement splits v according to the "#rule" construction
-// in RFC 2616 section 2.1 and calls fn for each non-empty element.
+// in RFC 7230 section 7 and calls fn for each non-empty element.
 func foreachHeaderElement(v string, fn func(string)) {
        v = textproto.TrimString(v)
        if v == "" {
@@ -2807,41 +2892,6 @@ func new400Handler(err error) http.HandlerFunc {
        }
 }
 
-// ValidTrailerHeader reports whether name is a valid header field name to appear
-// in trailers.
-// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
-func ValidTrailerHeader(name string) bool {
-       name = http.CanonicalHeaderKey(name)
-       if strings.HasPrefix(name, "If-") || badTrailer[name] {
-               return false
-       }
-       return true
-}
-
-var badTrailer = map[string]bool{
-       "Authorization":       true,
-       "Cache-Control":       true,
-       "Connection":          true,
-       "Content-Encoding":    true,
-       "Content-Length":      true,
-       "Content-Range":       true,
-       "Content-Type":        true,
-       "Expect":              true,
-       "Host":                true,
-       "Keep-Alive":          true,
-       "Max-Forwards":        true,
-       "Pragma":              true,
-       "Proxy-Authenticate":  true,
-       "Proxy-Authorization": true,
-       "Proxy-Connection":    true,
-       "Range":               true,
-       "Realm":               true,
-       "Te":                  true,
-       "Trailer":             true,
-       "Transfer-Encoding":   true,
-       "Www-Authenticate":    true,
-}
-
 // h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
 // disabled. See comments on h1ServerShutdownChan above for why
 // the code is written this way.