aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-02 07:40:22 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-02 07:42:44 -0800
commitd84f79bcc16d4e748c8a9400ea1cdb03d7f963fb (patch)
tree876d0a65d75c0f6aec97038e0d9f89c09f915c3f /src/bun.js/bindings/webcore/HTTPHeaderMap.cpp
parent917cbc8d5d0ea9446db66910be46b7fff4697304 (diff)
downloadbun-d84f79bcc16d4e748c8a9400ea1cdb03d7f963fb.tar.gz
bun-d84f79bcc16d4e748c8a9400ea1cdb03d7f963fb.tar.zst
bun-d84f79bcc16d4e748c8a9400ea1cdb03d7f963fb.zip
[fetch] Implement `Headers#getAll` and `Headers#getSetCookie()`
This matches Deno's behavior (get() combines, iterator preserves the order, set and append combine), but implements both the Cloudflare Workers `getAll()` and the potential standard `getSetCookie` function. The rationale for choosing both is to better support libraries which check for `getAll` and also because `getSetCookie` seems a little confusing (names are hard) This also makes `.toJSON` and JSON.stringify return an array for `Set-Cookie`
Diffstat (limited to 'src/bun.js/bindings/webcore/HTTPHeaderMap.cpp')
-rw-r--r--src/bun.js/bindings/webcore/HTTPHeaderMap.cpp82
1 files changed, 78 insertions, 4 deletions
diff --git a/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp b/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp
index 383b0a85f..580a171d3 100644
--- a/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp
+++ b/src/bun.js/bindings/webcore/HTTPHeaderMap.cpp
@@ -36,17 +36,26 @@
#include <wtf/CrossThreadCopier.h>
#include <wtf/text/StringView.h>
+static StringView extractCookieName(const StringView& cookie)
+{
+ auto nameEnd = cookie.find('=');
+ if (nameEnd == notFound)
+ return String();
+ return cookie.substring(0, nameEnd);
+}
+
namespace WebCore {
HTTPHeaderMap::HTTPHeaderMap()
{
}
-HTTPHeaderMap HTTPHeaderMap::isolatedCopy() const &
+HTTPHeaderMap HTTPHeaderMap::isolatedCopy() const&
{
HTTPHeaderMap map;
map.m_commonHeaders = crossThreadCopy(m_commonHeaders);
map.m_uncommonHeaders = crossThreadCopy(m_uncommonHeaders);
+ map.m_setCookieHeaders = crossThreadCopy(m_setCookieHeaders);
return map;
}
@@ -55,6 +64,7 @@ HTTPHeaderMap HTTPHeaderMap::isolatedCopy() &&
HTTPHeaderMap map;
map.m_commonHeaders = crossThreadCopy(WTFMove(m_commonHeaders));
map.m_uncommonHeaders = crossThreadCopy(WTFMove(m_uncommonHeaders));
+ map.m_setCookieHeaders = crossThreadCopy(WTFMove(m_setCookieHeaders));
return map;
}
@@ -153,10 +163,14 @@ void HTTPHeaderMap::append(const String& name, const String& value)
ASSERT(!contains(name));
HTTPHeaderName headerName;
- if (findHTTPHeaderName(name, headerName))
- m_commonHeaders.append(CommonHeader { headerName, value });
- else
+ if (findHTTPHeaderName(name, headerName)) {
+ if (headerName == HTTPHeaderName::SetCookie)
+ m_setCookieHeaders.append(value);
+ else
+ m_commonHeaders.append(CommonHeader { headerName, value });
+ } else {
m_uncommonHeaders.append(UncommonHeader { name, value });
+ }
}
bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& value)
@@ -181,6 +195,7 @@ bool HTTPHeaderMap::contains(const String& name) const
bool HTTPHeaderMap::remove(const String& name)
{
+
HTTPHeaderName headerName;
if (findHTTPHeaderName(name, headerName))
return remove(headerName);
@@ -192,6 +207,26 @@ bool HTTPHeaderMap::remove(const String& name)
String HTTPHeaderMap::get(HTTPHeaderName name) const
{
+ if (name == HTTPHeaderName::SetCookie) {
+ unsigned count = m_setCookieHeaders.size();
+ switch (count) {
+ case 0:
+ return String();
+ case 1:
+ return m_setCookieHeaders[0];
+ default: {
+ StringBuilder builder;
+ builder.reserveCapacity(m_setCookieHeaders[0].length() * count + (count - 1));
+ builder.append(m_setCookieHeaders[0]);
+ for (unsigned i = 1; i < count; ++i) {
+ builder.append(", "_s);
+ builder.append(m_setCookieHeaders[i]);
+ }
+ return builder.toString();
+ }
+ }
+ }
+
auto index = m_commonHeaders.findIf([&](auto& header) {
return header.key == name;
});
@@ -200,6 +235,20 @@ String HTTPHeaderMap::get(HTTPHeaderName name) const
void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
{
+ if (name == HTTPHeaderName::SetCookie) {
+ auto cookieName = extractCookieName(value);
+ size_t length = m_setCookieHeaders.size();
+ const auto& cookies = m_setCookieHeaders.data();
+ for (size_t i = 0; i < length; ++i) {
+ if (extractCookieName(cookies[i]) == cookieName) {
+ m_setCookieHeaders[i] = value;
+ return;
+ }
+ }
+ m_setCookieHeaders.append(value);
+ return;
+ }
+
auto index = m_commonHeaders.findIf([&](auto& header) {
return header.key == name;
});
@@ -211,6 +260,9 @@ void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
bool HTTPHeaderMap::contains(HTTPHeaderName name) const
{
+ if (name == HTTPHeaderName::SetCookie)
+ return !m_setCookieHeaders.isEmpty();
+
return m_commonHeaders.findIf([&](auto& header) {
return header.key == name;
}) != notFound;
@@ -218,6 +270,12 @@ bool HTTPHeaderMap::contains(HTTPHeaderName name) const
bool HTTPHeaderMap::remove(HTTPHeaderName name)
{
+ if (name == HTTPHeaderName::SetCookie) {
+ bool any = m_setCookieHeaders.size() > 0;
+ m_setCookieHeaders.clear();
+ return any;
+ }
+
return m_commonHeaders.removeFirstMatching([&](auto& header) {
return header.key == name;
});
@@ -225,6 +283,22 @@ bool HTTPHeaderMap::remove(HTTPHeaderName name)
void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
{
+ if (name == HTTPHeaderName::SetCookie) {
+ auto cookieName = extractCookieName(value);
+
+ size_t length = m_setCookieHeaders.size();
+ const auto& cookies = m_setCookieHeaders.data();
+ for (size_t i = 0; i < length; ++i) {
+ if (extractCookieName(cookies[i]) == cookieName) {
+ m_setCookieHeaders[i] = value;
+ return;
+ }
+ }
+ m_setCookieHeaders.append(value);
+
+ return;
+ }
+
auto index = m_commonHeaders.findIf([&](auto& header) {
return header.key == name;
});