11#include " headers.h"
2-
2+ // Turning off clang-tidy for this file due to issues it appears to have with
3+ // the simd intrinsics...
4+ // NOLINTBEGIN
5+ #include " simdutf.h"
36#include " util.h"
47
58#include < workerd/io/features.h>
@@ -70,14 +73,6 @@ constexpr size_t MAX_COMMON_HEADER_ID =
7073// and must be kept in sync with the ordinal values defined in http-over-capnp.capnp). Since
7174// it is extremely unlikely that those will change often, we hardcode them here for runtime
7275// efficiency.
73- //
74- // TODO(perf): We can potentially optimize this further by using the mechanisms within
75- // http-over-capnp, which also has a mapping of common header names to kj::HttpHeaderIds.
76- // However, accessing that functionality requires some amount of new API to be added to
77- // capnproto which needs to be carefully weighed. There's also the fact that, currently,
78- // the HttpOverCapnpFactory is accessed via IoContext and the Headers object can be
79- // created outside of an IoContext. Some amount of additional refactoring would be needed
80- // to make it work. For now, this hardcoded table is sufficient and efficient enough.
8176#define V (Name ) Name##_kj,
8277constexpr kj::StringPtr COMMON_HEADER_NAMES[] = {nullptr , // 0: invalid
8378 COMMON_HEADERS (V)};
@@ -164,16 +159,6 @@ static_assert(HEADER_HASH_TABLE.find("AcCePt-ChArSeT"_kj) == 1);
164159
165160static_assert (std::size(COMMON_HEADER_NAMES) == (MAX_COMMON_HEADER_ID + 1 ));
166161
167- inline constexpr void requireValidHeaderName (kj::StringPtr name) {
168- if (HEADER_HASH_TABLE.find (name) != 0 ) {
169- // Known common header, always valid
170- return ;
171- }
172- for (char c: name) {
173- JSG_REQUIRE (util::isHttpTokenChar (c), TypeError, " Invalid header name." );
174- }
175- }
176-
177162void maybeWarnIfBadHeaderString (kj::StringPtr str) {
178163 if (IoContext::hasCurrent ()) {
179164 auto & context = IoContext::current ();
@@ -241,6 +226,10 @@ constexpr Headers::HeaderKey getHeaderKeyFor(kj::StringPtr name) {
241226 return commonId;
242227 }
243228
229+ for (char c: name) {
230+ JSG_REQUIRE (util::isHttpTokenChar (c), TypeError, " Invalid header name." );
231+ }
232+
244233 // Not a common header, so allocate lowercase copy for uncommon header
245234 return toLower (name);
246235}
@@ -336,6 +325,9 @@ Headers::Headers(jsg::Lock& js, const Headers& other): guard(Guard::NONE) {
336325
337326Headers::Headers (jsg::Lock& js, const kj::HttpHeaders& other, Guard guard): guard(Guard::NONE) {
338327 headers.reserve (other.size ());
328+ // TODO(perf): Once kj::HttpHeaders supports an API for getting the CommonHeaderName directly
329+ // from the headers, we can optimize this to avoid looking up the common header IDs again,
330+ // making this constructor more efficient when copying common headers from kj::HttpHeaders.
339331 other.forEach ([this , &js](auto name, auto value) {
340332 // We have to copy the strings here but we can avoid normalizing and validating since
341333 // they presumably already went through that process when they were added to the
@@ -355,6 +347,8 @@ jsg::Ref<Headers> Headers::clone(jsg::Lock& js) const {
355347// Fill in the given HttpHeaders with these headers. Note that strings are inserted by
356348// reference, so the output must be consumed immediately.
357349void Headers::shallowCopyTo (kj::HttpHeaders& out) {
350+ // TODO(perf): Once kj::HttpHeaders supports an API for setting headers by CommonHeaderName,
351+ // we can optimize this to avoid the additional lookup of the header name and use of addPtrPtr.
358352 for (auto & entry: headers) {
359353 for (auto & value: entry.values ) {
360354 out.addPtrPtr (entry.getHeaderName (), value);
@@ -463,8 +457,7 @@ jsg::Ref<Headers> Headers::constructor(jsg::Lock& js, jsg::Optional<Initializer>
463457}
464458
465459kj::Maybe<kj::String> Headers::get (jsg::Lock& js, kj::String name) {
466- requireValidHeaderName (name);
467- return getUnguarded (js, name.asPtr ());
460+ return getUnguarded (js, name);
468461}
469462
470463kj::Maybe<kj::String> Headers::getUnguarded (jsg::Lock&, kj::StringPtr name) {
@@ -490,8 +483,6 @@ kj::Array<kj::StringPtr> Headers::getSetCookie() {
490483}
491484
492485kj::Array<kj::StringPtr> Headers::getAll (kj::String name) {
493- requireValidHeaderName (name);
494-
495486 if (!strcaseeq (name, " set-cookie" _kj)) {
496487 JSG_FAIL_REQUIRE (TypeError, " getAll() can only be used with the header name \" Set-Cookie\" ." );
497488 }
@@ -503,7 +494,6 @@ kj::Array<kj::StringPtr> Headers::getAll(kj::String name) {
503494}
504495
505496bool Headers::has (kj::String name) {
506- requireValidHeaderName (name);
507497 return headers.find (getHeaderKeyFor (name)) != kj::none;
508498}
509499
@@ -514,7 +504,6 @@ bool Headers::hasCommon(capnp::CommonHeaderName idx) {
514504
515505void Headers::set (jsg::Lock& js, kj::String name, kj::String value) {
516506 checkGuard ();
517- requireValidHeaderName (name);
518507 setUnguarded (js, kj::mv (name), normalizeHeaderValue (kj::mv (value)));
519508}
520509
@@ -542,7 +531,6 @@ void Headers::setCommon(capnp::CommonHeaderName idx, kj::String value) {
542531
543532void Headers::append (jsg::Lock& js, kj::String name, kj::String value) {
544533 checkGuard ();
545- requireValidHeaderName (name);
546534 appendUnguarded (js, kj::mv (name), normalizeHeaderValue (kj::mv (value)));
547535}
548536
@@ -561,7 +549,6 @@ void Headers::appendUnguarded(jsg::Lock& js, kj::String name, kj::String value)
561549
562550void Headers::delete_ (kj::String name) {
563551 checkGuard ();
564- requireValidHeaderName (name);
565552 headers.eraseMatch (getHeaderKeyFor (name));
566553}
567554
@@ -741,3 +728,4 @@ jsg::Ref<Headers> Headers::deserialize(
741728}
742729
743730} // namespace workerd::api
731+ // NOLINTEND
0 commit comments