netwerk/protocol/http/HttpChannelChild.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:7d1ac5c1f266
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 // HttpLog.h should generally be included first
9 #include "HttpLog.h"
10
11 #include "nsHttp.h"
12 #include "mozilla/unused.h"
13 #include "mozilla/dom/ContentChild.h"
14 #include "mozilla/dom/TabChild.h"
15 #include "mozilla/dom/FileDescriptorSetChild.h"
16 #include "mozilla/net/NeckoChild.h"
17 #include "mozilla/net/HttpChannelChild.h"
18
19 #include "nsStringStream.h"
20 #include "nsHttpHandler.h"
21 #include "nsNetUtil.h"
22 #include "nsSerializationHelper.h"
23 #include "mozilla/Attributes.h"
24 #include "mozilla/ipc/InputStreamUtils.h"
25 #include "mozilla/ipc/URIUtils.h"
26 #include "mozilla/net/ChannelDiverterChild.h"
27 #include "mozilla/net/DNS.h"
28 #include "SerializedLoadContext.h"
29
30 using namespace mozilla::dom;
31 using namespace mozilla::ipc;
32
33 namespace mozilla {
34 namespace net {
35
36 //-----------------------------------------------------------------------------
37 // HttpChannelChild
38 //-----------------------------------------------------------------------------
39
40 HttpChannelChild::HttpChannelChild()
41 : HttpAsyncAborter<HttpChannelChild>(MOZ_THIS_IN_INITIALIZER_LIST())
42 , mIsFromCache(false)
43 , mCacheEntryAvailable(false)
44 , mCacheExpirationTime(nsICache::NO_EXPIRATION_TIME)
45 , mSendResumeAt(false)
46 , mIPCOpen(false)
47 , mKeptAlive(false)
48 , mDivertingToParent(false)
49 , mFlushedForDiversion(false)
50 , mSuspendSent(false)
51 {
52 LOG(("Creating HttpChannelChild @%x\n", this));
53
54 mChannelCreationTime = PR_Now();
55 mChannelCreationTimestamp = TimeStamp::Now();
56 mAsyncOpenTime = TimeStamp::Now();
57 mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(this));
58 }
59
60 HttpChannelChild::~HttpChannelChild()
61 {
62 LOG(("Destroying HttpChannelChild @%x\n", this));
63 }
64
65 //-----------------------------------------------------------------------------
66 // HttpChannelChild::nsISupports
67 //-----------------------------------------------------------------------------
68
69 // Override nsHashPropertyBag's AddRef: we don't need thread-safe refcnt
70 NS_IMPL_ADDREF(HttpChannelChild)
71
72 NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release()
73 {
74 NS_PRECONDITION(0 != mRefCnt, "dup release");
75 NS_ASSERT_OWNINGTHREAD(HttpChannelChild);
76 --mRefCnt;
77 NS_LOG_RELEASE(this, mRefCnt, "HttpChannelChild");
78
79 // Normally we Send_delete in OnStopRequest, but when we need to retain the
80 // remote channel for security info IPDL itself holds 1 reference, so we
81 // Send_delete when refCnt==1. But if !mIPCOpen, then there's nobody to send
82 // to, so we fall through.
83 if (mKeptAlive && mRefCnt == 1 && mIPCOpen) {
84 mKeptAlive = false;
85 // Send_delete calls NeckoChild::DeallocPHttpChannel, which will release
86 // again to refcount==0
87 PHttpChannelChild::Send__delete__(this);
88 return 0;
89 }
90
91 if (mRefCnt == 0) {
92 mRefCnt = 1; /* stabilize */
93 delete this;
94 return 0;
95 }
96 return mRefCnt;
97 }
98
99 NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
100 NS_INTERFACE_MAP_ENTRY(nsIRequest)
101 NS_INTERFACE_MAP_ENTRY(nsIChannel)
102 NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
103 NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
104 NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
105 NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
106 NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
107 NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
108 NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
109 NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
110 NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
111 NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
112 NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
113 NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild)
114 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity, GetAssociatedContentSecurity())
115 NS_INTERFACE_MAP_ENTRY(nsIDivertableChannel)
116 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
117
118 //-----------------------------------------------------------------------------
119 // HttpChannelChild::PHttpChannelChild
120 //-----------------------------------------------------------------------------
121
122 void
123 HttpChannelChild::AddIPDLReference()
124 {
125 MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
126 mIPCOpen = true;
127 AddRef();
128 }
129
130 void
131 HttpChannelChild::ReleaseIPDLReference()
132 {
133 MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
134 mIPCOpen = false;
135 Release();
136 }
137
138 class AssociateApplicationCacheEvent : public ChannelEvent
139 {
140 public:
141 AssociateApplicationCacheEvent(HttpChannelChild* child,
142 const nsCString &groupID,
143 const nsCString &clientID)
144 : mChild(child)
145 , groupID(groupID)
146 , clientID(clientID) {}
147
148 void Run() { mChild->AssociateApplicationCache(groupID, clientID); }
149 private:
150 HttpChannelChild* mChild;
151 nsCString groupID;
152 nsCString clientID;
153 };
154
155 bool
156 HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID,
157 const nsCString &clientID)
158 {
159 if (mEventQ->ShouldEnqueue()) {
160 mEventQ->Enqueue(new AssociateApplicationCacheEvent(this, groupID, clientID));
161 } else {
162 AssociateApplicationCache(groupID, clientID);
163 }
164 return true;
165 }
166
167 void
168 HttpChannelChild::AssociateApplicationCache(const nsCString &groupID,
169 const nsCString &clientID)
170 {
171 nsresult rv;
172 mApplicationCache = do_CreateInstance(NS_APPLICATIONCACHE_CONTRACTID, &rv);
173 if (NS_FAILED(rv))
174 return;
175
176 mLoadedFromApplicationCache = true;
177 mApplicationCache->InitAsHandle(groupID, clientID);
178 }
179
180 class StartRequestEvent : public ChannelEvent
181 {
182 public:
183 StartRequestEvent(HttpChannelChild* child,
184 const nsresult& channelStatus,
185 const nsHttpResponseHead& responseHead,
186 const bool& useResponseHead,
187 const nsHttpHeaderArray& requestHeaders,
188 const bool& isFromCache,
189 const bool& cacheEntryAvailable,
190 const uint32_t& cacheExpirationTime,
191 const nsCString& cachedCharset,
192 const nsCString& securityInfoSerialization,
193 const NetAddr& selfAddr,
194 const NetAddr& peerAddr)
195 : mChild(child)
196 , mChannelStatus(channelStatus)
197 , mResponseHead(responseHead)
198 , mRequestHeaders(requestHeaders)
199 , mUseResponseHead(useResponseHead)
200 , mIsFromCache(isFromCache)
201 , mCacheEntryAvailable(cacheEntryAvailable)
202 , mCacheExpirationTime(cacheExpirationTime)
203 , mCachedCharset(cachedCharset)
204 , mSecurityInfoSerialization(securityInfoSerialization)
205 , mSelfAddr(selfAddr)
206 , mPeerAddr(peerAddr)
207 {}
208
209 void Run()
210 {
211 mChild->OnStartRequest(mChannelStatus, mResponseHead, mUseResponseHead,
212 mRequestHeaders, mIsFromCache, mCacheEntryAvailable,
213 mCacheExpirationTime, mCachedCharset,
214 mSecurityInfoSerialization, mSelfAddr, mPeerAddr);
215 }
216 private:
217 HttpChannelChild* mChild;
218 nsresult mChannelStatus;
219 nsHttpResponseHead mResponseHead;
220 nsHttpHeaderArray mRequestHeaders;
221 bool mUseResponseHead;
222 bool mIsFromCache;
223 bool mCacheEntryAvailable;
224 uint32_t mCacheExpirationTime;
225 nsCString mCachedCharset;
226 nsCString mSecurityInfoSerialization;
227 NetAddr mSelfAddr;
228 NetAddr mPeerAddr;
229 };
230
231 bool
232 HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus,
233 const nsHttpResponseHead& responseHead,
234 const bool& useResponseHead,
235 const nsHttpHeaderArray& requestHeaders,
236 const bool& isFromCache,
237 const bool& cacheEntryAvailable,
238 const uint32_t& cacheExpirationTime,
239 const nsCString& cachedCharset,
240 const nsCString& securityInfoSerialization,
241 const NetAddr& selfAddr,
242 const NetAddr& peerAddr,
243 const int16_t& redirectCount)
244 {
245 // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
246 // stage, as they are set in the listener's OnStartRequest.
247 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
248 "mFlushedForDiversion should be unset before OnStartRequest!");
249 MOZ_RELEASE_ASSERT(!mDivertingToParent,
250 "mDivertingToParent should be unset before OnStartRequest!");
251
252
253 mRedirectCount = redirectCount;
254
255 if (mEventQ->ShouldEnqueue()) {
256 mEventQ->Enqueue(new StartRequestEvent(this, channelStatus, responseHead,
257 useResponseHead, requestHeaders,
258 isFromCache, cacheEntryAvailable,
259 cacheExpirationTime, cachedCharset,
260 securityInfoSerialization, selfAddr,
261 peerAddr));
262 } else {
263 OnStartRequest(channelStatus, responseHead, useResponseHead, requestHeaders,
264 isFromCache, cacheEntryAvailable, cacheExpirationTime,
265 cachedCharset, securityInfoSerialization, selfAddr,
266 peerAddr);
267 }
268 return true;
269 }
270
271 void
272 HttpChannelChild::OnStartRequest(const nsresult& channelStatus,
273 const nsHttpResponseHead& responseHead,
274 const bool& useResponseHead,
275 const nsHttpHeaderArray& requestHeaders,
276 const bool& isFromCache,
277 const bool& cacheEntryAvailable,
278 const uint32_t& cacheExpirationTime,
279 const nsCString& cachedCharset,
280 const nsCString& securityInfoSerialization,
281 const NetAddr& selfAddr,
282 const NetAddr& peerAddr)
283 {
284 LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this));
285
286 // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
287 // stage, as they are set in the listener's OnStartRequest.
288 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
289 "mFlushedForDiversion should be unset before OnStartRequest!");
290 MOZ_RELEASE_ASSERT(!mDivertingToParent,
291 "mDivertingToParent should be unset before OnStartRequest!");
292
293 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
294 mStatus = channelStatus;
295 }
296
297 if (useResponseHead && !mCanceled)
298 mResponseHead = new nsHttpResponseHead(responseHead);
299
300 if (!securityInfoSerialization.IsEmpty()) {
301 NS_DeserializeObject(securityInfoSerialization,
302 getter_AddRefs(mSecurityInfo));
303 }
304
305 mIsFromCache = isFromCache;
306 mCacheEntryAvailable = cacheEntryAvailable;
307 mCacheExpirationTime = cacheExpirationTime;
308 mCachedCharset = cachedCharset;
309
310 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
311
312 // replace our request headers with what actually got sent in the parent
313 mRequestHead.Headers() = requestHeaders;
314
315 // Note: this is where we would notify "http-on-examine-response" observers.
316 // We have deliberately disabled this for child processes (see bug 806753)
317 //
318 // gHttpHandler->OnExamineResponse(this);
319
320 mTracingEnabled = false;
321
322 nsresult rv = mListener->OnStartRequest(this, mListenerContext);
323 if (NS_FAILED(rv)) {
324 Cancel(rv);
325 return;
326 }
327
328 if (mDivertingToParent) {
329 mListener = nullptr;
330 mListenerContext = nullptr;
331 if (mLoadGroup) {
332 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
333 }
334 }
335
336 if (mResponseHead)
337 SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
338
339 rv = ApplyContentConversions();
340 if (NS_FAILED(rv))
341 Cancel(rv);
342
343 mSelfAddr = selfAddr;
344 mPeerAddr = peerAddr;
345 }
346
347 class TransportAndDataEvent : public ChannelEvent
348 {
349 public:
350 TransportAndDataEvent(HttpChannelChild* child,
351 const nsresult& channelStatus,
352 const nsresult& transportStatus,
353 const uint64_t& progress,
354 const uint64_t& progressMax,
355 const nsCString& data,
356 const uint64_t& offset,
357 const uint32_t& count)
358 : mChild(child)
359 , mChannelStatus(channelStatus)
360 , mTransportStatus(transportStatus)
361 , mProgress(progress)
362 , mProgressMax(progressMax)
363 , mData(data)
364 , mOffset(offset)
365 , mCount(count) {}
366
367 void Run()
368 {
369 mChild->OnTransportAndData(mChannelStatus, mTransportStatus, mProgress,
370 mProgressMax, mData, mOffset, mCount);
371 }
372 private:
373 HttpChannelChild* mChild;
374 nsresult mChannelStatus;
375 nsresult mTransportStatus;
376 uint64_t mProgress;
377 uint64_t mProgressMax;
378 nsCString mData;
379 uint64_t mOffset;
380 uint32_t mCount;
381 };
382
383 bool
384 HttpChannelChild::RecvOnTransportAndData(const nsresult& channelStatus,
385 const nsresult& transportStatus,
386 const uint64_t& progress,
387 const uint64_t& progressMax,
388 const nsCString& data,
389 const uint64_t& offset,
390 const uint32_t& count)
391 {
392 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
393 "Should not be receiving any more callbacks from parent!");
394
395 if (mEventQ->ShouldEnqueue()) {
396 mEventQ->Enqueue(new TransportAndDataEvent(this, channelStatus,
397 transportStatus, progress,
398 progressMax, data, offset,
399 count));
400 } else {
401 MOZ_RELEASE_ASSERT(!mDivertingToParent,
402 "ShouldEnqueue when diverting to parent!");
403
404 OnTransportAndData(channelStatus, transportStatus, progress, progressMax,
405 data, offset, count);
406 }
407 return true;
408 }
409
410 void
411 HttpChannelChild::OnTransportAndData(const nsresult& channelStatus,
412 const nsresult& transportStatus,
413 const uint64_t progress,
414 const uint64_t& progressMax,
415 const nsCString& data,
416 const uint64_t& offset,
417 const uint32_t& count)
418 {
419 LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this));
420
421 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
422 mStatus = channelStatus;
423 }
424
425 // For diversion to parent, just SendDivertOnDataAvailable.
426 if (mDivertingToParent) {
427 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
428 "Should not be processing any more callbacks from parent!");
429
430 SendDivertOnDataAvailable(data, offset, count);
431 return;
432 }
433
434 if (mCanceled)
435 return;
436
437 // cache the progress sink so we don't have to query for it each time.
438 if (!mProgressSink)
439 GetCallback(mProgressSink);
440
441 // Hold queue lock throughout all three calls, else we might process a later
442 // necko msg in between them.
443 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
444
445 // block status/progress after Cancel or OnStopRequest has been called,
446 // or if channel has LOAD_BACKGROUND set.
447 // - JDUELL: may not need mStatus/mIsPending checks, given this is always called
448 // during OnDataAvailable, and we've already checked mCanceled. Code
449 // dupe'd from nsHttpChannel
450 if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
451 !(mLoadFlags & LOAD_BACKGROUND))
452 {
453 // OnStatus
454 //
455 MOZ_ASSERT(transportStatus == NS_NET_STATUS_RECEIVING_FROM ||
456 transportStatus == NS_NET_STATUS_READING);
457
458 nsAutoCString host;
459 mURI->GetHost(host);
460 mProgressSink->OnStatus(this, nullptr, transportStatus,
461 NS_ConvertUTF8toUTF16(host).get());
462 // OnProgress
463 //
464 if (progress > 0) {
465 MOZ_ASSERT(progress <= progressMax, "unexpected progress values");
466 mProgressSink->OnProgress(this, nullptr, progress, progressMax);
467 }
468 }
469
470 // OnDataAvailable
471 //
472 // NOTE: the OnDataAvailable contract requires the client to read all the data
473 // in the inputstream. This code relies on that ('data' will go away after
474 // this function). Apparently the previous, non-e10s behavior was to actually
475 // support only reading part of the data, allowing later calls to read the
476 // rest.
477 nsCOMPtr<nsIInputStream> stringStream;
478 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
479 count, NS_ASSIGNMENT_DEPEND);
480 if (NS_FAILED(rv)) {
481 Cancel(rv);
482 return;
483 }
484
485 rv = mListener->OnDataAvailable(this, mListenerContext,
486 stringStream, offset, count);
487 stringStream->Close();
488 if (NS_FAILED(rv)) {
489 Cancel(rv);
490 }
491 }
492
493 class StopRequestEvent : public ChannelEvent
494 {
495 public:
496 StopRequestEvent(HttpChannelChild* child,
497 const nsresult& channelStatus)
498 : mChild(child)
499 , mChannelStatus(channelStatus) {}
500
501 void Run() { mChild->OnStopRequest(mChannelStatus); }
502 private:
503 HttpChannelChild* mChild;
504 nsresult mChannelStatus;
505 };
506
507 bool
508 HttpChannelChild::RecvOnStopRequest(const nsresult& channelStatus)
509 {
510 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
511 "Should not be receiving any more callbacks from parent!");
512
513 if (mEventQ->ShouldEnqueue()) {
514 mEventQ->Enqueue(new StopRequestEvent(this, channelStatus));
515 } else {
516 MOZ_ASSERT(!mDivertingToParent, "ShouldEnqueue when diverting to parent!");
517
518 OnStopRequest(channelStatus);
519 }
520 return true;
521 }
522
523 void
524 HttpChannelChild::OnStopRequest(const nsresult& channelStatus)
525 {
526 LOG(("HttpChannelChild::OnStopRequest [this=%p status=%x]\n",
527 this, channelStatus));
528
529 if (mDivertingToParent) {
530 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
531 "Should not be processing any more callbacks from parent!");
532
533 SendDivertOnStopRequest(channelStatus);
534 return;
535 }
536
537 mIsPending = false;
538
539 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
540 mStatus = channelStatus;
541 }
542
543 { // We must flush the queue before we Send__delete__
544 // (although we really shouldn't receive any msgs after OnStop),
545 // so make sure this goes out of scope before then.
546 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
547
548 mListener->OnStopRequest(this, mListenerContext, mStatus);
549
550 mListener = 0;
551 mListenerContext = 0;
552 mCacheEntryAvailable = false;
553 if (mLoadGroup)
554 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
555 }
556
557 if (mLoadFlags & LOAD_DOCUMENT_URI) {
558 // Keep IPDL channel open, but only for updating security info.
559 mKeptAlive = true;
560 SendDocumentChannelCleanup();
561 } else {
562 // This calls NeckoChild::DeallocPHttpChannelChild(), which deletes |this| if IPDL
563 // holds the last reference. Don't rely on |this| existing after here.
564 PHttpChannelChild::Send__delete__(this);
565 }
566 }
567
568 class ProgressEvent : public ChannelEvent
569 {
570 public:
571 ProgressEvent(HttpChannelChild* child,
572 const uint64_t& progress,
573 const uint64_t& progressMax)
574 : mChild(child)
575 , mProgress(progress)
576 , mProgressMax(progressMax) {}
577
578 void Run() { mChild->OnProgress(mProgress, mProgressMax); }
579 private:
580 HttpChannelChild* mChild;
581 uint64_t mProgress, mProgressMax;
582 };
583
584 bool
585 HttpChannelChild::RecvOnProgress(const uint64_t& progress,
586 const uint64_t& progressMax)
587 {
588 if (mEventQ->ShouldEnqueue()) {
589 mEventQ->Enqueue(new ProgressEvent(this, progress, progressMax));
590 } else {
591 OnProgress(progress, progressMax);
592 }
593 return true;
594 }
595
596 void
597 HttpChannelChild::OnProgress(const uint64_t& progress,
598 const uint64_t& progressMax)
599 {
600 LOG(("HttpChannelChild::OnProgress [this=%p progress=%llu/%llu]\n",
601 this, progress, progressMax));
602
603 if (mCanceled)
604 return;
605
606 // cache the progress sink so we don't have to query for it each time.
607 if (!mProgressSink)
608 GetCallback(mProgressSink);
609
610 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
611
612 // block socket status event after Cancel or OnStopRequest has been called,
613 // or if channel has LOAD_BACKGROUND set
614 if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
615 !(mLoadFlags & LOAD_BACKGROUND))
616 {
617 if (progress > 0) {
618 MOZ_ASSERT(progress <= progressMax, "unexpected progress values");
619 mProgressSink->OnProgress(this, nullptr, progress, progressMax);
620 }
621 }
622 }
623
624 class StatusEvent : public ChannelEvent
625 {
626 public:
627 StatusEvent(HttpChannelChild* child,
628 const nsresult& status)
629 : mChild(child)
630 , mStatus(status) {}
631
632 void Run() { mChild->OnStatus(mStatus); }
633 private:
634 HttpChannelChild* mChild;
635 nsresult mStatus;
636 };
637
638 bool
639 HttpChannelChild::RecvOnStatus(const nsresult& status)
640 {
641 if (mEventQ->ShouldEnqueue()) {
642 mEventQ->Enqueue(new StatusEvent(this, status));
643 } else {
644 OnStatus(status);
645 }
646 return true;
647 }
648
649 void
650 HttpChannelChild::OnStatus(const nsresult& status)
651 {
652 LOG(("HttpChannelChild::OnStatus [this=%p status=%x]\n", this, status));
653
654 if (mCanceled)
655 return;
656
657 // cache the progress sink so we don't have to query for it each time.
658 if (!mProgressSink)
659 GetCallback(mProgressSink);
660
661 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
662
663 // block socket status event after Cancel or OnStopRequest has been called,
664 // or if channel has LOAD_BACKGROUND set
665 if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
666 !(mLoadFlags & LOAD_BACKGROUND))
667 {
668 nsAutoCString host;
669 mURI->GetHost(host);
670 mProgressSink->OnStatus(this, nullptr, status,
671 NS_ConvertUTF8toUTF16(host).get());
672 }
673 }
674
675 class FailedAsyncOpenEvent : public ChannelEvent
676 {
677 public:
678 FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status)
679 : mChild(child)
680 , mStatus(status) {}
681
682 void Run() { mChild->FailedAsyncOpen(mStatus); }
683 private:
684 HttpChannelChild* mChild;
685 nsresult mStatus;
686 };
687
688 bool
689 HttpChannelChild::RecvFailedAsyncOpen(const nsresult& status)
690 {
691 if (mEventQ->ShouldEnqueue()) {
692 mEventQ->Enqueue(new FailedAsyncOpenEvent(this, status));
693 } else {
694 FailedAsyncOpen(status);
695 }
696 return true;
697 }
698
699 // We need to have an implementation of this function just so that we can keep
700 // all references to mCallOnResume of type HttpChannelChild: it's not OK in C++
701 // to set a member function ptr to a base class function.
702 void
703 HttpChannelChild::HandleAsyncAbort()
704 {
705 HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
706 }
707
708 void
709 HttpChannelChild::FailedAsyncOpen(const nsresult& status)
710 {
711 LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%x]\n", this, status));
712
713 mStatus = status;
714 mIsPending = false;
715 // We're already being called from IPDL, therefore already "async"
716 HandleAsyncAbort();
717 }
718
719 void
720 HttpChannelChild::DoNotifyListenerCleanup()
721 {
722 if (mIPCOpen)
723 PHttpChannelChild::Send__delete__(this);
724 }
725
726 class DeleteSelfEvent : public ChannelEvent
727 {
728 public:
729 DeleteSelfEvent(HttpChannelChild* child) : mChild(child) {}
730 void Run() { mChild->DeleteSelf(); }
731 private:
732 HttpChannelChild* mChild;
733 };
734
735 bool
736 HttpChannelChild::RecvDeleteSelf()
737 {
738 if (mEventQ->ShouldEnqueue()) {
739 mEventQ->Enqueue(new DeleteSelfEvent(this));
740 } else {
741 DeleteSelf();
742 }
743 return true;
744 }
745
746 void
747 HttpChannelChild::DeleteSelf()
748 {
749 Send__delete__(this);
750 }
751
752 class Redirect1Event : public ChannelEvent
753 {
754 public:
755 Redirect1Event(HttpChannelChild* child,
756 const uint32_t& newChannelId,
757 const URIParams& newURI,
758 const uint32_t& redirectFlags,
759 const nsHttpResponseHead& responseHead)
760 : mChild(child)
761 , mNewChannelId(newChannelId)
762 , mNewURI(newURI)
763 , mRedirectFlags(redirectFlags)
764 , mResponseHead(responseHead) {}
765
766 void Run()
767 {
768 mChild->Redirect1Begin(mNewChannelId, mNewURI, mRedirectFlags,
769 mResponseHead);
770 }
771 private:
772 HttpChannelChild* mChild;
773 uint32_t mNewChannelId;
774 URIParams mNewURI;
775 uint32_t mRedirectFlags;
776 nsHttpResponseHead mResponseHead;
777 };
778
779 bool
780 HttpChannelChild::RecvRedirect1Begin(const uint32_t& newChannelId,
781 const URIParams& newUri,
782 const uint32_t& redirectFlags,
783 const nsHttpResponseHead& responseHead)
784 {
785 if (mEventQ->ShouldEnqueue()) {
786 mEventQ->Enqueue(new Redirect1Event(this, newChannelId, newUri,
787 redirectFlags, responseHead));
788 } else {
789 Redirect1Begin(newChannelId, newUri, redirectFlags, responseHead);
790 }
791 return true;
792 }
793
794 void
795 HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
796 const URIParams& newUri,
797 const uint32_t& redirectFlags,
798 const nsHttpResponseHead& responseHead)
799 {
800 nsresult rv;
801
802 nsCOMPtr<nsIIOService> ioService;
803 rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
804 if (NS_FAILED(rv)) {
805 // Veto redirect. nsHttpChannel decides to cancel or continue.
806 OnRedirectVerifyCallback(rv);
807 return;
808 }
809
810 nsCOMPtr<nsIURI> uri = DeserializeURI(newUri);
811
812 nsCOMPtr<nsIChannel> newChannel;
813 rv = ioService->NewChannelFromURI(uri, getter_AddRefs(newChannel));
814 if (NS_FAILED(rv)) {
815 // Veto redirect. nsHttpChannel decides to cancel or continue.
816 OnRedirectVerifyCallback(rv);
817 return;
818 }
819
820 // We won't get OnStartRequest, set cookies here.
821 mResponseHead = new nsHttpResponseHead(responseHead);
822 SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
823
824 bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET(mResponseHead->Status(),
825 mRequestHead.ParsedMethod());
826
827 rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET);
828 if (NS_FAILED(rv)) {
829 // Veto redirect. nsHttpChannel decides to cancel or continue.
830 OnRedirectVerifyCallback(rv);
831 return;
832 }
833
834 mRedirectChannelChild = do_QueryInterface(newChannel);
835 if (mRedirectChannelChild) {
836 mRedirectChannelChild->ConnectParent(newChannelId);
837 rv = gHttpHandler->AsyncOnChannelRedirect(this,
838 newChannel,
839 redirectFlags);
840 } else {
841 LOG((" redirecting to a protocol that doesn't implement"
842 " nsIChildChannel"));
843 rv = NS_ERROR_FAILURE;
844 }
845
846 if (NS_FAILED(rv))
847 OnRedirectVerifyCallback(rv);
848 }
849
850 class Redirect3Event : public ChannelEvent
851 {
852 public:
853 Redirect3Event(HttpChannelChild* child) : mChild(child) {}
854 void Run() { mChild->Redirect3Complete(); }
855 private:
856 HttpChannelChild* mChild;
857 };
858
859 bool
860 HttpChannelChild::RecvRedirect3Complete()
861 {
862 if (mEventQ->ShouldEnqueue()) {
863 mEventQ->Enqueue(new Redirect3Event(this));
864 } else {
865 Redirect3Complete();
866 }
867 return true;
868 }
869
870 class HttpFlushedForDiversionEvent : public ChannelEvent
871 {
872 public:
873 HttpFlushedForDiversionEvent(HttpChannelChild* aChild)
874 : mChild(aChild)
875 {
876 MOZ_RELEASE_ASSERT(aChild);
877 }
878
879 void Run()
880 {
881 mChild->FlushedForDiversion();
882 }
883 private:
884 HttpChannelChild* mChild;
885 };
886
887 bool
888 HttpChannelChild::RecvFlushedForDiversion()
889 {
890 MOZ_RELEASE_ASSERT(mDivertingToParent);
891 MOZ_RELEASE_ASSERT(mEventQ->ShouldEnqueue());
892
893 mEventQ->Enqueue(new HttpFlushedForDiversionEvent(this));
894
895 return true;
896 }
897
898 void
899 HttpChannelChild::FlushedForDiversion()
900 {
901 MOZ_RELEASE_ASSERT(mDivertingToParent);
902
903 // Once this is set, it should not be unset before HttpChannelChild is taken
904 // down. After it is set, no OnStart/OnData/OnStop callbacks should be
905 // received from the parent channel, nor dequeued from the ChannelEventQueue.
906 mFlushedForDiversion = true;
907
908 SendDivertComplete();
909 }
910
911 bool
912 HttpChannelChild::RecvDivertMessages()
913 {
914 MOZ_RELEASE_ASSERT(mDivertingToParent);
915 MOZ_RELEASE_ASSERT(mSuspendCount > 0);
916
917 // DivertTo() has been called on parent, so we can now start sending queued
918 // IPDL messages back to parent listener.
919 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(Resume()));
920
921 return true;
922 }
923
924 void
925 HttpChannelChild::Redirect3Complete()
926 {
927 nsresult rv = NS_OK;
928
929 // Chrome channel has been AsyncOpen'd. Reflect this in child.
930 if (mRedirectChannelChild)
931 rv = mRedirectChannelChild->CompleteRedirectSetup(mListener,
932 mListenerContext);
933
934 // Redirecting to new channel: shut this down and init new channel
935 if (mLoadGroup)
936 mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED);
937
938 if (NS_FAILED(rv))
939 NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
940
941 // Release ref to new channel.
942 mRedirectChannelChild = nullptr;
943 }
944
945 //-----------------------------------------------------------------------------
946 // HttpChannelChild::nsIChildChannel
947 //-----------------------------------------------------------------------------
948
949 NS_IMETHODIMP
950 HttpChannelChild::ConnectParent(uint32_t id)
951 {
952 mozilla::dom::TabChild* tabChild = nullptr;
953 nsCOMPtr<nsITabChild> iTabChild;
954 GetCallback(iTabChild);
955 if (iTabChild) {
956 tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
957 }
958 if (MissingRequiredTabChild(tabChild, "http")) {
959 return NS_ERROR_ILLEGAL_VALUE;
960 }
961
962 // The socket transport in the chrome process now holds a logical ref to us
963 // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
964 AddIPDLReference();
965
966 HttpChannelConnectArgs connectArgs(id);
967 if (!gNeckoChild->
968 SendPHttpChannelConstructor(this, tabChild,
969 IPC::SerializedLoadContext(this),
970 connectArgs)) {
971 return NS_ERROR_FAILURE;
972 }
973
974 return NS_OK;
975 }
976
977 NS_IMETHODIMP
978 HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
979 nsISupports *aContext)
980 {
981 LOG(("HttpChannelChild::FinishRedirectSetup [this=%p]\n", this));
982
983 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
984 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
985
986 /*
987 * No need to check for cancel: we don't get here if nsHttpChannel canceled
988 * before AsyncOpen(); if it's canceled after that, OnStart/Stop will just
989 * get called with error code as usual. So just setup mListener and make the
990 * channel reflect AsyncOpen'ed state.
991 */
992
993 mIsPending = true;
994 mWasOpened = true;
995 mListener = listener;
996 mListenerContext = aContext;
997
998 // add ourselves to the load group.
999 if (mLoadGroup)
1000 mLoadGroup->AddRequest(this, nullptr);
1001
1002 // We already have an open IPDL connection to the parent. If on-modify-request
1003 // listeners or load group observers canceled us, let the parent handle it
1004 // and send it back to us naturally.
1005 return NS_OK;
1006 }
1007
1008 //-----------------------------------------------------------------------------
1009 // HttpChannelChild::nsIAsyncVerifyRedirectCallback
1010 //-----------------------------------------------------------------------------
1011
1012 NS_IMETHODIMP
1013 HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
1014 {
1015 OptionalURIParams redirectURI;
1016 nsCOMPtr<nsIHttpChannel> newHttpChannel =
1017 do_QueryInterface(mRedirectChannelChild);
1018
1019 if (newHttpChannel) {
1020 // Must not be called until after redirect observers called.
1021 newHttpChannel->SetOriginalURI(mOriginalURI);
1022 }
1023
1024 RequestHeaderTuples emptyHeaders;
1025 RequestHeaderTuples* headerTuples = &emptyHeaders;
1026
1027 nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild =
1028 do_QueryInterface(mRedirectChannelChild);
1029 if (newHttpChannelChild && NS_SUCCEEDED(result)) {
1030 newHttpChannelChild->AddCookiesToRequest();
1031 newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples);
1032 }
1033
1034 /* If the redirect was canceled, bypass OMR and send an empty API
1035 * redirect URI */
1036 SerializeURI(nullptr, redirectURI);
1037
1038 if (NS_SUCCEEDED(result)) {
1039 // Note: this is where we would notify "http-on-modify-response" observers.
1040 // We have deliberately disabled this for child processes (see bug 806753)
1041 //
1042 // After we verify redirect, nsHttpChannel may hit the network: must give
1043 // "http-on-modify-request" observers the chance to cancel before that.
1044 //base->CallOnModifyRequestObservers();
1045
1046 nsCOMPtr<nsIHttpChannelInternal> newHttpChannelInternal =
1047 do_QueryInterface(mRedirectChannelChild);
1048 if (newHttpChannelInternal) {
1049 nsCOMPtr<nsIURI> apiRedirectURI;
1050 nsresult rv = newHttpChannelInternal->GetApiRedirectToURI(
1051 getter_AddRefs(apiRedirectURI));
1052 if (NS_SUCCEEDED(rv) && apiRedirectURI) {
1053 /* If there was an API redirect of this channel, we need to send it
1054 * up here, since it can't be sent via SendAsyncOpen. */
1055 SerializeURI(apiRedirectURI, redirectURI);
1056 }
1057 }
1058 }
1059
1060 if (mIPCOpen)
1061 SendRedirect2Verify(result, *headerTuples, redirectURI);
1062
1063 return NS_OK;
1064 }
1065
1066 //-----------------------------------------------------------------------------
1067 // HttpChannelChild::nsIRequest
1068 //-----------------------------------------------------------------------------
1069
1070 NS_IMETHODIMP
1071 HttpChannelChild::Cancel(nsresult status)
1072 {
1073 MOZ_ASSERT(NS_IsMainThread());
1074
1075 if (!mCanceled) {
1076 // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen
1077 // is responsible for cleaning up.
1078 mCanceled = true;
1079 mStatus = status;
1080 if (RemoteChannelExists())
1081 SendCancel(status);
1082 }
1083 return NS_OK;
1084 }
1085
1086 NS_IMETHODIMP
1087 HttpChannelChild::Suspend()
1088 {
1089 NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE);
1090
1091 // SendSuspend only once, when suspend goes from 0 to 1.
1092 // Don't SendSuspend at all if we're diverting callbacks to the parent;
1093 // suspend will be called at the correct time in the parent itself.
1094 if (!mSuspendCount++ && !mDivertingToParent) {
1095 SendSuspend();
1096 mSuspendSent = true;
1097 }
1098 mEventQ->Suspend();
1099
1100 return NS_OK;
1101 }
1102
1103 NS_IMETHODIMP
1104 HttpChannelChild::Resume()
1105 {
1106 NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE);
1107 NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
1108
1109 nsresult rv = NS_OK;
1110
1111 // SendResume only once, when suspend count drops to 0.
1112 // Don't SendResume at all if we're diverting callbacks to the parent (unless
1113 // suspend was sent earlier); otherwise, resume will be called at the correct
1114 // time in the parent itself.
1115 if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
1116 SendResume();
1117 if (mCallOnResume) {
1118 AsyncCall(mCallOnResume);
1119 mCallOnResume = nullptr;
1120 }
1121 }
1122 mEventQ->Resume();
1123
1124 return rv;
1125 }
1126
1127 //-----------------------------------------------------------------------------
1128 // HttpChannelChild::nsIChannel
1129 //-----------------------------------------------------------------------------
1130
1131 NS_IMETHODIMP
1132 HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
1133 {
1134 NS_ENSURE_ARG_POINTER(aSecurityInfo);
1135 NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
1136 return NS_OK;
1137 }
1138
1139 NS_IMETHODIMP
1140 HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
1141 {
1142 LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get()));
1143
1144 if (mCanceled)
1145 return mStatus;
1146
1147 NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
1148 NS_ENSURE_ARG_POINTER(listener);
1149 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
1150 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
1151
1152 mAsyncOpenTime = TimeStamp::Now();
1153
1154 // Port checked in parent, but duplicate here so we can return with error
1155 // immediately
1156 nsresult rv;
1157 rv = NS_CheckPortSafety(mURI);
1158 if (NS_FAILED(rv))
1159 return rv;
1160
1161 const char *cookieHeader = mRequestHead.PeekHeader(nsHttp::Cookie);
1162 if (cookieHeader) {
1163 mUserSetCookieHeader = cookieHeader;
1164 }
1165
1166 AddCookiesToRequest();
1167
1168 //
1169 // NOTE: From now on we must return NS_OK; all errors must be handled via
1170 // OnStart/OnStopRequest
1171 //
1172
1173 // Note: this is where we would notify "http-on-modify-request" observers.
1174 // We have deliberately disabled this for child processes (see bug 806753)
1175 //
1176 // notify "http-on-modify-request" observers
1177 //CallOnModifyRequestObservers();
1178
1179 mIsPending = true;
1180 mWasOpened = true;
1181 mListener = listener;
1182 mListenerContext = aContext;
1183
1184 // add ourselves to the load group.
1185 if (mLoadGroup)
1186 mLoadGroup->AddRequest(this, nullptr);
1187
1188 if (mCanceled) {
1189 // We may have been canceled already, either by on-modify-request
1190 // listeners or by load group observers; in that case, don't create IPDL
1191 // connection. See nsHttpChannel::AsyncOpen().
1192 AsyncAbort(mStatus);
1193 return NS_OK;
1194 }
1195
1196 nsCString appCacheClientId;
1197 if (mInheritApplicationCache) {
1198 // Pick up an application cache from the notification
1199 // callbacks if available
1200 nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
1201 GetCallback(appCacheContainer);
1202
1203 if (appCacheContainer) {
1204 nsCOMPtr<nsIApplicationCache> appCache;
1205 rv = appCacheContainer->GetApplicationCache(getter_AddRefs(appCache));
1206 if (NS_SUCCEEDED(rv) && appCache) {
1207 appCache->GetClientID(appCacheClientId);
1208 }
1209 }
1210 }
1211
1212 //
1213 // Send request to the chrome process...
1214 //
1215
1216 mozilla::dom::TabChild* tabChild = nullptr;
1217 nsCOMPtr<nsITabChild> iTabChild;
1218 GetCallback(iTabChild);
1219 if (iTabChild) {
1220 tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
1221 }
1222 if (MissingRequiredTabChild(tabChild, "http")) {
1223 return NS_ERROR_ILLEGAL_VALUE;
1224 }
1225
1226 HttpChannelOpenArgs openArgs;
1227 // No access to HttpChannelOpenArgs members, but they each have a
1228 // function with the struct name that returns a ref.
1229 SerializeURI(mURI, openArgs.uri());
1230 SerializeURI(mOriginalURI, openArgs.original());
1231 SerializeURI(mDocumentURI, openArgs.doc());
1232 SerializeURI(mReferrer, openArgs.referrer());
1233 SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
1234 openArgs.loadFlags() = mLoadFlags;
1235 openArgs.requestHeaders() = mClientSetRequestHeaders;
1236 openArgs.requestMethod() = mRequestHead.Method();
1237
1238 nsTArray<mozilla::ipc::FileDescriptor> fds;
1239 SerializeInputStream(mUploadStream, openArgs.uploadStream(), fds);
1240
1241 PFileDescriptorSetChild* fdSet = nullptr;
1242 if (!fds.IsEmpty()) {
1243 MOZ_ASSERT(gNeckoChild->Manager());
1244
1245 fdSet = gNeckoChild->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
1246 for (uint32_t i = 1; i < fds.Length(); ++i) {
1247 unused << fdSet->SendAddFileDescriptor(fds[i]);
1248 }
1249 }
1250
1251 OptionalFileDescriptorSet optionalFDs;
1252 if (fdSet) {
1253 optionalFDs = fdSet;
1254 } else {
1255 optionalFDs = mozilla::void_t();
1256 }
1257
1258 openArgs.fds() = optionalFDs;
1259
1260 openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
1261 openArgs.priority() = mPriority;
1262 openArgs.redirectionLimit() = mRedirectionLimit;
1263 openArgs.allowPipelining() = mAllowPipelining;
1264 openArgs.forceAllowThirdPartyCookie() = mForceAllowThirdPartyCookie;
1265 openArgs.resumeAt() = mSendResumeAt;
1266 openArgs.startPos() = mStartPos;
1267 openArgs.entityID() = mEntityID;
1268 openArgs.chooseApplicationCache() = mChooseApplicationCache;
1269 openArgs.appCacheClientID() = appCacheClientId;
1270 openArgs.allowSpdy() = mAllowSpdy;
1271
1272 // The socket transport in the chrome process now holds a logical ref to us
1273 // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
1274 AddIPDLReference();
1275
1276 gNeckoChild->SendPHttpChannelConstructor(this, tabChild,
1277 IPC::SerializedLoadContext(this),
1278 openArgs);
1279
1280 if (fdSet) {
1281 FileDescriptorSetChild* fdSetActor =
1282 static_cast<FileDescriptorSetChild*>(fdSet);
1283
1284 fdSetActor->ForgetFileDescriptors(fds);
1285 }
1286
1287 return NS_OK;
1288 }
1289
1290 //-----------------------------------------------------------------------------
1291 // HttpChannelChild::nsIHttpChannel
1292 //-----------------------------------------------------------------------------
1293
1294 NS_IMETHODIMP
1295 HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
1296 const nsACString& aValue,
1297 bool aMerge)
1298 {
1299 nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
1300 if (NS_FAILED(rv))
1301 return rv;
1302
1303 RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
1304 if (!tuple)
1305 return NS_ERROR_OUT_OF_MEMORY;
1306
1307 tuple->mHeader = aHeader;
1308 tuple->mValue = aValue;
1309 tuple->mMerge = aMerge;
1310 return NS_OK;
1311 }
1312
1313 NS_IMETHODIMP
1314 HttpChannelChild::RedirectTo(nsIURI *newURI)
1315 {
1316 // disabled until/unless addons run in child or something else needs this
1317 return NS_ERROR_NOT_IMPLEMENTED;
1318 }
1319
1320 //-----------------------------------------------------------------------------
1321 // HttpChannelChild::nsIHttpChannelInternal
1322 //-----------------------------------------------------------------------------
1323
1324 NS_IMETHODIMP
1325 HttpChannelChild::SetupFallbackChannel(const char *aFallbackKey)
1326 {
1327 DROP_DEAD();
1328 }
1329
1330 // The next four _should_ be implemented, but we need to figure out how
1331 // to transfer the data from the chrome process first.
1332
1333 NS_IMETHODIMP
1334 HttpChannelChild::GetRemoteAddress(nsACString & _result)
1335 {
1336 return NS_ERROR_NOT_AVAILABLE;
1337 }
1338
1339 NS_IMETHODIMP
1340 HttpChannelChild::GetRemotePort(int32_t * _result)
1341 {
1342 NS_ENSURE_ARG_POINTER(_result);
1343 return NS_ERROR_NOT_AVAILABLE;
1344 }
1345
1346 NS_IMETHODIMP
1347 HttpChannelChild::GetLocalAddress(nsACString & _result)
1348 {
1349 return NS_ERROR_NOT_AVAILABLE;
1350 }
1351
1352 NS_IMETHODIMP
1353 HttpChannelChild::GetLocalPort(int32_t * _result)
1354 {
1355 NS_ENSURE_ARG_POINTER(_result);
1356 return NS_ERROR_NOT_AVAILABLE;
1357 }
1358
1359
1360 //-----------------------------------------------------------------------------
1361 // HttpChannelChild::nsICacheInfoChannel
1362 //-----------------------------------------------------------------------------
1363
1364 NS_IMETHODIMP
1365 HttpChannelChild::GetCacheTokenExpirationTime(uint32_t *_retval)
1366 {
1367 NS_ENSURE_ARG_POINTER(_retval);
1368 if (!mCacheEntryAvailable)
1369 return NS_ERROR_NOT_AVAILABLE;
1370
1371 *_retval = mCacheExpirationTime;
1372 return NS_OK;
1373 }
1374
1375 NS_IMETHODIMP
1376 HttpChannelChild::GetCacheTokenCachedCharset(nsACString &_retval)
1377 {
1378 if (!mCacheEntryAvailable)
1379 return NS_ERROR_NOT_AVAILABLE;
1380
1381 _retval = mCachedCharset;
1382 return NS_OK;
1383 }
1384 NS_IMETHODIMP
1385 HttpChannelChild::SetCacheTokenCachedCharset(const nsACString &aCharset)
1386 {
1387 if (!mCacheEntryAvailable || !RemoteChannelExists())
1388 return NS_ERROR_NOT_AVAILABLE;
1389
1390 mCachedCharset = aCharset;
1391 if (!SendSetCacheTokenCachedCharset(PromiseFlatCString(aCharset))) {
1392 return NS_ERROR_FAILURE;
1393 }
1394 return NS_OK;
1395 }
1396
1397 NS_IMETHODIMP
1398 HttpChannelChild::IsFromCache(bool *value)
1399 {
1400 if (!mIsPending)
1401 return NS_ERROR_NOT_AVAILABLE;
1402
1403 *value = mIsFromCache;
1404 return NS_OK;
1405 }
1406
1407 //-----------------------------------------------------------------------------
1408 // HttpChannelChild::nsIResumableChannel
1409 //-----------------------------------------------------------------------------
1410
1411 NS_IMETHODIMP
1412 HttpChannelChild::ResumeAt(uint64_t startPos, const nsACString& entityID)
1413 {
1414 ENSURE_CALLED_BEFORE_CONNECT();
1415 mStartPos = startPos;
1416 mEntityID = entityID;
1417 mSendResumeAt = true;
1418 return NS_OK;
1419 }
1420
1421 // GetEntityID is shared in HttpBaseChannel
1422
1423 //-----------------------------------------------------------------------------
1424 // HttpChannelChild::nsISupportsPriority
1425 //-----------------------------------------------------------------------------
1426
1427 NS_IMETHODIMP
1428 HttpChannelChild::SetPriority(int32_t aPriority)
1429 {
1430 int16_t newValue = clamped<int32_t>(aPriority, INT16_MIN, INT16_MAX);
1431 if (mPriority == newValue)
1432 return NS_OK;
1433 mPriority = newValue;
1434 if (RemoteChannelExists())
1435 SendSetPriority(mPriority);
1436 return NS_OK;
1437 }
1438
1439 //-----------------------------------------------------------------------------
1440 // HttpChannelChild::nsIProxiedChannel
1441 //-----------------------------------------------------------------------------
1442
1443 NS_IMETHODIMP
1444 HttpChannelChild::GetProxyInfo(nsIProxyInfo **aProxyInfo)
1445 {
1446 DROP_DEAD();
1447 }
1448
1449 //-----------------------------------------------------------------------------
1450 // HttpChannelChild::nsIApplicationCacheContainer
1451 //-----------------------------------------------------------------------------
1452
1453 NS_IMETHODIMP
1454 HttpChannelChild::GetApplicationCache(nsIApplicationCache **aApplicationCache)
1455 {
1456 NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
1457 return NS_OK;
1458 }
1459 NS_IMETHODIMP
1460 HttpChannelChild::SetApplicationCache(nsIApplicationCache *aApplicationCache)
1461 {
1462 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
1463
1464 mApplicationCache = aApplicationCache;
1465 return NS_OK;
1466 }
1467
1468 //-----------------------------------------------------------------------------
1469 // HttpChannelChild::nsIApplicationCacheChannel
1470 //-----------------------------------------------------------------------------
1471
1472 NS_IMETHODIMP
1473 HttpChannelChild::GetApplicationCacheForWrite(nsIApplicationCache **aApplicationCache)
1474 {
1475 *aApplicationCache = nullptr;
1476 return NS_OK;
1477 }
1478 NS_IMETHODIMP
1479 HttpChannelChild::SetApplicationCacheForWrite(nsIApplicationCache *aApplicationCache)
1480 {
1481 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
1482
1483 // Child channels are not intended to be used for cache writes
1484 return NS_ERROR_NOT_IMPLEMENTED;
1485 }
1486
1487 NS_IMETHODIMP
1488 HttpChannelChild::GetLoadedFromApplicationCache(bool *aLoadedFromApplicationCache)
1489 {
1490 *aLoadedFromApplicationCache = mLoadedFromApplicationCache;
1491 return NS_OK;
1492 }
1493
1494 NS_IMETHODIMP
1495 HttpChannelChild::GetInheritApplicationCache(bool *aInherit)
1496 {
1497 *aInherit = mInheritApplicationCache;
1498 return NS_OK;
1499 }
1500 NS_IMETHODIMP
1501 HttpChannelChild::SetInheritApplicationCache(bool aInherit)
1502 {
1503 mInheritApplicationCache = aInherit;
1504 return NS_OK;
1505 }
1506
1507 NS_IMETHODIMP
1508 HttpChannelChild::GetChooseApplicationCache(bool *aChoose)
1509 {
1510 *aChoose = mChooseApplicationCache;
1511 return NS_OK;
1512 }
1513
1514 NS_IMETHODIMP
1515 HttpChannelChild::SetChooseApplicationCache(bool aChoose)
1516 {
1517 mChooseApplicationCache = aChoose;
1518 return NS_OK;
1519 }
1520
1521 NS_IMETHODIMP
1522 HttpChannelChild::MarkOfflineCacheEntryAsForeign()
1523 {
1524 SendMarkOfflineCacheEntryAsForeign();
1525 return NS_OK;
1526 }
1527
1528 //-----------------------------------------------------------------------------
1529 // HttpChannelChild::nsIAssociatedContentSecurity
1530 //-----------------------------------------------------------------------------
1531
1532 bool
1533 HttpChannelChild::GetAssociatedContentSecurity(
1534 nsIAssociatedContentSecurity** _result)
1535 {
1536 if (!mSecurityInfo)
1537 return false;
1538
1539 nsCOMPtr<nsIAssociatedContentSecurity> assoc =
1540 do_QueryInterface(mSecurityInfo);
1541 if (!assoc)
1542 return false;
1543
1544 if (_result)
1545 assoc.forget(_result);
1546 return true;
1547 }
1548
1549 /* attribute unsigned long countSubRequestsBrokenSecurity; */
1550 NS_IMETHODIMP
1551 HttpChannelChild::GetCountSubRequestsBrokenSecurity(
1552 int32_t *aSubRequestsBrokenSecurity)
1553 {
1554 nsCOMPtr<nsIAssociatedContentSecurity> assoc;
1555 if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
1556 return NS_OK;
1557
1558 return assoc->GetCountSubRequestsBrokenSecurity(aSubRequestsBrokenSecurity);
1559 }
1560 NS_IMETHODIMP
1561 HttpChannelChild::SetCountSubRequestsBrokenSecurity(
1562 int32_t aSubRequestsBrokenSecurity)
1563 {
1564 nsCOMPtr<nsIAssociatedContentSecurity> assoc;
1565 if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
1566 return NS_OK;
1567
1568 return assoc->SetCountSubRequestsBrokenSecurity(aSubRequestsBrokenSecurity);
1569 }
1570
1571 /* attribute unsigned long countSubRequestsNoSecurity; */
1572 NS_IMETHODIMP
1573 HttpChannelChild::GetCountSubRequestsNoSecurity(int32_t *aSubRequestsNoSecurity)
1574 {
1575 nsCOMPtr<nsIAssociatedContentSecurity> assoc;
1576 if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
1577 return NS_OK;
1578
1579 return assoc->GetCountSubRequestsNoSecurity(aSubRequestsNoSecurity);
1580 }
1581 NS_IMETHODIMP
1582 HttpChannelChild::SetCountSubRequestsNoSecurity(int32_t aSubRequestsNoSecurity)
1583 {
1584 nsCOMPtr<nsIAssociatedContentSecurity> assoc;
1585 if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
1586 return NS_OK;
1587
1588 return assoc->SetCountSubRequestsNoSecurity(aSubRequestsNoSecurity);
1589 }
1590
1591 NS_IMETHODIMP
1592 HttpChannelChild::Flush()
1593 {
1594 nsCOMPtr<nsIAssociatedContentSecurity> assoc;
1595 if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
1596 return NS_OK;
1597
1598 nsresult rv;
1599 int32_t broken, no;
1600
1601 rv = assoc->GetCountSubRequestsBrokenSecurity(&broken);
1602 NS_ENSURE_SUCCESS(rv, rv);
1603 rv = assoc->GetCountSubRequestsNoSecurity(&no);
1604 NS_ENSURE_SUCCESS(rv, rv);
1605
1606 if (mIPCOpen)
1607 SendUpdateAssociatedContentSecurity(broken, no);
1608
1609 return NS_OK;
1610 }
1611
1612 //-----------------------------------------------------------------------------
1613 // HttpChannelChild::nsIHttpChannelChild
1614 //-----------------------------------------------------------------------------
1615
1616 NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest()
1617 {
1618 HttpBaseChannel::AddCookiesToRequest();
1619 return NS_OK;
1620 }
1621
1622 NS_IMETHODIMP HttpChannelChild::GetClientSetRequestHeaders(RequestHeaderTuples **aRequestHeaders)
1623 {
1624 *aRequestHeaders = &mClientSetRequestHeaders;
1625 return NS_OK;
1626 }
1627
1628 //-----------------------------------------------------------------------------
1629 // HttpChannelChild::nsIDivertableChannel
1630 //-----------------------------------------------------------------------------
1631 NS_IMETHODIMP
1632 HttpChannelChild::DivertToParent(ChannelDiverterChild **aChild)
1633 {
1634 MOZ_RELEASE_ASSERT(aChild);
1635 MOZ_RELEASE_ASSERT(gNeckoChild);
1636 MOZ_RELEASE_ASSERT(!mDivertingToParent);
1637
1638 // We must fail DivertToParent() if there's no parent end of the channel (and
1639 // won't be!) due to early failure.
1640 if (NS_FAILED(mStatus) && !RemoteChannelExists()) {
1641 return mStatus;
1642 }
1643
1644 nsresult rv = Suspend();
1645 if (NS_WARN_IF(NS_FAILED(rv))) {
1646 return rv;
1647 }
1648
1649 // Once this is set, it should not be unset before the child is taken down.
1650 mDivertingToParent = true;
1651
1652 PChannelDiverterChild* diverter =
1653 gNeckoChild->SendPChannelDiverterConstructor(this);
1654 MOZ_RELEASE_ASSERT(diverter);
1655
1656 *aChild = static_cast<ChannelDiverterChild*>(diverter);
1657
1658 return NS_OK;
1659 }
1660
1661 }} // mozilla::net

mercurial