var frameParsers = map[FrameType]frameParser{
FrameData: parseDataFrame,
FrameHeaders: parseHeadersFrame,
FramePriority: parsePriorityFrame,
FrameRSTStream: parseRSTStreamFrame,
FrameSettings: parseSettingsFrame,
FramePushPromise: parsePushPromise,
FramePing: parsePingFrame,
FrameGoAway: parseGoAwayFrame,
FrameWindowUpdate: parseWindowUpdateFrame,
FrameContinuation: parseContinuationFrame,
}
func typeFrameParser(t FrameType) frameParser {
if f := frameParsers[t]; f != nil {
return f
}
return parseUnknownFrame
}
readFrameCh 中获取的数据,通知到主 goroutine,然后开始来逻辑处理:
func (sc *serverConn) serve() {
....
case res := <-sc.readFrameCh:
// 获取从客户端读取的一帧的结果
if !sc.processFrameFromReader(res) {
return
}
res.readMore()
if settingsTimer != nil {
settingsTimer.Stop()
settingsTimer = nil
}
...
}
func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
sc.serveG.check()
err := res.err
if err != nil {
// freame 太大
if err == ErrFrameTooLarge {
sc.goAway(ErrCodeFrameSize)
return true // goAway will close the loop
}
clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err)
if clientGone {
// TODO: could we also get into this state if
// the peer does a half close
// (e.g. CloseWrite) because they're done
// sending frames but they're still wanting
// our open replies? Investigate.
// TODO: add CloseWrite to crypto/tls.Conn first
// so we have a way to test this? I suppose
// just for testing we could have a non-TLS mode.
return false
}
} else {
// 获取一帧
f := res.f
if VerboseLogs {
// 获取一帧
sc.vlogf("http2: server read frame %v", summarizeFrame(f))
}
// 处理一帧
err = sc.processFrame(f)
if err == nil {
return true
}
}
switch ev := err.(type) {
case StreamError:
// 重置 stream
sc.resetStream(ev)
return true
case goAwayFlowError:
sc.goAway(ErrCodeFlowControl)
return true
case ConnectionError:
sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
sc.goAway(ErrCode(ev))
return true // goAway will handle shutdown
default:
if res.err != nil {
sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
} else {
sc.logf("http2: server closing client connection: %v", err)
}
return false
}
}
查看当前的 frame 是否太大,太大直接发 goAway 帧,
出来客户端关闭写的情况,这里留下了未实现的部分
开始处理不同类型的帧
// 处理各种类型的帧
func (sc *serverConn) processFrame(f Frame) error {
sc.serveG.check()
// First frame received must be SETTINGS.
if !sc.sawFirstSettings {
if _, ok := f.(*SettingsFrame); !ok {
return ConnectionError(ErrCodeProtocol)
}
// 第一帧必须是 setting 帧
sc.sawFirstSettings = true
}
switch f := f.(type) {
case *SettingsFrame:
/// 处理 setting 帧
return sc.processSettings(f)
case *MetaHeadersFrame:
return sc.processHeaders(f)
case *WindowUpdateFrame:
return sc.processWindowUpdate(f)
case *PingFrame: // ping frame
return sc.processPing(f)
case *DataFrame: // data frame
return sc.processData(f)
case *RSTStreamFrame:
return sc.processResetStream(f)
case *PriorityFrame:
return sc.processPriority(f)
// 处理 GoAway,用来通知客户端,要重新建立链接,这个链接的 stream 满了
case *GoAwayFrame:
return sc.processGoAway(f)
case *PushPromiseFrame:
// A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
// frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
return ConnectionError(ErrCodeProtocol)
default:
sc.vlogf("http2: server ignoring frame: %v", f.Header())
return nil
}
}
这个连接没有处理过第一帧,那么这一帧必须是 setting 帧
然后根据不同的帧类型来处理
处理 setting 帧
func (sc *serverConn) processSettings(f *SettingsFrame) error {
sc.serveG.check()
// 是客户端对 server 的 ack
if f.IsAck() {
sc.unackedSettings--
if sc.unackedSettings < 0 {
// Why is the peer ACKing settings we never sent?
// The spec doesn't mention this case, but
// hang up on them anyway.
return ConnectionError(ErrCodeProtocol)
}
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
}
// TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
// acknowledged individually, even if multiple are received before the ACK.
// 需要应达 setting 的 ack
sc.needToSendSettingsAck = true
sc.scheduleFrameWrite()
return nil
}
参考资料
处理客户端发送
readFrameCh 将解析获取的一帧数据返回给 main goroutine, 主要解析逻辑是 readFrame
这里的类型包含如下
readFrameCh 中获取的数据,通知到主 goroutine,然后开始来逻辑处理:
开始处理不同类型的帧
处理 setting 帧
type/golang #public