mirror of
https://github.com/oven-sh/bun
synced 2026-02-18 06:41:50 +00:00
fix(http): preserve original header name casing in Node.js HTTP server
When using `res.setHeader('location', ...)` in Bun's Node.js-compatible HTTP
server, the header was being sent as `Location` (title-case) instead of
preserving the original lowercase `location`. This is because known HTTP
headers were being normalized to enum values, losing the original casing.
The fix adds an `originalName` field to `CommonHeader` that stores the
original header name when set via the Node.js HTTP API. When writing
response headers, the original name is used if available, otherwise
falling back to the default casing.
This makes Bun's behavior match Node.js, which preserves the original
casing of header names set via `setHeader()`.
Fixes #15578
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -128,6 +128,31 @@ void HTTPHeaderMap::set(const String& name, const String& value)
|
||||
setUncommonHeader(name, value);
|
||||
}
|
||||
|
||||
void HTTPHeaderMap::setPreservingOriginalName(const String& name, const String& value)
|
||||
{
|
||||
HTTPHeaderName headerName;
|
||||
if (findHTTPHeaderName(name, headerName)) {
|
||||
if (headerName == HTTPHeaderName::SetCookie) {
|
||||
m_setCookieHeaders.clear();
|
||||
m_setCookieHeaders.append(value);
|
||||
return;
|
||||
}
|
||||
|
||||
auto index = m_commonHeaders.findIf([&](auto& header) {
|
||||
return header.key == headerName;
|
||||
});
|
||||
if (index == notFound)
|
||||
m_commonHeaders.append(CommonHeader { headerName, value, name });
|
||||
else {
|
||||
m_commonHeaders[index].value = value;
|
||||
m_commonHeaders[index].originalName = name;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setUncommonHeader(name, value);
|
||||
}
|
||||
|
||||
void HTTPHeaderMap::setUncommonHeader(const String& name, const String& value)
|
||||
{
|
||||
auto index = m_uncommonHeaders.findIf([&](auto& header) {
|
||||
@@ -178,7 +203,7 @@ void HTTPHeaderMap::append(const String& name, const String& value)
|
||||
if (headerName == HTTPHeaderName::SetCookie)
|
||||
m_setCookieHeaders.append(value);
|
||||
else
|
||||
m_commonHeaders.append(CommonHeader { headerName, value });
|
||||
m_commonHeaders.append(CommonHeader { headerName, value, String() });
|
||||
} else {
|
||||
m_uncommonHeaders.append(UncommonHeader { name, value });
|
||||
}
|
||||
@@ -189,7 +214,7 @@ bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& val
|
||||
if (contains(headerName))
|
||||
return false;
|
||||
|
||||
m_commonHeaders.append(CommonHeader { headerName, value });
|
||||
m_commonHeaders.append(CommonHeader { headerName, value, String() });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -290,7 +315,7 @@ void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
|
||||
return header.key == name;
|
||||
});
|
||||
if (index == notFound)
|
||||
m_commonHeaders.append(CommonHeader { name, value });
|
||||
m_commonHeaders.append(CommonHeader { name, value, String() });
|
||||
else
|
||||
m_commonHeaders[index].value = value;
|
||||
}
|
||||
@@ -344,7 +369,7 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
|
||||
if (index != notFound)
|
||||
m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, name == HTTPHeaderName::Cookie ? "; "_s : ", "_s, value);
|
||||
else
|
||||
m_commonHeaders.append(CommonHeader { name, value });
|
||||
m_commonHeaders.append(CommonHeader { name, value, String() });
|
||||
}
|
||||
|
||||
} // namespace WebCore
|
||||
|
||||
Reference in New Issue
Block a user