ErrorCode HTTP2Codec::parseHeadersImpl()

in proxygen/lib/http/codec/HTTP2Codec.cpp [440:542]


ErrorCode HTTP2Codec::parseHeadersImpl(
    Cursor& /*cursor*/,
    std::unique_ptr<IOBuf> headerBuf,
    const folly::Optional<http2::PriorityUpdate>& priority,
    const folly::Optional<uint32_t>& promisedStream,
    const folly::Optional<ExAttributes>& exAttributes) {
  curHeaderBlock_.append(std::move(headerBuf));
  std::unique_ptr<HTTPMessage> msg;
  uint32_t headersCompleteStream = curHeader_.stream;

  // if we're not parsing CONTINUATION, then it's start of new header block
  if (curHeader_.type != http2::FrameType::CONTINUATION) {
    headerBlockFrameType_ = curHeader_.type;
    if (promisedStream) {
      parsingReq_ = true;
    } else if (exAttributes) {
      parsingReq_ = isRequest(curHeader_.stream);
    } else {
      parsingReq_ = transportDirection_ == TransportDirection::DOWNSTREAM;
    }
  } else if (headerBlockFrameType_ == http2::FrameType::PUSH_PROMISE) {
    CHECK(promisedStream_.hasValue());
    headersCompleteStream = *promisedStream_;
  }

  DeferredParseError parseError;
  if (curHeader_.flags & http2::END_HEADERS) {
    auto parseRes = parseHeadersDecodeFrames(priority, exAttributes);
    if (parseRes.hasError()) {
      parseError = std::move(parseRes.error());
      if (parseError.connectionError) {
        return parseError.errorCode;
      }
    } else {
      msg = std::move(*parseRes);
    }
  }

  // Report back what we've parsed
  auto concurError = parseHeadersCheckConcurrentStreams(priority);
  if (concurError.has_value()) {
    return concurError.value();
  }

  bool trailers = parsingTrailers();
  bool allHeaderFramesReceived =
      (curHeader_.flags & http2::END_HEADERS) &&
      (headerBlockFrameType_ == http2::FrameType::HEADERS);
  if (allHeaderFramesReceived && !trailers) {
    // Only deliver onMessageBegin once per stream.
    // For responses with CONTINUATION, this will be delayed until
    // the frame with the END_HEADERS flag set.
    deliverCallbackIfAllowed(&HTTPCodec::Callback::onMessageBegin,
                             "onMessageBegin",
                             curHeader_.stream,
                             msg.get());
  } else if (curHeader_.type == http2::FrameType::EX_HEADERS) {
    deliverCallbackIfAllowed(&HTTPCodec::Callback::onExMessageBegin,
                             "onExMessageBegin",
                             curHeader_.stream,
                             exAttributes->controlStream,
                             exAttributes->unidirectional,
                             msg.get());
  } else if (curHeader_.type == http2::FrameType::PUSH_PROMISE) {
    DCHECK(promisedStream);
    deliverCallbackIfAllowed(&HTTPCodec::Callback::onPushMessageBegin,
                             "onPushMessageBegin",
                             *promisedStream,
                             curHeader_.stream,
                             msg.get());
    promisedStream_ = *promisedStream;
    headersCompleteStream = *promisedStream;
  }

  if (curHeader_.flags & http2::END_HEADERS) {
    if (!msg) {
      deliverDeferredParseError(parseError);
      return ErrorCode::NO_ERROR;
    }
    if (!(curHeader_.flags & http2::END_STREAM)) {
      // If it there are DATA frames coming, consider it chunked
      msg->setIsChunked(true);
    }
    if (trailers) {
      VLOG(4) << "Trailers complete for streamId=" << headersCompleteStream
              << " direction=" << transportDirection_;
      auto trailerHeaders =
          std::make_unique<HTTPHeaders>(msg->extractHeaders());
      msg.reset();
      deliverCallbackIfAllowed(&HTTPCodec::Callback::onTrailersComplete,
                               "onTrailersComplete",
                               headersCompleteStream,
                               std::move(trailerHeaders));
    } else {
      deliverCallbackIfAllowed(&HTTPCodec::Callback::onHeadersComplete,
                               "onHeadersComplete",
                               headersCompleteStream,
                               std::move(msg));
      promisedStream_ = folly::none;
    }
  }
  return handleEndStream();
}