1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #include "nsHttp.h"
9 #include "mozilla/BasePrincipal.h"
10 #include "mozilla/ContentPrincipal.h"
11 #include "mozilla/ipc/IPCStreamUtils.h"
12 #include "mozilla/net/ExtensionProtocolHandler.h"
13 #include "mozilla/net/PageThumbProtocolHandler.h"
14 #include "mozilla/net/NeckoParent.h"
15 #include "mozilla/net/HttpChannelParent.h"
16 #include "mozilla/net/CookieServiceParent.h"
17 #include "mozilla/net/FTPChannelParent.h"
18 #include "mozilla/net/WebSocketChannelParent.h"
19 #include "mozilla/net/WebSocketEventListenerParent.h"
20 #include "mozilla/net/DataChannelParent.h"
21 #include "mozilla/net/DocumentChannelParent.h"
22 #include "mozilla/net/SimpleChannelParent.h"
23 #include "mozilla/net/AltDataOutputStreamParent.h"
24 #include "mozilla/Unused.h"
25 #include "mozilla/net/FileChannelParent.h"
26 #include "mozilla/net/DNSRequestParent.h"
27 #include "mozilla/net/ChannelDiverterParent.h"
28 #include "mozilla/net/ClassifierDummyChannelParent.h"
29 #include "mozilla/net/IPCTransportProvider.h"
30 #include "mozilla/net/RequestContextService.h"
31 #include "mozilla/net/SocketProcessParent.h"
32 #include "mozilla/net/PSocketProcessBridgeParent.h"
33 #ifdef MOZ_WEBRTC
34 #  include "mozilla/net/StunAddrsRequestParent.h"
35 #  include "mozilla/net/WebrtcTCPSocketParent.h"
36 #endif
37 #include "mozilla/dom/ChromeUtils.h"
38 #include "mozilla/dom/ContentParent.h"
39 #include "mozilla/dom/TabContext.h"
40 #include "mozilla/dom/BrowserParent.h"
41 #include "mozilla/dom/network/TCPSocketParent.h"
42 #include "mozilla/dom/network/TCPServerSocketParent.h"
43 #include "mozilla/dom/network/UDPSocketParent.h"
44 #include "mozilla/dom/ServiceWorkerManager.h"
45 #include "mozilla/LoadContext.h"
46 #include "mozilla/MozPromise.h"
47 #include "nsPrintfCString.h"
48 #include "nsHTMLDNSPrefetch.h"
49 #include "nsEscape.h"
50 #include "SerializedLoadContext.h"
51 #include "nsAuthInformationHolder.h"
52 #include "nsIAuthPromptCallback.h"
53 #include "nsINetworkPredictor.h"
54 #include "nsINetworkPredictorVerifier.h"
55 #include "nsISpeculativeConnect.h"
56 #include "nsHttpHandler.h"
57 #include "nsNetUtil.h"
58 
59 using IPC::SerializedLoadContext;
60 using mozilla::OriginAttributes;
61 using mozilla::dom::BrowserParent;
62 using mozilla::dom::ChromeUtils;
63 using mozilla::dom::ContentParent;
64 using mozilla::dom::ServiceWorkerManager;
65 using mozilla::dom::TabContext;
66 using mozilla::dom::TCPServerSocketParent;
67 using mozilla::dom::TCPSocketParent;
68 using mozilla::dom::UDPSocketParent;
69 using mozilla::ipc::LoadInfoArgsToLoadInfo;
70 using mozilla::ipc::PrincipalInfo;
71 using mozilla::net::PTCPServerSocketParent;
72 using mozilla::net::PTCPSocketParent;
73 using mozilla::net::PUDPSocketParent;
74 
75 namespace mozilla {
76 namespace net {
77 
78 // C++ file contents
NeckoParent()79 NeckoParent::NeckoParent() : mSocketProcessBridgeInited(false) {
80   // Init HTTP protocol handler now since we need atomTable up and running very
81   // early (IPDL argument handling for PHttpChannel constructor needs it) so
82   // normal init (during 1st Http channel request) isn't early enough.
83   nsCOMPtr<nsIProtocolHandler> proto =
84       do_GetService("@mozilla.org/network/protocol;1?name=http");
85 }
86 
PBOverrideStatusFromLoadContext(const SerializedLoadContext & aSerialized)87 static PBOverrideStatus PBOverrideStatusFromLoadContext(
88     const SerializedLoadContext& aSerialized) {
89   if (!aSerialized.IsNotNull() && aSerialized.IsPrivateBitValid()) {
90     return (aSerialized.mOriginAttributes.mPrivateBrowsingId > 0)
91                ? kPBOverride_Private
92                : kPBOverride_NotPrivate;
93   }
94   return kPBOverride_Unset;
95 }
96 
GetRequestingPrincipal(const Maybe<LoadInfoArgs> & aOptionalLoadInfoArgs)97 static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
98     const Maybe<LoadInfoArgs>& aOptionalLoadInfoArgs) {
99   if (aOptionalLoadInfoArgs.isNothing()) {
100     return nullptr;
101   }
102 
103   const LoadInfoArgs& loadInfoArgs = aOptionalLoadInfoArgs.ref();
104   const Maybe<PrincipalInfo>& optionalPrincipalInfo =
105       loadInfoArgs.requestingPrincipalInfo();
106 
107   if (optionalPrincipalInfo.isNothing()) {
108     return nullptr;
109   }
110 
111   const PrincipalInfo& principalInfo = optionalPrincipalInfo.ref();
112 
113   auto principalOrErr = PrincipalInfoToPrincipal(principalInfo);
114   return principalOrErr.isOk() ? principalOrErr.unwrap().forget() : nullptr;
115 }
116 
GetRequestingPrincipal(const HttpChannelCreationArgs & aArgs)117 static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
118     const HttpChannelCreationArgs& aArgs) {
119   if (aArgs.type() != HttpChannelCreationArgs::THttpChannelOpenArgs) {
120     return nullptr;
121   }
122 
123   const HttpChannelOpenArgs& args = aArgs.get_HttpChannelOpenArgs();
124   return GetRequestingPrincipal(args.loadInfo());
125 }
126 
GetRequestingPrincipal(const FTPChannelCreationArgs & aArgs)127 static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
128     const FTPChannelCreationArgs& aArgs) {
129   if (aArgs.type() != FTPChannelCreationArgs::TFTPChannelOpenArgs) {
130     return nullptr;
131   }
132 
133   const FTPChannelOpenArgs& args = aArgs.get_FTPChannelOpenArgs();
134   return GetRequestingPrincipal(args.loadInfo());
135 }
136 
GetValidatedOriginAttributes(const SerializedLoadContext & aSerialized,PContentParent * aContent,nsIPrincipal * aRequestingPrincipal,OriginAttributes & aAttrs)137 const char* NeckoParent::GetValidatedOriginAttributes(
138     const SerializedLoadContext& aSerialized, PContentParent* aContent,
139     nsIPrincipal* aRequestingPrincipal, OriginAttributes& aAttrs) {
140   if (!aSerialized.IsNotNull()) {
141     // If serialized is null, we cannot validate anything. We have to assume
142     // that this requests comes from a SystemPrincipal.
143     aAttrs = OriginAttributes(false);
144   } else {
145     aAttrs = aSerialized.mOriginAttributes;
146   }
147   return nullptr;
148 }
149 
CreateChannelLoadContext(PBrowserParent * aBrowser,PContentParent * aContent,const SerializedLoadContext & aSerialized,nsIPrincipal * aRequestingPrincipal,nsCOMPtr<nsILoadContext> & aResult)150 const char* NeckoParent::CreateChannelLoadContext(
151     PBrowserParent* aBrowser, PContentParent* aContent,
152     const SerializedLoadContext& aSerialized,
153     nsIPrincipal* aRequestingPrincipal, nsCOMPtr<nsILoadContext>& aResult) {
154   OriginAttributes attrs;
155   const char* error = GetValidatedOriginAttributes(aSerialized, aContent,
156                                                    aRequestingPrincipal, attrs);
157   if (error) {
158     return error;
159   }
160 
161   // if !UsingNeckoIPCSecurity(), we may not have a LoadContext to set. This is
162   // the common case for most xpcshell tests.
163   if (aSerialized.IsNotNull()) {
164     attrs.SyncAttributesWithPrivateBrowsing(
165         aSerialized.mOriginAttributes.mPrivateBrowsingId > 0);
166 
167     RefPtr<BrowserParent> browserParent = BrowserParent::GetFrom(aBrowser);
168     dom::Element* topFrameElement = nullptr;
169     if (browserParent) {
170       topFrameElement = browserParent->GetOwnerElement();
171     }
172     aResult = new LoadContext(aSerialized, topFrameElement, attrs);
173   }
174 
175   return nullptr;
176 }
177 
ActorDestroy(ActorDestroyReason aWhy)178 void NeckoParent::ActorDestroy(ActorDestroyReason aWhy) {
179   // Nothing needed here. Called right before destructor since this is a
180   // non-refcounted class.
181 }
182 
AllocPHttpChannelParent(PBrowserParent * aBrowser,const SerializedLoadContext & aSerialized,const HttpChannelCreationArgs & aOpenArgs)183 already_AddRefed<PHttpChannelParent> NeckoParent::AllocPHttpChannelParent(
184     PBrowserParent* aBrowser, const SerializedLoadContext& aSerialized,
185     const HttpChannelCreationArgs& aOpenArgs) {
186   nsCOMPtr<nsIPrincipal> requestingPrincipal =
187       GetRequestingPrincipal(aOpenArgs);
188 
189   nsCOMPtr<nsILoadContext> loadContext;
190   const char* error = CreateChannelLoadContext(
191       aBrowser, Manager(), aSerialized, requestingPrincipal, loadContext);
192   if (error) {
193     printf_stderr(
194         "NeckoParent::AllocPHttpChannelParent: "
195         "FATAL error: %s: KILLING CHILD PROCESS\n",
196         error);
197     return nullptr;
198   }
199   PBOverrideStatus overrideStatus =
200       PBOverrideStatusFromLoadContext(aSerialized);
201   RefPtr<HttpChannelParent> p = new HttpChannelParent(
202       BrowserParent::GetFrom(aBrowser), loadContext, overrideStatus);
203   return p.forget();
204 }
205 
RecvPHttpChannelConstructor(PHttpChannelParent * aActor,PBrowserParent * aBrowser,const SerializedLoadContext & aSerialized,const HttpChannelCreationArgs & aOpenArgs)206 mozilla::ipc::IPCResult NeckoParent::RecvPHttpChannelConstructor(
207     PHttpChannelParent* aActor, PBrowserParent* aBrowser,
208     const SerializedLoadContext& aSerialized,
209     const HttpChannelCreationArgs& aOpenArgs) {
210   HttpChannelParent* p = static_cast<HttpChannelParent*>(aActor);
211   if (!p->Init(aOpenArgs)) {
212     return IPC_FAIL_NO_REASON(this);
213   }
214   return IPC_OK();
215 }
216 
AllocPStunAddrsRequestParent()217 PStunAddrsRequestParent* NeckoParent::AllocPStunAddrsRequestParent() {
218 #ifdef MOZ_WEBRTC
219   StunAddrsRequestParent* p = new StunAddrsRequestParent();
220   p->AddRef();
221   return p;
222 #else
223   return nullptr;
224 #endif
225 }
226 
DeallocPStunAddrsRequestParent(PStunAddrsRequestParent * aActor)227 bool NeckoParent::DeallocPStunAddrsRequestParent(
228     PStunAddrsRequestParent* aActor) {
229 #ifdef MOZ_WEBRTC
230   StunAddrsRequestParent* p = static_cast<StunAddrsRequestParent*>(aActor);
231   p->Release();
232 #endif
233   return true;
234 }
235 
AllocPWebrtcTCPSocketParent(const Maybe<TabId> & aTabId)236 PWebrtcTCPSocketParent* NeckoParent::AllocPWebrtcTCPSocketParent(
237     const Maybe<TabId>& aTabId) {
238 #ifdef MOZ_WEBRTC
239   WebrtcTCPSocketParent* parent = new WebrtcTCPSocketParent(aTabId);
240   parent->AddRef();
241   return parent;
242 #else
243   return nullptr;
244 #endif
245 }
246 
DeallocPWebrtcTCPSocketParent(PWebrtcTCPSocketParent * aActor)247 bool NeckoParent::DeallocPWebrtcTCPSocketParent(
248     PWebrtcTCPSocketParent* aActor) {
249 #ifdef MOZ_WEBRTC
250   WebrtcTCPSocketParent* parent = static_cast<WebrtcTCPSocketParent*>(aActor);
251   parent->Release();
252 #endif
253   return true;
254 }
255 
AllocPAltDataOutputStreamParent(const nsCString & type,const int64_t & predictedSize,PHttpChannelParent * channel)256 PAltDataOutputStreamParent* NeckoParent::AllocPAltDataOutputStreamParent(
257     const nsCString& type, const int64_t& predictedSize,
258     PHttpChannelParent* channel) {
259   HttpChannelParent* chan = static_cast<HttpChannelParent*>(channel);
260   nsCOMPtr<nsIAsyncOutputStream> stream;
261   nsresult rv = chan->OpenAlternativeOutputStream(type, predictedSize,
262                                                   getter_AddRefs(stream));
263   AltDataOutputStreamParent* parent = new AltDataOutputStreamParent(stream);
264   parent->AddRef();
265   // If the return value was not NS_OK, the error code will be sent
266   // asynchronously to the child, after receiving the first message.
267   parent->SetError(rv);
268   return parent;
269 }
270 
DeallocPAltDataOutputStreamParent(PAltDataOutputStreamParent * aActor)271 bool NeckoParent::DeallocPAltDataOutputStreamParent(
272     PAltDataOutputStreamParent* aActor) {
273   AltDataOutputStreamParent* parent =
274       static_cast<AltDataOutputStreamParent*>(aActor);
275   parent->Release();
276   return true;
277 }
278 
AllocPFTPChannelParent(PBrowserParent * aBrowser,const SerializedLoadContext & aSerialized,const FTPChannelCreationArgs & aOpenArgs)279 PFTPChannelParent* NeckoParent::AllocPFTPChannelParent(
280     PBrowserParent* aBrowser, const SerializedLoadContext& aSerialized,
281     const FTPChannelCreationArgs& aOpenArgs) {
282   nsCOMPtr<nsIPrincipal> requestingPrincipal =
283       GetRequestingPrincipal(aOpenArgs);
284 
285   nsCOMPtr<nsILoadContext> loadContext;
286   const char* error = CreateChannelLoadContext(
287       aBrowser, Manager(), aSerialized, requestingPrincipal, loadContext);
288   if (error) {
289     printf_stderr(
290         "NeckoParent::AllocPFTPChannelParent: "
291         "FATAL error: %s: KILLING CHILD PROCESS\n",
292         error);
293     return nullptr;
294   }
295   PBOverrideStatus overrideStatus =
296       PBOverrideStatusFromLoadContext(aSerialized);
297   FTPChannelParent* p = new FTPChannelParent(BrowserParent::GetFrom(aBrowser),
298                                              loadContext, overrideStatus);
299   p->AddRef();
300   return p;
301 }
302 
DeallocPFTPChannelParent(PFTPChannelParent * channel)303 bool NeckoParent::DeallocPFTPChannelParent(PFTPChannelParent* channel) {
304   FTPChannelParent* p = static_cast<FTPChannelParent*>(channel);
305   p->Release();
306   return true;
307 }
308 
RecvPFTPChannelConstructor(PFTPChannelParent * aActor,PBrowserParent * aBrowser,const SerializedLoadContext & aSerialized,const FTPChannelCreationArgs & aOpenArgs)309 mozilla::ipc::IPCResult NeckoParent::RecvPFTPChannelConstructor(
310     PFTPChannelParent* aActor, PBrowserParent* aBrowser,
311     const SerializedLoadContext& aSerialized,
312     const FTPChannelCreationArgs& aOpenArgs) {
313   FTPChannelParent* p = static_cast<FTPChannelParent*>(aActor);
314   if (!p->Init(aOpenArgs)) {
315     return IPC_FAIL_NO_REASON(this);
316   }
317   return IPC_OK();
318 }
319 
320 already_AddRefed<PDocumentChannelParent>
AllocPDocumentChannelParent(const MaybeDiscarded<BrowsingContext> & aContext,const DocumentChannelCreationArgs & args)321 NeckoParent::AllocPDocumentChannelParent(
322     const MaybeDiscarded<BrowsingContext>& aContext,
323     const DocumentChannelCreationArgs& args) {
324   RefPtr<DocumentChannelParent> p = new DocumentChannelParent();
325   return p.forget();
326 }
327 
RecvPDocumentChannelConstructor(PDocumentChannelParent * aActor,const MaybeDiscarded<BrowsingContext> & aContext,const DocumentChannelCreationArgs & aArgs)328 mozilla::ipc::IPCResult NeckoParent::RecvPDocumentChannelConstructor(
329     PDocumentChannelParent* aActor,
330     const MaybeDiscarded<BrowsingContext>& aContext,
331     const DocumentChannelCreationArgs& aArgs) {
332   DocumentChannelParent* p = static_cast<DocumentChannelParent*>(aActor);
333 
334   if (aContext.IsNullOrDiscarded()) {
335     Unused << p->SendFailedAsyncOpen(NS_ERROR_FAILURE);
336     return IPC_OK();
337   }
338 
339   if (!p->Init(aContext.get_canonical(), aArgs)) {
340     return IPC_FAIL_NO_REASON(this);
341   }
342   return IPC_OK();
343 }
344 
AllocPCookieServiceParent()345 PCookieServiceParent* NeckoParent::AllocPCookieServiceParent() {
346   return new CookieServiceParent();
347 }
348 
DeallocPCookieServiceParent(PCookieServiceParent * cs)349 bool NeckoParent::DeallocPCookieServiceParent(PCookieServiceParent* cs) {
350   delete cs;
351   return true;
352 }
353 
AllocPWebSocketParent(PBrowserParent * browser,const SerializedLoadContext & serialized,const uint32_t & aSerial)354 PWebSocketParent* NeckoParent::AllocPWebSocketParent(
355     PBrowserParent* browser, const SerializedLoadContext& serialized,
356     const uint32_t& aSerial) {
357   nsCOMPtr<nsILoadContext> loadContext;
358   const char* error = CreateChannelLoadContext(browser, Manager(), serialized,
359                                                nullptr, loadContext);
360   if (error) {
361     printf_stderr(
362         "NeckoParent::AllocPWebSocketParent: "
363         "FATAL error: %s: KILLING CHILD PROCESS\n",
364         error);
365     return nullptr;
366   }
367 
368   RefPtr<BrowserParent> browserParent = BrowserParent::GetFrom(browser);
369   PBOverrideStatus overrideStatus = PBOverrideStatusFromLoadContext(serialized);
370   WebSocketChannelParent* p = new WebSocketChannelParent(
371       browserParent, loadContext, overrideStatus, aSerial);
372   p->AddRef();
373   return p;
374 }
375 
DeallocPWebSocketParent(PWebSocketParent * actor)376 bool NeckoParent::DeallocPWebSocketParent(PWebSocketParent* actor) {
377   WebSocketChannelParent* p = static_cast<WebSocketChannelParent*>(actor);
378   p->Release();
379   return true;
380 }
381 
AllocPWebSocketEventListenerParent(const uint64_t & aInnerWindowID)382 PWebSocketEventListenerParent* NeckoParent::AllocPWebSocketEventListenerParent(
383     const uint64_t& aInnerWindowID) {
384   RefPtr<WebSocketEventListenerParent> c =
385       new WebSocketEventListenerParent(aInnerWindowID);
386   return c.forget().take();
387 }
388 
DeallocPWebSocketEventListenerParent(PWebSocketEventListenerParent * aActor)389 bool NeckoParent::DeallocPWebSocketEventListenerParent(
390     PWebSocketEventListenerParent* aActor) {
391   RefPtr<WebSocketEventListenerParent> c =
392       dont_AddRef(static_cast<WebSocketEventListenerParent*>(aActor));
393   MOZ_ASSERT(c);
394   return true;
395 }
396 
AllocPDataChannelParent(const uint32_t & channelId)397 already_AddRefed<PDataChannelParent> NeckoParent::AllocPDataChannelParent(
398     const uint32_t& channelId) {
399   RefPtr<DataChannelParent> p = new DataChannelParent();
400   return p.forget();
401 }
402 
RecvPDataChannelConstructor(PDataChannelParent * actor,const uint32_t & channelId)403 mozilla::ipc::IPCResult NeckoParent::RecvPDataChannelConstructor(
404     PDataChannelParent* actor, const uint32_t& channelId) {
405   DataChannelParent* p = static_cast<DataChannelParent*>(actor);
406   DebugOnly<bool> rv = p->Init(channelId);
407   MOZ_ASSERT(rv);
408   return IPC_OK();
409 }
410 
AllocPSimpleChannelParent(const uint32_t & channelId)411 PSimpleChannelParent* NeckoParent::AllocPSimpleChannelParent(
412     const uint32_t& channelId) {
413   RefPtr<SimpleChannelParent> p = new SimpleChannelParent();
414   return p.forget().take();
415 }
416 
DeallocPSimpleChannelParent(PSimpleChannelParent * actor)417 bool NeckoParent::DeallocPSimpleChannelParent(PSimpleChannelParent* actor) {
418   RefPtr<SimpleChannelParent> p =
419       dont_AddRef(actor).downcast<SimpleChannelParent>();
420   return true;
421 }
422 
RecvPSimpleChannelConstructor(PSimpleChannelParent * actor,const uint32_t & channelId)423 mozilla::ipc::IPCResult NeckoParent::RecvPSimpleChannelConstructor(
424     PSimpleChannelParent* actor, const uint32_t& channelId) {
425   SimpleChannelParent* p = static_cast<SimpleChannelParent*>(actor);
426   MOZ_ALWAYS_TRUE(p->Init(channelId));
427   return IPC_OK();
428 }
429 
AllocPFileChannelParent(const uint32_t & channelId)430 already_AddRefed<PFileChannelParent> NeckoParent::AllocPFileChannelParent(
431     const uint32_t& channelId) {
432   RefPtr<FileChannelParent> p = new FileChannelParent();
433   return p.forget();
434 }
435 
RecvPFileChannelConstructor(PFileChannelParent * actor,const uint32_t & channelId)436 mozilla::ipc::IPCResult NeckoParent::RecvPFileChannelConstructor(
437     PFileChannelParent* actor, const uint32_t& channelId) {
438   FileChannelParent* p = static_cast<FileChannelParent*>(actor);
439   DebugOnly<bool> rv = p->Init(channelId);
440   MOZ_ASSERT(rv);
441   return IPC_OK();
442 }
443 
AllocPTCPSocketParent(const nsString &,const uint16_t &)444 PTCPSocketParent* NeckoParent::AllocPTCPSocketParent(
445     const nsString& /* host */, const uint16_t& /* port */) {
446   // We actually don't need host/port to construct a TCPSocketParent since
447   // TCPSocketParent will maintain an internal nsIDOMTCPSocket instance which
448   // can be delegated to get the host/port.
449   TCPSocketParent* p = new TCPSocketParent();
450   p->AddIPDLReference();
451   return p;
452 }
453 
DeallocPTCPSocketParent(PTCPSocketParent * actor)454 bool NeckoParent::DeallocPTCPSocketParent(PTCPSocketParent* actor) {
455   TCPSocketParent* p = static_cast<TCPSocketParent*>(actor);
456   p->ReleaseIPDLReference();
457   return true;
458 }
459 
AllocPTCPServerSocketParent(const uint16_t & aLocalPort,const uint16_t & aBacklog,const bool & aUseArrayBuffers)460 PTCPServerSocketParent* NeckoParent::AllocPTCPServerSocketParent(
461     const uint16_t& aLocalPort, const uint16_t& aBacklog,
462     const bool& aUseArrayBuffers) {
463   TCPServerSocketParent* p =
464       new TCPServerSocketParent(this, aLocalPort, aBacklog, aUseArrayBuffers);
465   p->AddIPDLReference();
466   return p;
467 }
468 
RecvPTCPServerSocketConstructor(PTCPServerSocketParent * aActor,const uint16_t & aLocalPort,const uint16_t & aBacklog,const bool & aUseArrayBuffers)469 mozilla::ipc::IPCResult NeckoParent::RecvPTCPServerSocketConstructor(
470     PTCPServerSocketParent* aActor, const uint16_t& aLocalPort,
471     const uint16_t& aBacklog, const bool& aUseArrayBuffers) {
472   static_cast<TCPServerSocketParent*>(aActor)->Init();
473   return IPC_OK();
474 }
475 
DeallocPTCPServerSocketParent(PTCPServerSocketParent * actor)476 bool NeckoParent::DeallocPTCPServerSocketParent(PTCPServerSocketParent* actor) {
477   TCPServerSocketParent* p = static_cast<TCPServerSocketParent*>(actor);
478   p->ReleaseIPDLReference();
479   return true;
480 }
481 
AllocPUDPSocketParent(nsIPrincipal *,const nsCString &)482 PUDPSocketParent* NeckoParent::AllocPUDPSocketParent(
483     nsIPrincipal* /* unused */, const nsCString& /* unused */) {
484   RefPtr<UDPSocketParent> p = new UDPSocketParent(this);
485 
486   return p.forget().take();
487 }
488 
RecvPUDPSocketConstructor(PUDPSocketParent * aActor,nsIPrincipal * aPrincipal,const nsCString & aFilter)489 mozilla::ipc::IPCResult NeckoParent::RecvPUDPSocketConstructor(
490     PUDPSocketParent* aActor, nsIPrincipal* aPrincipal,
491     const nsCString& aFilter) {
492   if (!static_cast<UDPSocketParent*>(aActor)->Init(aPrincipal, aFilter)) {
493     return IPC_FAIL_NO_REASON(this);
494   }
495   return IPC_OK();
496 }
497 
DeallocPUDPSocketParent(PUDPSocketParent * actor)498 bool NeckoParent::DeallocPUDPSocketParent(PUDPSocketParent* actor) {
499   UDPSocketParent* p = static_cast<UDPSocketParent*>(actor);
500   p->Release();
501   return true;
502 }
503 
AllocPDNSRequestParent(const nsCString & aHost,const nsCString & aTrrServer,const uint16_t & aType,const OriginAttributes & aOriginAttributes,const uint32_t & aFlags)504 already_AddRefed<PDNSRequestParent> NeckoParent::AllocPDNSRequestParent(
505     const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType,
506     const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) {
507   RefPtr<DNSRequestHandler> handler = new DNSRequestHandler();
508   RefPtr<DNSRequestParent> actor = new DNSRequestParent(handler);
509   return actor.forget();
510 }
511 
RecvPDNSRequestConstructor(PDNSRequestParent * aActor,const nsCString & aHost,const nsCString & aTrrServer,const uint16_t & aType,const OriginAttributes & aOriginAttributes,const uint32_t & aFlags)512 mozilla::ipc::IPCResult NeckoParent::RecvPDNSRequestConstructor(
513     PDNSRequestParent* aActor, const nsCString& aHost,
514     const nsCString& aTrrServer, const uint16_t& aType,
515     const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) {
516   RefPtr<DNSRequestParent> actor = static_cast<DNSRequestParent*>(aActor);
517   RefPtr<DNSRequestHandler> handler =
518       actor->GetDNSRequest()->AsDNSRequestHandler();
519   handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags);
520   return IPC_OK();
521 }
522 
RecvSpeculativeConnect(nsIURI * aURI,nsIPrincipal * aPrincipal,const bool & aAnonymous)523 mozilla::ipc::IPCResult NeckoParent::RecvSpeculativeConnect(
524     nsIURI* aURI, nsIPrincipal* aPrincipal, const bool& aAnonymous) {
525   nsCOMPtr<nsISpeculativeConnect> speculator(gIOService);
526   nsCOMPtr<nsIPrincipal> principal(aPrincipal);
527   if (!aURI) {
528     return IPC_FAIL(this, "aURI must not be null");
529   }
530   if (aURI && speculator) {
531     if (aAnonymous) {
532       speculator->SpeculativeAnonymousConnect(aURI, principal, nullptr);
533     } else {
534       speculator->SpeculativeConnect(aURI, principal, nullptr);
535     }
536   }
537   return IPC_OK();
538 }
539 
RecvHTMLDNSPrefetch(const nsString & hostname,const bool & isHttps,const OriginAttributes & aOriginAttributes,const uint32_t & flags)540 mozilla::ipc::IPCResult NeckoParent::RecvHTMLDNSPrefetch(
541     const nsString& hostname, const bool& isHttps,
542     const OriginAttributes& aOriginAttributes, const uint32_t& flags) {
543   nsHTMLDNSPrefetch::Prefetch(hostname, isHttps, aOriginAttributes, flags);
544   return IPC_OK();
545 }
546 
RecvCancelHTMLDNSPrefetch(const nsString & hostname,const bool & isHttps,const OriginAttributes & aOriginAttributes,const uint32_t & flags,const nsresult & reason)547 mozilla::ipc::IPCResult NeckoParent::RecvCancelHTMLDNSPrefetch(
548     const nsString& hostname, const bool& isHttps,
549     const OriginAttributes& aOriginAttributes, const uint32_t& flags,
550     const nsresult& reason) {
551   nsHTMLDNSPrefetch::CancelPrefetch(hostname, isHttps, aOriginAttributes, flags,
552                                     reason);
553   return IPC_OK();
554 }
555 
AllocPChannelDiverterParent(const ChannelDiverterArgs & channel)556 PChannelDiverterParent* NeckoParent::AllocPChannelDiverterParent(
557     const ChannelDiverterArgs& channel) {
558   return new ChannelDiverterParent();
559 }
560 
RecvPChannelDiverterConstructor(PChannelDiverterParent * actor,const ChannelDiverterArgs & channel)561 mozilla::ipc::IPCResult NeckoParent::RecvPChannelDiverterConstructor(
562     PChannelDiverterParent* actor, const ChannelDiverterArgs& channel) {
563   auto parent = static_cast<ChannelDiverterParent*>(actor);
564   parent->Init(channel);
565   return IPC_OK();
566 }
567 
DeallocPChannelDiverterParent(PChannelDiverterParent * parent)568 bool NeckoParent::DeallocPChannelDiverterParent(
569     PChannelDiverterParent* parent) {
570   delete static_cast<ChannelDiverterParent*>(parent);
571   return true;
572 }
573 
AllocPTransportProviderParent()574 PTransportProviderParent* NeckoParent::AllocPTransportProviderParent() {
575   RefPtr<TransportProviderParent> res = new TransportProviderParent();
576   return res.forget().take();
577 }
578 
DeallocPTransportProviderParent(PTransportProviderParent * aActor)579 bool NeckoParent::DeallocPTransportProviderParent(
580     PTransportProviderParent* aActor) {
581   RefPtr<TransportProviderParent> provider =
582       dont_AddRef(static_cast<TransportProviderParent*>(aActor));
583   return true;
584 }
585 
586 namespace {
CallbackMap()587 std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> >& CallbackMap() {
588   MOZ_ASSERT(NS_IsMainThread());
589   static std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> > sCallbackMap;
590   return sCallbackMap;
591 }
592 }  // namespace
593 
NS_IMPL_ISUPPORTS(NeckoParent::NestedFrameAuthPrompt,nsIAuthPrompt2)594 NS_IMPL_ISUPPORTS(NeckoParent::NestedFrameAuthPrompt, nsIAuthPrompt2)
595 
596 NeckoParent::NestedFrameAuthPrompt::NestedFrameAuthPrompt(PNeckoParent* aParent,
597                                                           TabId aNestedFrameId)
598     : mNeckoParent(aParent), mNestedFrameId(aNestedFrameId) {}
599 
600 NS_IMETHODIMP
AsyncPromptAuth(nsIChannel * aChannel,nsIAuthPromptCallback * callback,nsISupports *,uint32_t,nsIAuthInformation * aInfo,nsICancelable **)601 NeckoParent::NestedFrameAuthPrompt::AsyncPromptAuth(
602     nsIChannel* aChannel, nsIAuthPromptCallback* callback, nsISupports*,
603     uint32_t, nsIAuthInformation* aInfo, nsICancelable**) {
604   static uint64_t callbackId = 0;
605   MOZ_ASSERT(XRE_IsParentProcess());
606   nsCOMPtr<nsIURI> uri;
607   nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
608   NS_ENSURE_SUCCESS(rv, rv);
609   nsAutoCString spec;
610   if (uri) {
611     rv = uri->GetSpec(spec);
612     NS_ENSURE_SUCCESS(rv, rv);
613   }
614   nsString realm;
615   rv = aInfo->GetRealm(realm);
616   NS_ENSURE_SUCCESS(rv, rv);
617   callbackId++;
618   if (mNeckoParent->SendAsyncAuthPromptForNestedFrame(mNestedFrameId, spec,
619                                                       realm, callbackId)) {
620     CallbackMap()[callbackId] = callback;
621     return NS_OK;
622   }
623   return NS_ERROR_FAILURE;
624 }
625 
RecvOnAuthAvailable(const uint64_t & aCallbackId,const nsString & aUser,const nsString & aPassword,const nsString & aDomain)626 mozilla::ipc::IPCResult NeckoParent::RecvOnAuthAvailable(
627     const uint64_t& aCallbackId, const nsString& aUser,
628     const nsString& aPassword, const nsString& aDomain) {
629   nsCOMPtr<nsIAuthPromptCallback> callback = CallbackMap()[aCallbackId];
630   if (!callback) {
631     return IPC_OK();
632   }
633   CallbackMap().erase(aCallbackId);
634 
635   RefPtr<nsAuthInformationHolder> holder =
636       new nsAuthInformationHolder(0, EmptyString(), EmptyCString());
637   holder->SetUsername(aUser);
638   holder->SetPassword(aPassword);
639   holder->SetDomain(aDomain);
640 
641   callback->OnAuthAvailable(nullptr, holder);
642   return IPC_OK();
643 }
644 
RecvOnAuthCancelled(const uint64_t & aCallbackId,const bool & aUserCancel)645 mozilla::ipc::IPCResult NeckoParent::RecvOnAuthCancelled(
646     const uint64_t& aCallbackId, const bool& aUserCancel) {
647   nsCOMPtr<nsIAuthPromptCallback> callback = CallbackMap()[aCallbackId];
648   if (!callback) {
649     return IPC_OK();
650   }
651   CallbackMap().erase(aCallbackId);
652   callback->OnAuthCancelled(nullptr, aUserCancel);
653   return IPC_OK();
654 }
655 
656 /* Predictor Messages */
RecvPredPredict(nsIURI * aTargetURI,nsIURI * aSourceURI,const uint32_t & aReason,const OriginAttributes & aOriginAttributes,const bool & hasVerifier)657 mozilla::ipc::IPCResult NeckoParent::RecvPredPredict(
658     nsIURI* aTargetURI, nsIURI* aSourceURI, const uint32_t& aReason,
659     const OriginAttributes& aOriginAttributes, const bool& hasVerifier) {
660   // Get the current predictor
661   nsresult rv = NS_OK;
662   nsCOMPtr<nsINetworkPredictor> predictor =
663       do_GetService("@mozilla.org/network/predictor;1", &rv);
664   NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this));
665 
666   nsCOMPtr<nsINetworkPredictorVerifier> verifier;
667   if (hasVerifier) {
668     verifier = do_QueryInterface(predictor);
669   }
670   predictor->PredictNative(aTargetURI, aSourceURI, aReason, aOriginAttributes,
671                            verifier);
672   return IPC_OK();
673 }
674 
RecvPredLearn(nsIURI * aTargetURI,nsIURI * aSourceURI,const uint32_t & aReason,const OriginAttributes & aOriginAttributes)675 mozilla::ipc::IPCResult NeckoParent::RecvPredLearn(
676     nsIURI* aTargetURI, nsIURI* aSourceURI, const uint32_t& aReason,
677     const OriginAttributes& aOriginAttributes) {
678   if (!aTargetURI) {
679     return IPC_FAIL(this, "aTargetURI is null");
680   }
681 
682   // Get the current predictor
683   nsresult rv = NS_OK;
684   nsCOMPtr<nsINetworkPredictor> predictor =
685       do_GetService("@mozilla.org/network/predictor;1", &rv);
686   NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this));
687 
688   predictor->LearnNative(aTargetURI, aSourceURI, aReason, aOriginAttributes);
689   return IPC_OK();
690 }
691 
RecvPredReset()692 mozilla::ipc::IPCResult NeckoParent::RecvPredReset() {
693   // Get the current predictor
694   nsresult rv = NS_OK;
695   nsCOMPtr<nsINetworkPredictor> predictor =
696       do_GetService("@mozilla.org/network/predictor;1", &rv);
697   NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this));
698 
699   predictor->Reset();
700   return IPC_OK();
701 }
702 
RecvRequestContextLoadBegin(const uint64_t & rcid)703 mozilla::ipc::IPCResult NeckoParent::RecvRequestContextLoadBegin(
704     const uint64_t& rcid) {
705   nsCOMPtr<nsIRequestContextService> rcsvc =
706       RequestContextService::GetOrCreate();
707   if (!rcsvc) {
708     return IPC_OK();
709   }
710   nsCOMPtr<nsIRequestContext> rc;
711   rcsvc->GetRequestContext(rcid, getter_AddRefs(rc));
712   if (rc) {
713     rc->BeginLoad();
714   }
715 
716   return IPC_OK();
717 }
718 
RecvRequestContextAfterDOMContentLoaded(const uint64_t & rcid)719 mozilla::ipc::IPCResult NeckoParent::RecvRequestContextAfterDOMContentLoaded(
720     const uint64_t& rcid) {
721   nsCOMPtr<nsIRequestContextService> rcsvc =
722       RequestContextService::GetOrCreate();
723   if (!rcsvc) {
724     return IPC_OK();
725   }
726   nsCOMPtr<nsIRequestContext> rc;
727   rcsvc->GetRequestContext(rcid, getter_AddRefs(rc));
728   if (rc) {
729     rc->DOMContentLoaded();
730   }
731 
732   return IPC_OK();
733 }
734 
RecvRemoveRequestContext(const uint64_t & rcid)735 mozilla::ipc::IPCResult NeckoParent::RecvRemoveRequestContext(
736     const uint64_t& rcid) {
737   nsCOMPtr<nsIRequestContextService> rcsvc =
738       RequestContextService::GetOrCreate();
739   if (!rcsvc) {
740     return IPC_OK();
741   }
742 
743   rcsvc->RemoveRequestContext(rcid);
744 
745   return IPC_OK();
746 }
747 
RecvGetExtensionStream(nsIURI * aURI,GetExtensionStreamResolver && aResolve)748 mozilla::ipc::IPCResult NeckoParent::RecvGetExtensionStream(
749     nsIURI* aURI, GetExtensionStreamResolver&& aResolve) {
750   if (!aURI) {
751     return IPC_FAIL(this, "aURI must not be null");
752   }
753 
754   RefPtr<ExtensionProtocolHandler> ph(ExtensionProtocolHandler::GetSingleton());
755   MOZ_ASSERT(ph);
756 
757   // Ask the ExtensionProtocolHandler to give us a new input stream for
758   // this URI. The request comes from an ExtensionProtocolHandler in the
759   // child process, but is not guaranteed to be a valid moz-extension URI,
760   // and not guaranteed to represent a resource that the child should be
761   // allowed to access. The ExtensionProtocolHandler is responsible for
762   // validating the request. Specifically, only URI's for local files that
763   // an extension is allowed to access via moz-extension URI's should be
764   // accepted.
765   nsCOMPtr<nsIInputStream> inputStream;
766   bool terminateSender = true;
767   auto inputStreamOrReason = ph->NewStream(aURI, &terminateSender);
768   if (inputStreamOrReason.isOk()) {
769     inputStream = inputStreamOrReason.unwrap();
770   }
771 
772   // If NewStream failed, we send back an invalid stream to the child so
773   // it can handle the error. MozPromise rejection is reserved for channel
774   // errors/disconnects.
775   aResolve(inputStream);
776 
777   if (terminateSender) {
778     return IPC_FAIL_NO_REASON(this);
779   }
780   return IPC_OK();
781 }
782 
RecvGetExtensionFD(nsIURI * aURI,GetExtensionFDResolver && aResolve)783 mozilla::ipc::IPCResult NeckoParent::RecvGetExtensionFD(
784     nsIURI* aURI, GetExtensionFDResolver&& aResolve) {
785   if (!aURI) {
786     return IPC_FAIL(this, "aURI must not be null");
787   }
788 
789   RefPtr<ExtensionProtocolHandler> ph(ExtensionProtocolHandler::GetSingleton());
790   MOZ_ASSERT(ph);
791 
792   // Ask the ExtensionProtocolHandler to give us a new input stream for
793   // this URI. The request comes from an ExtensionProtocolHandler in the
794   // child process, but is not guaranteed to be a valid moz-extension URI,
795   // and not guaranteed to represent a resource that the child should be
796   // allowed to access. The ExtensionProtocolHandler is responsible for
797   // validating the request. Specifically, only URI's for local files that
798   // an extension is allowed to access via moz-extension URI's should be
799   // accepted.
800   bool terminateSender = true;
801   auto result = ph->NewFD(aURI, &terminateSender, aResolve);
802 
803   if (result.isErr() && terminateSender) {
804     return IPC_FAIL_NO_REASON(this);
805   }
806 
807   if (result.isErr()) {
808     FileDescriptor invalidFD;
809     aResolve(invalidFD);
810   }
811 
812   return IPC_OK();
813 }
814 
AllocPClassifierDummyChannelParent(nsIURI * aURI,nsIURI * aTopWindowURI,const nsresult & aTopWindowURIResult,const Maybe<LoadInfoArgs> & aLoadInfo)815 PClassifierDummyChannelParent* NeckoParent::AllocPClassifierDummyChannelParent(
816     nsIURI* aURI, nsIURI* aTopWindowURI, const nsresult& aTopWindowURIResult,
817     const Maybe<LoadInfoArgs>& aLoadInfo) {
818   RefPtr<ClassifierDummyChannelParent> c = new ClassifierDummyChannelParent();
819   return c.forget().take();
820 }
821 
RecvPClassifierDummyChannelConstructor(PClassifierDummyChannelParent * aActor,nsIURI * aURI,nsIURI * aTopWindowURI,const nsresult & aTopWindowURIResult,const Maybe<LoadInfoArgs> & aLoadInfo)822 mozilla::ipc::IPCResult NeckoParent::RecvPClassifierDummyChannelConstructor(
823     PClassifierDummyChannelParent* aActor, nsIURI* aURI, nsIURI* aTopWindowURI,
824     const nsresult& aTopWindowURIResult, const Maybe<LoadInfoArgs>& aLoadInfo) {
825   ClassifierDummyChannelParent* p =
826       static_cast<ClassifierDummyChannelParent*>(aActor);
827 
828   if (NS_WARN_IF(!aURI)) {
829     return IPC_FAIL_NO_REASON(this);
830   }
831 
832   nsCOMPtr<nsILoadInfo> loadInfo;
833   nsresult rv = LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(loadInfo));
834   if (NS_WARN_IF(NS_FAILED(rv)) || !loadInfo) {
835     return IPC_FAIL_NO_REASON(this);
836   }
837 
838   p->Init(aURI, aTopWindowURI, aTopWindowURIResult, loadInfo);
839   return IPC_OK();
840 }
841 
DeallocPClassifierDummyChannelParent(PClassifierDummyChannelParent * aActor)842 bool NeckoParent::DeallocPClassifierDummyChannelParent(
843     PClassifierDummyChannelParent* aActor) {
844   RefPtr<ClassifierDummyChannelParent> c =
845       dont_AddRef(static_cast<ClassifierDummyChannelParent*>(aActor));
846   MOZ_ASSERT(c);
847   return true;
848 }
849 
RecvInitSocketProcessBridge(InitSocketProcessBridgeResolver && aResolver)850 mozilla::ipc::IPCResult NeckoParent::RecvInitSocketProcessBridge(
851     InitSocketProcessBridgeResolver&& aResolver) {
852   MOZ_ASSERT(NS_IsMainThread());
853 
854   Endpoint<PSocketProcessBridgeChild> invalidEndpoint;
855   if (NS_WARN_IF(mSocketProcessBridgeInited)) {
856     aResolver(std::move(invalidEndpoint));
857     return IPC_OK();
858   }
859 
860   SocketProcessParent* parent = SocketProcessParent::GetSingleton();
861   if (NS_WARN_IF(!parent)) {
862     aResolver(std::move(invalidEndpoint));
863     return IPC_OK();
864   }
865 
866   Endpoint<PSocketProcessBridgeParent> parentEndpoint;
867   Endpoint<PSocketProcessBridgeChild> childEndpoint;
868   if (NS_WARN_IF(NS_FAILED(PSocketProcessBridge::CreateEndpoints(
869           parent->OtherPid(), Manager()->OtherPid(), &parentEndpoint,
870           &childEndpoint)))) {
871     aResolver(std::move(invalidEndpoint));
872     return IPC_OK();
873   }
874 
875   if (NS_WARN_IF(!parent->SendInitSocketProcessBridgeParent(
876           Manager()->OtherPid(), std::move(parentEndpoint)))) {
877     aResolver(std::move(invalidEndpoint));
878     return IPC_OK();
879   }
880 
881   aResolver(std::move(childEndpoint));
882   mSocketProcessBridgeInited = true;
883   return IPC_OK();
884 }
885 
RecvEnsureHSTSData(EnsureHSTSDataResolver && aResolver)886 mozilla::ipc::IPCResult NeckoParent::RecvEnsureHSTSData(
887     EnsureHSTSDataResolver&& aResolver) {
888   auto callback = [aResolver{std::move(aResolver)}](bool aResult) {
889     aResolver(aResult);
890   };
891   RefPtr<HSTSDataCallbackWrapper> wrapper =
892       new HSTSDataCallbackWrapper(std::move(callback));
893   gHttpHandler->EnsureHSTSDataReadyNative(wrapper);
894   return IPC_OK();
895 }
896 
RecvGetPageThumbStream(nsIURI * aURI,GetPageThumbStreamResolver && aResolver)897 mozilla::ipc::IPCResult NeckoParent::RecvGetPageThumbStream(
898     nsIURI* aURI, GetPageThumbStreamResolver&& aResolver) {
899   // Only the privileged about content process is allowed to access
900   // things over the moz-page-thumb protocol. Any other content process
901   // that tries to send this should have been blocked via the
902   // ScriptSecurityManager, but if somehow the process has been tricked into
903   // sending this message, we send IPC_FAIL in order to crash that
904   // likely-compromised content process.
905   if (!static_cast<ContentParent*>(Manager())->GetRemoteType().EqualsLiteral(
906           PRIVILEGEDABOUT_REMOTE_TYPE)) {
907     return IPC_FAIL(this, "Wrong process type");
908   }
909 
910   RefPtr<PageThumbProtocolHandler> ph(PageThumbProtocolHandler::GetSingleton());
911   MOZ_ASSERT(ph);
912 
913   // Ask the PageThumbProtocolHandler to give us a new input stream for
914   // this URI. The request comes from a PageThumbProtocolHandler in the
915   // child process, but is not guaranteed to be a valid moz-page-thumb URI,
916   // and not guaranteed to represent a resource that the child should be
917   // allowed to access. The PageThumbProtocolHandler is responsible for
918   // validating the request.
919   nsCOMPtr<nsIInputStream> inputStream;
920   bool terminateSender = true;
921   auto inputStreamPromise = ph->NewStream(aURI, &terminateSender);
922 
923   if (terminateSender) {
924     return IPC_FAIL(this, "Malformed moz-page-thumb request");
925   }
926 
927   inputStreamPromise->Then(
928       GetMainThreadSerialEventTarget(), __func__,
929       [aResolver](const nsCOMPtr<nsIInputStream>& aStream) {
930         aResolver(aStream);
931       },
932       [aResolver](nsresult aRv) {
933         // If NewStream failed, we send back an invalid stream to the child so
934         // it can handle the error. MozPromise rejection is reserved for channel
935         // errors/disconnects.
936         Unused << NS_WARN_IF(NS_FAILED(aRv));
937         aResolver(nullptr);
938       });
939 
940   return IPC_OK();
941 }
942 
943 }  // namespace net
944 }  // namespace mozilla
945