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);
}
}