ErrorCode HTTP2Codec::parseDataFrameData()

in proxygen/lib/http/codec/HTTP2Codec.cpp [312:392]


ErrorCode HTTP2Codec::parseDataFrameData(Cursor& cursor,
                                         size_t bufLen,
                                         size_t& parsed) {
  FOLLY_SCOPED_TRACE_SECTION("HTTP2Codec - parseDataFrameData");
  if (bufLen == 0) {
    VLOG(10) << "No data to parse";
    return ErrorCode::NO_ERROR;
  }

  std::unique_ptr<IOBuf> outData;
  uint16_t padding = 0;
  VLOG(10) << "parsing DATA frame data for stream=" << curHeader_.stream
           << " frame data length=" << curHeader_.length
           << " pendingDataFrameBytes_=" << pendingDataFrameBytes_
           << " pendingDataFramePaddingBytes_=" << pendingDataFramePaddingBytes_
           << " bufLen=" << bufLen << " parsed=" << parsed;
  // Parse the padding information only the first time
  if (pendingDataFrameBytes_ == curHeader_.length &&
      pendingDataFramePaddingBytes_ == 0) {
    if (frameHasPadding(curHeader_) && bufLen == 1) {
      // We need to wait for more bytes otherwise we won't be able to pass
      // the correct padding to the first onBody call
      return ErrorCode::NO_ERROR;
    }
    const auto ret = http2::parseDataBegin(cursor, curHeader_, parsed, padding);
    RETURN_IF_ERROR(ret);
    if (padding > 0) {
      pendingDataFramePaddingBytes_ = padding - 1;
      pendingDataFrameBytes_--;
      bufLen--;
      parsed++;
    }
    VLOG(10)
        << "out padding=" << padding
        << " pendingDataFrameBytes_=" << pendingDataFrameBytes_
        << " pendingDataFramePaddingBytes_=" << pendingDataFramePaddingBytes_
        << " bufLen=" << bufLen << " parsed=" << parsed;
  }
  if (bufLen > 0) {
    // Check if we have application data to parse
    if (pendingDataFrameBytes_ > pendingDataFramePaddingBytes_) {
      const size_t pendingAppData =
          pendingDataFrameBytes_ - pendingDataFramePaddingBytes_;
      const size_t toClone = std::min(pendingAppData, bufLen);
      cursor.clone(outData, toClone);
      bufLen -= toClone;
      pendingDataFrameBytes_ -= toClone;
      parsed += toClone;
      VLOG(10) << "parsed some app data, pendingDataFrameBytes_="
               << pendingDataFrameBytes_ << " pendingDataFramePaddingBytes_="
               << pendingDataFramePaddingBytes_ << " bufLen=" << bufLen
               << " parsed=" << parsed;
    }
    // Check if we have padding bytes to parse
    if (bufLen > 0 && pendingDataFramePaddingBytes_ > 0) {
      size_t toSkip = 0;
      auto ret = http2::parseDataEnd(
          cursor, bufLen, pendingDataFramePaddingBytes_, toSkip);
      RETURN_IF_ERROR(ret);
      pendingDataFrameBytes_ -= toSkip;
      pendingDataFramePaddingBytes_ -= toSkip;
      parsed += toSkip;
      VLOG(10) << "parsed some padding, pendingDataFrameBytes_="
               << pendingDataFrameBytes_ << " pendingDataFramePaddingBytes_="
               << pendingDataFramePaddingBytes_ << " bufLen=" << bufLen
               << " parsed=" << parsed;
    }
  }

  if (callback_ && (padding > 0 || (outData && !outData->empty()))) {
    if (!outData) {
      outData = std::make_unique<IOBuf>();
    }
    deliverCallbackIfAllowed(&HTTPCodec::Callback::onBody,
                             "onBody",
                             curHeader_.stream,
                             std::move(outData),
                             padding);
  }
  return (pendingDataFrameBytes_ > 0) ? ErrorCode::NO_ERROR : handleEndStream();
}