Commit 1a8b95d1 authored by Harris Hancock's avatar Harris Hancock

Expose CONNECTION_HEADERS_COUNT in http.h

To safely use HttpHeaders::serialize*() with overridden connection-level headers, dependent code must stay up-to-date with any changes in the builtin header list. We now expose CONNECTION_HEADERS_COUNT and its friends to facilitate this.
parent 569879b2
...@@ -477,26 +477,14 @@ static const char* BUILTIN_HEADER_NAMES[] = { ...@@ -477,26 +477,14 @@ static const char* BUILTIN_HEADER_NAMES[] = {
#undef HEADER_NAME #undef HEADER_NAME
}; };
enum class BuiltinHeaderIndicesEnum { } // namespace
#define HEADER_ID(id, name) id,
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID)
#undef HEADER_ID
};
namespace BuiltinHeaderIndices { #define HEADER_ID(id, name) constexpr uint HttpHeaders::BuiltinIndices::id;
#define HEADER_ID(id, name) constexpr uint id = static_cast<uint>(BuiltinHeaderIndicesEnum::id);
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID) KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID)
#undef HEADER_ID #undef HEADER_ID
};
constexpr uint HEAD_RESPONSE_CONNECTION_HEADERS_COUNT = BuiltinHeaderIndices::CONTENT_LENGTH;
constexpr uint CONNECTION_HEADERS_COUNT = BuiltinHeaderIndices::SEC_WEBSOCKET_KEY;
constexpr uint WEBSOCKET_CONNECTION_HEADERS_COUNT = BuiltinHeaderIndices::HOST;
} // namespace
#define DEFINE_HEADER(id, name) \ #define DEFINE_HEADER(id, name) \
const HttpHeaderId HttpHeaderId::id(nullptr, BuiltinHeaderIndices::id); const HttpHeaderId HttpHeaderId::id(nullptr, HttpHeaders::BuiltinIndices::id);
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DEFINE_HEADER) KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DEFINE_HEADER)
#undef DEFINE_HEADER #undef DEFINE_HEADER
...@@ -560,7 +548,7 @@ HttpHeaderTable::HttpHeaderTable() ...@@ -560,7 +548,7 @@ HttpHeaderTable::HttpHeaderTable()
: idsByName(kj::heap<IdsByNameMap>()) { : idsByName(kj::heap<IdsByNameMap>()) {
#define ADD_HEADER(id, name) \ #define ADD_HEADER(id, name) \
namesById.add(name); \ namesById.add(name); \
idsByName->map.insert(std::make_pair(name, BuiltinHeaderIndices::id)); idsByName->map.insert(std::make_pair(name, HttpHeaders::BuiltinIndices::id));
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(ADD_HEADER); KJ_HTTP_FOR_EACH_BUILTIN_HEADER(ADD_HEADER);
#undef ADD_HEADER #undef ADD_HEADER
} }
...@@ -3023,7 +3011,7 @@ public: ...@@ -3023,7 +3011,7 @@ public:
"can't start new request until previous request body has been fully written"); "can't start new request until previous request body has been fully written");
closeWatcherTask = nullptr; closeWatcherTask = nullptr;
kj::StringPtr connectionHeaders[CONNECTION_HEADERS_COUNT]; kj::StringPtr connectionHeaders[HttpHeaders::CONNECTION_HEADERS_COUNT];
kj::String lengthStr; kj::String lengthStr;
bool isGet = method == HttpMethod::GET || method == HttpMethod::HEAD; bool isGet = method == HttpMethod::GET || method == HttpMethod::HEAD;
...@@ -3035,7 +3023,7 @@ public: ...@@ -3035,7 +3023,7 @@ public:
hasBody = false; hasBody = false;
} else { } else {
lengthStr = kj::str(*s); lengthStr = kj::str(*s);
connectionHeaders[BuiltinHeaderIndices::CONTENT_LENGTH] = lengthStr; connectionHeaders[HttpHeaders::BuiltinIndices::CONTENT_LENGTH] = lengthStr;
hasBody = true; hasBody = true;
} }
} else { } else {
...@@ -3048,7 +3036,7 @@ public: ...@@ -3048,7 +3036,7 @@ public:
// actually want to send a body. This allows pass-through of a GET request with a chunked // actually want to send a body. This allows pass-through of a GET request with a chunked
// body to "just work". We strongly discourage writing any new code that sends // body to "just work". We strongly discourage writing any new code that sends
// full-bodied GETs. // full-bodied GETs.
connectionHeaders[BuiltinHeaderIndices::TRANSFER_ENCODING] = "chunked"; connectionHeaders[HttpHeaders::BuiltinIndices::TRANSFER_ENCODING] = "chunked";
hasBody = true; hasBody = true;
} }
} }
...@@ -3118,11 +3106,11 @@ public: ...@@ -3118,11 +3106,11 @@ public:
"HttpClient").generate(keyBytes); "HttpClient").generate(keyBytes);
auto keyBase64 = kj::encodeBase64(keyBytes); auto keyBase64 = kj::encodeBase64(keyBytes);
kj::StringPtr connectionHeaders[WEBSOCKET_CONNECTION_HEADERS_COUNT]; kj::StringPtr connectionHeaders[HttpHeaders::WEBSOCKET_CONNECTION_HEADERS_COUNT];
connectionHeaders[BuiltinHeaderIndices::CONNECTION] = "Upgrade"; connectionHeaders[HttpHeaders::BuiltinIndices::CONNECTION] = "Upgrade";
connectionHeaders[BuiltinHeaderIndices::UPGRADE] = "websocket"; connectionHeaders[HttpHeaders::BuiltinIndices::UPGRADE] = "websocket";
connectionHeaders[BuiltinHeaderIndices::SEC_WEBSOCKET_VERSION] = "13"; connectionHeaders[HttpHeaders::BuiltinIndices::SEC_WEBSOCKET_VERSION] = "13";
connectionHeaders[BuiltinHeaderIndices::SEC_WEBSOCKET_KEY] = keyBase64; connectionHeaders[HttpHeaders::BuiltinIndices::SEC_WEBSOCKET_KEY] = keyBase64;
httpOutput.writeHeaders(headers.serializeRequest(HttpMethod::GET, url, connectionHeaders)); httpOutput.writeHeaders(headers.serializeRequest(HttpMethod::GET, url, connectionHeaders));
...@@ -4338,16 +4326,16 @@ private: ...@@ -4338,16 +4326,16 @@ private:
auto method = KJ_REQUIRE_NONNULL(currentMethod, "already called send()"); auto method = KJ_REQUIRE_NONNULL(currentMethod, "already called send()");
currentMethod = nullptr; currentMethod = nullptr;
kj::StringPtr connectionHeaders[CONNECTION_HEADERS_COUNT]; kj::StringPtr connectionHeaders[HttpHeaders::CONNECTION_HEADERS_COUNT];
kj::String lengthStr; kj::String lengthStr;
if (statusCode == 204 || statusCode == 205 || statusCode == 304) { if (statusCode == 204 || statusCode == 205 || statusCode == 304) {
// No entity-body. // No entity-body.
} else KJ_IF_MAYBE(s, expectedBodySize) { } else KJ_IF_MAYBE(s, expectedBodySize) {
lengthStr = kj::str(*s); lengthStr = kj::str(*s);
connectionHeaders[BuiltinHeaderIndices::CONTENT_LENGTH] = lengthStr; connectionHeaders[HttpHeaders::BuiltinIndices::CONTENT_LENGTH] = lengthStr;
} else { } else {
connectionHeaders[BuiltinHeaderIndices::TRANSFER_ENCODING] = "chunked"; connectionHeaders[HttpHeaders::BuiltinIndices::TRANSFER_ENCODING] = "chunked";
} }
// For HEAD requests, if the application specified a Content-Length or Transfer-Encoding // For HEAD requests, if the application specified a Content-Length or Transfer-Encoding
...@@ -4357,7 +4345,7 @@ private: ...@@ -4357,7 +4345,7 @@ private:
if (headers.get(HttpHeaderId::CONTENT_LENGTH) != nullptr || if (headers.get(HttpHeaderId::CONTENT_LENGTH) != nullptr ||
headers.get(HttpHeaderId::TRANSFER_ENCODING) != nullptr) { headers.get(HttpHeaderId::TRANSFER_ENCODING) != nullptr) {
connectionHeadersArray = connectionHeadersArray connectionHeadersArray = connectionHeadersArray
.slice(0, HEAD_RESPONSE_CONNECTION_HEADERS_COUNT); .slice(0, HttpHeaders::HEAD_RESPONSE_CONNECTION_HEADERS_COUNT);
} }
} }
...@@ -4408,10 +4396,10 @@ private: ...@@ -4408,10 +4396,10 @@ private:
auto websocketAccept = generateWebSocketAccept(key); auto websocketAccept = generateWebSocketAccept(key);
kj::StringPtr connectionHeaders[WEBSOCKET_CONNECTION_HEADERS_COUNT]; kj::StringPtr connectionHeaders[HttpHeaders::WEBSOCKET_CONNECTION_HEADERS_COUNT];
connectionHeaders[BuiltinHeaderIndices::SEC_WEBSOCKET_ACCEPT] = websocketAccept; connectionHeaders[HttpHeaders::BuiltinIndices::SEC_WEBSOCKET_ACCEPT] = websocketAccept;
connectionHeaders[BuiltinHeaderIndices::UPGRADE] = "websocket"; connectionHeaders[HttpHeaders::BuiltinIndices::UPGRADE] = "websocket";
connectionHeaders[BuiltinHeaderIndices::CONNECTION] = "Upgrade"; connectionHeaders[HttpHeaders::BuiltinIndices::CONNECTION] = "Upgrade";
httpOutput.writeHeaders(headers.serializeResponse( httpOutput.writeHeaders(headers.serializeResponse(
101, "Switching Protocols", connectionHeaders)); 101, "Switching Protocols", connectionHeaders));
......
...@@ -336,12 +336,33 @@ public: ...@@ -336,12 +336,33 @@ public:
kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const; kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const;
kj::String serializeResponse(uint statusCode, kj::StringPtr statusText, kj::String serializeResponse(uint statusCode, kj::StringPtr statusText,
kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const; kj::ArrayPtr<const kj::StringPtr> connectionHeaders = nullptr) const;
// **Most applications will not use these methods; they are called by the HTTP client and server
// implementations.**
//
// Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines // Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines
// and includes the double-newline to indicate the end of the headers. // and includes the double-newline to indicate the end of the headers.
// //
// `connectionHeaders`, if provided, contains connection-level headers supplied by the HTTP // `connectionHeaders`, if provided, contains connection-level headers supplied by the HTTP
// implementation, in the order specified by the KJ_HTTP_FOR_EACH_BUILTIN_HEADER macro. These // implementation, in the order specified by the KJ_HTTP_FOR_EACH_BUILTIN_HEADER macro. These
// headers values override any corresponding header value in the HttpHeaders object. // headers values override any corresponding header value in the HttpHeaders object. The
// CONNECTION_HEADERS_COUNT constants below can help you construct this `connectionHeaders` array.
enum class BuiltinIndicesEnum {
#define HEADER_ID(id, name) id,
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID)
#undef HEADER_ID
};
struct BuiltinIndices {
#define HEADER_ID(id, name) static constexpr uint id = static_cast<uint>(BuiltinIndicesEnum::id);
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID)
#undef HEADER_ID
};
static constexpr uint HEAD_RESPONSE_CONNECTION_HEADERS_COUNT = BuiltinIndices::CONTENT_LENGTH;
static constexpr uint CONNECTION_HEADERS_COUNT = BuiltinIndices::SEC_WEBSOCKET_KEY;
static constexpr uint WEBSOCKET_CONNECTION_HEADERS_COUNT = BuiltinIndices::HOST;
// Constants for use with HttpHeaders::serialize*().
kj::String toString() const; kj::String toString() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment