tbb-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2018
- 2 participants
- 147 discussions

[tor-browser/tor-browser-52.8.0esr-7.5-1] Bug 25147: Sanitize HTML fragments created for chrome-privileged documents
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 8c3c7dcd7e71ae7ca9237fef555efb602ddc7bcc
Author: Richard Pospesel <richard(a)torproject.org>
Date: Thu Mar 1 14:12:08 2018 -0800
Bug 25147: Sanitize HTML fragments created for chrome-privileged documents
Ported over firefox patch c2db4a50dc5c (Bug 1432966)
---
.../tests/mochitest/events/test_mutation.html | 4 +-
browser/base/content/browser-media.js | 59 ++++++------
.../customizableui/CustomizableWidgets.jsm | 2 +-
browser/modules/webrtcUI.jsm | 21 +++--
.../client/responsive.html/components/browser.js | 7 ++
devtools/shared/gcli/source/lib/gcli/util/util.js | 6 +-
.../tests/browser/browser_l10n_localizeMarkup.js | 4 +-
dom/base/Element.cpp | 6 ++
dom/base/Element.h | 1 +
dom/base/FragmentOrElement.cpp | 13 ++-
dom/base/FragmentOrElement.h | 3 +-
dom/base/nsContentUtils.cpp | 60 ++++++++++--
dom/base/nsContentUtils.h | 26 +++++-
dom/base/nsDocument.cpp | 12 ++-
dom/base/nsIDocument.h | 6 ++
dom/base/test/chrome.ini | 1 +
dom/base/test/chrome/test_bug683852.xul | 4 +-
dom/base/test/test_fragment_sanitization.xul | 101 +++++++++++++++++++++
dom/webidl/Document.webidl | 5 +
dom/webidl/Element.webidl | 10 ++
layout/style/test/chrome/bug418986-2.js | 16 +++-
mobile/android/chrome/content/config.js | 4 +-
toolkit/content/tests/chrome/test_bug570192.xul | 4 +-
toolkit/mozapps/extensions/content/extensions.js | 2 +-
24 files changed, 309 insertions(+), 68 deletions(-)
diff --git a/accessible/tests/mochitest/events/test_mutation.html b/accessible/tests/mochitest/events/test_mutation.html
index 232a0972777f..63dd74ca4775 100644
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -348,8 +348,8 @@
this.invoke = function insertReferredElm_invoke()
{
- this.containerNode.innerHTML =
- "<span id='insertReferredElms_span'></span><input aria-labelledby='insertReferredElms_span'>";
+ this.containerNode.unsafeSetInnerHTML(
+ "<span id='insertReferredElms_span'></span><input aria-labelledby='insertReferredElms_span'>");
}
this.getID = function insertReferredElm_getID()
diff --git a/browser/base/content/browser-media.js b/browser/base/content/browser-media.js
index 81e7faf17aad..c1ed8f9399fa 100644
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -41,11 +41,23 @@ var gEMEHandler = {
}
return true;
},
- getLearnMoreLink: function(msgId) {
- let text = gNavigatorBundle.getString("emeNotifications." + msgId + ".learnMoreLabel");
+ getEMEDisabledFragment(msgId) {
+ let mainMessage = gNavigatorBundle.getString("emeNotifications.drmContentDisabled.message");
+ let [prefix, suffix] = mainMessage.split(/%(?:1\$)?S/).map(s => document.createTextNode(s));
+ let text = gNavigatorBundle.getString("emeNotifications.drmContentDisabled.learnMoreLabel");
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
- return "<label class='text-link' href='" + baseURL + "drm-content'>" +
- text + "</label>";
+ let link = document.createElement("label");
+ link.className = "text-link";
+ link.setAttribute("href", baseURL + "drm-content");
+ link.textContent = text;
+
+ let fragment = document.createDocumentFragment();
+ [prefix, link, suffix].forEach(n => fragment.appendChild(n));
+ return fragment;
+ },
+ getMessageWithBrandName(notificationId) {
+ let msgId = "emeNotifications." + notificationId + ".message";
+ return gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
},
receiveMessage: function({target: browser, data: data}) {
let parsedData;
@@ -63,7 +75,8 @@ var gEMEHandler = {
let notificationId;
let buttonCallback;
- let params = [];
+ // Notification message can be either a string or a DOM fragment.
+ let notificationMessage;
switch (status) {
case "available":
case "cdm-created":
@@ -77,18 +90,18 @@ var gEMEHandler = {
case "api-disabled":
case "cdm-disabled":
notificationId = "drmContentDisabled";
- buttonCallback = gEMEHandler.ensureEMEEnabled.bind(gEMEHandler, browser, keySystem)
- params = [this.getLearnMoreLink(notificationId)];
+ buttonCallback = gEMEHandler.ensureEMEEnabled.bind(gEMEHandler, browser, keySystem);
+ notificationMessage = this.getEMEDisabledFragment();
break;
case "cdm-insufficient-version":
notificationId = "drmContentCDMInsufficientVersion";
- params = [this._brandShortName];
+ notificationMessage = this.getMessageWithBrandName(notificationId);
break;
case "cdm-not-installed":
notificationId = "drmContentCDMInstalling";
- params = [this._brandShortName];
+ notificationMessage = this.getMessageWithBrandName(notificationId);
break;
case "cdm-not-supported":
@@ -100,43 +113,27 @@ var gEMEHandler = {
return;
}
- this.showNotificationBar(browser, notificationId, keySystem, params, buttonCallback);
- },
- showNotificationBar: function(browser, notificationId, keySystem, labelParams, callback) {
+ // Now actually create the notification
+
let box = gBrowser.getNotificationBox(browser);
if (box.getNotificationWithValue(notificationId)) {
return;
}
- let msgPrefix = "emeNotifications." + notificationId + ".";
- let msgId = msgPrefix + "message";
-
- let message = labelParams.length ?
- gNavigatorBundle.getFormattedString(msgId, labelParams) :
- gNavigatorBundle.getString(msgId);
-
let buttons = [];
- if (callback) {
+ if (buttonCallback) {
+ let msgPrefix = "emeNotifications." + notificationId + ".";
let btnLabelId = msgPrefix + "button.label";
let btnAccessKeyId = msgPrefix + "button.accesskey";
buttons.push({
label: gNavigatorBundle.getString(btnLabelId),
accessKey: gNavigatorBundle.getString(btnAccessKeyId),
- callback: callback
+ callback: buttonCallback,
});
}
let iconURL = "chrome://browser/skin/drm-icon.svg#chains-black";
-
- // Do a little dance to get rich content into the notification:
- let fragment = document.createDocumentFragment();
- let descriptionContainer = document.createElement("description");
- descriptionContainer.innerHTML = message;
- while (descriptionContainer.childNodes.length) {
- fragment.appendChild(descriptionContainer.childNodes[0]);
- }
-
- box.appendNotification(fragment, notificationId, iconURL, box.PRIORITY_WARNING_MEDIUM,
+ box.appendNotification(notificationMessage, notificationId, iconURL, box.PRIORITY_WARNING_MEDIUM,
buttons);
},
showPopupNotificationForSuccess: function(browser, keySystem) {
diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm
index 907e2e0f75b7..b18249a35811 100644
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -327,7 +327,7 @@ const CustomizableWidgets = [
let promoParentElt = doc.getElementById("PanelUI-remotetabs-mobile-promo");
// Put it all together...
let contents = bundle.getFormattedString("appMenuRemoteTabs.mobilePromo.text2", formatArgs);
- promoParentElt.innerHTML = contents;
+ promoParentElt.unsafeSetInnerHTML(contents);
// We manually manage the "click" event to open the promo links because
// allowing the "text-link" widget handle it has 2 problems: (1) it only
// supports button 0 and (2) it's tricky to intercept when it does the
diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm
index b24135bfc959..ddcf09260f97 100644
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -536,21 +536,26 @@ function prompt(aBrowser, aRequest) {
bundle.getString("getUserMedia.shareScreen.learnMoreLabel");
let baseURL =
Services.urlFormatter.formatURLPref("app.support.baseURL");
- let learnMore =
- "<label class='text-link' href='" + baseURL + "screenshare-safety'>" +
- learnMoreText + "</label>";
+
+ let learnMore = chromeWin.document.createElement("label");
+ learnMore.className = "text-link";
+ learnMore.setAttribute("href", baseURL + "screenshare-safety");
+ learnMore.textContent = learnMoreText;
if (type == "screen") {
string = bundle.getFormattedString("getUserMedia.shareScreenWarning.message",
- [learnMore]);
- }
- else {
+ ["<>"]);
+ } else {
let brand =
chromeDoc.getElementById("bundle_brand").getString("brandShortName");
string = bundle.getFormattedString("getUserMedia.shareFirefoxWarning.message",
- [brand, learnMore]);
+ [brand, "<>"]);
}
- warning.innerHTML = string;
+
+ let [pre, post] = string.split("<>");
+ warning.textContent = pre;
+ warning.appendChild(learnMore);
+ warning.appendChild(chromeWin.document.createTextNode(post));
}
let perms = Services.perms;
diff --git a/devtools/client/responsive.html/components/browser.js b/devtools/client/responsive.html/components/browser.js
index f2902905b522..91f709f0cb8a 100644
--- a/devtools/client/responsive.html/components/browser.js
+++ b/devtools/client/responsive.html/components/browser.js
@@ -16,6 +16,13 @@ const Types = require("../types");
const e10s = require("../utils/e10s");
const message = require("../utils/message");
+// Allow creation of HTML fragments without automatic sanitization, even
+// though we're in a chrome-privileged document.
+// This is, unfortunately, necessary in order to React to function
+// correctly.
+
+document.allowUnsafeHTML = true;
+
module.exports = createClass({
/**
diff --git a/devtools/shared/gcli/source/lib/gcli/util/util.js b/devtools/shared/gcli/source/lib/gcli/util/util.js
index 065bf36c07db..cfc18062e1c5 100644
--- a/devtools/shared/gcli/source/lib/gcli/util/util.js
+++ b/devtools/shared/gcli/source/lib/gcli/util/util.js
@@ -498,7 +498,11 @@ exports.setContents = function(elem, contents) {
return;
}
- if ('innerHTML' in elem) {
+ if ('unsafeSetInnerHTML' in elem) {
+ // FIXME: Stop relying on unsanitized HTML.
+ elem.unsafeSetInnerHTML(contents);
+ }
+ else if ('innerHTML' in elem) {
elem.innerHTML = contents;
}
else {
diff --git a/devtools/shared/tests/browser/browser_l10n_localizeMarkup.js b/devtools/shared/tests/browser/browser_l10n_localizeMarkup.js
index f33a5a331c51..59bbb308ba44 100644
--- a/devtools/shared/tests/browser/browser_l10n_localizeMarkup.js
+++ b/devtools/shared/tests/browser/browser_l10n_localizeMarkup.js
@@ -18,7 +18,7 @@ add_task(function* () {
info("Create the test markup");
let div = document.createElement("div");
- div.innerHTML =
+ div.unsafeSetInnerHTML(
`<div data-localization-bundle="devtools/client/locales/startup.properties">
<div id="d0" data-localization="content=inspector.someInvalidKey"></div>
<div id="d1" data-localization="content=inspector.label">Text will disappear</div>
@@ -32,7 +32,7 @@ add_task(function* () {
<div id="d5" data-localization="content=toolbox.defaultTitle"></div>
</div>
</div>
- `;
+ `);
info("Use localization helper to localize the test markup");
localizeMarkup(div);
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index 09c6b39da574..daf5d6aa98bf 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3564,6 +3564,12 @@ Element::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
}
void
+Element::UnsafeSetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
+{
+ SetInnerHTMLInternal(aInnerHTML, aError, true);
+}
+
+void
Element::GetOuterHTML(nsAString& aOuterHTML)
{
GetMarkup(true, aOuterHTML);
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 5d878df60668..94991b26a641 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -896,6 +896,7 @@ public:
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
virtual void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
+ void UnsafeSetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
void GetOuterHTML(nsAString& aOuterHTML);
void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 4ad10931a8d0..c83a76dc2603 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -2183,7 +2183,8 @@ ContainsMarkup(const nsAString& aStr)
}
void
-FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError)
+FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError,
+ bool aNeverSanitize)
{
FragmentOrElement* target = this;
// Handle template case.
@@ -2237,6 +2238,9 @@ FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult
contextNameSpaceID = shadowRoot->GetHost()->GetNameSpaceID();
}
+ auto sanitize = (aNeverSanitize ? nsContentUtils::NeverSanitize
+ : nsContentUtils::SanitizeSystemPrivileged);
+
if (doc->IsHTMLDocument()) {
int32_t oldChildCount = target->GetChildCount();
aError = nsContentUtils::ParseFragmentHTML(aInnerHTML,
@@ -2245,14 +2249,17 @@ FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult
contextNameSpaceID,
doc->GetCompatibilityMode() ==
eCompatibility_NavQuirks,
- true);
+ true,
+ sanitize);
mb.NodesAdded();
// HTML5 parser has notified, but not fired mutation events.
nsContentUtils::FireMutationEventsForDirectParsing(doc, target,
oldChildCount);
} else {
RefPtr<DocumentFragment> df =
- nsContentUtils::CreateContextualFragment(target, aInnerHTML, true, aError);
+ nsContentUtils::CreateContextualFragment(target, aInnerHTML, true,
+ sanitize,
+ aError);
if (!aError.Failed()) {
// Suppress assertion about node removal mutation events that can't have
// listeners anyway, because no one has had the chance to register mutation
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 3cb5575fe063..c6ed7ab85e41 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -357,7 +357,8 @@ public:
protected:
void GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
- void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError);
+ void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError,
+ bool aNeverSanitize = false);
// Override from nsINode
virtual nsINode::nsSlots* CreateSlots() override;
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index f93274280f7c..182a1686d5fe 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -155,6 +155,7 @@
#include "nsIObserverService.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsIParser.h"
+#include "nsIParserUtils.h"
#include "nsIParserService.h"
#include "nsIPermissionManager.h"
#include "nsIPluginHost.h"
@@ -195,6 +196,7 @@
#include "nsTextFragment.h"
#include "nsTextNode.h"
#include "nsThreadUtils.h"
+#include "nsTreeSanitizer.h"
#include "nsUnicharUtilCIID.h"
#include "nsUnicodeProperties.h"
#include "nsViewManager.h"
@@ -4576,6 +4578,7 @@ already_AddRefed<DocumentFragment>
nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
const nsAString& aFragment,
bool aPreventScriptExecution,
+ SanitizeFragments aSanitize,
ErrorResult& aRv)
{
if (!aContextNode) {
@@ -4611,14 +4614,16 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
contextAsContent->GetNameSpaceID(),
(document->GetCompatibilityMode() ==
eCompatibility_NavQuirks),
- aPreventScriptExecution);
+ aPreventScriptExecution,
+ aSanitize);
} else {
aRv = ParseFragmentHTML(aFragment, frag,
nsGkAtoms::body,
kNameSpaceID_XHTML,
(document->GetCompatibilityMode() ==
eCompatibility_NavQuirks),
- aPreventScriptExecution);
+ aPreventScriptExecution,
+ aSanitize);
}
return frag.forget();
@@ -4682,7 +4687,8 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
nsCOMPtr<nsIDOMDocumentFragment> frag;
aRv = ParseFragmentXML(aFragment, document, tagStack,
- aPreventScriptExecution, getter_AddRefs(frag));
+ aPreventScriptExecution, getter_AddRefs(frag),
+ aSanitize);
return frag.forget().downcast<DocumentFragment>();
}
@@ -4709,7 +4715,8 @@ nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
nsIAtom* aContextLocalName,
int32_t aContextNamespace,
bool aQuirks,
- bool aPreventScriptExecution)
+ bool aPreventScriptExecution,
+ SanitizeFragments aSanitize)
{
AutoTimelineMarker m(aTargetNode->OwnerDoc()->GetDocShell(), "Parse HTML");
@@ -4723,13 +4730,39 @@ nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
// Now sHTMLFragmentParser owns the object
}
+
+ nsIContent* target = aTargetNode;
+
+ // If this is a chrome-privileged document, create a fragment first, and
+ // sanitize it before insertion.
+ RefPtr<DocumentFragment> fragment;
+ if (aSanitize != NeverSanitize && !aTargetNode->OwnerDoc()->AllowUnsafeHTML()) {
+ fragment = new DocumentFragment(aTargetNode->OwnerDoc()->NodeInfoManager());
+ target = fragment;
+ }
+
nsresult rv =
sHTMLFragmentParser->ParseFragment(aSourceBuffer,
- aTargetNode,
+ target,
aContextLocalName,
aContextNamespace,
aQuirks,
aPreventScriptExecution);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (fragment) {
+ // Don't fire mutation events for nodes removed by the sanitizer.
+ nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
+
+ nsTreeSanitizer sanitizer(nsIParserUtils::SanitizerAllowStyle |
+ nsIParserUtils::SanitizerAllowComments);
+ sanitizer.Sanitize(fragment);
+
+ ErrorResult error;
+ aTargetNode->AppendChild(*fragment, error);
+ rv = error.StealNSResult();
+ }
+
return rv;
}
@@ -4764,7 +4797,8 @@ nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
nsIDocument* aDocument,
nsTArray<nsString>& aTagStack,
bool aPreventScriptExecution,
- nsIDOMDocumentFragment** aReturn)
+ nsIDOMDocumentFragment** aReturn,
+ SanitizeFragments aSanitize)
{
AutoTimelineMarker m(aDocument->GetDocShell(), "Parse XML");
@@ -4803,6 +4837,20 @@ nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
sXMLFragmentParser->Reset();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // If this is a chrome-privileged document, sanitize the fragment before
+ // returning.
+ if (aSanitize != NeverSanitize && !aDocument->AllowUnsafeHTML()) {
+ // Don't fire mutation events for nodes removed by the sanitizer.
+ nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
+
+ RefPtr<DocumentFragment> fragment = static_cast<DocumentFragment*>(*aReturn);
+
+ nsTreeSanitizer sanitizer(nsIParserUtils::SanitizerAllowStyle |
+ nsIParserUtils::SanitizerAllowComments);
+ sanitizer.Sanitize(fragment);
+ }
return rv;
}
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 08c5cbf02e25..f2de4a16be5d 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1344,6 +1344,11 @@ public:
static bool IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix,
int32_t aNamespaceID);
+ enum SanitizeFragments {
+ SanitizeSystemPrivileged,
+ NeverSanitize,
+ };
+
/**
* Creates a DocumentFragment from text using a context node to resolve
* namespaces.
@@ -1357,6 +1362,8 @@ public:
* @param aFragment the string which is parsed to a DocumentFragment
* @param aReturn the resulting fragment
* @param aPreventScriptExecution whether to mark scripts as already started
+ * @param aSanitize whether the fragment should be sanitized prior to
+ * injection
*/
static nsresult CreateContextualFragment(nsINode* aContextNode,
const nsAString& aFragment,
@@ -1365,7 +1372,16 @@ public:
static already_AddRefed<mozilla::dom::DocumentFragment>
CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment,
bool aPreventScriptExecution,
+ SanitizeFragments aSanitize,
mozilla::ErrorResult& aRv);
+ static already_AddRefed<mozilla::dom::DocumentFragment>
+ CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment,
+ bool aPreventScriptExecution,
+ mozilla::ErrorResult& aRv)
+ {
+ return CreateContextualFragment(aContextNode, aFragment, aPreventScriptExecution,
+ SanitizeSystemPrivileged, aRv);
+ }
/**
* Invoke the fragment parsing algorithm (innerHTML) using the HTML parser.
@@ -1378,6 +1394,8 @@ public:
* @param aPreventScriptExecution true to prevent scripts from executing;
* don't set to false when parsing into a target node that has been
* bound to tree.
+ * @param aSanitize whether the fragment should be sanitized prior to
+ * injection
* @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
* fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
* long and NS_OK otherwise.
@@ -1387,7 +1405,8 @@ public:
nsIAtom* aContextLocalName,
int32_t aContextNamespace,
bool aQuirks,
- bool aPreventScriptExecution);
+ bool aPreventScriptExecution,
+ SanitizeFragments aSanitize = SanitizeSystemPrivileged);
/**
* Invoke the fragment parsing algorithm (innerHTML) using the XML parser.
@@ -1397,6 +1416,8 @@ public:
* @param aTagStack the namespace mapping context
* @param aPreventExecution whether to mark scripts as already started
* @param aReturn the result fragment
+ * @param aSanitize whether the fragment should be sanitized prior to
+ * injection
* @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
* fragments is made, a return code from the XML parser.
*/
@@ -1404,7 +1425,8 @@ public:
nsIDocument* aDocument,
nsTArray<nsString>& aTagStack,
bool aPreventScriptExecution,
- nsIDOMDocumentFragment** aReturn);
+ nsIDOMDocumentFragment** aReturn,
+ SanitizeFragments aSanitize = SanitizeSystemPrivileged);
/**
* Parse a string into a document using the HTML parser.
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 25e5d28d6c76..ba35493ad886 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1315,7 +1315,8 @@ nsIDocument::nsIDocument()
mFrameRequestCallbacksScheduled(false),
mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
mPartID(0),
- mUserHasInteracted(false)
+ mUserHasInteracted(false),
+ mAllowUnsafeHTML(false)
{
SetIsInDocument();
@@ -2659,7 +2660,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
(cspSandboxFlags & SANDBOXED_ORIGIN) && !(mSandboxFlags & SANDBOXED_ORIGIN);
mSandboxFlags |= cspSandboxFlags;
-
+
if (needNewNullPrincipal) {
principal = nsNullPrincipal::CreateWithInheritedAttributes(principal);
principal->SetCsp(csp);
@@ -5734,6 +5735,13 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
}
bool
+nsIDocument::AllowUnsafeHTML() const
+{
+ return (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) ||
+ mAllowUnsafeHTML);
+}
+
+bool
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
JS::Rooted<JSObject*> obj(aCx, aObject);
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index 5715fd233477..3ff69a6e8e1d 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2660,6 +2660,8 @@ public:
CreateAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aQualifiedName,
mozilla::ErrorResult& rv);
+ void SetAllowUnsafeHTML(bool aAllow) { mAllowUnsafeHTML = aAllow; }
+ bool AllowUnsafeHTML() const;
void GetInputEncoding(nsAString& aInputEncoding) const;
already_AddRefed<mozilla::dom::Location> GetLocation() const;
void GetReferrer(nsAString& aReferrer) const;
@@ -3206,6 +3208,10 @@ protected:
// UpdateFrameRequestCallbackSchedulingState.
bool mFrameRequestCallbacksScheduled : 1;
+ // True if unsafe HTML fragments should be allowed in chrome-privileged
+ // documents.
+ bool mAllowUnsafeHTML : 1;
+
enum Type {
eUnknown, // should never be used
eHTML,
diff --git a/dom/base/test/chrome.ini b/dom/base/test/chrome.ini
index f7e67ef6b9cb..8d4a9cd09a9c 100644
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -16,6 +16,7 @@ support-files =
[test_copypaste.xul]
subsuite = clipboard
[test_domrequesthelper.xul]
+[test_fragment_sanitization.xul]
[test_messagemanager_principal.html]
[test_messagemanager_send_principal.html]
skip-if = buildapp == 'mulet'
diff --git a/dom/base/test/chrome/test_bug683852.xul b/dom/base/test/chrome/test_bug683852.xul
index cebc8f3583bc..e7e106f7a483 100644
--- a/dom/base/test/chrome/test_bug683852.xul
+++ b/dom/base/test/chrome/test_bug683852.xul
@@ -20,6 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
/** Test for Bug 683852 **/
SimpleTest.waitForExplicitFinish();
+ const NS_HTML = "http://www.w3.org/1999/xhtml";
+
function startTest() {
is(document.contains(document), true, "Document should contain itself!");
@@ -48,7 +50,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
document.documentElement.appendChild(pi);
document.contains(pi, true, "Document should contain processing instruction");
- var df = document.createRange().createContextualFragment("<div>foo</div>");
+ var df = document.createRange().createContextualFragment(`<div xmlns="${NS_HTML}">foo</div>`);
is(df.contains(df.firstChild), true, "Document fragment should contain its child");
is(df.contains(df.firstChild.firstChild), true,
"Document fragment should contain its descendant");
diff --git a/dom/base/test/test_fragment_sanitization.xul b/dom/base/test/test_fragment_sanitization.xul
new file mode 100644
index 000000000000..0c91b210125c
--- /dev/null
+++ b/dom/base/test/test_fragment_sanitization.xul
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1432966
+-->
+<window title="Mozilla Bug 1432966"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"/>
+
+ <script type="application/javascript"><![CDATA[
+
+var { classes: Cc, interfaces: Ci } = Components;
+
+const NS_HTML = "http://www.w3.org/1999/xhtml";
+
+function awaitLoad(frame) {
+ return new Promise(resolve => {
+ frame.addEventListener("load", resolve, {once: true});
+ });
+}
+
+async function testFrame(frame, html, expected = html) {
+ document.querySelector("body").appendChild(frame);
+ await awaitLoad(frame);
+
+ // Remove the xmlns attributes that will be automatically added when we're
+ // in an XML document, and break the comparison.
+ function unNS(text) {
+ return text.replace(RegExp(` xmlns="${NS_HTML}"`, "g"), "");
+ }
+
+ let doc = frame.contentDocument;
+ let body = doc.body || doc.documentElement;
+
+ let div = doc.createElementNS(NS_HTML, "div");
+ body.appendChild(div);
+
+ div.innerHTML = html;
+ is(unNS(div.innerHTML), expected, "innerHTML value");
+
+ div.innerHTML = "<div></div>";
+ div.firstChild.outerHTML = html;
+ is(unNS(div.innerHTML), expected, "outerHTML value");
+
+ div.textContent = "";
+ div.insertAdjacentHTML("beforeend", html);
+ is(unNS(div.innerHTML), expected, "insertAdjacentHTML('beforeend') value");
+
+ div.innerHTML = "<a>foo</a>";
+ div.firstChild.insertAdjacentHTML("afterend", html);
+ is(unNS(div.innerHTML), "<a>foo</a>" + expected, "insertAdjacentHTML('afterend') value");
+
+ frame.remove();
+}
+
+add_task(async function test_fragment_sanitization() {
+ const XUL_URL = "chrome://global/content/win.xul";
+ const HTML_URL = "chrome://mochitests/content/chrome/dom/base/test/file_empty.html";
+
+ const HTML = '<a onclick="foo()" href="javascript:foo"><script>bar()<\/script>Meh.</a><a href="http://foo/"></a>';
+ const SANITIZED = '<a>Meh.</a><a href="http://foo/"></a>';
+
+ info("Test content HTML document");
+ {
+ let frame = document.createElementNS(NS_HTML, "iframe");
+ frame.src = "http://example.com/";
+
+ await testFrame(frame, HTML);
+ }
+
+ info("Test chrome HTML document");
+ {
+ let frame = document.createElementNS(NS_HTML, "iframe");
+ frame.src = HTML_URL;
+
+ await testFrame(frame, HTML, SANITIZED);
+ }
+
+ info("Test chrome XUL document");
+ {
+ let frame = document.createElementNS(NS_HTML, "iframe");
+ frame.src = XUL_URL;
+
+ await testFrame(frame, HTML, SANITIZED);
+ }
+});
+
+ ]]></script>
+
+ <description style="-moz-user-focus: normal; -moz-user-select: text;"><![CDATA[
+ hello
+ world
+ ]]></description>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1432966"
+ target="_blank">Mozilla Bug 1432966</a>
+ </body>
+</window>
diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl
index c895fad39275..ed071cbbd375 100644
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -95,6 +95,11 @@ interface Document : Node {
Attr createAttribute(DOMString name);
[NewObject, Throws]
Attr createAttributeNS(DOMString? namespace, DOMString name);
+
+ // Allows setting innerHTML without automatic sanitization.
+ // Do not use this.
+ [ChromeOnly]
+ attribute boolean allowUnsafeHTML;
};
// http://www.whatwg.org/specs/web-apps/current-work/#the-document-object
diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl
index ca5f1b35cd78..a66327ff96cd 100644
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -216,6 +216,16 @@ partial interface Element {
attribute DOMString outerHTML;
[Throws]
void insertAdjacentHTML(DOMString position, DOMString text);
+
+ /**
+ * Like the innerHTML setter, but does not sanitize its values, even in
+ * chrome-privileged documents.
+ *
+ * If you're thinking about using this, don't. You have many, much better
+ * options.
+ */
+ [ChromeOnly, Throws]
+ void unsafeSetInnerHTML(DOMString html);
};
// http://www.w3.org/TR/selectors-api/#interface-definitions
diff --git a/layout/style/test/chrome/bug418986-2.js b/layout/style/test/chrome/bug418986-2.js
index 4336f4abdb2c..2fcad6d70e0b 100644
--- a/layout/style/test/chrome/bug418986-2.js
+++ b/layout/style/test/chrome/bug418986-2.js
@@ -222,13 +222,23 @@ var green = (function () {
return getComputedStyle(temp).backgroundColor;
})();
+// Injected HTML will automatically be sanitized when we're in a chrome
+// document unless we use `unsafeSetInnerHTML`. That function doesn't
+// exist in non-chrome documents, so add a stub to allow the same code
+// to run in both.
+if (!Element.prototype.unsafeSetInnerHTML) {
+ Element.prototype.unsafeSetInnerHTML = html => {
+ this.innerHTML = html;
+ };
+}
+
// __testCSS(resisting)__.
// Creates a series of divs and CSS using media queries to set their
// background color. If all media queries match as expected, then
// all divs should have a green background color.
var testCSS = function (resisting) {
- document.getElementById("display").innerHTML = generateHtmlLines(resisting);
- document.getElementById("test-css").innerHTML = generateCSSLines(resisting);
+ document.getElementById("display").unsafeSetInnerHTML(generateHtmlLines(resisting));
+ document.getElementById("test-css").unsafeSetInnerHTML(generateCSSLines(resisting));
let cssTestDivs = document.querySelectorAll(".spoof,.suppress");
for (let div of cssTestDivs) {
let color = window.getComputedStyle(div).backgroundColor;
@@ -272,7 +282,7 @@ var testMediaQueriesInPictureElements = function* (resisting) {
lines += "</picture><br/>\n";
}
}
- document.getElementById("pictures").innerHTML = lines;
+ document.getElementById("pictures").unsafeSetInnerHTML(lines);
var testImages = document.getElementsByClassName("testImage");
yield sleep(0);
for (let testImage of testImages) {
diff --git a/mobile/android/chrome/content/config.js b/mobile/android/chrome/content/config.js
index 2c868f175ee8..83f93a51c86a 100644
--- a/mobile/android/chrome/content/config.js
+++ b/mobile/android/chrome/content/config.js
@@ -599,7 +599,7 @@ Pref.prototype = {
this.li.setAttribute("contextmenu", "prefs-context-menu");
// Create list item outline, bind to object actions
- this.li.innerHTML =
+ this.li.unsafeSetInnerHTML(
"<div class='pref-name' " +
"onclick='AboutConfig.selectOrToggleBoolPref(event);'>" +
this.name +
@@ -623,7 +623,7 @@ Pref.prototype = {
"<div class='pref-button down' " +
"onclick='AboutConfig.incrOrDecrIntPref(event, -1);'>" +
"</div>" +
- "</div>";
+ "</div>");
// Delay providing the list item values, until the LI is returned and added to the document
setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY);
diff --git a/toolkit/content/tests/chrome/test_bug570192.xul b/toolkit/content/tests/chrome/test_bug570192.xul
index 09f73e932b5d..91c55805c9da 100644
--- a/toolkit/content/tests/chrome/test_bug570192.xul
+++ b/toolkit/content/tests/chrome/test_bug570192.xul
@@ -36,8 +36,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=570192
addLoadEvent(function() {
try {
var content = document.getElementById("content");
- content.innerHTML = '<textbox newlines="pasteintact" ' +
- 'xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>';
+ content.unsafeSetInnerHTML('<textbox newlines="pasteintact" ' +
+ 'xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>');
var textbox = content.firstChild;
ok(textbox, "created the textbox");
ok(!textbox.editor, "do we have an editor?");
diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js
index 1e5f33b0a251..771008ed3bf8 100644
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -3078,7 +3078,7 @@ var gDetailView = {
// plugins without having bug 624602 fixed yet, and intentionally ignores
// localisation.
if (aAddon.isGMPlugin) {
- fullDesc.innerHTML = aAddon.fullDescription;
+ fullDesc.unsafeSetInnerHTML(aAddon.fullDescription);
} else {
fullDesc.textContent = aAddon.fullDescription;
}
1
0

[tor-browser/tor-browser-60.0.1esr-8.0-1] fixup! TB4: Tor Browser's Firefox preference overrides.
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 89614962f2ac1fa333b16c708a890167e9ec1b4e
Author: Georg Koppen <gk(a)torproject.org>
Date: Wed Jun 20 09:13:28 2018 +0000
fixup! TB4: Tor Browser's Firefox preference overrides.
Fixes our bug 26424 (disabling UNC paths) and activates Mozilla's fix
for https://bugzilla.mozilla.org/show_bug.cgi?id=1413868.
---
browser/app/profile/000-tor-browser.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
index 4289b7bcc5f9..cd901374ed9f 100644
--- a/browser/app/profile/000-tor-browser.js
+++ b/browser/app/profile/000-tor-browser.js
@@ -250,6 +250,8 @@ pref("devtools.appmanager.enabled", false);
pref("devtools.debugger.chrome-debugging-host", "127.0.0.1");
// Disable mozTCPSocket for sure (bug 18863)
pref("dom.mozTCPSocket.enabled", false);
+// Disable using UNC paths (bug 26424 and Mozilla's bug 1413868)
+pref("network.file.disable_unc_paths", true);
// Security slider
pref("svg.in-content.enabled", true);
1
0

[tor-browser/tor-browser-52.8.0esr-7.5-1] Bug 1448771 - Update hnjstdio to handle additional functions from stdio.h that libhyphen wants to use. r=glandium, a=RyanVM
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 20a839344bbb11759a15d38d283a9ff8862da30b
Author: Jonathan Kew <jkew(a)mozilla.com>
Date: Wed Mar 28 10:17:51 2018 +0100
Bug 1448771 - Update hnjstdio to handle additional functions from stdio.h that libhyphen wants to use. r=glandium, a=RyanVM
--HG--
extra : source : 846bcaa210aa2264bec412c0595113964fafc972
---
intl/hyphenation/glue/hnjalloc.h | 6 +++++
intl/hyphenation/glue/hnjstdio.cpp | 50 ++++++++++++++++++++++++++------------
2 files changed, 41 insertions(+), 15 deletions(-)
diff --git a/intl/hyphenation/glue/hnjalloc.h b/intl/hyphenation/glue/hnjalloc.h
index fec3a4bc9009..5cee1be1b6d7 100644
--- a/intl/hyphenation/glue/hnjalloc.h
+++ b/intl/hyphenation/glue/hnjalloc.h
@@ -31,6 +31,8 @@
#define fopen(path,mode) hnjFopen(path,mode)
#define fclose(file) hnjFclose(file)
#define fgets(buf,count,file) hnjFgets(buf,count,file)
+#define feof(file) hnjFeof(file)
+#define fgetc(file) hnjFgetc(file)
typedef struct hnjFile_ hnjFile;
@@ -44,6 +46,10 @@ int hnjFclose(hnjFile* f);
char* hnjFgets(char* s, int n, hnjFile* f);
+int hnjFeof(hnjFile* f);
+
+int hnjFgetc(hnjFile* f);
+
#ifdef __cplusplus
}
#endif
diff --git a/intl/hyphenation/glue/hnjstdio.cpp b/intl/hyphenation/glue/hnjstdio.cpp
index 660ebaf13291..8d50ae17f57b 100644
--- a/intl/hyphenation/glue/hnjstdio.cpp
+++ b/intl/hyphenation/glue/hnjstdio.cpp
@@ -22,6 +22,7 @@ struct hnjFile_ {
char mBuffer[BUFSIZE];
uint32_t mCurPos;
uint32_t mLimit;
+ bool mEOF;
};
// replacement for fopen()
@@ -58,6 +59,7 @@ hnjFopen(const char* aURISpec, const char* aMode)
f->mStream = instream;
f->mCurPos = 0;
f->mLimit = 0;
+ f->mEOF = false;
return f;
}
@@ -79,6 +81,27 @@ hnjFclose(hnjFile* f)
return result;
}
+// replacement for fgetc()
+int
+hnjFgetc(hnjFile* f)
+{
+ if (f->mCurPos >= f->mLimit) {
+ f->mCurPos = 0;
+
+ nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
+ if (NS_FAILED(rv)) {
+ f->mLimit = 0;
+ }
+
+ if (f->mLimit == 0) {
+ f->mEOF = true;
+ return EOF;
+ }
+ }
+
+ return f->mBuffer[f->mCurPos++];
+}
+
// replacement for fgets()
// (not a full reimplementation, but sufficient for libhyphen's needs)
char*
@@ -88,24 +111,15 @@ hnjFgets(char* s, int n, hnjFile* f)
int i = 0;
while (i < n - 1) {
- if (f->mCurPos < f->mLimit) {
- char c = f->mBuffer[f->mCurPos++];
- s[i++] = c;
- if (c == '\n' || c == '\r') {
- break;
- }
- continue;
- }
-
- f->mCurPos = 0;
+ int c = hnjFgetc(f);
- nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
- if (NS_FAILED(rv)) {
- f->mLimit = 0;
- return nullptr;
+ if (c == EOF) {
+ break;
}
- if (f->mLimit == 0) {
+ s[i++] = c;
+
+ if (c == '\n' || c == '\r') {
break;
}
}
@@ -117,3 +131,9 @@ hnjFgets(char* s, int n, hnjFile* f)
s[i] = '\0'; // null-terminate the returned string
return s;
}
+
+int
+hnjFeof(hnjFile* f)
+{
+ return f->mEOF ? EOF : 0;
+}
1
0

[tor-browser/tor-browser-52.8.0esr-7.5-1] Bug 1448771 - Merge fix from upstream. r=ryanvm, a=RyanVM
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 12148cf644e5820182306788a3d3309baf8c2720
Author: Jonathan Kew <jkew(a)mozilla.com>
Date: Mon Mar 26 20:35:48 2018 +0100
Bug 1448771 - Merge fix from upstream. r=ryanvm, a=RyanVM
--HG--
extra : source : f5db47b5c6416a3cef546de1aa9089d98109f95f
---
intl/hyphenation/hyphen/hyphen.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/intl/hyphenation/hyphen/hyphen.c b/intl/hyphenation/hyphen/hyphen.c
index 9a132d0262f2..9f2b7112c848 100644
--- a/intl/hyphenation/hyphen/hyphen.c
+++ b/intl/hyphenation/hyphen/hyphen.c
@@ -438,11 +438,25 @@ for (k = 0; k < 2; k++) {
}
if (k == 0 || nextlevel) {
- while (fgets (buf, sizeof(buf), f) != NULL) {
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+
+ /* discard lines that don't fit in buffer */
+ if (!feof(f) && strchr(buf, '\n') == NULL) {
+ int c;
+ while ((c = fgetc(f)) != '\n' && c != EOF);
+ /* issue warning if not a comment */
+ if (buf[0] != '%') {
+ fprintf(stderr, "Warning: skipping too long pattern (more than %lu chars)\n", sizeof(buf));
+ }
+ continue;
+ }
+
if (strncmp(buf, "NEXTLEVEL", 9) == 0) {
- nextlevel = 1;
- break;
- } else if (buf[0] != '%') hnj_hyphen_load_line(buf, dict[k], hashtab);
+ nextlevel = 1;
+ break;
+ } else if (buf[0] != '%') {
+ hnj_hyphen_load_line(buf, dict[k], hashtab);
+ }
}
} else if (k == 1) {
/* default first level: hyphen and ASCII apostrophe */
1
0

[tor-browser/tor-browser-52.8.0esr-7.5-1] Bug 21537: Mark .onion cookies as secure
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 1f33ee1778b0ad0f696977fbcbae67f72d34b99f
Author: Georg Koppen <gk(a)torproject.org>
Date: Fri Apr 13 16:59:24 2018 +0000
Bug 21537: Mark .onion cookies as secure
---
netwerk/cookie/nsCookieService.cpp | 60 ++++++++++++++++++++------------------
1 file changed, 32 insertions(+), 28 deletions(-)
diff --git a/netwerk/cookie/nsCookieService.cpp b/netwerk/cookie/nsCookieService.cpp
index cf1d91e2df36..f9390d7ef093 100644
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -3112,6 +3112,26 @@ PathMatches(nsCookie* aCookie, const nsACString& aPath) {
return true;
}
+static bool
+IsSecureHost(nsIURI *aHostURI) {
+ bool isSecure = true;
+ // If SchemeIs fails, assume an insecure connection, to be on the safe side.
+ if (aHostURI && NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
+ isSecure = false;
+ }
+ // In case HTTPS is not used check whether we have a .onion host in which
+ // case the cookie is secure, too.
+ if (aHostURI && !isSecure) {
+ nsresult rv;
+ nsAutoCString hostFromURI;
+ rv = aHostURI->GetAsciiHost(hostFromURI);
+ if (NS_SUCCEEDED(rv)) {
+ isSecure = StringEndsWith(hostFromURI, NS_LITERAL_CSTRING(".onion"));
+ }
+ }
+ return isSecure;
+}
+
void
nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
bool aIsForeign,
@@ -3164,13 +3184,10 @@ nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
// If it changes, please update that function, or file a bug for someone
// else to do so.
- // check if aHostURI is using an https secure protocol.
- // if it isn't, then we can't send a secure cookie over the connection.
- // if SchemeIs fails, assume an insecure connection, to be on the safe side
- bool isSecure;
- if (NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
- isSecure = false;
- }
+ // Check if aHostURI is using the HTTPS protocol or if the domain is a
+ // .onion. If it isn't, then we can't send a secure cookie over the
+ // connection.
+ bool isSecure = IsSecureHost(aHostURI);
nsCookie *cookie;
AutoTArray<nsCookie*, 8> foundCookieList;
@@ -3316,20 +3333,10 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
// so we can handle them separately.
bool newCookie = ParseAttributes(aCookieHeader, cookieAttributes);
- // Collect telemetry on how often secure cookies are set from non-secure
- // origins, and vice-versa.
- //
- // 0 = nonsecure and "http:"
- // 1 = nonsecure and "https:"
- // 2 = secure and "http:"
- // 3 = secure and "https:"
- bool isHTTPS;
- nsresult rv = aHostURI->SchemeIs("https", &isHTTPS);
- if (NS_SUCCEEDED(rv)) {
- Telemetry::Accumulate(Telemetry::COOKIE_SCHEME_SECURITY,
- ((cookieAttributes.isSecure)? 0x02 : 0x00) |
- ((isHTTPS)? 0x01 : 0x00));
- }
+ // Check if aHostURI is using the HTTPS protocol or if the domain is a
+ // .onion. If it isn't, then we can't send a secure cookie over the
+ // connection.
+ bool isSecure = IsSecureHost(aHostURI);
int64_t currentTimeInUsec = PR_Now();
@@ -3369,7 +3376,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
return newCookie;
}
// magic prefix checks. MUST be run after CheckDomain() and CheckPath()
- if (!CheckPrefixes(cookieAttributes, isHTTPS)) {
+ if (!CheckPrefixes(cookieAttributes, isSecure)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the prefix tests");
return newCookie;
}
@@ -3457,13 +3464,10 @@ nsCookieService::AddInternal(const nsCookieKey &aKey,
return;
}
- bool isSecure = true;
- if (aHostURI && NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
- isSecure = false;
- }
+ bool isSecure = IsSecureHost(aHostURI);
- // If the new cookie is non-https and wants to set secure flag,
- // browser have to ignore this new cookie.
+ // If the new cookie is non-https or not set by a .onion domain, and wants to
+ // set secure flag, browser have to ignore this new cookie.
// (draft-ietf-httpbis-cookie-alone section 3.1)
if (mLeaveSecureAlone && aCookie->IsSecure() && !isSecure) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
1
0

[tor-browser/tor-browser-52.8.0esr-7.5-1] Bug 1334776 - Store header names into nsHttpHeaderArray. r=mcmanus
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit cd2dd6a72bef0d0d5d405af3a1913bebb820fc02
Author: Dragana Damjanovic <dd.mozilla(a)gmail.com>
Date: Thu Apr 27 16:48:36 2017 +0200
Bug 1334776 - Store header names into nsHttpHeaderArray. r=mcmanus
Backported to TBB/ESR52 by Arthur Edelstein <arthuredelstein(a)gmail.com>
---
dom/security/test/cors/test_CrossSiteXHR.html | 2 +-
netwerk/protocol/http/HttpBaseChannel.cpp | 18 +---
netwerk/protocol/http/PHttpChannelParams.h | 15 +++-
netwerk/protocol/http/nsHttpHeaderArray.cpp | 100 +++++++++++++++++----
netwerk/protocol/http/nsHttpHeaderArray.h | 36 ++++++--
netwerk/protocol/http/nsHttpRequestHead.cpp | 23 ++++-
netwerk/protocol/http/nsHttpRequestHead.h | 4 +-
netwerk/protocol/http/nsHttpResponseHead.cpp | 50 ++++++++---
netwerk/protocol/http/nsHttpResponseHead.h | 6 +-
netwerk/test/unit/test_bug1064258.js | 2 +-
.../test/unit/test_original_sent_received_head.js | 14 +--
11 files changed, 204 insertions(+), 66 deletions(-)
diff --git a/dom/security/test/cors/test_CrossSiteXHR.html b/dom/security/test/cors/test_CrossSiteXHR.html
index b3cda3b871f3..d9aef5c60cd0 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 e68bff1d115e..97120b97a5d3 100644
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1678,13 +1678,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
@@ -1701,13 +1695,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
@@ -1763,7 +1751,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 4df5c7832ee8..b04f57306c58 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 670300dea50b..98c5a6b9ba47 100644
--- a/netwerk/protocol/http/nsHttpHeaderArray.cpp
+++ b/netwerk/protocol/http/nsHttpHeaderArray.cpp
@@ -18,8 +18,33 @@ 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)
@@ -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,12 @@ 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 +489,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 91b91f04aa1c..4c4b92911a5d 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 094a79457094..b366a8d54264 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 415968083477..b7020d33a0ac 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 6d384c48872e..fa6430b8231f 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 0a912f4b403b..8b51386ea229 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 3f76837ae935..da982c2d6f07 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 c4d02d5d2299..eab359a108ae 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");
}
@@ -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, "");
1
0

[tor-browser/tor-browser-52.8.0esr-7.5-1] Bug 1334776 - ResponseHeader Visitor will get original header casing. We need to fix it at some places in devtools.
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 1a800384e6ee8c909a1147737cdebad189f6ca3d
Author: Dragana Damjanovic <dd.mozilla(a)gmail.com>
Date: Thu Apr 27 16:48:43 2017 +0200
Bug 1334776 - ResponseHeader Visitor will get original header casing. We need to fix it at some places in devtools.
Backported to TBB/ESR52 by Arthur Edelstein <arthuredelstein(a)gmail.com>
Fixes bug 25938.
---
devtools/client/netmonitor/filter-predicates.js | 4 ++--
.../client/netmonitor/test/browser_net_copy_headers.js | 16 ++++++++--------
devtools/client/netmonitor/test/browser_net_filter-01.js | 4 ++--
.../netmonitor/test/browser_net_timing-division.js | 4 ++--
devtools/client/shared/AppCacheUtils.jsm | 8 ++++----
devtools/client/shared/curl.js | 8 ++++----
.../webconsole/net/test/mochitest/browser_net_headers.js | 4 ++--
...er_webconsole_bug_630733_response_redirect_headers.js | 2 +-
devtools/shared/webconsole/test/test_network_get.html | 8 ++++----
.../shared/webconsole/test/test_network_longstring.html | 4 ++--
devtools/shared/webconsole/test/test_network_post.html | 8 ++++----
11 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/devtools/client/netmonitor/filter-predicates.js b/devtools/client/netmonitor/filter-predicates.js
index 9c8e49c622b2..75ee422aad60 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 36ce2fb34789..bb582c8e1359 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_filter-01.js b/devtools/client/netmonitor/test/browser_net_filter-01.js
index b0d76c6293e0..7b3a8c457dd3 100644
--- a/devtools/client/netmonitor/test/browser_net_filter-01.js
+++ b/devtools/client/netmonitor/test/browser_net_filter-01.js
@@ -181,9 +181,9 @@ add_task(function* () {
"The details pane should still be visible after filtering.");
is(RequestsMenu.items.length, visibility.length,
- "There should be a specific amount of items in the requests menu.");
+ "There should be a specific amount of items in the requests menu.");
is(RequestsMenu.visibleItems.length, visibility.filter(e => e).length,
- "There should be a specific amount of visbile items in the requests menu.");
+ "There should be a specific amount of visbile items in the requests menu.");
for (let i = 0; i < visibility.length; i++) {
is(RequestsMenu.getItemAtIndex(i).target.hidden, !visibility[i],
diff --git a/devtools/client/netmonitor/test/browser_net_timing-division.js b/devtools/client/netmonitor/test/browser_net_timing-division.js
index 0114ba235500..ff2379dc28c4 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 a2beca993c32..7c8007d9ffe2 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.requestHeaders[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 978cbad9c845..ae954fe9f412 100644
--- a/devtools/client/shared/curl.js
+++ b/devtools/client/shared/curl.js
@@ -80,14 +80,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.
@@ -118,11 +118,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 4a47074ee194..14cde846c20c 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 5097499538c9..da4bdcf122ec 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 710c9b0d7516..c2313be12a30 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 d55136896917..9e6ea7771b63 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 d96b9b0b7c24..a0b8edb648f8 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);
1
0

[tor-browser/tor-browser-52.8.0esr-7.5-1] fixup! TB4: Tor Browser's Firefox preference overrides.
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit 76a19c911a7c847756d8ca20a70affdbcad56011
Author: Georg Koppen <gk(a)torproject.org>
Date: Wed Jun 20 09:13:28 2018 +0000
fixup! TB4: Tor Browser's Firefox preference overrides.
Fixes our bug 26424 (disabling UNC paths) and activates Mozilla's fix
for https://bugzilla.mozilla.org/show_bug.cgi?id=1413868.
---
browser/app/profile/000-tor-browser.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
index 6fa34860a7b5..f27c5dd93e04 100644
--- a/browser/app/profile/000-tor-browser.js
+++ b/browser/app/profile/000-tor-browser.js
@@ -255,6 +255,8 @@ pref("devtools.appmanager.enabled", false);
pref("devtools.debugger.chrome-debugging-host", "127.0.0.1");
// Disable mozTCPSocket for sure (bug 18863)
pref("dom.mozTCPSocket.enabled", false);
+// Disable using UNC paths (bug 26424 and Mozilla's bug 1413868)
+pref("network.file.disable_unc_paths", true);
// Security slider
pref("svg.in-content.enabled", true);
1
0

20 Jun '18
commit 08db71c6c4a7f4465f890bd13f502bd54fe35389
Author: Georg Koppen <gk(a)torproject.org>
Date: Wed Jun 20 10:54:43 2018 +0000
Release preparations for 0.2.14.5
Version bump
---
src/install.rdf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/install.rdf b/src/install.rdf
index 1604ac6..703b307 100644
--- a/src/install.rdf
+++ b/src/install.rdf
@@ -7,7 +7,7 @@
<em:creator>The Tor Project, Inc.</em:creator>
<em:contributor>Pearl Crescent, LLC</em:contributor>
<em:id>tor-launcher(a)torproject.org</em:id>
- <em:version>0.2.14.4</em:version>
+ <em:version>0.2.14.5</em:version>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<em:homepageURL>https://www.torproject.org/projects/torbrowser.html</em:homepageURL>
<em:updateURL>data:text/plain,</em:updateURL>
1
0

[tor-launcher/maint-0.2.14] Bug 20890: Increase control port connection timeout
by gk@torproject.org 20 Jun '18
by gk@torproject.org 20 Jun '18
20 Jun '18
commit f34e4cc7047a752f4c33736924b2133b371829b8
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Wed May 16 14:17:16 2018 -0400
Bug 20890: Increase control port connection timeout
On slow computers, it can take longer than 30 seconds for Tor Launcher
to connect to the tor control port. Increase the timeout to 5 minutes.
---
src/components/tl-process.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index 53c9919..2bf5a4c 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -38,8 +38,8 @@ TorProcessService.prototype =
kWizardProgressPageID: "progress",
kInitialControlConnDelayMS: 25,
- kMaxControlConnRetryMS: 500,
- kControlConnTimeoutMS: 30000, // Wait at most 30 seconds for tor to start.
+ kMaxControlConnRetryMS: 2000, // Retry at least every 2 seconds.
+ kControlConnTimeoutMS: 5*60*1000, // Wait at most 5 minutes for tor to start.
kStatusUnknown: 0, // Tor process status.
kStatusStarting: 1,
1
0