|
|
@@ -46,6 +46,7 @@ import (
|
|
|
"sync"
|
|
|
"time"
|
|
|
|
|
|
+ "golang.org/x/net/http/httpguts"
|
|
|
"golang.org/x/net/http2/hpack"
|
|
|
)
|
|
|
|
|
|
@@ -220,12 +221,15 @@ func ConfigureServer(s *http.Server, conf *Server) error {
|
|
|
} 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 +239,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 +407,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.
|
|
|
@@ -649,7 +653,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 +663,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 +858,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 +899,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 +921,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 {
|
|
|
@@ -1218,30 +1231,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 +1488,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
|
|
|
}
|
|
|
@@ -1562,6 +1582,12 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
|
|
// type PROTOCOL_ERROR."
|
|
|
return ConnectionError(ErrCodeProtocol)
|
|
|
}
|
|
|
+ // RFC 7540, sec 6.1: 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 state == stateClosed {
|
|
|
+ return streamError(id, ErrCodeStreamClosed)
|
|
|
+ }
|
|
|
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
|
|
|
@@ -1595,7 +1621,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 +1734,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 +1841,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.
|
|
|
@@ -2272,8 +2308,8 @@ func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) !=
|
|
|
// 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 +2346,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 +2359,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,
|
|
|
@@ -2394,7 +2443,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 +2527,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 +2555,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 {
|
|
|
@@ -2759,7 +2827,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 +2875,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.
|