in proxygen/lib/http/codec/HQFramedCodec.cpp [61:151]
size_t HQFramedCodec::onFramedIngress(const IOBuf& buf) {
FOLLY_SCOPED_TRACE_SECTION("HQFramedCodec - onFramedIngress");
// if for some reason onFramedIngress gets called again after erroring out,
// skip parsing
if (connError_ != folly::none) {
return 0;
}
Cursor cursor(&buf);
size_t parsedTot = 0;
auto bufLen = cursor.totalLength();
while (connError_ == folly::none && bufLen > 0 && !parserPaused_) {
size_t parsed = 0;
if (frameState_ == FrameState::FRAME_HEADER_TYPE) {
auto type = quic::decodeQuicInteger(cursor);
if (!type) {
break;
}
curHeader_.type = FrameType(type->first);
parsed += type->second;
auto res = checkFrameAllowed(curHeader_.type);
if (res) {
VLOG(4) << "Frame not allowed: 0x" << std::setfill('0')
<< std::setw(sizeof(uint64_t) * 2) << std::hex
<< (uint64_t)curHeader_.type << " on streamID=" << streamId_;
connError_ = res;
break;
}
frameState_ = FrameState::FRAME_HEADER_LENGTH;
} else if (frameState_ == FrameState::FRAME_HEADER_LENGTH) {
auto length = quic::decodeQuicInteger(cursor);
if (!length) {
break;
}
curHeader_.length = length->first;
parsed += length->second;
if (callback_) {
callback_->onFrameHeader(streamId_,
0, // no flags!
curHeader_.length,
static_cast<uint64_t>(curHeader_.type));
}
#ifndef NDEBUG
receivedFrameCount_++;
#endif
pendingDataFrameBytes_ = curHeader_.length;
if (curHeader_.length == 0) {
// If the frame length is zero, call parseFrame immediately. It is up
// to each frame to determine whether length 0 is valid.
connError_ = parseFrame(cursor);
frameState_ = FrameState::FRAME_HEADER_TYPE;
} else {
// For DATA frames, move to the streaming state
if (curHeader_.type == FrameType::DATA) {
frameState_ = FrameState::FRAME_PAYLOAD_STREAMING;
} else {
frameState_ = FrameState::FRAME_PAYLOAD;
}
}
} else if (frameState_ == FrameState::FRAME_PAYLOAD) {
// Already parsed the common frame header
const auto frameLen = curHeader_.length;
if (bufLen >= frameLen) {
connError_ = parseFrame(cursor);
// if connError_ is set, it means there was a frame error,
// so it doesn't really matter whether we have actually parsed all the
// data or not
parsed += curHeader_.length;
frameState_ = FrameState::FRAME_HEADER_TYPE;
} else {
break;
}
} else if (bufLen > 0 &&
frameState_ == FrameState::FRAME_PAYLOAD_STREAMING) {
FrameHeader auxDataFrameHeader;
auxDataFrameHeader.type = FrameType::DATA;
auxDataFrameHeader.length = std::min(pendingDataFrameBytes_, bufLen);
connError_ = parseData(cursor, auxDataFrameHeader);
parsed += auxDataFrameHeader.length;
pendingDataFrameBytes_ -= auxDataFrameHeader.length;
if (pendingDataFrameBytes_ == 0) {
frameState_ = FrameState::FRAME_HEADER_TYPE;
}
}
CHECK_GE(bufLen, parsed);
bufLen -= parsed;
parsedTot += parsed;
totalBytesParsed_ += parsed;
}
checkConnectionError(connError_, &buf);
return parsedTot;
}