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