void HTTP2Codec::generateHeaderImpl()

in proxygen/lib/http/codec/HTTP2Codec.cpp [1234:1353]


void HTTP2Codec::generateHeaderImpl(
    folly::IOBufQueue& writeBuf,
    StreamID stream,
    const HTTPMessage& msg,
    const folly::Optional<StreamID>& assocStream,
    const folly::Optional<HTTPCodec::ExAttributes>& exAttributes,
    bool eom,
    HTTPHeaderSize* size,
    const folly::Optional<HTTPHeaders>& extraHeaders) {
  HTTPHeaderSize localSize;
  if (!size) {
    size = &localSize;
  }
  if (assocStream) {
    CHECK(!exAttributes);
    VLOG(4) << "generating PUSH_PROMISE for stream=" << stream;
  } else if (exAttributes) {
    CHECK(!assocStream);
    VLOG(4) << "generating ExHEADERS for stream=" << stream
            << " with control stream=" << exAttributes->controlStream
            << " unidirectional=" << exAttributes->unidirectional;
  } else {
    VLOG(4) << "generating HEADERS for stream=" << stream;
  }

  if (!isStreamIngressEgressAllowed(stream)) {
    VLOG(2) << "Suppressing HEADERS/PROMISE for stream=" << stream
            << " ingressGoawayAck_=" << ingressGoawayAck_;
    if (size) {
      size->uncompressed = 0;
      size->compressed = 0;
    }
    return;
  }

  if (msg.isRequest()) {
    DCHECK(transportDirection_ == TransportDirection::UPSTREAM || assocStream ||
           exAttributes);
    if (msg.isEgressWebsocketUpgrade()) {
      upgradedStreams_.insert(stream);
    }
  } else {
    DCHECK(transportDirection_ == TransportDirection::DOWNSTREAM ||
           exAttributes);
  }

  auto httpPri = msg.getHTTP2Priority();
  folly::Optional<http2::PriorityUpdate> pri;
  if (httpPri) {
    pri = http2::PriorityUpdate{
        std::get<0>(*httpPri), std::get<1>(*httpPri), std::get<2>(*httpPri)};
    if (pri->streamDependency == stream) {
      LOG(ERROR) << "Overwriting circular dependency for stream=" << stream;
      pri = http2::DefaultPriority;
    }
  }
  auto headerSize = http2::calculatePreHeaderBlockSize(assocStream.has_value(),
                                                       exAttributes.has_value(),
                                                       pri.has_value(),
                                                       false);
  auto maxFrameSize = maxSendFrameSize();
  uint32_t remainingFrameSize =
      maxFrameSize - headerSize + http2::kFrameHeaderSize;
  auto frameHeader = writeBuf.preallocate(headerSize, kDefaultGrowth);
  writeBuf.postallocate(headerSize);
  headerCodec_.encodeHTTP(msg, writeBuf, addDateToResponse_, extraHeaders);
  *size = headerCodec_.getEncodedSize();

  IOBufQueue queue(IOBufQueue::cacheChainLength());
  auto chunkLen =
      splitCompressed(size->compressed, remainingFrameSize, writeBuf, queue);
  bool endHeaders = queue.chainLength() == 0;
  if (assocStream) {
    DCHECK_EQ(transportDirection_, TransportDirection::DOWNSTREAM);
    DCHECK(!eom);
    generateHeaderCallbackWrapper(
        stream,
        http2::FrameType::PUSH_PROMISE,
        http2::writePushPromise((uint8_t*)frameHeader.first,
                                frameHeader.second,
                                writeBuf,
                                *assocStream,
                                stream,
                                chunkLen,
                                http2::kNoPadding,
                                endHeaders));
  } else if (exAttributes) {
    generateHeaderCallbackWrapper(
        stream,
        http2::FrameType::EX_HEADERS,
        http2::writeExHeaders((uint8_t*)frameHeader.first,
                              frameHeader.second,
                              writeBuf,
                              chunkLen,
                              stream,
                              *exAttributes,
                              pri,
                              http2::kNoPadding,
                              eom,
                              endHeaders));
  } else {
    generateHeaderCallbackWrapper(
        stream,
        http2::FrameType::HEADERS,
        http2::writeHeaders((uint8_t*)frameHeader.first,
                            frameHeader.second,
                            writeBuf,
                            chunkLen,
                            stream,
                            pri,
                            http2::kNoPadding,
                            eom,
                            endHeaders));
  }

  if (!endHeaders) {
    generateContinuation(
        writeBuf, queue, assocStream ? *assocStream : stream, maxFrameSize);
  }
}