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(ErrorResult & aRv)249 void ChannelWrapper::Suspend(ErrorResult& aRv) {
250   if (!mSuspended) {
251     nsresult rv = NS_ERROR_UNEXPECTED;
252     if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
253       mSuspendTime = mozilla::TimeStamp::NowUnfuzzed();
254       rv = chan->Suspend();
255     }
256     if (NS_FAILED(rv)) {
257       aRv.Throw(rv);
258     } else {
259       mSuspended = true;
260     }
261   }
262 }
263 
Resume(const nsCString & aText,ErrorResult & aRv)264 void ChannelWrapper::Resume(const nsCString& aText, ErrorResult& aRv) {
265   if (mSuspended) {
266     nsresult rv = NS_ERROR_UNEXPECTED;
267     if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
268       rv = chan->Resume();
269 
270       PROFILER_MARKER_TEXT("Extension Suspend", NETWORK,
271                            MarkerTiming::IntervalUntilNowFrom(mSuspendTime),
272                            aText);
273     }
274     if (NS_FAILED(rv)) {
275       aRv.Throw(rv);
276     } else {
277       mSuspended = false;
278     }
279   }
280 }
281 
GetContentType(nsCString & aContentType) const282 void ChannelWrapper::GetContentType(nsCString& aContentType) const {
283   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
284     Unused << chan->GetContentType(aContentType);
285   }
286 }
287 
SetContentType(const nsACString & aContentType)288 void ChannelWrapper::SetContentType(const nsACString& aContentType) {
289   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
290     Unused << chan->SetContentType(aContentType);
291   }
292 }
293 
294 /*****************************************************************************
295  * Headers
296  *****************************************************************************/
297 
298 namespace {
299 
300 class MOZ_STACK_CLASS HeaderVisitor final : public nsIHttpHeaderVisitor {
301  public:
302   NS_DECL_NSIHTTPHEADERVISITOR
303 
HeaderVisitor(nsTArray<dom::MozHTTPHeader> & aHeaders)304   explicit HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders)
305       : mHeaders(aHeaders) {}
306 
HeaderVisitor(nsTArray<dom::MozHTTPHeader> & aHeaders,const nsCString & aContentTypeHdr)307   HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders,
308                 const nsCString& aContentTypeHdr)
309       : mHeaders(aHeaders), mContentTypeHdr(aContentTypeHdr) {}
310 
VisitRequestHeaders(nsIHttpChannel * aChannel,ErrorResult & aRv)311   void VisitRequestHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv) {
312     CheckResult(aChannel->VisitRequestHeaders(this), aRv);
313   }
314 
VisitResponseHeaders(nsIHttpChannel * aChannel,ErrorResult & aRv)315   void VisitResponseHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv) {
316     CheckResult(aChannel->VisitResponseHeaders(this), aRv);
317   }
318 
319   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
320 
321   // Stub AddRef/Release since this is a stack class.
AddRef(void)322   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override {
323     return ++mRefCnt;
324   }
325 
Release(void)326   NS_IMETHOD_(MozExternalRefCountType) Release(void) override {
327     return --mRefCnt;
328   }
329 
~HeaderVisitor()330   virtual ~HeaderVisitor() { MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0); }
331 
332  private:
CheckResult(nsresult aNSRv,ErrorResult & aRv)333   bool CheckResult(nsresult aNSRv, ErrorResult& aRv) {
334     if (NS_FAILED(aNSRv)) {
335       aRv.Throw(aNSRv);
336       return false;
337     }
338     return true;
339   }
340 
341   nsTArray<dom::MozHTTPHeader>& mHeaders;
342   nsCString mContentTypeHdr = VoidCString();
343 
344   nsrefcnt mRefCnt = 0;
345 };
346 
347 NS_IMETHODIMP
VisitHeader(const nsACString & aHeader,const nsACString & aValue)348 HeaderVisitor::VisitHeader(const nsACString& aHeader,
349                            const nsACString& aValue) {
350   auto dict = mHeaders.AppendElement(fallible);
351   if (!dict) {
352     return NS_ERROR_OUT_OF_MEMORY;
353   }
354   dict->mName = aHeader;
355 
356   if (!mContentTypeHdr.IsVoid() &&
357       aHeader.LowerCaseEqualsLiteral("content-type")) {
358     dict->mValue = mContentTypeHdr;
359   } else {
360     dict->mValue = aValue;
361   }
362 
363   return NS_OK;
364 }
365 
366 NS_IMPL_QUERY_INTERFACE(HeaderVisitor, nsIHttpHeaderVisitor)
367 
368 }  // anonymous namespace
369 
GetRequestHeaders(nsTArray<dom::MozHTTPHeader> & aRetVal,ErrorResult & aRv) const370 void ChannelWrapper::GetRequestHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal,
371                                        ErrorResult& aRv) const {
372   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
373     HeaderVisitor visitor(aRetVal);
374     visitor.VisitRequestHeaders(chan, aRv);
375   } else {
376     aRv.Throw(NS_ERROR_UNEXPECTED);
377   }
378 }
379 
GetRequestHeader(const nsCString & aHeader,nsCString & aResult,ErrorResult & aRv) const380 void ChannelWrapper::GetRequestHeader(const nsCString& aHeader,
381                                       nsCString& aResult,
382                                       ErrorResult& aRv) const {
383   aResult.SetIsVoid(true);
384   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
385     Unused << chan->GetRequestHeader(aHeader, aResult);
386   } else {
387     aRv.Throw(NS_ERROR_UNEXPECTED);
388   }
389 }
390 
GetResponseHeaders(nsTArray<dom::MozHTTPHeader> & aRetVal,ErrorResult & aRv) const391 void ChannelWrapper::GetResponseHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal,
392                                         ErrorResult& aRv) const {
393   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
394     HeaderVisitor visitor(aRetVal, mContentTypeHdr);
395     visitor.VisitResponseHeaders(chan, aRv);
396   } else {
397     aRv.Throw(NS_ERROR_UNEXPECTED);
398   }
399 }
400 
SetRequestHeader(const nsCString & aHeader,const nsCString & aValue,bool aMerge,ErrorResult & aRv)401 void ChannelWrapper::SetRequestHeader(const nsCString& aHeader,
402                                       const nsCString& aValue, bool aMerge,
403                                       ErrorResult& aRv) {
404   nsresult rv = NS_ERROR_UNEXPECTED;
405   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
406     rv = chan->SetRequestHeader(aHeader, aValue, aMerge);
407   }
408   if (NS_FAILED(rv)) {
409     aRv.Throw(rv);
410   }
411 }
412 
SetResponseHeader(const nsCString & aHeader,const nsCString & aValue,bool aMerge,ErrorResult & aRv)413 void ChannelWrapper::SetResponseHeader(const nsCString& aHeader,
414                                        const nsCString& aValue, bool aMerge,
415                                        ErrorResult& aRv) {
416   nsresult rv = NS_ERROR_UNEXPECTED;
417   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
418     if (aHeader.LowerCaseEqualsLiteral("content-type")) {
419       rv = chan->SetContentType(aValue);
420       if (NS_SUCCEEDED(rv)) {
421         mContentTypeHdr = aValue;
422       }
423     } else {
424       rv = chan->SetResponseHeader(aHeader, aValue, aMerge);
425     }
426   }
427   if (NS_FAILED(rv)) {
428     aRv.Throw(rv);
429   }
430 }
431 
432 /*****************************************************************************
433  * LoadInfo
434  *****************************************************************************/
435 
GetLoadContext() const436 already_AddRefed<nsILoadContext> ChannelWrapper::GetLoadContext() const {
437   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
438     nsCOMPtr<nsILoadContext> ctxt;
439     NS_QueryNotificationCallbacks(chan, ctxt);
440     return ctxt.forget();
441   }
442   return nullptr;
443 }
444 
GetBrowserElement() const445 already_AddRefed<Element> ChannelWrapper::GetBrowserElement() const {
446   if (nsCOMPtr<nsILoadContext> ctxt = GetLoadContext()) {
447     RefPtr<Element> elem;
448     if (NS_SUCCEEDED(ctxt->GetTopFrameElement(getter_AddRefs(elem)))) {
449       return elem.forget();
450     }
451   }
452   return nullptr;
453 }
454 
IsSystemPrincipal(nsIPrincipal * aPrincipal)455 static inline bool IsSystemPrincipal(nsIPrincipal* aPrincipal) {
456   return BasePrincipal::Cast(aPrincipal)->Is<SystemPrincipal>();
457 }
458 
IsSystemLoad() const459 bool ChannelWrapper::IsSystemLoad() const {
460   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
461     if (nsIPrincipal* prin = loadInfo->GetLoadingPrincipal()) {
462       return IsSystemPrincipal(prin);
463     }
464 
465     if (RefPtr<BrowsingContext> bc = loadInfo->GetBrowsingContext();
466         !bc || bc->IsTop()) {
467       return false;
468     }
469 
470     if (nsIPrincipal* prin = loadInfo->PrincipalToInherit()) {
471       return IsSystemPrincipal(prin);
472     }
473     if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) {
474       return IsSystemPrincipal(prin);
475     }
476   }
477   return false;
478 }
479 
CanModify() const480 bool ChannelWrapper::CanModify() const {
481   if (WebExtensionPolicy::IsRestrictedURI(FinalURLInfo())) {
482     return false;
483   }
484 
485   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
486     if (nsIPrincipal* prin = loadInfo->GetLoadingPrincipal()) {
487       if (IsSystemPrincipal(prin)) {
488         return false;
489       }
490 
491       auto* docURI = DocumentURLInfo();
492       if (docURI && WebExtensionPolicy::IsRestrictedURI(*docURI)) {
493         return false;
494       }
495     }
496   }
497   return true;
498 }
499 
GetOriginURI() const500 already_AddRefed<nsIURI> ChannelWrapper::GetOriginURI() const {
501   nsCOMPtr<nsIURI> uri;
502   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
503     if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) {
504       if (prin->GetIsContentPrincipal()) {
505         auto* basePrin = BasePrincipal::Cast(prin);
506         Unused << basePrin->GetURI(getter_AddRefs(uri));
507       }
508     }
509   }
510   return uri.forget();
511 }
512 
GetDocumentURI() const513 already_AddRefed<nsIURI> ChannelWrapper::GetDocumentURI() const {
514   nsCOMPtr<nsIURI> uri;
515   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
516     if (nsIPrincipal* prin = loadInfo->GetLoadingPrincipal()) {
517       if (prin->GetIsContentPrincipal()) {
518         auto* basePrin = BasePrincipal::Cast(prin);
519         Unused << basePrin->GetURI(getter_AddRefs(uri));
520       }
521     }
522   }
523   return uri.forget();
524 }
525 
GetOriginURL(nsCString & aRetVal) const526 void ChannelWrapper::GetOriginURL(nsCString& aRetVal) const {
527   if (nsCOMPtr<nsIURI> uri = GetOriginURI()) {
528     Unused << uri->GetSpec(aRetVal);
529   }
530 }
531 
GetDocumentURL(nsCString & aRetVal) const532 void ChannelWrapper::GetDocumentURL(nsCString& aRetVal) const {
533   if (nsCOMPtr<nsIURI> uri = GetDocumentURI()) {
534     Unused << uri->GetSpec(aRetVal);
535   }
536 }
537 
FinalURLInfo() const538 const URLInfo& ChannelWrapper::FinalURLInfo() const {
539   if (mFinalURLInfo.isNothing()) {
540     ErrorResult rv;
541     nsCOMPtr<nsIURI> uri = FinalURI();
542     MOZ_ASSERT(uri);
543 
544     // If this is a view-source scheme, get the nested uri.
545     while (uri && uri->SchemeIs("view-source")) {
546       nsCOMPtr<nsINestedURI> nested = do_QueryInterface(uri);
547       if (!nested) {
548         break;
549       }
550       nested->GetInnerURI(getter_AddRefs(uri));
551     }
552     mFinalURLInfo.emplace(uri.get(), true);
553 
554     // If this is a WebSocket request, mangle the URL so that the scheme is
555     // ws: or wss:, as appropriate.
556     auto& url = mFinalURLInfo.ref();
557     if (Type() == MozContentPolicyType::Websocket &&
558         (url.Scheme() == nsGkAtoms::http || url.Scheme() == nsGkAtoms::https)) {
559       nsAutoCString spec(url.CSpec());
560       spec.Replace(0, 4, "ws"_ns);
561 
562       Unused << NS_NewURI(getter_AddRefs(uri), spec);
563       MOZ_RELEASE_ASSERT(uri);
564       mFinalURLInfo.reset();
565       mFinalURLInfo.emplace(uri.get(), true);
566     }
567   }
568   return mFinalURLInfo.ref();
569 }
570 
DocumentURLInfo() const571 const URLInfo* ChannelWrapper::DocumentURLInfo() const {
572   if (mDocumentURLInfo.isNothing()) {
573     nsCOMPtr<nsIURI> uri = GetDocumentURI();
574     if (!uri) {
575       return nullptr;
576     }
577     mDocumentURLInfo.emplace(uri.get(), true);
578   }
579   return &mDocumentURLInfo.ref();
580 }
581 
Matches(const dom::MozRequestFilter & aFilter,const WebExtensionPolicy * aExtension,const dom::MozRequestMatchOptions & aOptions) const582 bool ChannelWrapper::Matches(
583     const dom::MozRequestFilter& aFilter, const WebExtensionPolicy* aExtension,
584     const dom::MozRequestMatchOptions& aOptions) const {
585   if (!HaveChannel()) {
586     return false;
587   }
588 
589   if (!aFilter.mTypes.IsNull() && !aFilter.mTypes.Value().Contains(Type())) {
590     return false;
591   }
592 
593   auto& urlInfo = FinalURLInfo();
594   if (aFilter.mUrls && !aFilter.mUrls->Matches(urlInfo)) {
595     return false;
596   }
597 
598   nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo();
599   bool isPrivate =
600       loadInfo && loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
601   if (!aFilter.mIncognito.IsNull() && aFilter.mIncognito.Value() != isPrivate) {
602     return false;
603   }
604 
605   if (aExtension) {
606     // Verify extension access to private requests
607     if (isPrivate && !aExtension->PrivateBrowsingAllowed()) {
608       return false;
609     }
610 
611     bool isProxy =
612         aOptions.mIsProxy && aExtension->HasPermission(nsGkAtoms::proxy);
613     // Proxies are allowed access to all urls, including restricted urls.
614     if (!aExtension->CanAccessURI(urlInfo, false, !isProxy, true)) {
615       return false;
616     }
617 
618     // If this isn't the proxy phase of the request, check that the extension
619     // has origin permissions for origin that originated the request.
620     if (!isProxy) {
621       if (IsSystemLoad()) {
622         return false;
623       }
624 
625       auto origin = DocumentURLInfo();
626       // Extensions with the file:-permission may observe requests from file:
627       // origins, because such documents can already be modified by content
628       // scripts anyway.
629       if (origin && !aExtension->CanAccessURI(*origin, false, true, true)) {
630         return false;
631       }
632     }
633   }
634 
635   return true;
636 }
637 
NormalizeFrameID(nsILoadInfo * aLoadInfo,uint64_t bcID)638 int64_t NormalizeFrameID(nsILoadInfo* aLoadInfo, uint64_t bcID) {
639   if (RefPtr<BrowsingContext> bc = aLoadInfo->GetBrowsingContext();
640       !bc || bcID == bc->Top()->Id()) {
641     return 0;
642   }
643   return bcID;
644 }
645 
BrowsingContextId(nsILoadInfo * aLoadInfo) const646 uint64_t ChannelWrapper::BrowsingContextId(nsILoadInfo* aLoadInfo) const {
647   auto frameID = aLoadInfo->GetFrameBrowsingContextID();
648   if (!frameID) {
649     frameID = aLoadInfo->GetBrowsingContextID();
650   }
651   return frameID;
652 }
653 
FrameId() const654 int64_t ChannelWrapper::FrameId() const {
655   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
656     return NormalizeFrameID(loadInfo, BrowsingContextId(loadInfo));
657   }
658   return 0;
659 }
660 
ParentFrameId() const661 int64_t ChannelWrapper::ParentFrameId() const {
662   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
663     if (RefPtr<BrowsingContext> bc = loadInfo->GetBrowsingContext()) {
664       if (BrowsingContextId(loadInfo) == bc->Top()->Id()) {
665         return -1;
666       }
667 
668       uint64_t parentID = -1;
669       if (loadInfo->GetFrameBrowsingContextID()) {
670         parentID = loadInfo->GetBrowsingContextID();
671       } else if (bc->GetParent()) {
672         parentID = bc->GetParent()->Id();
673       }
674       return NormalizeFrameID(loadInfo, parentID);
675     }
676   }
677   return -1;
678 }
679 
GetFrameAncestors(dom::Nullable<nsTArray<dom::MozFrameAncestorInfo>> & aFrameAncestors,ErrorResult & aRv) const680 void ChannelWrapper::GetFrameAncestors(
681     dom::Nullable<nsTArray<dom::MozFrameAncestorInfo>>& aFrameAncestors,
682     ErrorResult& aRv) const {
683   nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo();
684   if (!loadInfo || BrowsingContextId(loadInfo) == 0) {
685     aFrameAncestors.SetNull();
686     return;
687   }
688 
689   nsresult rv = GetFrameAncestors(loadInfo, aFrameAncestors.SetValue());
690   if (NS_FAILED(rv)) {
691     aRv.Throw(rv);
692   }
693 }
694 
GetFrameAncestors(nsILoadInfo * aLoadInfo,nsTArray<dom::MozFrameAncestorInfo> & aFrameAncestors) const695 nsresult ChannelWrapper::GetFrameAncestors(
696     nsILoadInfo* aLoadInfo,
697     nsTArray<dom::MozFrameAncestorInfo>& aFrameAncestors) const {
698   const nsTArray<nsCOMPtr<nsIPrincipal>>& ancestorPrincipals =
699       aLoadInfo->AncestorPrincipals();
700   const nsTArray<uint64_t>& ancestorBrowsingContextIDs =
701       aLoadInfo->AncestorBrowsingContextIDs();
702   uint32_t size = ancestorPrincipals.Length();
703   MOZ_DIAGNOSTIC_ASSERT(size == ancestorBrowsingContextIDs.Length());
704   if (size != ancestorBrowsingContextIDs.Length()) {
705     return NS_ERROR_UNEXPECTED;
706   }
707 
708   bool subFrame = aLoadInfo->GetExternalContentPolicyType() ==
709                   ExtContentPolicy::TYPE_SUBDOCUMENT;
710   if (!aFrameAncestors.SetCapacity(subFrame ? size : size + 1, fallible)) {
711     return NS_ERROR_OUT_OF_MEMORY;
712   }
713 
714   // The immediate parent is always the first element in the ancestor arrays,
715   // however SUBDOCUMENTs do not have their immediate parent included, so we
716   // inject it here. This will force wrapper.parentBrowsingContextId ==
717   // wrapper.frameAncestors[0].frameId to always be true.  All ather requests
718   // already match this way.
719   if (subFrame) {
720     auto ancestor = aFrameAncestors.AppendElement();
721     GetDocumentURL(ancestor->mUrl);
722     ancestor->mFrameId = ParentFrameId();
723   }
724 
725   for (uint32_t i = 0; i < size; ++i) {
726     auto ancestor = aFrameAncestors.AppendElement();
727     MOZ_TRY(ancestorPrincipals[i]->GetAsciiSpec(ancestor->mUrl));
728     ancestor->mFrameId =
729         NormalizeFrameID(aLoadInfo, ancestorBrowsingContextIDs[i]);
730   }
731   return NS_OK;
732 }
733 
734 /*****************************************************************************
735  * Response filtering
736  *****************************************************************************/
737 
RegisterTraceableChannel(const WebExtensionPolicy & aAddon,nsIRemoteTab * aBrowserParent)738 void ChannelWrapper::RegisterTraceableChannel(const WebExtensionPolicy& aAddon,
739                                               nsIRemoteTab* aBrowserParent) {
740   // We can't attach new listeners after the response has started, so don't
741   // bother registering anything.
742   if (mResponseStarted || !CanModify()) {
743     return;
744   }
745 
746   mAddonEntries.InsertOrUpdate(aAddon.Id(), aBrowserParent);
747   if (!mChannelEntry) {
748     mChannelEntry = WebRequestService::GetSingleton().RegisterChannel(this);
749     CheckEventListeners();
750   }
751 }
752 
GetTraceableChannel(nsAtom * aAddonId,dom::ContentParent * aContentParent) const753 already_AddRefed<nsITraceableChannel> ChannelWrapper::GetTraceableChannel(
754     nsAtom* aAddonId, dom::ContentParent* aContentParent) const {
755   nsCOMPtr<nsIRemoteTab> remoteTab;
756   if (mAddonEntries.Get(aAddonId, getter_AddRefs(remoteTab))) {
757     ContentParent* contentParent = nullptr;
758     if (remoteTab) {
759       contentParent =
760           BrowserHost::GetFrom(remoteTab.get())->GetActor()->Manager();
761     }
762 
763     if (contentParent == aContentParent) {
764       nsCOMPtr<nsITraceableChannel> chan = QueryChannel();
765       return chan.forget();
766     }
767   }
768   return nullptr;
769 }
770 
771 /*****************************************************************************
772  * ...
773  *****************************************************************************/
774 
GetContentPolicyType(ExtContentPolicyType aType)775 MozContentPolicyType GetContentPolicyType(ExtContentPolicyType aType) {
776   // Note: Please keep this function in sync with the external types in
777   // nsIContentPolicy.idl
778   switch (aType) {
779     case ExtContentPolicy::TYPE_DOCUMENT:
780       return MozContentPolicyType::Main_frame;
781     case ExtContentPolicy::TYPE_SUBDOCUMENT:
782       return MozContentPolicyType::Sub_frame;
783     case ExtContentPolicy::TYPE_STYLESHEET:
784       return MozContentPolicyType::Stylesheet;
785     case ExtContentPolicy::TYPE_SCRIPT:
786       return MozContentPolicyType::Script;
787     case ExtContentPolicy::TYPE_IMAGE:
788       return MozContentPolicyType::Image;
789     case ExtContentPolicy::TYPE_OBJECT:
790       return MozContentPolicyType::Object;
791     case ExtContentPolicy::TYPE_OBJECT_SUBREQUEST:
792       return MozContentPolicyType::Object_subrequest;
793     case ExtContentPolicy::TYPE_XMLHTTPREQUEST:
794       return MozContentPolicyType::Xmlhttprequest;
795     // TYPE_FETCH returns xmlhttprequest for cross-browser compatibility.
796     case ExtContentPolicy::TYPE_FETCH:
797       return MozContentPolicyType::Xmlhttprequest;
798     case ExtContentPolicy::TYPE_XSLT:
799       return MozContentPolicyType::Xslt;
800     case ExtContentPolicy::TYPE_PING:
801       return MozContentPolicyType::Ping;
802     case ExtContentPolicy::TYPE_BEACON:
803       return MozContentPolicyType::Beacon;
804     case ExtContentPolicy::TYPE_DTD:
805       return MozContentPolicyType::Xml_dtd;
806     case ExtContentPolicy::TYPE_FONT:
807     case ExtContentPolicy::TYPE_UA_FONT:
808       return MozContentPolicyType::Font;
809     case ExtContentPolicy::TYPE_MEDIA:
810       return MozContentPolicyType::Media;
811     case ExtContentPolicy::TYPE_WEBSOCKET:
812       return MozContentPolicyType::Websocket;
813     case ExtContentPolicy::TYPE_CSP_REPORT:
814       return MozContentPolicyType::Csp_report;
815     case ExtContentPolicy::TYPE_IMAGESET:
816       return MozContentPolicyType::Imageset;
817     case ExtContentPolicy::TYPE_WEB_MANIFEST:
818       return MozContentPolicyType::Web_manifest;
819     case ExtContentPolicy::TYPE_SPECULATIVE:
820       return MozContentPolicyType::Speculative;
821     case ExtContentPolicy::TYPE_INVALID:
822     case ExtContentPolicy::TYPE_OTHER:
823     case ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD:
824       break;
825       // Do not add default: so that compilers can catch the missing case.
826   }
827   return MozContentPolicyType::Other;
828 }
829 
Type() const830 MozContentPolicyType ChannelWrapper::Type() const {
831   if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) {
832     return GetContentPolicyType(loadInfo->GetExternalContentPolicyType());
833   }
834   return MozContentPolicyType::Other;
835 }
836 
GetMethod(nsCString & aMethod) const837 void ChannelWrapper::GetMethod(nsCString& aMethod) const {
838   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
839     Unused << chan->GetRequestMethod(aMethod);
840   }
841 }
842 
843 /*****************************************************************************
844  * ...
845  *****************************************************************************/
846 
StatusCode() const847 uint32_t ChannelWrapper::StatusCode() const {
848   uint32_t result = 0;
849   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
850     Unused << chan->GetResponseStatus(&result);
851   }
852   return result;
853 }
854 
GetStatusLine(nsCString & aRetVal) const855 void ChannelWrapper::GetStatusLine(nsCString& aRetVal) const {
856   nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel();
857   nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(chan);
858 
859   if (internal) {
860     nsAutoCString statusText;
861     uint32_t major, minor, status;
862     if (NS_FAILED(chan->GetResponseStatus(&status)) ||
863         NS_FAILED(chan->GetResponseStatusText(statusText)) ||
864         NS_FAILED(internal->GetResponseVersion(&major, &minor))) {
865       return;
866     }
867 
868     aRetVal = nsPrintfCString("HTTP/%u.%u %u %s", major, minor, status,
869                               statusText.get());
870   }
871 }
872 
ResponseSize() const873 uint64_t ChannelWrapper::ResponseSize() const {
874   uint64_t result = 0;
875   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
876     Unused << chan->GetTransferSize(&result);
877   }
878   return result;
879 }
880 
RequestSize() const881 uint64_t ChannelWrapper::RequestSize() const {
882   uint64_t result = 0;
883   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
884     Unused << chan->GetRequestSize(&result);
885   }
886   return result;
887 }
888 
889 /*****************************************************************************
890  * ...
891  *****************************************************************************/
892 
FinalURI() const893 already_AddRefed<nsIURI> ChannelWrapper::FinalURI() const {
894   nsCOMPtr<nsIURI> uri;
895   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
896     NS_GetFinalChannelURI(chan, getter_AddRefs(uri));
897   }
898   return uri.forget();
899 }
900 
GetFinalURL(nsString & aRetVal) const901 void ChannelWrapper::GetFinalURL(nsString& aRetVal) const {
902   if (HaveChannel()) {
903     aRetVal = FinalURLInfo().Spec();
904   }
905 }
906 
907 /*****************************************************************************
908  * ...
909  *****************************************************************************/
910 
FillProxyInfo(MozProxyInfo & aDict,nsIProxyInfo * aProxyInfo)911 nsresult FillProxyInfo(MozProxyInfo& aDict, nsIProxyInfo* aProxyInfo) {
912   MOZ_TRY(aProxyInfo->GetHost(aDict.mHost));
913   MOZ_TRY(aProxyInfo->GetPort(&aDict.mPort));
914   MOZ_TRY(aProxyInfo->GetType(aDict.mType));
915   MOZ_TRY(aProxyInfo->GetUsername(aDict.mUsername));
916   MOZ_TRY(
917       aProxyInfo->GetProxyAuthorizationHeader(aDict.mProxyAuthorizationHeader));
918   MOZ_TRY(aProxyInfo->GetConnectionIsolationKey(aDict.mConnectionIsolationKey));
919   MOZ_TRY(aProxyInfo->GetFailoverTimeout(&aDict.mFailoverTimeout.Construct()));
920 
921   uint32_t flags;
922   MOZ_TRY(aProxyInfo->GetFlags(&flags));
923   aDict.mProxyDNS = flags & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
924 
925   return NS_OK;
926 }
927 
GetProxyInfo(dom::Nullable<MozProxyInfo> & aRetVal,ErrorResult & aRv) const928 void ChannelWrapper::GetProxyInfo(dom::Nullable<MozProxyInfo>& aRetVal,
929                                   ErrorResult& aRv) const {
930   nsCOMPtr<nsIProxyInfo> proxyInfo;
931   if (nsCOMPtr<nsIProxiedChannel> proxied = QueryChannel()) {
932     Unused << proxied->GetProxyInfo(getter_AddRefs(proxyInfo));
933   }
934   if (proxyInfo) {
935     MozProxyInfo result;
936 
937     nsresult rv = FillProxyInfo(result, proxyInfo);
938     if (NS_FAILED(rv)) {
939       aRv.Throw(rv);
940     } else {
941       aRetVal.SetValue(std::move(result));
942     }
943   }
944 }
945 
GetRemoteAddress(nsCString & aRetVal) const946 void ChannelWrapper::GetRemoteAddress(nsCString& aRetVal) const {
947   aRetVal.SetIsVoid(true);
948   if (nsCOMPtr<nsIHttpChannelInternal> internal = QueryChannel()) {
949     Unused << internal->GetRemoteAddress(aRetVal);
950   }
951 }
952 
FillClassification(Sequence<mozilla::dom::MozUrlClassificationFlags> & classifications,uint32_t classificationFlags,ErrorResult & aRv)953 void FillClassification(
954     Sequence<mozilla::dom::MozUrlClassificationFlags>& classifications,
955     uint32_t classificationFlags, ErrorResult& aRv) {
956   if (classificationFlags == 0) {
957     return;
958   }
959   for (const auto& entry : classificationArray) {
960     if (classificationFlags & entry.mFlag) {
961       if (!classifications.AppendElement(entry.mValue, mozilla::fallible)) {
962         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
963         return;
964       }
965     }
966   }
967 }
968 
GetUrlClassification(dom::Nullable<dom::MozUrlClassification> & aRetVal,ErrorResult & aRv) const969 void ChannelWrapper::GetUrlClassification(
970     dom::Nullable<dom::MozUrlClassification>& aRetVal, ErrorResult& aRv) const {
971   MozUrlClassification classification;
972   if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) {
973     nsCOMPtr<nsIClassifiedChannel> classified = do_QueryInterface(chan);
974     MOZ_DIAGNOSTIC_ASSERT(
975         classified,
976         "Must be an object inheriting from both nsIHttpChannel and "
977         "nsIClassifiedChannel");
978     uint32_t classificationFlags;
979     classified->GetFirstPartyClassificationFlags(&classificationFlags);
980     FillClassification(classification.mFirstParty, classificationFlags, aRv);
981     if (aRv.Failed()) {
982       return;
983     }
984     classified->GetThirdPartyClassificationFlags(&classificationFlags);
985     FillClassification(classification.mThirdParty, classificationFlags, aRv);
986   }
987   aRetVal.SetValue(std::move(classification));
988 }
989 
ThirdParty() const990 bool ChannelWrapper::ThirdParty() const {
991   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
992       components::ThirdPartyUtil::Service();
993   if (NS_WARN_IF(!thirdPartyUtil)) {
994     return true;
995   }
996 
997   nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel();
998   if (!chan) {
999     return false;
1000   }
1001 
1002   bool thirdParty = false;
1003   nsresult rv = thirdPartyUtil->IsThirdPartyChannel(chan, nullptr, &thirdParty);
1004   if (NS_WARN_IF(NS_FAILED(rv))) {
1005     return true;
1006   }
1007 
1008   return thirdParty;
1009 }
1010 
1011 /*****************************************************************************
1012  * Error handling
1013  *****************************************************************************/
1014 
GetErrorString(nsString & aRetVal) const1015 void ChannelWrapper::GetErrorString(nsString& aRetVal) const {
1016   if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) {
1017     nsCOMPtr<nsISupports> securityInfo;
1018     Unused << chan->GetSecurityInfo(getter_AddRefs(securityInfo));
1019     if (nsCOMPtr<nsITransportSecurityInfo> tsi =
1020             do_QueryInterface(securityInfo)) {
1021       int32_t errorCode = 0;
1022       tsi->GetErrorCode(&errorCode);
1023       if (psm::IsNSSErrorCode(errorCode)) {
1024         nsCOMPtr<nsINSSErrorsService> nsserr =
1025             do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
1026 
1027         nsresult rv = psm::GetXPCOMFromNSSError(errorCode);
1028         if (nsserr && NS_SUCCEEDED(nsserr->GetErrorMessage(rv, aRetVal))) {
1029           return;
1030         }
1031       }
1032     }
1033 
1034     nsresult status;
1035     if (NS_SUCCEEDED(chan->GetStatus(&status)) && NS_FAILED(status)) {
1036       nsAutoCString name;
1037       GetErrorName(status, name);
1038       AppendUTF8toUTF16(name, aRetVal);
1039     } else {
1040       aRetVal.SetIsVoid(true);
1041     }
1042   } else {
1043     aRetVal.AssignLiteral("NS_ERROR_UNEXPECTED");
1044   }
1045 }
1046 
ErrorCheck()1047 void ChannelWrapper::ErrorCheck() {
1048   if (!mFiredErrorEvent) {
1049     nsAutoString error;
1050     GetErrorString(error);
1051     if (error.Length()) {
1052       mChannelEntry = nullptr;
1053       mFiredErrorEvent = true;
1054       ChannelWrapper_Binding::ClearCachedErrorStringValue(this);
1055       FireEvent(u"error"_ns);
1056     }
1057   }
1058 }
1059 
1060 /*****************************************************************************
1061  * nsIWebRequestListener
1062  *****************************************************************************/
1063 
NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener,nsIStreamListener,nsIMultiPartChannelListener,nsIRequestObserver,nsIThreadRetargetableStreamListener)1064 NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener, nsIStreamListener,
1065                   nsIMultiPartChannelListener, nsIRequestObserver,
1066                   nsIThreadRetargetableStreamListener)
1067 
1068 ChannelWrapper::RequestListener::~RequestListener() {
1069   NS_ReleaseOnMainThread("RequestListener::mChannelWrapper",
1070                          mChannelWrapper.forget());
1071 }
1072 
Init()1073 nsresult ChannelWrapper::RequestListener::Init() {
1074   if (nsCOMPtr<nsITraceableChannel> chan = mChannelWrapper->QueryChannel()) {
1075     return chan->SetNewListener(this, false,
1076                                 getter_AddRefs(mOrigStreamListener));
1077   }
1078   return NS_ERROR_UNEXPECTED;
1079 }
1080 
1081 NS_IMETHODIMP
OnStartRequest(nsIRequest * request)1082 ChannelWrapper::RequestListener::OnStartRequest(nsIRequest* request) {
1083   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1084 
1085   mChannelWrapper->mChannelEntry = nullptr;
1086   mChannelWrapper->mResponseStarted = true;
1087   mChannelWrapper->ErrorCheck();
1088   mChannelWrapper->FireEvent(u"start"_ns);
1089 
1090   return mOrigStreamListener->OnStartRequest(request);
1091 }
1092 
1093 NS_IMETHODIMP
OnStopRequest(nsIRequest * request,nsresult aStatus)1094 ChannelWrapper::RequestListener::OnStopRequest(nsIRequest* request,
1095                                                nsresult aStatus) {
1096   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1097 
1098   mChannelWrapper->mChannelEntry = nullptr;
1099   mChannelWrapper->ErrorCheck();
1100   mChannelWrapper->FireEvent(u"stop"_ns);
1101 
1102   return mOrigStreamListener->OnStopRequest(request, aStatus);
1103 }
1104 
1105 NS_IMETHODIMP
OnDataAvailable(nsIRequest * request,nsIInputStream * inStr,uint64_t sourceOffset,uint32_t count)1106 ChannelWrapper::RequestListener::OnDataAvailable(nsIRequest* request,
1107                                                  nsIInputStream* inStr,
1108                                                  uint64_t sourceOffset,
1109                                                  uint32_t count) {
1110   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1111   return mOrigStreamListener->OnDataAvailable(request, inStr, sourceOffset,
1112                                               count);
1113 }
1114 
1115 NS_IMETHODIMP
OnAfterLastPart(nsresult aStatus)1116 ChannelWrapper::RequestListener::OnAfterLastPart(nsresult aStatus) {
1117   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
1118   if (nsCOMPtr<nsIMultiPartChannelListener> listener =
1119           do_QueryInterface(mOrigStreamListener)) {
1120     return listener->OnAfterLastPart(aStatus);
1121   }
1122   return NS_OK;
1123 }
1124 
1125 NS_IMETHODIMP
CheckListenerChain()1126 ChannelWrapper::RequestListener::CheckListenerChain() {
1127   MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!");
1128   nsresult rv;
1129   nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
1130       do_QueryInterface(mOrigStreamListener, &rv);
1131   if (retargetableListener) {
1132     return retargetableListener->CheckListenerChain();
1133   }
1134   return rv;
1135 }
1136 
1137 /*****************************************************************************
1138  * Event dispatching
1139  *****************************************************************************/
1140 
FireEvent(const nsAString & aType)1141 void ChannelWrapper::FireEvent(const nsAString& aType) {
1142   EventInit init;
1143   init.mBubbles = false;
1144   init.mCancelable = false;
1145 
1146   RefPtr<Event> event = Event::Constructor(this, aType, init);
1147   event->SetTrusted(true);
1148 
1149   DispatchEvent(*event);
1150 }
1151 
CheckEventListeners()1152 void ChannelWrapper::CheckEventListeners() {
1153   if (!mAddedStreamListener &&
1154       (HasListenersFor(nsGkAtoms::onerror) ||
1155        HasListenersFor(nsGkAtoms::onstart) ||
1156        HasListenersFor(nsGkAtoms::onstop) || mChannelEntry)) {
1157     auto listener = MakeRefPtr<RequestListener>(this);
1158     if (!NS_WARN_IF(NS_FAILED(listener->Init()))) {
1159       mAddedStreamListener = true;
1160     }
1161   }
1162 }
1163 
EventListenerAdded(nsAtom * aType)1164 void ChannelWrapper::EventListenerAdded(nsAtom* aType) {
1165   CheckEventListeners();
1166 }
1167 
EventListenerRemoved(nsAtom * aType)1168 void ChannelWrapper::EventListenerRemoved(nsAtom* aType) {
1169   CheckEventListeners();
1170 }
1171 
1172 /*****************************************************************************
1173  * Glue
1174  *****************************************************************************/
1175 
WrapObject(JSContext * aCx,HandleObject aGivenProto)1176 JSObject* ChannelWrapper::WrapObject(JSContext* aCx, HandleObject aGivenProto) {
1177   return ChannelWrapper_Binding::Wrap(aCx, this, aGivenProto);
1178 }
1179 
1180 NS_IMPL_CYCLE_COLLECTION_CLASS(ChannelWrapper)
1181 
1182 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper)
1183   NS_INTERFACE_MAP_ENTRY(ChannelWrapper)
1184 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
1185 
1186 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ChannelWrapper,
1187                                                 DOMEventTargetHelper)
1188   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
1189   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStub)
1190   NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
1191 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1192 
1193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ChannelWrapper,
1194                                                   DOMEventTargetHelper)
1195   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
1196   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStub)
1197 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1198 
1199 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ChannelWrapper,
1200                                                DOMEventTargetHelper)
1201 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1202 
1203 NS_IMPL_ADDREF_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1204 NS_IMPL_RELEASE_INHERITED(ChannelWrapper, DOMEventTargetHelper)
1205 
1206 }  // namespace extensions
1207 }  // namespace mozilla
1208