|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set sw=2 ts=8 et tw=80 : */ |
|
3 |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include "mozilla/net/FTPChannelParent.h" |
|
9 #include "nsFTPChannel.h" |
|
10 #include "nsNetUtil.h" |
|
11 #include "nsFtpProtocolHandler.h" |
|
12 #include "mozilla/ipc/InputStreamUtils.h" |
|
13 #include "mozilla/ipc/URIUtils.h" |
|
14 #include "mozilla/unused.h" |
|
15 #include "SerializedLoadContext.h" |
|
16 |
|
17 using namespace mozilla::ipc; |
|
18 |
|
19 #undef LOG |
|
20 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args) |
|
21 |
|
22 namespace mozilla { |
|
23 namespace net { |
|
24 |
|
25 FTPChannelParent::FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus) |
|
26 : mIPCClosed(false) |
|
27 , mLoadContext(aLoadContext) |
|
28 , mPBOverride(aOverrideStatus) |
|
29 , mStatus(NS_OK) |
|
30 , mDivertingFromChild(false) |
|
31 , mDivertedOnStartRequest(false) |
|
32 , mSuspendedForDiversion(false) |
|
33 { |
|
34 nsIProtocolHandler* handler; |
|
35 CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler); |
|
36 NS_ASSERTION(handler, "no ftp handler"); |
|
37 } |
|
38 |
|
39 FTPChannelParent::~FTPChannelParent() |
|
40 { |
|
41 gFtpHandler->Release(); |
|
42 } |
|
43 |
|
44 void |
|
45 FTPChannelParent::ActorDestroy(ActorDestroyReason why) |
|
46 { |
|
47 // We may still have refcount>0 if the channel hasn't called OnStopRequest |
|
48 // yet, but we must not send any more msgs to child. |
|
49 mIPCClosed = true; |
|
50 } |
|
51 |
|
52 //----------------------------------------------------------------------------- |
|
53 // FTPChannelParent::nsISupports |
|
54 //----------------------------------------------------------------------------- |
|
55 |
|
56 NS_IMPL_ISUPPORTS(FTPChannelParent, |
|
57 nsIStreamListener, |
|
58 nsIParentChannel, |
|
59 nsIInterfaceRequestor, |
|
60 nsIRequestObserver) |
|
61 |
|
62 //----------------------------------------------------------------------------- |
|
63 // FTPChannelParent::PFTPChannelParent |
|
64 //----------------------------------------------------------------------------- |
|
65 |
|
66 //----------------------------------------------------------------------------- |
|
67 // FTPChannelParent methods |
|
68 //----------------------------------------------------------------------------- |
|
69 |
|
70 bool |
|
71 FTPChannelParent::Init(const FTPChannelCreationArgs& aArgs) |
|
72 { |
|
73 switch (aArgs.type()) { |
|
74 case FTPChannelCreationArgs::TFTPChannelOpenArgs: |
|
75 { |
|
76 const FTPChannelOpenArgs& a = aArgs.get_FTPChannelOpenArgs(); |
|
77 return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream()); |
|
78 } |
|
79 case FTPChannelCreationArgs::TFTPChannelConnectArgs: |
|
80 { |
|
81 const FTPChannelConnectArgs& cArgs = aArgs.get_FTPChannelConnectArgs(); |
|
82 return ConnectChannel(cArgs.channelId()); |
|
83 } |
|
84 default: |
|
85 NS_NOTREACHED("unknown open type"); |
|
86 return false; |
|
87 } |
|
88 } |
|
89 |
|
90 bool |
|
91 FTPChannelParent::DoAsyncOpen(const URIParams& aURI, |
|
92 const uint64_t& aStartPos, |
|
93 const nsCString& aEntityID, |
|
94 const OptionalInputStreamParams& aUploadStream) |
|
95 { |
|
96 nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); |
|
97 if (!uri) |
|
98 return false; |
|
99 |
|
100 #ifdef DEBUG |
|
101 nsCString uriSpec; |
|
102 uri->GetSpec(uriSpec); |
|
103 LOG(("FTPChannelParent DoAsyncOpen [this=%p uri=%s]\n", |
|
104 this, uriSpec.get())); |
|
105 #endif |
|
106 |
|
107 nsresult rv; |
|
108 nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv)); |
|
109 if (NS_FAILED(rv)) |
|
110 return SendFailedAsyncOpen(rv); |
|
111 |
|
112 nsCOMPtr<nsIChannel> chan; |
|
113 rv = NS_NewChannel(getter_AddRefs(chan), uri, ios); |
|
114 if (NS_FAILED(rv)) |
|
115 return SendFailedAsyncOpen(rv); |
|
116 |
|
117 mChannel = static_cast<nsFtpChannel*>(chan.get()); |
|
118 |
|
119 if (mPBOverride != kPBOverride_Unset) { |
|
120 mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); |
|
121 } |
|
122 |
|
123 rv = mChannel->SetNotificationCallbacks(this); |
|
124 if (NS_FAILED(rv)) |
|
125 return SendFailedAsyncOpen(rv); |
|
126 |
|
127 nsTArray<mozilla::ipc::FileDescriptor> fds; |
|
128 nsCOMPtr<nsIInputStream> upload = DeserializeInputStream(aUploadStream, fds); |
|
129 if (upload) { |
|
130 // contentType and contentLength are ignored |
|
131 rv = mChannel->SetUploadStream(upload, EmptyCString(), 0); |
|
132 if (NS_FAILED(rv)) |
|
133 return SendFailedAsyncOpen(rv); |
|
134 } |
|
135 |
|
136 rv = mChannel->ResumeAt(aStartPos, aEntityID); |
|
137 if (NS_FAILED(rv)) |
|
138 return SendFailedAsyncOpen(rv); |
|
139 |
|
140 rv = mChannel->AsyncOpen(this, nullptr); |
|
141 if (NS_FAILED(rv)) |
|
142 return SendFailedAsyncOpen(rv); |
|
143 |
|
144 return true; |
|
145 } |
|
146 |
|
147 bool |
|
148 FTPChannelParent::ConnectChannel(const uint32_t& channelId) |
|
149 { |
|
150 nsresult rv; |
|
151 |
|
152 LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId)); |
|
153 |
|
154 nsCOMPtr<nsIChannel> channel; |
|
155 rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)); |
|
156 if (NS_SUCCEEDED(rv)) |
|
157 mChannel = static_cast<nsFtpChannel*>(channel.get()); |
|
158 |
|
159 LOG((" found channel %p, rv=%08x", mChannel.get(), rv)); |
|
160 |
|
161 return true; |
|
162 } |
|
163 |
|
164 bool |
|
165 FTPChannelParent::RecvCancel(const nsresult& status) |
|
166 { |
|
167 if (mChannel) |
|
168 mChannel->Cancel(status); |
|
169 return true; |
|
170 } |
|
171 |
|
172 bool |
|
173 FTPChannelParent::RecvSuspend() |
|
174 { |
|
175 if (mChannel) |
|
176 mChannel->Suspend(); |
|
177 return true; |
|
178 } |
|
179 |
|
180 bool |
|
181 FTPChannelParent::RecvResume() |
|
182 { |
|
183 if (mChannel) |
|
184 mChannel->Resume(); |
|
185 return true; |
|
186 } |
|
187 |
|
188 bool |
|
189 FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data, |
|
190 const uint64_t& offset, |
|
191 const uint32_t& count) |
|
192 { |
|
193 if (NS_WARN_IF(!mDivertingFromChild)) { |
|
194 MOZ_ASSERT(mDivertingFromChild, |
|
195 "Cannot RecvDivertOnDataAvailable if diverting is not set!"); |
|
196 FailDiversion(NS_ERROR_UNEXPECTED); |
|
197 return false; |
|
198 } |
|
199 |
|
200 // Drop OnDataAvailables if the parent was canceled already. |
|
201 if (NS_FAILED(mStatus)) { |
|
202 return true; |
|
203 } |
|
204 |
|
205 nsCOMPtr<nsIInputStream> stringStream; |
|
206 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), |
|
207 count, NS_ASSIGNMENT_DEPEND); |
|
208 if (NS_FAILED(rv)) { |
|
209 if (mChannel) { |
|
210 mChannel->Cancel(rv); |
|
211 } |
|
212 mStatus = rv; |
|
213 return true; |
|
214 } |
|
215 |
|
216 rv = OnDataAvailable(mChannel, nullptr, stringStream, offset, count); |
|
217 |
|
218 stringStream->Close(); |
|
219 if (NS_FAILED(rv)) { |
|
220 if (mChannel) { |
|
221 mChannel->Cancel(rv); |
|
222 } |
|
223 mStatus = rv; |
|
224 } |
|
225 return true; |
|
226 } |
|
227 |
|
228 bool |
|
229 FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode) |
|
230 { |
|
231 if (NS_WARN_IF(!mDivertingFromChild)) { |
|
232 MOZ_ASSERT(mDivertingFromChild, |
|
233 "Cannot RecvDivertOnStopRequest if diverting is not set!"); |
|
234 FailDiversion(NS_ERROR_UNEXPECTED); |
|
235 return false; |
|
236 } |
|
237 |
|
238 // Honor the channel's status even if the underlying transaction completed. |
|
239 nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode; |
|
240 |
|
241 // Reset fake pending status in case OnStopRequest has already been called. |
|
242 if (mChannel) { |
|
243 mChannel->ForcePending(false); |
|
244 } |
|
245 |
|
246 OnStopRequest(mChannel, nullptr, status); |
|
247 return true; |
|
248 } |
|
249 |
|
250 bool |
|
251 FTPChannelParent::RecvDivertComplete() |
|
252 { |
|
253 if (NS_WARN_IF(!mDivertingFromChild)) { |
|
254 MOZ_ASSERT(mDivertingFromChild, |
|
255 "Cannot RecvDivertComplete if diverting is not set!"); |
|
256 FailDiversion(NS_ERROR_UNEXPECTED); |
|
257 return false; |
|
258 } |
|
259 |
|
260 nsresult rv = ResumeForDiversion(); |
|
261 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
262 FailDiversion(NS_ERROR_UNEXPECTED); |
|
263 return false; |
|
264 } |
|
265 |
|
266 return true; |
|
267 } |
|
268 |
|
269 //----------------------------------------------------------------------------- |
|
270 // FTPChannelParent::nsIRequestObserver |
|
271 //----------------------------------------------------------------------------- |
|
272 |
|
273 NS_IMETHODIMP |
|
274 FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) |
|
275 { |
|
276 LOG(("FTPChannelParent::OnStartRequest [this=%p]\n", this)); |
|
277 |
|
278 if (mDivertingFromChild) { |
|
279 MOZ_RELEASE_ASSERT(mDivertToListener, |
|
280 "Cannot divert if listener is unset!"); |
|
281 return mDivertToListener->OnStartRequest(aRequest, aContext); |
|
282 } |
|
283 |
|
284 nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest); |
|
285 MOZ_ASSERT(chan); |
|
286 NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED); |
|
287 |
|
288 int64_t contentLength; |
|
289 chan->GetContentLength(&contentLength); |
|
290 nsCString contentType; |
|
291 chan->GetContentType(contentType); |
|
292 |
|
293 nsCString entityID; |
|
294 nsCOMPtr<nsIResumableChannel> resChan = do_QueryInterface(aRequest); |
|
295 MOZ_ASSERT(resChan); // both FTP and HTTP should implement nsIResumableChannel |
|
296 if (resChan) { |
|
297 resChan->GetEntityID(entityID); |
|
298 } |
|
299 |
|
300 nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest); |
|
301 PRTime lastModified = 0; |
|
302 if (ftpChan) { |
|
303 ftpChan->GetLastModifiedTime(&lastModified); |
|
304 } else { |
|
305 // Temporary hack: if we were redirected to use an HTTP channel (ie FTP is |
|
306 // using an HTTP proxy), cancel, as we don't support those redirects yet. |
|
307 aRequest->Cancel(NS_ERROR_NOT_IMPLEMENTED); |
|
308 } |
|
309 |
|
310 URIParams uriparam; |
|
311 nsCOMPtr<nsIURI> uri; |
|
312 chan->GetURI(getter_AddRefs(uri)); |
|
313 SerializeURI(uri, uriparam); |
|
314 |
|
315 if (mIPCClosed || !SendOnStartRequest(mStatus, contentLength, contentType, |
|
316 lastModified, entityID, uriparam)) { |
|
317 return NS_ERROR_UNEXPECTED; |
|
318 } |
|
319 |
|
320 return NS_OK; |
|
321 } |
|
322 |
|
323 NS_IMETHODIMP |
|
324 FTPChannelParent::OnStopRequest(nsIRequest* aRequest, |
|
325 nsISupports* aContext, |
|
326 nsresult aStatusCode) |
|
327 { |
|
328 LOG(("FTPChannelParent::OnStopRequest: [this=%p status=%ul]\n", |
|
329 this, aStatusCode)); |
|
330 |
|
331 if (mDivertingFromChild) { |
|
332 MOZ_RELEASE_ASSERT(mDivertToListener, |
|
333 "Cannot divert if listener is unset!"); |
|
334 return mDivertToListener->OnStopRequest(aRequest, aContext, aStatusCode); |
|
335 } |
|
336 |
|
337 if (mIPCClosed || !SendOnStopRequest(aStatusCode)) { |
|
338 return NS_ERROR_UNEXPECTED; |
|
339 } |
|
340 |
|
341 return NS_OK; |
|
342 } |
|
343 |
|
344 //----------------------------------------------------------------------------- |
|
345 // FTPChannelParent::nsIStreamListener |
|
346 //----------------------------------------------------------------------------- |
|
347 |
|
348 NS_IMETHODIMP |
|
349 FTPChannelParent::OnDataAvailable(nsIRequest* aRequest, |
|
350 nsISupports* aContext, |
|
351 nsIInputStream* aInputStream, |
|
352 uint64_t aOffset, |
|
353 uint32_t aCount) |
|
354 { |
|
355 LOG(("FTPChannelParent::OnDataAvailable [this=%p]\n", this)); |
|
356 |
|
357 if (mDivertingFromChild) { |
|
358 MOZ_RELEASE_ASSERT(mDivertToListener, |
|
359 "Cannot divert if listener is unset!"); |
|
360 return mDivertToListener->OnDataAvailable(aRequest, aContext, aInputStream, |
|
361 aOffset, aCount); |
|
362 } |
|
363 |
|
364 nsCString data; |
|
365 nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount); |
|
366 if (NS_FAILED(rv)) |
|
367 return rv; |
|
368 |
|
369 if (mIPCClosed || !SendOnDataAvailable(mStatus, data, aOffset, aCount)) |
|
370 return NS_ERROR_UNEXPECTED; |
|
371 |
|
372 return NS_OK; |
|
373 } |
|
374 |
|
375 //----------------------------------------------------------------------------- |
|
376 // FTPChannelParent::nsIParentChannel |
|
377 //----------------------------------------------------------------------------- |
|
378 |
|
379 NS_IMETHODIMP |
|
380 FTPChannelParent::SetParentListener(HttpChannelParentListener* aListener) |
|
381 { |
|
382 // Do not need ptr to HttpChannelParentListener. |
|
383 return NS_OK; |
|
384 } |
|
385 |
|
386 NS_IMETHODIMP |
|
387 FTPChannelParent::Delete() |
|
388 { |
|
389 if (mIPCClosed || !SendDeleteSelf()) |
|
390 return NS_ERROR_UNEXPECTED; |
|
391 |
|
392 return NS_OK; |
|
393 } |
|
394 |
|
395 //----------------------------------------------------------------------------- |
|
396 // FTPChannelParent::nsIInterfaceRequestor |
|
397 //----------------------------------------------------------------------------- |
|
398 |
|
399 NS_IMETHODIMP |
|
400 FTPChannelParent::GetInterface(const nsIID& uuid, void** result) |
|
401 { |
|
402 // Only support nsILoadContext if child channel's callbacks did too |
|
403 if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { |
|
404 NS_ADDREF(mLoadContext); |
|
405 *result = static_cast<nsILoadContext*>(mLoadContext); |
|
406 return NS_OK; |
|
407 } |
|
408 |
|
409 return QueryInterface(uuid, result); |
|
410 } |
|
411 |
|
412 //----------------------------------------------------------------------------- |
|
413 // FTPChannelParent::ADivertableParentChannel |
|
414 //----------------------------------------------------------------------------- |
|
415 nsresult |
|
416 FTPChannelParent::SuspendForDiversion() |
|
417 { |
|
418 MOZ_ASSERT(mChannel); |
|
419 if (NS_WARN_IF(mDivertingFromChild)) { |
|
420 MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!"); |
|
421 return NS_ERROR_UNEXPECTED; |
|
422 } |
|
423 |
|
424 // Try suspending the channel. Allow it to fail, since OnStopRequest may have |
|
425 // been called and thus the channel may not be pending. |
|
426 nsresult rv = mChannel->Suspend(); |
|
427 MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE); |
|
428 mSuspendedForDiversion = NS_SUCCEEDED(rv); |
|
429 |
|
430 // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent |
|
431 // to the child. |
|
432 mDivertingFromChild = true; |
|
433 |
|
434 return NS_OK; |
|
435 } |
|
436 |
|
437 /* private, supporting function for ADivertableParentChannel */ |
|
438 nsresult |
|
439 FTPChannelParent::ResumeForDiversion() |
|
440 { |
|
441 MOZ_ASSERT(mChannel); |
|
442 MOZ_ASSERT(mDivertToListener); |
|
443 if (NS_WARN_IF(!mDivertingFromChild)) { |
|
444 MOZ_ASSERT(mDivertingFromChild, |
|
445 "Cannot ResumeForDiversion if not diverting!"); |
|
446 return NS_ERROR_UNEXPECTED; |
|
447 } |
|
448 |
|
449 if (mSuspendedForDiversion) { |
|
450 nsresult rv = mChannel->Resume(); |
|
451 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
452 FailDiversion(NS_ERROR_UNEXPECTED, true); |
|
453 return rv; |
|
454 } |
|
455 mSuspendedForDiversion = false; |
|
456 } |
|
457 |
|
458 // Delete() will tear down IPDL, but ref from underlying nsFTPChannel will |
|
459 // keep us alive if there's more data to be delivered to listener. |
|
460 if (NS_WARN_IF(NS_FAILED(Delete()))) { |
|
461 FailDiversion(NS_ERROR_UNEXPECTED); |
|
462 return NS_ERROR_UNEXPECTED; |
|
463 } |
|
464 return NS_OK; |
|
465 } |
|
466 |
|
467 void |
|
468 FTPChannelParent::DivertTo(nsIStreamListener *aListener) |
|
469 { |
|
470 MOZ_ASSERT(aListener); |
|
471 if (NS_WARN_IF(!mDivertingFromChild)) { |
|
472 MOZ_ASSERT(mDivertingFromChild, |
|
473 "Cannot DivertTo new listener if diverting is not set!"); |
|
474 return; |
|
475 } |
|
476 |
|
477 if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) { |
|
478 FailDiversion(NS_ERROR_UNEXPECTED); |
|
479 return; |
|
480 } |
|
481 |
|
482 mDivertToListener = aListener; |
|
483 |
|
484 // Call OnStartRequest and SendDivertMessages asynchronously to avoid |
|
485 // reentering client context. |
|
486 NS_DispatchToCurrentThread( |
|
487 NS_NewRunnableMethod(this, &FTPChannelParent::StartDiversion)); |
|
488 return; |
|
489 } |
|
490 |
|
491 void |
|
492 FTPChannelParent::StartDiversion() |
|
493 { |
|
494 if (NS_WARN_IF(!mDivertingFromChild)) { |
|
495 MOZ_ASSERT(mDivertingFromChild, |
|
496 "Cannot StartDiversion if diverting is not set!"); |
|
497 return; |
|
498 } |
|
499 |
|
500 // Fake pending status in case OnStopRequest has already been called. |
|
501 if (mChannel) { |
|
502 mChannel->ForcePending(true); |
|
503 } |
|
504 |
|
505 // Call OnStartRequest for the "DivertTo" listener. |
|
506 nsresult rv = OnStartRequest(mChannel, nullptr); |
|
507 if (NS_FAILED(rv)) { |
|
508 if (mChannel) { |
|
509 mChannel->Cancel(rv); |
|
510 } |
|
511 mStatus = rv; |
|
512 return; |
|
513 } |
|
514 |
|
515 // After OnStartRequest has been called, tell FTPChannelChild to divert the |
|
516 // OnDataAvailables and OnStopRequest to this FTPChannelParent. |
|
517 if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) { |
|
518 FailDiversion(NS_ERROR_UNEXPECTED); |
|
519 return; |
|
520 } |
|
521 } |
|
522 |
|
523 class FTPFailDiversionEvent : public nsRunnable |
|
524 { |
|
525 public: |
|
526 FTPFailDiversionEvent(FTPChannelParent *aChannelParent, |
|
527 nsresult aErrorCode, |
|
528 bool aSkipResume) |
|
529 : mChannelParent(aChannelParent) |
|
530 , mErrorCode(aErrorCode) |
|
531 , mSkipResume(aSkipResume) |
|
532 { |
|
533 MOZ_RELEASE_ASSERT(aChannelParent); |
|
534 MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); |
|
535 } |
|
536 NS_IMETHOD Run() |
|
537 { |
|
538 mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume); |
|
539 return NS_OK; |
|
540 } |
|
541 private: |
|
542 nsRefPtr<FTPChannelParent> mChannelParent; |
|
543 nsresult mErrorCode; |
|
544 bool mSkipResume; |
|
545 }; |
|
546 |
|
547 void |
|
548 FTPChannelParent::FailDiversion(nsresult aErrorCode, |
|
549 bool aSkipResume) |
|
550 { |
|
551 MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); |
|
552 MOZ_RELEASE_ASSERT(mDivertingFromChild); |
|
553 MOZ_RELEASE_ASSERT(mDivertToListener); |
|
554 MOZ_RELEASE_ASSERT(mChannel); |
|
555 |
|
556 NS_DispatchToCurrentThread( |
|
557 new FTPFailDiversionEvent(this, aErrorCode, aSkipResume)); |
|
558 } |
|
559 |
|
560 void |
|
561 FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode, |
|
562 bool aSkipResume) |
|
563 { |
|
564 MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); |
|
565 MOZ_RELEASE_ASSERT(mDivertingFromChild); |
|
566 MOZ_RELEASE_ASSERT(mDivertToListener); |
|
567 MOZ_RELEASE_ASSERT(mChannel); |
|
568 |
|
569 mChannel->Cancel(aErrorCode); |
|
570 |
|
571 mChannel->ForcePending(false); |
|
572 |
|
573 bool isPending = false; |
|
574 nsresult rv = mChannel->IsPending(&isPending); |
|
575 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
|
576 |
|
577 // Resume only we suspended earlier. |
|
578 if (mSuspendedForDiversion) { |
|
579 mChannel->Resume(); |
|
580 } |
|
581 // Channel has already sent OnStartRequest to the child, so ensure that we |
|
582 // call it here if it hasn't already been called. |
|
583 if (!mDivertedOnStartRequest) { |
|
584 mChannel->ForcePending(true); |
|
585 mDivertToListener->OnStartRequest(mChannel, nullptr); |
|
586 mChannel->ForcePending(false); |
|
587 } |
|
588 // If the channel is pending, it will call OnStopRequest itself; otherwise, do |
|
589 // it here. |
|
590 if (!isPending) { |
|
591 mDivertToListener->OnStopRequest(mChannel, nullptr, aErrorCode); |
|
592 } |
|
593 mDivertToListener = nullptr; |
|
594 mChannel = nullptr; |
|
595 |
|
596 if (!mIPCClosed) { |
|
597 unused << SendDeleteSelf(); |
|
598 } |
|
599 } |
|
600 |
|
601 //--------------------- |
|
602 } // namespace net |
|
603 } // namespace mozilla |
|
604 |