void HPACKCodec::encodeHTTP()

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