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