diff options
Diffstat (limited to 'src/bun.js/bindings/webcore/FetchHeaders.cpp')
-rw-r--r-- | src/bun.js/bindings/webcore/FetchHeaders.cpp | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/src/bun.js/bindings/webcore/FetchHeaders.cpp b/src/bun.js/bindings/webcore/FetchHeaders.cpp index 713b8a6ac..7834836c7 100644 --- a/src/bun.js/bindings/webcore/FetchHeaders.cpp +++ b/src/bun.js/bindings/webcore/FetchHeaders.cpp @@ -39,6 +39,18 @@ static void removePrivilegedNoCORSRequestHeaders(HTTPHeaderMap& headers) headers.remove(HTTPHeaderName::Range); } +static ExceptionOr<bool> canWriteHeader(const HTTPHeaderName name, const String& value, const String& combinedValue, FetchHeaders::Guard guard) +{ + ASSERT(value.isEmpty() || (!isHTTPSpace(value[0]) && !isHTTPSpace(value[value.length() - 1]))); + if (!isValidHTTPHeaderValue((value))) + return Exception { TypeError, makeString("Header '", name, "' has invalid value: '", value, "'") }; + if (guard == FetchHeaders::Guard::Immutable) + return Exception { TypeError, "Headers object's guard is 'immutable'"_s }; + if (guard == FetchHeaders::Guard::RequestNoCors && !combinedValue.isEmpty()) + return false; + return true; +} + static ExceptionOr<bool> canWriteHeader(const String& name, const String& value, const String& combinedValue, FetchHeaders::Guard guard) { if (!isValidHTTPToken(name)) @@ -61,6 +73,31 @@ static ExceptionOr<void> appendToHeaderMap(const String& name, const String& val { String normalizedValue = stripLeadingAndTrailingHTTPSpaces(value); String combinedValue = normalizedValue; + HTTPHeaderName headerName; + if (findHTTPHeaderName(name, headerName)) { + + if (headerName != HTTPHeaderName::SetCookie) { + if (headers.contains(headerName)) { + combinedValue = makeString(headers.get(headerName), ", ", normalizedValue); + } + } + + auto canWriteResult = canWriteHeader(headerName, normalizedValue, combinedValue, guard); + + if (canWriteResult.hasException()) + return canWriteResult.releaseException(); + if (!canWriteResult.releaseReturnValue()) + return {}; + + if (headerName != HTTPHeaderName::SetCookie) { + headers.set(headerName, combinedValue); + } else { + headers.add(headerName, normalizedValue); + } + + return {}; + } + if (headers.contains(name)) combinedValue = makeString(headers.get(name), ", ", normalizedValue); auto canWriteResult = canWriteHeader(name, normalizedValue, combinedValue, guard); @@ -222,28 +259,42 @@ void FetchHeaders::filterAndFill(const HTTPHeaderMap& headers, Guard guard) } } +static NeverDestroyed<const String> setCookieLowercaseString(MAKE_STATIC_STRING_IMPL("set-cookie")); + std::optional<KeyValuePair<String, String>> FetchHeaders::Iterator::next() { if (m_keys.isEmpty() || m_updateCounter != m_headers->m_updateCounter) { m_keys.resize(0); m_keys.reserveCapacity(m_headers->m_headers.size()); for (auto& header : m_headers->m_headers) - m_keys.uncheckedAppend(header.key.convertToASCIILowercase()); + m_keys.uncheckedAppend(header.asciiLowerCaseName()); std::sort(m_keys.begin(), m_keys.end(), WTF::codePointCompareLessThan); m_updateCounter = m_headers->m_updateCounter; + m_cookieIndex = 0; } + + auto& setCookieHeaders = m_headers->m_headers.getSetCookieHeaders(); + while (m_currentIndex < m_keys.size()) { auto key = m_keys[m_currentIndex++]; + + if (!setCookieHeaders.isEmpty() && key == setCookieLowercaseString) { + auto cookie = setCookieHeaders[m_cookieIndex++]; + return KeyValuePair<String, String> { WTFMove(key), WTFMove(cookie) }; + } + auto value = m_headers->m_headers.get(key); if (!value.isNull()) return KeyValuePair<String, String> { WTFMove(key), WTFMove(value) }; } + return std::nullopt; } FetchHeaders::Iterator::Iterator(FetchHeaders& headers) : m_headers(headers) { + m_cookieIndex = 0; } } // namespace WebCore |