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"
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"),
43 mCallerOrigin(aCallerOrigin
),
44 mTargetWindow(aTargetWindow
),
45 mProvidedPrincipal(aProvidedPrincipal
),
46 mCallerWindowID(aCallerWindowID
),
47 mCallerDocumentURI(aCallerDocumentURI
),
48 mIsFromPrivateWindow(aIsFromPrivateWindow
) {}
50 PostMessageEvent::~PostMessageEvent() {}
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
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())
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
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
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",
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());
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
,
159 holder
= &mHolder
.ref
<StructuredCloneHolder
>();
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
);
171 RefPtr
<MessageEvent
> event
= new MessageEvent(eventTarget
, nullptr, nullptr);
173 Nullable
<WindowProxyOrMessagePortOrServiceWorker
> source
;
175 source
.SetValue().SetAsWindowProxy() = mSource
;
178 Sequence
<OwningNonNull
<MessagePort
>> ports
;
179 if (!holder
->TakeTransferredPortsAsSequence(ports
)) {
180 DispatchError(cx
, targetWindow
, eventTarget
);
184 event
->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"), CanBubble::eNo
,
185 Cancelable::eNo
, messageData
, mCallerOrigin
,
186 EmptyString(), source
, ports
);
188 Dispatch(targetWindow
, event
);
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
;
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
,
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
);
228 } // namespace mozilla