in mux.go [229:279]
func (m *mux) getContentType(framer *http2.Framer, framesBuf *bytes.Buffer) (contentType string, _ error) {
// Code based on https://github.com/soheilhy/cmux
//
// Copyright 2016 The CMux Authors. All rights reserved.
dec := decoderPool.Get().(*decoder)
// Read frames until we have the content-type header, or we know there isn't one.
var haveFirstSettings bool
var haveFirstSettingsACK bool
var haveEndHeaders bool
for (dec.contentType == "" && !haveEndHeaders) || !haveFirstSettings || !haveFirstSettingsACK {
f, err := framer.ReadFrame()
if err != nil {
return "", err
}
switch f := f.(type) {
case *http2.SettingsFrame:
switch {
case !haveFirstSettingsACK && f.IsAck():
haveFirstSettingsACK = true
// We accept the ACK, and omit it from the frames
// written to the real server.
framesBuf.Truncate(framesBuf.Len() - int(f.Length) - http2FrameHeaderLength)
case !haveFirstSettings && !f.IsAck():
haveFirstSettings = true
// We ACK the client's first SETTINGS to unblock it,
// and ignore the first ACK from the real server.
if err := framer.WriteSettingsAck(); err != nil {
return "", err
}
}
case *http2.ContinuationFrame:
if _, err := dec.d.Write(f.HeaderBlockFragment()); err != nil {
return "", err
}
haveEndHeaders = f.FrameHeader.Flags&http2.FlagHeadersEndHeaders != 0
case *http2.HeadersFrame:
if _, err := dec.d.Write(f.HeaderBlockFragment()); err != nil {
return "", err
}
haveEndHeaders = f.FrameHeader.Flags&http2.FlagHeadersEndHeaders != 0
}
}
contentType = dec.contentType
if dec.d.Close() == nil {
dec.contentType = ""
decoderPool.Put(dec)
}
return contentType, nil
}