Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / base / PostMessageEvent.cpp
blobc01507153cb061bbbc433ddaa236e0e587e7b2f0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "PostMessageEvent.h"
9 #include "MessageEvent.h"
10 #include "mozilla/dom/BlobBinding.h"
11 #include "mozilla/dom/DocumentInlines.h"
12 #include "mozilla/dom/File.h"
13 #include "mozilla/dom/FileList.h"
14 #include "mozilla/dom/FileListBinding.h"
15 #include "mozilla/dom/MessageEventBinding.h"
16 #include "mozilla/dom/MessagePort.h"
17 #include "mozilla/dom/MessagePortBinding.h"
18 #include "mozilla/dom/PMessagePort.h"
19 #include "mozilla/dom/StructuredCloneTags.h"
20 #include "mozilla/dom/UnionConversions.h"
21 #include "mozilla/EventDispatcher.h"
22 #include "nsDocShell.h"
23 #include "nsGlobalWindow.h"
24 #include "nsIConsoleService.h"
25 #include "nsIPrincipal.h"
26 #include "nsIScriptError.h"
27 #include "nsNetUtil.h"
28 #include "nsPresContext.h"
29 #include "nsQueryObject.h"
31 namespace mozilla {
32 namespace dom {
34 PostMessageEvent::PostMessageEvent(BrowsingContext* aSource,
35 const nsAString& aCallerOrigin,
36 nsGlobalWindowOuter* aTargetWindow,
37 nsIPrincipal* aProvidedPrincipal,
38 const Maybe<uint64_t>& aCallerWindowID,
39 nsIURI* aCallerDocumentURI,
40 bool aIsFromPrivateWindow)
41 : Runnable("dom::PostMessageEvent"),
42 mSource(aSource),
43 mCallerOrigin(aCallerOrigin),
44 mTargetWindow(aTargetWindow),
45 mProvidedPrincipal(aProvidedPrincipal),
46 mCallerWindowID(aCallerWindowID),
47 mCallerDocumentURI(aCallerDocumentURI),
48 mIsFromPrivateWindow(aIsFromPrivateWindow) {}
50 PostMessageEvent::~PostMessageEvent() {}
52 NS_IMETHODIMP
53 PostMessageEvent::Run() {
54 // Note: We don't init this AutoJSAPI with targetWindow, because we do not
55 // want exceptions during message deserialization to trigger error events on
56 // targetWindow.
57 AutoJSAPI jsapi;
58 jsapi.Init();
59 JSContext* cx = jsapi.cx();
61 // The document URI is just used for the principal mismatch error message
62 // below. Use a stack variable so mCallerDocumentURI is not held onto after
63 // this method finishes, regardless of the method outcome.
64 nsCOMPtr<nsIURI> callerDocumentURI = mCallerDocumentURI.forget();
66 // If we bailed before this point we're going to leak mMessage, but
67 // that's probably better than crashing.
69 RefPtr<nsGlobalWindowInner> targetWindow;
70 if (mTargetWindow->IsClosedOrClosing() ||
71 !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
72 targetWindow->IsDying())
73 return NS_OK;
75 JSAutoRealm ar(cx, targetWindow->GetWrapper());
77 // Ensure that any origin which might have been provided is the origin of this
78 // window's document. Note that we do this *now* instead of when postMessage
79 // is called because the target window might have been navigated to a
80 // different location between then and now. If this check happened when
81 // postMessage was called, it would be fairly easy for a malicious webpage to
82 // intercept messages intended for another site by carefully timing navigation
83 // of the target window so it changed location after postMessage but before
84 // now.
85 if (mProvidedPrincipal) {
86 // Get the target's origin either from its principal or, in the case the
87 // principal doesn't carry a URI (e.g. the system principal), the target's
88 // document.
89 nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
90 if (NS_WARN_IF(!targetPrin)) return NS_OK;
92 // Note: This is contrary to the spec with respect to file: URLs, which
93 // the spec groups into a single origin, but given we intentionally
94 // don't do that in other places it seems better to hold the line for
95 // now. Long-term, we want HTML5 to address this so that we can
96 // be compliant while being safer.
97 if (!targetPrin->Equals(mProvidedPrincipal)) {
98 OriginAttributes sourceAttrs = mProvidedPrincipal->OriginAttributesRef();
99 OriginAttributes targetAttrs = targetPrin->OriginAttributesRef();
101 MOZ_DIAGNOSTIC_ASSERT(
102 sourceAttrs.mUserContextId == targetAttrs.mUserContextId,
103 "Target and source should have the same userContextId attribute.");
104 MOZ_DIAGNOSTIC_ASSERT(sourceAttrs.mInIsolatedMozBrowser ==
105 targetAttrs.mInIsolatedMozBrowser,
106 "Target and source should have the same "
107 "inIsolatedMozBrowser attribute.");
109 nsAutoString providedOrigin, targetOrigin;
110 nsresult rv = nsContentUtils::GetUTFOrigin(targetPrin, targetOrigin);
111 NS_ENSURE_SUCCESS(rv, rv);
112 rv = nsContentUtils::GetUTFOrigin(mProvidedPrincipal, providedOrigin);
113 NS_ENSURE_SUCCESS(rv, rv);
115 const char16_t* params[] = {providedOrigin.get(), targetOrigin.get()};
117 nsAutoString errorText;
118 nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
119 "TargetPrincipalDoesNotMatch",
120 params, errorText);
122 nsCOMPtr<nsIScriptError> errorObject =
123 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
124 NS_ENSURE_SUCCESS(rv, rv);
126 if (mCallerWindowID.isSome()) {
127 rv = errorObject->InitWithSourceURI(
128 errorText, callerDocumentURI, EmptyString(), 0, 0,
129 nsIScriptError::errorFlag, "DOM Window", mCallerWindowID.value());
130 } else {
131 nsString uriSpec;
132 rv = NS_GetSanitizedURIStringFromURI(callerDocumentURI, uriSpec);
133 NS_ENSURE_SUCCESS(rv, rv);
135 rv = errorObject->Init(
136 errorText, uriSpec, EmptyString(), 0, 0, nsIScriptError::errorFlag,
137 "DOM Window", mIsFromPrivateWindow,
138 nsContentUtils::IsSystemPrincipal(mProvidedPrincipal));
140 NS_ENSURE_SUCCESS(rv, rv);
142 nsCOMPtr<nsIConsoleService> consoleService =
143 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
144 NS_ENSURE_SUCCESS(rv, rv);
146 return consoleService->LogMessage(errorObject);
150 IgnoredErrorResult rv;
151 JS::Rooted<JS::Value> messageData(cx);
152 nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
153 do_QueryObject(targetWindow);
155 StructuredCloneHolder* holder;
156 if (mHolder.constructed<StructuredCloneHolder>()) {
157 mHolder.ref<StructuredCloneHolder>().Read(ToSupports(targetWindow), cx,
158 &messageData, rv);
159 holder = &mHolder.ref<StructuredCloneHolder>();
160 } else {
161 MOZ_ASSERT(mHolder.constructed<ipc::StructuredCloneData>());
162 mHolder.ref<ipc::StructuredCloneData>().Read(cx, &messageData, rv);
163 holder = &mHolder.ref<ipc::StructuredCloneData>();
165 if (NS_WARN_IF(rv.Failed())) {
166 DispatchError(cx, targetWindow, eventTarget);
167 return NS_OK;
170 // Create the event
171 RefPtr<MessageEvent> event = new MessageEvent(eventTarget, nullptr, nullptr);
173 Nullable<WindowProxyOrMessagePortOrServiceWorker> source;
174 if (mSource) {
175 source.SetValue().SetAsWindowProxy() = mSource;
178 Sequence<OwningNonNull<MessagePort>> ports;
179 if (!holder->TakeTransferredPortsAsSequence(ports)) {
180 DispatchError(cx, targetWindow, eventTarget);
181 return NS_OK;
184 event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"), CanBubble::eNo,
185 Cancelable::eNo, messageData, mCallerOrigin,
186 EmptyString(), source, ports);
188 Dispatch(targetWindow, event);
189 return NS_OK;
192 void PostMessageEvent::DispatchError(JSContext* aCx,
193 nsGlobalWindowInner* aTargetWindow,
194 mozilla::dom::EventTarget* aEventTarget) {
195 RootedDictionary<MessageEventInit> init(aCx);
196 init.mBubbles = false;
197 init.mCancelable = false;
198 init.mOrigin = mCallerOrigin;
200 if (mSource) {
201 init.mSource.SetValue().SetAsWindowProxy() = mSource;
204 RefPtr<Event> event = MessageEvent::Constructor(
205 aEventTarget, NS_LITERAL_STRING("messageerror"), init);
206 Dispatch(aTargetWindow, event);
209 void PostMessageEvent::Dispatch(nsGlobalWindowInner* aTargetWindow,
210 Event* aEvent) {
211 // We can't simply call dispatchEvent on the window because doing so ends
212 // up flipping the trusted bit on the event, and we don't want that to
213 // happen because then untrusted content can call postMessage on a chrome
214 // window if it can get a reference to it.
216 RefPtr<nsPresContext> presContext =
217 aTargetWindow->GetExtantDoc()->GetPresContext();
219 aEvent->SetTrusted(true);
220 WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
222 nsEventStatus status = nsEventStatus_eIgnore;
223 EventDispatcher::Dispatch(ToSupports(aTargetWindow), presContext,
224 internalEvent, aEvent, &status);
227 } // namespace dom
228 } // namespace mozilla