summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-04-25 23:08:37 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-04-25 23:08:37 +0200
commit42f8488a5f66d7c1e5324bd1755d7f693b16ee97 (patch)
tree54c7d2a62c4ea34b1250b5362c8e6f89d03f1a02 /dom
parent681c39a0ecc84fc918b2bec72cc69ad27d39903a (diff)
parent6c3f95480a191ce432ddfb2aa400a6d70c4884a8 (diff)
downloadUXP-42f8488a5f66d7c1e5324bd1755d7f693b16ee97.tar
UXP-42f8488a5f66d7c1e5324bd1755d7f693b16ee97.tar.gz
UXP-42f8488a5f66d7c1e5324bd1755d7f693b16ee97.tar.lz
UXP-42f8488a5f66d7c1e5324bd1755d7f693b16ee97.tar.xz
UXP-42f8488a5f66d7c1e5324bd1755d7f693b16ee97.zip
Merge branch 'master' into Basilisk-releasev2018.04.26
Diffstat (limited to 'dom')
-rw-r--r--dom/base/Element.cpp18
-rw-r--r--dom/base/Location.cpp21
-rw-r--r--dom/base/nsContentPolicy.cpp6
-rw-r--r--dom/base/nsDocument.cpp37
-rw-r--r--dom/base/nsIDocument.h3
-rw-r--r--dom/base/nsINode.cpp4
-rwxr-xr-xdom/events/Event.cpp19
-rw-r--r--dom/events/EventDispatcher.cpp5
-rw-r--r--dom/events/test/pointerevents/mochitest.ini18
-rw-r--r--dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html57
-rw-r--r--dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html76
-rw-r--r--dom/fetch/Response.cpp8
-rw-r--r--dom/fetch/Response.h2
-rw-r--r--dom/html/nsHTMLDocument.cpp18
-rw-r--r--dom/html/nsHTMLDocument.h1
-rw-r--r--dom/indexedDB/test/browser_forgetThisSite.js7
-rw-r--r--dom/locales/en-US/chrome/security/security.properties3
-rw-r--r--dom/security/nsCSPContext.cpp5
-rw-r--r--dom/security/nsContentSecurityManager.cpp140
-rw-r--r--dom/security/nsContentSecurityManager.h2
-rw-r--r--dom/security/test/general/browser.ini14
-rw-r--r--dom/security/test/general/browser_test_data_download.js37
-rw-r--r--dom/security/test/general/browser_test_data_text_csv.js37
-rw-r--r--dom/security/test/general/browser_test_toplevel_data_navigations.js54
-rw-r--r--dom/security/test/general/browser_test_view_image_data_navigation.js30
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation.html14
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation2.html29
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation3.html13
-rw-r--r--dom/security/test/general/file_block_toplevel_data_redirect.sjs14
-rw-r--r--dom/security/test/general/file_data_download.html14
-rw-r--r--dom/security/test/general/file_data_text_csv.html14
-rw-r--r--dom/security/test/general/file_toplevel_data_meta_redirect.html10
-rw-r--r--dom/security/test/general/file_toplevel_data_navigations.sjs14
-rw-r--r--dom/security/test/general/file_view_image_data_navigation.html12
-rw-r--r--dom/security/test/general/mochitest.ini12
-rw-r--r--dom/security/test/general/test_allow_opening_data_json.html39
-rw-r--r--dom/security/test/general/test_allow_opening_data_pdf.html41
-rw-r--r--dom/security/test/general/test_block_toplevel_data_img_navigation.html53
-rw-r--r--dom/security/test/general/test_block_toplevel_data_navigation.html86
-rw-r--r--dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html1
-rw-r--r--dom/security/test/moz.build1
-rw-r--r--dom/url/URL.cpp40
-rw-r--r--dom/webidl/Document.webidl6
-rw-r--r--dom/webidl/HTMLDocument.webidl4
-rw-r--r--dom/webidl/Response.webidl2
-rw-r--r--dom/webidl/Selection.webidl3
46 files changed, 934 insertions, 110 deletions
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index 8b9808aa3..092755590 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1844,6 +1844,24 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
SetParentIsContent(false);
}
+#ifdef DEBUG
+ // If we can get access to the PresContext, then we sanity-check that
+ // we're not leaving behind a pointer to ourselves as the PresContext's
+ // cached provider of the viewport's scrollbar styles.
+ if (document) {
+ nsIPresShell* presShell = document->GetShell();
+ if (presShell) {
+ nsPresContext* presContext = presShell->GetPresContext();
+ if (presContext) {
+ MOZ_ASSERT(this !=
+ presContext->GetViewportScrollbarStylesOverrideNode(),
+ "Leaving behind a raw pointer to this node (as having "
+ "propagated scrollbar styles) - that's dangerous...");
+ }
+ }
+ }
+#endif
+
// Ensure that CSS transitions don't continue on an element at a
// different place in the tree (even if reinserted before next
// animation refresh).
diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp
index e3b614931..b6b95aaa6 100644
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -577,19 +577,17 @@ Location::GetPathname(nsAString& aPathname)
aPathname.Truncate();
nsCOMPtr<nsIURI> uri;
- nsresult result = NS_OK;
+ nsresult result = GetURI(getter_AddRefs(uri));
+ if (NS_FAILED(result) || !uri) {
+ return result;
+ }
- result = GetURI(getter_AddRefs(uri));
+ nsAutoCString file;
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri));
- if (url) {
- nsAutoCString file;
+ result = uri->GetFilePath(file);
- result = url->GetFilePath(file);
-
- if (NS_SUCCEEDED(result)) {
- AppendUTF8toUTF16(file, aPathname);
- }
+ if (NS_SUCCEEDED(result)) {
+ AppendUTF8toUTF16(file, aPathname);
}
return result;
@@ -604,8 +602,7 @@ Location::SetPathname(const nsAString& aPathname)
return rv;
}
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri));
- if (url && NS_SUCCEEDED(url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) {
+ if (NS_SUCCEEDED(uri->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) {
return SetURI(uri);
}
diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp
index 337debcea..5511b9086 100644
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -20,6 +20,7 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMWindow.h"
+#include "nsITabChild.h"
#include "nsIContent.h"
#include "nsILoadContext.h"
#include "nsCOMArray.h"
@@ -89,8 +90,9 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
{
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext));
nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext));
- NS_ASSERTION(!requestingContext || node || window,
- "Context should be a DOM node or a DOM window!");
+ nsCOMPtr<nsITabChild> tabChild(do_QueryInterface(requestingContext));
+ NS_ASSERTION(!requestingContext || node || window || tabChild,
+ "Context should be a DOM node, DOM window or a tabChild!");
}
#endif
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index eaea49b02..fd3b52948 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2054,10 +2054,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
mFirstChild = content->GetNextSibling();
}
mChildren.RemoveChildAt(i);
+ if (content == mCachedRootElement) {
+ // Immediately clear mCachedRootElement, now that it's been removed
+ // from mChildren, so that GetRootElement() will stop returning this
+ // now-stale value.
+ mCachedRootElement = nullptr;
+ }
nsNodeUtils::ContentRemoved(this, content, i, previousSibling);
content->UnbindFromTree();
}
- mCachedRootElement = nullptr;
+ MOZ_ASSERT(!mCachedRootElement,
+ "After removing all children, there should be no root elem");
}
mInUnlinkOrDeletion = oldVal;
@@ -3913,8 +3920,18 @@ nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify)
DestroyElementMaps();
}
- doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
+ // Preemptively clear mCachedRootElement, since we may be about to remove it
+ // from our child list, and we don't want to return this maybe-obsolete value
+ // from any GetRootElement() calls that happen inside of doRemoveChildAt().
+ // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
+ // GetRootElement() calls until after it's removed the child from mChildren.
+ // Any call before that point would restore this soon-to-be-obsolete cached
+ // answer, and our clearing here would be fruitless.)
mCachedRootElement = nullptr;
+ doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
+ MOZ_ASSERT(mCachedRootElement != oldKid,
+ "Stale pointer in mCachedRootElement, after we tried to clear it "
+ "(maybe somebody called GetRootElement() too early?)");
}
void
@@ -12846,3 +12863,19 @@ nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions,
return is;
}
+
+Selection*
+nsIDocument::GetSelection(ErrorResult& aRv)
+{
+ nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow();
+ if (!window) {
+ return nullptr;
+ }
+
+ NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!");
+ if (!window->IsCurrentInnerWindow()) {
+ return nullptr;
+ }
+
+ return nsGlobalWindow::Cast(window)->GetSelection(aRv);
+}
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index 8f35e9ba5..1e0c9562e 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -151,6 +151,7 @@ class NodeIterator;
enum class OrientationType : uint32_t;
class ProcessingInstruction;
class Promise;
+class Selection;
class StyleSheetList;
class SVGDocument;
class SVGSVGElement;
@@ -898,6 +899,8 @@ public:
*/
Element* GetRootElement() const;
+ mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv);
+
/**
* Retrieve information about the viewport as a data structure.
* This will return information in the viewport META data section
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 3a649a61d..715ca93ea 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1907,6 +1907,10 @@ void
nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
nsIContent* aKid, nsAttrAndChildArray& aChildArray)
{
+ // NOTE: This function must not trigger any calls to
+ // nsIDocument::GetRootElement() calls until *after* it has removed aKid from
+ // aChildArray. Any calls before then could potentially restore a stale
+ // value for our cached root element, per note in nsDocument::RemoveChildAt().
NS_PRECONDITION(aKid && aKid->GetParentNode() == this &&
aKid == GetChildAt(aIndex) &&
IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 2546a81ad..7e19cd74d 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -855,6 +855,25 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
}
}
break;
+ case ePointerEventClass:
+ if (aEvent->IsTrusted() &&
+ aEvent->AsPointerEvent()->button == WidgetMouseEvent::eLeftButton) {
+ switch(aEvent->mMessage) {
+ case ePointerUp:
+ if (PopupAllowedForEvent("pointerup")) {
+ abuse = openControlled;
+ }
+ break;
+ case ePointerDown:
+ if (PopupAllowedForEvent("pointerdown")) {
+ abuse = openControlled;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
case eFormEventClass:
// For these following events only allow popups if they're
// triggered while handling user input. See
diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp
index a1d0675ae..65f01844b 100644
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -1056,6 +1056,11 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
LOG_EVENT_CREATION(STORAGEEVENT);
return NS_NewDOMStorageEvent(aOwner);
}
+ if (aEventType.LowerCaseEqualsLiteral("focusevent")) {
+ RefPtr<Event> event = NS_NewDOMFocusEvent(aOwner, aPresContext, nullptr);
+ event->MarkUninitialized();
+ return event.forget();
+ }
#undef LOG_EVENT_CREATION
diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini
index 5de7f27ea..af762feb2 100644
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -6,6 +6,14 @@ support-files =
pointerevent_styles.css
pointerevent_support.js
+[test_bug1285128.html]
+[test_bug1293174_implicit_pointer_capture_for_touch_1.html]
+ support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
+[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
+ support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
+[test_bug1323158.html]
+[test_empty_file.html]
+ disabled = disabled # Bug 1150091 - Issue with support-files
[test_pointerevent_attributes_mouse-manual.html]
support-files = pointerevent_attributes_mouse-manual.html
[test_pointerevent_capture_mouse-manual.html]
@@ -143,11 +151,5 @@ support-files =
pointerevent_touch-action-span-test_touch-manual.html
pointerevent_touch-action-svg-test_touch-manual.html
pointerevent_touch-action-table-test_touch-manual.html
-[test_bug1285128.html]
-[test_bug1293174_implicit_pointer_capture_for_touch_1.html]
- support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
-[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
- support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
-[test_bug1323158.html]
-[test_empty_file.html]
- disabled = disabled # Bug 1150091 - Issue with support-files
+[test_trigger_fullscreen_by_pointer_events.html]
+[test_trigger_popup_by_pointer_events.html]
diff --git a/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html
new file mode 100644
index 000000000..53d390996
--- /dev/null
+++ b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering Fullscreen by pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ let win = window.open("data:text/html,<body><div id='target' style='width: 50px; height: 50px; background: green'></div></body>", "_blank");
+ win.addEventListener("load", () => {
+ let target = win.document.getElementById("target");
+ target.addEventListener("pointerdown", () => {
+ target.requestFullscreen();
+ target.addEventListener("pointerdown", () => {
+ win.document.exitFullscreen();
+ }, {once: true});
+ }, {once: true});
+
+ win.document.addEventListener("fullscreenchange", () => {
+ if (win.document.fullscreenElement) {
+ ok(win.document.fullscreenElement, target, "fullscreenElement should be the div element");
+ // synthesize mouse events to generate pointer events and leave full screen.
+ synthesizeMouseAtCenter(target, { type: "mousedown" }, win);
+ synthesizeMouseAtCenter(target, { type: "mouseup" }, win);
+ } else {
+ win.close();
+ SimpleTest.finish();
+ }
+ });
+ // Make sure our window is focused before starting the test
+ SimpleTest.waitForFocus(() => {
+ // synthesize mouse events to generate pointer events and enter full screen.
+ synthesizeMouseAtCenter(target, { type: "mousedown" }, win);
+ synthesizeMouseAtCenter(target, { type: "mouseup" }, win);
+ }, win);
+ });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["full-screen-api.unprefix.enabled", true],
+ ["full-screen-api.allow-trusted-requests-only", false],
+ ["dom.w3c_pointer_events.enabled", true]
+ ]
+ }, startTest);
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html
new file mode 100644
index 000000000..cda279e26
--- /dev/null
+++ b/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering popup by pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="target" style="width: 50px; height: 50px; background: green"></div>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function sendMouseEvent(element, eventName, listenEventName, handler) {
+ element.addEventListener(listenEventName, handler, {once: true});
+ synthesizeMouseAtCenter(element, {type: eventName});
+}
+
+function checkAllowOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(w, "Should allow popup in the " + e.type + " listener");
+ if (w) {
+ w.close();
+ }
+}
+
+function checkBlockOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(!w, "Should block popup in the " + e.type + " listener");
+ if (w) {
+ w.close();
+ }
+}
+
+function startTest() {
+ let target = document.getElementById("target");
+ // By default, only allow opening popup in the pointerup listener.
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousedown", "pointerdown", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
+ SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
+ "pointerdown pointerup"]]}, () => {
+ // Adding pointerdown to preference should work
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
+ SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
+ "pointerdown pointerup pointermove"]]}, () => {
+ // Adding pointermove to preference should be no effect.
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
+ SimpleTest.finish();
+ });
+ });
+}
+
+const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPermissions([{'type': 'popup', 'allow': DENY_ACTION,
+ 'context': document}], () => {
+ SpecialPowers.pushPrefEnv({
+ "set": [["dom.w3c_pointer_events.enabled", true]]
+ }, startTest);
+ });
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp
index a76071bf8..3b3ada6d3 100644
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -104,7 +104,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
return nullptr;
}
- Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams> body;
+ Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>> body;
ResponseInit init;
init.mStatus = aStatus;
RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
@@ -125,7 +125,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
/*static*/ already_AddRefed<Response>
Response::Constructor(const GlobalObject& aGlobal,
- const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
+ const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
const ResponseInit& aInit, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@@ -191,7 +191,7 @@ Response::Constructor(const GlobalObject& aGlobal,
}
}
- if (aBody.WasPassed()) {
+ if (aBody.WasPassed() && !aBody.Value().IsNull()) {
if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
return nullptr;
@@ -200,7 +200,7 @@ Response::Constructor(const GlobalObject& aGlobal,
nsCOMPtr<nsIInputStream> bodyStream;
nsCString contentType;
uint64_t bodySize = 0;
- aRv = ExtractByteStreamFromBody(aBody.Value(),
+ aRv = ExtractByteStreamFromBody(aBody.Value().Value(),
getter_AddRefs(bodyStream),
contentType,
bodySize);
diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h
index 64b3c5f45..de367bef6 100644
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -114,7 +114,7 @@ public:
static already_AddRefed<Response>
Constructor(const GlobalObject& aGlobal,
- const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
+ const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
const ResponseInit& aInit, ErrorResult& rv);
nsIGlobalObject* GetParentObject() const
diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp
index be5a34d41..69e710242 100644
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -2149,26 +2149,10 @@ NS_IMETHODIMP
nsHTMLDocument::GetSelection(nsISelection** aReturn)
{
ErrorResult rv;
- NS_IF_ADDREF(*aReturn = GetSelection(rv));
+ NS_IF_ADDREF(*aReturn = nsDocument::GetSelection(rv));
return rv.StealNSResult();
}
-Selection*
-nsHTMLDocument::GetSelection(ErrorResult& aRv)
-{
- nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
- if (!window) {
- return nullptr;
- }
-
- NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!");
- if (!window->IsCurrentInnerWindow()) {
- return nullptr;
- }
-
- return nsGlobalWindow::Cast(window)->GetSelection(aRv);
-}
-
NS_IMETHODIMP
nsHTMLDocument::CaptureEvents()
{
diff --git a/dom/html/nsHTMLDocument.h b/dom/html/nsHTMLDocument.h
index 426ebddc5..1fa81f6cd 100644
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -242,7 +242,6 @@ public:
{
// Deprecated
}
- mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv);
// The XPCOM CaptureEvents works fine for us.
// The XPCOM ReleaseEvents works fine for us.
// We're picking up GetLocation from Document
diff --git a/dom/indexedDB/test/browser_forgetThisSite.js b/dom/indexedDB/test/browser_forgetThisSite.js
index c1177908f..02674922f 100644
--- a/dom/indexedDB/test/browser_forgetThisSite.js
+++ b/dom/indexedDB/test/browser_forgetThisSite.js
@@ -67,9 +67,10 @@ function test2()
function test3()
{
// Remove database from domain 2
- ForgetAboutSite.removeDataFromDomain(domains[1]);
- setPermission(testPageURL4, "indexedDB");
- executeSoon(test4);
+ ForgetAboutSite.removeDataFromDomain(domains[1]).then(() => {
+ setPermission(testPageURL4, "indexedDB");
+ executeSoon(test4);
+ });
}
function test4()
diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties
index 8b66cc265..c0b80996c 100644
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -81,3 +81,6 @@ MimeTypeMismatch=The resource from “%1$S” was blocked due to MIME type misma
XCTOHeaderValueMissing=X-Content-Type-Options header warning: value was “%1$S”; did you mean to send “nosniff”?
BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type.
+
+# LOCALIZATION NOTE: Do not translate "data: URI".
+BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp
index a7517f65e..979bd915f 100644
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -171,9 +171,10 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
}
}
- // aExtra is only non-null if the channel got redirected.
- bool wasRedirected = (aExtra != nullptr);
+ // aExtra holds the original URI of the channel if the
+ // channel got redirected (until we fix Bug 1332422).
nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
+ bool wasRedirected = originalURI;
bool permitted = permitsInternal(dir,
aContentLocation,
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index c4e1ed8e1..0cc4933fe 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -1,8 +1,10 @@
#include "nsContentSecurityManager.h"
+#include "nsEscape.h"
#include "nsIChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIStreamListener.h"
#include "nsILoadInfo.h"
+#include "nsIOService.h"
#include "nsContentUtils.h"
#include "nsCORSListenerProxy.h"
#include "nsIStreamListener.h"
@@ -10,11 +12,86 @@
#include "nsMixedContentBlocker.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabChild.h"
NS_IMPL_ISUPPORTS(nsContentSecurityManager,
nsIContentSecurityManager,
nsIChannelEventSink)
+/* static */ bool
+nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel)
+{
+ // Let's block all toplevel document navigations to a data: URI.
+ // In all cases where the toplevel document is navigated to a
+ // data: URI the triggeringPrincipal is a codeBasePrincipal, or
+ // a NullPrincipal. In other cases, e.g. typing a data: URL into
+ // the URL-Bar, the triggeringPrincipal is a SystemPrincipal;
+ // we don't want to block those loads. Only exception, loads coming
+ // from an external applicaton (e.g. Thunderbird) don't load
+ // using a codeBasePrincipal, but we want to block those loads.
+ if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) {
+ return true;
+ }
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ if (!loadInfo) {
+ return true;
+ }
+ if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
+ return true;
+ }
+ if (loadInfo->GetForceAllowDataURI()) {
+ // if the loadinfo explicitly allows the data URI navigation, let's allow it now
+ return true;
+ }
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, true);
+ bool isDataURI =
+ (NS_SUCCEEDED(uri->SchemeIs("data", &isDataURI)) && isDataURI);
+ if (!isDataURI) {
+ return true;
+ }
+ // Whitelist data: images as long as they are not SVGs
+ nsAutoCString filePath;
+ uri->GetFilePath(filePath);
+ if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) &&
+ !StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) {
+ return true;
+ }
+ // Whitelist data: PDFs and JSON
+ if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/pdf")) ||
+ StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/json"))) {
+ return true;
+ }
+ // Redirecting to a toplevel data: URI is not allowed, hence we make
+ // sure the RedirectChain is empty.
+ if (!loadInfo->GetLoadTriggeredFromExternal() &&
+ nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal()) &&
+ loadInfo->RedirectChain().IsEmpty()) {
+ return true;
+ }
+ nsAutoCString dataSpec;
+ uri->GetSpec(dataSpec);
+ if (dataSpec.Length() > 50) {
+ dataSpec.Truncate(50);
+ dataSpec.AppendLiteral("...");
+ }
+ nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(loadInfo->ContextForTopLevelLoad());
+ nsCOMPtr<nsIDocument> doc;
+ if (tabChild) {
+ doc = static_cast<mozilla::dom::TabChild*>(tabChild.get())->GetDocument();
+ }
+ NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
+ const char16_t* params[] = { specUTF16.get() };
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("DATA_URI_BLOCKED"),
+ doc,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "BlockTopLevelDataURINavigation",
+ params, ArrayLength(params));
+ return false;
+}
+
static nsresult
ValidateSecurityFlags(nsILoadInfo* aLoadInfo)
{
@@ -176,7 +253,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
nsContentPolicyType internalContentPolicyType =
aLoadInfo->InternalContentPolicyType();
nsCString mimeTypeGuess;
- nsCOMPtr<nsINode> requestingContext = nullptr;
+ nsCOMPtr<nsISupports> requestingContext = nullptr;
#ifdef DEBUG
// Don't enforce TYPE_DOCUMENT assertions for loads
@@ -250,10 +327,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_XMLHTTPREQUEST: {
// alias nsIContentPolicy::TYPE_DATAREQUEST:
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_xml requires requestingContext of type Document");
-
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_xml requires requestingContext of type Document");
+ }
+#endif
// We're checking for the external TYPE_XMLHTTPREQUEST here in case
// an addon creates a request with that type.
if (internalContentPolicyType ==
@@ -274,18 +354,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE,
- "type_subrequest requires requestingContext of type Element");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE,
+ "type_subrequest requires requestingContext of type Element");
+ }
+#endif
break;
}
case nsIContentPolicy::TYPE_DTD: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_dtd requires requestingContext of type Document");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_dtd requires requestingContext of type Document");
+ }
+#endif
break;
}
@@ -303,9 +391,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
mimeTypeGuess = EmptyCString();
}
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE,
- "type_media requires requestingContext of type Element");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE,
+ "type_media requires requestingContext of type Element");
+ }
+#endif
break;
}
@@ -332,18 +424,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_XSLT: {
mimeTypeGuess = NS_LITERAL_CSTRING("application/xml");
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_xslt requires requestingContext of type Document");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_xslt requires requestingContext of type Document");
+ }
+#endif
break;
}
case nsIContentPolicy::TYPE_BEACON: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_beacon requires requestingContext of type Document");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_beacon requires requestingContext of type Document");
+ }
+#endif
break;
}
diff --git a/dom/security/nsContentSecurityManager.h b/dom/security/nsContentSecurityManager.h
index 912c0e89f..bab847743 100644
--- a/dom/security/nsContentSecurityManager.h
+++ b/dom/security/nsContentSecurityManager.h
@@ -32,6 +32,8 @@ public:
static nsresult doContentSecurityCheck(nsIChannel* aChannel,
nsCOMPtr<nsIStreamListener>& aInAndOutListener);
+ static bool AllowTopLevelNavigationToDataURI(nsIChannel* aChannel);
+
private:
static nsresult CheckChannel(nsIChannel* aChannel);
diff --git a/dom/security/test/general/browser.ini b/dom/security/test/general/browser.ini
new file mode 100644
index 000000000..b00baa95d
--- /dev/null
+++ b/dom/security/test/general/browser.ini
@@ -0,0 +1,14 @@
+[DEFAULT]
+[browser_test_toplevel_data_navigations.js]
+support-files =
+ file_toplevel_data_navigations.sjs
+ file_toplevel_data_meta_redirect.html
+[browser_test_data_download.js]
+support-files =
+ file_data_download.html
+[browser_test_data_text_csv.js]
+support-files =
+ file_data_text_csv.html
+[browser_test_view_image_data_navigation.js]
+support-files =
+ file_view_image_data_navigation.html
diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js
new file mode 100644
index 000000000..1ee8d5844
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_download.js
@@ -0,0 +1,37 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kTestURI = kTestPath + "file_data_download.html";
+
+function addWindowListener(aURL, aCallback) {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ waitForFocus(function() {
+ is(domwindow.document.location.href, aURL, "should have seen the right window open");
+ aCallback(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) { },
+ onWindowTitleChange(aXULWindow, aNewTitle) { }
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+ });
+ addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
+ is(win.document.getElementById("location").value, "data-foo.html",
+ "file name of download should match");
+ win.close();
+ finish();
+ });
+ gBrowser.loadURI(kTestURI);
+}
diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js
new file mode 100644
index 000000000..c45e40cc2
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_text_csv.js
@@ -0,0 +1,37 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kTestURI = kTestPath + "file_data_text_csv.html";
+
+function addWindowListener(aURL, aCallback) {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ waitForFocus(function() {
+ is(domwindow.document.location.href, aURL, "should have seen the right window open");
+ aCallback(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) { },
+ onWindowTitleChange(aXULWindow, aNewTitle) { }
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+ });
+ addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
+ is(win.document.getElementById("location").value, "text/csv;foo,bar,foobar",
+ "file name of download should match");
+ win.close();
+ finish();
+ });
+ gBrowser.loadURI(kTestURI);
+}
diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js
new file mode 100644
index 000000000..a13a6350e
--- /dev/null
+++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js
@@ -0,0 +1,54 @@
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+"use strict";
+
+const kDataBody = "toplevel navigation to data: URI allowed";
+const kDataURI = "data:text/html,<body>" + kDataBody + "</body>";
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kRedirectURI = kTestPath + "file_toplevel_data_navigations.sjs";
+const kMetaRedirectURI = kTestPath + "file_toplevel_data_meta_redirect.html";
+
+add_task(async function test_nav_data_uri() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ await BrowserTestUtils.withNewTab(kDataURI, async function(browser) {
+ await ContentTask.spawn(gBrowser.selectedBrowser, {kDataBody}, async function({kDataBody}) { // eslint-disable-line
+ is(content.document.body.innerHTML, kDataBody,
+ "data: URI navigation from system should be allowed");
+ });
+ });
+});
+
+add_task(async function test_nav_data_uri_redirect() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ let tab = BrowserTestUtils.addTab(gBrowser, kRedirectURI);
+ registerCleanupFunction(async function() {
+ await BrowserTestUtils.removeTab(tab);
+ });
+ // wait to make sure data: URI did not load before checking that it got blocked
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
+ is(content.document.body.innerHTML, "",
+ "data: URI navigation after server redirect should be blocked");
+ });
+});
+
+add_task(async function test_nav_data_uri_meta_redirect() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ let tab = BrowserTestUtils.addTab(gBrowser, kMetaRedirectURI);
+ registerCleanupFunction(async function() {
+ await BrowserTestUtils.removeTab(tab);
+ });
+ // wait to make sure data: URI did not load before checking that it got blocked
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
+ is(content.document.body.innerHTML, "",
+ "data: URI navigation after meta redirect should be blocked");
+ });
+});
diff --git a/dom/security/test/general/browser_test_view_image_data_navigation.js b/dom/security/test/general/browser_test_view_image_data_navigation.js
new file mode 100644
index 000000000..22de35894
--- /dev/null
+++ b/dom/security/test/general/browser_test_view_image_data_navigation.js
@@ -0,0 +1,30 @@
+"use strict";
+
+const TEST_PAGE = getRootDirectory(gTestPath) + "file_view_image_data_navigation.html";
+
+add_task(async function test_principal_right_click_open_link_in_new_tab() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+
+ await BrowserTestUtils.withNewTab(TEST_PAGE, async function(browser) {
+ let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, true);
+
+ // simulate right-click->view-image
+ BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
+ // These are operations that must be executed synchronously with the event.
+ document.getElementById("context-viewimage").doCommand();
+ event.target.hidePopup();
+ return true;
+ });
+ BrowserTestUtils.synthesizeMouseAtCenter("#testimage",
+ { type: "contextmenu", button: 2 },
+ gBrowser.selectedBrowser);
+ await loadPromise;
+
+ await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
+ ok(content.document.location.toString().startsWith("data:image/svg+xml;"),
+ "data:image/svg navigation allowed through right-click view-image")
+ });
+ });
+});
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation.html b/dom/security/test/general/file_block_toplevel_data_navigation.html
new file mode 100644
index 000000000..5fbfdfdef
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test1: clicking data: URI tries to navigate window<br/>
+<a id="testlink" href="data:text/html,<body>toplevel data: URI navigations should be blocked</body>">click me</a>
+<script>
+ document.getElementById('testlink').click();
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation2.html b/dom/security/test/general/file_block_toplevel_data_navigation2.html
new file mode 100644
index 000000000..e0308e1ae
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation2.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test2: data: URI in iframe tries to window.open(data:, _blank);<br/>
+<iframe id="testFrame" src=""></iframe>
+<script>
+ let DATA_URI = `data:text/html,<body><script>
+ var win = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", "_blank");
+ setTimeout(function () {
+ var result = win.document.body.innerHTML === "" ? "blocked" : "navigated";
+ parent.postMessage(result, "*");
+ win.close();
+ }, 1000);
+ <\/script></body>`;
+
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ // propagate the information back to the caller
+ window.opener.postMessage(event.data, "*");
+ }
+ document.getElementById('testFrame').src = DATA_URI;
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation3.html b/dom/security/test/general/file_block_toplevel_data_navigation3.html
new file mode 100644
index 000000000..34aeddab3
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation3.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test3: performing data: URI navigation through win.loc.href<br/>
+<script>
+ window.location.href = "data:text/html,<body>toplevel data: URI navigations should be blocked</body>";
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_redirect.sjs b/dom/security/test/general/file_block_toplevel_data_redirect.sjs
new file mode 100644
index 000000000..64e294cab
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_redirect.sjs
@@ -0,0 +1,14 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1394554 - Block toplevel data: URI navigations after redirect
+
+var DATA_URI =
+ "<body>toplevel data: URI navigations after redirect should be blocked</body>";
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", "data:text/html," + escape(DATA_URI), false);
+}
diff --git a/dom/security/test/general/file_data_download.html b/dom/security/test/general/file_data_download.html
new file mode 100644
index 000000000..4cc92fe8f
--- /dev/null
+++ b/dom/security/test/general/file_data_download.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test download attribute for data: URI</title>
+</head>
+<body>
+ <a href="data:text/html,<body>data download</body>" download="data-foo.html" id="testlink">download data</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_data_text_csv.html b/dom/security/test/general/file_data_text_csv.html
new file mode 100644
index 000000000..a9ac369d1
--- /dev/null
+++ b/dom/security/test/general/file_data_text_csv.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test open data:text/csv</title>
+</head>
+<body>
+ <a href="data:text/csv;foo,bar,foobar" id="testlink">test text/csv</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_toplevel_data_meta_redirect.html b/dom/security/test/general/file_toplevel_data_meta_redirect.html
new file mode 100644
index 000000000..f4f5deb52
--- /dev/null
+++ b/dom/security/test/general/file_toplevel_data_meta_redirect.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+<head>
+ <meta http-equiv="refresh"
+ content="0; url='data:text/html,<body>toplevel meta redirect to data: URI should be blocked</body>'">
+</head>
+<body>
+Meta Redirect to data: URI
+</body>
+</html>
diff --git a/dom/security/test/general/file_toplevel_data_navigations.sjs b/dom/security/test/general/file_toplevel_data_navigations.sjs
new file mode 100644
index 000000000..501b833e5
--- /dev/null
+++ b/dom/security/test/general/file_toplevel_data_navigations.sjs
@@ -0,0 +1,14 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1394554 - Block toplevel data: URI navigations after redirect
+
+var DATA_URI =
+ "data:text/html,<body>toplevel data: URI navigations after redirect should be blocked</body>";
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", DATA_URI, false);
+}
diff --git a/dom/security/test/general/file_view_image_data_navigation.html b/dom/security/test/general/file_view_image_data_navigation.html
new file mode 100644
index 000000000..a3f9acfb4
--- /dev/null
+++ b/dom/security/test/general/file_view_image_data_navigation.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1407891: Test navigation for right-click view-image on data:image/svg</title>
+</head>
+<body>
+
+<img id="testimage" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg=="></img>
+
+</body>
+</html>
diff --git a/dom/security/test/general/mochitest.ini b/dom/security/test/general/mochitest.ini
index 70c0c9fb6..f3bcca072 100644
--- a/dom/security/test/general/mochitest.ini
+++ b/dom/security/test/general/mochitest.ini
@@ -3,7 +3,19 @@ support-files =
file_contentpolicytype_targeted_link_iframe.sjs
file_nosniff_testserver.sjs
file_block_script_wrong_mime_server.sjs
+ file_block_toplevel_data_navigation.html
+ file_block_toplevel_data_navigation2.html
+ file_block_toplevel_data_navigation3.html
+ file_block_toplevel_data_redirect.sjs
[test_contentpolicytype_targeted_link_iframe.html]
[test_nosniff.html]
[test_block_script_wrong_mime.html]
+[test_block_toplevel_data_navigation.html]
+skip-if = toolkit == 'android' # intermittent failure
+[test_block_toplevel_data_img_navigation.html]
+skip-if = toolkit == 'android' # intermittent failure
+[test_allow_opening_data_pdf.html]
+skip-if = toolkit == 'android'
+[test_allow_opening_data_json.html]
+skip-if = toolkit == 'android'
diff --git a/dom/security/test/general/test_allow_opening_data_json.html b/dom/security/test/general/test_allow_opening_data_json.html
new file mode 100644
index 000000000..1530a24e8
--- /dev/null
+++ b/dom/security/test/general/test_allow_opening_data_json.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1403814: Allow toplevel data URI navigation data:application/json</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test_toplevel_data_json() {
+ const DATA_JSON = "data:application/json,{'my_json_key':'my_json_value'}";
+
+ let win = window.open(DATA_JSON);
+ let wrappedWin = SpecialPowers.wrap(win);
+
+ // Unfortunately we can't detect whether the JSON has loaded or not using some
+ // event, hence we are constantly polling location.href till we see that
+ // the data: URI appears. Test times out on failure.
+ var jsonLoaded = setInterval(function() {
+ if (wrappedWin.document.location.href.startsWith("data:application/json")) {
+ clearInterval(jsonLoaded);
+ ok(true, "navigating to data:application/json allowed");
+ wrappedWin.close();
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+
+SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
+}, test_toplevel_data_json);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_allow_opening_data_pdf.html b/dom/security/test/general/test_allow_opening_data_pdf.html
new file mode 100644
index 000000000..6b51fe57b
--- /dev/null
+++ b/dom/security/test/general/test_allow_opening_data_pdf.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1398692: Allow toplevel navigation to a data:application/pdf</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test_toplevel_data_pdf() {
+ // The PDF contains one page and it is a 3/72" square, the minimum allowed by the spec
+ const DATA_PDF =
+ "data:application/pdf;base64,JVBERi0xLjANCjEgMCBvYmo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PmVuZG9iaiAyIDAgb2JqPDwvVHlwZS9QYWdlcy9LaWRzWzMgMCBSXS9Db3VudCAxPj5lbmRvYmogMyAwIG9iajw8L1R5cGUvUGFnZS9NZWRpYUJveFswIDAgMyAzXT4+ZW5kb2JqDQp4cmVmDQowIDQNCjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxMCAwMDAwMCBuDQowMDAwMDAwMDUzIDAwMDAwIG4NCjAwMDAwMDAxMDIgMDAwMDAgbg0KdHJhaWxlcjw8L1NpemUgNC9Sb290IDEgMCBSPj4NCnN0YXJ0eHJlZg0KMTQ5DQolRU9G";
+
+ let win = window.open(DATA_PDF);
+ let wrappedWin = SpecialPowers.wrap(win);
+
+ // Unfortunately we can't detect whether the PDF has loaded or not using some
+ // event, hence we are constantly polling location.href till we see that
+ // the data: URI appears. Test times out on failure.
+ var pdfLoaded = setInterval(function() {
+ if (wrappedWin.document.location.href.startsWith("data:application/pdf")) {
+ clearInterval(pdfLoaded);
+ ok(true, "navigating to data:application/pdf allowed");
+ wrappedWin.close();
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+
+SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
+}, test_toplevel_data_pdf);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_toplevel_data_img_navigation.html b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
new file mode 100644
index 000000000..7f8dfc748
--- /dev/null
+++ b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1396798: Do not block toplevel data: navigation to image (except svgs)</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+SimpleTest.registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("have to test that top level data:image loading is blocked/allowed");
+
+function test_toplevel_data_image() {
+ const DATA_PNG =
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+ let win1 = window.open(DATA_PNG);
+ let wrappedWin1 = SpecialPowers.wrap(win1);
+ setTimeout(function () {
+ let images = wrappedWin1.document.getElementsByTagName('img');
+ is(images.length, 1, "Loading data:image/png should be allowed");
+ is(images[0].src, DATA_PNG, "Sanity: img src matches");
+ wrappedWin1.close();
+ test_toplevel_data_image_svg();
+ }, 1000);
+}
+
+function test_toplevel_data_image_svg() {
+ const DATA_SVG =
+ "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==";
+ let win2 = window.open(DATA_SVG);
+ // Unfortunately we can't detect whether the window was closed using some event,
+ // hence we are constantly polling till we see that win == null.
+ // Test times out on failure.
+ var win2Closed = setInterval(function() {
+ if (win2 == null || win2.closed) {
+ clearInterval(win2Closed);
+ ok(true, "Loading data:image/svg+xml should be blocked");
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+// fire up the tests
+test_toplevel_data_image();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html
new file mode 100644
index 000000000..cef232b65
--- /dev/null
+++ b/dom/security/test/general/test_block_toplevel_data_navigation.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1331351 - Block top level window data: URI navigations</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+SimpleTest.registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("have to test that top level data: URI navgiation is blocked");
+
+function test1() {
+ // simple data: URI click navigation should be prevented
+ let TEST_FILE = "file_block_toplevel_data_navigation.html";
+ let win1 = window.open(TEST_FILE);
+ setTimeout(function () {
+ ok(SpecialPowers.wrap(win1).document.body.innerHTML.indexOf("test1:") !== -1,
+ "toplevel data: URI navigation through click() should be blocked");
+ win1.close();
+ test2();
+ }, 1000);
+}
+
+function test2() {
+ // data: URI in iframe which opens data: URI in _blank should be blocked
+ let win2 = window.open("file_block_toplevel_data_navigation2.html");
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ is(event.data, "blocked",
+ "data: URI navigation using _blank from data: URI should be blocked");
+ win2.close();
+ test3();
+ }
+}
+
+function test3() {
+ // navigating to a data: URI using window.location.href should be blocked
+ let win3 = window.open("file_block_toplevel_data_navigation3.html");
+ setTimeout(function () {
+ ok(win3.document.body.innerHTML.indexOf("test3:") !== -1,
+ "data: URI navigation through win.loc.href should be blocked");
+ win3.close();
+ test4();
+ }, 1000);
+}
+
+function test4() {
+ // navigating to a data: URI using window.open() should be blocked
+ let win4 = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>");
+ setTimeout(function () {
+ // Please note that the data: URI will be displayed in the URL-Bar but not
+ // loaded, hence we rather rely on document.body than document.location
+ is(win4.document.body.innerHTML, "",
+ "navigating to a data: URI using window.open() should be blocked");
+ test5();
+ }, 1000);
+}
+
+function test5() {
+ // navigating to a URI which redirects to a data: URI using window.open() should be blocked
+ let win5 = window.open("file_block_toplevel_data_redirect.sjs");
+ setTimeout(function () {
+ // Please note that the data: URI will be displayed in the URL-Bar but not
+ // loaded, hence we rather rely on document.body than document.location
+ is(SpecialPowers.wrap(win5).document.body.innerHTML, "",
+ "navigating to URI which redirects to a data: URI using window.open() should be blocked");
+ win5.close();
+ SimpleTest.finish();
+ }, 1000);
+}
+
+// fire up the tests
+test1();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
index 7b1ab72dc..3ef243824 100644
--- a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
+++ b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
@@ -61,6 +61,7 @@ var policy = {
"content policy type should TYPESUBDOCUMENT");
categoryManager.deleteCategoryEntry("content-policy", POLICYNAME, false);
SimpleTest.finish();
+ return Ci.nsIContentPolicy.REJECT_REQUEST;
}
return Ci.nsIContentPolicy.ACCEPT;
},
diff --git a/dom/security/test/moz.build b/dom/security/test/moz.build
index ddb4e9b89..946959dee 100644
--- a/dom/security/test/moz.build
+++ b/dom/security/test/moz.build
@@ -27,5 +27,6 @@ MOCHITEST_CHROME_MANIFESTS += [
BROWSER_CHROME_MANIFESTS += [
'contentverifier/browser.ini',
'csp/browser.ini',
+ 'general/browser.ini',
'hsts/browser.ini',
]
diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp
index 1f15e1151..c8724c359 100644
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -17,7 +17,6 @@
#include "nsEscape.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsIIOService.h"
-#include "nsIURIWithQuery.h"
#include "nsIURL.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
@@ -525,21 +524,10 @@ URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
// Do not throw! Not having a valid URI or URL should result in an empty
// string.
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
- if (url) {
- nsAutoCString file;
- nsresult rv = url->GetFilePath(file);
- if (NS_SUCCEEDED(rv)) {
- CopyUTF8toUTF16(file, aPathname);
- }
-
- return;
- }
-
- nsAutoCString path;
- nsresult rv = mURI->GetPath(path);
+ nsAutoCString file;
+ nsresult rv = mURI->GetFilePath(file);
if (NS_SUCCEEDED(rv)) {
- CopyUTF8toUTF16(path, aPathname);
+ CopyUTF8toUTF16(file, aPathname);
}
}
@@ -548,11 +536,7 @@ URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
{
// Do not throw!
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
- if (url) {
- url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
- return;
- }
+ mURI->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
}
void
@@ -566,13 +550,9 @@ URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
nsAutoCString search;
nsresult rv;
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
- if (url) {
- rv = url->GetQuery(search);
- if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
- CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
- }
- return;
+ rv = mURI->GetQuery(search);
+ if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
+ CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
}
}
@@ -603,11 +583,7 @@ URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
{
// Ignore failures to be compatible with NS4.
- nsCOMPtr<nsIURIWithQuery> uriWithQuery(do_QueryInterface(mURI));
- if (uriWithQuery) {
- uriWithQuery->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
- return;
- }
+ mURI->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
}
} // anonymous namespace
diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl
index f05656e84..0b8c278fe 100644
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -430,6 +430,12 @@ partial interface Document {
void removeAnonymousContent(AnonymousContent aContent);
};
+// http://w3c.github.io/selection-api/#extensions-to-document-interface
+partial interface Document {
+ [Throws]
+ Selection? getSelection();
+};
+
// Extension to give chrome JS the ability to determine whether
// the user has interacted with the document or not.
partial interface Document {
diff --git a/dom/webidl/HTMLDocument.webidl b/dom/webidl/HTMLDocument.webidl
index 61b466ff0..42f6d98f7 100644
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -73,10 +73,6 @@ interface HTMLDocument : Document {
readonly attribute HTMLAllCollection all;
- // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections
- [Throws]
- Selection? getSelection();
-
// @deprecated These are old Netscape 4 methods. Do not use,
// the implementation is no-op.
// XXXbz do we actually need these anymore?
diff --git a/dom/webidl/Response.webidl b/dom/webidl/Response.webidl
index 8713146aa..08f31fe29 100644
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -7,7 +7,7 @@
* https://fetch.spec.whatwg.org/#response-class
*/
-[Constructor(optional BodyInit body, optional ResponseInit init),
+[Constructor(optional BodyInit? body, optional ResponseInit init),
Exposed=(Window,Worker)]
interface Response {
[NewObject] static Response error();
diff --git a/dom/webidl/Selection.webidl b/dom/webidl/Selection.webidl
index c90844dfa..c3eac016c 100644
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -33,6 +33,7 @@ interface Selection {
void deleteFromDocument();
readonly attribute unsigned long rangeCount;
+ readonly attribute DOMString type;
[Throws]
Range getRangeAt(unsigned long index);
[Throws]
@@ -77,7 +78,7 @@ partial interface Selection {
void removeSelectionListener(nsISelectionListener listenerToRemove);
[ChromeOnly,BinaryName="rawType"]
- readonly attribute short type;
+ readonly attribute short selectionType;
[ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"]
sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset,