in proxygen/lib/http/codec/compress/HPACKCodec.cpp [70:151]
void HPACKCodec::encodeHTTP(
const HTTPMessage& msg,
folly::IOBufQueue& writeBuf,
bool includeDate,
const folly::Optional<HTTPHeaders>& extraHeaders) noexcept {
auto prevSize = writeBuf.chainLength();
encoder_.startEncode(writeBuf);
auto uncompressed = 0;
if (msg.isRequest()) {
if (msg.isEgressWebsocketUpgrade()) {
uncompressed += encoder_.encodeHeader(
HTTP_HEADER_COLON_METHOD, methodToString(HTTPMethod::CONNECT));
uncompressed += encoder_.encodeHeader(HTTP_HEADER_COLON_PROTOCOL,
headers::kWebsocketString);
} else {
uncompressed += encoder_.encodeHeader(HTTP_HEADER_COLON_METHOD,
msg.getMethodString());
}
if (msg.getMethod() != HTTPMethod::CONNECT ||
msg.isEgressWebsocketUpgrade()) {
uncompressed +=
encoder_.encodeHeader(HTTP_HEADER_COLON_SCHEME, msg.getScheme());
uncompressed +=
encoder_.encodeHeader(HTTP_HEADER_COLON_PATH, msg.getURL());
}
const HTTPHeaders& headers = msg.getHeaders();
const std::string& host = headers.getSingleOrEmpty(HTTP_HEADER_HOST);
uncompressed += encoder_.encodeHeader(HTTP_HEADER_COLON_AUTHORITY, host);
} else {
if (msg.isEgressWebsocketUpgrade()) {
uncompressed +=
encoder_.encodeHeader(HTTP_HEADER_COLON_STATUS, headers::kStatus200);
} else {
uncompressed += encoder_.encodeHeader(
HTTP_HEADER_COLON_STATUS,
folly::to<folly::fbstring>(msg.getStatusCode()));
}
// HEADERS frames do not include a version or reason string.
}
bool hasDateHeader = false;
// Add the HTTP headers supplied by the caller, but skip
// any per-hop headers that aren't supported in HTTP/2.
auto headerEncodeHelper = [&](HTTPHeaderCode code,
const std::string& name,
const std::string& value) {
if (CodecUtil::perHopHeaderCodes()[code] || name.empty() ||
name[0] == ':') {
DCHECK(!name.empty()) << "Empty header";
DCHECK_NE(name[0], ':') << "Invalid header=" << name;
return;
}
// Note this code will not drop headers named by Connection. That's the
// caller's job
// see HTTP/2 spec, 8.1.2
DCHECK(name != "TE" || value == "trailers");
if ((!name.empty() && name[0] != ':') && code != HTTP_HEADER_HOST) {
if (code == HTTP_HEADER_OTHER) {
uncompressed += encoder_.encodeHeader(name, value);
} else {
uncompressed += encoder_.encodeHeader(code, value);
}
}
hasDateHeader |= ((code == HTTP_HEADER_DATE) ? 1 : 0);
};
msg.getHeaders().forEachWithCode(headerEncodeHelper);
if (extraHeaders) {
extraHeaders->forEachWithCode(headerEncodeHelper);
}
if (includeDate && msg.isResponse() && !hasDateHeader) {
uncompressed += encoder_.encodeHeader(HTTP_HEADER_DATE,
HTTPMessage::formatDateHeader());
}
encoder_.completeEncode();
encodedSize_.uncompressed = uncompressed;
recordCompressedSize(writeBuf.chainLength() - prevSize);
}