/src/mozilla-central/toolkit/components/extensions/webrequest/ChannelWrapper.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
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/ErrorNames.h" |
20 | | #include "mozilla/ResultExtensions.h" |
21 | | #include "mozilla/Unused.h" |
22 | | #include "mozilla/dom/Element.h" |
23 | | #include "mozilla/dom/Event.h" |
24 | | #include "mozilla/dom/TabParent.h" |
25 | | #include "nsIContentPolicy.h" |
26 | | #include "nsIHttpChannelInternal.h" |
27 | | #include "nsIHttpHeaderVisitor.h" |
28 | | #include "nsIInterfaceRequestor.h" |
29 | | #include "nsIInterfaceRequestorUtils.h" |
30 | | #include "nsILoadContext.h" |
31 | | #include "nsILoadGroup.h" |
32 | | #include "nsIProxiedChannel.h" |
33 | | #include "nsIProxyInfo.h" |
34 | | #include "nsITraceableChannel.h" |
35 | | #include "nsIWritablePropertyBag2.h" |
36 | | #include "nsNetUtil.h" |
37 | | #include "nsProxyRelease.h" |
38 | | #include "nsPrintfCString.h" |
39 | | |
40 | | using namespace mozilla::dom; |
41 | | using namespace JS; |
42 | | |
43 | | namespace mozilla { |
44 | | namespace extensions { |
45 | | |
46 | 0 | #define CHANNELWRAPPER_PROP_KEY NS_LITERAL_STRING("ChannelWrapper::CachedInstance") |
47 | | |
48 | | /***************************************************************************** |
49 | | * Initialization |
50 | | *****************************************************************************/ |
51 | | |
52 | | /* static */ |
53 | | |
54 | | already_AddRefed<ChannelWrapper> |
55 | | ChannelWrapper::Get(const GlobalObject& global, nsIChannel* channel) |
56 | 0 | { |
57 | 0 | RefPtr<ChannelWrapper> wrapper; |
58 | 0 |
|
59 | 0 | nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel); |
60 | 0 | if (props) { |
61 | 0 | Unused << props->GetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY, |
62 | 0 | NS_GET_IID(ChannelWrapper), |
63 | 0 | getter_AddRefs(wrapper)); |
64 | 0 |
|
65 | 0 | if (wrapper) { |
66 | 0 | // Assume cached attributes may have changed at this point. |
67 | 0 | wrapper->ClearCachedAttributes(); |
68 | 0 | } |
69 | 0 | } |
70 | 0 |
|
71 | 0 | if (!wrapper) { |
72 | 0 | wrapper = new ChannelWrapper(global.GetAsSupports(), channel); |
73 | 0 | if (props) { |
74 | 0 | Unused << props->SetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY, |
75 | 0 | wrapper); |
76 | 0 | } |
77 | 0 | } |
78 | 0 |
|
79 | 0 | return wrapper.forget(); |
80 | 0 | } |
81 | | |
82 | | already_AddRefed<ChannelWrapper> |
83 | | ChannelWrapper::GetRegisteredChannel(const GlobalObject& global, uint64_t aChannelId, const WebExtensionPolicy& aAddon, nsITabParent* aTabParent) |
84 | 0 | { |
85 | 0 | nsIContentParent* contentParent = nullptr; |
86 | 0 | if (TabParent* parent = static_cast<TabParent*>(aTabParent)) { |
87 | 0 | contentParent = static_cast<nsIContentParent*>(parent->Manager()); |
88 | 0 | } |
89 | 0 |
|
90 | 0 | auto& webreq = WebRequestService::GetSingleton(); |
91 | 0 |
|
92 | 0 | nsCOMPtr<nsITraceableChannel> channel = webreq.GetTraceableChannel(aChannelId, aAddon.Id(), contentParent); |
93 | 0 | if (!channel) { |
94 | 0 | return nullptr; |
95 | 0 | } |
96 | 0 | nsCOMPtr<nsIChannel> chan(do_QueryInterface(channel)); |
97 | 0 | return ChannelWrapper::Get(global, chan); |
98 | 0 | } |
99 | | |
100 | | void |
101 | | ChannelWrapper::SetChannel(nsIChannel* aChannel) |
102 | 0 | { |
103 | 0 | detail::ChannelHolder::SetChannel(aChannel); |
104 | 0 | ClearCachedAttributes(); |
105 | 0 | ChannelWrapper_Binding::ClearCachedFinalURIValue(this); |
106 | 0 | ChannelWrapper_Binding::ClearCachedFinalURLValue(this); |
107 | 0 | mFinalURLInfo.reset(); |
108 | 0 | ChannelWrapper_Binding::ClearCachedProxyInfoValue(this); |
109 | 0 | } |
110 | | |
111 | | void |
112 | | ChannelWrapper::ClearCachedAttributes() |
113 | 0 | { |
114 | 0 | ChannelWrapper_Binding::ClearCachedRemoteAddressValue(this); |
115 | 0 | ChannelWrapper_Binding::ClearCachedStatusCodeValue(this); |
116 | 0 | ChannelWrapper_Binding::ClearCachedStatusLineValue(this); |
117 | 0 | if (!mFiredErrorEvent) { |
118 | 0 | ChannelWrapper_Binding::ClearCachedErrorStringValue(this); |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | /***************************************************************************** |
123 | | * ... |
124 | | *****************************************************************************/ |
125 | | |
126 | | void |
127 | | ChannelWrapper::Cancel(uint32_t aResult, ErrorResult& aRv) |
128 | 0 | { |
129 | 0 | nsresult rv = NS_ERROR_UNEXPECTED; |
130 | 0 | if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) { |
131 | 0 | rv = chan->Cancel(nsresult(aResult)); |
132 | 0 | ErrorCheck(); |
133 | 0 | } |
134 | 0 | if (NS_FAILED(rv)) { |
135 | 0 | aRv.Throw(rv); |
136 | 0 | } |
137 | 0 | } |
138 | | |
139 | | void |
140 | | ChannelWrapper::RedirectTo(nsIURI* aURI, ErrorResult& aRv) |
141 | 0 | { |
142 | 0 | nsresult rv = NS_ERROR_UNEXPECTED; |
143 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
144 | 0 | rv = chan->RedirectTo(aURI); |
145 | 0 | } |
146 | 0 | if (NS_FAILED(rv)) { |
147 | 0 | aRv.Throw(rv); |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | void |
152 | | ChannelWrapper::UpgradeToSecure(ErrorResult& aRv) |
153 | 0 | { |
154 | 0 | nsresult rv = NS_ERROR_UNEXPECTED; |
155 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
156 | 0 | rv = chan->UpgradeToSecure(); |
157 | 0 | } |
158 | 0 | if (NS_FAILED(rv)) { |
159 | 0 | aRv.Throw(rv); |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | void |
164 | | ChannelWrapper::SetSuspended(bool aSuspended, ErrorResult& aRv) |
165 | 0 | { |
166 | 0 | if (aSuspended != mSuspended) { |
167 | 0 | nsresult rv = NS_ERROR_UNEXPECTED; |
168 | 0 | if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) { |
169 | 0 | if (aSuspended) { |
170 | 0 | rv = chan->Suspend(); |
171 | 0 | } else { |
172 | 0 | rv = chan->Resume(); |
173 | 0 | } |
174 | 0 | } |
175 | 0 | if (NS_FAILED(rv)) { |
176 | 0 | aRv.Throw(rv); |
177 | 0 | } else { |
178 | 0 | mSuspended = aSuspended; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | } |
182 | | |
183 | | void |
184 | | ChannelWrapper::GetContentType(nsCString& aContentType) const |
185 | 0 | { |
186 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
187 | 0 | Unused << chan->GetContentType(aContentType); |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | void |
192 | | ChannelWrapper::SetContentType(const nsACString& aContentType) |
193 | 0 | { |
194 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
195 | 0 | Unused << chan->SetContentType(aContentType); |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | | |
200 | | /***************************************************************************** |
201 | | * Headers |
202 | | *****************************************************************************/ |
203 | | |
204 | | namespace { |
205 | | |
206 | | class MOZ_STACK_CLASS HeaderVisitor final : public nsIHttpHeaderVisitor |
207 | | { |
208 | | public: |
209 | | NS_DECL_NSIHTTPHEADERVISITOR |
210 | | |
211 | | explicit HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders) |
212 | | : mHeaders(aHeaders) |
213 | 0 | {} |
214 | | |
215 | | HeaderVisitor(nsTArray<dom::MozHTTPHeader>& aHeaders, |
216 | | const nsCString& aContentTypeHdr) |
217 | | : mHeaders(aHeaders) |
218 | | , mContentTypeHdr(aContentTypeHdr) |
219 | 0 | {} |
220 | | |
221 | | void VisitRequestHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv) |
222 | 0 | { |
223 | 0 | CheckResult(aChannel->VisitRequestHeaders(this), aRv); |
224 | 0 | } |
225 | | |
226 | | void VisitResponseHeaders(nsIHttpChannel* aChannel, ErrorResult& aRv) |
227 | 0 | { |
228 | 0 | CheckResult(aChannel->VisitResponseHeaders(this), aRv); |
229 | 0 | } |
230 | | |
231 | | NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; |
232 | | |
233 | | // Stub AddRef/Release since this is a stack class. |
234 | | NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override |
235 | 0 | { |
236 | 0 | return ++mRefCnt; |
237 | 0 | } |
238 | | |
239 | | NS_IMETHOD_(MozExternalRefCountType) Release(void) override |
240 | 0 | { |
241 | 0 | return --mRefCnt; |
242 | 0 | } |
243 | | |
244 | | virtual ~HeaderVisitor() |
245 | 0 | { |
246 | 0 | MOZ_DIAGNOSTIC_ASSERT(mRefCnt == 0); |
247 | 0 | } |
248 | | |
249 | | private: |
250 | | bool CheckResult(nsresult aNSRv, ErrorResult& aRv) |
251 | 0 | { |
252 | 0 | if (NS_FAILED(aNSRv)) { |
253 | 0 | aRv.Throw(aNSRv); |
254 | 0 | return false; |
255 | 0 | } |
256 | 0 | return true; |
257 | 0 | } |
258 | | |
259 | | nsTArray<dom::MozHTTPHeader>& mHeaders; |
260 | | nsCString mContentTypeHdr = VoidCString(); |
261 | | |
262 | | nsrefcnt mRefCnt = 0; |
263 | | }; |
264 | | |
265 | | NS_IMETHODIMP |
266 | | HeaderVisitor::VisitHeader(const nsACString& aHeader, const nsACString& aValue) |
267 | 0 | { |
268 | 0 | auto dict = mHeaders.AppendElement(fallible); |
269 | 0 | if (!dict) { |
270 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
271 | 0 | } |
272 | 0 | dict->mName = aHeader; |
273 | 0 |
|
274 | 0 | if (!mContentTypeHdr.IsVoid() && aHeader.LowerCaseEqualsLiteral("content-type")) { |
275 | 0 | dict->mValue = mContentTypeHdr; |
276 | 0 | } else { |
277 | 0 | dict->mValue = aValue; |
278 | 0 | } |
279 | 0 |
|
280 | 0 | return NS_OK; |
281 | 0 | } |
282 | | |
283 | | NS_IMPL_QUERY_INTERFACE(HeaderVisitor, nsIHttpHeaderVisitor) |
284 | | |
285 | | } // anonymous namespace |
286 | | |
287 | | |
288 | | void |
289 | | ChannelWrapper::GetRequestHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal, ErrorResult& aRv) const |
290 | 0 | { |
291 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
292 | 0 | HeaderVisitor visitor(aRetVal); |
293 | 0 | visitor.VisitRequestHeaders(chan, aRv); |
294 | 0 | } else { |
295 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
296 | 0 | } |
297 | 0 | } |
298 | | |
299 | | void |
300 | | ChannelWrapper::GetResponseHeaders(nsTArray<dom::MozHTTPHeader>& aRetVal, ErrorResult& aRv) const |
301 | 0 | { |
302 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
303 | 0 | HeaderVisitor visitor(aRetVal, mContentTypeHdr); |
304 | 0 | visitor.VisitResponseHeaders(chan, aRv); |
305 | 0 | } else { |
306 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | void |
311 | | ChannelWrapper::SetRequestHeader(const nsCString& aHeader, const nsCString& aValue, bool aMerge, ErrorResult& aRv) |
312 | 0 | { |
313 | 0 | nsresult rv = NS_ERROR_UNEXPECTED; |
314 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
315 | 0 | rv = chan->SetRequestHeader(aHeader, aValue, aMerge); |
316 | 0 | } |
317 | 0 | if (NS_FAILED(rv)) { |
318 | 0 | aRv.Throw(rv); |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | void |
323 | | ChannelWrapper::SetResponseHeader(const nsCString& aHeader, const nsCString& aValue, bool aMerge, ErrorResult& aRv) |
324 | 0 | { |
325 | 0 | nsresult rv = NS_ERROR_UNEXPECTED; |
326 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
327 | 0 | if (aHeader.LowerCaseEqualsLiteral("content-type")) { |
328 | 0 | rv = chan->SetContentType(aValue); |
329 | 0 | if (NS_SUCCEEDED(rv)) { |
330 | 0 | mContentTypeHdr = aValue; |
331 | 0 | } |
332 | 0 | } else { |
333 | 0 | rv = chan->SetResponseHeader(aHeader, aValue, aMerge); |
334 | 0 | } |
335 | 0 | } |
336 | 0 | if (NS_FAILED(rv)) { |
337 | 0 | aRv.Throw(rv); |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | | /***************************************************************************** |
342 | | * LoadInfo |
343 | | *****************************************************************************/ |
344 | | |
345 | | already_AddRefed<nsILoadContext> |
346 | | ChannelWrapper::GetLoadContext() const |
347 | 0 | { |
348 | 0 | if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) { |
349 | 0 | nsCOMPtr<nsILoadContext> ctxt; |
350 | 0 | NS_QueryNotificationCallbacks(chan, ctxt); |
351 | 0 | return ctxt.forget(); |
352 | 0 | } |
353 | 0 | return nullptr; |
354 | 0 | } |
355 | | |
356 | | already_AddRefed<Element> |
357 | | ChannelWrapper::GetBrowserElement() const |
358 | 0 | { |
359 | 0 | if (nsCOMPtr<nsILoadContext> ctxt = GetLoadContext()) { |
360 | 0 | RefPtr<Element> elem; |
361 | 0 | if (NS_SUCCEEDED(ctxt->GetTopFrameElement(getter_AddRefs(elem)))) { |
362 | 0 | return elem.forget(); |
363 | 0 | } |
364 | 0 | } |
365 | 0 | return nullptr; |
366 | 0 | } |
367 | | |
368 | | static inline bool |
369 | | IsSystemPrincipal(nsIPrincipal* aPrincipal) |
370 | 0 | { |
371 | 0 | return BasePrincipal::Cast(aPrincipal)->Is<SystemPrincipal>(); |
372 | 0 | } |
373 | | |
374 | | bool |
375 | | ChannelWrapper::IsSystemLoad() const |
376 | 0 | { |
377 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
378 | 0 | if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) { |
379 | 0 | return IsSystemPrincipal(prin); |
380 | 0 | } |
381 | 0 | |
382 | 0 | if (loadInfo->GetOuterWindowID() == loadInfo->GetTopOuterWindowID()) { |
383 | 0 | return false; |
384 | 0 | } |
385 | 0 | |
386 | 0 | if (nsIPrincipal* prin = loadInfo->PrincipalToInherit()) { |
387 | 0 | return IsSystemPrincipal(prin); |
388 | 0 | } |
389 | 0 | if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) { |
390 | 0 | return IsSystemPrincipal(prin); |
391 | 0 | } |
392 | 0 | } |
393 | 0 | return false; |
394 | 0 | } |
395 | | |
396 | | bool |
397 | | ChannelWrapper::CanModify() const |
398 | 0 | { |
399 | 0 | if (WebExtensionPolicy::IsRestrictedURI(FinalURLInfo())) { |
400 | 0 | return false; |
401 | 0 | } |
402 | 0 | |
403 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
404 | 0 | if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) { |
405 | 0 | if (IsSystemPrincipal(prin)) { |
406 | 0 | return false; |
407 | 0 | } |
408 | 0 | |
409 | 0 | auto* docURI = DocumentURLInfo(); |
410 | 0 | if (docURI && WebExtensionPolicy::IsRestrictedURI(*docURI)) { |
411 | 0 | return false; |
412 | 0 | } |
413 | 0 | } |
414 | 0 | } |
415 | 0 | return true; |
416 | 0 | } |
417 | | |
418 | | already_AddRefed<nsIURI> |
419 | | ChannelWrapper::GetOriginURI() const |
420 | 0 | { |
421 | 0 | nsCOMPtr<nsIURI> uri; |
422 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
423 | 0 | if (nsIPrincipal* prin = loadInfo->TriggeringPrincipal()) { |
424 | 0 | if (prin->GetIsCodebasePrincipal()) { |
425 | 0 | Unused << prin->GetURI(getter_AddRefs(uri)); |
426 | 0 | } |
427 | 0 | } |
428 | 0 | } |
429 | 0 | return uri.forget(); |
430 | 0 | } |
431 | | |
432 | | already_AddRefed<nsIURI> |
433 | | ChannelWrapper::GetDocumentURI() const |
434 | 0 | { |
435 | 0 | nsCOMPtr<nsIURI> uri; |
436 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
437 | 0 | if (nsIPrincipal* prin = loadInfo->LoadingPrincipal()) { |
438 | 0 | if (prin->GetIsCodebasePrincipal()) { |
439 | 0 | Unused << prin->GetURI(getter_AddRefs(uri)); |
440 | 0 | } |
441 | 0 | } |
442 | 0 | } |
443 | 0 | return uri.forget(); |
444 | 0 | } |
445 | | |
446 | | |
447 | | void |
448 | | ChannelWrapper::GetOriginURL(nsCString& aRetVal) const |
449 | 0 | { |
450 | 0 | if (nsCOMPtr<nsIURI> uri = GetOriginURI()) { |
451 | 0 | Unused << uri->GetSpec(aRetVal); |
452 | 0 | } |
453 | 0 | } |
454 | | |
455 | | void |
456 | | ChannelWrapper::GetDocumentURL(nsCString& aRetVal) const |
457 | 0 | { |
458 | 0 | if (nsCOMPtr<nsIURI> uri = GetDocumentURI()) { |
459 | 0 | Unused << uri->GetSpec(aRetVal); |
460 | 0 | } |
461 | 0 | } |
462 | | |
463 | | |
464 | | const URLInfo& |
465 | | ChannelWrapper::FinalURLInfo() const |
466 | 0 | { |
467 | 0 | if (mFinalURLInfo.isNothing()) { |
468 | 0 | ErrorResult rv; |
469 | 0 | nsCOMPtr<nsIURI> uri = FinalURI(); |
470 | 0 | MOZ_ASSERT(uri); |
471 | 0 | mFinalURLInfo.emplace(uri.get(), true); |
472 | 0 |
|
473 | 0 | // If this is a WebSocket request, mangle the URL so that the scheme is |
474 | 0 | // ws: or wss:, as appropriate. |
475 | 0 | auto& url = mFinalURLInfo.ref(); |
476 | 0 | if (Type() == MozContentPolicyType::Websocket && |
477 | 0 | (url.Scheme() == nsGkAtoms::http || |
478 | 0 | url.Scheme() == nsGkAtoms::https)) { |
479 | 0 | nsAutoCString spec(url.CSpec()); |
480 | 0 | spec.Replace(0, 4, NS_LITERAL_CSTRING("ws")); |
481 | 0 |
|
482 | 0 | Unused << NS_NewURI(getter_AddRefs(uri), spec); |
483 | 0 | MOZ_RELEASE_ASSERT(uri); |
484 | 0 | mFinalURLInfo.reset(); |
485 | 0 | mFinalURLInfo.emplace(uri.get(), true); |
486 | 0 | } |
487 | 0 | } |
488 | 0 | return mFinalURLInfo.ref(); |
489 | 0 | } |
490 | | |
491 | | const URLInfo* |
492 | | ChannelWrapper::DocumentURLInfo() const |
493 | 0 | { |
494 | 0 | if (mDocumentURLInfo.isNothing()) { |
495 | 0 | nsCOMPtr<nsIURI> uri = GetDocumentURI(); |
496 | 0 | if (!uri) { |
497 | 0 | return nullptr; |
498 | 0 | } |
499 | 0 | mDocumentURLInfo.emplace(uri.get(), true); |
500 | 0 | } |
501 | 0 | return &mDocumentURLInfo.ref(); |
502 | 0 | } |
503 | | |
504 | | |
505 | | bool |
506 | | ChannelWrapper::Matches(const dom::MozRequestFilter& aFilter, |
507 | | const WebExtensionPolicy* aExtension, |
508 | | const dom::MozRequestMatchOptions& aOptions) const |
509 | 0 | { |
510 | 0 | if (!HaveChannel()) { |
511 | 0 | return false; |
512 | 0 | } |
513 | 0 | |
514 | 0 | if (!aFilter.mTypes.IsNull() && !aFilter.mTypes.Value().Contains(Type())) { |
515 | 0 | return false; |
516 | 0 | } |
517 | 0 | |
518 | 0 | auto& urlInfo = FinalURLInfo(); |
519 | 0 | if (aFilter.mUrls && !aFilter.mUrls->Matches(urlInfo)) { |
520 | 0 | return false; |
521 | 0 | } |
522 | 0 | |
523 | 0 | if (aExtension) { |
524 | 0 | bool isProxy = aOptions.mIsProxy && aExtension->HasPermission(nsGkAtoms::proxy); |
525 | 0 | // Proxies are allowed access to all urls, including restricted urls. |
526 | 0 | if (!aExtension->CanAccessURI(urlInfo, false, !isProxy)) { |
527 | 0 | return false; |
528 | 0 | } |
529 | 0 | |
530 | 0 | // If this isn't the proxy phase of the request, check that the extension |
531 | 0 | // has origin permissions for origin that originated the request. |
532 | 0 | if (!isProxy) { |
533 | 0 | if (IsSystemLoad()) { |
534 | 0 | return false; |
535 | 0 | } |
536 | 0 | |
537 | 0 | if (auto origin = DocumentURLInfo()) { |
538 | 0 | nsAutoCString baseURL; |
539 | 0 | aExtension->GetBaseURL(baseURL); |
540 | 0 |
|
541 | 0 | if (!StringBeginsWith(origin->CSpec(), baseURL) && |
542 | 0 | !aExtension->CanAccessURI(*origin)) { |
543 | 0 | return false; |
544 | 0 | } |
545 | 0 | } |
546 | 0 | } |
547 | 0 | } |
548 | 0 | |
549 | 0 | return true; |
550 | 0 | } |
551 | | |
552 | | |
553 | | |
554 | | int64_t |
555 | | NormalizeWindowID(nsILoadInfo* aLoadInfo, uint64_t windowID) |
556 | 0 | { |
557 | 0 | if (windowID == aLoadInfo->GetTopOuterWindowID()) { |
558 | 0 | return 0; |
559 | 0 | } |
560 | 0 | return windowID; |
561 | 0 | } |
562 | | |
563 | | uint64_t |
564 | | ChannelWrapper::WindowId(nsILoadInfo* aLoadInfo) const |
565 | 0 | { |
566 | 0 | auto frameID = aLoadInfo->GetFrameOuterWindowID(); |
567 | 0 | if (!frameID) { |
568 | 0 | frameID = aLoadInfo->GetOuterWindowID(); |
569 | 0 | } |
570 | 0 | return frameID; |
571 | 0 | } |
572 | | |
573 | | int64_t |
574 | | ChannelWrapper::WindowId() const |
575 | 0 | { |
576 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
577 | 0 | return NormalizeWindowID(loadInfo, WindowId(loadInfo)); |
578 | 0 | } |
579 | 0 | return 0; |
580 | 0 | } |
581 | | |
582 | | int64_t |
583 | | ChannelWrapper::ParentWindowId() const |
584 | 0 | { |
585 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
586 | 0 | if (WindowId(loadInfo) == loadInfo->GetTopOuterWindowID()) { |
587 | 0 | return -1; |
588 | 0 | } |
589 | 0 | |
590 | 0 | uint64_t parentID; |
591 | 0 | if (loadInfo->GetFrameOuterWindowID()) { |
592 | 0 | parentID = loadInfo->GetOuterWindowID(); |
593 | 0 | } else { |
594 | 0 | parentID = loadInfo->GetParentOuterWindowID(); |
595 | 0 | } |
596 | 0 | return NormalizeWindowID(loadInfo, parentID); |
597 | 0 | } |
598 | 0 | return -1; |
599 | 0 | } |
600 | | |
601 | | void |
602 | | ChannelWrapper::GetFrameAncestors(dom::Nullable<nsTArray<dom::MozFrameAncestorInfo>>& aFrameAncestors, ErrorResult& aRv) const |
603 | 0 | { |
604 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo(); |
605 | 0 | if (!loadInfo || WindowId(loadInfo) == 0) { |
606 | 0 | aFrameAncestors.SetNull(); |
607 | 0 | return; |
608 | 0 | } |
609 | 0 | |
610 | 0 | nsresult rv = GetFrameAncestors(loadInfo, aFrameAncestors.SetValue()); |
611 | 0 | if (NS_FAILED(rv)) { |
612 | 0 | aRv.Throw(rv); |
613 | 0 | } |
614 | 0 | } |
615 | | |
616 | | nsresult |
617 | | ChannelWrapper::GetFrameAncestors(nsILoadInfo* aLoadInfo, nsTArray<dom::MozFrameAncestorInfo>& aFrameAncestors) const |
618 | 0 | { |
619 | 0 | const nsTArray<nsCOMPtr<nsIPrincipal>>& ancestorPrincipals = aLoadInfo->AncestorPrincipals(); |
620 | 0 | const nsTArray<uint64_t>& ancestorOuterWindowIDs = aLoadInfo->AncestorOuterWindowIDs(); |
621 | 0 | uint32_t size = ancestorPrincipals.Length(); |
622 | 0 | MOZ_DIAGNOSTIC_ASSERT(size == ancestorOuterWindowIDs.Length()); |
623 | 0 | if (size != ancestorOuterWindowIDs.Length()) { |
624 | 0 | return NS_ERROR_UNEXPECTED; |
625 | 0 | } |
626 | 0 | |
627 | 0 | bool subFrame = aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT; |
628 | 0 | if (!aFrameAncestors.SetCapacity(subFrame ? size : size + 1, fallible)) { |
629 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
630 | 0 | } |
631 | 0 | |
632 | 0 | // The immediate parent is always the first element in the ancestor arrays, however |
633 | 0 | // SUBDOCUMENTs do not have their immediate parent included, so we inject it here. |
634 | 0 | // This will force wrapper.parentWindowId == wrapper.frameAncestors[0].frameId to |
635 | 0 | // always be true. All ather requests already match this way. |
636 | 0 | if (subFrame) { |
637 | 0 | auto ancestor = aFrameAncestors.AppendElement(); |
638 | 0 | GetDocumentURL(ancestor->mUrl); |
639 | 0 | ancestor->mFrameId = ParentWindowId(); |
640 | 0 | } |
641 | 0 |
|
642 | 0 | for (uint32_t i = 0; i < size; ++i) { |
643 | 0 | auto ancestor = aFrameAncestors.AppendElement(); |
644 | 0 | nsCOMPtr<nsIURI> uri; |
645 | 0 | MOZ_TRY(ancestorPrincipals[i]->GetURI(getter_AddRefs(uri))); |
646 | 0 | if (!uri) { |
647 | 0 | return NS_ERROR_UNEXPECTED; |
648 | 0 | } |
649 | 0 | MOZ_TRY(uri->GetSpec(ancestor->mUrl)); |
650 | 0 | ancestor->mFrameId = NormalizeWindowID(aLoadInfo, ancestorOuterWindowIDs[i]); |
651 | 0 | } |
652 | 0 | return NS_OK; |
653 | 0 | } |
654 | | |
655 | | /***************************************************************************** |
656 | | * Response filtering |
657 | | *****************************************************************************/ |
658 | | |
659 | | void |
660 | | ChannelWrapper::RegisterTraceableChannel(const WebExtensionPolicy& aAddon, nsITabParent* aTabParent) |
661 | 0 | { |
662 | 0 | // We can't attach new listeners after the response has started, so don't |
663 | 0 | // bother registering anything. |
664 | 0 | if (mResponseStarted || !CanModify()) { |
665 | 0 | return; |
666 | 0 | } |
667 | 0 | |
668 | 0 | mAddonEntries.Put(aAddon.Id(), aTabParent); |
669 | 0 | if (!mChannelEntry) { |
670 | 0 | mChannelEntry = WebRequestService::GetSingleton().RegisterChannel(this); |
671 | 0 | CheckEventListeners(); |
672 | 0 | } |
673 | 0 | } |
674 | | |
675 | | already_AddRefed<nsITraceableChannel> |
676 | | ChannelWrapper::GetTraceableChannel(nsAtom* aAddonId, dom::nsIContentParent* aContentParent) const |
677 | 0 | { |
678 | 0 | nsCOMPtr<nsITabParent> tabParent; |
679 | 0 | if (mAddonEntries.Get(aAddonId, getter_AddRefs(tabParent))) { |
680 | 0 | nsIContentParent* contentParent = nullptr; |
681 | 0 | if (tabParent) { |
682 | 0 | contentParent = static_cast<nsIContentParent*>( |
683 | 0 | static_cast<TabParent*>(tabParent.get())->Manager()); |
684 | 0 | } |
685 | 0 |
|
686 | 0 | if (contentParent == aContentParent) { |
687 | 0 | nsCOMPtr<nsITraceableChannel> chan = QueryChannel(); |
688 | 0 | return chan.forget(); |
689 | 0 | } |
690 | 0 | } |
691 | 0 | return nullptr; |
692 | 0 | } |
693 | | |
694 | | /***************************************************************************** |
695 | | * ... |
696 | | *****************************************************************************/ |
697 | | |
698 | | MozContentPolicyType |
699 | | GetContentPolicyType(uint32_t aType) |
700 | | { |
701 | | // Note: Please keep this function in sync with the external types in |
702 | | // nsIContentPolicy.idl |
703 | | switch (aType) { |
704 | | case nsIContentPolicy::TYPE_DOCUMENT: |
705 | | return MozContentPolicyType::Main_frame; |
706 | | case nsIContentPolicy::TYPE_SUBDOCUMENT: |
707 | | return MozContentPolicyType::Sub_frame; |
708 | | case nsIContentPolicy::TYPE_STYLESHEET: |
709 | | return MozContentPolicyType::Stylesheet; |
710 | | case nsIContentPolicy::TYPE_SCRIPT: |
711 | | return MozContentPolicyType::Script; |
712 | | case nsIContentPolicy::TYPE_IMAGE: |
713 | | return MozContentPolicyType::Image; |
714 | | case nsIContentPolicy::TYPE_OBJECT: |
715 | | return MozContentPolicyType::Object; |
716 | | case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: |
717 | | return MozContentPolicyType::Object_subrequest; |
718 | | case nsIContentPolicy::TYPE_XMLHTTPREQUEST: |
719 | | return MozContentPolicyType::Xmlhttprequest; |
720 | | // TYPE_FETCH returns xmlhttprequest for cross-browser compatibility. |
721 | | case nsIContentPolicy::TYPE_FETCH: |
722 | | return MozContentPolicyType::Xmlhttprequest; |
723 | | case nsIContentPolicy::TYPE_XBL: |
724 | | return MozContentPolicyType::Xbl; |
725 | | case nsIContentPolicy::TYPE_XSLT: |
726 | | return MozContentPolicyType::Xslt; |
727 | | case nsIContentPolicy::TYPE_PING: |
728 | | return MozContentPolicyType::Ping; |
729 | | case nsIContentPolicy::TYPE_BEACON: |
730 | | return MozContentPolicyType::Beacon; |
731 | | case nsIContentPolicy::TYPE_DTD: |
732 | | return MozContentPolicyType::Xml_dtd; |
733 | | case nsIContentPolicy::TYPE_FONT: |
734 | | return MozContentPolicyType::Font; |
735 | | case nsIContentPolicy::TYPE_MEDIA: |
736 | | return MozContentPolicyType::Media; |
737 | | case nsIContentPolicy::TYPE_WEBSOCKET: |
738 | | return MozContentPolicyType::Websocket; |
739 | | case nsIContentPolicy::TYPE_CSP_REPORT: |
740 | | return MozContentPolicyType::Csp_report; |
741 | | case nsIContentPolicy::TYPE_IMAGESET: |
742 | | return MozContentPolicyType::Imageset; |
743 | | case nsIContentPolicy::TYPE_WEB_MANIFEST: |
744 | | return MozContentPolicyType::Web_manifest; |
745 | | case nsIContentPolicy::TYPE_SPECULATIVE: |
746 | | return MozContentPolicyType::Speculative; |
747 | | default: |
748 | | return MozContentPolicyType::Other; |
749 | | } |
750 | | } |
751 | | |
752 | | MozContentPolicyType |
753 | | ChannelWrapper::Type() const |
754 | 0 | { |
755 | 0 | if (nsCOMPtr<nsILoadInfo> loadInfo = GetLoadInfo()) { |
756 | 0 | return GetContentPolicyType(loadInfo->GetExternalContentPolicyType()); |
757 | 0 | } |
758 | 0 | return MozContentPolicyType::Other; |
759 | 0 | } |
760 | | |
761 | | void |
762 | | ChannelWrapper::GetMethod(nsCString& aMethod) const |
763 | 0 | { |
764 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
765 | 0 | Unused << chan->GetRequestMethod(aMethod); |
766 | 0 | } |
767 | 0 | } |
768 | | |
769 | | |
770 | | /***************************************************************************** |
771 | | * ... |
772 | | *****************************************************************************/ |
773 | | |
774 | | uint32_t |
775 | | ChannelWrapper::StatusCode() const |
776 | 0 | { |
777 | 0 | uint32_t result = 0; |
778 | 0 | if (nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel()) { |
779 | 0 | Unused << chan->GetResponseStatus(&result); |
780 | 0 | } |
781 | 0 | return result; |
782 | 0 | } |
783 | | |
784 | | void |
785 | | ChannelWrapper::GetStatusLine(nsCString& aRetVal) const |
786 | 0 | { |
787 | 0 | nsCOMPtr<nsIHttpChannel> chan = MaybeHttpChannel(); |
788 | 0 | nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(chan); |
789 | 0 |
|
790 | 0 | if (internal) { |
791 | 0 | nsAutoCString statusText; |
792 | 0 | uint32_t major, minor, status; |
793 | 0 | if (NS_FAILED(chan->GetResponseStatus(&status)) || |
794 | 0 | NS_FAILED(chan->GetResponseStatusText(statusText)) || |
795 | 0 | NS_FAILED(internal->GetResponseVersion(&major, &minor))) { |
796 | 0 | return; |
797 | 0 | } |
798 | 0 | |
799 | 0 | aRetVal = nsPrintfCString("HTTP/%u.%u %u %s", |
800 | 0 | major, minor, status, statusText.get()); |
801 | 0 | } |
802 | 0 | } |
803 | | |
804 | | /***************************************************************************** |
805 | | * ... |
806 | | *****************************************************************************/ |
807 | | |
808 | | already_AddRefed<nsIURI> |
809 | | ChannelWrapper::FinalURI() const |
810 | 0 | { |
811 | 0 | nsCOMPtr<nsIURI> uri; |
812 | 0 | if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) { |
813 | 0 | NS_GetFinalChannelURI(chan, getter_AddRefs(uri)); |
814 | 0 | } |
815 | 0 | return uri.forget(); |
816 | 0 | } |
817 | | |
818 | | void |
819 | | ChannelWrapper::GetFinalURL(nsString& aRetVal) const |
820 | 0 | { |
821 | 0 | if (HaveChannel()) { |
822 | 0 | aRetVal = FinalURLInfo().Spec(); |
823 | 0 | } |
824 | 0 | } |
825 | | |
826 | | /***************************************************************************** |
827 | | * ... |
828 | | *****************************************************************************/ |
829 | | |
830 | | nsresult |
831 | | FillProxyInfo(MozProxyInfo &aDict, nsIProxyInfo* aProxyInfo) |
832 | 0 | { |
833 | 0 | MOZ_TRY(aProxyInfo->GetHost(aDict.mHost)); |
834 | 0 | MOZ_TRY(aProxyInfo->GetPort(&aDict.mPort)); |
835 | 0 | MOZ_TRY(aProxyInfo->GetType(aDict.mType)); |
836 | 0 | MOZ_TRY(aProxyInfo->GetUsername(aDict.mUsername)); |
837 | 0 | MOZ_TRY(aProxyInfo->GetFailoverTimeout(&aDict.mFailoverTimeout.Construct())); |
838 | 0 |
|
839 | 0 | uint32_t flags; |
840 | 0 | MOZ_TRY(aProxyInfo->GetFlags(&flags)); |
841 | 0 | aDict.mProxyDNS = flags & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; |
842 | 0 |
|
843 | 0 | return NS_OK; |
844 | 0 | } |
845 | | |
846 | | void |
847 | | ChannelWrapper::GetProxyInfo(dom::Nullable<MozProxyInfo>& aRetVal, ErrorResult& aRv) const |
848 | 0 | { |
849 | 0 | nsCOMPtr<nsIProxyInfo> proxyInfo; |
850 | 0 | if (nsCOMPtr<nsIProxiedChannel> proxied = QueryChannel()) { |
851 | 0 | Unused << proxied->GetProxyInfo(getter_AddRefs(proxyInfo)); |
852 | 0 | } |
853 | 0 | if (proxyInfo) { |
854 | 0 | MozProxyInfo result; |
855 | 0 |
|
856 | 0 | nsresult rv = FillProxyInfo(result, proxyInfo); |
857 | 0 | if (NS_FAILED(rv)) { |
858 | 0 | aRv.Throw(rv); |
859 | 0 | } else { |
860 | 0 | aRetVal.SetValue(std::move(result)); |
861 | 0 | } |
862 | 0 | } |
863 | 0 | } |
864 | | |
865 | | void |
866 | | ChannelWrapper::GetRemoteAddress(nsCString& aRetVal) const |
867 | 0 | { |
868 | 0 | aRetVal.SetIsVoid(true); |
869 | 0 | if (nsCOMPtr<nsIHttpChannelInternal> internal = QueryChannel()) { |
870 | 0 | Unused << internal->GetRemoteAddress(aRetVal); |
871 | 0 | } |
872 | 0 | } |
873 | | |
874 | | /***************************************************************************** |
875 | | * Error handling |
876 | | *****************************************************************************/ |
877 | | |
878 | | void |
879 | | ChannelWrapper::GetErrorString(nsString& aRetVal) const |
880 | 0 | { |
881 | 0 | if (nsCOMPtr<nsIChannel> chan = MaybeChannel()) { |
882 | 0 | nsCOMPtr<nsISupports> securityInfo; |
883 | 0 | Unused << chan->GetSecurityInfo(getter_AddRefs(securityInfo)); |
884 | 0 | if (nsCOMPtr<nsITransportSecurityInfo> tsi = do_QueryInterface(securityInfo)) { |
885 | 0 | int32_t errorCode = 0; |
886 | 0 | tsi->GetErrorCode(&errorCode); |
887 | 0 | if (psm::IsNSSErrorCode(errorCode)) { |
888 | 0 | nsCOMPtr<nsINSSErrorsService> nsserr = |
889 | 0 | do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID); |
890 | 0 |
|
891 | 0 | nsresult rv = psm::GetXPCOMFromNSSError(errorCode); |
892 | 0 | if (nsserr && NS_SUCCEEDED(nsserr->GetErrorMessage(rv, aRetVal))) { |
893 | 0 | return; |
894 | 0 | } |
895 | 0 | } |
896 | 0 | } |
897 | 0 | |
898 | 0 | nsresult status; |
899 | 0 | if (NS_SUCCEEDED(chan->GetStatus(&status)) && NS_FAILED(status)) { |
900 | 0 | nsAutoCString name; |
901 | 0 | GetErrorName(status, name); |
902 | 0 | AppendUTF8toUTF16(name, aRetVal); |
903 | 0 | } else { |
904 | 0 | aRetVal.SetIsVoid(true); |
905 | 0 | } |
906 | 0 | } else { |
907 | 0 | aRetVal.AssignLiteral("NS_ERROR_UNEXPECTED"); |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | | void |
912 | | ChannelWrapper::ErrorCheck() |
913 | 0 | { |
914 | 0 | if (!mFiredErrorEvent) { |
915 | 0 | nsAutoString error; |
916 | 0 | GetErrorString(error); |
917 | 0 | if (error.Length()) { |
918 | 0 | mChannelEntry = nullptr; |
919 | 0 | mFiredErrorEvent = true; |
920 | 0 | ChannelWrapper_Binding::ClearCachedErrorStringValue(this); |
921 | 0 | FireEvent(NS_LITERAL_STRING("error")); |
922 | 0 | } |
923 | 0 | } |
924 | 0 | } |
925 | | |
926 | | /***************************************************************************** |
927 | | * nsIWebRequestListener |
928 | | *****************************************************************************/ |
929 | | |
930 | | NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener, |
931 | | nsIStreamListener, |
932 | | nsIRequestObserver, |
933 | | nsIThreadRetargetableStreamListener) |
934 | | |
935 | 0 | ChannelWrapper::RequestListener::~RequestListener() { |
936 | 0 | NS_ReleaseOnMainThreadSystemGroup("RequestListener::mChannelWrapper", |
937 | 0 | mChannelWrapper.forget()); |
938 | 0 | } |
939 | | |
940 | | nsresult |
941 | | ChannelWrapper::RequestListener::Init() |
942 | 0 | { |
943 | 0 | if (nsCOMPtr<nsITraceableChannel> chan = mChannelWrapper->QueryChannel()) { |
944 | 0 | return chan->SetNewListener(this, getter_AddRefs(mOrigStreamListener)); |
945 | 0 | } |
946 | 0 | return NS_ERROR_UNEXPECTED; |
947 | 0 | } |
948 | | |
949 | | NS_IMETHODIMP |
950 | | ChannelWrapper::RequestListener::OnStartRequest(nsIRequest *request, nsISupports * aCtxt) |
951 | 0 | { |
952 | 0 | MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener"); |
953 | 0 |
|
954 | 0 | mChannelWrapper->mChannelEntry = nullptr; |
955 | 0 | mChannelWrapper->mResponseStarted = true; |
956 | 0 | mChannelWrapper->ErrorCheck(); |
957 | 0 | mChannelWrapper->FireEvent(NS_LITERAL_STRING("start")); |
958 | 0 |
|
959 | 0 | return mOrigStreamListener->OnStartRequest(request, aCtxt); |
960 | 0 | } |
961 | | |
962 | | NS_IMETHODIMP |
963 | | ChannelWrapper::RequestListener::OnStopRequest(nsIRequest *request, nsISupports *aCtxt, |
964 | | nsresult aStatus) |
965 | 0 | { |
966 | 0 | MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener"); |
967 | 0 |
|
968 | 0 | mChannelWrapper->mChannelEntry = nullptr; |
969 | 0 | mChannelWrapper->ErrorCheck(); |
970 | 0 | mChannelWrapper->FireEvent(NS_LITERAL_STRING("stop")); |
971 | 0 |
|
972 | 0 | return mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus); |
973 | 0 | } |
974 | | |
975 | | NS_IMETHODIMP |
976 | | ChannelWrapper::RequestListener::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt, |
977 | | nsIInputStream * inStr, |
978 | | uint64_t sourceOffset, uint32_t count) |
979 | 0 | { |
980 | 0 | MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener"); |
981 | 0 | return mOrigStreamListener->OnDataAvailable(request, aCtxt, inStr, sourceOffset, count); |
982 | 0 | } |
983 | | |
984 | | NS_IMETHODIMP |
985 | | ChannelWrapper::RequestListener::CheckListenerChain() |
986 | 0 | { |
987 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!"); |
988 | 0 | nsresult rv; |
989 | 0 | nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener = |
990 | 0 | do_QueryInterface(mOrigStreamListener, &rv); |
991 | 0 | if (retargetableListener) { |
992 | 0 | return retargetableListener->CheckListenerChain(); |
993 | 0 | } |
994 | 0 | return rv; |
995 | 0 | } |
996 | | |
997 | | /***************************************************************************** |
998 | | * Event dispatching |
999 | | *****************************************************************************/ |
1000 | | |
1001 | | void |
1002 | | ChannelWrapper::FireEvent(const nsAString& aType) |
1003 | 0 | { |
1004 | 0 | EventInit init; |
1005 | 0 | init.mBubbles = false; |
1006 | 0 | init.mCancelable = false; |
1007 | 0 |
|
1008 | 0 | RefPtr<Event> event = Event::Constructor(this, aType, init); |
1009 | 0 | event->SetTrusted(true); |
1010 | 0 |
|
1011 | 0 | DispatchEvent(*event); |
1012 | 0 | } |
1013 | | |
1014 | | void |
1015 | | ChannelWrapper::CheckEventListeners() |
1016 | 0 | { |
1017 | 0 | if (!mAddedStreamListener && (HasListenersFor(nsGkAtoms::onerror) || |
1018 | 0 | HasListenersFor(nsGkAtoms::onstart) || |
1019 | 0 | HasListenersFor(nsGkAtoms::onstop) || |
1020 | 0 | mChannelEntry)) { |
1021 | 0 | auto listener = MakeRefPtr<RequestListener>(this); |
1022 | 0 | if (!NS_WARN_IF(NS_FAILED(listener->Init()))) { |
1023 | 0 | mAddedStreamListener = true; |
1024 | 0 | } |
1025 | 0 | } |
1026 | 0 | } |
1027 | | |
1028 | | void |
1029 | | ChannelWrapper::EventListenerAdded(nsAtom* aType) |
1030 | 0 | { |
1031 | 0 | CheckEventListeners(); |
1032 | 0 | } |
1033 | | |
1034 | | void |
1035 | | ChannelWrapper::EventListenerRemoved(nsAtom* aType) |
1036 | 0 | { |
1037 | 0 | CheckEventListeners(); |
1038 | 0 | } |
1039 | | |
1040 | | /***************************************************************************** |
1041 | | * Glue |
1042 | | *****************************************************************************/ |
1043 | | |
1044 | | JSObject* |
1045 | | ChannelWrapper::WrapObject(JSContext* aCx, HandleObject aGivenProto) |
1046 | 0 | { |
1047 | 0 | return ChannelWrapper_Binding::Wrap(aCx, this, aGivenProto); |
1048 | 0 | } |
1049 | | |
1050 | | NS_IMPL_CYCLE_COLLECTION_CLASS(ChannelWrapper) |
1051 | | |
1052 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChannelWrapper) |
1053 | 0 | NS_INTERFACE_MAP_ENTRY(ChannelWrapper) |
1054 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
1055 | | |
1056 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper) |
1057 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) |
1058 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
1059 | | |
1060 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper) |
1061 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) |
1062 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
1063 | | |
1064 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ChannelWrapper, DOMEventTargetHelper) |
1065 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
1066 | | |
1067 | | NS_IMPL_ADDREF_INHERITED(ChannelWrapper, DOMEventTargetHelper) |
1068 | | NS_IMPL_RELEASE_INHERITED(ChannelWrapper, DOMEventTargetHelper) |
1069 | | |
1070 | | } // namespace extensions |
1071 | | } // namespace mozilla |
1072 | | |