aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/webcore/FetchHeaders.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/bindings/webcore/FetchHeaders.cpp')
-rw-r--r--src/bun.js/bindings/webcore/FetchHeaders.cpp53
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