|
|
|
@ -143,7 +143,7 @@ type Server struct {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) initialConnRecvWindowSize() int32 {
|
|
|
|
|
if s.MaxUploadBufferPerConnection > initialWindowSize {
|
|
|
|
|
if s.MaxUploadBufferPerConnection >= initialWindowSize {
|
|
|
|
|
return s.MaxUploadBufferPerConnection
|
|
|
|
|
}
|
|
|
|
|
return 1 << 20
|
|
|
|
@ -315,6 +315,20 @@ type ServeConnOpts struct {
|
|
|
|
|
// requests. If nil, BaseConfig.Handler is used. If BaseConfig
|
|
|
|
|
// or BaseConfig.Handler is nil, http.DefaultServeMux is used.
|
|
|
|
|
Handler http.Handler
|
|
|
|
|
|
|
|
|
|
// UpgradeRequest is an initial request received on a connection
|
|
|
|
|
// undergoing an h2c upgrade. The request body must have been
|
|
|
|
|
// completely read from the connection before calling ServeConn,
|
|
|
|
|
// and the 101 Switching Protocols response written.
|
|
|
|
|
UpgradeRequest *http.Request
|
|
|
|
|
|
|
|
|
|
// Settings is the decoded contents of the HTTP2-Settings header
|
|
|
|
|
// in an h2c upgrade request.
|
|
|
|
|
Settings []byte
|
|
|
|
|
|
|
|
|
|
// SawClientPreface is set if the HTTP/2 connection preface
|
|
|
|
|
// has already been read from the connection.
|
|
|
|
|
SawClientPreface bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (o *ServeConnOpts) context() context.Context {
|
|
|
|
@ -383,6 +397,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
|
|
|
|
headerTableSize: initialHeaderTableSize,
|
|
|
|
|
serveG: newGoroutineLock(),
|
|
|
|
|
pushEnabled: true,
|
|
|
|
|
sawClientPreface: opts.SawClientPreface,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.state.registerConn(sc)
|
|
|
|
@ -400,7 +415,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
|
|
|
|
if s.NewWriteScheduler != nil {
|
|
|
|
|
sc.writeSched = s.NewWriteScheduler()
|
|
|
|
|
} else {
|
|
|
|
|
sc.writeSched = NewRandomWriteScheduler()
|
|
|
|
|
sc.writeSched = NewPriorityWriteScheduler(nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// These start at the RFC-specified defaults. If there is a higher
|
|
|
|
@ -465,9 +480,27 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if opts.Settings != nil {
|
|
|
|
|
fr := &SettingsFrame{
|
|
|
|
|
FrameHeader: FrameHeader{valid: true},
|
|
|
|
|
p: opts.Settings,
|
|
|
|
|
}
|
|
|
|
|
if err := fr.ForeachSetting(sc.processSetting); err != nil {
|
|
|
|
|
sc.rejectConn(ErrCodeProtocol, "invalid settings")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
opts.Settings = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hook := testHookGetServerConn; hook != nil {
|
|
|
|
|
hook(sc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if opts.UpgradeRequest != nil {
|
|
|
|
|
sc.upgradeRequest(opts.UpgradeRequest)
|
|
|
|
|
opts.UpgradeRequest = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sc.serve()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -512,6 +545,7 @@ type serverConn struct {
|
|
|
|
|
// Everything following is owned by the serve loop; use serveG.check():
|
|
|
|
|
serveG goroutineLock // used to verify funcs are on serve()
|
|
|
|
|
pushEnabled bool
|
|
|
|
|
sawClientPreface bool // preface has already been read, used in h2c upgrade
|
|
|
|
|
sawFirstSettings bool // got the initial SETTINGS frame after the preface
|
|
|
|
|
needToSendSettingsAck bool
|
|
|
|
|
unackedSettings int // how many SETTINGS have we sent without ACKs?
|
|
|
|
@ -835,9 +869,7 @@ func (sc *serverConn) serve() {
|
|
|
|
|
|
|
|
|
|
// Each connection starts with initialWindowSize inflow tokens.
|
|
|
|
|
// If a higher value is configured, we add more tokens.
|
|
|
|
|
if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 {
|
|
|
|
|
sc.sendWindowUpdate(nil, int(diff))
|
|
|
|
|
}
|
|
|
|
|
sc.sendWindowUpdate(nil)
|
|
|
|
|
|
|
|
|
|
if err := sc.readPreface(); err != nil {
|
|
|
|
|
sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
|
|
|
|
@ -974,6 +1006,9 @@ var errPrefaceTimeout = errors.New("timeout waiting for client preface")
|
|
|
|
|
// returns errPrefaceTimeout on timeout, or an error if the greeting
|
|
|
|
|
// is invalid.
|
|
|
|
|
func (sc *serverConn) readPreface() error {
|
|
|
|
|
if sc.sawClientPreface {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
errc := make(chan error, 1)
|
|
|
|
|
go func() {
|
|
|
|
|
// Read the client preface
|
|
|
|
@ -1334,6 +1369,9 @@ func (sc *serverConn) startGracefulShutdownInternal() {
|
|
|
|
|
func (sc *serverConn) goAway(code ErrCode) {
|
|
|
|
|
sc.serveG.check()
|
|
|
|
|
if sc.inGoAway {
|
|
|
|
|
if sc.goAwayCode == ErrCodeNo {
|
|
|
|
|
sc.goAwayCode = code
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
sc.inGoAway = true
|
|
|
|
@ -1548,7 +1586,7 @@ func (sc *serverConn) closeStream(st *stream, err error) {
|
|
|
|
|
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())
|
|
|
|
|
sc.sendWindowUpdate(nil)
|
|
|
|
|
|
|
|
|
|
p.CloseWithError(err)
|
|
|
|
|
}
|
|
|
|
@ -1696,7 +1734,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
|
|
|
|
// sendWindowUpdate, which also schedules sending the
|
|
|
|
|
// frames.
|
|
|
|
|
sc.inflow.take(int32(f.Length))
|
|
|
|
|
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
|
|
|
|
|
sc.sendWindowUpdate(nil) // conn-level
|
|
|
|
|
|
|
|
|
|
if st != nil && st.resetQueued {
|
|
|
|
|
// Already have a stream error in flight. Don't send another.
|
|
|
|
@ -1710,6 +1748,12 @@ 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 {
|
|
|
|
|
if sc.inflow.available() < int32(f.Length) {
|
|
|
|
|
return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
|
|
|
|
|
}
|
|
|
|
|
sc.inflow.take(int32(f.Length))
|
|
|
|
|
sc.sendWindowUpdate(nil) // conn-level
|
|
|
|
|
|
|
|
|
|
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
|
|
|
|
|
// 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
|
|
|
|
@ -1726,7 +1770,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)
|
|
|
|
|
sc.sendWindowUpdate32(nil, int32(f.Length)-int32(wrote))
|
|
|
|
|
return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
|
|
|
|
|
}
|
|
|
|
|
if wrote != len(data) {
|
|
|
|
@ -1915,6 +1959,26 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (sc *serverConn) upgradeRequest(req *http.Request) {
|
|
|
|
|
sc.serveG.check()
|
|
|
|
|
id := uint32(1)
|
|
|
|
|
sc.maxClientStreamID = id
|
|
|
|
|
st := sc.newStream(id, 0, stateHalfClosedRemote)
|
|
|
|
|
st.reqTrailer = req.Trailer
|
|
|
|
|
if st.reqTrailer != nil {
|
|
|
|
|
st.trailer = make(http.Header)
|
|
|
|
|
}
|
|
|
|
|
rw := sc.newResponseWriter(st, req)
|
|
|
|
|
|
|
|
|
|
// Disable any read deadline set by the net/http package
|
|
|
|
|
// prior to the upgrade.
|
|
|
|
|
if sc.hs.ReadTimeout != 0 {
|
|
|
|
|
sc.conn.SetReadDeadline(time.Time{})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
go sc.runHandler(rw, req, sc.handler.ServeHTTP)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
|
|
|
|
|
sc := st.sc
|
|
|
|
|
sc.serveG.check()
|
|
|
|
@ -2033,12 +2097,6 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
|
|
|
|
|
return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bodyOpen := !f.StreamEnded()
|
|
|
|
|
if rp.method == "HEAD" && bodyOpen {
|
|
|
|
|
// HEAD requests can't have bodies
|
|
|
|
|
return nil, nil, sc.countError("head_body", streamError(f.StreamID, ErrCodeProtocol))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rp.header = make(http.Header)
|
|
|
|
|
for _, hf := range f.RegularFields() {
|
|
|
|
|
rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
|
|
|
|
@ -2051,6 +2109,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
bodyOpen := !f.StreamEnded()
|
|
|
|
|
if bodyOpen {
|
|
|
|
|
if vv, ok := rp.header["Content-Length"]; ok {
|
|
|
|
|
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
|
|
|
|
@ -2145,6 +2204,11 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
|
|
|
|
|
}
|
|
|
|
|
req = req.WithContext(st.ctx)
|
|
|
|
|
|
|
|
|
|
rw := sc.newResponseWriter(st, req)
|
|
|
|
|
return rw, req, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (sc *serverConn) newResponseWriter(st *stream, req *http.Request) *responseWriter {
|
|
|
|
|
rws := responseWriterStatePool.Get().(*responseWriterState)
|
|
|
|
|
bwSave := rws.bw
|
|
|
|
|
*rws = responseWriterState{} // zero all the fields
|
|
|
|
@ -2153,10 +2217,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
|
|
|
|
|
rws.bw.Reset(chunkWriter{rws})
|
|
|
|
|
rws.stream = st
|
|
|
|
|
rws.req = req
|
|
|
|
|
rws.body = body
|
|
|
|
|
|
|
|
|
|
rw := &responseWriter{rws: rws}
|
|
|
|
|
return rw, req, nil
|
|
|
|
|
return &responseWriter{rws: rws}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run on its own goroutine.
|
|
|
|
@ -2164,6 +2225,9 @@ func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler
|
|
|
|
|
didPanic := true
|
|
|
|
|
defer func() {
|
|
|
|
|
rw.rws.stream.cancelCtx()
|
|
|
|
|
if req.MultipartForm != nil {
|
|
|
|
|
req.MultipartForm.RemoveAll()
|
|
|
|
|
}
|
|
|
|
|
if didPanic {
|
|
|
|
|
e := recover()
|
|
|
|
|
sc.writeFrameFromHandler(FrameWriteRequest{
|
|
|
|
@ -2258,17 +2322,32 @@ func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {
|
|
|
|
|
|
|
|
|
|
func (sc *serverConn) noteBodyRead(st *stream, n int) {
|
|
|
|
|
sc.serveG.check()
|
|
|
|
|
sc.sendWindowUpdate(nil, n) // conn-level
|
|
|
|
|
sc.sendWindowUpdate(nil) // conn-level
|
|
|
|
|
if st.state != stateHalfClosedRemote && st.state != stateClosed {
|
|
|
|
|
// Don't send this WINDOW_UPDATE if the stream is closed
|
|
|
|
|
// remotely.
|
|
|
|
|
sc.sendWindowUpdate(st, n)
|
|
|
|
|
sc.sendWindowUpdate(st)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// st may be nil for conn-level
|
|
|
|
|
func (sc *serverConn) sendWindowUpdate(st *stream, n int) {
|
|
|
|
|
func (sc *serverConn) sendWindowUpdate(st *stream) {
|
|
|
|
|
sc.serveG.check()
|
|
|
|
|
|
|
|
|
|
var n int32
|
|
|
|
|
if st == nil {
|
|
|
|
|
if avail, windowSize := sc.inflow.available(), sc.srv.initialConnRecvWindowSize(); avail > windowSize/2 {
|
|
|
|
|
return
|
|
|
|
|
} else {
|
|
|
|
|
n = windowSize - avail
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if avail, windowSize := st.inflow.available(), sc.srv.initialStreamRecvWindowSize(); avail > windowSize/2 {
|
|
|
|
|
return
|
|
|
|
|
} else {
|
|
|
|
|
n = windowSize - avail
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// "The legal range for the increment to the flow control
|
|
|
|
|
// window is 1 to 2^31-1 (2,147,483,647) octets."
|
|
|
|
|
// A Go Read call on 64-bit machines could in theory read
|
|
|
|
@ -2316,17 +2395,18 @@ type requestBody struct {
|
|
|
|
|
_ incomparable
|
|
|
|
|
stream *stream
|
|
|
|
|
conn *serverConn
|
|
|
|
|
closed bool // for use by Close only
|
|
|
|
|
sawEOF bool // for use by Read only
|
|
|
|
|
pipe *pipe // non-nil if we have a HTTP entity message body
|
|
|
|
|
needsContinue bool // need to send a 100-continue
|
|
|
|
|
closeOnce sync.Once // for use by Close only
|
|
|
|
|
sawEOF bool // for use by Read only
|
|
|
|
|
pipe *pipe // non-nil if we have a HTTP entity message body
|
|
|
|
|
needsContinue bool // need to send a 100-continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *requestBody) Close() error {
|
|
|
|
|
if b.pipe != nil && !b.closed {
|
|
|
|
|
b.pipe.BreakWithError(errClosedBody)
|
|
|
|
|
}
|
|
|
|
|
b.closed = true
|
|
|
|
|
b.closeOnce.Do(func() {
|
|
|
|
|
if b.pipe != nil {
|
|
|
|
|
b.pipe.BreakWithError(errClosedBody)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2370,7 +2450,6 @@ type responseWriterState struct {
|
|
|
|
|
// immutable within a request:
|
|
|
|
|
stream *stream
|
|
|
|
|
req *http.Request
|
|
|
|
|
body *requestBody // to close at end of request, if DATA frames didn't
|
|
|
|
|
conn *serverConn
|
|
|
|
|
|
|
|
|
|
// TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc
|
|
|
|
@ -2434,6 +2513,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|
|
|
|
rws.writeHeader(200)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if rws.handlerDone {
|
|
|
|
|
rws.promoteUndeclaredTrailers()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isHeadResp := rws.req.Method == "HEAD"
|
|
|
|
|
if !rws.sentHeader {
|
|
|
|
|
rws.sentHeader = true
|
|
|
|
@ -2505,10 +2588,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|
|
|
|
return 0, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if rws.handlerDone {
|
|
|
|
|
rws.promoteUndeclaredTrailers()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// only send trailers if they have actually been defined by the
|
|
|
|
|
// server handler.
|
|
|
|
|
hasNonemptyTrailers := rws.hasNonemptyTrailers()
|
|
|
|
@ -2546,8 +2625,9 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|
|
|
|
// prior to the headers being written. If the set of trailers is fixed
|
|
|
|
|
// or known before the header is written, the normal Go trailers mechanism
|
|
|
|
|
// is preferred:
|
|
|
|
|
// https://golang.org/pkg/net/http/#ResponseWriter
|
|
|
|
|
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
|
|
|
|
|
//
|
|
|
|
|
// https://golang.org/pkg/net/http/#ResponseWriter
|
|
|
|
|
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
|
|
|
|
|
const TrailerPrefix = "Trailer:"
|
|
|
|
|
|
|
|
|
|
// promoteUndeclaredTrailers permits http.Handlers to set trailers
|
|
|
|
@ -2643,8 +2723,7 @@ 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).
|
|
|
|
|
// at http://httpwg.org/specs/rfc7231.html#status.codes).
|
|
|
|
|
// But for now any three digits.
|
|
|
|
|
//
|
|
|
|
|
// We used to send "HTTP/1.1 000 0" on the wire in responses but there's
|
|
|
|
@ -2665,13 +2744,41 @@ 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 {
|
|
|
|
|
rws.snapHeader = cloneHeader(rws.handlerHeader)
|
|
|
|
|
if rws.wroteHeader {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkWriteHeaderCode(code)
|
|
|
|
|
|
|
|
|
|
// Handle informational headers
|
|
|
|
|
if code >= 100 && code <= 199 {
|
|
|
|
|
// Per RFC 8297 we must not clear the current header map
|
|
|
|
|
h := rws.handlerHeader
|
|
|
|
|
|
|
|
|
|
_, cl := h["Content-Length"]
|
|
|
|
|
_, te := h["Transfer-Encoding"]
|
|
|
|
|
if cl || te {
|
|
|
|
|
h = h.Clone()
|
|
|
|
|
h.Del("Content-Length")
|
|
|
|
|
h.Del("Transfer-Encoding")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if rws.conn.writeHeaders(rws.stream, &writeResHeaders{
|
|
|
|
|
streamID: rws.stream.id,
|
|
|
|
|
httpResCode: code,
|
|
|
|
|
h: h,
|
|
|
|
|
endStream: rws.handlerDone && !rws.hasTrailers(),
|
|
|
|
|
}) != nil {
|
|
|
|
|
rws.dirty = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rws.wroteHeader = true
|
|
|
|
|
rws.status = code
|
|
|
|
|
if len(rws.handlerHeader) > 0 {
|
|
|
|
|
rws.snapHeader = cloneHeader(rws.handlerHeader)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|