summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoonchild <mcwerewolf@gmail.com>2018-09-27 00:59:51 +0200
committerGitHub <noreply@github.com>2018-09-27 00:59:51 +0200
commitb92dbaf6a1da5e06e9c0eb818288c0db1b6e45e2 (patch)
tree61462bdb3c34813d3cbd32c87628854a48392cea
parent63875408947b0e5551f41e4de1e0ca44dd970c36 (diff)
parentc5c9445e3adf6b65c98f6810551d7c3d64133134 (diff)
downloaduxp-b92dbaf6a1da5e06e9c0eb818288c0db1b6e45e2.tar.gz
Merge pull request #791 from g4jc/session_supercookie
Issue #792 - backport mozbug 1334776 - CVE-2017-7797 Header name interning leaks across origins
-rw-r--r--devtools/client/netmonitor/filter-predicates.js4
-rw-r--r--devtools/client/netmonitor/test/browser_net_copy_headers.js16
-rw-r--r--devtools/client/netmonitor/test/browser_net_timing-division.js4
-rw-r--r--devtools/client/shared/AppCacheUtils.jsm8
-rw-r--r--devtools/client/shared/curl.js8
-rw-r--r--devtools/client/webconsole/net/test/mochitest/browser_net_headers.js4
-rw-r--r--devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js2
-rw-r--r--devtools/shared/webconsole/test/test_network_get.html8
-rw-r--r--devtools/shared/webconsole/test/test_network_longstring.html4
-rw-r--r--devtools/shared/webconsole/test/test_network_post.html8
-rw-r--r--dom/security/test/cors/test_CrossSiteXHR.html2
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.cpp18
-rw-r--r--netwerk/protocol/http/PHttpChannelParams.h15
-rw-r--r--netwerk/protocol/http/nsHttpHeaderArray.cpp99
-rw-r--r--netwerk/protocol/http/nsHttpHeaderArray.h36
-rw-r--r--netwerk/protocol/http/nsHttpRequestHead.cpp23
-rw-r--r--netwerk/protocol/http/nsHttpRequestHead.h4
-rw-r--r--netwerk/protocol/http/nsHttpResponseHead.cpp50
-rw-r--r--netwerk/protocol/http/nsHttpResponseHead.h6
-rw-r--r--netwerk/test/unit/test_bug1064258.js2
-rw-r--r--netwerk/test/unit/test_original_sent_received_head.js18
21 files changed, 238 insertions, 101 deletions
diff --git a/devtools/client/netmonitor/filter-predicates.js b/devtools/client/netmonitor/filter-predicates.js
index 9c8e49c622..75ee422aad 100644
--- a/devtools/client/netmonitor/filter-predicates.js
+++ b/devtools/client/netmonitor/filter-predicates.js
@@ -72,7 +72,7 @@ function isWS({ requestHeaders, responseHeaders }) {
// Find the 'upgrade' header.
let upgradeHeader = requestHeaders.headers.find(header => {
- return (header.name == "Upgrade");
+ return (header.name.toLowerCase() == "upgrade");
});
// If no header found on request, check response - mainly to get
@@ -81,7 +81,7 @@ function isWS({ requestHeaders, responseHeaders }) {
if (!upgradeHeader && responseHeaders &&
Array.isArray(responseHeaders.headers)) {
upgradeHeader = responseHeaders.headers.find(header => {
- return (header.name == "Upgrade");
+ return (header.name.toLowerCase() == "upgrade");
});
}
diff --git a/devtools/client/netmonitor/test/browser_net_copy_headers.js b/devtools/client/netmonitor/test/browser_net_copy_headers.js
index 36ce2fb347..bb582c8e13 100644
--- a/devtools/client/netmonitor/test/browser_net_copy_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_headers.js
@@ -49,12 +49,12 @@ add_task(function* () {
const EXPECTED_RESPONSE_HEADERS = [
`${httpVersion} ${status} ${statusText}`,
- "Last-Modified: Sun, 3 May 2015 11:11:11 GMT",
- "Content-Type: text/html",
- "Content-Length: 465",
- "Connection: close",
- "Server: httpd.js",
- "Date: Sun, 3 May 2015 11:11:11 GMT"
+ "last-modified: Sun, 3 May 2015 11:11:11 GMT",
+ "content-type: text/html",
+ "content-length: 465",
+ "connection: close",
+ "server: httpd.js",
+ "date: Sun, 3 May 2015 11:11:11 GMT"
].join("\n");
yield waitForClipboardPromise(function setup() {
@@ -62,8 +62,8 @@ add_task(function* () {
}, function validate(result) {
// Fake the "Last-Modified" and "Date" headers because they will vary:
result = String(result)
- .replace(/Last-Modified: [^\n]+ GMT/, "Last-Modified: Sun, 3 May 2015 11:11:11 GMT")
- .replace(/Date: [^\n]+ GMT/, "Date: Sun, 3 May 2015 11:11:11 GMT");
+ .replace(/last-modified: [^\n]+ GMT/, "last-modified: Sun, 3 May 2015 11:11:11 GMT")
+ .replace(/date: [^\n]+ GMT/, "date: Sun, 3 May 2015 11:11:11 GMT");
return result === EXPECTED_RESPONSE_HEADERS;
});
info("Clipboard contains the currently selected item's response headers.");
diff --git a/devtools/client/netmonitor/test/browser_net_timing-division.js b/devtools/client/netmonitor/test/browser_net_timing-division.js
index 0114ba2355..ff2379dc28 100644
--- a/devtools/client/netmonitor/test/browser_net_timing-division.js
+++ b/devtools/client/netmonitor/test/browser_net_timing-division.js
@@ -48,9 +48,9 @@ add_task(function* () {
let lastRequest = RequestsMenu.getItemAtIndex(1);
info("First request happened at: " +
- firstRequest.attachment.responseHeaders.headers.find(e => e.name == "Date").value);
+ firstRequest.attachment.responseHeaders.headers.find(e => e.name == "date").value);
info("Last request happened at: " +
- lastRequest.attachment.responseHeaders.headers.find(e => e.name == "Date").value);
+ lastRequest.attachment.responseHeaders.headers.find(e => e.name == "date").value);
ok(secDivs.length,
"There should be at least one division on the seconds time scale.");
diff --git a/devtools/client/shared/AppCacheUtils.jsm b/devtools/client/shared/AppCacheUtils.jsm
index a2beca993c..9fd4d0541e 100644
--- a/devtools/client/shared/AppCacheUtils.jsm
+++ b/devtools/client/shared/AppCacheUtils.jsm
@@ -86,7 +86,7 @@ AppCacheUtils.prototype = {
_parseManifest: function ACU__parseManifest(uriInfo) {
let deferred = defer();
let manifestName = uriInfo.name;
- let manifestLastModified = new Date(uriInfo.responseHeaders["Last-Modified"]);
+ let manifestLastModified = new Date(uriInfo.responseHeaders["last-modified"]);
if (uriInfo.charset.toLowerCase() != "utf-8") {
this._addError(0, "notUTF8", uriInfo.charset);
@@ -158,7 +158,7 @@ AppCacheUtils.prototype = {
// Check that the resource was not modified after the manifest was last
// modified. If it was then the manifest file should be refreshed.
let resourceLastModified =
- new Date(uriInfo.responseHeaders["Last-Modified"]);
+ new Date(uriInfo.responseHeaders["last-modified"]);
if (manifestLastModified < resourceLastModified) {
this._addError(parsedUri.line, "fileChangedButNotManifest",
@@ -230,12 +230,12 @@ AppCacheUtils.prototype = {
result.requestHeaders = {};
request.visitRequestHeaders(function (header, value) {
- result.requestHeaders[header] = value;
+ result.responseHeaders[header.toLowerCase()] = value;
});
result.responseHeaders = {};
request.visitResponseHeaders(function (header, value) {
- result.responseHeaders[header] = value;
+ result.responseHeaders[header.toLowerCase()] = value;
});
deferred.resolve(result);
diff --git a/devtools/client/shared/curl.js b/devtools/client/shared/curl.js
index 420fe6aa5c..6d33ad9717 100644
--- a/devtools/client/shared/curl.js
+++ b/devtools/client/shared/curl.js
@@ -81,14 +81,14 @@ const Curl = {
postDataText = data.postDataText;
postData.push("--data");
postData.push(escapeString(utils.writePostDataTextParams(postDataText)));
- ignoredHeaders.add("Content-Length");
+ ignoredHeaders.add("content-length");
} else if (multipartRequest) {
postDataText = data.postDataText;
postData.push("--data-binary");
let boundary = utils.getMultipartBoundary(data);
let text = utils.removeBinaryDataFromMultipartText(postDataText, boundary);
postData.push(escapeString(text));
- ignoredHeaders.add("Content-Length");
+ ignoredHeaders.add("content-length");
}
// Add method.
@@ -125,11 +125,11 @@ const Curl = {
}
for (let i = 0; i < headers.length; i++) {
let header = headers[i];
- if (header.name === "Accept-Encoding") {
+ if (header.name.toLowerCase() === "accept-encoding") {
command.push("--compressed");
continue;
}
- if (ignoredHeaders.has(header.name)) {
+ if (ignoredHeaders.has(header.name.toLowerCase())) {
continue;
}
command.push("-H");
diff --git a/devtools/client/webconsole/net/test/mochitest/browser_net_headers.js b/devtools/client/webconsole/net/test/mochitest/browser_net_headers.js
index 4a47074ee1..14cde846c2 100644
--- a/devtools/client/webconsole/net/test/mochitest/browser_net_headers.js
+++ b/devtools/client/webconsole/net/test/mochitest/browser_net_headers.js
@@ -26,11 +26,11 @@ add_task(function* () {
// Select "Headers" tab
let tabBody = yield selectNetInfoTab(hud, netInfoBody, "headers");
let paramName = tabBody.querySelector(
- ".netInfoParamName > span[title='Content-Type']");
+ ".netInfoParamName > span[title='content-type']");
// Verify "Content-Type" header (name and value)
ok(paramName, "Header name must exist");
- is(paramName.textContent, "Content-Type",
+ is(paramName.textContent, "content-type",
"The header name must have proper value");
let paramValue = paramName.parentNode.nextSibling;
diff --git a/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js b/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
index 5097499538..da4bdcf122 100644
--- a/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
+++ b/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
@@ -87,7 +87,7 @@ function getContent() {
function performTest() {
function readHeader(name) {
for (let header of headers) {
- if (header.name == name) {
+ if (header.name.toLowerCase() == name.toLowerCase()) {
return header.value;
}
}
diff --git a/devtools/shared/webconsole/test/test_network_get.html b/devtools/shared/webconsole/test/test_network_get.html
index 710c9b0d75..c2313be12a 100644
--- a/devtools/shared/webconsole/test/test_network_get.html
+++ b/devtools/shared/webconsole/test/test_network_get.html
@@ -196,13 +196,13 @@ function onResponseHeaders(aState, aResponse)
ok(!!aResponse.rawHeaders, "response rawHeaders available");
checkHeadersOrCookies(aResponse.headers, {
- "Content-Type": /^application\/(json|octet-stream)$/,
- "Content-Length": /^\d+$/,
+ "content-type": /^application\/(json|octet-stream)$/,
+ "content-length": /^\d+$/,
});
checkRawHeaders(aResponse.rawHeaders, {
- "Content-Type": /^application\/(json|octet-stream)$/,
- "Content-Length": /^\d+$/,
+ "content-type": /^application\/(json|octet-stream)$/,
+ "content-length": /^\d+$/,
});
onResponseCookies = onResponseCookies.bind(null, aState);
diff --git a/devtools/shared/webconsole/test/test_network_longstring.html b/devtools/shared/webconsole/test/test_network_longstring.html
index d551368969..9e6ea7771b 100644
--- a/devtools/shared/webconsole/test/test_network_longstring.html
+++ b/devtools/shared/webconsole/test/test_network_longstring.html
@@ -212,8 +212,8 @@ function onResponseHeaders(aState, aResponse)
ok(aResponse.headersSize > 0, "response headersSize > 0");
checkHeadersOrCookies(aResponse.headers, {
- "Content-Type": /^application\/(json|octet-stream)$/,
- "Content-Length": /^\d+$/,
+ "content-type": /^application\/(json|octet-stream)$/,
+ "content-length": /^\d+$/,
"x-very-short": "hello world",
"x-very-long": {
"type": "longString",
diff --git a/devtools/shared/webconsole/test/test_network_post.html b/devtools/shared/webconsole/test/test_network_post.html
index d96b9b0b7c..a0b8edb648 100644
--- a/devtools/shared/webconsole/test/test_network_post.html
+++ b/devtools/shared/webconsole/test/test_network_post.html
@@ -204,13 +204,13 @@ function onResponseHeaders(aState, aResponse)
ok(!!aResponse.rawHeaders, "response rawHeaders available");
checkHeadersOrCookies(aResponse.headers, {
- "Content-Type": /^application\/(json|octet-stream)$/,
- "Content-Length": /^\d+$/,
+ "content-type": /^application\/(json|octet-stream)$/,
+ "content-length": /^\d+$/,
});
checkRawHeaders(aResponse.rawHeaders, {
- "Content-Type": /^application\/(json|octet-stream)$/,
- "Content-Length": /^\d+$/,
+ "content-type": /^application\/(json|octet-stream)$/,
+ "content-length": /^\d+$/,
});
onResponseCookies = onResponseCookies.bind(null, aState);
diff --git a/dom/security/test/cors/test_CrossSiteXHR.html b/dom/security/test/cors/test_CrossSiteXHR.html
index b3cda3b871..d9aef5c60c 100644
--- a/dom/security/test/cors/test_CrossSiteXHR.html
+++ b/dom/security/test/cors/test_CrossSiteXHR.html
@@ -743,7 +743,7 @@ function runTest() {
is(res.responseHeaders[header], test.responseHeaders[header],
"|xhr.getResponseHeader()|wrong response header (" + header + ") in test for " +
test.toSource());
- is(res.allResponseHeaders[header], test.responseHeaders[header],
+ is(res.allResponseHeaders[header.toLowerCase()], test.responseHeaders[header],
"|xhr.getAllResponseHeaderss()|wrong response header (" + header + ") in test for " +
test.toSource());
}
diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
index c4e764d26d..03123ceb08 100644
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1665,13 +1665,7 @@ HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
return NS_ERROR_INVALID_ARG;
}
- nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
- if (!atom) {
- NS_WARNING("failed to resolve atom");
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mRequestHead.SetHeader(atom, flatValue, aMerge);
+ return mRequestHead.SetHeader(aHeader, flatValue, aMerge);
}
NS_IMETHODIMP
@@ -1688,13 +1682,7 @@ HttpBaseChannel::SetEmptyRequestHeader(const nsACString& aHeader)
return NS_ERROR_INVALID_ARG;
}
- nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
- if (!atom) {
- NS_WARNING("failed to resolve atom");
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mRequestHead.SetEmptyHeader(atom);
+ return mRequestHead.SetEmptyHeader(aHeader);
}
NS_IMETHODIMP
@@ -1750,7 +1738,7 @@ HttpBaseChannel::SetResponseHeader(const nsACString& header,
mResponseHeadersModified = true;
- return mResponseHead->SetHeader(atom, value, merge);
+ return mResponseHead->SetHeader(header, value, merge);
}
NS_IMETHODIMP
diff --git a/netwerk/protocol/http/PHttpChannelParams.h b/netwerk/protocol/http/PHttpChannelParams.h
index 4df5c7832e..b04f57306c 100644
--- a/netwerk/protocol/http/PHttpChannelParams.h
+++ b/netwerk/protocol/http/PHttpChannelParams.h
@@ -98,7 +98,11 @@ struct ParamTraits<mozilla::net::nsHttpHeaderArray::nsEntry>
static void Write(Message* aMsg, const paramType& aParam)
{
- WriteParam(aMsg, aParam.header);
+ if (aParam.headerNameOriginal.IsEmpty()) {
+ WriteParam(aMsg, aParam.header);
+ } else {
+ WriteParam(aMsg, aParam.headerNameOriginal);
+ }
WriteParam(aMsg, aParam.value);
switch (aParam.variety) {
case mozilla::net::nsHttpHeaderArray::eVarietyUnknown:
@@ -124,11 +128,18 @@ struct ParamTraits<mozilla::net::nsHttpHeaderArray::nsEntry>
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
uint8_t variety;
- if (!ReadParam(aMsg, aIter, &aResult->header) ||
+ nsAutoCString header;
+ if (!ReadParam(aMsg, aIter, &header) ||
!ReadParam(aMsg, aIter, &aResult->value) ||
!ReadParam(aMsg, aIter, &variety))
return false;
+ mozilla::net::nsHttpAtom atom = mozilla::net::nsHttp::ResolveAtom(header);
+ aResult->header = atom;
+ if (!header.Equals(atom.get())) {
+ aResult->headerNameOriginal = header;
+ }
+
switch (variety) {
case 0:
aResult->variety = mozilla::net::nsHttpHeaderArray::eVarietyUnknown;
diff --git a/netwerk/protocol/http/nsHttpHeaderArray.cpp b/netwerk/protocol/http/nsHttpHeaderArray.cpp
index 670300dea5..1030bc91ee 100644
--- a/netwerk/protocol/http/nsHttpHeaderArray.cpp
+++ b/netwerk/protocol/http/nsHttpHeaderArray.cpp
@@ -18,12 +18,37 @@ namespace net {
//-----------------------------------------------------------------------------
// nsHttpHeaderArray <public>
//-----------------------------------------------------------------------------
+
+nsresult
+nsHttpHeaderArray::SetHeader(const nsACString &headerName,
+ const nsACString &value,
+ bool merge,
+ nsHttpHeaderArray::HeaderVariety variety)
+{
+ nsHttpAtom header = nsHttp::ResolveAtom(PromiseFlatCString(headerName).get());
+ if (!header) {
+ NS_WARNING("failed to resolve atom");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ return SetHeader(header, headerName, value, merge, variety);
+}
+
nsresult
nsHttpHeaderArray::SetHeader(nsHttpAtom header,
const nsACString &value,
bool merge,
nsHttpHeaderArray::HeaderVariety variety)
{
+ return SetHeader(header, EmptyCString(), value, merge, variety);
+}
+
+nsresult
+nsHttpHeaderArray::SetHeader(nsHttpAtom header,
+ const nsACString &headerName,
+ const nsACString &value,
+ bool merge,
+ nsHttpHeaderArray::HeaderVariety variety)
+{
MOZ_ASSERT((variety == eVarietyResponse) ||
(variety == eVarietyRequestDefault) ||
(variety == eVarietyRequestOverride),
@@ -51,7 +76,7 @@ nsHttpHeaderArray::SetHeader(nsHttpAtom header,
MOZ_ASSERT(!entry || variety != eVarietyRequestDefault,
"Cannot set default entry which overrides existing entry!");
if (!entry) {
- return SetHeader_internal(header, value, variety);
+ return SetHeader_internal(header, headerName, value, variety);
} else if (merge && !IsSingletonHeader(header)) {
return MergeHeader(header, entry, value, variety);
} else {
@@ -59,7 +84,7 @@ nsHttpHeaderArray::SetHeader(nsHttpAtom header,
if (entry->variety == eVarietyResponseNetOriginalAndResponse) {
MOZ_ASSERT(variety == eVarietyResponse);
entry->variety = eVarietyResponseNetOriginal;
- return SetHeader_internal(header, value, variety);
+ return SetHeader_internal(header, headerName, value, variety);
} else {
entry->value = value;
entry->variety = variety;
@@ -71,6 +96,7 @@ nsHttpHeaderArray::SetHeader(nsHttpAtom header,
nsresult
nsHttpHeaderArray::SetHeader_internal(nsHttpAtom header,
+ const nsACString &headerName,
const nsACString &value,
nsHttpHeaderArray::HeaderVariety variety)
{
@@ -79,14 +105,26 @@ nsHttpHeaderArray::SetHeader_internal(nsHttpAtom header,
return NS_ERROR_OUT_OF_MEMORY;
}
entry->header = header;
+ // Only save original form of a header if it is different than the header
+ // atom string.
+ if (!headerName.Equals(header.get())) {
+ entry->headerNameOriginal = headerName;
+ }
entry->value = value;
entry->variety = variety;
return NS_OK;
}
nsresult
-nsHttpHeaderArray::SetEmptyHeader(nsHttpAtom header, HeaderVariety variety)
+nsHttpHeaderArray::SetEmptyHeader(const nsACString &headerName,
+ HeaderVariety variety)
{
+ nsHttpAtom header = nsHttp::ResolveAtom(PromiseFlatCString(headerName).get());
+ if (!header) {
+ NS_WARNING("failed to resolve atom");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
MOZ_ASSERT((variety == eVarietyResponse) ||
(variety == eVarietyRequestDefault) ||
(variety == eVarietyRequestOverride),
@@ -104,11 +142,12 @@ nsHttpHeaderArray::SetEmptyHeader(nsHttpAtom header, HeaderVariety variety)
entry->variety = eVarietyResponseNetOriginal;
}
- return SetHeader_internal(header, EmptyCString(), variety);
+ return SetHeader_internal(header, headerName, EmptyCString(), variety);
}
nsresult
nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header,
+ const nsACString &headerNameOriginal,
const nsACString &value,
bool response)
{
@@ -125,7 +164,7 @@ nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header,
LOG(("Ignoring Empty Header: %s\n", header.get()));
if (response) {
// Set header as original but not as response header.
- return SetHeader_internal(header, value,
+ return SetHeader_internal(header, headerNameOriginal, value,
eVarietyResponseNetOriginal);
}
return NS_OK; // ignore empty headers by default
@@ -135,7 +174,7 @@ nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header,
if (response) {
variety = eVarietyResponseNetOriginalAndResponse;
}
- return SetHeader_internal(header, value, variety);
+ return SetHeader_internal(header, headerNameOriginal, value, variety);
} else if (!IsSingletonHeader(header)) {
HeaderVariety variety = eVarietyRequestOverride;
@@ -147,7 +186,7 @@ nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header,
return rv;
}
if (response) {
- rv = SetHeader_internal(header, value,
+ rv = SetHeader_internal(header, headerNameOriginal, value,
eVarietyResponseNetOriginal);
}
return rv;
@@ -164,7 +203,7 @@ nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header,
}
if (response) {
- return SetHeader_internal(header, value,
+ return SetHeader_internal(header, headerNameOriginal, value,
eVarietyResponseNetOriginal);
}
}
@@ -174,6 +213,7 @@ nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header,
nsresult
nsHttpHeaderArray::SetResponseHeaderFromCache(nsHttpAtom header,
+ const nsACString &headerNameOriginal,
const nsACString &value,
nsHttpHeaderArray::HeaderVariety variety)
{
@@ -183,7 +223,7 @@ nsHttpHeaderArray::SetResponseHeaderFromCache(nsHttpAtom header,
"eVarietyResponseNetOriginal");
if (variety == eVarietyResponseNetOriginal) {
- return SetHeader_internal(header, value,
+ return SetHeader_internal(header, headerNameOriginal, value,
eVarietyResponseNetOriginal);
} else {
nsTArray<nsEntry>::index_type index = 0;
@@ -203,7 +243,8 @@ nsHttpHeaderArray::SetResponseHeaderFromCache(nsHttpAtom header,
}
} while (index != mHeaders.NoIndex);
// If we are here, we have not found an entry so add a new one.
- return SetHeader_internal(header, value, eVarietyResponse);
+ return SetHeader_internal(header, headerNameOriginal, value,
+ eVarietyResponse);
}
}
@@ -260,8 +301,16 @@ nsHttpHeaderArray::GetOriginalHeader(nsHttpAtom aHeader,
if (entry.variety == eVarietyResponse) {
continue;
}
+
+ nsAutoCString hdr;
+ if (entry.headerNameOriginal.IsEmpty()) {
+ hdr = nsDependentCString(entry.header);
+ } else {
+ hdr = entry.headerNameOriginal;
+ }
+
rv = NS_OK;
- if (NS_FAILED(aVisitor->VisitHeader(nsDependentCString(entry.header),
+ if (NS_FAILED(aVisitor->VisitHeader(hdr,
entry.value))) {
break;
}
@@ -298,8 +347,14 @@ nsHttpHeaderArray::VisitHeaders(nsIHttpHeaderVisitor *visitor, nsHttpHeaderArray
} else if (filter == eFilterResponseOriginal && entry.variety == eVarietyResponse) {
continue;
}
- rv = visitor->VisitHeader(
- nsDependentCString(entry.header), entry.value);
+
+ nsAutoCString hdr;
+ if (entry.headerNameOriginal.IsEmpty()) {
+ hdr = nsDependentCString(entry.header);
+ } else {
+ hdr = entry.headerNameOriginal;
+ }
+ rv = visitor->VisitHeader(hdr, entry.value);
if NS_FAILED(rv) {
return rv;
}
@@ -310,6 +365,7 @@ nsHttpHeaderArray::VisitHeaders(nsIHttpHeaderVisitor *visitor, nsHttpHeaderArray
/*static*/ nsresult
nsHttpHeaderArray::ParseHeaderLine(const nsACString& line,
nsHttpAtom *hdr,
+ nsACString *headerName,
nsACString *val)
{
//
@@ -360,6 +416,7 @@ nsHttpHeaderArray::ParseHeaderLine(const nsACString& line,
// assign return values
if (hdr) *hdr = atom;
if (val) val->Assign(p, p2 - p + 1);
+ if (headerName) headerName->Assign(sub);
return NS_OK;
}
@@ -397,7 +454,11 @@ nsHttpHeaderArray::Flatten(nsACString &buf, bool pruneProxyHeaders,
continue;
}
- buf.Append(entry.header);
+ if (entry.headerNameOriginal.IsEmpty()) {
+ buf.Append(entry.header);
+ } else {
+ buf.Append(entry.headerNameOriginal);
+ }
buf.AppendLiteral(": ");
buf.Append(entry.value);
buf.AppendLiteral("\r\n");
@@ -415,7 +476,11 @@ nsHttpHeaderArray::FlattenOriginalHeader(nsACString &buf)
continue;
}
- buf.Append(entry.header);
+ if (entry.headerNameOriginal.IsEmpty()) {
+ buf.Append(entry.header);
+ } else {
+ buf.Append(entry.headerNameOriginal);
+ }
buf.AppendLiteral(": ");
buf.Append(entry.value);
buf.AppendLiteral("\r\n");
@@ -423,11 +488,13 @@ nsHttpHeaderArray::FlattenOriginalHeader(nsACString &buf)
}
const char *
-nsHttpHeaderArray::PeekHeaderAt(uint32_t index, nsHttpAtom &header) const
+nsHttpHeaderArray::PeekHeaderAt(uint32_t index, nsHttpAtom &header,
+ nsACString &headerNameOriginal) const
{
const nsEntry &entry = mHeaders[index];
header = entry.header;
+ headerNameOriginal = entry.headerNameOriginal;
return entry.value.get();
}
diff --git a/netwerk/protocol/http/nsHttpHeaderArray.h b/netwerk/protocol/http/nsHttpHeaderArray.h
index 91b91f04aa..3ffdfa8146 100644
--- a/netwerk/protocol/http/nsHttpHeaderArray.h
+++ b/netwerk/protocol/http/nsHttpHeaderArray.h
@@ -49,19 +49,30 @@ public:
};
// Used by internal setters: to set header from network use SetHeaderFromNet
+ nsresult SetHeader(const nsACString &headerName,
+ const nsACString &value,
+ bool merge, HeaderVariety variety);
nsresult SetHeader(nsHttpAtom header, const nsACString &value,
bool merge, HeaderVariety variety);
+ nsresult SetHeader(nsHttpAtom header,
+ const nsACString &headerName,
+ const nsACString &value,
+ bool merge, HeaderVariety variety);
// Used by internal setters to set an empty header
- nsresult SetEmptyHeader(nsHttpAtom header, HeaderVariety variety);
+ nsresult SetEmptyHeader(const nsACString &headerName, HeaderVariety variety);
// Merges supported headers. For other duplicate values, determines if error
// needs to be thrown or 1st value kept.
// For the response header we keep the original headers as well.
- nsresult SetHeaderFromNet(nsHttpAtom header, const nsACString &value,
+ nsresult SetHeaderFromNet(nsHttpAtom header,
+ const nsACString &headerNameOriginal,
+ const nsACString &value,
bool response);
- nsresult SetResponseHeaderFromCache(nsHttpAtom header, const nsACString &value,
+ nsresult SetResponseHeaderFromCache(nsHttpAtom header,
+ const nsACString &headerNameOriginal,
+ const nsACString &value,
HeaderVariety variety);
nsresult GetHeader(nsHttpAtom header, nsACString &value) const;
@@ -97,15 +108,17 @@ public:
// parse a header line, return the header atom and a pointer to the
// header value (the substring of the header line -- do not free).
static nsresult ParseHeaderLine(const nsACString& line,
- nsHttpAtom *header=nullptr,
- nsACString* value=nullptr);
+ nsHttpAtom *header = nullptr,
+ nsACString *headerNameOriginal = nullptr,
+ nsACString *value = nullptr);
void Flatten(nsACString &, bool pruneProxyHeaders, bool pruneTransients);
void FlattenOriginalHeader(nsACString &);
uint32_t Count() const { return mHeaders.Length(); }
- const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header) const;
+ const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header,
+ nsACString &headerNameOriginal) const;
void Clear();
@@ -113,6 +126,7 @@ public:
struct nsEntry
{
nsHttpAtom header;
+ nsCString headerNameOriginal;
nsCString value;
HeaderVariety variety = eVarietyUnknown;
@@ -140,7 +154,9 @@ private:
int32_t LookupEntry(nsHttpAtom header, nsEntry **);
nsresult MergeHeader(nsHttpAtom header, nsEntry *entry,
const nsACString &value, HeaderVariety variety);
- nsresult SetHeader_internal(nsHttpAtom header, const nsACString &value,
+ nsresult SetHeader_internal(nsHttpAtom header,
+ const nsACString &headerName,
+ const nsACString &value,
HeaderVariety variety);
// Header cannot be merged: only one value possible
@@ -257,7 +273,11 @@ nsHttpHeaderArray::MergeHeader(nsHttpAtom header,
if (entry->variety == eVarietyResponseNetOriginalAndResponse) {
MOZ_ASSERT(variety == eVarietyResponse);
entry->variety = eVarietyResponseNetOriginal;
- nsresult rv = SetHeader_internal(header, newValue, eVarietyResponse);
+ // Copy entry->headerNameOriginal because in SetHeader_internal we are going
+ // to a new one and a realocation can happen.
+ nsCString headerNameOriginal = entry->headerNameOriginal;
+ nsresult rv = SetHeader_internal(header, headerNameOriginal,
+ newValue, eVarietyResponse);
if (NS_FAILED(rv)) {
return rv;
}
diff --git a/netwerk/protocol/http/nsHttpRequestHead.cpp b/netwerk/protocol/http/nsHttpRequestHead.cpp
index 094a794570..b366a8d542 100644
--- a/netwerk/protocol/http/nsHttpRequestHead.cpp
+++ b/netwerk/protocol/http/nsHttpRequestHead.cpp
@@ -131,6 +131,20 @@ nsHttpRequestHead::Origin(nsACString &aOrigin)
}
nsresult
+nsHttpRequestHead::SetHeader(const nsACString &h, const nsACString &v,
+ bool m /*= false*/)
+{
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+ if (mInVisitHeaders) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return mHeaders.SetHeader(h, v, m,
+ nsHttpHeaderArray::eVarietyRequestOverride);
+}
+
+nsresult
nsHttpRequestHead::SetHeader(nsHttpAtom h, const nsACString &v,
bool m /*= false*/)
{
@@ -158,7 +172,7 @@ nsHttpRequestHead::SetHeader(nsHttpAtom h, const nsACString &v, bool m,
}
nsresult
-nsHttpRequestHead::SetEmptyHeader(nsHttpAtom h)
+nsHttpRequestHead::SetEmptyHeader(const nsACString &h)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@@ -253,6 +267,7 @@ nsHttpRequestHead::ParseHeaderSet(const char *buffer)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsHttpAtom hdr;
+ nsAutoCString headerNameOriginal;
nsAutoCString val;
while (buffer) {
const char *eof = strchr(buffer, '\r');
@@ -262,9 +277,13 @@ nsHttpRequestHead::ParseHeaderSet(const char *buffer)
if (NS_SUCCEEDED(nsHttpHeaderArray::ParseHeaderLine(
nsDependentCSubstring(buffer, eof - buffer),
&hdr,
+ &headerNameOriginal,
&val))) {
- mHeaders.SetHeaderFromNet(hdr, val, false);
+ mHeaders.SetHeaderFromNet(hdr,
+ headerNameOriginal,
+ val,
+ false);
}
buffer = eof + 1;
if (*buffer == '\n') {
diff --git a/netwerk/protocol/http/nsHttpRequestHead.h b/netwerk/protocol/http/nsHttpRequestHead.h
index 4159680834..b7020d33a0 100644
--- a/netwerk/protocol/http/nsHttpRequestHead.h
+++ b/netwerk/protocol/http/nsHttpRequestHead.h
@@ -57,10 +57,12 @@ public:
int32_t port);
void Origin(nsACString &aOrigin);
+ nsresult SetHeader(const nsACString &h, const nsACString &v,
+ bool m=false);
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false);
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m,
nsHttpHeaderArray::HeaderVariety variety);
- nsresult SetEmptyHeader(nsHttpAtom h);
+ nsresult SetEmptyHeader(const nsACString &h);
nsresult GetHeader(nsHttpAtom h, nsACString &v);
nsresult ClearHeader(nsHttpAtom h);
diff --git a/netwerk/protocol/http/nsHttpResponseHead.cpp b/netwerk/protocol/http/nsHttpResponseHead.cpp
index 6d384c4887..fa6430b823 100644
--- a/netwerk/protocol/http/nsHttpResponseHead.cpp
+++ b/netwerk/protocol/http/nsHttpResponseHead.cpp
@@ -137,6 +137,26 @@ nsHttpResponseHead::Immutable()
}
nsresult
+nsHttpResponseHead::SetHeader(const nsACString &hdr,
+ const nsACString &val,
+ bool merge)
+{
+ ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+
+ if (mInVisitHeaders) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsHttpAtom atom = nsHttp::ResolveAtom(PromiseFlatCString(hdr).get());
+ if (!atom) {
+ NS_WARNING("failed to resolve atom");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ return SetHeader_locked(atom, hdr, val, merge);
+}
+
+nsresult
nsHttpResponseHead::SetHeader(nsHttpAtom hdr,
const nsACString &val,
bool merge)
@@ -147,24 +167,25 @@ nsHttpResponseHead::SetHeader(nsHttpAtom hdr,
return NS_ERROR_FAILURE;
}
- return SetHeader_locked(hdr, val, merge);
+ return SetHeader_locked(hdr, EmptyCString(), val, merge);
}
nsresult
-nsHttpResponseHead::SetHeader_locked(nsHttpAtom hdr,
+nsHttpResponseHead::SetHeader_locked(nsHttpAtom atom,
+ const nsACString &hdr,
const nsACString &val,
bool merge)
{
- nsresult rv = mHeaders.SetHeader(hdr, val, merge,
+ nsresult rv = mHeaders.SetHeader(atom, hdr, val, merge,
nsHttpHeaderArray::eVarietyResponse);
if (NS_FAILED(rv)) return rv;
// respond to changes in these headers. we need to reparse the entire
// header since the change may have merged in additional values.
- if (hdr == nsHttp::Cache_Control)
- ParseCacheControl(mHeaders.PeekHeader(hdr));
- else if (hdr == nsHttp::Pragma)
- ParsePragma(mHeaders.PeekHeader(hdr));
+ if (atom == nsHttp::Cache_Control)
+ ParseCacheControl(mHeaders.PeekHeader(atom));
+ else if (atom == nsHttp::Pragma)
+ ParsePragma(mHeaders.PeekHeader(atom));
return NS_OK;
}
@@ -316,6 +337,7 @@ nsHttpResponseHead::ParseCachedOriginalHeaders(char *block)
char *p = block;
nsHttpAtom hdr = {0};
+ nsAutoCString headerNameOriginal;
nsAutoCString val;
nsresult rv;
@@ -331,12 +353,13 @@ nsHttpResponseHead::ParseCachedOriginalHeaders(char *block)
*p = 0;
if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(
- nsDependentCString(block, p - block), &hdr, &val))) {
+ nsDependentCString(block, p - block), &hdr, &headerNameOriginal, &val))) {
return NS_OK;
}
rv = mHeaders.SetResponseHeaderFromCache(hdr,
+ headerNameOriginal,
val,
nsHttpHeaderArray::eVarietyResponseNetOriginal);
@@ -567,18 +590,21 @@ nsresult
nsHttpResponseHead::ParseHeaderLine_locked(const nsACString &line, bool originalFromNetHeaders)
{
nsHttpAtom hdr = {0};
+ nsAutoCString headerNameOriginal;
nsAutoCString val;
- if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(line, &hdr, &val))) {
+ if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(line, &hdr, &headerNameOriginal, &val))) {
return NS_OK;
}
nsresult rv;
if (originalFromNetHeaders) {
rv = mHeaders.SetHeaderFromNet(hdr,
+ headerNameOriginal,
val,
true);
} else {
rv = mHeaders.SetResponseHeaderFromCache(hdr,
+ headerNameOriginal,
val,
nsHttpHeaderArray::eVarietyResponse);
}
@@ -856,7 +882,8 @@ nsHttpResponseHead::UpdateHeaders(nsHttpResponseHead *aOther)
uint32_t i, count = aOther->mHeaders.Count();
for (i=0; i<count; ++i) {
nsHttpAtom header;
- const char *val = aOther->mHeaders.PeekHeaderAt(i, header);
+ nsAutoCString headerNameOriginal;
+ const char *val = aOther->mHeaders.PeekHeaderAt(i, header, headerNameOriginal);
if (!val) {
continue;
@@ -890,7 +917,8 @@ nsHttpResponseHead::UpdateHeaders(nsHttpResponseHead *aOther)
LOG(("new response header [%s: %s]\n", header.get(), val));
// overwrite the current header value with the new value...
- SetHeader_locked(header, nsDependentCString(val));
+ SetHeader_locked(header, headerNameOriginal,
+ nsDependentCString(val));
}
}
diff --git a/netwerk/protocol/http/nsHttpResponseHead.h b/netwerk/protocol/http/nsHttpResponseHead.h
index 0a912f4b40..8b51386ea2 100644
--- a/netwerk/protocol/http/nsHttpResponseHead.h
+++ b/netwerk/protocol/http/nsHttpResponseHead.h
@@ -65,6 +65,8 @@ public:
*/
int64_t TotalEntitySize();
+ nsresult SetHeader(const nsACString &h, const nsACString &v,
+ bool m=false);
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false);
nsresult GetHeader(nsHttpAtom h, nsACString &v);
void ClearHeader(nsHttpAtom h);
@@ -137,8 +139,8 @@ public:
bool HasContentType();
bool HasContentCharset();
private:
- nsresult SetHeader_locked(nsHttpAtom h, const nsACString &v,
- bool m=false);
+ nsresult SetHeader_locked(nsHttpAtom atom, const nsACString &h,
+ const nsACString &v, bool m=false);
void AssignDefaultStatusText();
void ParseVersion(const char *);
void ParseCacheControl(const char *);
diff --git a/netwerk/test/unit/test_bug1064258.js b/netwerk/test/unit/test_bug1064258.js
index 3f76837ae9..da982c2d6f 100644
--- a/netwerk/test/unit/test_bug1064258.js
+++ b/netwerk/test/unit/test_bug1064258.js
@@ -133,7 +133,7 @@ function cacheCheck2(status, entry)
do_check_eq(entry.dataSize, 0);
try {
do_check_neq(entry.getMetaDataElement("response-head"), null);
- do_check_true(entry.getMetaDataElement("response-head").match('Etag: testetag'));
+ do_check_true(entry.getMetaDataElement("response-head").match('etag: testetag'));
}
catch (ex) {
do_throw("Missing response head");
diff --git a/netwerk/test/unit/test_original_sent_received_head.js b/netwerk/test/unit/test_original_sent_received_head.js
index c4d02d5d22..d668abf590 100644
--- a/netwerk/test/unit/test_original_sent_received_head.js
+++ b/netwerk/test/unit/test_original_sent_received_head.js
@@ -114,11 +114,11 @@ function checkResponse(request, data, context) {
var locationHeaderFound = 0;
request.visitResponseHeaders({
visitHeader: function visit(aName, aValue) {
- if (aName == "Link") {
+ if (aName == "link") {
linkHeaderFound++;
do_check_eq(aValue, "value1, value2");
}
- if (aName == "Location") {
+ if (aName == "location") {
locationHeaderFound++;
do_check_eq(aValue, "loc");
}
@@ -132,7 +132,7 @@ function checkResponse(request, data, context) {
var locationOrgHeaderFound = 0;
request.visitOriginalResponseHeaders({
visitHeader: function visitOrg(aName, aValue) {
- if (aName == "Link") {
+ if (aName == "link") {
if (linkOrgHeaderFound == 0) {
do_check_eq(aValue, "");
} else if (linkOrgHeaderFound == 1 ) {
@@ -142,7 +142,7 @@ function checkResponse(request, data, context) {
}
linkOrgHeaderFound++;
}
- if (aName == "Location") {
+ if (aName == "location") {
locationOrgHeaderFound++;
do_check_eq(aValue, "loc");
}
@@ -160,10 +160,10 @@ function checkResponse(request, data, context) {
var locationHeaderFound2 = 0;
request.visitResponseHeaders({
visitHeader: function visit(aName, aValue) {
- if (aName == "Link") {
+ if (aName == "link") {
linkHeaderFound2 = true;
}
- if (aName == "Location") {
+ if (aName == "location") {
locationHeaderFound2 = true;
}
}
@@ -176,7 +176,7 @@ function checkResponse(request, data, context) {
var locationOrgHeaderFound2 = 0;
request.visitOriginalResponseHeaders({
visitHeader: function visitOrg(aName, aValue) {
- if (aName == "Link") {
+ if (aName == "link") {
if (linkOrgHeaderFound2 == 0) {
do_check_eq(aValue, "");
} else if (linkOrgHeaderFound2 == 1 ) {
@@ -186,7 +186,7 @@ function checkResponse(request, data, context) {
}
linkOrgHeaderFound2++;
}
- if (aName == "Location") {
+ if (aName == "location") {
locationOrgHeaderFound2++;
do_check_eq(aValue, "loc");
}
@@ -199,7 +199,7 @@ function checkResponse(request, data, context) {
if (dbg) { print("============== Test GetResponseHeader"); }
var linkOrgHeaderFound3 = 0;
- request.getOriginalResponseHeader("Link",{
+ request.getOriginalResponseHeader("link",{
visitHeader: function visitOrg(aName, aValue) {
if (linkOrgHeaderFound3 == 0) {
do_check_eq(aValue, "");