func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest) {
	err := wr.write.writeFrame(sc)
	sc.wroteFrameCh <- frameWriteResult{wr: wr, err: err}
}
writeFrameAsync runs in its own goroutine and writes a single frame
and then reports when it's done.
At most one goroutine can be running writeFrameAsync at a time per
serverConn.
package http2
import (
	"bufio"
	"bytes"
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"net"
	"net/http"
	"net/textproto"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
	"golang.org/x/net/http/httpguts"
	"github.com/minight/h2csmuggler/http2/hpack"
)
const (
	prefaceTimeout         = 10 * time.Second
	firstSettingsTimeout   = 2 * time.Second  
	handlerChunkWriteSize  = 4 << 10
	defaultMaxStreams      = 250  
	maxQueuedControlFrames = 10000
)
var (
	errClientDisconnected = errors.New("client disconnected")
	errClosedBody         = errors.New("body closed by handler")
	errHandlerComplete    = errors.New("http2: request body closed due to handler exiting")
	errStreamClosed       = errors.New("http2: stream closed")
)
var responseWriterStatePool = sync.Pool{
	New: func() interface{} {
		rws := &responseWriterState{}
		rws.bw = bufio.NewWriterSize(chunkWriter{rws}, handlerChunkWriteSize)
		return rws
	},
}
var (
	testHookOnConn        func()
	testHookGetServerConn func(*serverConn)
	testHookOnPanicMu     *sync.Mutex  
	testHookOnPanic       func(sc *serverConn, panicVal interface{}) (rePanic bool)
)
type Server struct {
	MaxHandlers int
	MaxConcurrentStreams uint32
	MaxReadFrameSize uint32
	PermitProhibitedCipherSuites bool
	IdleTimeout time.Duration
	MaxUploadBufferPerConnection int32
	MaxUploadBufferPerStream int32
	NewWriteScheduler func() WriteScheduler
	state *serverInternalState
}
func (s *Server) initialConnRecvWindowSize() int32 {
	if s.MaxUploadBufferPerConnection > initialWindowSize {
		return s.MaxUploadBufferPerConnection
	}
	return 1 << 20
}
func (s *Server) initialStreamRecvWindowSize() int32 {
	if s.MaxUploadBufferPerStream > 0 {
		return s.MaxUploadBufferPerStream
	}
	return 1 << 20
}
func (s *Server) maxReadFrameSize() uint32 {
	if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize {
		return v
	}
	return defaultMaxReadFrameSize
}
func (s *Server) maxConcurrentStreams() uint32 {
	if v := s.MaxConcurrentStreams; v > 0 {
		return v
	}
	return defaultMaxStreams
}
func (s *Server) maxQueuedControlFrames() int {
	return maxQueuedControlFrames
}
type serverInternalState struct {
	mu          sync.Mutex
	activeConns map[*serverConn]struct{}
}
func (s *serverInternalState) registerConn(sc *serverConn) {
	if s == nil {
		return  
	}
	s.mu.Lock()
	s.activeConns[sc] = struct{}{}
	s.mu.Unlock()
}
func (s *serverInternalState) unregisterConn(sc *serverConn) {
	if s == nil {
		return  
	}
	s.mu.Lock()
	delete(s.activeConns, sc)
	s.mu.Unlock()
}
func (s *serverInternalState) startGracefulShutdown() {
	if s == nil {
		return  
	}
	s.mu.Lock()
	for sc := range s.activeConns {
		sc.startGracefulShutdown()
	}
	s.mu.Unlock()
}
func ConfigureServer(s *http.Server, conf *Server) error {
	if s == nil {
		panic("nil *http.Server")
	}
	if conf == nil {
		conf = new(Server)
	}
	conf.state = &serverInternalState{activeConns: make(map[*serverConn]struct{})}
	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 {
		haveRequired := false
		sawBad := false
		for i, cs := range s.TLSConfig.CipherSuites {
			switch cs {
			case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
				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 (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).")
		}
	}
	s.TLSConfig.PreferServerCipherSuites = true
	haveNPN := false
	for _, p := range s.TLSConfig.NextProtos {
		if p == NextProtoTLS {
			haveNPN = true
			break
		}
	}
	if !haveNPN {
		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS)
	}
	if s.TLSNextProto == nil {
		s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
	}
	protoHandler := func(hs *http.Server, c *tls.Conn, h http.Handler) {
		if testHookOnConn != nil {
			testHookOnConn()
		}
		var ctx context.Context
		type baseContexter interface {
			BaseContext() context.Context
		}
		if bc, ok := h.(baseContexter); ok {
			ctx = bc.BaseContext()
		}
		conf.ServeConn(c, &ServeConnOpts{
			Context:    ctx,
			Handler:    h,
			BaseConfig: hs,
		})
	}
	s.TLSNextProto[NextProtoTLS] = protoHandler
	return nil
}
type ServeConnOpts struct {
	Context context.Context
	BaseConfig *http.Server
	Handler http.Handler
}
func (o *ServeConnOpts) context() context.Context {
	if o != nil && o.Context != nil {
		return o.Context
	}
	return context.Background()
}
func (o *ServeConnOpts) baseConfig() *http.Server {
	if o != nil && o.BaseConfig != nil {
		return o.BaseConfig
	}
	return new(http.Server)
}
func (o *ServeConnOpts) handler() http.Handler {
	if o != nil {
		if o.Handler != nil {
			return o.Handler
		}
		if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
			return o.BaseConfig.Handler
		}
	}
	return http.DefaultServeMux
}
func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
	baseCtx, cancel := serverConnBaseContext(c, opts)
	defer cancel()
	sc := &serverConn{
		srv:                         s,
		hs:                          opts.baseConfig(),
		conn:                        c,
		baseCtx:                     baseCtx,
		remoteAddrStr:               c.RemoteAddr().String(),
		bw:                          newBufferedWriter(c),
		handler:                     opts.handler(),
		streams:                     make(map[uint32]*stream),
		readFrameCh:                 make(chan readFrameResult),
		wantWriteFrameCh:            make(chan FrameWriteRequest, 8),
		serveMsgCh:                  make(chan interface{}, 8),
		wroteFrameCh:                make(chan frameWriteResult, 1),  
		bodyReadCh:                  make(chan bodyReadMsg),          
		doneServing:                 make(chan struct{}),
		clientMaxStreams:            math.MaxUint32,  
		advMaxStreams:               s.maxConcurrentStreams(),
		initialStreamSendWindowSize: initialWindowSize,
		maxFrameSize:                initialMaxFrameSize,
		headerTableSize:             initialHeaderTableSize,
		serveG:                      newGoroutineLock(),
		pushEnabled:                 true,
	}
	s.state.registerConn(sc)
	defer s.state.unregisterConn(sc)
	if sc.hs.WriteTimeout != 0 {
		sc.conn.SetWriteDeadline(time.Time{})
	}
	if s.NewWriteScheduler != nil {
		sc.writeSched = s.NewWriteScheduler()
	} else {
		sc.writeSched = NewRandomWriteScheduler()
	}
	sc.flow.add(initialWindowSize)
	sc.inflow.add(initialWindowSize)
	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
	fr := NewFramer(sc.bw, c)
	fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
	fr.MaxHeaderListSize = sc.maxHeaderListSize()
	fr.SetMaxReadFrameSize(s.maxReadFrameSize())
	sc.framer = fr
	if tc, ok := c.(connectionStater); ok {
		sc.tlsState = new(tls.ConnectionState)
		*sc.tlsState = tc.ConnectionState()
		if sc.tlsState.Version < tls.VersionTLS12 {
			sc.rejectConn(ErrCodeInadequateSecurity, "TLS version too low")
			return
		}
		if sc.tlsState.ServerName == "" {
		}
		if !s.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
			sc.rejectConn(ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
			return
		}
	}
	if hook := testHookGetServerConn; hook != nil {
		hook(sc)
	}
	sc.serve()
}
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
	ctx, cancel = context.WithCancel(opts.context())
	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)
	sc.framer.WriteGoAway(0, err, []byte(debug))
	sc.bw.Flush()
	sc.conn.Close()
}
type serverConn struct {
	srv              *Server
	hs               *http.Server
	conn             net.Conn
	bw               *bufferedWriter  
	handler          http.Handler
	baseCtx          context.Context
	framer           *Framer
	doneServing      chan struct{}           
	readFrameCh      chan readFrameResult    
	wantWriteFrameCh chan FrameWriteRequest  
	wroteFrameCh     chan frameWriteResult   
	bodyReadCh       chan bodyReadMsg        
	serveMsgCh       chan interface{}        
	flow             flow                    
	inflow           flow                    
	tlsState         *tls.ConnectionState    
	remoteAddrStr    string
	writeSched       WriteScheduler
	serveG                      goroutineLock  
	pushEnabled                 bool
	sawFirstSettings            bool  
	needToSendSettingsAck       bool
	unackedSettings             int     
	queuedControlFrames         int     
	clientMaxStreams            uint32  
	advMaxStreams               uint32  
	curClientStreams            uint32  
	curPushedStreams            uint32  
	maxClientStreamID           uint32  
	maxPushPromiseID            uint32  
	streams                     map[uint32]*stream
	initialStreamSendWindowSize int32
	maxFrameSize                int32
	headerTableSize             uint32
	peerMaxHeaderListSize       uint32             
	canonHeader                 map[string]string  
	writingFrame                bool               
	writingFrameAsync           bool               
	needsFrameFlush             bool               
	inGoAway                    bool               
	inFrameScheduleLoop         bool               
	needToSendGoAway            bool               
	goAwayCode                  ErrCode
	shutdownTimer               *time.Timer  
	idleTimer                   *time.Timer  
	headerWriteBuf bytes.Buffer
	hpackEncoder   *hpack.Encoder
	shutdownOnce sync.Once
}
func (sc *serverConn) maxHeaderListSize() uint32 {
	n := sc.hs.MaxHeaderBytes
	if n <= 0 {
		n = http.DefaultMaxHeaderBytes
	}
	const perFieldOverhead = 32  
	const typicalHeaders = 10    
	return uint32(n + typicalHeaders*perFieldOverhead)
}
func (sc *serverConn) curOpenStreams() uint32 {
	sc.serveG.check()
	return sc.curClientStreams + sc.curPushedStreams
}
type stream struct {
	sc        *serverConn
	id        uint32
	body      *pipe        
	cw        closeWaiter  
	ctx       context.Context
	cancelCtx func()
	bodyBytes        int64  
	declBodyBytes    int64  
	flow             flow   
	inflow           flow   
	state            streamState
	resetQueued      bool         
	gotTrailerHeader bool         
	wroteHeaders     bool         
	writeDeadline    *time.Timer  
	trailer    http.Header  
	reqTrailer http.Header  
}
func (sc *serverConn) Framer() *Framer  { return sc.framer }
func (sc *serverConn) CloseConn() error { return sc.conn.Close() }
func (sc *serverConn) Flush() error     { return sc.bw.Flush() }
func (sc *serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
	return sc.hpackEncoder, &sc.headerWriteBuf
}
func (sc *serverConn) state(streamID uint32) (streamState, *stream) {
	sc.serveG.check()
	if st, ok := sc.streams[streamID]; ok {
		return st.state, st
	}
	if streamID%2 == 1 {
		if streamID <= sc.maxClientStreamID {
			return stateClosed, nil
		}
	} else {
		if streamID <= sc.maxPushPromiseID {
			return stateClosed, nil
		}
	}
	return stateIdle, nil
}
func (sc *serverConn) setConnState(state http.ConnState) {
	if sc.hs.ConnState != nil {
		sc.hs.ConnState(sc.conn, state)
	}
}
func (sc *serverConn) vlogf(format string, args ...interface{}) {
	if VerboseLogs {
		sc.logf(format, args...)
	}
}
func (sc *serverConn) logf(format string, args ...interface{}) {
	if lg := sc.hs.ErrorLog; lg != nil {
		lg.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}
func errno(v error) uintptr {
	if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
		return uintptr(rv.Uint())
	}
	return 0
}
func isClosedConnError(err error) bool {
	if err == nil {
		return false
	}
	str := err.Error()
	if strings.Contains(str, "use of closed network connection") {
		return true
	}
	if runtime.GOOS == "windows" {
		if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
			if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
				const WSAECONNABORTED = 10053
				const WSAECONNRESET = 10054
				if n := errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
					return true
				}
			}
		}
	}
	return false
}
func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
	if err == nil {
		return
	}
	if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) || err == errPrefaceTimeout {
		sc.vlogf(format, args...)
	} else {
		sc.logf(format, args...)
	}
}
func (sc *serverConn) canonicalHeader(v string) string {
	sc.serveG.check()
	buildCommonHeaderMapsOnce()
	cv, ok := commonCanonHeader[v]
	if ok {
		return cv
	}
	cv, ok = sc.canonHeader[v]
	if ok {
		return cv
	}
	if sc.canonHeader == nil {
		sc.canonHeader = make(map[string]string)
	}
	cv = http.CanonicalHeaderKey(v)
	sc.canonHeader[v] = cv
	return cv
}
type readFrameResult struct {
	f   Frame  
	err error
	readMore func()
}
func (sc *serverConn) readFrames() {
	gate := make(gate)
	gateDone := gate.Done
	for {
		f, err := sc.framer.ReadFrame()
		select {
		case sc.readFrameCh <- readFrameResult{f, err, gateDone}:
		case <-sc.doneServing:
			return
		}
		select {
		case <-gate:
		case <-sc.doneServing:
			return
		}
		if terminalReadFrameError(err) {
			return
		}
	}
}
type frameWriteResult struct {
	_   incomparable
	wr  FrameWriteRequest  
	err error              
}