diff options
author | 2022-12-02 07:40:22 -0800 | |
---|---|---|
committer | 2022-12-02 07:42:44 -0800 | |
commit | d84f79bcc16d4e748c8a9400ea1cdb03d7f963fb (patch) | |
tree | 876d0a65d75c0f6aec97038e0d9f89c09f915c3f /src/bun.js/bindings/webcore/HTTPHeaderMap.cpp | |
parent | 917cbc8d5d0ea9446db66910be46b7fff4697304 (diff) | |
download | bun-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.cpp | 82 |
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; }); |