/src/mozilla-central/netwerk/base/nsBaseChannel.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set sw=2 sts=2 ts=8 et 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 "nsBaseChannel.h" |
8 | | #include "nsContentUtils.h" |
9 | | #include "nsURLHelper.h" |
10 | | #include "nsNetCID.h" |
11 | | #include "nsMimeTypes.h" |
12 | | #include "nsUnknownDecoder.h" |
13 | | #include "nsIScriptSecurityManager.h" |
14 | | #include "nsMimeTypes.h" |
15 | | #include "nsIHttpChannel.h" |
16 | | #include "nsIChannelEventSink.h" |
17 | | #include "nsIStreamConverterService.h" |
18 | | #include "nsChannelClassifier.h" |
19 | | #include "nsAsyncRedirectVerifyHelper.h" |
20 | | #include "nsProxyRelease.h" |
21 | | #include "nsXULAppAPI.h" |
22 | | #include "nsContentSecurityManager.h" |
23 | | #include "LoadInfo.h" |
24 | | #include "nsServiceManagerUtils.h" |
25 | | #include "nsRedirectHistoryEntry.h" |
26 | | |
27 | | // This class is used to suspend a request across a function scope. |
28 | | class ScopedRequestSuspender { |
29 | | public: |
30 | | explicit ScopedRequestSuspender(nsIRequest *request) |
31 | 0 | : mRequest(request) { |
32 | 0 | if (mRequest && NS_FAILED(mRequest->Suspend())) { |
33 | 0 | NS_WARNING("Couldn't suspend pump"); |
34 | 0 | mRequest = nullptr; |
35 | 0 | } |
36 | 0 | } |
37 | 0 | ~ScopedRequestSuspender() { |
38 | 0 | if (mRequest) |
39 | 0 | mRequest->Resume(); |
40 | 0 | } |
41 | | private: |
42 | | nsIRequest *mRequest; |
43 | | }; |
44 | | |
45 | | // Used to suspend data events from mRequest within a function scope. This is |
46 | | // usually needed when a function makes callbacks that could process events. |
47 | | #define SUSPEND_PUMP_FOR_SCOPE() \ |
48 | 0 | ScopedRequestSuspender pump_suspender__(mRequest) |
49 | | |
50 | | //----------------------------------------------------------------------------- |
51 | | // nsBaseChannel |
52 | | |
53 | | nsBaseChannel::nsBaseChannel() |
54 | | : NeckoTargetHolder(nullptr) |
55 | | , mPumpingData(false) |
56 | | , mLoadFlags(LOAD_NORMAL) |
57 | | , mQueriedProgressSink(true) |
58 | | , mSynthProgressEvents(false) |
59 | | , mAllowThreadRetargeting(true) |
60 | | , mWaitingOnAsyncRedirect(false) |
61 | | , mOpenRedirectChannel(false) |
62 | | , mRedirectFlags{ 0 } |
63 | | , mStatus(NS_OK) |
64 | | , mContentDispositionHint(UINT32_MAX) |
65 | | , mContentLength(-1) |
66 | | , mWasOpened(false) |
67 | 0 | { |
68 | 0 | mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); |
69 | 0 | } |
70 | | |
71 | | nsBaseChannel::~nsBaseChannel() |
72 | 0 | { |
73 | 0 | NS_ReleaseOnMainThreadSystemGroup( |
74 | 0 | "nsBaseChannel::mLoadInfo", mLoadInfo.forget()); |
75 | 0 | } |
76 | | |
77 | | nsresult |
78 | | nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags, |
79 | | bool openNewChannel) |
80 | 0 | { |
81 | 0 | SUSPEND_PUMP_FOR_SCOPE(); |
82 | 0 |
|
83 | 0 | // Transfer properties |
84 | 0 |
|
85 | 0 | newChannel->SetLoadGroup(mLoadGroup); |
86 | 0 | newChannel->SetNotificationCallbacks(mCallbacks); |
87 | 0 | newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE); |
88 | 0 |
|
89 | 0 | // make a copy of the loadinfo, append to the redirectchain |
90 | 0 | // and set it on the new channel |
91 | 0 | if (mLoadInfo) { |
92 | 0 | nsSecurityFlags secFlags = mLoadInfo->GetSecurityFlags() & |
93 | 0 | ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; |
94 | 0 | nsCOMPtr<nsILoadInfo> newLoadInfo = |
95 | 0 | static_cast<mozilla::net::LoadInfo*>(mLoadInfo.get())->CloneWithNewSecFlags(secFlags); |
96 | 0 |
|
97 | 0 | nsCOMPtr<nsIPrincipal> uriPrincipal; |
98 | 0 | nsIScriptSecurityManager *sm = nsContentUtils::GetSecurityManager(); |
99 | 0 | sm->GetChannelURIPrincipal(this, getter_AddRefs(uriPrincipal)); |
100 | 0 | bool isInternalRedirect = |
101 | 0 | (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL | |
102 | 0 | nsIChannelEventSink::REDIRECT_STS_UPGRADE)); |
103 | 0 |
|
104 | 0 | // nsBaseChannel hst no thing to do with HttpBaseChannel, we would not care |
105 | 0 | // about referrer and remote address in this case |
106 | 0 | nsCOMPtr<nsIRedirectHistoryEntry> entry = |
107 | 0 | new nsRedirectHistoryEntry(uriPrincipal, nullptr, EmptyCString()); |
108 | 0 |
|
109 | 0 | newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect); |
110 | 0 |
|
111 | 0 | // Ensure the channel's loadInfo's result principal URI so that it's |
112 | 0 | // either non-null or updated to the redirect target URI. |
113 | 0 | // We must do this because in case the loadInfo's result principal URI |
114 | 0 | // is null, it would be taken from OriginalURI of the channel. But we |
115 | 0 | // overwrite it with the whole redirect chain first URI before opening |
116 | 0 | // the target channel, hence the information would be lost. |
117 | 0 | // If the protocol handler that created the channel wants to use |
118 | 0 | // the originalURI of the channel as the principal URI, it has left |
119 | 0 | // the result principal URI on the load info null. |
120 | 0 | nsCOMPtr<nsIURI> resultPrincipalURI; |
121 | 0 |
|
122 | 0 | nsCOMPtr<nsILoadInfo> existingLoadInfo = newChannel->GetLoadInfo(); |
123 | 0 | if (existingLoadInfo) { |
124 | 0 | existingLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); |
125 | 0 | } |
126 | 0 | if (!resultPrincipalURI) { |
127 | 0 | newChannel->GetOriginalURI(getter_AddRefs(resultPrincipalURI)); |
128 | 0 | } |
129 | 0 |
|
130 | 0 | newLoadInfo->SetResultPrincipalURI(resultPrincipalURI); |
131 | 0 |
|
132 | 0 | newChannel->SetLoadInfo(newLoadInfo); |
133 | 0 | } |
134 | 0 | else { |
135 | 0 | // the newChannel was created with a dummy loadInfo, we should clear |
136 | 0 | // it in case the original channel does not have a loadInfo |
137 | 0 | newChannel->SetLoadInfo(nullptr); |
138 | 0 | } |
139 | 0 |
|
140 | 0 | // Preserve the privacy bit if it has been overridden |
141 | 0 | if (mPrivateBrowsingOverriden) { |
142 | 0 | nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel = |
143 | 0 | do_QueryInterface(newChannel); |
144 | 0 | if (newPBChannel) { |
145 | 0 | newPBChannel->SetPrivate(mPrivateBrowsing); |
146 | 0 | } |
147 | 0 | } |
148 | 0 |
|
149 | 0 | nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel); |
150 | 0 | if (bag) { |
151 | 0 | for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) { |
152 | 0 | bag->SetProperty(iter.Key(), iter.UserData()); |
153 | 0 | } |
154 | 0 | } |
155 | 0 |
|
156 | 0 | // Notify consumer, giving chance to cancel redirect. |
157 | 0 |
|
158 | 0 | RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper = |
159 | 0 | new nsAsyncRedirectVerifyHelper(); |
160 | 0 |
|
161 | 0 | bool checkRedirectSynchronously = !openNewChannel; |
162 | 0 | nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); |
163 | 0 |
|
164 | 0 | mRedirectChannel = newChannel; |
165 | 0 | mRedirectFlags = redirectFlags; |
166 | 0 | mOpenRedirectChannel = openNewChannel; |
167 | 0 | nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags, |
168 | 0 | target, checkRedirectSynchronously); |
169 | 0 | if (NS_FAILED(rv)) |
170 | 0 | return rv; |
171 | 0 | |
172 | 0 | if (checkRedirectSynchronously && NS_FAILED(mStatus)) |
173 | 0 | return mStatus; |
174 | 0 | |
175 | 0 | return NS_OK; |
176 | 0 | } |
177 | | |
178 | | nsresult |
179 | | nsBaseChannel::ContinueRedirect() |
180 | 0 | { |
181 | 0 | // Make sure to do this _after_ making all the OnChannelRedirect calls |
182 | 0 | mRedirectChannel->SetOriginalURI(OriginalURI()); |
183 | 0 |
|
184 | 0 | // If we fail to open the new channel, then we want to leave this channel |
185 | 0 | // unaffected, so we defer tearing down our channel until we have succeeded |
186 | 0 | // with the redirect. |
187 | 0 |
|
188 | 0 | if (mOpenRedirectChannel) { |
189 | 0 | nsresult rv = NS_OK; |
190 | 0 | if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) { |
191 | 0 | MOZ_ASSERT(!mListenerContext, "mListenerContext should be null!"); |
192 | 0 | rv = mRedirectChannel->AsyncOpen2(mListener); |
193 | 0 | } |
194 | 0 | else { |
195 | 0 | rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext); |
196 | 0 | } |
197 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
198 | 0 | } |
199 | 0 |
|
200 | 0 | mRedirectChannel = nullptr; |
201 | 0 |
|
202 | 0 | // close down this channel |
203 | 0 | Cancel(NS_BINDING_REDIRECTED); |
204 | 0 | ChannelDone(); |
205 | 0 |
|
206 | 0 | return NS_OK; |
207 | 0 | } |
208 | | |
209 | | bool |
210 | | nsBaseChannel::HasContentTypeHint() const |
211 | 0 | { |
212 | 0 | NS_ASSERTION(!Pending(), "HasContentTypeHint called too late"); |
213 | 0 | return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE); |
214 | 0 | } |
215 | | |
216 | | nsresult |
217 | | nsBaseChannel::PushStreamConverter(const char *fromType, |
218 | | const char *toType, |
219 | | bool invalidatesContentLength, |
220 | | nsIStreamListener **result) |
221 | 0 | { |
222 | 0 | NS_ASSERTION(mListener, "no listener"); |
223 | 0 |
|
224 | 0 | nsresult rv; |
225 | 0 | nsCOMPtr<nsIStreamConverterService> scs = |
226 | 0 | do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv); |
227 | 0 | if (NS_FAILED(rv)) |
228 | 0 | return rv; |
229 | 0 | |
230 | 0 | nsCOMPtr<nsIStreamListener> converter; |
231 | 0 | rv = scs->AsyncConvertData(fromType, toType, mListener, mListenerContext, |
232 | 0 | getter_AddRefs(converter)); |
233 | 0 | if (NS_SUCCEEDED(rv)) { |
234 | 0 | mListener = converter; |
235 | 0 | if (invalidatesContentLength) |
236 | 0 | mContentLength = -1; |
237 | 0 | if (result) { |
238 | 0 | *result = nullptr; |
239 | 0 | converter.swap(*result); |
240 | 0 | } |
241 | 0 | } |
242 | 0 | return rv; |
243 | 0 | } |
244 | | |
245 | | nsresult |
246 | | nsBaseChannel::BeginPumpingData() |
247 | 0 | { |
248 | 0 | nsresult rv; |
249 | 0 |
|
250 | 0 | rv = BeginAsyncRead(this, getter_AddRefs(mRequest)); |
251 | 0 | if (NS_SUCCEEDED(rv)) { |
252 | 0 | mPumpingData = true; |
253 | 0 | return NS_OK; |
254 | 0 | } |
255 | 0 | if (rv != NS_ERROR_NOT_IMPLEMENTED) { |
256 | 0 | return rv; |
257 | 0 | } |
258 | 0 | |
259 | 0 | nsCOMPtr<nsIInputStream> stream; |
260 | 0 | nsCOMPtr<nsIChannel> channel; |
261 | 0 | rv = OpenContentStream(true, getter_AddRefs(stream), |
262 | 0 | getter_AddRefs(channel)); |
263 | 0 | if (NS_FAILED(rv)) |
264 | 0 | return rv; |
265 | 0 | |
266 | 0 | NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?"); |
267 | 0 |
|
268 | 0 | if (channel) { |
269 | 0 | nsCOMPtr<nsIRunnable> runnable = new RedirectRunnable(this, channel); |
270 | 0 | rv = Dispatch(runnable.forget()); |
271 | 0 | if (NS_SUCCEEDED(rv)) |
272 | 0 | mWaitingOnAsyncRedirect = true; |
273 | 0 | return rv; |
274 | 0 | } |
275 | 0 |
|
276 | 0 | // By assigning mPump, we flag this channel as pending (see Pending). It's |
277 | 0 | // important that the pending flag is set when we call into the stream (the |
278 | 0 | // call to AsyncRead results in the stream's AsyncWait method being called) |
279 | 0 | // and especially when we call into the loadgroup. Our caller takes care to |
280 | 0 | // release mPump if we return an error. |
281 | 0 |
|
282 | 0 | nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); |
283 | 0 | rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, 0, 0, true, |
284 | 0 | target); |
285 | 0 | if (NS_SUCCEEDED(rv)) { |
286 | 0 | mPumpingData = true; |
287 | 0 | mRequest = mPump; |
288 | 0 | rv = mPump->AsyncRead(this, nullptr); |
289 | 0 | } |
290 | 0 |
|
291 | 0 | return rv; |
292 | 0 | } |
293 | | |
294 | | void |
295 | | nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel) |
296 | 0 | { |
297 | 0 | NS_ASSERTION(!mPumpingData, "Shouldn't have gotten here"); |
298 | 0 |
|
299 | 0 | nsresult rv = mStatus; |
300 | 0 | if (NS_SUCCEEDED(mStatus)) { |
301 | 0 | rv = Redirect(newChannel, |
302 | 0 | nsIChannelEventSink::REDIRECT_TEMPORARY, |
303 | 0 | true); |
304 | 0 | if (NS_SUCCEEDED(rv)) { |
305 | 0 | // OnRedirectVerifyCallback will be called asynchronously |
306 | 0 | return; |
307 | 0 | } |
308 | 0 | } |
309 | 0 | |
310 | 0 | ContinueHandleAsyncRedirect(rv); |
311 | 0 | } |
312 | | |
313 | | void |
314 | | nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result) |
315 | 0 | { |
316 | 0 | mWaitingOnAsyncRedirect = false; |
317 | 0 |
|
318 | 0 | if (NS_FAILED(result)) |
319 | 0 | Cancel(result); |
320 | 0 |
|
321 | 0 | if (NS_FAILED(result) && mListener) { |
322 | 0 | // Notify our consumer ourselves |
323 | 0 | mListener->OnStartRequest(this, mListenerContext); |
324 | 0 | mListener->OnStopRequest(this, mListenerContext, mStatus); |
325 | 0 | ChannelDone(); |
326 | 0 | } |
327 | 0 |
|
328 | 0 | if (mLoadGroup) |
329 | 0 | mLoadGroup->RemoveRequest(this, nullptr, mStatus); |
330 | 0 |
|
331 | 0 | // Drop notification callbacks to prevent cycles. |
332 | 0 | mCallbacks = nullptr; |
333 | 0 | CallbacksChanged(); |
334 | 0 | } |
335 | | |
336 | | void |
337 | | nsBaseChannel::ClassifyURI() |
338 | 0 | { |
339 | 0 | // For channels created in the child process, delegate to the parent to |
340 | 0 | // classify URIs. |
341 | 0 | if (!XRE_IsParentProcess()) { |
342 | 0 | return; |
343 | 0 | } |
344 | 0 | |
345 | 0 | if (mLoadFlags & LOAD_CLASSIFY_URI) { |
346 | 0 | RefPtr<nsChannelClassifier> classifier = new nsChannelClassifier(this); |
347 | 0 | if (classifier) { |
348 | 0 | classifier->Start(); |
349 | 0 | } else { |
350 | 0 | Cancel(NS_ERROR_OUT_OF_MEMORY); |
351 | 0 | } |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | //----------------------------------------------------------------------------- |
356 | | // nsBaseChannel::nsISupports |
357 | | |
358 | | NS_IMPL_ISUPPORTS_INHERITED(nsBaseChannel, |
359 | | nsHashPropertyBag, |
360 | | nsIRequest, |
361 | | nsIChannel, |
362 | | nsIThreadRetargetableRequest, |
363 | | nsIInterfaceRequestor, |
364 | | nsITransportEventSink, |
365 | | nsIRequestObserver, |
366 | | nsIStreamListener, |
367 | | nsIThreadRetargetableStreamListener, |
368 | | nsIAsyncVerifyRedirectCallback, |
369 | | nsIPrivateBrowsingChannel) |
370 | | |
371 | | //----------------------------------------------------------------------------- |
372 | | // nsBaseChannel::nsIRequest |
373 | | |
374 | | NS_IMETHODIMP |
375 | | nsBaseChannel::GetName(nsACString &result) |
376 | 0 | { |
377 | 0 | if (!mURI) { |
378 | 0 | result.Truncate(); |
379 | 0 | return NS_OK; |
380 | 0 | } |
381 | 0 | return mURI->GetSpec(result); |
382 | 0 | } |
383 | | |
384 | | NS_IMETHODIMP |
385 | | nsBaseChannel::IsPending(bool *result) |
386 | 0 | { |
387 | 0 | *result = Pending(); |
388 | 0 | return NS_OK; |
389 | 0 | } |
390 | | |
391 | | NS_IMETHODIMP |
392 | | nsBaseChannel::GetStatus(nsresult *status) |
393 | 0 | { |
394 | 0 | if (mRequest && NS_SUCCEEDED(mStatus)) { |
395 | 0 | mRequest->GetStatus(status); |
396 | 0 | } else { |
397 | 0 | *status = mStatus; |
398 | 0 | } |
399 | 0 | return NS_OK; |
400 | 0 | } |
401 | | |
402 | | NS_IMETHODIMP |
403 | | nsBaseChannel::Cancel(nsresult status) |
404 | 0 | { |
405 | 0 | // Ignore redundant cancelation |
406 | 0 | if (NS_FAILED(mStatus)) |
407 | 0 | return NS_OK; |
408 | 0 | |
409 | 0 | mStatus = status; |
410 | 0 |
|
411 | 0 | if (mRequest) |
412 | 0 | mRequest->Cancel(status); |
413 | 0 |
|
414 | 0 | return NS_OK; |
415 | 0 | } |
416 | | |
417 | | NS_IMETHODIMP |
418 | | nsBaseChannel::Suspend() |
419 | 0 | { |
420 | 0 | NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED); |
421 | 0 | NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED); |
422 | 0 | return mRequest->Suspend(); |
423 | 0 | } |
424 | | |
425 | | NS_IMETHODIMP |
426 | | nsBaseChannel::Resume() |
427 | 0 | { |
428 | 0 | NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED); |
429 | 0 | NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED); |
430 | 0 | return mRequest->Resume(); |
431 | 0 | } |
432 | | |
433 | | NS_IMETHODIMP |
434 | | nsBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) |
435 | 0 | { |
436 | 0 | *aLoadFlags = mLoadFlags; |
437 | 0 | return NS_OK; |
438 | 0 | } |
439 | | |
440 | | NS_IMETHODIMP |
441 | | nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags) |
442 | 0 | { |
443 | 0 | mLoadFlags = aLoadFlags; |
444 | 0 | return NS_OK; |
445 | 0 | } |
446 | | |
447 | | NS_IMETHODIMP |
448 | | nsBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) |
449 | 0 | { |
450 | 0 | NS_IF_ADDREF(*aLoadGroup = mLoadGroup); |
451 | 0 | return NS_OK; |
452 | 0 | } |
453 | | |
454 | | NS_IMETHODIMP |
455 | | nsBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) |
456 | 0 | { |
457 | 0 | if (!CanSetLoadGroup(aLoadGroup)) { |
458 | 0 | return NS_ERROR_FAILURE; |
459 | 0 | } |
460 | 0 | |
461 | 0 | mLoadGroup = aLoadGroup; |
462 | 0 | CallbacksChanged(); |
463 | 0 | UpdatePrivateBrowsing(); |
464 | 0 | return NS_OK; |
465 | 0 | } |
466 | | |
467 | | //----------------------------------------------------------------------------- |
468 | | // nsBaseChannel::nsIChannel |
469 | | |
470 | | NS_IMETHODIMP |
471 | | nsBaseChannel::GetOriginalURI(nsIURI **aURI) |
472 | 0 | { |
473 | 0 | *aURI = OriginalURI(); |
474 | 0 | NS_ADDREF(*aURI); |
475 | 0 | return NS_OK; |
476 | 0 | } |
477 | | |
478 | | NS_IMETHODIMP |
479 | | nsBaseChannel::SetOriginalURI(nsIURI *aURI) |
480 | 0 | { |
481 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
482 | 0 | mOriginalURI = aURI; |
483 | 0 | return NS_OK; |
484 | 0 | } |
485 | | |
486 | | NS_IMETHODIMP |
487 | | nsBaseChannel::GetURI(nsIURI **aURI) |
488 | 0 | { |
489 | 0 | NS_IF_ADDREF(*aURI = mURI); |
490 | 0 | return NS_OK; |
491 | 0 | } |
492 | | |
493 | | NS_IMETHODIMP |
494 | | nsBaseChannel::GetOwner(nsISupports **aOwner) |
495 | 0 | { |
496 | 0 | NS_IF_ADDREF(*aOwner = mOwner); |
497 | 0 | return NS_OK; |
498 | 0 | } |
499 | | |
500 | | NS_IMETHODIMP |
501 | | nsBaseChannel::SetOwner(nsISupports *aOwner) |
502 | 0 | { |
503 | 0 | mOwner = aOwner; |
504 | 0 | return NS_OK; |
505 | 0 | } |
506 | | |
507 | | NS_IMETHODIMP |
508 | | nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) |
509 | 0 | { |
510 | 0 | mLoadInfo = aLoadInfo; |
511 | 0 |
|
512 | 0 | // Need to update |mNeckoTarget| when load info has changed. |
513 | 0 | SetupNeckoTarget(); |
514 | 0 | return NS_OK; |
515 | 0 | } |
516 | | |
517 | | NS_IMETHODIMP |
518 | | nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) |
519 | 0 | { |
520 | 0 | NS_IF_ADDREF(*aLoadInfo = mLoadInfo); |
521 | 0 | return NS_OK; |
522 | 0 | } |
523 | | |
524 | | NS_IMETHODIMP |
525 | | nsBaseChannel::GetIsDocument(bool *aIsDocument) |
526 | 0 | { |
527 | 0 | return NS_GetIsDocumentChannel(this, aIsDocument); |
528 | 0 | } |
529 | | |
530 | | NS_IMETHODIMP |
531 | | nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) |
532 | 0 | { |
533 | 0 | NS_IF_ADDREF(*aCallbacks = mCallbacks); |
534 | 0 | return NS_OK; |
535 | 0 | } |
536 | | |
537 | | NS_IMETHODIMP |
538 | | nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) |
539 | 0 | { |
540 | 0 | if (!CanSetCallbacks(aCallbacks)) { |
541 | 0 | return NS_ERROR_FAILURE; |
542 | 0 | } |
543 | 0 | |
544 | 0 | mCallbacks = aCallbacks; |
545 | 0 | CallbacksChanged(); |
546 | 0 | UpdatePrivateBrowsing(); |
547 | 0 | return NS_OK; |
548 | 0 | } |
549 | | |
550 | | NS_IMETHODIMP |
551 | | nsBaseChannel::GetSecurityInfo(nsISupports **aSecurityInfo) |
552 | 0 | { |
553 | 0 | NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo); |
554 | 0 | return NS_OK; |
555 | 0 | } |
556 | | |
557 | | NS_IMETHODIMP |
558 | | nsBaseChannel::GetContentType(nsACString &aContentType) |
559 | 0 | { |
560 | 0 | aContentType = mContentType; |
561 | 0 | return NS_OK; |
562 | 0 | } |
563 | | |
564 | | NS_IMETHODIMP |
565 | | nsBaseChannel::SetContentType(const nsACString &aContentType) |
566 | 0 | { |
567 | 0 | // mContentCharset is unchanged if not parsed |
568 | 0 | bool dummy; |
569 | 0 | net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy); |
570 | 0 | return NS_OK; |
571 | 0 | } |
572 | | |
573 | | NS_IMETHODIMP |
574 | | nsBaseChannel::GetContentCharset(nsACString &aContentCharset) |
575 | 0 | { |
576 | 0 | aContentCharset = mContentCharset; |
577 | 0 | return NS_OK; |
578 | 0 | } |
579 | | |
580 | | NS_IMETHODIMP |
581 | | nsBaseChannel::SetContentCharset(const nsACString &aContentCharset) |
582 | 0 | { |
583 | 0 | mContentCharset = aContentCharset; |
584 | 0 | return NS_OK; |
585 | 0 | } |
586 | | |
587 | | NS_IMETHODIMP |
588 | | nsBaseChannel::GetContentDisposition(uint32_t *aContentDisposition) |
589 | 0 | { |
590 | 0 | // preserve old behavior, fail unless explicitly set. |
591 | 0 | if (mContentDispositionHint == UINT32_MAX) { |
592 | 0 | return NS_ERROR_NOT_AVAILABLE; |
593 | 0 | } |
594 | 0 | |
595 | 0 | *aContentDisposition = mContentDispositionHint; |
596 | 0 | return NS_OK; |
597 | 0 | } |
598 | | |
599 | | NS_IMETHODIMP |
600 | | nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition) |
601 | 0 | { |
602 | 0 | mContentDispositionHint = aContentDisposition; |
603 | 0 | return NS_OK; |
604 | 0 | } |
605 | | |
606 | | NS_IMETHODIMP |
607 | | nsBaseChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename) |
608 | 0 | { |
609 | 0 | if (!mContentDispositionFilename) { |
610 | 0 | return NS_ERROR_NOT_AVAILABLE; |
611 | 0 | } |
612 | 0 | |
613 | 0 | aContentDispositionFilename = *mContentDispositionFilename; |
614 | 0 | return NS_OK; |
615 | 0 | } |
616 | | |
617 | | NS_IMETHODIMP |
618 | | nsBaseChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename) |
619 | 0 | { |
620 | 0 | mContentDispositionFilename = new nsString(aContentDispositionFilename); |
621 | 0 | return NS_OK; |
622 | 0 | } |
623 | | |
624 | | NS_IMETHODIMP |
625 | | nsBaseChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader) |
626 | 0 | { |
627 | 0 | return NS_ERROR_NOT_AVAILABLE; |
628 | 0 | } |
629 | | |
630 | | NS_IMETHODIMP |
631 | | nsBaseChannel::GetContentLength(int64_t *aContentLength) |
632 | 0 | { |
633 | 0 | *aContentLength = mContentLength; |
634 | 0 | return NS_OK; |
635 | 0 | } |
636 | | |
637 | | NS_IMETHODIMP |
638 | | nsBaseChannel::SetContentLength(int64_t aContentLength) |
639 | 0 | { |
640 | 0 | mContentLength = aContentLength; |
641 | 0 | return NS_OK; |
642 | 0 | } |
643 | | |
644 | | NS_IMETHODIMP |
645 | | nsBaseChannel::Open(nsIInputStream **result) |
646 | 0 | { |
647 | 0 | NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED); |
648 | 0 | NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS); |
649 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS); |
650 | 0 |
|
651 | 0 | nsCOMPtr<nsIChannel> chan; |
652 | 0 | nsresult rv = OpenContentStream(false, result, getter_AddRefs(chan)); |
653 | 0 | NS_ASSERTION(!chan || !*result, "Got both a channel and a stream?"); |
654 | 0 | if (NS_SUCCEEDED(rv) && chan) { |
655 | 0 | rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false); |
656 | 0 | if (NS_FAILED(rv)) |
657 | 0 | return rv; |
658 | 0 | rv = chan->Open(result); |
659 | 0 | } else if (rv == NS_ERROR_NOT_IMPLEMENTED) |
660 | 0 | return NS_ImplementChannelOpen(this, result); |
661 | 0 | |
662 | 0 | if (NS_SUCCEEDED(rv)) { |
663 | 0 | mWasOpened = true; |
664 | 0 | ClassifyURI(); |
665 | 0 | } |
666 | 0 |
|
667 | 0 | return rv; |
668 | 0 | } |
669 | | |
670 | | NS_IMETHODIMP |
671 | | nsBaseChannel::Open2(nsIInputStream** aStream) |
672 | 0 | { |
673 | 0 | nsCOMPtr<nsIStreamListener> listener; |
674 | 0 | nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); |
675 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
676 | 0 | return Open(aStream); |
677 | 0 | } |
678 | | |
679 | | NS_IMETHODIMP |
680 | | nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) |
681 | 0 | { |
682 | 0 | MOZ_ASSERT(!mLoadInfo || |
683 | 0 | mLoadInfo->GetSecurityMode() == 0 || |
684 | 0 | mLoadInfo->GetInitialSecurityCheckDone() || |
685 | 0 | (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && |
686 | 0 | nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())), |
687 | 0 | "security flags in loadInfo but asyncOpen2() not called"); |
688 | 0 |
|
689 | 0 | NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED); |
690 | 0 | NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS); |
691 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); |
692 | 0 | NS_ENSURE_ARG(listener); |
693 | 0 |
|
694 | 0 | SetupNeckoTarget(); |
695 | 0 |
|
696 | 0 | // Skip checking for chrome:// sub-resources. |
697 | 0 | nsAutoCString scheme; |
698 | 0 | mURI->GetScheme(scheme); |
699 | 0 | if (!scheme.EqualsLiteral("file")) { |
700 | 0 | NS_CompareLoadInfoAndLoadContext(this); |
701 | 0 | } |
702 | 0 |
|
703 | 0 | // Ensure that this is an allowed port before proceeding. |
704 | 0 | nsresult rv = NS_CheckPortSafety(mURI); |
705 | 0 | if (NS_FAILED(rv)) { |
706 | 0 | mCallbacks = nullptr; |
707 | 0 | return rv; |
708 | 0 | } |
709 | 0 | |
710 | 0 | // Store the listener and context early so that OpenContentStream and the |
711 | 0 | // stream's AsyncWait method (called by AsyncRead) can have access to them |
712 | 0 | // via PushStreamConverter and the StreamListener methods. However, since |
713 | 0 | // this typically introduces a reference cycle between this and the listener, |
714 | 0 | // we need to be sure to break the reference if this method does not succeed. |
715 | 0 | mListener = listener; |
716 | 0 | mListenerContext = ctxt; |
717 | 0 |
|
718 | 0 | // This method assigns mPump as a side-effect. We need to clear mPump if |
719 | 0 | // this method fails. |
720 | 0 | rv = BeginPumpingData(); |
721 | 0 | if (NS_FAILED(rv)) { |
722 | 0 | mPump = nullptr; |
723 | 0 | mRequest = nullptr; |
724 | 0 | mPumpingData = false; |
725 | 0 | ChannelDone(); |
726 | 0 | mCallbacks = nullptr; |
727 | 0 | return rv; |
728 | 0 | } |
729 | 0 | |
730 | 0 | // At this point, we are going to return success no matter what. |
731 | 0 | |
732 | 0 | mWasOpened = true; |
733 | 0 |
|
734 | 0 | SUSPEND_PUMP_FOR_SCOPE(); |
735 | 0 |
|
736 | 0 | if (mLoadGroup) |
737 | 0 | mLoadGroup->AddRequest(this, nullptr); |
738 | 0 |
|
739 | 0 | ClassifyURI(); |
740 | 0 |
|
741 | 0 | return NS_OK; |
742 | 0 | } |
743 | | |
744 | | NS_IMETHODIMP |
745 | | nsBaseChannel::AsyncOpen2(nsIStreamListener *aListener) |
746 | 0 | { |
747 | 0 | nsCOMPtr<nsIStreamListener> listener = aListener; |
748 | 0 | nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); |
749 | 0 | if (NS_FAILED(rv)) { |
750 | 0 | mCallbacks = nullptr; |
751 | 0 | return rv; |
752 | 0 | } |
753 | 0 | return AsyncOpen(listener, nullptr); |
754 | 0 | } |
755 | | |
756 | | //----------------------------------------------------------------------------- |
757 | | // nsBaseChannel::nsITransportEventSink |
758 | | |
759 | | NS_IMETHODIMP |
760 | | nsBaseChannel::OnTransportStatus(nsITransport *transport, nsresult status, |
761 | | int64_t progress, int64_t progressMax) |
762 | 0 | { |
763 | 0 | // In some cases, we may wish to suppress transport-layer status events. |
764 | 0 |
|
765 | 0 | if (!mPumpingData || NS_FAILED(mStatus)) { |
766 | 0 | return NS_OK; |
767 | 0 | } |
768 | 0 | |
769 | 0 | SUSPEND_PUMP_FOR_SCOPE(); |
770 | 0 |
|
771 | 0 | // Lazily fetch mProgressSink |
772 | 0 | if (!mProgressSink) { |
773 | 0 | if (mQueriedProgressSink) { |
774 | 0 | return NS_OK; |
775 | 0 | } |
776 | 0 | GetCallback(mProgressSink); |
777 | 0 | mQueriedProgressSink = true; |
778 | 0 | if (!mProgressSink) { |
779 | 0 | return NS_OK; |
780 | 0 | } |
781 | 0 | } |
782 | 0 | |
783 | 0 | if (!HasLoadFlag(LOAD_BACKGROUND)) { |
784 | 0 | nsAutoString statusArg; |
785 | 0 | if (GetStatusArg(status, statusArg)) { |
786 | 0 | mProgressSink->OnStatus(this, mListenerContext, status, statusArg.get()); |
787 | 0 | } |
788 | 0 | } |
789 | 0 |
|
790 | 0 | if (progress) { |
791 | 0 | mProgressSink->OnProgress(this, mListenerContext, progress, progressMax); |
792 | 0 | } |
793 | 0 |
|
794 | 0 | return NS_OK; |
795 | 0 | } |
796 | | |
797 | | //----------------------------------------------------------------------------- |
798 | | // nsBaseChannel::nsIInterfaceRequestor |
799 | | |
800 | | NS_IMETHODIMP |
801 | | nsBaseChannel::GetInterface(const nsIID &iid, void **result) |
802 | 0 | { |
803 | 0 | NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result); |
804 | 0 | return *result ? NS_OK : NS_ERROR_NO_INTERFACE; |
805 | 0 | } |
806 | | |
807 | | //----------------------------------------------------------------------------- |
808 | | // nsBaseChannel::nsIRequestObserver |
809 | | |
810 | | static void |
811 | | CallTypeSniffers(void *aClosure, const uint8_t *aData, uint32_t aCount) |
812 | 0 | { |
813 | 0 | nsIChannel *chan = static_cast<nsIChannel*>(aClosure); |
814 | 0 |
|
815 | 0 | nsAutoCString newType; |
816 | 0 | NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType); |
817 | 0 | if (!newType.IsEmpty()) { |
818 | 0 | chan->SetContentType(newType); |
819 | 0 | } |
820 | 0 | } |
821 | | |
822 | | static void |
823 | | CallUnknownTypeSniffer(void *aClosure, const uint8_t *aData, uint32_t aCount) |
824 | 0 | { |
825 | 0 | nsIChannel *chan = static_cast<nsIChannel*>(aClosure); |
826 | 0 |
|
827 | 0 | RefPtr<nsUnknownDecoder> sniffer = new nsUnknownDecoder(); |
828 | 0 |
|
829 | 0 | nsAutoCString detected; |
830 | 0 | nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected); |
831 | 0 | if (NS_SUCCEEDED(rv)) |
832 | 0 | chan->SetContentType(detected); |
833 | 0 | } |
834 | | |
835 | | NS_IMETHODIMP |
836 | | nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt) |
837 | 0 | { |
838 | 0 | MOZ_ASSERT_IF(mRequest, request == mRequest); |
839 | 0 |
|
840 | 0 | if (mPump) { |
841 | 0 | // If our content type is unknown, use the content type |
842 | 0 | // sniffer. If the sniffer is not available for some reason, then we just keep |
843 | 0 | // going as-is. |
844 | 0 | if (NS_SUCCEEDED(mStatus) && |
845 | 0 | mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) { |
846 | 0 | mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this)); |
847 | 0 | } |
848 | 0 |
|
849 | 0 | // Now, the general type sniffers. Skip this if we have none. |
850 | 0 | if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) |
851 | 0 | mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this)); |
852 | 0 | } |
853 | 0 |
|
854 | 0 | SUSPEND_PUMP_FOR_SCOPE(); |
855 | 0 |
|
856 | 0 | if (mListener) // null in case of redirect |
857 | 0 | return mListener->OnStartRequest(this, mListenerContext); |
858 | 0 | return NS_OK; |
859 | 0 | } |
860 | | |
861 | | NS_IMETHODIMP |
862 | | nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, |
863 | | nsresult status) |
864 | 0 | { |
865 | 0 | // If both mStatus and status are failure codes, we keep mStatus as-is since |
866 | 0 | // that is consistent with our GetStatus and Cancel methods. |
867 | 0 | if (NS_SUCCEEDED(mStatus)) |
868 | 0 | mStatus = status; |
869 | 0 |
|
870 | 0 | // Cause Pending to return false. |
871 | 0 | mPump = nullptr; |
872 | 0 | mRequest = nullptr; |
873 | 0 | mPumpingData = false; |
874 | 0 |
|
875 | 0 | if (mListener) // null in case of redirect |
876 | 0 | mListener->OnStopRequest(this, mListenerContext, mStatus); |
877 | 0 | ChannelDone(); |
878 | 0 |
|
879 | 0 | // No need to suspend pump in this scope since we will not be receiving |
880 | 0 | // any more events from it. |
881 | 0 |
|
882 | 0 | if (mLoadGroup) |
883 | 0 | mLoadGroup->RemoveRequest(this, nullptr, mStatus); |
884 | 0 |
|
885 | 0 | // Drop notification callbacks to prevent cycles. |
886 | 0 | mCallbacks = nullptr; |
887 | 0 | CallbacksChanged(); |
888 | 0 |
|
889 | 0 | return NS_OK; |
890 | 0 | } |
891 | | |
892 | | //----------------------------------------------------------------------------- |
893 | | // nsBaseChannel::nsIStreamListener |
894 | | |
895 | | NS_IMETHODIMP |
896 | | nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, |
897 | | nsIInputStream *stream, uint64_t offset, |
898 | | uint32_t count) |
899 | 0 | { |
900 | 0 | SUSPEND_PUMP_FOR_SCOPE(); |
901 | 0 |
|
902 | 0 | nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream, |
903 | 0 | offset, count); |
904 | 0 | if (mSynthProgressEvents && NS_SUCCEEDED(rv)) { |
905 | 0 | int64_t prog = offset + count; |
906 | 0 | if (NS_IsMainThread()) { |
907 | 0 | OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength); |
908 | 0 | } else { |
909 | 0 | class OnTransportStatusAsyncEvent : public mozilla::Runnable |
910 | 0 | { |
911 | 0 | RefPtr<nsBaseChannel> mChannel; |
912 | 0 | int64_t mProgress; |
913 | 0 | int64_t mContentLength; |
914 | 0 | public: |
915 | 0 | OnTransportStatusAsyncEvent(nsBaseChannel* aChannel, |
916 | 0 | int64_t aProgress, |
917 | 0 | int64_t aContentLength) |
918 | 0 | : mozilla::Runnable("OnTransportStatusAsyncEvent") |
919 | 0 | , mChannel(aChannel) |
920 | 0 | , mProgress(aProgress) |
921 | 0 | , mContentLength(aContentLength) |
922 | 0 | { } |
923 | 0 |
|
924 | 0 | NS_IMETHOD Run() override |
925 | 0 | { |
926 | 0 | return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING, |
927 | 0 | mProgress, mContentLength); |
928 | 0 | } |
929 | 0 | }; |
930 | 0 |
|
931 | 0 | nsCOMPtr<nsIRunnable> runnable = |
932 | 0 | new OnTransportStatusAsyncEvent(this, prog, mContentLength); |
933 | 0 | Dispatch(runnable.forget()); |
934 | 0 | } |
935 | 0 | } |
936 | 0 |
|
937 | 0 | return rv; |
938 | 0 | } |
939 | | |
940 | | NS_IMETHODIMP |
941 | | nsBaseChannel::OnRedirectVerifyCallback(nsresult result) |
942 | 0 | { |
943 | 0 | if (NS_SUCCEEDED(result)) |
944 | 0 | result = ContinueRedirect(); |
945 | 0 |
|
946 | 0 | if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) { |
947 | 0 | if (NS_SUCCEEDED(mStatus)) |
948 | 0 | mStatus = result; |
949 | 0 | return NS_OK; |
950 | 0 | } |
951 | 0 |
|
952 | 0 | if (mWaitingOnAsyncRedirect) |
953 | 0 | ContinueHandleAsyncRedirect(result); |
954 | 0 |
|
955 | 0 | return NS_OK; |
956 | 0 | } |
957 | | |
958 | | NS_IMETHODIMP |
959 | | nsBaseChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget) |
960 | 0 | { |
961 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
962 | 0 |
|
963 | 0 | NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED); |
964 | 0 |
|
965 | 0 | nsCOMPtr<nsIThreadRetargetableRequest> req; |
966 | 0 | if (mAllowThreadRetargeting) { |
967 | 0 | req = do_QueryInterface(mRequest); |
968 | 0 | } |
969 | 0 |
|
970 | 0 | NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED); |
971 | 0 |
|
972 | 0 | return req->RetargetDeliveryTo(aEventTarget); |
973 | 0 | } |
974 | | |
975 | | NS_IMETHODIMP |
976 | | nsBaseChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget) |
977 | 0 | { |
978 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
979 | 0 |
|
980 | 0 | NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED); |
981 | 0 |
|
982 | 0 | nsCOMPtr<nsIThreadRetargetableRequest> req; |
983 | 0 | req = do_QueryInterface(mRequest); |
984 | 0 |
|
985 | 0 | NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED); |
986 | 0 | return req->GetDeliveryTarget(aEventTarget); |
987 | 0 | } |
988 | | |
989 | | NS_IMETHODIMP |
990 | | nsBaseChannel::CheckListenerChain() |
991 | 0 | { |
992 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
993 | 0 |
|
994 | 0 | if (!mAllowThreadRetargeting) { |
995 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
996 | 0 | } |
997 | 0 | |
998 | 0 | nsCOMPtr<nsIThreadRetargetableStreamListener> listener = |
999 | 0 | do_QueryInterface(mListener); |
1000 | 0 | if (!listener) { |
1001 | 0 | return NS_ERROR_NO_INTERFACE; |
1002 | 0 | } |
1003 | 0 | |
1004 | 0 | return listener->CheckListenerChain(); |
1005 | 0 | } |
1006 | | |
1007 | | void |
1008 | | nsBaseChannel::SetupNeckoTarget() |
1009 | 0 | { |
1010 | 0 | mNeckoTarget = |
1011 | 0 | nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, TaskCategory::Other); |
1012 | 0 | } |