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/. */
6 
7 #include "ChannelWrapper.h"
8 
9 #include "jsapi.h"
10 #include "xpcpublic.h"
11 
12 #include "mozilla/BasePrincipal.h"
13 #include "mozilla/SystemPrincipal.h"
14 
15 #include "NSSErrorsService.h"
16 #include "nsITransportSecurityInfo.h"
17 
18 #include "mozilla/AddonManagerWebAPI.h"
19 #include "mozilla/ClearOnShutdown.h"
20 #include "mozilla/Components.h"
21 #include "mozilla/ErrorNames.h"
22 #include "mozilla/ResultExtensions.h"
23 #include "mozilla/Unused.h"
24 #include "mozilla/dom/Element.h"
25 #include "mozilla/dom/Event.h"
26 #include "mozilla/dom/EventBinding.h"
27 #include "mozilla/dom/BrowserHost.h"
28 #include "mozIThirdPartyUtil.h"
29 #include "nsContentUtils.h"
30 #include "nsIContentPolicy.h"
31 #include "nsIClassifiedChannel.h"
32 #include "nsIHttpChannelInternal.h"
33 #include "nsIHttpHeaderVisitor.h"
34 #include "nsIInterfaceRequestor.h"
35 #include "nsIInterfaceRequestorUtils.h"
36 #include "nsILoadContext.h"
37 #include "nsIProxiedChannel.h"
38 #include "nsIProxyInfo.h"
39 #include "nsITraceableChannel.h"
40 #include "nsIWritablePropertyBag.h"
41 #include "nsIWritablePropertyBag2.h"
42 #include "nsNetUtil.h"
43 #include "nsProxyRelease.h"
44 #include "nsPrintfCString.h"
45 
46 using namespace mozilla::dom;
47 using namespace JS;
48 
49 namespace mozilla {
50 namespace extensions {
51 
52 #define CHANNELWRAPPER_PROP_KEY u"ChannelWrapper::CachedInstance"_ns
53 
54 using CF = nsIClassifiedChannel::ClassificationFlags;
55 using MUC = MozUrlClassificationFlags;
56 
57 struct ClassificationStruct {
58   uint32_t mFlag;
59   MozUrlClassificationFlags mValue;
60 };
61 static const ClassificationStruct classificationArray[] = {
62     {CF::CLASSIFIED_FINGERPRINTING, MUC::Fingerprinting},
63     {CF::CLASSIFIED_FINGERPRINTING_CONTENT, MUC::Fingerprinting_content},
64     {CF::CLASSIFIED_CRYPTOMINING, MUC::Cryptomining},
65     {CF::CLASSIFIED_CRYPTOMINING_CONTENT, MUC::Cryptomining_content},
66     {CF::CLASSIFIED_TRACKING, MUC::Tracking},
67     {CF::CLASSIFIED_TRACKING_AD, MUC::Tracking_ad},
68     {CF::CLASSIFIED_TRACKING_ANALYTICS, MUC::Tracking_analytics},
69     {CF::CLASSIFIED_TRACKING_SOCIAL, MUC::Tracking_social},
70     {CF::CLASSIFIED_TRACKING_CONTENT, MUC::Tracking_content},
71     {CF::CLASSIFIED_SOCIALTRACKING, MUC::Socialtracking},
72     {CF::CLASSIFIED_SOCIALTRACKING_FACEBOOK, MUC::Socialtracking_facebook},
73     {CF::CLASSIFIED_SOCIALTRACKING_LINKEDIN, MUC::Socialtracking_linkedin},
74     {CF::CLASSIFIED_SOCIALTRACKING_TWITTER, MUC::Socialtracking_twitter},
75     {CF::CLASSIFIED_ANY_BASIC_TRACKING, MUC::Any_basic_tracking},
76     {CF::CLASSIFIED_ANY_STRICT_TRACKING, MUC::Any_strict_tracking},
77     {CF::CLASSIFIED_ANY_SOCIAL_TRACKING, MUC::Any_social_tracking}};
78 
79 /*****************************************************************************
80  * Lifetimes
81  *****************************************************************************/
82 
83 namespace {
84 class ChannelListHolder : public LinkedList<ChannelWrapper> {
85  public:
ChannelListHolder()86   ChannelListHolder() : LinkedList<ChannelWrapper>() {}
87 
88   ~ChannelListHolder();
89 };
90 
91 }  // anonymous namespace
92 
~ChannelListHolder()93 ChannelListHolder::~ChannelListHolder() {
94   while (ChannelWrapper* wrapper = popFirst()) {
95     wrapper->Die();
96   }
97 }
98 
GetChannelList()99 static LinkedList<ChannelWrapper>* GetChannelList() {
100   static UniquePtr<ChannelListHolder> sChannelList;
101   if (!sChannelList && !PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) {
102     sChannelList.reset(new ChannelListHolder());
103     ClearOnShutdown(&sChannelList, ShutdownPhase::XPCOMShutdown);
104   }
105   return sChannelList.get();
106 }
107 
108 NS_IMPL_CYCLE_COLLECTING_ADDREF(ChannelWrapper::ChannelWrapperStub)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ChannelWrapper::ChannelWrapperStub)109 NS_IMPL_CYCLE_COLLECTING_RELEASE(ChannelWrapper::ChannelWrapperStub)
110 
111 NS_IMPL_CYCLE_COLLECTION(ChannelWrapper::ChannelWrapperStub, mChannelWrapper)
112 
113 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper::ChannelWrapperStub)
114   NS_INTERFACE_MAP_ENTRY_TEAROFF(ChannelWrapper, mChannelWrapper)
115   NS_INTERFACE_MAP_ENTRY(nsISupports)
116 NS_INTERFACE_MAP_END
117 
118 /*****************************************************************************
119  * Initialization
120  *****************************************************************************/
121 
122 ChannelWrapper::ChannelWrapper(nsISupports* aParent, nsIChannel* aChannel)
123     : ChannelHolder(aChannel), mParent(aParent) {
124   mStub = new ChannelWrapperStub(this);
125 
126   if (auto* list = GetChannelList()) {
127     list->insertBack(this);
128   }
129 }
130 
~ChannelWrapper()131 ChannelWrapper::~ChannelWrapper() {
132   if (LinkedListElement<ChannelWrapper>::isInList()) {
133     LinkedListElement<ChannelWrapper>::remove();
134   }
135 }
136 
Die()137 void ChannelWrapper::Die() {
138   if (mStub) {
139     mStub->mChannelWrapper = nullptr;
140   }
141 }
142 
143 /* static */
Get(const GlobalObject & global,nsIChannel * channel)144 already_AddRefed<ChannelWrapper> ChannelWrapper::Get(const GlobalObject& global,
145                                                      nsIChannel* channel) {
146   RefPtr<ChannelWrapper> wrapper;
147 
148   nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
149   if (props) {
150     wrapper = do_GetProperty(props, CHANNELWRAPPER_PROP_KEY);
151     if (wrapper) {
152       // Assume cached attributes may have changed at this point.
153       wrapper->ClearCachedAttributes();
154     }
155   }
156 
157   if (!wrapper) {
158     wrapper = new ChannelWrapper(global.GetAsSupports(), channel);
159     if (props) {
160       Unused << props->SetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY,
161                                               wrapper->mStub);
162     }
163   }
164 
165   return wrapper.forget();
166 }
167 
GetRegisteredChannel(const GlobalObject & global,uint64_t aChannelId,const WebExtensionPolicy & aAddon,nsIRemoteTab * aRemoteTab)168 already_AddRefed<ChannelWrapper> ChannelWrapper::GetRegisteredChannel(
169     const GlobalObject& global, uint64_t aChannelId,
170     const WebExtensionPolicy& aAddon, nsIRemoteTab* aRemoteTab) {
171   ContentParent* contentParent = nullptr;
172   if (BrowserHost* host = BrowserHost::GetFrom(aRemoteTab)) {
173     contentParent = host->GetActor()->Manager();
174   }
175 
176   auto& webreq = WebRequestService::GetSingleton();
177 
178   nsCOMPtr<nsITraceableChannel> channel =
179       webreq.GetTraceableChannel(aChannelId, aAddon.Id(), contentParent);
180   if (!channel) {
181     return nullptr;
182   }
183   nsCOMPtr<nsIChannel> chan(do_QueryInterface(channel));
184   return ChannelWrapper::Get(global, chan);
185 }
186 
SetChannel(nsIChannel * aChannel)187 void ChannelWrapper::SetChannel(nsIChannel* aChannel) {
188   detail::ChannelHolder::SetChannel(aChannel);
189   ClearCachedAttributes();
190   ChannelWrapper_Binding::ClearCachedFinalURIValue(this);
191   ChannelWrapper_Binding::ClearCachedFinalURLValue(this);
192   mFinalURLInfo.reset();
193   ChannelWrapper_Binding::ClearCachedProxyInfoValue(this);
194 }
195 
ClearCachedAttributes()196 void ChannelWrapper::ClearCachedAttributes() {
197   ChannelWrapper_Binding::ClearCachedRemoteAddressValue(this);
198   ChannelWrapper_Binding::ClearCachedStatusCodeValue(this);
199   ChannelWrapper_Binding::ClearCachedStatusLineValue(this);
200   ChannelWrapper_Binding::ClearCachedUrlClassificationValue(this);
201   if (!mFiredErrorEvent) {
202     ChannelWrapper_Binding::ClearCachedErrorStringValue(this);
203   }
204 
205   ChannelWrapper_Binding::ClearCachedRequestSizeValue(this);
206   ChannelWrapper_Binding::ClearCachedResponseSizeValue(this);
207 }
208 
209 /*****************************************************************************
210  * ...
211  *****************************************************************************/
212 
Cancel(uint32_t aResult,uint32_t aReason,ErrorResult & aRv)213 void ChannelWrapper::Cancel(uint32_t aResult, uint32_t aReason,
214                             ErrorResult& aRv) {
215   nsresult rv = NS_ERROR_UNEXPECTED;
216   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
217     nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo();
218     if (aReason > 0 && loadInfo) {
219       loadInfo->SetRequestBlockingReason(aReason);
220     }
221     rv = chan->Cancel(nsresult(aResult));
222     ErrorCheck();
223   }
224   if (NS_FAILED(rv)) {
225     aRv.Throw(rv);
226   }
227 }
228 
RedirectTo(nsIURI * aURI,ErrorResult & aRv)229 void ChannelWrapper::RedirectTo(nsIURI* aURI, ErrorResult& aRv) {
230   nsresult rv = NS_ERROR_UNEXPECTED;
231   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
232     rv = chan->RedirectTo(aURI);
233   }
234   if (NS_FAILED(rv)) {
235     aRv.Throw(rv);
236   }
237 }
238 
UpgradeToSecure(ErrorResult & aRv)239 void ChannelWrapper::UpgradeToSecure(ErrorResult& aRv) {
240   nsresult rv = NS_ERROR_UNEXPECTED;
241   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
242     rv = chan->UpgradeToSecure();
243   }
244   if (NS_FAILED(rv)) {
245     aRv.Throw(rv);
246   }
247 }
248 
Suspend(const nsCString & aProfileMarkerText,ErrorResult & aRv)249 void ChannelWrapper::Suspend(const nsCString& aProfileMarkerText,
250                              ErrorResult& aRv) {
251   if (!mSuspended) {
252     nsresult rv = NS_ERROR_UNEXPECTED;
253     if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
254       rv = chan->Suspend();
255     }
256     if (NS_FAILED(rv)) {
257       aRv.Throw(rv);
258     } else {
259       mSuspended = true;
260       MOZ_ASSERT(mSuspendedMarkerText.IsVoid());
261       mSuspendedMarkerText = aProfileMarkerText;
262       PROFILER_MARKER_TEXT("Extension Suspend", NETWORK,
263                            MarkerOptions(MarkerTiming::IntervalStart()),
264                            mSuspendedMarkerText);
265     }
266   }
267 }
268 
Resume(ErrorResult & aRv)269 void ChannelWrapper::Resume(ErrorResult& aRv) {
270   if (mSuspended) {
271     nsresult rv = NS_ERROR_UNEXPECTED;
272     if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
273       rv = chan->Resume();
274     }
275     if (NS_FAILED(rv)) {
276       aRv.Throw(rv);
277     } else {
278       mSuspended = false;
279       PROFILER_MARKER_TEXT("Extension Suspend", NETWORK,
280                            MarkerOptions(MarkerTiming::IntervalEnd()),
281                            mSuspendedMarkerText);
282       mSuspendedMarkerText = VoidCString();
283     }
284   }
285 }
286 
GetContentType(nsCString & aContentType) const287 void ChannelWrapper::GetContentType(nsCString& aContentType) const {
288   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
289     Unused << chan->GetContentType(aContentType);
290   }
291 }
292 
SetContentType(const nsACString & aContentType)293 void ChannelWrapper::SetContentType(const nsACString& aContentType) {
294   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
295     Unused << chan->SetContentType(aContentType);
296   }
297 }
298 
299 /*****************************************************************************
300  * Headers
301  *****************************************************************************/
302 
303 namespace {
304 
305 class MOZ_STACK_CLASS HeaderVisitor final : public nsIHttpHeaderVisitor {
306  public:
307   NS_DECL_NSIHTTPHEADERVISITOR
308 
HeaderVisitor(nsTArray<dom::MozHTTPHeader> & aHeaders)309   explicit HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders)
310       : mHeaders(aHeaders) {}
311 
HeaderVisitor(nsTArray<dom::MozHTTPHeader> & aHeaders,const nsCString & aContentTypeHdr)312   HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders,
313                 const nsCString& aContentTypeHdr)
314       : mHeaders(aHeaders), mContentTypeHdr(aContentTypeHdr) {}
315 
VisitRequestHeaders(nsIHttpChannel * aChannel,ErrorResult & aRv)316   void VisitRequestHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv) {
317     CheckResult(aChannel->VisitRequestHeaders(this), aRv);
318   }
319 
VisitResponseHeaders(nsIHttpChannel * aChannel,ErrorResult & aRv)320   void VisitResponseHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv) {
321     CheckResult(aChannel->VisitResponseHeaders(this), aRv);
322   }
323 
324   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
325 
326   // Stub AddRef/Release since this is a stack class.
AddRef(void)327   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override {
328     return ++mRefCnt;
329   }
330 
Release(void)331   NS_IMETHOD_(MozExternalRefCountType) Release(void) override {
332     return --mRefCnt;
333   }
334 
~HeaderVisitor()335   virtual ~HeaderVisitor() { MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0); }
336 
337  private:
CheckResult(nsresult aNSRv,ErrorResult & aRv)338   bool CheckResult(nsresult aNSRv, ErrorResult& aRv) {
339     if (NS_FAILED(aNSRv)) {
340       aRv.Throw(aNSRv);
341       return false;
342     }
343     return true;
344   }
345 
346   nsTArray<dom::MozHTTPHeader>& mHeaders;
347   nsCString mContentTypeHdr = VoidCString();
348 
349   nsrefcnt mRefCnt = 0;
350 };
351 
352 NS_IMETHODIMP
VisitHeader(const nsACString & aHeader,const nsACString & aValue)353 HeaderVisitor::VisitHeader(const nsACString& aHeader,
354                            const nsACString& aValue) {
355   auto dict = mHeaders.AppendElement(fallible);
356   if (!dict) {
357     return NS_ERROR_OUT_OF_MEMORY;
358   }
359   dict->mName = aHeader;
360 
361   if (!mContentTypeHdr.IsVoid() &&
362       aHeader.LowerCaseEqualsLiteral("content-type")) {
363     dict->mValue = mContentTypeHdr;
364   } else {
365     dict->mValue = aValue;
366   }
367 
368   return NS_OK;
369 }
370 
371 NS_IMPL_QUERY_INTERFACE(HeaderVisitor, nsIHttpHeaderVisitor)
372 
373 }  // anonymous namespace
374 
GetRequestHeaders(nsTArray<dom::MozHTTPHeader> & aRetVal,ErrorResult & aRv) const375 void ChannelWrapper::GetRequestHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal,
376                                        ErrorResult& aRv) const {
377   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
378     HeaderVisitor visitor(aRetVal);
379     visitor.VisitRequestHeaders(chan, aRv);
380   } else {
381     aRv.Throw(NS_ERROR_UNEXPECTED);
382   }
383 }
384 
GetRequestHeader(const nsCString & aHeader,nsCString & aResult,ErrorResult & aRv) const385 void ChannelWrapper::GetRequestHeader(const nsCString& aHeader,
386                                       nsCString& aResult,
387                                       ErrorResult& aRv) const {
388   aResult.SetIsVoid(true);
389   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
390     Unused << chan->GetRequestHeader(aHeader, aResult);
391   } else {
392     aRv.Throw(NS_ERROR_UNEXPECTED);
393   }
394 }
395 
GetResponseHeaders(nsTArray<dom::MozHTTPHeader> & aRetVal,ErrorResult & aRv) const396 void ChannelWrapper::GetResponseHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal,
397                                         ErrorResult& aRv) const {
398   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
399     HeaderVisitor visitor(aRetVal, mContentTypeHdr);
400     visitor.VisitResponseHeaders(chan, aRv);
401   } else {
402     aRv.Throw(NS_ERROR_UNEXPECTED);
403   }
404 }
405 
SetRequestHeader(const nsCString & aHeader,const nsCString & aValue,bool aMerge,ErrorResult & aRv)406 void ChannelWrapper::SetRequestHeader(const nsCString& aHeader,
407                                       const nsCString& aValue, bool aMerge,
408                                       ErrorResult& aRv) {
409   nsresult rv = NS_ERROR_UNEXPECTED;
410   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
411     rv = chan->SetRequestHeader(aHeader, aValue, aMerge);
412   }
413   if (NS_FAILED(rv)) {
414     aRv.Throw(rv);
415   }
416 }
417 
SetResponseHeader(const nsCString & aHeader,const nsCString & aValue,bool aMerge,ErrorResult & aRv)418 void ChannelWrapper::SetResponseHeader(const nsCString& aHeader,
419                                        const nsCString& aValue, bool aMerge,
420                                        ErrorResult& aRv) {
421   nsresult rv = NS_ERROR_UNEXPECTED;
422   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
423     if (aHeader.LowerCaseEqualsLiteral("content-type")) {
424       rv = chan->SetContentType(aValue);
425       if (NS_SUCCEEDED(rv)) {
426         mContentTypeHdr = aValue;
427       }
428     } else {
429       rv = chan->SetResponseHeader(aHeader, aValue, aMerge);
430     }
431   }
432   if (NS_FAILED(rv)) {
433     aRv.Throw(rv);
434   }
435 }
436 
437 /*****************************************************************************
438  * LoadInfo
439  *****************************************************************************/
440 
GetLoadContext() const441 already_AddRefed<nsILoadContext> ChannelWrapper::GetLoadContext() const {
442   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
443     nsCOMPtr<nsILoadContext> ctxt;
444     NS_QueryNotificationCallbacks(chan, ctxt);
445     return ctxt.forget();
446   }
447   return nullptr;
448 }
449 
GetBrowserElement() const450 already_AddRefed<Element> ChannelWrapper::GetBrowserElement() const {
451   if (nsCOMPtr<nsILoadContext> ctxt = GetLoadContext()) {
452     RefPtr<Element> elem;
453     if (NS_SUCCEEDED(ctxt->GetTopFrameElement(getter_AddRefs(elem)))) {
454       return elem.forget();
455     }
456   }
457   return nullptr;
458 }
459 
IsServiceWorkerScript() const460 bool ChannelWrapper::IsServiceWorkerScript() const {
461   nsCOMPtr<nsIChannel> chan = MaybeChannel();
462   return IsServiceWorkerScript(chan);
463 }
464 
465 // static
IsServiceWorkerScript(const nsCOMPtr<nsIChannel> & chan)466 bool ChannelWrapper::IsServiceWorkerScript(const nsCOMPtr<nsIChannel>& chan) {
467   nsCOMPtr<nsILoadInfo> loadInfo;
468 
469   if (chan) {
470     chan->GetLoadInfo(getter_AddRefs(loadInfo));
471   }
472 
473   if (loadInfo) {
474     // Not a script.
475     if (loadInfo->GetExternalContentPolicyType() !=
476         ExtContentPolicy::TYPE_SCRIPT) {
477       return false;
478     }
479 
480     // Service worker main script load.
481     if (loadInfo->InternalContentPolicyType() ==
482         nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
483       return true;
484     }
485 
486     // Service worker import scripts load.
487     if (loadInfo->InternalContentPolicyType() ==
488         nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS) {
489       nsLoadFlags loadFlags = 0;
490       chan->GetLoadFlags(&loadFlags);
491       return loadFlags & nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
492     }
493   }
494 
495   return false;
496 }
497 
IsSystemPrincipal(nsIPrincipal * aPrincipal)498 static inline bool IsSystemPrincipal(nsIPrincipal* aPrincipal) {
499   return BasePrincipal::Cast(aPrincipal)->Is<SystemPrincipal>();
500 }
501 
IsSystemLoad() const502 bool ChannelWrapper::IsSystemLoad() const {
503   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
504     if (nsIPrincipal* prin = loadInfo->GetLoadingPrincipal()) {
505       return IsSystemPrincipal(prin);
506     }
507 
508     if (RefPtr<BrowsingContext> bc = loadInfo->GetBrowsingContext();
509         !bc || bc->IsTop()) {
510       return false;
511     }
512 
513     if (nsIPrincipal* prin = loadInfo->PrincipalToInherit()) {
514       return IsSystemPrincipal(prin);
515     }
516     if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) {
517       return IsSystemPrincipal(prin);
518     }
519   }
520   return false;
521 }
522 
CanModify() const523 bool ChannelWrapper::CanModify() const {
524   if (WebExtensionPolicy::IsRestrictedURI(FinalURLInfo())) {
525     return false;
526   }
527 
528   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
529     if (nsIPrincipal* prin = loadInfo->GetLoadingPrincipal()) {
530       if (IsSystemPrincipal(prin)) {
531         return false;
532       }
533 
534       auto* docURI = DocumentURLInfo();
535       if (docURI && WebExtensionPolicy::IsRestrictedURI(*docURI)) {
536         return false;
537       }
538     }
539   }
540   return true;
541 }
542 
GetOriginURI() const543 already_AddRefed<nsIURI> ChannelWrapper::GetOriginURI() const {
544   nsCOMPtr<nsIURI> uri;
545   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
546     if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) {
547       if (prin->GetIsContentPrincipal()) {
548         auto* basePrin = BasePrincipal::Cast(prin);
549         Unused << basePrin->GetURI(getter_AddRefs(uri));
550       }
551     }
552   }
553   return uri.forget();
554 }
555 
GetDocumentURI() const556 already_AddRefed<nsIURI> ChannelWrapper::GetDocumentURI() const {
557   nsCOMPtr<nsIURI> uri;
558   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
559     if (nsIPrincipal* prin = loadInfo->GetLoadingPrincipal()) {
560       if (prin->GetIsContentPrincipal()) {
561         auto* basePrin = BasePrincipal::Cast(prin);
562         Unused << basePrin->GetURI(getter_AddRefs(uri));
563       }
564     }
565   }
566   return uri.forget();
567 }
568 
GetOriginURL(nsCString & aRetVal) const569 void ChannelWrapper::GetOriginURL(nsCString& aRetVal) const {
570   if (nsCOMPtr<nsIURI> uri = GetOriginURI()) {
571     Unused << uri->GetSpec(aRetVal);
572   }
573 }
574 
GetDocumentURL(nsCString & aRetVal) const575 void ChannelWrapper::GetDocumentURL(nsCString& aRetVal) const {
576   if (nsCOMPtr<nsIURI> uri = GetDocumentURI()) {
577     Unused << uri->GetSpec(aRetVal);
578   }
579 }
580 
FinalURLInfo() const581 const URLInfo& ChannelWrapper::FinalURLInfo() const {
582   if (mFinalURLInfo.isNothing()) {
583     ErrorResult rv;
584     nsCOMPtr<nsIURI> uri = FinalURI();
585     MOZ_ASSERT(uri);
586 
587     // If this is a view-source scheme, get the nested uri.
588     while (uri && uri->SchemeIs("view-source")) {
589       nsCOMPtr<nsINestedURI> nested = do_QueryInterface(uri);
590       if (!nested) {
591         break;
592       }
593       nested->GetInnerURI(getter_AddRefs(uri));
594     }
595     mFinalURLInfo.emplace(uri.get(), true);
596 
597     // If this is a WebSocket request, mangle the URL so that the scheme is
598     // ws: or wss:, as appropriate.
599     auto& url = mFinalURLInfo.ref();
600     if (Type() == MozContentPolicyType::Websocket &&
601         (url.Scheme() == nsGkAtoms::http || url.Scheme() == nsGkAtoms::https)) {
602       nsAutoCString spec(url.CSpec());
603       spec.Replace(0, 4, "ws"_ns);
604 
605       Unused << NS_NewURI(getter_AddRefs(uri), spec);
606       MOZ_RELEASE_ASSERT(uri);
607       mFinalURLInfo.reset();
608       mFinalURLInfo.emplace(uri.get(), true);
609     }
610   }
611   return mFinalURLInfo.ref();
612 }
613 
DocumentURLInfo() const614 const URLInfo* ChannelWrapper::DocumentURLInfo() const {
615   if (mDocumentURLInfo.isNothing()) {
616     nsCOMPtr<nsIURI> uri = GetDocumentURI();
617     if (!uri) {
618       return nullptr;
619     }
620     mDocumentURLInfo.emplace(uri.get(), true);
621   }
622   return &mDocumentURLInfo.ref();
623 }
624 
Matches(const dom::MozRequestFilter & aFilter,const WebExtensionPolicy * aExtension,const dom::MozRequestMatchOptions & aOptions) const625 bool ChannelWrapper::Matches(
626     const dom::MozRequestFilter& aFilter, const WebExtensionPolicy* aExtension,
627     const dom::MozRequestMatchOptions& aOptions) const {
628   if (!HaveChannel()) {
629     return false;
630   }
631 
632   if (!aFilter.mTypes.IsNull() && !aFilter.mTypes.Value().Contains(Type())) {
633     return false;
634   }
635 
636   auto& urlInfo = FinalURLInfo();
637   if (aFilter.mUrls && !aFilter.mUrls->Matches(urlInfo)) {
638     return false;
639   }
640 
641   nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo();
642   bool isPrivate =
643       loadInfo && loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
644   if (!aFilter.mIncognito.IsNull() && aFilter.mIncognito.Value() != isPrivate) {
645     return false;
646   }
647 
648   if (aExtension) {
649     // Verify extension access to private requests
650     if (isPrivate && !aExtension->PrivateBrowsingAllowed()) {
651       return false;
652     }
653 
654     bool isProxy =
655         aOptions.mIsProxy && aExtension->HasPermission(nsGkAtoms::proxy);
656     // Proxies are allowed access to all urls, including restricted urls.
657     if (!aExtension->CanAccessURI(urlInfo, false, !isProxy, true)) {
658       return false;
659     }
660 
661     // If this isn't the proxy phase of the request, check that the extension
662     // has origin permissions for origin that originated the request.
663     if (!isProxy) {
664       if (IsSystemLoad()) {
665         return false;
666       }
667 
668       auto origin = DocumentURLInfo();
669       // Extensions with the file:-permission may observe requests from file:
670       // origins, because such documents can already be modified by content
671       // scripts anyway.
672       if (origin && !aExtension->CanAccessURI(*origin, false, true, true)) {
673         return false;
674       }
675     }
676   }
677 
678   return true;
679 }
680 
NormalizeFrameID(nsILoadInfo * aLoadInfo,uint64_t bcID)681 int64_t NormalizeFrameID(nsILoadInfo* aLoadInfo, uint64_t bcID) {
682   if (RefPtr<BrowsingContext> bc = aLoadInfo->GetBrowsingContext();
683       !bc || bcID == bc->Top()->Id()) {
684     return 0;
685   }
686   return bcID;
687 }
688 
BrowsingContextId(nsILoadInfo * aLoadInfo) const689 uint64_t ChannelWrapper::BrowsingContextId(nsILoadInfo* aLoadInfo) const {
690   auto frameID = aLoadInfo->GetFrameBrowsingContextID();
691   if (!frameID) {
692     frameID = aLoadInfo->GetBrowsingContextID();
693   }
694   return frameID;
695 }
696 
FrameId() const697 int64_t ChannelWrapper::FrameId() const {
698   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
699     return NormalizeFrameID(loadInfo, BrowsingContextId(loadInfo));
700   }
701   return 0;
702 }
703 
ParentFrameId() const704 int64_t ChannelWrapper::ParentFrameId() const {
705   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
706     if (RefPtr<BrowsingContext> bc = loadInfo->GetBrowsingContext()) {
707       if (BrowsingContextId(loadInfo) == bc->Top()->Id()) {
708         return -1;
709       }
710 
711       uint64_t parentID = -1;
712       if (loadInfo->GetFrameBrowsingContextID()) {
713         parentID = loadInfo->GetBrowsingContextID();
714       } else if (bc->GetParent()) {
715         parentID = bc->GetParent()->Id();
716       }
717       return NormalizeFrameID(loadInfo, parentID);
718     }
719   }
720   return -1;
721 }
722 
GetFrameAncestors(dom::Nullable<nsTArray<dom::MozFrameAncestorInfo>> & aFrameAncestors,ErrorResult & aRv) const723 void ChannelWrapper::GetFrameAncestors(
724     dom::Nullable<nsTArray<dom::MozFrameAncestorInfo>>& aFrameAncestors,
725     ErrorResult& aRv) const {
726   nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo();
727   if (!loadInfo || BrowsingContextId(loadInfo) == 0) {
728     aFrameAncestors.SetNull();
729     return;
730   }
731 
732   nsresult rv = GetFrameAncestors(loadInfo, aFrameAncestors.SetValue());
733   if (NS_FAILED(rv)) {
734     aRv.Throw(rv);
735   }
736 }
737 
GetFrameAncestors(nsILoadInfo * aLoadInfo,nsTArray<dom::MozFrameAncestorInfo> & aFrameAncestors) const738 nsresult ChannelWrapper::GetFrameAncestors(
739     nsILoadInfo* aLoadInfo,
740     nsTArray<dom::MozFrameAncestorInfo>& aFrameAncestors) const {
741   const nsTArray<nsCOMPtr<nsIPrincipal>>& ancestorPrincipals =
742       aLoadInfo->AncestorPrincipals();
743   const nsTArray<uint64_t>& ancestorBrowsingContextIDs =
744       aLoadInfo->AncestorBrowsingContextIDs();
745   uint32_t size = ancestorPrincipals.Length();
746   MOZ_DIAGNOSTIC_ASSERT(size == ancestorBrowsingContextIDs.Length());
747   if (size != ancestorBrowsingContextIDs.Length()) {
748     return NS_ERROR_UNEXPECTED;
749   }
750 
751   bool subFrame = aLoadInfo->GetExternalContentPolicyType() ==
752                   ExtContentPolicy::TYPE_SUBDOCUMENT;
753   if (!aFrameAncestors.SetCapacity(subFrame ? size : size + 1, fallible)) {
754     return NS_ERROR_OUT_OF_MEMORY;
755   }
756 
757   // The immediate parent is always the first element in the ancestor arrays,
758   // however SUBDOCUMENTs do not have their immediate parent included, so we
759   // inject it here. This will force wrapper.parentBrowsingContextId ==
760   // wrapper.frameAncestors[0].frameId to always be true.  All ather requests
761   // already match this way.
762   if (subFrame) {
763     auto ancestor = aFrameAncestors.AppendElement();
764     GetDocumentURL(ancestor->mUrl);
765     ancestor->mFrameId = ParentFrameId();
766   }
767 
768   for (uint32_t i = 0; i < size; ++i) {
769     auto ancestor = aFrameAncestors.AppendElement();
770     MOZ_TRY(ancestorPrincipals[i]->GetAsciiSpec(ancestor->mUrl));
771     ancestor->mFrameId =
772         NormalizeFrameID(aLoadInfo, ancestorBrowsingContextIDs[i]);
773   }
774   return NS_OK;
775 }
776 
777 /*****************************************************************************
778  * Response filtering
779  *****************************************************************************/
780 
RegisterTraceableChannel(const WebExtensionPolicy & aAddon,nsIRemoteTab * aBrowserParent)781 void ChannelWrapper::RegisterTraceableChannel(const WebExtensionPolicy& aAddon,
782                                               nsIRemoteTab* aBrowserParent) {
783   // We can't attach new listeners after the response has started, so don't
784   // bother registering anything.
785   if (mResponseStarted || !CanModify()) {
786     return;
787   }
788 
789   mAddonEntries.InsertOrUpdate(aAddon.Id(), aBrowserParent);
790   if (!mChannelEntry) {
791     mChannelEntry = WebRequestService::GetSingleton().RegisterChannel(this);
792     CheckEventListeners();
793   }
794 }
795 
GetTraceableChannel(nsAtom * aAddonId,dom::ContentParent * aContentParent) const796 already_AddRefed<nsITraceableChannel> ChannelWrapper::GetTraceableChannel(
797     nsAtom* aAddonId, dom::ContentParent* aContentParent) const {
798   nsCOMPtr<nsIRemoteTab> remoteTab;
799   if (mAddonEntries.Get(aAddonId, getter_AddRefs(remoteTab))) {
800     ContentParent* contentParent = nullptr;
801     if (remoteTab) {
802       contentParent =
803           BrowserHost::GetFrom(remoteTab.get())->GetActor()->Manager();
804     }
805 
806     if (contentParent == aContentParent) {
807       nsCOMPtr<nsITraceableChannel> chan = QueryChannel();
808       return chan.forget();
809     }
810   }
811   return nullptr;
812 }
813 
814 /*****************************************************************************
815  * ...
816  *****************************************************************************/
817 
GetContentPolicyType(ExtContentPolicyType aType)818 MozContentPolicyType GetContentPolicyType(ExtContentPolicyType aType) {
819   // Note: Please keep this function in sync with the external types in
820   // nsIContentPolicy.idl
821   switch (aType) {
822     case ExtContentPolicy::TYPE_DOCUMENT:
823       return MozContentPolicyType::Main_frame;
824     case ExtContentPolicy::TYPE_SUBDOCUMENT:
825       return MozContentPolicyType::Sub_frame;
826     case ExtContentPolicy::TYPE_STYLESHEET:
827       return MozContentPolicyType::Stylesheet;
828     case ExtContentPolicy::TYPE_SCRIPT:
829       return MozContentPolicyType::Script;
830     case ExtContentPolicy::TYPE_IMAGE:
831       return MozContentPolicyType::Image;
832     case ExtContentPolicy::TYPE_OBJECT:
833       return MozContentPolicyType::Object;
834     case ExtContentPolicy::TYPE_OBJECT_SUBREQUEST:
835       return MozContentPolicyType::Object_subrequest;
836     case ExtContentPolicy::TYPE_XMLHTTPREQUEST:
837       return MozContentPolicyType::Xmlhttprequest;
838     // TYPE_FETCH returns xmlhttprequest for cross-browser compatibility.
839     case ExtContentPolicy::TYPE_FETCH:
840       return MozContentPolicyType::Xmlhttprequest;
841     case ExtContentPolicy::TYPE_XSLT:
842       return MozContentPolicyType::Xslt;
843     case ExtContentPolicy::TYPE_PING:
844       return MozContentPolicyType::Ping;
845     case ExtContentPolicy::TYPE_BEACON:
846       return MozContentPolicyType::Beacon;
847     case ExtContentPolicy::TYPE_DTD:
848       return MozContentPolicyType::Xml_dtd;
849     case ExtContentPolicy::TYPE_FONT:
850     case ExtContentPolicy::TYPE_UA_FONT:
851       return MozContentPolicyType::Font;
852     case ExtContentPolicy::TYPE_MEDIA:
853       return MozContentPolicyType::Media;
854     case ExtContentPolicy::TYPE_WEBSOCKET:
855       return MozContentPolicyType::Websocket;
856     case ExtContentPolicy::TYPE_CSP_REPORT:
857       return MozContentPolicyType::Csp_report;
858     case ExtContentPolicy::TYPE_IMAGESET:
859       return MozContentPolicyType::Imageset;
860     case ExtContentPolicy::TYPE_WEB_MANIFEST:
861       return MozContentPolicyType::Web_manifest;
862     case ExtContentPolicy::TYPE_SPECULATIVE:
863       return MozContentPolicyType::Speculative;
864     case ExtContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA:
865     case ExtContentPolicy::TYPE_INVALID:
866     case ExtContentPolicy::TYPE_OTHER:
867     case ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD:
868       break;
869       // Do not add default: so that compilers can catch the missing case.
870   }
871   return MozContentPolicyType::Other;
872 }
873 
Type() const874 MozContentPolicyType ChannelWrapper::Type() const {
875   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
876     return GetContentPolicyType(loadInfo->GetExternalContentPolicyType());
877   }
878   return MozContentPolicyType::Other;
879 }
880 
GetMethod(nsCString & aMethod) const881 void ChannelWrapper::GetMethod(nsCString& aMethod) const {
882   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
883     Unused << chan->GetRequestMethod(aMethod);
884   }
885 }
886 
887 /*****************************************************************************
888  * ...
889  *****************************************************************************/
890 
StatusCode() const891 uint32_t ChannelWrapper::StatusCode() const {
892   uint32_t result = 0;
893   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
894     Unused << chan->GetResponseStatus(&result);
895   }
896   return result;
897 }
898 
GetStatusLine(nsCString & aRetVal) const899 void ChannelWrapper::GetStatusLine(nsCString& aRetVal) const {
900   nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel();
901   nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(chan);
902 
903   if (internal) {
904     nsAutoCString statusText;
905     uint32_t major, minor, status;
906     if (NS_FAILED(chan->GetResponseStatus(&status)) ||
907         NS_FAILED(chan->GetResponseStatusText(statusText)) ||
908         NS_FAILED(internal->GetResponseVersion(&major, &minor))) {
909       return;
910     }
911 
912     aRetVal = nsPrintfCString("HTTP/%u.%u %u %s", major, minor, status,
913                               statusText.get());
914   }
915 }
916 
ResponseSize() const917 uint64_t ChannelWrapper::ResponseSize() const {
918   uint64_t result = 0;
919   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
920     Unused << chan->GetTransferSize(&result);
921   }
922   return result;
923 }
924 
RequestSize() const925 uint64_t ChannelWrapper::RequestSize() const {
926   uint64_t result = 0;
927   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
928     Unused << chan->GetRequestSize(&result);
929   }
930   return result;
931 }
932 
933 /*****************************************************************************
934  * ...
935  *****************************************************************************/
936 
FinalURI() const937 already_AddRefed<nsIURI> ChannelWrapper::FinalURI() const {
938   nsCOMPtr<nsIURI> uri;
939   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
940     NS_GetFinalChannelURI(chan, getter_AddRefs(uri));
941   }
942   return uri.forget();
943 }
944 
GetFinalURL(nsString & aRetVal) const945 void ChannelWrapper::GetFinalURL(nsString& aRetVal) const {
946   if (HaveChannel()) {
947     aRetVal = FinalURLInfo().Spec();
948   }
949 }
950 
951 /*****************************************************************************
952  * ...
953  *****************************************************************************/
954 
FillProxyInfo(MozProxyInfo & aDict,nsIProxyInfo * aProxyInfo)955 nsresult FillProxyInfo(MozProxyInfo& aDict, nsIProxyInfo* aProxyInfo) {
956   MOZ_TRY(aProxyInfo->GetHost(aDict.mHost));
957   MOZ_TRY(aProxyInfo->GetPort(&aDict.mPort));
958   MOZ_TRY(aProxyInfo->GetType(aDict.mType));
959   MOZ_TRY(aProxyInfo->GetUsername(aDict.mUsername));
960   MOZ_TRY(
961       aProxyInfo->GetProxyAuthorizationHeader(aDict.mProxyAuthorizationHeader));
962   MOZ_TRY(aProxyInfo->GetConnectionIsolationKey(aDict.mConnectionIsolationKey));
963   MOZ_TRY(aProxyInfo->GetFailoverTimeout(&aDict.mFailoverTimeout.Construct()));
964 
965   uint32_t flags;
966   MOZ_TRY(aProxyInfo->GetFlags(&flags));
967   aDict.mProxyDNS = flags & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
968 
969   return NS_OK;
970 }
971 
GetProxyInfo(dom::Nullable<MozProxyInfo> & aRetVal,ErrorResult & aRv) const972 void ChannelWrapper::GetProxyInfo(dom::Nullable<MozProxyInfo>& aRetVal,
973                                   ErrorResult& aRv) const {
974   nsCOMPtr<nsIProxyInfo> proxyInfo;
975   if (nsCOMPtr<nsIProxiedChannel> proxied = QueryChannel()) {
976     Unused << proxied->GetProxyInfo(getter_AddRefs(proxyInfo));
977   }
978   if (proxyInfo) {
979     MozProxyInfo result;
980 
981     nsresult rv = FillProxyInfo(result, proxyInfo);
982     if (NS_FAILED(rv)) {
983       aRv.Throw(rv);
984     } else {
985       aRetVal.SetValue(std::move(result));
986     }
987   }
988 }
989 
GetRemoteAddress(nsCString & aRetVal) const990 void ChannelWrapper::GetRemoteAddress(nsCString& aRetVal) const {
991   aRetVal.SetIsVoid(true);
992   if (nsCOMPtr<nsIHttpChannelInternal> internal = QueryChannel()) {
993     Unused << internal->GetRemoteAddress(aRetVal);
994   }
995 }
996 
FillClassification(Sequence<mozilla::dom::MozUrlClassificationFlags> & classifications,uint32_t classificationFlags,ErrorResult & aRv)997 void FillClassification(
998     Sequence<mozilla::dom::MozUrlClassificationFlags>& classifications,
999     uint32_t classificationFlags, ErrorResult& aRv) {
1000   if (classificationFlags == 0) {
1001     return;
1002   }
1003   for (const auto& entry : classificationArray) {
1004     if (classificationFlags & entry.mFlag) {
1005       if (!classifications.AppendElement(entry.mValue, mozilla::fallible)) {
1006         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1007         return;
1008       }
1009     }
1010   }
1011 }
1012 
GetUrlClassification(dom::Nullable<dom::MozUrlClassification> & aRetVal,ErrorResult & aRv) const1013 void ChannelWrapper::GetUrlClassification(
1014     dom::Nullable<dom::MozUrlClassification>& aRetVal, ErrorResult& aRv) const {
1015   MozUrlClassification classification;
1016   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
1017     nsCOMPtr<nsIClassifiedChannel> classified = do_QueryInterface(chan);
1018     MOZ_DIAGNOSTIC_ASSERT(
1019         classified,
1020         "Must be an object inheriting from both nsIHttpChannel and "
1021         "nsIClassifiedChannel");
1022     uint32_t classificationFlags;
1023     classified->GetFirstPartyClassificationFlags(&classificationFlags);
1024     FillClassification(classification.mFirstParty, classificationFlags, aRv);
1025     if (aRv.Failed()) {
1026       return;
1027     }
1028     classified->GetThirdPartyClassificationFlags(&classificationFlags);
1029     FillClassification(classification.mThirdParty, classificationFlags, aRv);
1030   }
1031   aRetVal.SetValue(std::move(classification));
1032 }
1033 
ThirdParty() const1034 bool ChannelWrapper::ThirdParty() const {
1035   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
1036       components::ThirdPartyUtil::Service();
1037   if (NS_WARN_IF(!thirdPartyUtil)) {
1038     return true;
1039   }
1040 
1041   nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel();
1042   if (!chan) {
1043     return false;
1044   }
1045 
1046   bool thirdParty = false;
1047   nsresult rv = thirdPartyUtil->IsThirdPartyChannel(chan, nullptr, &thirdParty);
1048   if (NS_WARN_IF(NS_FAILED(rv))) {
1049     return true;
1050   }
1051 
1052   return thirdParty;
1053 }
1054 
1055 /*****************************************************************************
1056  * Error handling
1057  *****************************************************************************/
1058 
GetErrorString(nsString & aRetVal) const1059 void ChannelWrapper::GetErrorString(nsString& aRetVal) const {
1060   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
1061     nsCOMPtr<nsISupports> securityInfo;
1062     Unused << chan->GetSecurityInfo(getter_AddRefs(securityInfo));
1063     if (nsCOMPtr<nsITransportSecurityInfo> tsi =
1064             do_QueryInterface(securityInfo)) {
1065       int32_t errorCode = 0;
1066       tsi->GetErrorCode(&errorCode);
1067       if (psm::IsNSSErrorCode(errorCode)) {
1068         nsCOMPtr<nsINSSErrorsService> nsserr =
1069             do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
1070 
1071         nsresult rv = psm::GetXPCOMFromNSSError(errorCode);
1072         if (nsserr && NS_SUCCEEDED(nsserr->GetErrorMessage(rv, aRetVal))) {
1073           return;
1074         }
1075       }
1076     }
1077 
1078     nsresult status;
1079     if (NS_SUCCEEDED(chan->GetStatus(&status)) && NS_FAILED(status)) {
1080       nsAutoCString name;
1081       GetErrorName(status, name);
1082       AppendUTF8toUTF16(name, aRetVal);
1083     } else {
1084       aRetVal.SetIsVoid(true);
1085     }
1086   } else {
1087     aRetVal.AssignLiteral("NS_ERROR_UNEXPECTED");
1088   }
1089 }
1090 
ErrorCheck()1091 void ChannelWrapper::ErrorCheck() {
1092   if (!mFiredErrorEvent) {
1093     nsAutoString error;
1094     GetErrorString(error);
1095     if (error.Length()) {
1096       mChannelEntry = nullptr;
1097       mFiredErrorEvent = true;
1098       ChannelWrapper_Binding::ClearCachedErrorStringValue(this);
1099       FireEvent(u"error"_ns);
1100     }
1101   }
1102 }
1103 
1104 /*****************************************************************************
1105  * nsIWebRequestListener
1106  *****************************************************************************/
1107 
NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener,nsIStreamListener,nsIMultiPartChannelListener,nsIRequestObserver,nsIThreadRetargetableStreamListener)1108 NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener, nsIStreamListener,
1109                   nsIMultiPartChannelListener, nsIRequestObserver,
1110                   nsIThreadRetargetableStreamListener)
1111 
1112 ChannelWrapper::RequestListener::~RequestListener() {
1113   NS_ReleaseOnMainThread("RequestListener::mChannelWrapper",
1114                          mChannelWrapper.forget());
1115 }
1116 
Init()1117 nsresult ChannelWrapper::RequestListener::Init() {
1118   if (nsCOMPtr<nsITraceableChannel> chan = mChannelWrapper->QueryChannel()) {
1119     return chan->SetNewListener(this, false,
1120                                 getter_AddRefs(mOrigStreamListener));
1121   }
1122   return NS_ERROR_UNEXPECTED;
1123 }
1124 
1125 NS_IMETHODIMP
OnStartRequest(nsIRequest * request)1126 ChannelWrapper::RequestListener::OnStartRequest(nsIRequest* request) {
1127   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1128 
1129   mChannelWrapper->mChannelEntry = nullptr;
1130   mChannelWrapper->mResponseStarted = true;
1131   mChannelWrapper->ErrorCheck();
1132   mChannelWrapper->FireEvent(u"start"_ns);
1133 
1134   return mOrigStreamListener->OnStartRequest(request);
1135 }
1136 
1137 NS_IMETHODIMP
OnStopRequest(nsIRequest * request,nsresult aStatus)1138 ChannelWrapper::RequestListener::OnStopRequest(nsIRequest* request,
1139                                                nsresult aStatus) {
1140   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1141 
1142   mChannelWrapper->mChannelEntry = nullptr;
1143   mChannelWrapper->ErrorCheck();
1144   mChannelWrapper->FireEvent(u"stop"_ns);
1145 
1146   return mOrigStreamListener->OnStopRequest(request, aStatus);
1147 }
1148 
1149 NS_IMETHODIMP
OnDataAvailable(nsIRequest * request,nsIInputStream * inStr,uint64_t sourceOffset,uint32_t count)1150 ChannelWrapper::RequestListener::OnDataAvailable(nsIRequest* request,
1151                                                  nsIInputStream* inStr,
1152                                                  uint64_t sourceOffset,
1153                                                  uint32_t count) {
1154   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1155   return mOrigStreamListener->OnDataAvailable(request, inStr, sourceOffset,
1156                                               count);
1157 }
1158 
1159 NS_IMETHODIMP
OnAfterLastPart(nsresult aStatus)1160 ChannelWrapper::RequestListener::OnAfterLastPart(nsresult aStatus) {
1161   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1162   if (nsCOMPtr<nsIMultiPartChannelListener> listener =
1163           do_QueryInterface(mOrigStreamListener)) {
1164     return listener->OnAfterLastPart(aStatus);
1165   }
1166   return NS_OK;
1167 }
1168 
1169 NS_IMETHODIMP
CheckListenerChain()1170 ChannelWrapper::RequestListener::CheckListenerChain() {
1171   MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!");
1172   nsresult rv;
1173   nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
1174       do_QueryInterface(mOrigStreamListener, &rv);
1175   if (retargetableListener) {
1176     return retargetableListener->CheckListenerChain();
1177   }
1178   return rv;
1179 }
1180 
1181 /*****************************************************************************
1182  * Event dispatching
1183  *****************************************************************************/
1184 
FireEvent(const nsAString & aType)1185 void ChannelWrapper::FireEvent(const nsAString& aType) {
1186   EventInit init;
1187   init.mBubbles = false;
1188   init.mCancelable = false;
1189 
1190   RefPtr<Event> event = Event::Constructor(this, aType, init);
1191   event->SetTrusted(true);
1192 
1193   DispatchEvent(*event);
1194 }
1195 
CheckEventListeners()1196 void ChannelWrapper::CheckEventListeners() {
1197   if (!mAddedStreamListener &&
1198       (HasListenersFor(nsGkAtoms::onerror) ||
1199        HasListenersFor(nsGkAtoms::onstart) ||
1200        HasListenersFor(nsGkAtoms::onstop) || mChannelEntry)) {
1201     auto listener = MakeRefPtr<RequestListener>(this);
1202     if (!NS_WARN_IF(NS_FAILED(listener->Init()))) {
1203       mAddedStreamListener = true;
1204     }
1205   }
1206 }
1207 
EventListenerAdded(nsAtom * aType)1208 void ChannelWrapper::EventListenerAdded(nsAtom* aType) {
1209   CheckEventListeners();
1210 }
1211 
EventListenerRemoved(nsAtom * aType)1212 void ChannelWrapper::EventListenerRemoved(nsAtom* aType) {
1213   CheckEventListeners();
1214 }
1215 
1216 /*****************************************************************************
1217  * Glue
1218  *****************************************************************************/
1219 
WrapObject(JSContext * aCx,HandleObject aGivenProto)1220 JSObject* ChannelWrapper::WrapObject(JSContext* aCx, HandleObject aGivenProto) {
1221   return ChannelWrapper_Binding::Wrap(aCx, this, aGivenProto);
1222 }
1223 
1224 NS_IMPL_CYCLE_COLLECTION_CLASS(ChannelWrapper)
1225 
1226 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper)
1227   NS_INTERFACE_MAP_ENTRY(ChannelWrapper)
1228 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
1229 
1230 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ChannelWrapper,
1231                                                 DOMEventTargetHelper)
1232   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
1233   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStub)
1234   NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
1235 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1236 
1237 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ChannelWrapper,
1238                                                   DOMEventTargetHelper)
1239   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
1240   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStub)
1241 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1242 
1243 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ChannelWrapper,
1244                                                DOMEventTargetHelper)
1245 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1246 
1247 NS_IMPL_ADDREF_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1248 NS_IMPL_RELEASE_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1249 
1250 }  // namespace extensions
1251 }  // namespace mozilla
1252