/src/mozilla-central/netwerk/protocol/http/HttpChannelChild.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsICacheEntry.h" |
13 | | #include "mozilla/AntiTrackingCommon.h" |
14 | | #include "mozilla/Unused.h" |
15 | | #include "mozilla/dom/ContentChild.h" |
16 | | #include "mozilla/dom/DocGroup.h" |
17 | | #include "mozilla/dom/ServiceWorkerUtils.h" |
18 | | #include "mozilla/dom/TabChild.h" |
19 | | #include "mozilla/dom/TabGroup.h" |
20 | | #include "mozilla/extensions/StreamFilterParent.h" |
21 | | #include "mozilla/ipc/FileDescriptorSetChild.h" |
22 | | #include "mozilla/ipc/IPCStreamUtils.h" |
23 | | #include "mozilla/net/NeckoChild.h" |
24 | | #include "mozilla/net/HttpChannelChild.h" |
25 | | |
26 | | #include "AltDataOutputStreamChild.h" |
27 | | #include "CookieServiceChild.h" |
28 | | #include "HttpBackgroundChannelChild.h" |
29 | | #include "nsCOMPtr.h" |
30 | | #include "nsISupportsPrimitives.h" |
31 | | #include "nsChannelClassifier.h" |
32 | | #include "nsContentPolicyUtils.h" |
33 | | #include "nsGlobalWindow.h" |
34 | | #include "nsStringStream.h" |
35 | | #include "nsHttpChannel.h" |
36 | | #include "nsHttpHandler.h" |
37 | | #include "nsNetUtil.h" |
38 | | #include "nsSerializationHelper.h" |
39 | | #include "mozilla/Attributes.h" |
40 | | #include "mozilla/dom/PerformanceStorage.h" |
41 | | #include "mozilla/ipc/InputStreamUtils.h" |
42 | | #include "mozilla/ipc/URIUtils.h" |
43 | | #include "mozilla/ipc/BackgroundUtils.h" |
44 | | #include "mozilla/net/ChannelDiverterChild.h" |
45 | | #include "mozilla/net/DNS.h" |
46 | | #include "SerializedLoadContext.h" |
47 | | #include "nsInputStreamPump.h" |
48 | | #include "InterceptedChannel.h" |
49 | | #include "mozIThirdPartyUtil.h" |
50 | | #include "nsContentSecurityManager.h" |
51 | | #include "nsIDeprecationWarner.h" |
52 | | #include "nsICompressConvStats.h" |
53 | | #include "nsIDocument.h" |
54 | | #include "nsIDOMWindowUtils.h" |
55 | | #include "nsIEventTarget.h" |
56 | | #include "nsRedirectHistoryEntry.h" |
57 | | #include "nsSocketTransportService2.h" |
58 | | #include "nsStreamUtils.h" |
59 | | #include "nsThreadUtils.h" |
60 | | #include "nsCORSListenerProxy.h" |
61 | | #include "nsApplicationCache.h" |
62 | | |
63 | | #ifdef MOZ_TASK_TRACER |
64 | | #include "GeckoTaskTracer.h" |
65 | | #endif |
66 | | |
67 | | #ifdef MOZ_GECKO_PROFILER |
68 | | #include "ProfilerMarkerPayload.h" |
69 | | #endif |
70 | | |
71 | | using namespace mozilla::dom; |
72 | | using namespace mozilla::ipc; |
73 | | |
74 | | namespace mozilla { |
75 | | namespace net { |
76 | | |
77 | | NS_IMPL_ISUPPORTS(InterceptStreamListener, |
78 | | nsIStreamListener, |
79 | | nsIRequestObserver, |
80 | | nsIProgressEventSink) |
81 | | |
82 | | NS_IMETHODIMP |
83 | | InterceptStreamListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) |
84 | 0 | { |
85 | 0 | if (mOwner) { |
86 | 0 | mOwner->DoOnStartRequest(mOwner, mContext); |
87 | 0 | } |
88 | 0 | return NS_OK; |
89 | 0 | } |
90 | | |
91 | | NS_IMETHODIMP |
92 | | InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsISupports* aContext, |
93 | | nsresult status, const char16_t* aStatusArg) |
94 | 0 | { |
95 | 0 | if (mOwner) { |
96 | 0 | mOwner->DoOnStatus(mOwner, status); |
97 | 0 | } |
98 | 0 | return NS_OK; |
99 | 0 | } |
100 | | |
101 | | NS_IMETHODIMP |
102 | | InterceptStreamListener::OnProgress(nsIRequest* aRequest, nsISupports* aContext, |
103 | | int64_t aProgress, int64_t aProgressMax) |
104 | 0 | { |
105 | 0 | if (mOwner) { |
106 | 0 | mOwner->DoOnProgress(mOwner, aProgress, aProgressMax); |
107 | 0 | } |
108 | 0 | return NS_OK; |
109 | 0 | } |
110 | | |
111 | | NS_IMETHODIMP |
112 | | InterceptStreamListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, |
113 | | nsIInputStream* aInputStream, uint64_t aOffset, |
114 | | uint32_t aCount) |
115 | 0 | { |
116 | 0 | if (!mOwner) { |
117 | 0 | return NS_OK; |
118 | 0 | } |
119 | 0 | |
120 | 0 | uint32_t loadFlags; |
121 | 0 | mOwner->GetLoadFlags(&loadFlags); |
122 | 0 |
|
123 | 0 | if (!(loadFlags & HttpBaseChannel::LOAD_BACKGROUND)) { |
124 | 0 | nsCOMPtr<nsIURI> uri; |
125 | 0 | mOwner->GetURI(getter_AddRefs(uri)); |
126 | 0 |
|
127 | 0 | nsAutoCString host; |
128 | 0 | uri->GetHost(host); |
129 | 0 |
|
130 | 0 | OnStatus(mOwner, aContext, NS_NET_STATUS_READING, NS_ConvertUTF8toUTF16(host).get()); |
131 | 0 |
|
132 | 0 | int64_t progress = aOffset + aCount; |
133 | 0 | OnProgress(mOwner, aContext, progress, mOwner->mSynthesizedStreamLength); |
134 | 0 | } |
135 | 0 |
|
136 | 0 | mOwner->DoOnDataAvailable(mOwner, mContext, aInputStream, aOffset, aCount); |
137 | 0 | return NS_OK; |
138 | 0 | } |
139 | | |
140 | | NS_IMETHODIMP |
141 | | InterceptStreamListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatusCode) |
142 | 0 | { |
143 | 0 | if (mOwner) { |
144 | 0 | mOwner->DoPreOnStopRequest(aStatusCode); |
145 | 0 | mOwner->DoOnStopRequest(mOwner, aStatusCode, mContext); |
146 | 0 | } |
147 | 0 | Cleanup(); |
148 | 0 | return NS_OK; |
149 | 0 | } |
150 | | |
151 | | void |
152 | | InterceptStreamListener::Cleanup() |
153 | 0 | { |
154 | 0 | mOwner = nullptr; |
155 | 0 | mContext = nullptr; |
156 | 0 | } |
157 | | |
158 | | //----------------------------------------------------------------------------- |
159 | | // HttpChannelChild |
160 | | //----------------------------------------------------------------------------- |
161 | | |
162 | | HttpChannelChild::HttpChannelChild() |
163 | | : HttpAsyncAborter<HttpChannelChild>(this) |
164 | | , NeckoTargetHolder(nullptr) |
165 | | , mBgChildMutex("HttpChannelChild::BgChildMutex") |
166 | | , mEventTargetMutex("HttpChannelChild::EventTargetMutex") |
167 | | , mSynthesizedStreamLength(0) |
168 | | , mCacheEntryId(0) |
169 | | , mCacheKey(0) |
170 | | , mCacheFetchCount(0) |
171 | | , mCacheExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME) |
172 | | , mDeletingChannelSent(false) |
173 | | , mIPCOpen(false) |
174 | | , mUnknownDecoderInvolved(false) |
175 | | , mDivertingToParent(false) |
176 | | , mFlushedForDiversion(false) |
177 | | , mIsFromCache(false) |
178 | | , mCacheEntryAvailable(false) |
179 | | , mAltDataCacheEntryAvailable(false) |
180 | | , mSendResumeAt(false) |
181 | | , mKeptAlive(false) |
182 | | , mSuspendSent(false) |
183 | | , mSynthesizedResponse(false) |
184 | | , mShouldInterceptSubsequentRedirect(false) |
185 | | , mRedirectingForSubsequentSynthesizedResponse(false) |
186 | | , mPostRedirectChannelShouldIntercept(false) |
187 | | , mPostRedirectChannelShouldUpgrade(false) |
188 | | , mShouldParentIntercept(false) |
189 | | , mSuspendParentAfterSynthesizeResponse(false) |
190 | | , mCacheNeedToReportBytesReadInitialized(false) |
191 | | , mNeedToReportBytesRead(true) |
192 | 0 | { |
193 | 0 | LOG(("Creating HttpChannelChild @%p\n", this)); |
194 | 0 |
|
195 | 0 | mChannelCreationTime = PR_Now(); |
196 | 0 | mChannelCreationTimestamp = TimeStamp::Now(); |
197 | 0 | mLastStatusReported = mChannelCreationTimestamp; // in case we enable the profiler after Init() |
198 | 0 | mAsyncOpenTime = TimeStamp::Now(); |
199 | 0 | mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(this)); |
200 | 0 |
|
201 | 0 | // Ensure that the cookie service is initialized before the first |
202 | 0 | // IPC HTTP channel is created. |
203 | 0 | // We require that the parent cookie service actor exists while |
204 | 0 | // processing HTTP responses. |
205 | 0 | RefPtr<CookieServiceChild> cookieService = CookieServiceChild::GetSingleton(); |
206 | 0 | } |
207 | | |
208 | | HttpChannelChild::~HttpChannelChild() |
209 | 0 | { |
210 | 0 | LOG(("Destroying HttpChannelChild @%p\n", this)); |
211 | 0 |
|
212 | 0 | ReleaseMainThreadOnlyReferences(); |
213 | 0 | } |
214 | | |
215 | | void |
216 | | HttpChannelChild::ReleaseMainThreadOnlyReferences() |
217 | 0 | { |
218 | 0 | if (NS_IsMainThread()) { |
219 | 0 | // Already on main thread, let dtor to |
220 | 0 | // take care of releasing references |
221 | 0 | return; |
222 | 0 | } |
223 | 0 | |
224 | 0 | nsTArray<nsCOMPtr<nsISupports>> arrayToRelease; |
225 | 0 | arrayToRelease.AppendElement(mRedirectChannelChild.forget()); |
226 | 0 |
|
227 | 0 | // To solve multiple inheritence of nsISupports in InterceptStreamListener |
228 | 0 | nsCOMPtr<nsIStreamListener> listener = mInterceptListener.forget(); |
229 | 0 | arrayToRelease.AppendElement(listener.forget()); |
230 | 0 |
|
231 | 0 | arrayToRelease.AppendElement(mInterceptedRedirectListener.forget()); |
232 | 0 | arrayToRelease.AppendElement(mInterceptedRedirectContext.forget()); |
233 | 0 |
|
234 | 0 | NS_DispatchToMainThread(new ProxyReleaseRunnable(std::move(arrayToRelease))); |
235 | 0 | } |
236 | | //----------------------------------------------------------------------------- |
237 | | // HttpChannelChild::nsISupports |
238 | | //----------------------------------------------------------------------------- |
239 | | |
240 | | NS_IMPL_ADDREF(HttpChannelChild) |
241 | | |
242 | | NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() |
243 | 0 | { |
244 | 0 | if (!NS_IsMainThread()) { |
245 | 0 | nsrefcnt count = mRefCnt; |
246 | 0 | nsresult rv = NS_DispatchToMainThread( |
247 | 0 | NewNonOwningRunnableMethod("HttpChannelChild::Release", |
248 | 0 | this, |
249 | 0 | &HttpChannelChild::Release)); |
250 | 0 |
|
251 | 0 | // Continue Release procedure if failed to dispatch to main thread. |
252 | 0 | if (!NS_WARN_IF(NS_FAILED(rv))) { |
253 | 0 | return count - 1; |
254 | 0 | } |
255 | 0 | } |
256 | 0 | |
257 | 0 | nsrefcnt count = --mRefCnt; |
258 | 0 | MOZ_ASSERT(int32_t(count) >= 0, "dup release"); |
259 | 0 | NS_LOG_RELEASE(this, count, "HttpChannelChild"); |
260 | 0 |
|
261 | 0 | // Normally we Send_delete in OnStopRequest, but when we need to retain the |
262 | 0 | // remote channel for security info IPDL itself holds 1 reference, so we |
263 | 0 | // Send_delete when refCnt==1. But if !mIPCOpen, then there's nobody to send |
264 | 0 | // to, so we fall through. |
265 | 0 | if (mKeptAlive && count == 1 && mIPCOpen) { |
266 | 0 | mKeptAlive = false; |
267 | 0 | // We send a message to the parent, which calls SendDelete, and then the |
268 | 0 | // child calling Send__delete__() to finally drop the refcount to 0. |
269 | 0 | TrySendDeletingChannel(); |
270 | 0 | return 1; |
271 | 0 | } |
272 | 0 | |
273 | 0 | if (count == 0) { |
274 | 0 | mRefCnt = 1; /* stabilize */ |
275 | 0 | delete this; |
276 | 0 | return 0; |
277 | 0 | } |
278 | 0 | return count; |
279 | 0 | } |
280 | | |
281 | 0 | NS_INTERFACE_MAP_BEGIN(HttpChannelChild) |
282 | 0 | NS_INTERFACE_MAP_ENTRY(nsIRequest) |
283 | 0 | NS_INTERFACE_MAP_ENTRY(nsIChannel) |
284 | 0 | NS_INTERFACE_MAP_ENTRY(nsIHttpChannel) |
285 | 0 | NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal) |
286 | 0 | NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel) |
287 | 0 | NS_INTERFACE_MAP_ENTRY(nsIResumableChannel) |
288 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsPriority) |
289 | 0 | NS_INTERFACE_MAP_ENTRY(nsIClassOfService) |
290 | 0 | NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel) |
291 | 0 | NS_INTERFACE_MAP_ENTRY(nsITraceableChannel) |
292 | 0 | NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer) |
293 | 0 | NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel) |
294 | 0 | NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback) |
295 | 0 | NS_INTERFACE_MAP_ENTRY(nsIChildChannel) |
296 | 0 | NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild) |
297 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDivertableChannel) |
298 | 0 | NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) |
299 | 0 | NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelChild) |
300 | 0 | NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel) |
301 | | |
302 | | //----------------------------------------------------------------------------- |
303 | | // HttpChannelChild::PHttpChannelChild |
304 | | //----------------------------------------------------------------------------- |
305 | | |
306 | | void |
307 | | HttpChannelChild::AddIPDLReference() |
308 | 0 | { |
309 | 0 | MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference"); |
310 | 0 | mIPCOpen = true; |
311 | 0 | AddRef(); |
312 | 0 | } |
313 | | |
314 | | void |
315 | | HttpChannelChild::ReleaseIPDLReference() |
316 | 0 | { |
317 | 0 | MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference"); |
318 | 0 | mIPCOpen = false; |
319 | 0 | Release(); |
320 | 0 | } |
321 | | |
322 | | void |
323 | | HttpChannelChild::OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild) |
324 | 0 | { |
325 | 0 | LOG(("HttpChannelChild::OnBackgroundChildReady [this=%p, bgChild=%p]\n", |
326 | 0 | this, aBgChild)); |
327 | 0 | MOZ_ASSERT(OnSocketThread()); |
328 | 0 |
|
329 | 0 | { |
330 | 0 | MutexAutoLock lock(mBgChildMutex); |
331 | 0 |
|
332 | 0 | // mBgChild might be removed or replaced while the original background |
333 | 0 | // channel is inited on STS thread. |
334 | 0 | if (mBgChild != aBgChild) { |
335 | 0 | return; |
336 | 0 | } |
337 | 0 | |
338 | 0 | MOZ_ASSERT(mBgInitFailCallback); |
339 | 0 | mBgInitFailCallback = nullptr; |
340 | 0 | } |
341 | 0 | } |
342 | | |
343 | | void |
344 | | HttpChannelChild::OnBackgroundChildDestroyed(HttpBackgroundChannelChild* aBgChild) |
345 | 0 | { |
346 | 0 | LOG(("HttpChannelChild::OnBackgroundChildDestroyed [this=%p]\n", this)); |
347 | 0 | // This function might be called during shutdown phase, so OnSocketThread() |
348 | 0 | // might return false even on STS thread. Use IsOnCurrentThreadInfallible() |
349 | 0 | // to get correct information. |
350 | 0 | MOZ_ASSERT(gSocketTransportService); |
351 | 0 | MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible()); |
352 | 0 |
|
353 | 0 | nsCOMPtr<nsIRunnable> callback; |
354 | 0 | { |
355 | 0 | MutexAutoLock lock(mBgChildMutex); |
356 | 0 |
|
357 | 0 | // mBgChild might be removed or replaced while the original background |
358 | 0 | // channel is destroyed on STS thread. |
359 | 0 | if (aBgChild != mBgChild) { |
360 | 0 | return; |
361 | 0 | } |
362 | 0 | |
363 | 0 | mBgChild = nullptr; |
364 | 0 | callback = mBgInitFailCallback.forget(); |
365 | 0 | } |
366 | 0 |
|
367 | 0 | if (callback) { |
368 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
369 | 0 | neckoTarget->Dispatch(callback, NS_DISPATCH_NORMAL); |
370 | 0 | } |
371 | 0 | } |
372 | | |
373 | | class AssociateApplicationCacheEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
374 | | { |
375 | | public: |
376 | | AssociateApplicationCacheEvent(HttpChannelChild* aChild, |
377 | | const nsCString &aGroupID, |
378 | | const nsCString &aClientID) |
379 | | : NeckoTargetChannelEvent<HttpChannelChild>(aChild) |
380 | | , groupID(aGroupID) |
381 | 0 | , clientID(aClientID) {} |
382 | | |
383 | 0 | void Run() override { mChild->AssociateApplicationCache(groupID, clientID); } |
384 | | |
385 | | private: |
386 | | nsCString groupID; |
387 | | nsCString clientID; |
388 | | }; |
389 | | |
390 | | mozilla::ipc::IPCResult |
391 | | HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID, |
392 | | const nsCString &clientID) |
393 | 0 | { |
394 | 0 | LOG(("HttpChannelChild::RecvAssociateApplicationCache [this=%p]\n", this)); |
395 | 0 | mEventQ->RunOrEnqueue(new AssociateApplicationCacheEvent(this, groupID, |
396 | 0 | clientID)); |
397 | 0 | return IPC_OK(); |
398 | 0 | } |
399 | | |
400 | | void |
401 | | HttpChannelChild::AssociateApplicationCache(const nsCString &groupID, |
402 | | const nsCString &clientID) |
403 | 0 | { |
404 | 0 | LOG(("HttpChannelChild::AssociateApplicationCache [this=%p]\n", this)); |
405 | 0 | mApplicationCache = new nsApplicationCache(); |
406 | 0 |
|
407 | 0 | mLoadedFromApplicationCache = true; |
408 | 0 | mApplicationCache->InitAsHandle(groupID, clientID); |
409 | 0 | } |
410 | | |
411 | | class StartRequestEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
412 | | { |
413 | | public: |
414 | | StartRequestEvent(HttpChannelChild* aChild, |
415 | | const nsresult& aChannelStatus, |
416 | | const nsHttpResponseHead& aResponseHead, |
417 | | const bool& aUseResponseHead, |
418 | | const nsHttpHeaderArray& aRequestHeaders, |
419 | | const ParentLoadInfoForwarderArgs& loadInfoForwarder, |
420 | | const bool& aIsFromCache, |
421 | | const bool& aCacheEntryAvailable, |
422 | | const uint64_t& aCacheEntryId, |
423 | | const int32_t& aCacheFetchCount, |
424 | | const uint32_t& aCacheExpirationTime, |
425 | | const nsCString& aCachedCharset, |
426 | | const nsCString& aSecurityInfoSerialization, |
427 | | const NetAddr& aSelfAddr, |
428 | | const NetAddr& aPeerAddr, |
429 | | const uint32_t& aCacheKey, |
430 | | const nsCString& altDataType, |
431 | | const int64_t& altDataLen, |
432 | | const bool& aApplyConversion, |
433 | | const ResourceTimingStruct& aTiming) |
434 | | : NeckoTargetChannelEvent<HttpChannelChild>(aChild) |
435 | | , mChannelStatus(aChannelStatus) |
436 | | , mResponseHead(aResponseHead) |
437 | | , mRequestHeaders(aRequestHeaders) |
438 | | , mUseResponseHead(aUseResponseHead) |
439 | | , mApplyConversion(aApplyConversion) |
440 | | , mIsFromCache(aIsFromCache) |
441 | | , mCacheEntryAvailable(aCacheEntryAvailable) |
442 | | , mCacheEntryId(aCacheEntryId) |
443 | | , mCacheFetchCount(aCacheFetchCount) |
444 | | , mCacheExpirationTime(aCacheExpirationTime) |
445 | | , mCachedCharset(aCachedCharset) |
446 | | , mSecurityInfoSerialization(aSecurityInfoSerialization) |
447 | | , mSelfAddr(aSelfAddr) |
448 | | , mPeerAddr(aPeerAddr) |
449 | | , mCacheKey(aCacheKey) |
450 | | , mAltDataType(altDataType) |
451 | | , mAltDataLen(altDataLen) |
452 | | , mLoadInfoForwarder(loadInfoForwarder) |
453 | | , mTiming(aTiming) |
454 | 0 | {} |
455 | | |
456 | | void Run() override |
457 | 0 | { |
458 | 0 | LOG(("StartRequestEvent [this=%p]\n", mChild)); |
459 | 0 | mChild->OnStartRequest(mChannelStatus, mResponseHead, mUseResponseHead, |
460 | 0 | mRequestHeaders, mLoadInfoForwarder, |
461 | 0 | mIsFromCache, mCacheEntryAvailable, |
462 | 0 | mCacheEntryId, mCacheFetchCount, |
463 | 0 | mCacheExpirationTime, mCachedCharset, |
464 | 0 | mSecurityInfoSerialization, mSelfAddr, mPeerAddr, |
465 | 0 | mCacheKey, mAltDataType, mAltDataLen, |
466 | 0 | mApplyConversion, mTiming); |
467 | 0 | } |
468 | | |
469 | | private: |
470 | | nsresult mChannelStatus; |
471 | | nsHttpResponseHead mResponseHead; |
472 | | nsHttpHeaderArray mRequestHeaders; |
473 | | bool mUseResponseHead; |
474 | | bool mApplyConversion; |
475 | | bool mIsFromCache; |
476 | | bool mCacheEntryAvailable; |
477 | | uint64_t mCacheEntryId; |
478 | | int32_t mCacheFetchCount; |
479 | | uint32_t mCacheExpirationTime; |
480 | | nsCString mCachedCharset; |
481 | | nsCString mSecurityInfoSerialization; |
482 | | NetAddr mSelfAddr; |
483 | | NetAddr mPeerAddr; |
484 | | uint32_t mCacheKey; |
485 | | nsCString mAltDataType; |
486 | | int64_t mAltDataLen; |
487 | | ParentLoadInfoForwarderArgs mLoadInfoForwarder; |
488 | | ResourceTimingStruct mTiming; |
489 | | }; |
490 | | |
491 | | mozilla::ipc::IPCResult |
492 | | HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus, |
493 | | const nsHttpResponseHead& responseHead, |
494 | | const bool& useResponseHead, |
495 | | const nsHttpHeaderArray& requestHeaders, |
496 | | const ParentLoadInfoForwarderArgs& loadInfoForwarder, |
497 | | const bool& isFromCache, |
498 | | const bool& cacheEntryAvailable, |
499 | | const uint64_t& cacheEntryId, |
500 | | const int32_t& cacheFetchCount, |
501 | | const uint32_t& cacheExpirationTime, |
502 | | const nsCString& cachedCharset, |
503 | | const nsCString& securityInfoSerialization, |
504 | | const NetAddr& selfAddr, |
505 | | const NetAddr& peerAddr, |
506 | | const int16_t& redirectCount, |
507 | | const uint32_t& cacheKey, |
508 | | const nsCString& altDataType, |
509 | | const int64_t& altDataLen, |
510 | | const bool& aApplyConversion, |
511 | | const ResourceTimingStruct& aTiming) |
512 | 0 | { |
513 | 0 | LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this)); |
514 | 0 | // mFlushedForDiversion and mDivertingToParent should NEVER be set at this |
515 | 0 | // stage, as they are set in the listener's OnStartRequest. |
516 | 0 | MOZ_RELEASE_ASSERT(!mFlushedForDiversion, |
517 | 0 | "mFlushedForDiversion should be unset before OnStartRequest!"); |
518 | 0 | MOZ_RELEASE_ASSERT(!mDivertingToParent, |
519 | 0 | "mDivertingToParent should be unset before OnStartRequest!"); |
520 | 0 |
|
521 | 0 |
|
522 | 0 | mRedirectCount = redirectCount; |
523 | 0 |
|
524 | 0 | mEventQ->RunOrEnqueue(new StartRequestEvent(this, channelStatus, responseHead, |
525 | 0 | useResponseHead, requestHeaders, |
526 | 0 | loadInfoForwarder, |
527 | 0 | isFromCache, cacheEntryAvailable, |
528 | 0 | cacheEntryId, cacheFetchCount, |
529 | 0 | cacheExpirationTime, cachedCharset, |
530 | 0 | securityInfoSerialization, |
531 | 0 | selfAddr, peerAddr, cacheKey, |
532 | 0 | altDataType, altDataLen, |
533 | 0 | aApplyConversion, |
534 | 0 | aTiming)); |
535 | 0 |
|
536 | 0 | { |
537 | 0 | // Child's mEventQ is to control the execution order of the IPC messages |
538 | 0 | // from both main thread IPDL and PBackground IPDL. |
539 | 0 | // To guarantee the ordering, PBackground IPC messages that are sent after |
540 | 0 | // OnStartRequest will be throttled until OnStartRequest hits the Child's |
541 | 0 | // mEventQ. |
542 | 0 | MutexAutoLock lock(mBgChildMutex); |
543 | 0 |
|
544 | 0 | if (mBgChild) { |
545 | 0 | MOZ_RELEASE_ASSERT(gSocketTransportService); |
546 | 0 | DebugOnly<nsresult> rv = |
547 | 0 | gSocketTransportService->Dispatch( |
548 | 0 | NewRunnableMethod( |
549 | 0 | "HttpBackgroundChannelChild::OnStartRequestReceived", |
550 | 0 | mBgChild, &HttpBackgroundChannelChild::OnStartRequestReceived), |
551 | 0 | NS_DISPATCH_NORMAL); |
552 | 0 | } |
553 | 0 | } |
554 | 0 |
|
555 | 0 | return IPC_OK(); |
556 | 0 | } |
557 | | |
558 | | void |
559 | | HttpChannelChild::OnStartRequest(const nsresult& channelStatus, |
560 | | const nsHttpResponseHead& responseHead, |
561 | | const bool& useResponseHead, |
562 | | const nsHttpHeaderArray& requestHeaders, |
563 | | const ParentLoadInfoForwarderArgs& loadInfoForwarder, |
564 | | const bool& isFromCache, |
565 | | const bool& cacheEntryAvailable, |
566 | | const uint64_t& cacheEntryId, |
567 | | const int32_t& cacheFetchCount, |
568 | | const uint32_t& cacheExpirationTime, |
569 | | const nsCString& cachedCharset, |
570 | | const nsCString& securityInfoSerialization, |
571 | | const NetAddr& selfAddr, |
572 | | const NetAddr& peerAddr, |
573 | | const uint32_t& cacheKey, |
574 | | const nsCString& altDataType, |
575 | | const int64_t& altDataLen, |
576 | | const bool& aApplyConversion, |
577 | | const ResourceTimingStruct& aTiming) |
578 | 0 | { |
579 | 0 | LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this)); |
580 | 0 |
|
581 | 0 | // mFlushedForDiversion and mDivertingToParent should NEVER be set at this |
582 | 0 | // stage, as they are set in the listener's OnStartRequest. |
583 | 0 | MOZ_RELEASE_ASSERT(!mFlushedForDiversion, |
584 | 0 | "mFlushedForDiversion should be unset before OnStartRequest!"); |
585 | 0 | MOZ_RELEASE_ASSERT(!mDivertingToParent, |
586 | 0 | "mDivertingToParent should be unset before OnStartRequest!"); |
587 | 0 |
|
588 | 0 | if (!mCanceled && NS_SUCCEEDED(mStatus)) { |
589 | 0 | mStatus = channelStatus; |
590 | 0 | } |
591 | 0 |
|
592 | 0 | // Cookies headers should not be visible to the child process |
593 | 0 | MOZ_ASSERT(!requestHeaders.HasHeader(nsHttp::Cookie)); |
594 | 0 | MOZ_ASSERT(!nsHttpResponseHead(responseHead).HasHeader(nsHttp::Set_Cookie)); |
595 | 0 |
|
596 | 0 | if (useResponseHead && !mCanceled) |
597 | 0 | mResponseHead = new nsHttpResponseHead(responseHead); |
598 | 0 |
|
599 | 0 | if (!securityInfoSerialization.IsEmpty()) { |
600 | 0 | NS_DeserializeObject(securityInfoSerialization, |
601 | 0 | getter_AddRefs(mSecurityInfo)); |
602 | 0 | } |
603 | 0 |
|
604 | 0 | ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo); |
605 | 0 |
|
606 | 0 | mIsFromCache = isFromCache; |
607 | 0 | mCacheEntryAvailable = cacheEntryAvailable; |
608 | 0 | mCacheEntryId = cacheEntryId; |
609 | 0 | mCacheFetchCount = cacheFetchCount; |
610 | 0 | mCacheExpirationTime = cacheExpirationTime; |
611 | 0 | mCachedCharset = cachedCharset; |
612 | 0 | mSelfAddr = selfAddr; |
613 | 0 | mPeerAddr = peerAddr; |
614 | 0 |
|
615 | 0 | mAvailableCachedAltDataType = altDataType; |
616 | 0 | mAltDataLength = altDataLen; |
617 | 0 |
|
618 | 0 | SetApplyConversion(aApplyConversion); |
619 | 0 |
|
620 | 0 | mAfterOnStartRequestBegun = true; |
621 | 0 |
|
622 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
623 | 0 |
|
624 | 0 | mCacheKey = cacheKey; |
625 | 0 |
|
626 | 0 | // replace our request headers with what actually got sent in the parent |
627 | 0 | mRequestHead.SetHeaders(requestHeaders); |
628 | 0 |
|
629 | 0 | // Note: this is where we would notify "http-on-examine-response" observers. |
630 | 0 | // We have deliberately disabled this for child processes (see bug 806753) |
631 | 0 | // |
632 | 0 | // gHttpHandler->OnExamineResponse(this); |
633 | 0 |
|
634 | 0 | mTracingEnabled = false; |
635 | 0 |
|
636 | 0 | mTransactionTimings = aTiming; |
637 | 0 |
|
638 | 0 | DoOnStartRequest(this, mListenerContext); |
639 | 0 | } |
640 | | |
641 | | class SyntheticDiversionListener final : public nsIStreamListener |
642 | | { |
643 | | RefPtr<HttpChannelChild> mChannel; |
644 | | |
645 | 0 | ~SyntheticDiversionListener() = default; |
646 | | |
647 | | public: |
648 | | explicit SyntheticDiversionListener(HttpChannelChild* aChannel) |
649 | | : mChannel(aChannel) |
650 | 0 | { |
651 | 0 | MOZ_ASSERT(mChannel); |
652 | 0 | } |
653 | | |
654 | | NS_IMETHOD |
655 | | OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override |
656 | 0 | { |
657 | 0 | MOZ_ASSERT_UNREACHABLE("SyntheticDiversionListener should never see OnStartRequest"); |
658 | 0 | return NS_OK; |
659 | 0 | } |
660 | | |
661 | | NS_IMETHOD |
662 | | OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, |
663 | | nsresult aStatus) override |
664 | 0 | { |
665 | 0 | if (mChannel->mIPCOpen) { |
666 | 0 | mChannel->SendDivertOnStopRequest(aStatus); |
667 | 0 | mChannel->SendDivertComplete(); |
668 | 0 | } |
669 | 0 | return NS_OK; |
670 | 0 | } |
671 | | |
672 | | NS_IMETHOD |
673 | | OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, |
674 | | nsIInputStream* aInputStream, uint64_t aOffset, |
675 | | uint32_t aCount) override |
676 | 0 | { |
677 | 0 | if (!mChannel->mIPCOpen) { |
678 | 0 | aRequest->Cancel(NS_ERROR_ABORT); |
679 | 0 | return NS_ERROR_ABORT; |
680 | 0 | } |
681 | 0 | |
682 | 0 | nsAutoCString data; |
683 | 0 | nsresult rv = NS_ConsumeStream(aInputStream, aCount, data); |
684 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
685 | 0 | aRequest->Cancel(rv); |
686 | 0 | return rv; |
687 | 0 | } |
688 | 0 | |
689 | 0 | mChannel->SendDivertOnDataAvailable(data, aOffset, aCount); |
690 | 0 | return NS_OK; |
691 | 0 | } |
692 | | |
693 | | NS_DECL_ISUPPORTS |
694 | | }; |
695 | | |
696 | | NS_IMPL_ISUPPORTS(SyntheticDiversionListener, nsIStreamListener); |
697 | | |
698 | | static nsresult |
699 | | GetTopDocument(nsIChannel* aChannel, nsIDocument** aResult) |
700 | 0 | { |
701 | 0 | nsresult rv; |
702 | 0 |
|
703 | 0 | nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil(); |
704 | 0 | if (NS_WARN_IF(!thirdPartyUtil)) { |
705 | 0 | return NS_ERROR_FAILURE; |
706 | 0 | } |
707 | 0 | |
708 | 0 | nsCOMPtr<mozIDOMWindowProxy> win; |
709 | 0 | rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, |
710 | 0 | getter_AddRefs(win)); |
711 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
712 | 0 | return rv; |
713 | 0 | } |
714 | 0 | |
715 | 0 | auto* pwin = nsPIDOMWindowOuter::From(win); |
716 | 0 | nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell(); |
717 | 0 | if (!docShell) { |
718 | 0 | return NS_ERROR_FAILURE; |
719 | 0 | } |
720 | 0 | |
721 | 0 | nsCOMPtr<nsIDocument> doc = docShell->GetDocument(); |
722 | 0 | if (!doc) { |
723 | 0 | return NS_ERROR_FAILURE; |
724 | 0 | } |
725 | 0 | |
726 | 0 | doc.forget(aResult); |
727 | 0 | return NS_OK; |
728 | 0 | } |
729 | | |
730 | | void |
731 | | HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext) |
732 | 0 | { |
733 | 0 | LOG(("HttpChannelChild::DoOnStartRequest [this=%p]\n", this)); |
734 | 0 |
|
735 | 0 | // In theory mListener should not be null, but in practice sometimes it is. |
736 | 0 | MOZ_ASSERT(mListener); |
737 | 0 | if (!mListener) { |
738 | 0 | Cancel(NS_ERROR_FAILURE); |
739 | 0 | return; |
740 | 0 | } |
741 | 0 | |
742 | 0 | if (mSynthesizedResponsePump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { |
743 | 0 | mSynthesizedResponsePump->PeekStream(CallTypeSniffers, |
744 | 0 | static_cast<nsIChannel*>(this)); |
745 | 0 | } |
746 | 0 |
|
747 | 0 | bool isTracker; |
748 | 0 | MOZ_ALWAYS_SUCCEEDS(mLoadInfo->GetIsTracker(&isTracker)); |
749 | 0 | if (isTracker) { |
750 | 0 | bool isTrackerBlocked; |
751 | 0 | MOZ_ALWAYS_SUCCEEDS(mLoadInfo->GetIsTrackerBlocked(&isTrackerBlocked)); |
752 | 0 | LOG(("HttpChannelChild::DoOnStartRequest FastBlock %d [this=%p]\n", |
753 | 0 | isTrackerBlocked, |
754 | 0 | this)); |
755 | 0 |
|
756 | 0 | nsCOMPtr<nsIDocument> doc; |
757 | 0 | if (!NS_WARN_IF(NS_FAILED(GetTopDocument(this, |
758 | 0 | getter_AddRefs(doc))))) { |
759 | 0 | doc->IncrementTrackerCount(); |
760 | 0 | if (isTrackerBlocked) { |
761 | 0 | doc->IncrementTrackerBlockedCount(); |
762 | 0 |
|
763 | 0 | Telemetry::LABELS_DOCUMENT_ANALYTICS_TRACKER_FASTBLOCKED label = |
764 | 0 | Telemetry::LABELS_DOCUMENT_ANALYTICS_TRACKER_FASTBLOCKED::other; |
765 | 0 | MOZ_ALWAYS_SUCCEEDS(mLoadInfo->GetTrackerBlockedReason(&label)); |
766 | 0 | doc->NoteTrackerBlockedReason(label); |
767 | 0 | } |
768 | 0 | } |
769 | 0 | } |
770 | 0 |
|
771 | 0 | nsresult rv = mListener->OnStartRequest(aRequest, aContext); |
772 | 0 | if (NS_FAILED(rv)) { |
773 | 0 | Cancel(rv); |
774 | 0 | return; |
775 | 0 | } |
776 | 0 | |
777 | 0 | if (mDivertingToParent) { |
778 | 0 | mListener = nullptr; |
779 | 0 | mListenerContext = nullptr; |
780 | 0 | mCompressListener = nullptr; |
781 | 0 | if (mLoadGroup) { |
782 | 0 | mLoadGroup->RemoveRequest(this, nullptr, mStatus); |
783 | 0 | } |
784 | 0 |
|
785 | 0 | // If the response has been synthesized in the child, then we are going |
786 | 0 | // be getting OnDataAvailable and OnStopRequest from the synthetic |
787 | 0 | // stream pump. We need to forward these back to the parent diversion |
788 | 0 | // listener. |
789 | 0 | if (mSynthesizedResponse) { |
790 | 0 | mListener = new SyntheticDiversionListener(this); |
791 | 0 | } |
792 | 0 |
|
793 | 0 | return; |
794 | 0 | } |
795 | 0 |
|
796 | 0 | nsCOMPtr<nsIStreamListener> listener; |
797 | 0 | rv = DoApplyContentConversions(mListener, getter_AddRefs(listener), |
798 | 0 | mListenerContext); |
799 | 0 | if (NS_FAILED(rv)) { |
800 | 0 | Cancel(rv); |
801 | 0 | } else if (listener) { |
802 | 0 | mListener = listener; |
803 | 0 | mCompressListener = listener; |
804 | 0 | } |
805 | 0 | } |
806 | | |
807 | | class TransportAndDataEvent : public ChannelEvent |
808 | | { |
809 | | public: |
810 | | TransportAndDataEvent(HttpChannelChild* child, |
811 | | const nsresult& channelStatus, |
812 | | const nsresult& transportStatus, |
813 | | const nsCString& data, |
814 | | const uint64_t& offset, |
815 | | const uint32_t& count) |
816 | | : mChild(child) |
817 | | , mChannelStatus(channelStatus) |
818 | | , mTransportStatus(transportStatus) |
819 | | , mData(data) |
820 | | , mOffset(offset) |
821 | 0 | , mCount(count) {} |
822 | | |
823 | | void Run() override |
824 | 0 | { |
825 | 0 | mChild->OnTransportAndData(mChannelStatus, mTransportStatus, |
826 | 0 | mOffset, mCount, mData); |
827 | 0 | } |
828 | | |
829 | | already_AddRefed<nsIEventTarget> GetEventTarget() override |
830 | 0 | { |
831 | 0 | MOZ_ASSERT(mChild); |
832 | 0 | nsCOMPtr<nsIEventTarget> target = mChild->GetODATarget(); |
833 | 0 | return target.forget(); |
834 | 0 | } |
835 | | private: |
836 | | HttpChannelChild* mChild; |
837 | | nsresult mChannelStatus; |
838 | | nsresult mTransportStatus; |
839 | | nsCString mData; |
840 | | uint64_t mOffset; |
841 | | uint32_t mCount; |
842 | | }; |
843 | | |
844 | | void |
845 | | HttpChannelChild::ProcessOnTransportAndData(const nsresult& aChannelStatus, |
846 | | const nsresult& aTransportStatus, |
847 | | const uint64_t& aOffset, |
848 | | const uint32_t& aCount, |
849 | | const nsCString& aData) |
850 | 0 | { |
851 | 0 | LOG(("HttpChannelChild::ProcessOnTransportAndData [this=%p]\n", this)); |
852 | 0 | MOZ_ASSERT(OnSocketThread()); |
853 | 0 | MOZ_RELEASE_ASSERT(!mFlushedForDiversion, |
854 | 0 | "Should not be receiving any more callbacks from parent!"); |
855 | 0 | mEventQ->RunOrEnqueue(new TransportAndDataEvent(this, aChannelStatus, |
856 | 0 | aTransportStatus, aData, |
857 | 0 | aOffset, aCount), |
858 | 0 | mDivertingToParent); |
859 | 0 | } |
860 | | |
861 | | class MaybeDivertOnDataHttpEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
862 | | { |
863 | | public: |
864 | | MaybeDivertOnDataHttpEvent(HttpChannelChild* child, |
865 | | const nsCString& data, |
866 | | const uint64_t& offset, |
867 | | const uint32_t& count) |
868 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
869 | | , mData(data) |
870 | | , mOffset(offset) |
871 | 0 | , mCount(count) {} |
872 | | |
873 | | void Run() override |
874 | 0 | { |
875 | 0 | mChild->MaybeDivertOnData(mData, mOffset, mCount); |
876 | 0 | } |
877 | | |
878 | | private: |
879 | | nsCString mData; |
880 | | uint64_t mOffset; |
881 | | uint32_t mCount; |
882 | | }; |
883 | | |
884 | | void |
885 | | HttpChannelChild::MaybeDivertOnData(const nsCString& data, |
886 | | const uint64_t& offset, |
887 | | const uint32_t& count) |
888 | 0 | { |
889 | 0 | LOG(("HttpChannelChild::MaybeDivertOnData [this=%p]", this)); |
890 | 0 |
|
891 | 0 | if (mDivertingToParent) { |
892 | 0 | SendDivertOnDataAvailable(data, offset, count); |
893 | 0 | } |
894 | 0 | } |
895 | | |
896 | | void |
897 | | HttpChannelChild::OnTransportAndData(const nsresult& channelStatus, |
898 | | const nsresult& transportStatus, |
899 | | const uint64_t& offset, |
900 | | const uint32_t& count, |
901 | | const nsCString& data) |
902 | 0 | { |
903 | 0 | LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this)); |
904 | 0 |
|
905 | 0 | if (!mCanceled && NS_SUCCEEDED(mStatus)) { |
906 | 0 | mStatus = channelStatus; |
907 | 0 | } |
908 | 0 |
|
909 | 0 | // For diversion to parent, just SendDivertOnDataAvailable. |
910 | 0 | if (mDivertingToParent) { |
911 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
912 | 0 | MOZ_RELEASE_ASSERT(!mFlushedForDiversion, |
913 | 0 | "Should not be processing any more callbacks from parent!"); |
914 | 0 |
|
915 | 0 | SendDivertOnDataAvailable(data, offset, count); |
916 | 0 | return; |
917 | 0 | } |
918 | 0 | |
919 | 0 | if (mCanceled) |
920 | 0 | return; |
921 | 0 | |
922 | 0 | if (mUnknownDecoderInvolved) { |
923 | 0 | LOG(("UnknownDecoder is involved queue OnDataAvailable call. [this=%p]", |
924 | 0 | this)); |
925 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
926 | 0 | mUnknownDecoderEventQ.AppendElement( |
927 | 0 | MakeUnique<MaybeDivertOnDataHttpEvent>(this, data, offset, count)); |
928 | 0 | } |
929 | 0 |
|
930 | 0 | // Hold queue lock throughout all three calls, else we might process a later |
931 | 0 | // necko msg in between them. |
932 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
933 | 0 |
|
934 | 0 | int64_t progressMax; |
935 | 0 | if (NS_FAILED(GetContentLength(&progressMax))) { |
936 | 0 | progressMax = -1; |
937 | 0 | } |
938 | 0 |
|
939 | 0 | const int64_t progress = offset + count; |
940 | 0 |
|
941 | 0 | // OnTransportAndData will be run on retargeted thread if applicable, however |
942 | 0 | // OnStatus/OnProgress event can only be fired on main thread. We need to |
943 | 0 | // dispatch the status/progress event handling back to main thread with the |
944 | 0 | // appropriate event target for networking. |
945 | 0 | if (NS_IsMainThread()) { |
946 | 0 | DoOnStatus(this, transportStatus); |
947 | 0 | DoOnProgress(this, progress, progressMax); |
948 | 0 | } else { |
949 | 0 | RefPtr<HttpChannelChild> self = this; |
950 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
951 | 0 | MOZ_ASSERT(neckoTarget); |
952 | 0 |
|
953 | 0 | DebugOnly<nsresult> rv = neckoTarget->Dispatch( |
954 | 0 | NS_NewRunnableFunction("net::HttpChannelChild::OnTransportAndData", |
955 | 0 | [self, transportStatus, progress, progressMax]() { |
956 | 0 | self->DoOnStatus(self, transportStatus); |
957 | 0 | self->DoOnProgress(self, progress, progressMax); |
958 | 0 | }), |
959 | 0 | NS_DISPATCH_NORMAL); |
960 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
961 | 0 | } |
962 | 0 |
|
963 | 0 | // OnDataAvailable |
964 | 0 | // |
965 | 0 | // NOTE: the OnDataAvailable contract requires the client to read all the data |
966 | 0 | // in the inputstream. This code relies on that ('data' will go away after |
967 | 0 | // this function). Apparently the previous, non-e10s behavior was to actually |
968 | 0 | // support only reading part of the data, allowing later calls to read the |
969 | 0 | // rest. |
970 | 0 | nsCOMPtr<nsIInputStream> stringStream; |
971 | 0 | nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), |
972 | 0 | count, NS_ASSIGNMENT_DEPEND); |
973 | 0 | if (NS_FAILED(rv)) { |
974 | 0 | Cancel(rv); |
975 | 0 | return; |
976 | 0 | } |
977 | 0 | |
978 | 0 | DoOnDataAvailable(this, mListenerContext, stringStream, offset, count); |
979 | 0 | stringStream->Close(); |
980 | 0 |
|
981 | 0 | if (NeedToReportBytesRead()) { |
982 | 0 | mUnreportBytesRead += count; |
983 | 0 | if (mUnreportBytesRead >= gHttpHandler->SendWindowSize() >> 2) { |
984 | 0 | if (NS_IsMainThread()) { |
985 | 0 | Unused << SendBytesRead(mUnreportBytesRead); |
986 | 0 | } else { |
987 | 0 | // PHttpChannel connects to the main thread |
988 | 0 | RefPtr<HttpChannelChild> self = this; |
989 | 0 | int32_t bytesRead = mUnreportBytesRead; |
990 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
991 | 0 | MOZ_ASSERT(neckoTarget); |
992 | 0 |
|
993 | 0 | DebugOnly<nsresult> rv = neckoTarget->Dispatch( |
994 | 0 | NS_NewRunnableFunction("net::HttpChannelChild::SendBytesRead", |
995 | 0 | [self, bytesRead]() { |
996 | 0 | Unused << self->SendBytesRead(bytesRead); |
997 | 0 | }), |
998 | 0 | NS_DISPATCH_NORMAL); |
999 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1000 | 0 | } |
1001 | 0 | mUnreportBytesRead = 0; |
1002 | 0 | } |
1003 | 0 | } |
1004 | 0 | } |
1005 | | |
1006 | | bool |
1007 | 0 | HttpChannelChild::NeedToReportBytesRead() { |
1008 | 0 | if (mCacheNeedToReportBytesReadInitialized) { |
1009 | 0 | return mNeedToReportBytesRead; |
1010 | 0 | } |
1011 | 0 | |
1012 | 0 | // Might notify parent for partial cache, and the IPC message is ignored by |
1013 | 0 | // parent. |
1014 | 0 | int64_t contentLength = -1; |
1015 | 0 | if (gHttpHandler->SendWindowSize() == 0 || |
1016 | 0 | mIsFromCache || |
1017 | 0 | NS_FAILED(GetContentLength(&contentLength)) || |
1018 | 0 | contentLength < gHttpHandler->SendWindowSize()) { |
1019 | 0 | mNeedToReportBytesRead = false; |
1020 | 0 | } |
1021 | 0 |
|
1022 | 0 | mCacheNeedToReportBytesReadInitialized = true; |
1023 | 0 | return mNeedToReportBytesRead; |
1024 | 0 | } |
1025 | | |
1026 | | void |
1027 | | HttpChannelChild::DoOnStatus(nsIRequest* aRequest, nsresult status) |
1028 | 0 | { |
1029 | 0 | LOG(("HttpChannelChild::DoOnStatus [this=%p]\n", this)); |
1030 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1031 | 0 |
|
1032 | 0 | if (mCanceled) |
1033 | 0 | return; |
1034 | 0 | |
1035 | 0 | // cache the progress sink so we don't have to query for it each time. |
1036 | 0 | if (!mProgressSink) |
1037 | 0 | GetCallback(mProgressSink); |
1038 | 0 |
|
1039 | 0 | // Temporary fix for bug 1116124 |
1040 | 0 | // See 1124971 - Child removes LOAD_BACKGROUND flag from channel |
1041 | 0 | if (status == NS_OK) |
1042 | 0 | return; |
1043 | 0 | |
1044 | 0 | // block status/progress after Cancel or OnStopRequest has been called, |
1045 | 0 | // or if channel has LOAD_BACKGROUND set. |
1046 | 0 | if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && |
1047 | 0 | !(mLoadFlags & LOAD_BACKGROUND)) |
1048 | 0 | { |
1049 | 0 | // OnStatus |
1050 | 0 | // |
1051 | 0 | MOZ_ASSERT(status == NS_NET_STATUS_RECEIVING_FROM || |
1052 | 0 | status == NS_NET_STATUS_READING); |
1053 | 0 |
|
1054 | 0 | nsAutoCString host; |
1055 | 0 | mURI->GetHost(host); |
1056 | 0 | mProgressSink->OnStatus(aRequest, nullptr, status, |
1057 | 0 | NS_ConvertUTF8toUTF16(host).get()); |
1058 | 0 | } |
1059 | 0 | } |
1060 | | |
1061 | | void |
1062 | | HttpChannelChild::DoOnProgress(nsIRequest* aRequest, int64_t progress, int64_t progressMax) |
1063 | 0 | { |
1064 | 0 | LOG(("HttpChannelChild::DoOnProgress [this=%p]\n", this)); |
1065 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1066 | 0 |
|
1067 | 0 | if (mCanceled) |
1068 | 0 | return; |
1069 | 0 | |
1070 | 0 | // cache the progress sink so we don't have to query for it each time. |
1071 | 0 | if (!mProgressSink) |
1072 | 0 | GetCallback(mProgressSink); |
1073 | 0 |
|
1074 | 0 | // block status/progress after Cancel or OnStopRequest has been called, |
1075 | 0 | // or if channel has LOAD_BACKGROUND set. |
1076 | 0 | if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && |
1077 | 0 | !(mLoadFlags & LOAD_BACKGROUND)) |
1078 | 0 | { |
1079 | 0 | // OnProgress |
1080 | 0 | // |
1081 | 0 | if (progress > 0) { |
1082 | 0 | mProgressSink->OnProgress(aRequest, nullptr, progress, progressMax); |
1083 | 0 | } |
1084 | 0 | } |
1085 | 0 | } |
1086 | | |
1087 | | void |
1088 | | HttpChannelChild::DoOnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, |
1089 | | nsIInputStream* aStream, |
1090 | | uint64_t offset, uint32_t count) |
1091 | 0 | { |
1092 | 0 | LOG(("HttpChannelChild::DoOnDataAvailable [this=%p]\n", this)); |
1093 | 0 | if (mCanceled) |
1094 | 0 | return; |
1095 | 0 | |
1096 | 0 | nsresult rv = mListener->OnDataAvailable(aRequest, aContext, aStream, offset, count); |
1097 | 0 | if (NS_FAILED(rv)) { |
1098 | 0 | CancelOnMainThread(rv); |
1099 | 0 | } |
1100 | 0 | } |
1101 | | |
1102 | | class StopRequestEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
1103 | | { |
1104 | | public: |
1105 | | StopRequestEvent(HttpChannelChild* child, |
1106 | | const nsresult& channelStatus, |
1107 | | const ResourceTimingStruct& timing, |
1108 | | const nsHttpHeaderArray& aResponseTrailers) |
1109 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
1110 | | , mChannelStatus(channelStatus) |
1111 | | , mTiming(timing) |
1112 | 0 | , mResponseTrailers(aResponseTrailers) {} |
1113 | | |
1114 | 0 | void Run() override { mChild->OnStopRequest(mChannelStatus, mTiming, mResponseTrailers); } |
1115 | | |
1116 | | private: |
1117 | | nsresult mChannelStatus; |
1118 | | ResourceTimingStruct mTiming; |
1119 | | nsHttpHeaderArray mResponseTrailers; |
1120 | | }; |
1121 | | |
1122 | | void |
1123 | | HttpChannelChild::ProcessOnStopRequest(const nsresult& aChannelStatus, |
1124 | | const ResourceTimingStruct& aTiming, |
1125 | | const nsHttpHeaderArray& aResponseTrailers) |
1126 | 0 | { |
1127 | 0 | LOG(("HttpChannelChild::ProcessOnStopRequest [this=%p]\n", this)); |
1128 | 0 | MOZ_ASSERT(OnSocketThread()); |
1129 | 0 | MOZ_RELEASE_ASSERT(!mFlushedForDiversion, |
1130 | 0 | "Should not be receiving any more callbacks from parent!"); |
1131 | 0 |
|
1132 | 0 | mEventQ->RunOrEnqueue(new StopRequestEvent(this, aChannelStatus, |
1133 | 0 | aTiming, aResponseTrailers), |
1134 | 0 | mDivertingToParent); |
1135 | 0 | } |
1136 | | |
1137 | | class MaybeDivertOnStopHttpEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
1138 | | { |
1139 | | public: |
1140 | | MaybeDivertOnStopHttpEvent(HttpChannelChild* child, |
1141 | | const nsresult& channelStatus) |
1142 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
1143 | | , mChannelStatus(channelStatus) |
1144 | 0 | {} |
1145 | | |
1146 | | void Run() override |
1147 | 0 | { |
1148 | 0 | mChild->MaybeDivertOnStop(mChannelStatus); |
1149 | 0 | } |
1150 | | |
1151 | | private: |
1152 | | nsresult mChannelStatus; |
1153 | | }; |
1154 | | |
1155 | | void |
1156 | | HttpChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus) |
1157 | 0 | { |
1158 | 0 | LOG(("HttpChannelChild::MaybeDivertOnStop [this=%p, " |
1159 | 0 | "mDivertingToParent=%d status=%" PRIx32 "]", this, |
1160 | 0 | static_cast<bool>(mDivertingToParent), |
1161 | 0 | static_cast<uint32_t>(aChannelStatus))); |
1162 | 0 | if (mDivertingToParent) { |
1163 | 0 | SendDivertOnStopRequest(aChannelStatus); |
1164 | 0 | } |
1165 | 0 | } |
1166 | | |
1167 | | void |
1168 | | HttpChannelChild::OnStopRequest(const nsresult& channelStatus, |
1169 | | const ResourceTimingStruct& timing, |
1170 | | const nsHttpHeaderArray& aResponseTrailers) |
1171 | 0 | { |
1172 | 0 | LOG(("HttpChannelChild::OnStopRequest [this=%p status=%" PRIx32 "]\n", |
1173 | 0 | this, static_cast<uint32_t>(channelStatus))); |
1174 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1175 | 0 |
|
1176 | 0 | if (mDivertingToParent) { |
1177 | 0 | MOZ_RELEASE_ASSERT(!mFlushedForDiversion, |
1178 | 0 | "Should not be processing any more callbacks from parent!"); |
1179 | 0 |
|
1180 | 0 | SendDivertOnStopRequest(channelStatus); |
1181 | 0 | return; |
1182 | 0 | } |
1183 | 0 | |
1184 | 0 | if (mUnknownDecoderInvolved) { |
1185 | 0 | LOG(("UnknownDecoder is involved queue OnStopRequest call. [this=%p]", |
1186 | 0 | this)); |
1187 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1188 | 0 | mUnknownDecoderEventQ.AppendElement( |
1189 | 0 | MakeUnique<MaybeDivertOnStopHttpEvent>(this, channelStatus)); |
1190 | 0 | } |
1191 | 0 |
|
1192 | 0 | nsCOMPtr<nsICompressConvStats> conv = do_QueryInterface(mCompressListener); |
1193 | 0 | if (conv) { |
1194 | 0 | conv->GetDecodedDataLength(&mDecodedBodySize); |
1195 | 0 | } |
1196 | 0 |
|
1197 | 0 | mTransactionTimings.domainLookupStart = timing.domainLookupStart; |
1198 | 0 | mTransactionTimings.domainLookupEnd = timing.domainLookupEnd; |
1199 | 0 | mTransactionTimings.connectStart = timing.connectStart; |
1200 | 0 | mTransactionTimings.tcpConnectEnd = timing.tcpConnectEnd; |
1201 | 0 | mTransactionTimings.secureConnectionStart = timing.secureConnectionStart; |
1202 | 0 | mTransactionTimings.connectEnd = timing.connectEnd; |
1203 | 0 | mTransactionTimings.requestStart = timing.requestStart; |
1204 | 0 | mTransactionTimings.responseStart = timing.responseStart; |
1205 | 0 | mTransactionTimings.responseEnd = timing.responseEnd; |
1206 | 0 |
|
1207 | 0 | // Do not overwrite or adjust the original mAsyncOpenTime by timing.fetchStart |
1208 | 0 | // We must use the original child process time in order to account for child |
1209 | 0 | // side work and IPC transit overhead. |
1210 | 0 | // XXX: This depends on TimeStamp being equivalent across processes. |
1211 | 0 | // This is true for modern hardware but for older platforms it is not always |
1212 | 0 | // true. |
1213 | 0 |
|
1214 | 0 | mRedirectStartTimeStamp = timing.redirectStart; |
1215 | 0 | mRedirectEndTimeStamp = timing.redirectEnd; |
1216 | 0 | mTransferSize = timing.transferSize; |
1217 | 0 | mEncodedBodySize = timing.encodedBodySize; |
1218 | 0 | mProtocolVersion = timing.protocolVersion; |
1219 | 0 |
|
1220 | 0 | mCacheReadStart = timing.cacheReadStart; |
1221 | 0 | mCacheReadEnd = timing.cacheReadEnd; |
1222 | 0 |
|
1223 | 0 | #ifdef MOZ_GECKO_PROFILER |
1224 | 0 | if (profiler_is_active()) { |
1225 | 0 | int32_t priority = PRIORITY_NORMAL; |
1226 | 0 | GetPriority(&priority); |
1227 | 0 | profiler_add_network_marker(mURI, priority, mChannelId, NetworkLoadType::LOAD_STOP, |
1228 | 0 | mLastStatusReported, TimeStamp::Now(), |
1229 | 0 | mTransferSize, |
1230 | 0 | &mTransactionTimings); |
1231 | 0 | } |
1232 | 0 | #endif |
1233 | 0 |
|
1234 | 0 | mResponseTrailers = new nsHttpHeaderArray(aResponseTrailers); |
1235 | 0 |
|
1236 | 0 | DoPreOnStopRequest(channelStatus); |
1237 | 0 |
|
1238 | 0 | { // We must flush the queue before we Send__delete__ |
1239 | 0 | // (although we really shouldn't receive any msgs after OnStop), |
1240 | 0 | // so make sure this goes out of scope before then. |
1241 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
1242 | 0 |
|
1243 | 0 | DoOnStopRequest(this, channelStatus, mListenerContext); |
1244 | 0 | // DoOnStopRequest() calls ReleaseListeners() |
1245 | 0 | } |
1246 | 0 |
|
1247 | 0 | // If unknownDecoder is involved and the received content is short we will |
1248 | 0 | // know whether we need to divert to parent only after OnStopRequest of the |
1249 | 0 | // listeners chain is called in DoOnStopRequest. At that moment |
1250 | 0 | // unknownDecoder will call OnStartRequest of the real listeners of the |
1251 | 0 | // channel including the OnStopRequest of UrlLoader which decides whether we |
1252 | 0 | // need to divert to parent. |
1253 | 0 | // If we are diverting to parent we should not do a cleanup. |
1254 | 0 | if (mDivertingToParent) { |
1255 | 0 | LOG(("HttpChannelChild::OnStopRequest - We are diverting to parent, " |
1256 | 0 | "postpone cleaning up.")); |
1257 | 0 | return; |
1258 | 0 | } |
1259 | 0 |
|
1260 | 0 | CleanupBackgroundChannel(); |
1261 | 0 |
|
1262 | 0 | // If there is a possibility we might want to write alt data to the cache |
1263 | 0 | // entry, we keep the channel alive. We still send the DocumentChannelCleanup |
1264 | 0 | // message but request the cache entry to be kept by the parent. |
1265 | 0 | // If the channel has failed, the cache entry is in a non-writtable state and |
1266 | 0 | // we want to release it to not block following consumers. |
1267 | 0 | if (NS_SUCCEEDED(channelStatus) && !mPreferredCachedAltDataType.IsEmpty()) { |
1268 | 0 | mKeptAlive = true; |
1269 | 0 | SendDocumentChannelCleanup(false); // don't clear cache entry |
1270 | 0 | return; |
1271 | 0 | } |
1272 | 0 | |
1273 | 0 | if (mLoadFlags & LOAD_DOCUMENT_URI) { |
1274 | 0 | // Keep IPDL channel open, but only for updating security info. |
1275 | 0 | // If IPDL is already closed, then do nothing. |
1276 | 0 | if (mIPCOpen) { |
1277 | 0 | mKeptAlive = true; |
1278 | 0 | SendDocumentChannelCleanup(true); |
1279 | 0 | } |
1280 | 0 | } else { |
1281 | 0 | // The parent process will respond by sending a DeleteSelf message and |
1282 | 0 | // making sure not to send any more messages after that. |
1283 | 0 | TrySendDeletingChannel(); |
1284 | 0 | } |
1285 | 0 | } |
1286 | | |
1287 | | void |
1288 | | HttpChannelChild::DoPreOnStopRequest(nsresult aStatus) |
1289 | 0 | { |
1290 | 0 | LOG(("HttpChannelChild::DoPreOnStopRequest [this=%p status=%" PRIx32 "]\n", |
1291 | 0 | this, static_cast<uint32_t>(aStatus))); |
1292 | 0 | mIsPending = false; |
1293 | 0 |
|
1294 | 0 | MaybeCallSynthesizedCallback(); |
1295 | 0 |
|
1296 | 0 | MaybeReportTimingData(); |
1297 | 0 |
|
1298 | 0 | if (!mCanceled && NS_SUCCEEDED(mStatus)) { |
1299 | 0 | mStatus = aStatus; |
1300 | 0 | } |
1301 | 0 |
|
1302 | 0 | CollectOMTTelemetry(); |
1303 | 0 | } |
1304 | | |
1305 | | void |
1306 | | HttpChannelChild::CollectOMTTelemetry() |
1307 | 0 | { |
1308 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1309 | 0 |
|
1310 | 0 | // Only collect telemetry for HTTP channel that is loaded successfully and |
1311 | 0 | // completely. |
1312 | 0 | if (mCanceled || NS_FAILED(mStatus)) { |
1313 | 0 | return; |
1314 | 0 | } |
1315 | 0 | |
1316 | 0 | // Use content policy type to accumulate data by usage. |
1317 | 0 | nsContentPolicyType type = mLoadInfo ? |
1318 | 0 | mLoadInfo->InternalContentPolicyType() : |
1319 | 0 | nsIContentPolicy::TYPE_OTHER; |
1320 | 0 |
|
1321 | 0 | nsAutoCString key(NS_CP_ContentTypeName(type)); |
1322 | 0 |
|
1323 | 0 | Telemetry::AccumulateCategoricalKeyed(key, mOMTResult); |
1324 | 0 | } |
1325 | | |
1326 | | void |
1327 | | HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest, nsresult aChannelStatus, nsISupports* aContext) |
1328 | 0 | { |
1329 | 0 | LOG(("HttpChannelChild::DoOnStopRequest [this=%p]\n", this)); |
1330 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1331 | 0 | MOZ_ASSERT(!mIsPending); |
1332 | 0 |
|
1333 | 0 | // NB: We use aChannelStatus here instead of mStatus because if there was an |
1334 | 0 | // nsCORSListenerProxy on this request, it will override the tracking |
1335 | 0 | // protection's return value. |
1336 | 0 | if (aChannelStatus == NS_ERROR_TRACKING_URI || |
1337 | 0 | aChannelStatus == NS_ERROR_MALWARE_URI || |
1338 | 0 | aChannelStatus == NS_ERROR_UNWANTED_URI || |
1339 | 0 | aChannelStatus == NS_ERROR_BLOCKED_URI || |
1340 | 0 | aChannelStatus == NS_ERROR_HARMFUL_URI || |
1341 | 0 | aChannelStatus == NS_ERROR_PHISHING_URI) { |
1342 | 0 | nsCString list, provider, fullhash; |
1343 | 0 |
|
1344 | 0 | nsresult rv = GetMatchedList(list); |
1345 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
1346 | 0 |
|
1347 | 0 | rv = GetMatchedProvider(provider); |
1348 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
1349 | 0 |
|
1350 | 0 | rv = GetMatchedFullHash(fullhash); |
1351 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
1352 | 0 |
|
1353 | 0 | nsChannelClassifier::SetBlockedContent(this, aChannelStatus, list, provider, fullhash); |
1354 | 0 | } |
1355 | 0 |
|
1356 | 0 | MOZ_ASSERT(!mOnStopRequestCalled, |
1357 | 0 | "We should not call OnStopRequest twice"); |
1358 | 0 |
|
1359 | 0 | // In theory mListener should not be null, but in practice sometimes it is. |
1360 | 0 | MOZ_ASSERT(mListener); |
1361 | 0 | if (mListener) { |
1362 | 0 | mListener->OnStopRequest(aRequest, aContext, mStatus); |
1363 | 0 | } |
1364 | 0 | mOnStopRequestCalled = true; |
1365 | 0 |
|
1366 | 0 | // notify "http-on-stop-connect" observers |
1367 | 0 | gHttpHandler->OnStopRequest(this); |
1368 | 0 |
|
1369 | 0 | ReleaseListeners(); |
1370 | 0 |
|
1371 | 0 | // If a preferred alt-data type was set, the parent would hold a reference to |
1372 | 0 | // the cache entry in case the child calls openAlternativeOutputStream(). |
1373 | 0 | // (see nsHttpChannel::OnStopRequest) |
1374 | 0 | if (!mPreferredCachedAltDataType.IsEmpty()) { |
1375 | 0 | mAltDataCacheEntryAvailable = mCacheEntryAvailable; |
1376 | 0 | } |
1377 | 0 | mCacheEntryAvailable = false; |
1378 | 0 |
|
1379 | 0 | if (mLoadGroup) |
1380 | 0 | mLoadGroup->RemoveRequest(this, nullptr, mStatus); |
1381 | 0 | } |
1382 | | |
1383 | | class ProgressEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
1384 | | { |
1385 | | public: |
1386 | | ProgressEvent(HttpChannelChild* child, |
1387 | | const int64_t& progress, |
1388 | | const int64_t& progressMax) |
1389 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
1390 | | , mProgress(progress) |
1391 | 0 | , mProgressMax(progressMax) {} |
1392 | | |
1393 | 0 | void Run() override { mChild->OnProgress(mProgress, mProgressMax); } |
1394 | | |
1395 | | private: |
1396 | | int64_t mProgress, mProgressMax; |
1397 | | }; |
1398 | | |
1399 | | void |
1400 | | HttpChannelChild::ProcessOnProgress(const int64_t& aProgress, |
1401 | | const int64_t& aProgressMax) |
1402 | 0 | { |
1403 | 0 | LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this)); |
1404 | 0 | MOZ_ASSERT(OnSocketThread()); |
1405 | 0 | mEventQ->RunOrEnqueue(new ProgressEvent(this, aProgress, aProgressMax)); |
1406 | 0 | } |
1407 | | |
1408 | | void |
1409 | | HttpChannelChild::OnProgress(const int64_t& progress, |
1410 | | const int64_t& progressMax) |
1411 | 0 | { |
1412 | 0 | LOG(("HttpChannelChild::OnProgress [this=%p progress=%" PRId64 "/%" PRId64 "]\n", |
1413 | 0 | this, progress, progressMax)); |
1414 | 0 |
|
1415 | 0 | if (mCanceled) |
1416 | 0 | return; |
1417 | 0 | |
1418 | 0 | // cache the progress sink so we don't have to query for it each time. |
1419 | 0 | if (!mProgressSink) { |
1420 | 0 | GetCallback(mProgressSink); |
1421 | 0 | } |
1422 | 0 |
|
1423 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
1424 | 0 |
|
1425 | 0 | // Block socket status event after Cancel or OnStopRequest has been called. |
1426 | 0 | if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending) |
1427 | 0 | { |
1428 | 0 | if (progress > 0) { |
1429 | 0 | mProgressSink->OnProgress(this, nullptr, progress, progressMax); |
1430 | 0 | } |
1431 | 0 | } |
1432 | 0 | } |
1433 | | |
1434 | | class StatusEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
1435 | | { |
1436 | | public: |
1437 | | StatusEvent(HttpChannelChild* child, |
1438 | | const nsresult& status) |
1439 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
1440 | 0 | , mStatus(status) {} |
1441 | | |
1442 | 0 | void Run() override { mChild->OnStatus(mStatus); } |
1443 | | |
1444 | | private: |
1445 | | nsresult mStatus; |
1446 | | }; |
1447 | | |
1448 | | void |
1449 | | HttpChannelChild::ProcessOnStatus(const nsresult& aStatus) |
1450 | 0 | { |
1451 | 0 | LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this)); |
1452 | 0 | MOZ_ASSERT(OnSocketThread()); |
1453 | 0 | mEventQ->RunOrEnqueue(new StatusEvent(this, aStatus)); |
1454 | 0 | } |
1455 | | |
1456 | | void |
1457 | | HttpChannelChild::OnStatus(const nsresult& status) |
1458 | 0 | { |
1459 | 0 | LOG(("HttpChannelChild::OnStatus [this=%p status=%" PRIx32 "]\n", |
1460 | 0 | this, static_cast<uint32_t>(status))); |
1461 | 0 |
|
1462 | 0 | if (mCanceled) |
1463 | 0 | return; |
1464 | 0 | |
1465 | 0 | // cache the progress sink so we don't have to query for it each time. |
1466 | 0 | if (!mProgressSink) |
1467 | 0 | GetCallback(mProgressSink); |
1468 | 0 |
|
1469 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
1470 | 0 |
|
1471 | 0 | // block socket status event after Cancel or OnStopRequest has been called, |
1472 | 0 | // or if channel has LOAD_BACKGROUND set |
1473 | 0 | if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && |
1474 | 0 | !(mLoadFlags & LOAD_BACKGROUND)) |
1475 | 0 | { |
1476 | 0 | nsAutoCString host; |
1477 | 0 | mURI->GetHost(host); |
1478 | 0 | mProgressSink->OnStatus(this, nullptr, status, |
1479 | 0 | NS_ConvertUTF8toUTF16(host).get()); |
1480 | 0 | } |
1481 | 0 | } |
1482 | | |
1483 | | class FailedAsyncOpenEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
1484 | | { |
1485 | | public: |
1486 | | FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status) |
1487 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
1488 | 0 | , mStatus(status) {} |
1489 | | |
1490 | 0 | void Run() override { mChild->FailedAsyncOpen(mStatus); } |
1491 | | |
1492 | | private: |
1493 | | nsresult mStatus; |
1494 | | }; |
1495 | | |
1496 | | mozilla::ipc::IPCResult |
1497 | | HttpChannelChild::RecvFailedAsyncOpen(const nsresult& status) |
1498 | 0 | { |
1499 | 0 | LOG(("HttpChannelChild::RecvFailedAsyncOpen [this=%p]\n", this)); |
1500 | 0 | mEventQ->RunOrEnqueue(new FailedAsyncOpenEvent(this, status)); |
1501 | 0 | return IPC_OK(); |
1502 | 0 | } |
1503 | | |
1504 | | // We need to have an implementation of this function just so that we can keep |
1505 | | // all references to mCallOnResume of type HttpChannelChild: it's not OK in C++ |
1506 | | // to set a member function ptr to a base class function. |
1507 | | void |
1508 | | HttpChannelChild::HandleAsyncAbort() |
1509 | 0 | { |
1510 | 0 | HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort(); |
1511 | 0 |
|
1512 | 0 | // Ignore all the messages from background channel after channel aborted. |
1513 | 0 | CleanupBackgroundChannel(); |
1514 | 0 | } |
1515 | | |
1516 | | void |
1517 | | HttpChannelChild::FailedAsyncOpen(const nsresult& status) |
1518 | 0 | { |
1519 | 0 | LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%" PRIx32 "]\n", |
1520 | 0 | this, static_cast<uint32_t>(status))); |
1521 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1522 | 0 |
|
1523 | 0 | // Might be called twice in race condition in theory. |
1524 | 0 | // (one by RecvFailedAsyncOpen, another by |
1525 | 0 | // HttpBackgroundChannelChild::ActorFailed) |
1526 | 0 | if (NS_WARN_IF(NS_FAILED(mStatus))) { |
1527 | 0 | return; |
1528 | 0 | } |
1529 | 0 | |
1530 | 0 | mStatus = status; |
1531 | 0 |
|
1532 | 0 | // We're already being called from IPDL, therefore already "async" |
1533 | 0 | HandleAsyncAbort(); |
1534 | 0 |
|
1535 | 0 | if (mIPCOpen) { |
1536 | 0 | TrySendDeletingChannel(); |
1537 | 0 | } |
1538 | 0 | } |
1539 | | |
1540 | | void |
1541 | | HttpChannelChild::CleanupBackgroundChannel() |
1542 | 0 | { |
1543 | 0 | MutexAutoLock lock(mBgChildMutex); |
1544 | 0 |
|
1545 | 0 | LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p bgChild=%p]\n", |
1546 | 0 | this, mBgChild.get())); |
1547 | 0 |
|
1548 | 0 | mBgInitFailCallback = nullptr; |
1549 | 0 |
|
1550 | 0 | if (!mBgChild) { |
1551 | 0 | return; |
1552 | 0 | } |
1553 | 0 | |
1554 | 0 | RefPtr<HttpBackgroundChannelChild> bgChild = mBgChild.forget(); |
1555 | 0 |
|
1556 | 0 | MOZ_RELEASE_ASSERT(gSocketTransportService); |
1557 | 0 | if (!OnSocketThread()) { |
1558 | 0 | gSocketTransportService->Dispatch( |
1559 | 0 | NewRunnableMethod( |
1560 | 0 | "HttpBackgroundChannelChild::OnChannelClosed", |
1561 | 0 | bgChild, &HttpBackgroundChannelChild::OnChannelClosed), |
1562 | 0 | NS_DISPATCH_NORMAL); |
1563 | 0 | } else { |
1564 | 0 | bgChild->OnChannelClosed(); |
1565 | 0 | } |
1566 | 0 | } |
1567 | | |
1568 | | void |
1569 | | HttpChannelChild::DoNotifyListenerCleanup() |
1570 | 0 | { |
1571 | 0 | LOG(("HttpChannelChild::DoNotifyListenerCleanup [this=%p]\n", this)); |
1572 | 0 |
|
1573 | 0 | if (mInterceptListener) { |
1574 | 0 | mInterceptListener->Cleanup(); |
1575 | 0 | mInterceptListener = nullptr; |
1576 | 0 | } |
1577 | 0 |
|
1578 | 0 | MaybeCallSynthesizedCallback(); |
1579 | 0 | } |
1580 | | |
1581 | | void |
1582 | | HttpChannelChild::DoAsyncAbort(nsresult aStatus) |
1583 | 0 | { |
1584 | 0 | Unused << AsyncAbort(aStatus); |
1585 | 0 | } |
1586 | | |
1587 | | class DeleteSelfEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
1588 | | { |
1589 | | public: |
1590 | | explicit DeleteSelfEvent(HttpChannelChild* child) |
1591 | 0 | : NeckoTargetChannelEvent<HttpChannelChild>(child) {} |
1592 | 0 | void Run() override { mChild->DeleteSelf(); } |
1593 | | }; |
1594 | | |
1595 | | mozilla::ipc::IPCResult |
1596 | | HttpChannelChild::RecvDeleteSelf() |
1597 | 0 | { |
1598 | 0 | LOG(("HttpChannelChild::RecvDeleteSelf [this=%p]\n", this)); |
1599 | 0 | mEventQ->RunOrEnqueue(new DeleteSelfEvent(this)); |
1600 | 0 | return IPC_OK(); |
1601 | 0 | } |
1602 | | |
1603 | | HttpChannelChild::OverrideRunnable::OverrideRunnable( |
1604 | | HttpChannelChild* aChannel, |
1605 | | HttpChannelChild* aNewChannel, |
1606 | | InterceptStreamListener* aListener, |
1607 | | nsIInputStream* aInput, |
1608 | | nsIInterceptedBodyCallback* aCallback, |
1609 | | nsAutoPtr<nsHttpResponseHead>& aHead, |
1610 | | nsICacheInfoChannel* aCacheInfo) |
1611 | | : Runnable("net::HttpChannelChild::OverrideRunnable") |
1612 | 0 | { |
1613 | 0 | mChannel = aChannel; |
1614 | 0 | mNewChannel = aNewChannel; |
1615 | 0 | mListener = aListener; |
1616 | 0 | mInput = aInput; |
1617 | 0 | mCallback = aCallback; |
1618 | 0 | mHead = aHead; |
1619 | 0 | mSynthesizedCacheInfo = aCacheInfo; |
1620 | 0 | } |
1621 | | |
1622 | | void |
1623 | | HttpChannelChild::OverrideRunnable::OverrideWithSynthesizedResponse() |
1624 | 0 | { |
1625 | 0 | if (mNewChannel) { |
1626 | 0 | mNewChannel->OverrideWithSynthesizedResponse(mHead, mInput, mCallback, mListener, mSynthesizedCacheInfo); |
1627 | 0 | } |
1628 | 0 | } |
1629 | | |
1630 | | NS_IMETHODIMP |
1631 | | HttpChannelChild::OverrideRunnable::Run() |
1632 | 0 | { |
1633 | 0 | // Check to see if the channel was canceled in the middle of the redirect. |
1634 | 0 | nsresult rv = NS_OK; |
1635 | 0 | Unused << mChannel->GetStatus(&rv); |
1636 | 0 | if (NS_FAILED(rv)) { |
1637 | 0 | if (mCallback) { |
1638 | 0 | mCallback->BodyComplete(rv); |
1639 | 0 | mCallback = nullptr; |
1640 | 0 | } |
1641 | 0 | mChannel->CleanupRedirectingChannel(rv); |
1642 | 0 | if (mNewChannel) { |
1643 | 0 | mNewChannel->Cancel(rv); |
1644 | 0 | } |
1645 | 0 | return NS_OK; |
1646 | 0 | } |
1647 | 0 |
|
1648 | 0 | bool ret = mChannel->Redirect3Complete(this); |
1649 | 0 |
|
1650 | 0 | // If the method returns false, it means the IPDL connection is being |
1651 | 0 | // asyncly torn down and reopened, and OverrideWithSynthesizedResponse |
1652 | 0 | // will be called later from FinishInterceptedRedirect. This object will |
1653 | 0 | // be assigned to HttpChannelChild::mOverrideRunnable in order to do so. |
1654 | 0 | // If it is true, we can call the method right now. |
1655 | 0 | if (ret) { |
1656 | 0 | OverrideWithSynthesizedResponse(); |
1657 | 0 | } |
1658 | 0 |
|
1659 | 0 | return NS_OK; |
1660 | 0 | } |
1661 | | |
1662 | | mozilla::ipc::IPCResult |
1663 | | HttpChannelChild::RecvFinishInterceptedRedirect() |
1664 | 0 | { |
1665 | 0 | // Hold a ref to this to keep it from being deleted by Send__delete__() |
1666 | 0 | RefPtr<HttpChannelChild> self(this); |
1667 | 0 | Send__delete__(this); |
1668 | 0 |
|
1669 | 0 | { |
1670 | 0 | // Reset the event target since the IPC actor is about to be destroyed. |
1671 | 0 | // Following channel event should be handled on main thread. |
1672 | 0 | MutexAutoLock lock(mEventTargetMutex); |
1673 | 0 | mNeckoTarget = nullptr; |
1674 | 0 | } |
1675 | 0 |
|
1676 | 0 | // The IPDL connection was torn down by a interception logic in |
1677 | 0 | // CompleteRedirectSetup, and we need to call FinishInterceptedRedirect. |
1678 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
1679 | 0 | MOZ_ASSERT(neckoTarget); |
1680 | 0 |
|
1681 | 0 | Unused << neckoTarget->Dispatch( |
1682 | 0 | NewRunnableMethod("net::HttpChannelChild::FinishInterceptedRedirect", |
1683 | 0 | this, |
1684 | 0 | &HttpChannelChild::FinishInterceptedRedirect), |
1685 | 0 | NS_DISPATCH_NORMAL); |
1686 | 0 |
|
1687 | 0 | return IPC_OK(); |
1688 | 0 | } |
1689 | | |
1690 | | void |
1691 | | HttpChannelChild::DeleteSelf() |
1692 | 0 | { |
1693 | 0 | Send__delete__(this); |
1694 | 0 | } |
1695 | | |
1696 | | void HttpChannelChild::FinishInterceptedRedirect() |
1697 | 0 | { |
1698 | 0 | nsresult rv; |
1699 | 0 | if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) { |
1700 | 0 | MOZ_ASSERT(!mInterceptedRedirectContext, "the context should be null!"); |
1701 | 0 | rv = AsyncOpen2(mInterceptedRedirectListener); |
1702 | 0 | } else { |
1703 | 0 | rv = AsyncOpen(mInterceptedRedirectListener, mInterceptedRedirectContext); |
1704 | 0 | } |
1705 | 0 | mInterceptedRedirectListener = nullptr; |
1706 | 0 | mInterceptedRedirectContext = nullptr; |
1707 | 0 |
|
1708 | 0 | if (mInterceptingChannel) { |
1709 | 0 | mInterceptingChannel->CleanupRedirectingChannel(rv); |
1710 | 0 | mInterceptingChannel = nullptr; |
1711 | 0 | } |
1712 | 0 |
|
1713 | 0 | if (mOverrideRunnable) { |
1714 | 0 | mOverrideRunnable->OverrideWithSynthesizedResponse(); |
1715 | 0 | mOverrideRunnable = nullptr; |
1716 | 0 | } |
1717 | 0 | } |
1718 | | |
1719 | | mozilla::ipc::IPCResult |
1720 | | HttpChannelChild::RecvReportSecurityMessage(const nsString& messageTag, |
1721 | | const nsString& messageCategory) |
1722 | 0 | { |
1723 | 0 | DebugOnly<nsresult> rv = AddSecurityMessage(messageTag, messageCategory); |
1724 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1725 | 0 | return IPC_OK(); |
1726 | 0 | } |
1727 | | |
1728 | | class Redirect1Event : public NeckoTargetChannelEvent<HttpChannelChild> |
1729 | | { |
1730 | | public: |
1731 | | Redirect1Event(HttpChannelChild* child, |
1732 | | const uint32_t& registrarId, |
1733 | | const URIParams& newURI, |
1734 | | const uint32_t& newLoadFlags, |
1735 | | const uint32_t& redirectFlags, |
1736 | | const ParentLoadInfoForwarderArgs& loadInfoForwarder, |
1737 | | const nsHttpResponseHead& responseHead, |
1738 | | const nsACString& securityInfoSerialization, |
1739 | | const uint64_t& channelId) |
1740 | | : NeckoTargetChannelEvent<HttpChannelChild>(child) |
1741 | | , mRegistrarId(registrarId) |
1742 | | , mNewURI(newURI) |
1743 | | , mNewLoadFlags(newLoadFlags) |
1744 | | , mRedirectFlags(redirectFlags) |
1745 | | , mResponseHead(responseHead) |
1746 | | , mSecurityInfoSerialization(securityInfoSerialization) |
1747 | | , mChannelId(channelId) |
1748 | | , mLoadInfoForwarder(loadInfoForwarder) |
1749 | 0 | { |
1750 | 0 | } |
1751 | | |
1752 | | void Run() override |
1753 | 0 | { |
1754 | 0 | mChild->Redirect1Begin(mRegistrarId, mNewURI, mNewLoadFlags, mRedirectFlags, |
1755 | 0 | mLoadInfoForwarder, mResponseHead, |
1756 | 0 | mSecurityInfoSerialization, mChannelId); |
1757 | 0 | } |
1758 | | |
1759 | | private: |
1760 | | uint32_t mRegistrarId; |
1761 | | URIParams mNewURI; |
1762 | | uint32_t mNewLoadFlags; |
1763 | | uint32_t mRedirectFlags; |
1764 | | nsHttpResponseHead mResponseHead; |
1765 | | nsCString mSecurityInfoSerialization; |
1766 | | uint64_t mChannelId; |
1767 | | ParentLoadInfoForwarderArgs mLoadInfoForwarder; |
1768 | | }; |
1769 | | |
1770 | | mozilla::ipc::IPCResult |
1771 | | HttpChannelChild::RecvRedirect1Begin(const uint32_t& registrarId, |
1772 | | const URIParams& newUri, |
1773 | | const uint32_t& newLoadFlags, |
1774 | | const uint32_t& redirectFlags, |
1775 | | const ParentLoadInfoForwarderArgs& loadInfoForwarder, |
1776 | | const nsHttpResponseHead& responseHead, |
1777 | | const nsCString& securityInfoSerialization, |
1778 | | const uint64_t& channelId, |
1779 | | const NetAddr& oldPeerAddr) |
1780 | 0 | { |
1781 | 0 | // TODO: handle security info |
1782 | 0 | LOG(("HttpChannelChild::RecvRedirect1Begin [this=%p]\n", this)); |
1783 | 0 | // We set peer address of child to the old peer, |
1784 | 0 | // Then it will be updated to new peer in OnStartRequest |
1785 | 0 | mPeerAddr = oldPeerAddr; |
1786 | 0 |
|
1787 | 0 | // Cookies headers should not be visible to the child process |
1788 | 0 | MOZ_ASSERT(!nsHttpResponseHead(responseHead).HasHeader(nsHttp::Set_Cookie)); |
1789 | 0 |
|
1790 | 0 | mEventQ->RunOrEnqueue(new Redirect1Event(this, registrarId, newUri, newLoadFlags, |
1791 | 0 | redirectFlags, loadInfoForwarder, |
1792 | 0 | responseHead, securityInfoSerialization, |
1793 | 0 | channelId)); |
1794 | 0 | return IPC_OK(); |
1795 | 0 | } |
1796 | | |
1797 | | nsresult |
1798 | | HttpChannelChild::SetupRedirect(nsIURI* uri, |
1799 | | const nsHttpResponseHead* responseHead, |
1800 | | const uint32_t& redirectFlags, |
1801 | | nsIChannel** outChannel) |
1802 | 0 | { |
1803 | 0 | LOG(("HttpChannelChild::SetupRedirect [this=%p]\n", this)); |
1804 | 0 |
|
1805 | 0 | nsresult rv; |
1806 | 0 | nsCOMPtr<nsIIOService> ioService; |
1807 | 0 | rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); |
1808 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1809 | 0 |
|
1810 | 0 | nsCOMPtr<nsIChannel> newChannel; |
1811 | 0 | nsCOMPtr<nsILoadInfo> redirectLoadInfo = CloneLoadInfoForRedirect(uri, redirectFlags); |
1812 | 0 | rv = NS_NewChannelInternal(getter_AddRefs(newChannel), |
1813 | 0 | uri, |
1814 | 0 | redirectLoadInfo, |
1815 | 0 | nullptr, // PerformanceStorage |
1816 | 0 | nullptr, // aLoadGroup |
1817 | 0 | nullptr, // aCallbacks |
1818 | 0 | nsIRequest::LOAD_NORMAL, |
1819 | 0 | ioService); |
1820 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1821 | 0 |
|
1822 | 0 | // We won't get OnStartRequest, set cookies here. |
1823 | 0 | mResponseHead = new nsHttpResponseHead(*responseHead); |
1824 | 0 |
|
1825 | 0 | bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET(mResponseHead->Status(), |
1826 | 0 | mRequestHead.ParsedMethod()); |
1827 | 0 |
|
1828 | 0 | rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET, redirectFlags); |
1829 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1830 | 0 |
|
1831 | 0 | nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(newChannel); |
1832 | 0 | if (httpChannelChild) { |
1833 | 0 | bool shouldUpgrade = false; |
1834 | 0 | auto channelChild = static_cast<HttpChannelChild*>(httpChannelChild.get()); |
1835 | 0 | if (mShouldInterceptSubsequentRedirect) { |
1836 | 0 | // In the case where there was a synthesized response that caused a redirection, |
1837 | 0 | // we must force the new channel to intercept the request in the parent before a |
1838 | 0 | // network transaction is initiated. |
1839 | 0 | rv = httpChannelChild->ForceIntercepted(false, false); |
1840 | 0 | } else if (mRedirectMode == nsIHttpChannelInternal::REDIRECT_MODE_MANUAL && |
1841 | 0 | ((redirectFlags & (nsIChannelEventSink::REDIRECT_TEMPORARY | |
1842 | 0 | nsIChannelEventSink::REDIRECT_PERMANENT)) != 0) && |
1843 | 0 | channelChild->ShouldInterceptURI(uri, shouldUpgrade)) { |
1844 | 0 | // In the case where the redirect mode is manual, we need to check whether |
1845 | 0 | // the post-redirect channel needs to be intercepted. If that is the |
1846 | 0 | // case, force the new channel to intercept the request in the parent |
1847 | 0 | // similar to the case above, but also remember that ShouldInterceptURI() |
1848 | 0 | // returned true to avoid calling it a second time. |
1849 | 0 | rv = httpChannelChild->ForceIntercepted(true, shouldUpgrade); |
1850 | 0 | } |
1851 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1852 | 0 | } |
1853 | 0 |
|
1854 | 0 | mRedirectChannelChild = do_QueryInterface(newChannel); |
1855 | 0 | newChannel.forget(outChannel); |
1856 | 0 |
|
1857 | 0 | return NS_OK; |
1858 | 0 | } |
1859 | | |
1860 | | void |
1861 | | HttpChannelChild::Redirect1Begin(const uint32_t& registrarId, |
1862 | | const URIParams& newOriginalURI, |
1863 | | const uint32_t& newLoadFlags, |
1864 | | const uint32_t& redirectFlags, |
1865 | | const ParentLoadInfoForwarderArgs& loadInfoForwarder, |
1866 | | const nsHttpResponseHead& responseHead, |
1867 | | const nsACString& securityInfoSerialization, |
1868 | | const uint64_t& channelId) |
1869 | 0 | { |
1870 | 0 | nsresult rv; |
1871 | 0 |
|
1872 | 0 | LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this)); |
1873 | 0 |
|
1874 | 0 | ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo); |
1875 | 0 |
|
1876 | 0 | nsCOMPtr<nsIURI> uri = DeserializeURI(newOriginalURI); |
1877 | 0 |
|
1878 | 0 | PROFILER_ADD_NETWORK_MARKER(mURI, mPriority, channelId, NetworkLoadType::LOAD_REDIRECT, |
1879 | 0 | mLastStatusReported, TimeStamp::Now(), |
1880 | 0 | 0, |
1881 | 0 | &mTransactionTimings, |
1882 | 0 | uri); |
1883 | 0 |
|
1884 | 0 | if (!securityInfoSerialization.IsEmpty()) { |
1885 | 0 | NS_DeserializeObject(securityInfoSerialization, |
1886 | 0 | getter_AddRefs(mSecurityInfo)); |
1887 | 0 | } |
1888 | 0 |
|
1889 | 0 | nsCOMPtr<nsIChannel> newChannel; |
1890 | 0 | rv = SetupRedirect(uri, &responseHead, redirectFlags, |
1891 | 0 | getter_AddRefs(newChannel)); |
1892 | 0 |
|
1893 | 0 | if (NS_SUCCEEDED(rv)) { |
1894 | 0 | MOZ_ALWAYS_SUCCEEDS(newChannel->SetLoadFlags(newLoadFlags)); |
1895 | 0 |
|
1896 | 0 | if (mRedirectChannelChild) { |
1897 | 0 | // Set the channelId allocated in parent to the child instance |
1898 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mRedirectChannelChild); |
1899 | 0 | if (httpChannel) { |
1900 | 0 | rv = httpChannel->SetChannelId(channelId); |
1901 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1902 | 0 | } |
1903 | 0 | mRedirectChannelChild->ConnectParent(registrarId); |
1904 | 0 | } |
1905 | 0 |
|
1906 | 0 | nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); |
1907 | 0 | MOZ_ASSERT(target); |
1908 | 0 |
|
1909 | 0 | rv = gHttpHandler->AsyncOnChannelRedirect(this, |
1910 | 0 | newChannel, |
1911 | 0 | redirectFlags, |
1912 | 0 | target); |
1913 | 0 | } |
1914 | 0 |
|
1915 | 0 | if (NS_FAILED(rv)) |
1916 | 0 | OnRedirectVerifyCallback(rv); |
1917 | 0 | } |
1918 | | |
1919 | | void |
1920 | | HttpChannelChild::BeginNonIPCRedirect(nsIURI* responseURI, |
1921 | | const nsHttpResponseHead* responseHead, |
1922 | | bool aResponseRedirected) |
1923 | 0 | { |
1924 | 0 | LOG(("HttpChannelChild::BeginNonIPCRedirect [this=%p]\n", this)); |
1925 | 0 |
|
1926 | 0 | // This method is only used by child-side service workers. It should not be |
1927 | 0 | // used by new code. We want to remove it in the future. |
1928 | 0 | MOZ_DIAGNOSTIC_ASSERT(mSynthesizedResponse); |
1929 | 0 |
|
1930 | 0 | // If the response has been redirected, propagate all the URLs to content. |
1931 | 0 | // Thus, the exact value of the redirect flag does not matter as long as it's |
1932 | 0 | // not REDIRECT_INTERNAL. |
1933 | 0 | const uint32_t redirectFlag = |
1934 | 0 | aResponseRedirected ? nsIChannelEventSink::REDIRECT_TEMPORARY |
1935 | 0 | : nsIChannelEventSink::REDIRECT_INTERNAL; |
1936 | 0 |
|
1937 | 0 |
|
1938 | 0 | nsCOMPtr<nsIChannel> newChannel; |
1939 | 0 | nsresult rv = SetupRedirect(responseURI, |
1940 | 0 | responseHead, |
1941 | 0 | redirectFlag, |
1942 | 0 | getter_AddRefs(newChannel)); |
1943 | 0 |
|
1944 | 0 | if (NS_SUCCEEDED(rv)) { |
1945 | 0 | // Ensure that the new channel shares the original channel's security information, |
1946 | 0 | // since it won't be provided via IPC. In particular, if the target of this redirect |
1947 | 0 | // is a synthesized response that has its own security info, the pre-redirect channel |
1948 | 0 | // has already received it and it must be propagated to the post-redirect channel. |
1949 | 0 | nsCOMPtr<nsIHttpChannelChild> channelChild = do_QueryInterface(newChannel); |
1950 | 0 | if (mSecurityInfo && channelChild) { |
1951 | 0 | HttpChannelChild* httpChannelChild = static_cast<HttpChannelChild*>(channelChild.get()); |
1952 | 0 | httpChannelChild->OverrideSecurityInfoForNonIPCRedirect(mSecurityInfo); |
1953 | 0 | } |
1954 | 0 |
|
1955 | 0 | // Normally we don't propagate the LoadInfo's service worker tainting |
1956 | 0 | // synthesis flag on redirect. A real redirect normally will want to allow |
1957 | 0 | // normal tainting to proceed from its starting taint. For this particular |
1958 | 0 | // redirect, though, we are performing a redirect to communicate the URL of |
1959 | 0 | // the service worker synthetic response itself. This redirect still represents |
1960 | 0 | // the synthetic response, so we must preserve the flag. |
1961 | 0 | if (mLoadInfo && mLoadInfo->GetServiceWorkerTaintingSynthesized()) { |
1962 | 0 | nsCOMPtr<nsILoadInfo> newChannelLoadInfo; |
1963 | 0 | Unused << newChannel->GetLoadInfo(getter_AddRefs(newChannelLoadInfo)); |
1964 | 0 | if (newChannelLoadInfo) { |
1965 | 0 | newChannelLoadInfo->SynthesizeServiceWorkerTainting(mLoadInfo->GetTainting()); |
1966 | 0 | } |
1967 | 0 | } |
1968 | 0 |
|
1969 | 0 | nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); |
1970 | 0 | MOZ_ASSERT(target); |
1971 | 0 |
|
1972 | 0 | rv = gHttpHandler->AsyncOnChannelRedirect(this, |
1973 | 0 | newChannel, |
1974 | 0 | redirectFlag, |
1975 | 0 | target); |
1976 | 0 | } |
1977 | 0 |
|
1978 | 0 | if (NS_FAILED(rv)) |
1979 | 0 | OnRedirectVerifyCallback(rv); |
1980 | 0 | } |
1981 | | |
1982 | | void |
1983 | | HttpChannelChild::OverrideSecurityInfoForNonIPCRedirect(nsISupports* securityInfo) |
1984 | 0 | { |
1985 | 0 | mResponseCouldBeSynthesized = true; |
1986 | 0 | DebugOnly<nsresult> rv = OverrideSecurityInfo(securityInfo); |
1987 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1988 | 0 | } |
1989 | | |
1990 | | class Redirect3Event : public NeckoTargetChannelEvent<HttpChannelChild> |
1991 | | { |
1992 | | public: |
1993 | | explicit Redirect3Event(HttpChannelChild* child) |
1994 | 0 | : NeckoTargetChannelEvent<HttpChannelChild>(child) {} |
1995 | 0 | void Run() override { mChild->Redirect3Complete(nullptr); } |
1996 | | }; |
1997 | | |
1998 | | mozilla::ipc::IPCResult |
1999 | | HttpChannelChild::RecvRedirect3Complete() |
2000 | 0 | { |
2001 | 0 | LOG(("HttpChannelChild::RecvRedirect3Complete [this=%p]\n", this)); |
2002 | 0 | mEventQ->RunOrEnqueue(new Redirect3Event(this)); |
2003 | 0 | return IPC_OK(); |
2004 | 0 | } |
2005 | | |
2006 | | class HttpFlushedForDiversionEvent : public NeckoTargetChannelEvent<HttpChannelChild> |
2007 | | { |
2008 | | public: |
2009 | | explicit HttpFlushedForDiversionEvent(HttpChannelChild* aChild) |
2010 | | : NeckoTargetChannelEvent<HttpChannelChild>(aChild) |
2011 | 0 | { |
2012 | 0 | MOZ_RELEASE_ASSERT(aChild); |
2013 | 0 | } |
2014 | | |
2015 | | void Run() override |
2016 | 0 | { |
2017 | 0 | mChild->FlushedForDiversion(); |
2018 | 0 | } |
2019 | | }; |
2020 | | |
2021 | | void |
2022 | | HttpChannelChild::ProcessFlushedForDiversion() |
2023 | 0 | { |
2024 | 0 | LOG(("HttpChannelChild::ProcessFlushedForDiversion [this=%p]\n", this)); |
2025 | 0 | MOZ_ASSERT(OnSocketThread()); |
2026 | 0 | MOZ_RELEASE_ASSERT(mDivertingToParent); |
2027 | 0 |
|
2028 | 0 | mEventQ->RunOrEnqueue(new HttpFlushedForDiversionEvent(this), true); |
2029 | 0 | } |
2030 | | |
2031 | | void |
2032 | | HttpChannelChild::ProcessNotifyTrackingProtectionDisabled() |
2033 | 0 | { |
2034 | 0 | LOG(("HttpChannelChild::ProcessNotifyTrackingProtectionDisabled [this=%p]\n", this)); |
2035 | 0 | MOZ_ASSERT(OnSocketThread()); |
2036 | 0 |
|
2037 | 0 | RefPtr<HttpChannelChild> self = this; |
2038 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
2039 | 0 | neckoTarget->Dispatch( |
2040 | 0 | NS_NewRunnableFunction( |
2041 | 0 | "nsChannelClassifier::NotifyTrackingProtectionDisabled", |
2042 | 0 | [self]() { |
2043 | 0 | nsChannelClassifier::NotifyTrackingProtectionDisabled(self); |
2044 | 0 | }), |
2045 | 0 | NS_DISPATCH_NORMAL); |
2046 | 0 | } |
2047 | | |
2048 | | void |
2049 | | HttpChannelChild::ProcessNotifyTrackingCookieBlocked(uint32_t aRejectedReason) |
2050 | 0 | { |
2051 | 0 | LOG(("HttpChannelChild::ProcessNotifyTrackingCookieBlocked [this=%p]\n", this)); |
2052 | 0 | MOZ_ASSERT(OnSocketThread()); |
2053 | 0 |
|
2054 | 0 | RefPtr<HttpChannelChild> self = this; |
2055 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
2056 | 0 | neckoTarget->Dispatch( |
2057 | 0 | NS_NewRunnableFunction( |
2058 | 0 | "nsChannelClassifier::NotifyTrackingCookieBlocked", |
2059 | 0 | [self, aRejectedReason]() { |
2060 | 0 | AntiTrackingCommon::NotifyRejection(self, aRejectedReason); |
2061 | 0 | }), |
2062 | 0 | NS_DISPATCH_NORMAL); |
2063 | 0 | } |
2064 | | |
2065 | | void |
2066 | | HttpChannelChild::ProcessNotifyTrackingResource(bool aIsThirdParty) |
2067 | 0 | { |
2068 | 0 | LOG(("HttpChannelChild::ProcessNotifyTrackingResource thirdparty=%d " |
2069 | 0 | "[this=%p]\n", static_cast<int>(aIsThirdParty), this)); |
2070 | 0 | MOZ_ASSERT(OnSocketThread()); |
2071 | 0 |
|
2072 | 0 | SetIsTrackingResource(aIsThirdParty); |
2073 | 0 | } |
2074 | | |
2075 | | void |
2076 | | HttpChannelChild::FlushedForDiversion() |
2077 | 0 | { |
2078 | 0 | LOG(("HttpChannelChild::FlushedForDiversion [this=%p]\n", this)); |
2079 | 0 | MOZ_RELEASE_ASSERT(mDivertingToParent); |
2080 | 0 |
|
2081 | 0 | // Once this is set, it should not be unset before HttpChannelChild is taken |
2082 | 0 | // down. After it is set, no OnStart/OnData/OnStop callbacks should be |
2083 | 0 | // received from the parent channel, nor dequeued from the ChannelEventQueue. |
2084 | 0 | mFlushedForDiversion = true; |
2085 | 0 |
|
2086 | 0 | // If we're synthesized, it's up to the SyntheticDiversionListener to invoke |
2087 | 0 | // SendDivertComplete after it has sent the DivertOnStopRequestMessage. |
2088 | 0 | if (!mSynthesizedResponse) { |
2089 | 0 | SendDivertComplete(); |
2090 | 0 | } |
2091 | 0 | } |
2092 | | |
2093 | | void |
2094 | | HttpChannelChild::ProcessSetClassifierMatchedInfo(const nsCString& aList, |
2095 | | const nsCString& aProvider, |
2096 | | const nsCString& aFullHash) |
2097 | 0 | { |
2098 | 0 | LOG(("HttpChannelChild::ProcessSetClassifierMatchedInfo [this=%p]\n", this)); |
2099 | 0 | MOZ_ASSERT(OnSocketThread()); |
2100 | 0 |
|
2101 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
2102 | 0 | neckoTarget->Dispatch( |
2103 | 0 | NewRunnableMethod<const nsCString, const nsCString, const nsCString> |
2104 | 0 | ("HttpChannelChild::SetMatchedInfo", |
2105 | 0 | this, &HttpChannelChild::SetMatchedInfo, |
2106 | 0 | aList, aProvider, aFullHash), |
2107 | 0 | NS_DISPATCH_NORMAL); |
2108 | 0 | } |
2109 | | |
2110 | | void |
2111 | | HttpChannelChild::ProcessDivertMessages() |
2112 | 0 | { |
2113 | 0 | LOG(("HttpChannelChild::ProcessDivertMessages [this=%p]\n", this)); |
2114 | 0 | MOZ_ASSERT(OnSocketThread()); |
2115 | 0 | MOZ_RELEASE_ASSERT(mDivertingToParent); |
2116 | 0 |
|
2117 | 0 | // DivertTo() has been called on parent, so we can now start sending queued |
2118 | 0 | // IPDL messages back to parent listener. |
2119 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
2120 | 0 | MOZ_ASSERT(neckoTarget); |
2121 | 0 | nsresult rv = |
2122 | 0 | neckoTarget->Dispatch( |
2123 | 0 | NewRunnableMethod( |
2124 | 0 | "HttpChannelChild::Resume", |
2125 | 0 | this, &HttpChannelChild::Resume), |
2126 | 0 | NS_DISPATCH_NORMAL); |
2127 | 0 |
|
2128 | 0 | MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
2129 | 0 | } |
2130 | | |
2131 | | // Returns true if has actually completed the redirect and cleaned up the |
2132 | | // channel, or false the interception logic kicked in and we need to asyncly |
2133 | | // call FinishInterceptedRedirect and CleanupRedirectingChannel. |
2134 | | // The argument is an optional OverrideRunnable that we pass to the redirected |
2135 | | // channel. |
2136 | | bool |
2137 | | HttpChannelChild::Redirect3Complete(OverrideRunnable* aRunnable) |
2138 | 0 | { |
2139 | 0 | LOG(("HttpChannelChild::Redirect3Complete [this=%p]\n", this)); |
2140 | 0 | nsresult rv = NS_OK; |
2141 | 0 |
|
2142 | 0 | nsCOMPtr<nsIHttpChannelChild> chan = do_QueryInterface(mRedirectChannelChild); |
2143 | 0 | RefPtr<HttpChannelChild> httpChannelChild = static_cast<HttpChannelChild*>(chan.get()); |
2144 | 0 | // Chrome channel has been AsyncOpen'd. Reflect this in child. |
2145 | 0 | if (mRedirectChannelChild) { |
2146 | 0 | if (httpChannelChild) { |
2147 | 0 | httpChannelChild->mOverrideRunnable = aRunnable; |
2148 | 0 | httpChannelChild->mInterceptingChannel = this; |
2149 | 0 | } |
2150 | 0 | rv = mRedirectChannelChild->CompleteRedirectSetup(mListener, |
2151 | 0 | mListenerContext); |
2152 | 0 | } |
2153 | 0 |
|
2154 | 0 | if (!httpChannelChild || !httpChannelChild->mShouldParentIntercept) { |
2155 | 0 | // The redirect channel either isn't a HttpChannelChild, or the interception |
2156 | 0 | // logic wasn't triggered, so we can clean it up right here. |
2157 | 0 | CleanupRedirectingChannel(rv); |
2158 | 0 | if (httpChannelChild) { |
2159 | 0 | httpChannelChild->mOverrideRunnable = nullptr; |
2160 | 0 | httpChannelChild->mInterceptingChannel = nullptr; |
2161 | 0 | } |
2162 | 0 | return true; |
2163 | 0 | } |
2164 | 0 | return false; |
2165 | 0 | } |
2166 | | |
2167 | | mozilla::ipc::IPCResult |
2168 | | HttpChannelChild::RecvCancelRedirected() |
2169 | 0 | { |
2170 | 0 | CleanupRedirectingChannel(NS_BINDING_REDIRECTED); |
2171 | 0 | return IPC_OK(); |
2172 | 0 | } |
2173 | | |
2174 | | void |
2175 | | HttpChannelChild::CleanupRedirectingChannel(nsresult rv) |
2176 | 0 | { |
2177 | 0 | // Redirecting to new channel: shut this down and init new channel |
2178 | 0 | if (mLoadGroup) |
2179 | 0 | mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED); |
2180 | 0 |
|
2181 | 0 | if (NS_SUCCEEDED(rv)) { |
2182 | 0 | if (mLoadInfo) { |
2183 | 0 | nsCString remoteAddress; |
2184 | 0 | Unused << GetRemoteAddress(remoteAddress); |
2185 | 0 | nsCOMPtr<nsIRedirectHistoryEntry> entry = |
2186 | 0 | new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress); |
2187 | 0 |
|
2188 | 0 | mLoadInfo->AppendRedirectHistoryEntry(entry, false); |
2189 | 0 | } |
2190 | 0 | } |
2191 | 0 | else { |
2192 | 0 | NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?"); |
2193 | 0 | } |
2194 | 0 |
|
2195 | 0 | // Release ref to new channel. |
2196 | 0 | mRedirectChannelChild = nullptr; |
2197 | 0 |
|
2198 | 0 | if (mInterceptListener) { |
2199 | 0 | mInterceptListener->Cleanup(); |
2200 | 0 | mInterceptListener = nullptr; |
2201 | 0 | } |
2202 | 0 | ReleaseListeners(); |
2203 | 0 | } |
2204 | | |
2205 | | //----------------------------------------------------------------------------- |
2206 | | // HttpChannelChild::nsIChildChannel |
2207 | | //----------------------------------------------------------------------------- |
2208 | | |
2209 | | NS_IMETHODIMP |
2210 | | HttpChannelChild::ConnectParent(uint32_t registrarId) |
2211 | 0 | { |
2212 | 0 | LOG(("HttpChannelChild::ConnectParent [this=%p, id=%" PRIu32 "]\n", this, registrarId)); |
2213 | 0 | mozilla::dom::TabChild* tabChild = nullptr; |
2214 | 0 | nsCOMPtr<nsITabChild> iTabChild; |
2215 | 0 | GetCallback(iTabChild); |
2216 | 0 | if (iTabChild) { |
2217 | 0 | tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get()); |
2218 | 0 | } |
2219 | 0 | if (MissingRequiredTabChild(tabChild, "http")) { |
2220 | 0 | return NS_ERROR_ILLEGAL_VALUE; |
2221 | 0 | } |
2222 | 0 | |
2223 | 0 | if (tabChild && !tabChild->IPCOpen()) { |
2224 | 0 | return NS_ERROR_FAILURE; |
2225 | 0 | } |
2226 | 0 | |
2227 | 0 | ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager()); |
2228 | 0 | if (cc->IsShuttingDown()) { |
2229 | 0 | return NS_ERROR_FAILURE; |
2230 | 0 | } |
2231 | 0 | |
2232 | 0 | HttpBaseChannel::SetDocshellUserAgentOverride(); |
2233 | 0 |
|
2234 | 0 | // The socket transport in the chrome process now holds a logical ref to us |
2235 | 0 | // until OnStopRequest, or we do a redirect, or we hit an IPDL error. |
2236 | 0 | AddIPDLReference(); |
2237 | 0 |
|
2238 | 0 | // This must happen before the constructor message is sent. Otherwise messages |
2239 | 0 | // from the parent could arrive quickly and be delivered to the wrong event |
2240 | 0 | // target. |
2241 | 0 | SetEventTarget(); |
2242 | 0 |
|
2243 | 0 | HttpChannelConnectArgs connectArgs(registrarId, mShouldParentIntercept); |
2244 | 0 | PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager()) |
2245 | 0 | ->GetBrowserOrId(tabChild); |
2246 | 0 | if (!gNeckoChild-> |
2247 | 0 | SendPHttpChannelConstructor(this, browser, |
2248 | 0 | IPC::SerializedLoadContext(this), |
2249 | 0 | connectArgs)) { |
2250 | 0 | return NS_ERROR_FAILURE; |
2251 | 0 | } |
2252 | 0 | |
2253 | 0 | { |
2254 | 0 | MutexAutoLock lock(mBgChildMutex); |
2255 | 0 |
|
2256 | 0 | MOZ_ASSERT(!mBgChild); |
2257 | 0 | MOZ_ASSERT(!mBgInitFailCallback); |
2258 | 0 |
|
2259 | 0 | mBgInitFailCallback = NewRunnableMethod<nsresult>( |
2260 | 0 | "HttpChannelChild::OnRedirectVerifyCallback", |
2261 | 0 | this, &HttpChannelChild::OnRedirectVerifyCallback, |
2262 | 0 | NS_ERROR_FAILURE); |
2263 | 0 |
|
2264 | 0 | RefPtr<HttpBackgroundChannelChild> bgChild = |
2265 | 0 | new HttpBackgroundChannelChild(); |
2266 | 0 |
|
2267 | 0 | MOZ_RELEASE_ASSERT(gSocketTransportService); |
2268 | 0 |
|
2269 | 0 | RefPtr<HttpChannelChild> self = this; |
2270 | 0 | nsresult rv = |
2271 | 0 | gSocketTransportService->Dispatch( |
2272 | 0 | NewRunnableMethod<RefPtr<HttpChannelChild>>( |
2273 | 0 | "HttpBackgroundChannelChild::Init", |
2274 | 0 | bgChild, &HttpBackgroundChannelChild::Init, std::move(self)), |
2275 | 0 | NS_DISPATCH_NORMAL); |
2276 | 0 |
|
2277 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
2278 | 0 | return rv; |
2279 | 0 | } |
2280 | 0 | |
2281 | 0 | mBgChild = bgChild.forget(); |
2282 | 0 | } |
2283 | 0 |
|
2284 | 0 | return NS_OK; |
2285 | 0 | } |
2286 | | |
2287 | | NS_IMETHODIMP |
2288 | | HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener, |
2289 | | nsISupports *aContext) |
2290 | 0 | { |
2291 | 0 | LOG(("HttpChannelChild::FinishRedirectSetup [this=%p]\n", this)); |
2292 | 0 |
|
2293 | 0 | NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); |
2294 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); |
2295 | 0 |
|
2296 | 0 | if (mShouldParentIntercept) { |
2297 | 0 | // This is a redirected channel, and the corresponding parent channel has started |
2298 | 0 | // AsyncOpen but was intercepted and suspended. We must tear it down and start |
2299 | 0 | // fresh - we will intercept the child channel this time, before creating a new |
2300 | 0 | // parent channel unnecessarily. |
2301 | 0 |
|
2302 | 0 | // Since this method is called from RecvRedirect3Complete which itself is |
2303 | 0 | // called from either OnRedirectVerifyCallback via OverrideRunnable, or from |
2304 | 0 | // RecvRedirect3Complete. The order of events must always be: |
2305 | 0 | // 1. Teardown the IPDL connection |
2306 | 0 | // 2. AsyncOpen the connection again |
2307 | 0 | // 3. Cleanup the redirecting channel (the one calling Redirect3Complete) |
2308 | 0 | // 4. [optional] Call OverrideWithSynthesizedResponse on the redirected |
2309 | 0 | // channel if the call came from OverrideRunnable. |
2310 | 0 | mInterceptedRedirectListener = listener; |
2311 | 0 | mInterceptedRedirectContext = aContext; |
2312 | 0 |
|
2313 | 0 | // This will send a message to the parent notifying it that we are closing |
2314 | 0 | // down. After closing the IPC channel, we will proceed to execute |
2315 | 0 | // FinishInterceptedRedirect() which AsyncOpen's the channel again. |
2316 | 0 | SendFinishInterceptedRedirect(); |
2317 | 0 |
|
2318 | 0 | // XXX valentin: The interception logic should be rewritten to avoid |
2319 | 0 | // calling AsyncOpen on the channel _after_ we call Send__delete__() |
2320 | 0 | return NS_OK; |
2321 | 0 | } |
2322 | 0 | |
2323 | 0 | /* |
2324 | 0 | * No need to check for cancel: we don't get here if nsHttpChannel canceled |
2325 | 0 | * before AsyncOpen(); if it's canceled after that, OnStart/Stop will just |
2326 | 0 | * get called with error code as usual. So just setup mListener and make the |
2327 | 0 | * channel reflect AsyncOpen'ed state. |
2328 | 0 | */ |
2329 | 0 | |
2330 | 0 | mIsPending = true; |
2331 | 0 | mWasOpened = true; |
2332 | 0 | mListener = listener; |
2333 | 0 | mListenerContext = aContext; |
2334 | 0 |
|
2335 | 0 | // add ourselves to the load group. |
2336 | 0 | if (mLoadGroup) |
2337 | 0 | mLoadGroup->AddRequest(this, nullptr); |
2338 | 0 |
|
2339 | 0 | // We already have an open IPDL connection to the parent. If on-modify-request |
2340 | 0 | // listeners or load group observers canceled us, let the parent handle it |
2341 | 0 | // and send it back to us naturally. |
2342 | 0 | return NS_OK; |
2343 | 0 | } |
2344 | | |
2345 | | //----------------------------------------------------------------------------- |
2346 | | // HttpChannelChild::nsIAsyncVerifyRedirectCallback |
2347 | | //----------------------------------------------------------------------------- |
2348 | | |
2349 | | NS_IMETHODIMP |
2350 | | HttpChannelChild::OnRedirectVerifyCallback(nsresult result) |
2351 | 0 | { |
2352 | 0 | LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this)); |
2353 | 0 | OptionalURIParams redirectURI; |
2354 | 0 | nsresult rv; |
2355 | 0 |
|
2356 | 0 | uint32_t referrerPolicy = REFERRER_POLICY_UNSET; |
2357 | 0 | OptionalURIParams referrerURI; |
2358 | 0 | SerializeURI(nullptr, referrerURI); |
2359 | 0 |
|
2360 | 0 | nsCOMPtr<nsIHttpChannel> newHttpChannel = |
2361 | 0 | do_QueryInterface(mRedirectChannelChild); |
2362 | 0 |
|
2363 | 0 | if (NS_SUCCEEDED(result) && !mRedirectChannelChild) { |
2364 | 0 | // mRedirectChannelChild doesn't exist means we're redirecting to a protocol |
2365 | 0 | // that doesn't implement nsIChildChannel. The redirect result should be set |
2366 | 0 | // as failed by veto listeners and shouldn't enter this condition. As the |
2367 | 0 | // last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here |
2368 | 0 | // to let nsHttpChannel::ContinueProcessResponse2 know it's redirecting to |
2369 | 0 | // another protocol and throw an error. |
2370 | 0 | LOG((" redirecting to a protocol that doesn't implement nsIChildChannel")); |
2371 | 0 | result = NS_ERROR_DOM_BAD_URI; |
2372 | 0 | } |
2373 | 0 |
|
2374 | 0 | if (newHttpChannel) { |
2375 | 0 | // Must not be called until after redirect observers called. |
2376 | 0 | newHttpChannel->SetOriginalURI(mOriginalURI); |
2377 | 0 |
|
2378 | 0 | rv = newHttpChannel->GetReferrerPolicy(&referrerPolicy); |
2379 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2380 | 0 | nsCOMPtr<nsIURI> newChannelReferrerURI; |
2381 | 0 | rv = newHttpChannel->GetReferrer(getter_AddRefs(newChannelReferrerURI)); |
2382 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2383 | 0 |
|
2384 | 0 | SerializeURI(newChannelReferrerURI, referrerURI); |
2385 | 0 | } |
2386 | 0 |
|
2387 | 0 | if (mRedirectingForSubsequentSynthesizedResponse) { |
2388 | 0 | nsCOMPtr<nsIHttpChannelChild> httpChannelChild = do_QueryInterface(mRedirectChannelChild); |
2389 | 0 | RefPtr<HttpChannelChild> redirectedChannel = |
2390 | 0 | static_cast<HttpChannelChild*>(httpChannelChild.get()); |
2391 | 0 | // redirectChannel will be NULL if mRedirectChannelChild isn't a |
2392 | 0 | // nsIHttpChannelChild (it could be a DataChannelChild). |
2393 | 0 |
|
2394 | 0 | RefPtr<InterceptStreamListener> streamListener = |
2395 | 0 | new InterceptStreamListener(redirectedChannel, mListenerContext); |
2396 | 0 |
|
2397 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
2398 | 0 | MOZ_ASSERT(neckoTarget); |
2399 | 0 |
|
2400 | 0 | nsCOMPtr<nsIInterceptedBodyCallback> callback = |
2401 | 0 | mSynthesizedCallback.forget(); |
2402 | 0 |
|
2403 | 0 | Unused << neckoTarget->Dispatch( |
2404 | 0 | new OverrideRunnable(this, redirectedChannel, streamListener, |
2405 | 0 | mSynthesizedInput, callback, mResponseHead, |
2406 | 0 | mSynthesizedCacheInfo), |
2407 | 0 | NS_DISPATCH_NORMAL); |
2408 | 0 |
|
2409 | 0 | return NS_OK; |
2410 | 0 | } |
2411 | 0 |
|
2412 | 0 | RequestHeaderTuples emptyHeaders; |
2413 | 0 | RequestHeaderTuples* headerTuples = &emptyHeaders; |
2414 | 0 | nsLoadFlags loadFlags = 0; |
2415 | 0 | OptionalCorsPreflightArgs corsPreflightArgs = mozilla::void_t(); |
2416 | 0 |
|
2417 | 0 | nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild = |
2418 | 0 | do_QueryInterface(mRedirectChannelChild); |
2419 | 0 | if (newHttpChannelChild && NS_SUCCEEDED(result)) { |
2420 | 0 | rv = newHttpChannelChild->AddCookiesToRequest(); |
2421 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2422 | 0 | rv = newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples); |
2423 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2424 | 0 | newHttpChannelChild->GetClientSetCorsPreflightParameters(corsPreflightArgs); |
2425 | 0 | } |
2426 | 0 |
|
2427 | 0 | /* If the redirect was canceled, bypass OMR and send an empty API |
2428 | 0 | * redirect URI */ |
2429 | 0 | SerializeURI(nullptr, redirectURI); |
2430 | 0 |
|
2431 | 0 | if (NS_SUCCEEDED(result)) { |
2432 | 0 | // Note: this is where we would notify "http-on-modify-response" observers. |
2433 | 0 | // We have deliberately disabled this for child processes (see bug 806753) |
2434 | 0 | // |
2435 | 0 | // After we verify redirect, nsHttpChannel may hit the network: must give |
2436 | 0 | // "http-on-modify-request" observers the chance to cancel before that. |
2437 | 0 | //base->CallOnModifyRequestObservers(); |
2438 | 0 |
|
2439 | 0 | nsCOMPtr<nsIHttpChannelInternal> newHttpChannelInternal = |
2440 | 0 | do_QueryInterface(mRedirectChannelChild); |
2441 | 0 | if (newHttpChannelInternal) { |
2442 | 0 | nsCOMPtr<nsIURI> apiRedirectURI; |
2443 | 0 | rv = newHttpChannelInternal->GetApiRedirectToURI( |
2444 | 0 | getter_AddRefs(apiRedirectURI)); |
2445 | 0 | if (NS_SUCCEEDED(rv) && apiRedirectURI) { |
2446 | 0 | /* If there was an API redirect of this channel, we need to send it |
2447 | 0 | * up here, since it can't be sent via SendAsyncOpen. */ |
2448 | 0 | SerializeURI(apiRedirectURI, redirectURI); |
2449 | 0 | } |
2450 | 0 | } |
2451 | 0 |
|
2452 | 0 | nsCOMPtr<nsIRequest> request = do_QueryInterface(mRedirectChannelChild); |
2453 | 0 | if (request) { |
2454 | 0 | request->GetLoadFlags(&loadFlags); |
2455 | 0 | } |
2456 | 0 | } |
2457 | 0 |
|
2458 | 0 | MaybeCallSynthesizedCallback(); |
2459 | 0 |
|
2460 | 0 | bool chooseAppcache = false; |
2461 | 0 | nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
2462 | 0 | do_QueryInterface(newHttpChannel); |
2463 | 0 | if (appCacheChannel) { |
2464 | 0 | appCacheChannel->GetChooseApplicationCache(&chooseAppcache); |
2465 | 0 | } |
2466 | 0 |
|
2467 | 0 | nsCOMPtr<nsILoadInfo> newChannelLoadInfo; |
2468 | 0 | nsCOMPtr<nsIChannel> newChannel = do_QueryInterface(mRedirectChannelChild); |
2469 | 0 | if (newChannel) { |
2470 | 0 | Unused << newChannel->GetLoadInfo(getter_AddRefs(newChannelLoadInfo)); |
2471 | 0 | } |
2472 | 0 |
|
2473 | 0 | ChildLoadInfoForwarderArgs loadInfoForwarder; |
2474 | 0 | LoadInfoToChildLoadInfoForwarder(newChannelLoadInfo, &loadInfoForwarder); |
2475 | 0 |
|
2476 | 0 | if (mIPCOpen) |
2477 | 0 | SendRedirect2Verify(result, *headerTuples, loadInfoForwarder, loadFlags, |
2478 | 0 | referrerPolicy, referrerURI, redirectURI, |
2479 | 0 | corsPreflightArgs, chooseAppcache); |
2480 | 0 |
|
2481 | 0 | return NS_OK; |
2482 | 0 | } |
2483 | | |
2484 | | //----------------------------------------------------------------------------- |
2485 | | // HttpChannelChild::nsIRequest |
2486 | | //----------------------------------------------------------------------------- |
2487 | | |
2488 | | NS_IMETHODIMP |
2489 | | HttpChannelChild::Cancel(nsresult status) |
2490 | 0 | { |
2491 | 0 | LOG(("HttpChannelChild::Cancel [this=%p, status=%" PRIx32 "]\n", |
2492 | 0 | this, static_cast<uint32_t>(status))); |
2493 | 0 | LogCallingScriptLocation(this); |
2494 | 0 |
|
2495 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2496 | 0 |
|
2497 | 0 | if (!mCanceled) { |
2498 | 0 | // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen |
2499 | 0 | // is responsible for cleaning up. |
2500 | 0 | mCanceled = true; |
2501 | 0 | mStatus = status; |
2502 | 0 | if (RemoteChannelExists()) { |
2503 | 0 | SendCancel(status); |
2504 | 0 | } |
2505 | 0 |
|
2506 | 0 | // If the channel is intercepted and already pumping, then just |
2507 | 0 | // cancel the pump. This will call OnStopRequest(). |
2508 | 0 | if (mSynthesizedResponsePump) { |
2509 | 0 | mSynthesizedResponsePump->Cancel(status); |
2510 | 0 | } |
2511 | 0 | |
2512 | 0 | // If we are canceled while intercepting, but not yet pumping, then |
2513 | 0 | // we must call AsyncAbort() to trigger OnStopRequest(). |
2514 | 0 | else if (mInterceptListener) { |
2515 | 0 | mInterceptListener->Cleanup(); |
2516 | 0 | mInterceptListener = nullptr; |
2517 | 0 | Unused << AsyncAbort(status); |
2518 | 0 | } |
2519 | 0 | } |
2520 | 0 | return NS_OK; |
2521 | 0 | } |
2522 | | |
2523 | | NS_IMETHODIMP |
2524 | | HttpChannelChild::Suspend() |
2525 | 0 | { |
2526 | 0 | LOG(("HttpChannelChild::Suspend [this=%p, mSuspendCount=%" PRIu32 ", " |
2527 | 0 | "mDivertingToParent=%d]\n", this, mSuspendCount + 1, |
2528 | 0 | static_cast<bool>(mDivertingToParent))); |
2529 | 0 | NS_ENSURE_TRUE(RemoteChannelExists() || mInterceptListener, |
2530 | 0 | NS_ERROR_NOT_AVAILABLE); |
2531 | 0 |
|
2532 | 0 | // SendSuspend only once, when suspend goes from 0 to 1. |
2533 | 0 | // Don't SendSuspend at all if we're diverting callbacks to the parent; |
2534 | 0 | // suspend will be called at the correct time in the parent itself. |
2535 | 0 | if (!mSuspendCount++ && !mDivertingToParent) { |
2536 | 0 | if (RemoteChannelExists()) { |
2537 | 0 | SendSuspend(); |
2538 | 0 | mSuspendSent = true; |
2539 | 0 | } |
2540 | 0 | } |
2541 | 0 | if (mSynthesizedResponsePump) { |
2542 | 0 | mSynthesizedResponsePump->Suspend(); |
2543 | 0 | } |
2544 | 0 | mEventQ->Suspend(); |
2545 | 0 |
|
2546 | 0 | return NS_OK; |
2547 | 0 | } |
2548 | | |
2549 | | NS_IMETHODIMP |
2550 | | HttpChannelChild::Resume() |
2551 | 0 | { |
2552 | 0 | LOG(("HttpChannelChild::Resume [this=%p, mSuspendCount=%" PRIu32 ", " |
2553 | 0 | "mDivertingToParent=%d]\n", this, mSuspendCount - 1, |
2554 | 0 | static_cast<bool>(mDivertingToParent))); |
2555 | 0 | NS_ENSURE_TRUE(RemoteChannelExists() || mInterceptListener, |
2556 | 0 | NS_ERROR_NOT_AVAILABLE); |
2557 | 0 | NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED); |
2558 | 0 |
|
2559 | 0 | nsresult rv = NS_OK; |
2560 | 0 |
|
2561 | 0 | // SendResume only once, when suspend count drops to 0. |
2562 | 0 | // Don't SendResume at all if we're diverting callbacks to the parent (unless |
2563 | 0 | // suspend was sent earlier); otherwise, resume will be called at the correct |
2564 | 0 | // time in the parent itself. |
2565 | 0 | if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) { |
2566 | 0 | if (RemoteChannelExists()) { |
2567 | 0 | SendResume(); |
2568 | 0 | } |
2569 | 0 | if (mCallOnResume) { |
2570 | 0 | rv = AsyncCall(mCallOnResume); |
2571 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2572 | 0 | mCallOnResume = nullptr; |
2573 | 0 | } |
2574 | 0 | } |
2575 | 0 | if (mSynthesizedResponsePump) { |
2576 | 0 | mSynthesizedResponsePump->Resume(); |
2577 | 0 | } |
2578 | 0 | mEventQ->Resume(); |
2579 | 0 |
|
2580 | 0 | return rv; |
2581 | 0 | } |
2582 | | |
2583 | | //----------------------------------------------------------------------------- |
2584 | | // HttpChannelChild::nsIChannel |
2585 | | //----------------------------------------------------------------------------- |
2586 | | |
2587 | | NS_IMETHODIMP |
2588 | | HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo) |
2589 | 0 | { |
2590 | 0 | NS_ENSURE_ARG_POINTER(aSecurityInfo); |
2591 | 0 | NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo); |
2592 | 0 | return NS_OK; |
2593 | 0 | } |
2594 | | |
2595 | | NS_IMETHODIMP |
2596 | | HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) |
2597 | 0 | { |
2598 | 0 | MOZ_ASSERT(!mLoadInfo || |
2599 | 0 | mLoadInfo->GetSecurityMode() == 0 || |
2600 | 0 | mLoadInfo->GetInitialSecurityCheckDone() || |
2601 | 0 | (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && |
2602 | 0 | nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())), |
2603 | 0 | "security flags in loadInfo but asyncOpen2() not called"); |
2604 | 0 |
|
2605 | 0 | LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get())); |
2606 | 0 | LogCallingScriptLocation(this); |
2607 | 0 |
|
2608 | 0 | if (!mLoadGroup && !mCallbacks) { |
2609 | 0 | // If no one called SetLoadGroup or SetNotificationCallbacks, the private |
2610 | 0 | // state has not been updated on PrivateBrowsingChannel (which we derive from) |
2611 | 0 | // Hence, we have to call UpdatePrivateBrowsing() here |
2612 | 0 | UpdatePrivateBrowsing(); |
2613 | 0 | } |
2614 | 0 |
|
2615 | | #ifdef DEBUG |
2616 | | AssertPrivateBrowsingId(); |
2617 | | #endif |
2618 | |
|
2619 | 0 | if (mCanceled) |
2620 | 0 | return mStatus; |
2621 | 0 | |
2622 | 0 | NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE); |
2623 | 0 | NS_ENSURE_ARG_POINTER(listener); |
2624 | 0 | NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS); |
2625 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); |
2626 | 0 |
|
2627 | 0 | if (MaybeWaitForUploadStreamLength(listener, aContext)) { |
2628 | 0 | return NS_OK; |
2629 | 0 | } |
2630 | 0 | |
2631 | 0 | if (!mAsyncOpenTimeOverriden) { |
2632 | 0 | mAsyncOpenTime = TimeStamp::Now(); |
2633 | 0 | } |
2634 | 0 |
|
2635 | | #ifdef MOZ_TASK_TRACER |
2636 | | if (tasktracer::IsStartLogging()) { |
2637 | | nsCOMPtr<nsIURI> uri; |
2638 | | GetURI(getter_AddRefs(uri)); |
2639 | | nsAutoCString urispec; |
2640 | | uri->GetSpec(urispec); |
2641 | | tasktracer::AddLabel("HttpChannelChild::AsyncOpen %s", urispec.get()); |
2642 | | } |
2643 | | #endif |
2644 | |
|
2645 | 0 |
|
2646 | 0 | // Port checked in parent, but duplicate here so we can return with error |
2647 | 0 | // immediately |
2648 | 0 | nsresult rv; |
2649 | 0 | rv = NS_CheckPortSafety(mURI); |
2650 | 0 | if (NS_FAILED(rv)) |
2651 | 0 | return rv; |
2652 | 0 | |
2653 | 0 | nsAutoCString cookie; |
2654 | 0 | if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Cookie, cookie))) { |
2655 | 0 | mUserSetCookieHeader = cookie; |
2656 | 0 | } |
2657 | 0 |
|
2658 | 0 | rv = AddCookiesToRequest(); |
2659 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2660 | 0 |
|
2661 | 0 | // |
2662 | 0 | // NOTE: From now on we must return NS_OK; all errors must be handled via |
2663 | 0 | // OnStart/OnStopRequest |
2664 | 0 | // |
2665 | 0 |
|
2666 | 0 | // We notify "http-on-opening-request" observers in the child |
2667 | 0 | // process so that devtools can capture a stack trace at the |
2668 | 0 | // appropriate spot. See bug 806753 for some information about why |
2669 | 0 | // other http-* notifications are disabled in child processes. |
2670 | 0 | gHttpHandler->OnOpeningRequest(this); |
2671 | 0 |
|
2672 | 0 | mLastStatusReported = TimeStamp::Now(); |
2673 | 0 | PROFILER_ADD_NETWORK_MARKER(mURI, mPriority, mChannelId, NetworkLoadType::LOAD_START, |
2674 | 0 | mChannelCreationTimestamp, mLastStatusReported, |
2675 | 0 | 0, nullptr, nullptr); |
2676 | 0 |
|
2677 | 0 | mIsPending = true; |
2678 | 0 | mWasOpened = true; |
2679 | 0 | mListener = listener; |
2680 | 0 | mListenerContext = aContext; |
2681 | 0 |
|
2682 | 0 | // add ourselves to the load group. |
2683 | 0 | if (mLoadGroup) |
2684 | 0 | mLoadGroup->AddRequest(this, nullptr); |
2685 | 0 |
|
2686 | 0 | if (mCanceled) { |
2687 | 0 | // We may have been canceled already, either by on-modify-request |
2688 | 0 | // listeners or by load group observers; in that case, don't create IPDL |
2689 | 0 | // connection. See nsHttpChannel::AsyncOpen(). |
2690 | 0 | return NS_OK; |
2691 | 0 | } |
2692 | 0 | |
2693 | 0 | // Set user agent override from docshell |
2694 | 0 | HttpBaseChannel::SetDocshellUserAgentOverride(); |
2695 | 0 |
|
2696 | 0 | MOZ_ASSERT_IF(mPostRedirectChannelShouldUpgrade, |
2697 | 0 | mPostRedirectChannelShouldIntercept); |
2698 | 0 | bool shouldUpgrade = mPostRedirectChannelShouldUpgrade; |
2699 | 0 | if (mPostRedirectChannelShouldIntercept || |
2700 | 0 | ShouldInterceptURI(mURI, shouldUpgrade)) { |
2701 | 0 | mResponseCouldBeSynthesized = true; |
2702 | 0 |
|
2703 | 0 | nsCOMPtr<nsINetworkInterceptController> controller; |
2704 | 0 | GetCallback(controller); |
2705 | 0 |
|
2706 | 0 | mInterceptListener = new InterceptStreamListener(this, mListenerContext); |
2707 | 0 |
|
2708 | 0 | RefPtr<InterceptedChannelContent> intercepted = |
2709 | 0 | new InterceptedChannelContent(this, controller, |
2710 | 0 | mInterceptListener, shouldUpgrade); |
2711 | 0 | intercepted->NotifyController(); |
2712 | 0 | return NS_OK; |
2713 | 0 | } |
2714 | 0 | |
2715 | 0 | return ContinueAsyncOpen(); |
2716 | 0 | } |
2717 | | |
2718 | | NS_IMETHODIMP |
2719 | | HttpChannelChild::AsyncOpen2(nsIStreamListener *aListener) |
2720 | 0 | { |
2721 | 0 | nsCOMPtr<nsIStreamListener> listener = aListener; |
2722 | 0 | nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); |
2723 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
2724 | 0 | ReleaseListeners(); |
2725 | 0 | return rv; |
2726 | 0 | } |
2727 | 0 | return AsyncOpen(listener, nullptr); |
2728 | 0 | } |
2729 | | |
2730 | | // Assigns an nsIEventTarget to our IPDL actor so that IPC messages are sent to |
2731 | | // the correct DocGroup/TabGroup. |
2732 | | void |
2733 | | HttpChannelChild::SetEventTarget() |
2734 | 0 | { |
2735 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
2736 | 0 | GetLoadInfo(getter_AddRefs(loadInfo)); |
2737 | 0 |
|
2738 | 0 | nsCOMPtr<nsIEventTarget> target = |
2739 | 0 | nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Network); |
2740 | 0 |
|
2741 | 0 | if (!target) { |
2742 | 0 | return; |
2743 | 0 | } |
2744 | 0 | |
2745 | 0 | gNeckoChild->SetEventTargetForActor(this, target); |
2746 | 0 |
|
2747 | 0 | { |
2748 | 0 | MutexAutoLock lock(mEventTargetMutex); |
2749 | 0 | mNeckoTarget = target; |
2750 | 0 | } |
2751 | 0 | } |
2752 | | |
2753 | | already_AddRefed<nsIEventTarget> |
2754 | | HttpChannelChild::GetNeckoTarget() |
2755 | 0 | { |
2756 | 0 | nsCOMPtr<nsIEventTarget> target; |
2757 | 0 | { |
2758 | 0 | MutexAutoLock lock(mEventTargetMutex); |
2759 | 0 | target = mNeckoTarget; |
2760 | 0 | } |
2761 | 0 |
|
2762 | 0 | if (!target) { |
2763 | 0 | target = GetMainThreadEventTarget(); |
2764 | 0 | } |
2765 | 0 | return target.forget(); |
2766 | 0 | } |
2767 | | |
2768 | | already_AddRefed<nsIEventTarget> |
2769 | | HttpChannelChild::GetODATarget() |
2770 | 0 | { |
2771 | 0 | nsCOMPtr<nsIEventTarget> target; |
2772 | 0 | { |
2773 | 0 | MutexAutoLock lock(mEventTargetMutex); |
2774 | 0 | target = mODATarget ? mODATarget : mNeckoTarget; |
2775 | 0 | } |
2776 | 0 |
|
2777 | 0 | if (!target) { |
2778 | 0 | target = GetMainThreadEventTarget(); |
2779 | 0 | } |
2780 | 0 | return target.forget(); |
2781 | 0 | } |
2782 | | |
2783 | | nsresult |
2784 | | HttpChannelChild::ContinueAsyncOpen() |
2785 | 0 | { |
2786 | 0 | nsCString appCacheClientId; |
2787 | 0 | if (mInheritApplicationCache) { |
2788 | 0 | // Pick up an application cache from the notification |
2789 | 0 | // callbacks if available |
2790 | 0 | nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer; |
2791 | 0 | GetCallback(appCacheContainer); |
2792 | 0 |
|
2793 | 0 | if (appCacheContainer) { |
2794 | 0 | nsCOMPtr<nsIApplicationCache> appCache; |
2795 | 0 | nsresult rv = appCacheContainer->GetApplicationCache(getter_AddRefs(appCache)); |
2796 | 0 | if (NS_SUCCEEDED(rv) && appCache) { |
2797 | 0 | appCache->GetClientID(appCacheClientId); |
2798 | 0 | } |
2799 | 0 | } |
2800 | 0 | } |
2801 | 0 |
|
2802 | 0 | // |
2803 | 0 | // Send request to the chrome process... |
2804 | 0 | // |
2805 | 0 |
|
2806 | 0 | mozilla::dom::TabChild* tabChild = nullptr; |
2807 | 0 | nsCOMPtr<nsITabChild> iTabChild; |
2808 | 0 | GetCallback(iTabChild); |
2809 | 0 | if (iTabChild) { |
2810 | 0 | tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get()); |
2811 | 0 | } |
2812 | 0 | if (MissingRequiredTabChild(tabChild, "http")) { |
2813 | 0 | return NS_ERROR_ILLEGAL_VALUE; |
2814 | 0 | } |
2815 | 0 | |
2816 | 0 | // This id identifies the inner window's top-level document, |
2817 | 0 | // which changes on every new load or navigation. |
2818 | 0 | uint64_t contentWindowId = 0; |
2819 | 0 | TimeStamp navigationStartTimeStamp; |
2820 | 0 | if (tabChild) { |
2821 | 0 | MOZ_ASSERT(tabChild->WebNavigation()); |
2822 | 0 | nsCOMPtr<nsIDocument> document = tabChild->GetDocument(); |
2823 | 0 | if (document) { |
2824 | 0 | contentWindowId = document->InnerWindowID(); |
2825 | 0 | nsDOMNavigationTiming* navigationTiming = document->GetNavigationTiming(); |
2826 | 0 | if (navigationTiming) { |
2827 | 0 | navigationStartTimeStamp = navigationTiming->GetNavigationStartTimeStamp(); |
2828 | 0 | } |
2829 | 0 | mTopLevelOuterContentWindowId = document->OuterWindowID(); |
2830 | 0 | } |
2831 | 0 | } |
2832 | 0 | SetTopLevelContentWindowId(contentWindowId); |
2833 | 0 |
|
2834 | 0 | HttpChannelOpenArgs openArgs; |
2835 | 0 | // No access to HttpChannelOpenArgs members, but they each have a |
2836 | 0 | // function with the struct name that returns a ref. |
2837 | 0 | SerializeURI(mURI, openArgs.uri()); |
2838 | 0 | SerializeURI(mOriginalURI, openArgs.original()); |
2839 | 0 | SerializeURI(mDocumentURI, openArgs.doc()); |
2840 | 0 | SerializeURI(mReferrer, openArgs.referrer()); |
2841 | 0 | openArgs.referrerPolicy() = mReferrerPolicy; |
2842 | 0 | SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo()); |
2843 | 0 | openArgs.loadFlags() = mLoadFlags; |
2844 | 0 | openArgs.requestHeaders() = mClientSetRequestHeaders; |
2845 | 0 | mRequestHead.Method(openArgs.requestMethod()); |
2846 | 0 | openArgs.preferredAlternativeType() = mPreferredCachedAltDataType; |
2847 | 0 |
|
2848 | 0 | AutoIPCStream autoStream(openArgs.uploadStream()); |
2849 | 0 | if (mUploadStream) { |
2850 | 0 | autoStream.Serialize(mUploadStream, ContentChild::GetSingleton()); |
2851 | 0 | autoStream.TakeOptionalValue(); |
2852 | 0 | } |
2853 | 0 |
|
2854 | 0 | if (mResponseHead) { |
2855 | 0 | openArgs.synthesizedResponseHead() = *mResponseHead; |
2856 | 0 | openArgs.suspendAfterSynthesizeResponse() = |
2857 | 0 | mSuspendParentAfterSynthesizeResponse; |
2858 | 0 | } else { |
2859 | 0 | openArgs.synthesizedResponseHead() = mozilla::void_t(); |
2860 | 0 | openArgs.suspendAfterSynthesizeResponse() = false; |
2861 | 0 | } |
2862 | 0 |
|
2863 | 0 | nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(mSecurityInfo); |
2864 | 0 | if (secInfoSer) { |
2865 | 0 | NS_SerializeToString(secInfoSer, openArgs.synthesizedSecurityInfoSerialization()); |
2866 | 0 | } |
2867 | 0 |
|
2868 | 0 | OptionalCorsPreflightArgs optionalCorsPreflightArgs; |
2869 | 0 | GetClientSetCorsPreflightParameters(optionalCorsPreflightArgs); |
2870 | 0 |
|
2871 | 0 | // NB: This call forces us to cache mTopWindowURI if we haven't already. |
2872 | 0 | nsCOMPtr<nsIURI> uri; |
2873 | 0 | GetTopWindowURI(getter_AddRefs(uri)); |
2874 | 0 |
|
2875 | 0 | SerializeURI(mTopWindowURI, openArgs.topWindowURI()); |
2876 | 0 |
|
2877 | 0 | openArgs.preflightArgs() = optionalCorsPreflightArgs; |
2878 | 0 |
|
2879 | 0 | openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders; |
2880 | 0 | openArgs.priority() = mPriority; |
2881 | 0 | openArgs.classOfService() = mClassOfService; |
2882 | 0 | openArgs.redirectionLimit() = mRedirectionLimit; |
2883 | 0 | openArgs.allowSTS() = mAllowSTS; |
2884 | 0 | openArgs.thirdPartyFlags() = mThirdPartyFlags; |
2885 | 0 | openArgs.resumeAt() = mSendResumeAt; |
2886 | 0 | openArgs.startPos() = mStartPos; |
2887 | 0 | openArgs.entityID() = mEntityID; |
2888 | 0 | openArgs.chooseApplicationCache() = mChooseApplicationCache; |
2889 | 0 | openArgs.appCacheClientID() = appCacheClientId; |
2890 | 0 | openArgs.allowSpdy() = mAllowSpdy; |
2891 | 0 | openArgs.allowAltSvc() = mAllowAltSvc; |
2892 | 0 | openArgs.beConservative() = mBeConservative; |
2893 | 0 | openArgs.tlsFlags() = mTlsFlags; |
2894 | 0 | openArgs.initialRwin() = mInitialRwin; |
2895 | 0 |
|
2896 | 0 | openArgs.cacheKey() = mCacheKey; |
2897 | 0 |
|
2898 | 0 | openArgs.blockAuthPrompt() = mBlockAuthPrompt; |
2899 | 0 |
|
2900 | 0 | openArgs.allowStaleCacheContent() = mAllowStaleCacheContent; |
2901 | 0 |
|
2902 | 0 | openArgs.contentTypeHint() = mContentTypeHint; |
2903 | 0 |
|
2904 | 0 | nsresult rv = mozilla::ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &openArgs.loadInfo()); |
2905 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2906 | 0 |
|
2907 | 0 | EnsureRequestContextID(); |
2908 | 0 | openArgs.requestContextID() = mRequestContextID; |
2909 | 0 |
|
2910 | 0 | openArgs.corsMode() = mCorsMode; |
2911 | 0 | openArgs.redirectMode() = mRedirectMode; |
2912 | 0 |
|
2913 | 0 | openArgs.channelId() = mChannelId; |
2914 | 0 |
|
2915 | 0 | openArgs.integrityMetadata() = mIntegrityMetadata; |
2916 | 0 |
|
2917 | 0 | openArgs.contentWindowId() = contentWindowId; |
2918 | 0 | openArgs.topLevelOuterContentWindowId() = mTopLevelOuterContentWindowId; |
2919 | 0 |
|
2920 | 0 | LOG(("HttpChannelChild::ContinueAsyncOpen this=%p gid=%" PRIu64 " topwinid=%" PRIx64, |
2921 | 0 | this, mChannelId, mTopLevelOuterContentWindowId)); |
2922 | 0 |
|
2923 | 0 | if (tabChild && !tabChild->IPCOpen()) { |
2924 | 0 | return NS_ERROR_FAILURE; |
2925 | 0 | } |
2926 | 0 | |
2927 | 0 | ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager()); |
2928 | 0 | if (cc->IsShuttingDown()) { |
2929 | 0 | return NS_ERROR_FAILURE; |
2930 | 0 | } |
2931 | 0 | |
2932 | 0 | openArgs.launchServiceWorkerStart() = mLaunchServiceWorkerStart; |
2933 | 0 | openArgs.launchServiceWorkerEnd() = mLaunchServiceWorkerEnd; |
2934 | 0 | openArgs.dispatchFetchEventStart() = mDispatchFetchEventStart; |
2935 | 0 | openArgs.dispatchFetchEventEnd() = mDispatchFetchEventEnd; |
2936 | 0 | openArgs.handleFetchEventStart() = mHandleFetchEventStart; |
2937 | 0 | openArgs.handleFetchEventEnd() = mHandleFetchEventEnd; |
2938 | 0 |
|
2939 | 0 | openArgs.forceMainDocumentChannel() = mForceMainDocumentChannel; |
2940 | 0 |
|
2941 | 0 | openArgs.navigationStartTimeStamp() = navigationStartTimeStamp; |
2942 | 0 |
|
2943 | 0 | // This must happen before the constructor message is sent. Otherwise messages |
2944 | 0 | // from the parent could arrive quickly and be delivered to the wrong event |
2945 | 0 | // target. |
2946 | 0 | SetEventTarget(); |
2947 | 0 |
|
2948 | 0 | // The socket transport in the chrome process now holds a logical ref to us |
2949 | 0 | // until OnStopRequest, or we do a redirect, or we hit an IPDL error. |
2950 | 0 | AddIPDLReference(); |
2951 | 0 |
|
2952 | 0 | PBrowserOrId browser = cc->GetBrowserOrId(tabChild); |
2953 | 0 | if (!gNeckoChild->SendPHttpChannelConstructor(this, browser, |
2954 | 0 | IPC::SerializedLoadContext(this), |
2955 | 0 | openArgs)) { |
2956 | 0 | return NS_ERROR_FAILURE; |
2957 | 0 | } |
2958 | 0 | |
2959 | 0 | { |
2960 | 0 | MutexAutoLock lock(mBgChildMutex); |
2961 | 0 |
|
2962 | 0 | MOZ_RELEASE_ASSERT(gSocketTransportService); |
2963 | 0 |
|
2964 | 0 | // Service worker might use the same HttpChannelChild to do async open |
2965 | 0 | // twice. Need to disconnect with previous background channel before |
2966 | 0 | // creating the new one, to prevent receiving further notification |
2967 | 0 | // from it. |
2968 | 0 | if (mBgChild) { |
2969 | 0 | RefPtr<HttpBackgroundChannelChild> prevBgChild = mBgChild.forget(); |
2970 | 0 | gSocketTransportService->Dispatch( |
2971 | 0 | NewRunnableMethod( |
2972 | 0 | "HttpBackgroundChannelChild::OnChannelClosed", |
2973 | 0 | prevBgChild, &HttpBackgroundChannelChild::OnChannelClosed), |
2974 | 0 | NS_DISPATCH_NORMAL); |
2975 | 0 | } |
2976 | 0 |
|
2977 | 0 | MOZ_ASSERT(!mBgInitFailCallback); |
2978 | 0 |
|
2979 | 0 | mBgInitFailCallback = NewRunnableMethod<nsresult>( |
2980 | 0 | "HttpChannelChild::FailedAsyncOpen", |
2981 | 0 | this, &HttpChannelChild::FailedAsyncOpen, |
2982 | 0 | NS_ERROR_FAILURE); |
2983 | 0 |
|
2984 | 0 | RefPtr<HttpBackgroundChannelChild> bgChild = |
2985 | 0 | new HttpBackgroundChannelChild(); |
2986 | 0 |
|
2987 | 0 | RefPtr<HttpChannelChild> self = this; |
2988 | 0 | nsresult rv = |
2989 | 0 | gSocketTransportService->Dispatch( |
2990 | 0 | NewRunnableMethod<RefPtr<HttpChannelChild>>( |
2991 | 0 | "HttpBackgroundChannelChild::Init", |
2992 | 0 | bgChild, &HttpBackgroundChannelChild::Init, self), |
2993 | 0 | NS_DISPATCH_NORMAL); |
2994 | 0 |
|
2995 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
2996 | 0 | return rv; |
2997 | 0 | } |
2998 | 0 | |
2999 | 0 | mBgChild = bgChild.forget(); |
3000 | 0 | } |
3001 | 0 |
|
3002 | 0 | return NS_OK; |
3003 | 0 | } |
3004 | | |
3005 | | //----------------------------------------------------------------------------- |
3006 | | // HttpChannelChild::nsIHttpChannel |
3007 | | //----------------------------------------------------------------------------- |
3008 | | |
3009 | | NS_IMETHODIMP |
3010 | | HttpChannelChild::SetReferrerWithPolicy(nsIURI *referrer, |
3011 | | uint32_t referrerPolicy) |
3012 | 0 | { |
3013 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
3014 | 0 |
|
3015 | 0 | // remove old referrer if any, loop backwards |
3016 | 0 | for (int i = mClientSetRequestHeaders.Length() - 1; i >= 0; --i) { |
3017 | 0 | if (NS_LITERAL_CSTRING("Referer").Equals(mClientSetRequestHeaders[i].mHeader)) { |
3018 | 0 | mClientSetRequestHeaders.RemoveElementAt(i); |
3019 | 0 | } |
3020 | 0 | } |
3021 | 0 |
|
3022 | 0 | nsresult rv = HttpBaseChannel::SetReferrerWithPolicy(referrer, referrerPolicy); |
3023 | 0 | if (NS_FAILED(rv)) |
3024 | 0 | return rv; |
3025 | 0 | return NS_OK; |
3026 | 0 |
|
3027 | 0 | } |
3028 | | NS_IMETHODIMP |
3029 | | HttpChannelChild::SetRequestHeader(const nsACString& aHeader, |
3030 | | const nsACString& aValue, |
3031 | | bool aMerge) |
3032 | 0 | { |
3033 | 0 | LOG(("HttpChannelChild::SetRequestHeader [this=%p]\n", this)); |
3034 | 0 | nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge); |
3035 | 0 | if (NS_FAILED(rv)) |
3036 | 0 | return rv; |
3037 | 0 | |
3038 | 0 | RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement(); |
3039 | 0 | if (!tuple) |
3040 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
3041 | 0 | |
3042 | 0 | tuple->mHeader = aHeader; |
3043 | 0 | tuple->mValue = aValue; |
3044 | 0 | tuple->mMerge = aMerge; |
3045 | 0 | tuple->mEmpty = false; |
3046 | 0 | return NS_OK; |
3047 | 0 | } |
3048 | | |
3049 | | NS_IMETHODIMP |
3050 | | HttpChannelChild::SetEmptyRequestHeader(const nsACString& aHeader) |
3051 | 0 | { |
3052 | 0 | LOG(("HttpChannelChild::SetEmptyRequestHeader [this=%p]\n", this)); |
3053 | 0 | nsresult rv = HttpBaseChannel::SetEmptyRequestHeader(aHeader); |
3054 | 0 | if (NS_FAILED(rv)) |
3055 | 0 | return rv; |
3056 | 0 | |
3057 | 0 | RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement(); |
3058 | 0 | if (!tuple) |
3059 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
3060 | 0 | |
3061 | 0 | tuple->mHeader = aHeader; |
3062 | 0 | tuple->mMerge = false; |
3063 | 0 | tuple->mEmpty = true; |
3064 | 0 | return NS_OK; |
3065 | 0 | } |
3066 | | |
3067 | | NS_IMETHODIMP |
3068 | | HttpChannelChild::RedirectTo(nsIURI *newURI) |
3069 | 0 | { |
3070 | 0 | // disabled until/unless addons run in child or something else needs this |
3071 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
3072 | 0 | } |
3073 | | |
3074 | | NS_IMETHODIMP |
3075 | | HttpChannelChild::UpgradeToSecure() |
3076 | 0 | { |
3077 | 0 | // disabled until/unless addons run in child or something else needs this |
3078 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
3079 | 0 | } |
3080 | | |
3081 | | NS_IMETHODIMP |
3082 | | HttpChannelChild::GetProtocolVersion(nsACString& aProtocolVersion) |
3083 | 0 | { |
3084 | 0 | aProtocolVersion = mProtocolVersion; |
3085 | 0 | return NS_OK; |
3086 | 0 | } |
3087 | | |
3088 | | //----------------------------------------------------------------------------- |
3089 | | // HttpChannelChild::nsIHttpChannelInternal |
3090 | | //----------------------------------------------------------------------------- |
3091 | | |
3092 | | NS_IMETHODIMP |
3093 | | HttpChannelChild::SetupFallbackChannel(const char *aFallbackKey) |
3094 | 0 | { |
3095 | 0 | DROP_DEAD(); |
3096 | 0 | } |
3097 | | |
3098 | | //----------------------------------------------------------------------------- |
3099 | | // HttpChannelChild::nsICacheInfoChannel |
3100 | | //----------------------------------------------------------------------------- |
3101 | | |
3102 | | NS_IMETHODIMP |
3103 | | HttpChannelChild::GetCacheTokenFetchCount(int32_t *_retval) |
3104 | 0 | { |
3105 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
3106 | 0 |
|
3107 | 0 | if (mSynthesizedCacheInfo) { |
3108 | 0 | return mSynthesizedCacheInfo->GetCacheTokenFetchCount(_retval); |
3109 | 0 | } |
3110 | 0 | |
3111 | 0 | if (!mCacheEntryAvailable && !mAltDataCacheEntryAvailable) { |
3112 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3113 | 0 | } |
3114 | 0 | |
3115 | 0 | *_retval = mCacheFetchCount; |
3116 | 0 | return NS_OK; |
3117 | 0 | } |
3118 | | |
3119 | | NS_IMETHODIMP |
3120 | | HttpChannelChild::GetCacheTokenExpirationTime(uint32_t *_retval) |
3121 | 0 | { |
3122 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
3123 | 0 |
|
3124 | 0 | if (mSynthesizedCacheInfo) { |
3125 | 0 | return mSynthesizedCacheInfo->GetCacheTokenExpirationTime(_retval); |
3126 | 0 | } |
3127 | 0 | |
3128 | 0 | if (!mCacheEntryAvailable) |
3129 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3130 | 0 | |
3131 | 0 | *_retval = mCacheExpirationTime; |
3132 | 0 | return NS_OK; |
3133 | 0 | } |
3134 | | |
3135 | | NS_IMETHODIMP |
3136 | | HttpChannelChild::GetCacheTokenCachedCharset(nsACString &_retval) |
3137 | 0 | { |
3138 | 0 | if (mSynthesizedCacheInfo) { |
3139 | 0 | return mSynthesizedCacheInfo->GetCacheTokenCachedCharset(_retval); |
3140 | 0 | } |
3141 | 0 | |
3142 | 0 | if (!mCacheEntryAvailable) |
3143 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3144 | 0 | |
3145 | 0 | _retval = mCachedCharset; |
3146 | 0 | return NS_OK; |
3147 | 0 | } |
3148 | | NS_IMETHODIMP |
3149 | | HttpChannelChild::SetCacheTokenCachedCharset(const nsACString &aCharset) |
3150 | 0 | { |
3151 | 0 | if (mSynthesizedCacheInfo) { |
3152 | 0 | return mSynthesizedCacheInfo->SetCacheTokenCachedCharset(aCharset); |
3153 | 0 | } |
3154 | 0 | |
3155 | 0 | if (!mCacheEntryAvailable || !RemoteChannelExists()) |
3156 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3157 | 0 | |
3158 | 0 | mCachedCharset = aCharset; |
3159 | 0 | if (!SendSetCacheTokenCachedCharset(PromiseFlatCString(aCharset))) { |
3160 | 0 | return NS_ERROR_FAILURE; |
3161 | 0 | } |
3162 | 0 | return NS_OK; |
3163 | 0 | } |
3164 | | |
3165 | | NS_IMETHODIMP |
3166 | | HttpChannelChild::IsFromCache(bool *value) |
3167 | 0 | { |
3168 | 0 | if (mSynthesizedCacheInfo) { |
3169 | 0 | return mSynthesizedCacheInfo->IsFromCache(value); |
3170 | 0 | } |
3171 | 0 | |
3172 | 0 | if (!mIsPending) |
3173 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3174 | 0 | |
3175 | 0 | *value = mIsFromCache; |
3176 | 0 | return NS_OK; |
3177 | 0 | } |
3178 | | |
3179 | | NS_IMETHODIMP |
3180 | | HttpChannelChild::GetCacheEntryId(uint64_t *aCacheEntryId) |
3181 | 0 | { |
3182 | 0 | if (mSynthesizedCacheInfo) { |
3183 | 0 | return mSynthesizedCacheInfo->GetCacheEntryId(aCacheEntryId); |
3184 | 0 | } |
3185 | 0 | |
3186 | 0 | bool fromCache = false; |
3187 | 0 | if (NS_FAILED(IsFromCache(&fromCache)) || |
3188 | 0 | !fromCache || |
3189 | 0 | !mCacheEntryAvailable) { |
3190 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3191 | 0 | } |
3192 | 0 | |
3193 | 0 | *aCacheEntryId = mCacheEntryId; |
3194 | 0 | return NS_OK; |
3195 | 0 | } |
3196 | | |
3197 | | NS_IMETHODIMP |
3198 | | HttpChannelChild::GetCacheKey(uint32_t *cacheKey) |
3199 | 0 | { |
3200 | 0 | if (mSynthesizedCacheInfo) { |
3201 | 0 | return mSynthesizedCacheInfo->GetCacheKey(cacheKey); |
3202 | 0 | } |
3203 | 0 | |
3204 | 0 | *cacheKey = mCacheKey; |
3205 | 0 | return NS_OK; |
3206 | 0 | } |
3207 | | NS_IMETHODIMP |
3208 | | HttpChannelChild::SetCacheKey(uint32_t cacheKey) |
3209 | 0 | { |
3210 | 0 | if (mSynthesizedCacheInfo) { |
3211 | 0 | return mSynthesizedCacheInfo->SetCacheKey(cacheKey); |
3212 | 0 | } |
3213 | 0 | |
3214 | 0 | ENSURE_CALLED_BEFORE_ASYNC_OPEN(); |
3215 | 0 |
|
3216 | 0 | mCacheKey = cacheKey; |
3217 | 0 | return NS_OK; |
3218 | 0 | } |
3219 | | |
3220 | | NS_IMETHODIMP |
3221 | | HttpChannelChild::SetAllowStaleCacheContent(bool aAllowStaleCacheContent) |
3222 | 0 | { |
3223 | 0 | if (mSynthesizedCacheInfo) { |
3224 | 0 | return mSynthesizedCacheInfo->SetAllowStaleCacheContent(aAllowStaleCacheContent); |
3225 | 0 | } |
3226 | 0 | |
3227 | 0 | mAllowStaleCacheContent = aAllowStaleCacheContent; |
3228 | 0 | return NS_OK; |
3229 | 0 | } |
3230 | | NS_IMETHODIMP |
3231 | | HttpChannelChild::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent) |
3232 | 0 | { |
3233 | 0 | if (mSynthesizedCacheInfo) { |
3234 | 0 | return mSynthesizedCacheInfo->GetAllowStaleCacheContent(aAllowStaleCacheContent); |
3235 | 0 | } |
3236 | 0 | |
3237 | 0 | NS_ENSURE_ARG(aAllowStaleCacheContent); |
3238 | 0 | *aAllowStaleCacheContent = mAllowStaleCacheContent; |
3239 | 0 | return NS_OK; |
3240 | 0 | } |
3241 | | |
3242 | | NS_IMETHODIMP |
3243 | | HttpChannelChild::PreferAlternativeDataType(const nsACString & aType) |
3244 | 0 | { |
3245 | 0 | ENSURE_CALLED_BEFORE_ASYNC_OPEN(); |
3246 | 0 |
|
3247 | 0 | if (mSynthesizedCacheInfo) { |
3248 | 0 | return mSynthesizedCacheInfo->PreferAlternativeDataType(aType); |
3249 | 0 | } |
3250 | 0 | |
3251 | 0 | mPreferredCachedAltDataType = aType; |
3252 | 0 | return NS_OK; |
3253 | 0 | } |
3254 | | |
3255 | | NS_IMETHODIMP |
3256 | | HttpChannelChild::GetPreferredAlternativeDataType(nsACString & aType) |
3257 | 0 | { |
3258 | 0 | aType = mPreferredCachedAltDataType; |
3259 | 0 | return NS_OK; |
3260 | 0 | } |
3261 | | |
3262 | | NS_IMETHODIMP |
3263 | | HttpChannelChild::GetAlternativeDataType(nsACString & aType) |
3264 | 0 | { |
3265 | 0 | if (mSynthesizedCacheInfo) { |
3266 | 0 | return mSynthesizedCacheInfo->GetAlternativeDataType(aType); |
3267 | 0 | } |
3268 | 0 | |
3269 | 0 | // Must be called during or after OnStartRequest |
3270 | 0 | if (!mAfterOnStartRequestBegun) { |
3271 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3272 | 0 | } |
3273 | 0 | |
3274 | 0 | aType = mAvailableCachedAltDataType; |
3275 | 0 | return NS_OK; |
3276 | 0 | } |
3277 | | |
3278 | | NS_IMETHODIMP |
3279 | | HttpChannelChild::OpenAlternativeOutputStream(const nsACString & aType, int64_t aPredictedSize, nsIOutputStream * *_retval) |
3280 | 0 | { |
3281 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); |
3282 | 0 |
|
3283 | 0 | if (mSynthesizedCacheInfo) { |
3284 | 0 | return mSynthesizedCacheInfo->OpenAlternativeOutputStream(aType, aPredictedSize, _retval); |
3285 | 0 | } |
3286 | 0 | |
3287 | 0 | if (!mIPCOpen) { |
3288 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3289 | 0 | } |
3290 | 0 | if (static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown()) { |
3291 | 0 | return NS_ERROR_NOT_AVAILABLE; |
3292 | 0 | } |
3293 | 0 | |
3294 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
3295 | 0 | MOZ_ASSERT(neckoTarget); |
3296 | 0 |
|
3297 | 0 | RefPtr<AltDataOutputStreamChild> stream = new AltDataOutputStreamChild(); |
3298 | 0 | stream->AddIPDLReference(); |
3299 | 0 |
|
3300 | 0 | gNeckoChild->SetEventTargetForActor(stream, neckoTarget); |
3301 | 0 |
|
3302 | 0 | if (!gNeckoChild->SendPAltDataOutputStreamConstructor(stream, |
3303 | 0 | nsCString(aType), |
3304 | 0 | aPredictedSize, |
3305 | 0 | this)) { |
3306 | 0 | return NS_ERROR_FAILURE; |
3307 | 0 | } |
3308 | 0 | |
3309 | 0 | stream.forget(_retval); |
3310 | 0 | return NS_OK; |
3311 | 0 | } |
3312 | | |
3313 | | //----------------------------------------------------------------------------- |
3314 | | // HttpChannelChild::nsIResumableChannel |
3315 | | //----------------------------------------------------------------------------- |
3316 | | |
3317 | | NS_IMETHODIMP |
3318 | | HttpChannelChild::ResumeAt(uint64_t startPos, const nsACString& entityID) |
3319 | 0 | { |
3320 | 0 | LOG(("HttpChannelChild::ResumeAt [this=%p]\n", this)); |
3321 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
3322 | 0 | mStartPos = startPos; |
3323 | 0 | mEntityID = entityID; |
3324 | 0 | mSendResumeAt = true; |
3325 | 0 | return NS_OK; |
3326 | 0 | } |
3327 | | |
3328 | | // GetEntityID is shared in HttpBaseChannel |
3329 | | |
3330 | | //----------------------------------------------------------------------------- |
3331 | | // HttpChannelChild::nsISupportsPriority |
3332 | | //----------------------------------------------------------------------------- |
3333 | | |
3334 | | NS_IMETHODIMP |
3335 | | HttpChannelChild::SetPriority(int32_t aPriority) |
3336 | 0 | { |
3337 | 0 | LOG(("HttpChannelChild::SetPriority %p p=%d", this, aPriority)); |
3338 | 0 |
|
3339 | 0 | int16_t newValue = clamped<int32_t>(aPriority, INT16_MIN, INT16_MAX); |
3340 | 0 | if (mPriority == newValue) |
3341 | 0 | return NS_OK; |
3342 | 0 | mPriority = newValue; |
3343 | 0 | if (RemoteChannelExists()) |
3344 | 0 | SendSetPriority(mPriority); |
3345 | 0 | return NS_OK; |
3346 | 0 | } |
3347 | | |
3348 | | //----------------------------------------------------------------------------- |
3349 | | // HttpChannelChild::nsIClassOfService |
3350 | | //----------------------------------------------------------------------------- |
3351 | | NS_IMETHODIMP |
3352 | | HttpChannelChild::SetClassFlags(uint32_t inFlags) |
3353 | 0 | { |
3354 | 0 | if (mClassOfService == inFlags) { |
3355 | 0 | return NS_OK; |
3356 | 0 | } |
3357 | 0 | |
3358 | 0 | mClassOfService = inFlags; |
3359 | 0 |
|
3360 | 0 | LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService)); |
3361 | 0 |
|
3362 | 0 | if (RemoteChannelExists()) { |
3363 | 0 | SendSetClassOfService(mClassOfService); |
3364 | 0 | } |
3365 | 0 | return NS_OK; |
3366 | 0 | } |
3367 | | |
3368 | | NS_IMETHODIMP |
3369 | | HttpChannelChild::AddClassFlags(uint32_t inFlags) |
3370 | 0 | { |
3371 | 0 | mClassOfService |= inFlags; |
3372 | 0 |
|
3373 | 0 | LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService)); |
3374 | 0 |
|
3375 | 0 | if (RemoteChannelExists()) { |
3376 | 0 | SendSetClassOfService(mClassOfService); |
3377 | 0 | } |
3378 | 0 | return NS_OK; |
3379 | 0 | } |
3380 | | |
3381 | | NS_IMETHODIMP |
3382 | | HttpChannelChild::ClearClassFlags(uint32_t inFlags) |
3383 | 0 | { |
3384 | 0 | mClassOfService &= ~inFlags; |
3385 | 0 |
|
3386 | 0 | LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService)); |
3387 | 0 |
|
3388 | 0 | if (RemoteChannelExists()) { |
3389 | 0 | SendSetClassOfService(mClassOfService); |
3390 | 0 | } |
3391 | 0 | return NS_OK; |
3392 | 0 | } |
3393 | | |
3394 | | //----------------------------------------------------------------------------- |
3395 | | // HttpChannelChild::nsIProxiedChannel |
3396 | | //----------------------------------------------------------------------------- |
3397 | | |
3398 | | NS_IMETHODIMP |
3399 | | HttpChannelChild::GetProxyInfo(nsIProxyInfo **aProxyInfo) |
3400 | 0 | { |
3401 | 0 | DROP_DEAD(); |
3402 | 0 | } |
3403 | | |
3404 | | //----------------------------------------------------------------------------- |
3405 | | // HttpChannelChild::nsIApplicationCacheContainer |
3406 | | //----------------------------------------------------------------------------- |
3407 | | |
3408 | | NS_IMETHODIMP |
3409 | | HttpChannelChild::GetApplicationCache(nsIApplicationCache **aApplicationCache) |
3410 | 0 | { |
3411 | 0 | NS_IF_ADDREF(*aApplicationCache = mApplicationCache); |
3412 | 0 | return NS_OK; |
3413 | 0 | } |
3414 | | NS_IMETHODIMP |
3415 | | HttpChannelChild::SetApplicationCache(nsIApplicationCache *aApplicationCache) |
3416 | 0 | { |
3417 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); |
3418 | 0 |
|
3419 | 0 | mApplicationCache = aApplicationCache; |
3420 | 0 | return NS_OK; |
3421 | 0 | } |
3422 | | |
3423 | | //----------------------------------------------------------------------------- |
3424 | | // HttpChannelChild::nsIApplicationCacheChannel |
3425 | | //----------------------------------------------------------------------------- |
3426 | | |
3427 | | NS_IMETHODIMP |
3428 | | HttpChannelChild::GetApplicationCacheForWrite(nsIApplicationCache **aApplicationCache) |
3429 | 0 | { |
3430 | 0 | *aApplicationCache = nullptr; |
3431 | 0 | return NS_OK; |
3432 | 0 | } |
3433 | | NS_IMETHODIMP |
3434 | | HttpChannelChild::SetApplicationCacheForWrite(nsIApplicationCache *aApplicationCache) |
3435 | 0 | { |
3436 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); |
3437 | 0 |
|
3438 | 0 | // Child channels are not intended to be used for cache writes |
3439 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
3440 | 0 | } |
3441 | | |
3442 | | NS_IMETHODIMP |
3443 | | HttpChannelChild::GetLoadedFromApplicationCache(bool *aLoadedFromApplicationCache) |
3444 | 0 | { |
3445 | 0 | *aLoadedFromApplicationCache = mLoadedFromApplicationCache; |
3446 | 0 | return NS_OK; |
3447 | 0 | } |
3448 | | |
3449 | | NS_IMETHODIMP |
3450 | | HttpChannelChild::GetInheritApplicationCache(bool *aInherit) |
3451 | 0 | { |
3452 | 0 | *aInherit = mInheritApplicationCache; |
3453 | 0 | return NS_OK; |
3454 | 0 | } |
3455 | | NS_IMETHODIMP |
3456 | | HttpChannelChild::SetInheritApplicationCache(bool aInherit) |
3457 | 0 | { |
3458 | 0 | mInheritApplicationCache = aInherit; |
3459 | 0 | return NS_OK; |
3460 | 0 | } |
3461 | | |
3462 | | NS_IMETHODIMP |
3463 | | HttpChannelChild::GetChooseApplicationCache(bool *aChoose) |
3464 | 0 | { |
3465 | 0 | *aChoose = mChooseApplicationCache; |
3466 | 0 | return NS_OK; |
3467 | 0 | } |
3468 | | |
3469 | | NS_IMETHODIMP |
3470 | | HttpChannelChild::SetChooseApplicationCache(bool aChoose) |
3471 | 0 | { |
3472 | 0 | mChooseApplicationCache = aChoose; |
3473 | 0 | return NS_OK; |
3474 | 0 | } |
3475 | | |
3476 | | NS_IMETHODIMP |
3477 | | HttpChannelChild::MarkOfflineCacheEntryAsForeign() |
3478 | 0 | { |
3479 | 0 | SendMarkOfflineCacheEntryAsForeign(); |
3480 | 0 | return NS_OK; |
3481 | 0 | } |
3482 | | |
3483 | | //----------------------------------------------------------------------------- |
3484 | | // HttpChannelChild::nsIHttpChannelChild |
3485 | | //----------------------------------------------------------------------------- |
3486 | | |
3487 | | NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest() |
3488 | 0 | { |
3489 | 0 | HttpBaseChannel::AddCookiesToRequest(); |
3490 | 0 | return NS_OK; |
3491 | 0 | } |
3492 | | |
3493 | | NS_IMETHODIMP HttpChannelChild::GetClientSetRequestHeaders(RequestHeaderTuples **aRequestHeaders) |
3494 | 0 | { |
3495 | 0 | *aRequestHeaders = &mClientSetRequestHeaders; |
3496 | 0 | return NS_OK; |
3497 | 0 | } |
3498 | | |
3499 | | void |
3500 | | HttpChannelChild::GetClientSetCorsPreflightParameters(OptionalCorsPreflightArgs& aArgs) |
3501 | 0 | { |
3502 | 0 | if (mRequireCORSPreflight) { |
3503 | 0 | CorsPreflightArgs args; |
3504 | 0 | args.unsafeHeaders() = mUnsafeHeaders; |
3505 | 0 | aArgs = args; |
3506 | 0 | } else { |
3507 | 0 | aArgs = mozilla::void_t(); |
3508 | 0 | } |
3509 | 0 | } |
3510 | | |
3511 | | NS_IMETHODIMP |
3512 | | HttpChannelChild::RemoveCorsPreflightCacheEntry(nsIURI* aURI, |
3513 | | nsIPrincipal* aPrincipal) |
3514 | 0 | { |
3515 | 0 | URIParams uri; |
3516 | 0 | SerializeURI(aURI, uri); |
3517 | 0 | PrincipalInfo principalInfo; |
3518 | 0 | nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo); |
3519 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
3520 | 0 | return rv; |
3521 | 0 | } |
3522 | 0 | bool result = false; |
3523 | 0 | // Be careful to not attempt to send a message to the parent after the |
3524 | 0 | // actor has been destroyed. |
3525 | 0 | if (mIPCOpen) { |
3526 | 0 | result = SendRemoveCorsPreflightCacheEntry(uri, principalInfo); |
3527 | 0 | } |
3528 | 0 | return result ? NS_OK : NS_ERROR_FAILURE; |
3529 | 0 | } |
3530 | | |
3531 | | //----------------------------------------------------------------------------- |
3532 | | // HttpChannelChild::nsIDivertableChannel |
3533 | | //----------------------------------------------------------------------------- |
3534 | | NS_IMETHODIMP |
3535 | | HttpChannelChild::DivertToParent(ChannelDiverterChild **aChild) |
3536 | 0 | { |
3537 | 0 | LOG(("HttpChannelChild::DivertToParent [this=%p]\n", this)); |
3538 | 0 | MOZ_RELEASE_ASSERT(aChild); |
3539 | 0 | MOZ_RELEASE_ASSERT(gNeckoChild); |
3540 | 0 | MOZ_RELEASE_ASSERT(!mDivertingToParent); |
3541 | 0 |
|
3542 | 0 | nsresult rv = NS_OK; |
3543 | 0 |
|
3544 | 0 | // If the channel was intercepted, then we likely do not have an IPC actor |
3545 | 0 | // yet. We need one, though, in order to have a parent side to divert to. |
3546 | 0 | // Therefore, create the actor just in time for us to suspend and divert it. |
3547 | 0 | if (mSynthesizedResponse && !RemoteChannelExists()) { |
3548 | 0 | mSuspendParentAfterSynthesizeResponse = true; |
3549 | 0 | rv = ContinueAsyncOpen(); |
3550 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3551 | 0 | } |
3552 | 0 |
|
3553 | 0 | // We must fail DivertToParent() if there's no parent end of the channel (and |
3554 | 0 | // won't be!) due to early failure. |
3555 | 0 | if (NS_FAILED(mStatus) && !RemoteChannelExists()) { |
3556 | 0 | return mStatus; |
3557 | 0 | } |
3558 | 0 | |
3559 | 0 | // Once this is set, it should not be unset before the child is taken down. |
3560 | 0 | mDivertingToParent = true; |
3561 | 0 |
|
3562 | 0 | rv = Suspend(); |
3563 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
3564 | 0 | return rv; |
3565 | 0 | } |
3566 | 0 | if (static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown()) { |
3567 | 0 | return NS_ERROR_FAILURE; |
3568 | 0 | } |
3569 | 0 | |
3570 | 0 | HttpChannelDiverterArgs args; |
3571 | 0 | args.mChannelChild() = this; |
3572 | 0 | args.mApplyConversion() = mApplyConversion; |
3573 | 0 |
|
3574 | 0 | PChannelDiverterChild* diverter = |
3575 | 0 | gNeckoChild->SendPChannelDiverterConstructor(args); |
3576 | 0 | MOZ_RELEASE_ASSERT(diverter); |
3577 | 0 |
|
3578 | 0 | *aChild = static_cast<ChannelDiverterChild*>(diverter); |
3579 | 0 |
|
3580 | 0 | return NS_OK; |
3581 | 0 | } |
3582 | | |
3583 | | NS_IMETHODIMP |
3584 | | HttpChannelChild::UnknownDecoderInvolvedKeepData() |
3585 | 0 | { |
3586 | 0 | LOG(("HttpChannelChild::UnknownDecoderInvolvedKeepData [this=%p]", |
3587 | 0 | this)); |
3588 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3589 | 0 |
|
3590 | 0 | mUnknownDecoderInvolved = true; |
3591 | 0 | return NS_OK; |
3592 | 0 | } |
3593 | | |
3594 | | NS_IMETHODIMP |
3595 | | HttpChannelChild::UnknownDecoderInvolvedOnStartRequestCalled() |
3596 | 0 | { |
3597 | 0 | LOG(("HttpChannelChild::UnknownDecoderInvolvedOnStartRequestCalled " |
3598 | 0 | "[this=%p, mDivertingToParent=%d]", this, |
3599 | 0 | static_cast<bool>(mDivertingToParent))); |
3600 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3601 | 0 |
|
3602 | 0 | mUnknownDecoderInvolved = false; |
3603 | 0 |
|
3604 | 0 | nsresult rv = NS_OK; |
3605 | 0 |
|
3606 | 0 | if (mDivertingToParent) { |
3607 | 0 | rv = mEventQ->PrependEvents(mUnknownDecoderEventQ); |
3608 | 0 | } |
3609 | 0 | mUnknownDecoderEventQ.Clear(); |
3610 | 0 |
|
3611 | 0 | return rv; |
3612 | 0 | } |
3613 | | |
3614 | | NS_IMETHODIMP |
3615 | | HttpChannelChild::GetDivertingToParent(bool* aDiverting) |
3616 | 0 | { |
3617 | 0 | NS_ENSURE_ARG_POINTER(aDiverting); |
3618 | 0 | *aDiverting = mDivertingToParent; |
3619 | 0 | return NS_OK; |
3620 | 0 | } |
3621 | | |
3622 | | //----------------------------------------------------------------------------- |
3623 | | // HttpChannelChild::nsIThreadRetargetableRequest |
3624 | | //----------------------------------------------------------------------------- |
3625 | | |
3626 | | NS_IMETHODIMP |
3627 | | HttpChannelChild::RetargetDeliveryTo(nsIEventTarget* aNewTarget) |
3628 | 0 | { |
3629 | 0 | LOG(("HttpChannelChild::RetargetDeliveryTo [this=%p, aNewTarget=%p]", |
3630 | 0 | this, aNewTarget)); |
3631 | 0 |
|
3632 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only"); |
3633 | 0 | MOZ_ASSERT(!mODATarget); |
3634 | 0 | MOZ_ASSERT(aNewTarget); |
3635 | 0 |
|
3636 | 0 | NS_ENSURE_ARG(aNewTarget); |
3637 | 0 | if (aNewTarget->IsOnCurrentThread()) { |
3638 | 0 | NS_WARNING("Retargeting delivery to same thread"); |
3639 | 0 | mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::successMainThread; |
3640 | 0 | return NS_OK; |
3641 | 0 | } |
3642 | 0 |
|
3643 | 0 | // Ensure that |mListener| and any subsequent listeners can be retargeted |
3644 | 0 | // to another thread. |
3645 | 0 | nsresult rv = NS_OK; |
3646 | 0 | nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener = |
3647 | 0 | do_QueryInterface(mListener, &rv); |
3648 | 0 | if (!retargetableListener || NS_FAILED(rv)) { |
3649 | 0 | NS_WARNING("Listener is not retargetable"); |
3650 | 0 | mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListener; |
3651 | 0 | return NS_ERROR_NO_INTERFACE; |
3652 | 0 | } |
3653 | 0 |
|
3654 | 0 | rv = retargetableListener->CheckListenerChain(); |
3655 | 0 | if (NS_FAILED(rv)) { |
3656 | 0 | NS_WARNING("Subsequent listeners are not retargetable"); |
3657 | 0 | mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListenerChain; |
3658 | 0 | return rv; |
3659 | 0 | } |
3660 | 0 |
|
3661 | 0 | { |
3662 | 0 | MutexAutoLock lock(mEventTargetMutex); |
3663 | 0 | mODATarget = aNewTarget; |
3664 | 0 | } |
3665 | 0 |
|
3666 | 0 | mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::success; |
3667 | 0 | return NS_OK; |
3668 | 0 | } |
3669 | | |
3670 | | NS_IMETHODIMP |
3671 | | HttpChannelChild::GetDeliveryTarget(nsIEventTarget** aEventTarget) |
3672 | 0 | { |
3673 | 0 | MutexAutoLock lock(mEventTargetMutex); |
3674 | 0 |
|
3675 | 0 | nsCOMPtr<nsIEventTarget> target = mODATarget; |
3676 | 0 | if (!mODATarget) { |
3677 | 0 | target = GetCurrentThreadEventTarget(); |
3678 | 0 | } |
3679 | 0 | target.forget(aEventTarget); |
3680 | 0 | return NS_OK; |
3681 | 0 | } |
3682 | | |
3683 | | void |
3684 | | HttpChannelChild::ResetInterception() |
3685 | 0 | { |
3686 | 0 | NS_ENSURE_TRUE_VOID(gNeckoChild != nullptr); |
3687 | 0 |
|
3688 | 0 | if (mInterceptListener) { |
3689 | 0 | mInterceptListener->Cleanup(); |
3690 | 0 | } |
3691 | 0 | mInterceptListener = nullptr; |
3692 | 0 |
|
3693 | 0 | // The chance to intercept any further requests associated with this channel |
3694 | 0 | // (such as redirects) has passed. |
3695 | 0 | if (mRedirectMode != nsIHttpChannelInternal::REDIRECT_MODE_MANUAL) { |
3696 | 0 | mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER; |
3697 | 0 | } |
3698 | 0 |
|
3699 | 0 | // If the channel has already been aborted or canceled, just stop. |
3700 | 0 | if (NS_FAILED(mStatus)) { |
3701 | 0 | return; |
3702 | 0 | } |
3703 | 0 | |
3704 | 0 | // Continue with the original cross-process request |
3705 | 0 | nsresult rv = ContinueAsyncOpen(); |
3706 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
3707 | 0 | Unused << Cancel(rv); |
3708 | 0 | } |
3709 | 0 | } |
3710 | | |
3711 | | void |
3712 | | HttpChannelChild::TrySendDeletingChannel() |
3713 | 0 | { |
3714 | 0 | if (!mDeletingChannelSent.compareExchange(false, true)) { |
3715 | 0 | // SendDeletingChannel is already sent. |
3716 | 0 | return; |
3717 | 0 | } |
3718 | 0 | |
3719 | 0 | if (NS_IsMainThread()) { |
3720 | 0 | if (NS_WARN_IF(!mIPCOpen)) { |
3721 | 0 | // IPC actor is detroyed already, do not send more messages. |
3722 | 0 | return; |
3723 | 0 | } |
3724 | 0 | |
3725 | 0 | Unused << PHttpChannelChild::SendDeletingChannel(); |
3726 | 0 | return; |
3727 | 0 | } |
3728 | 0 | |
3729 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
3730 | 0 | MOZ_ASSERT(neckoTarget); |
3731 | 0 |
|
3732 | 0 | DebugOnly<nsresult> rv = neckoTarget->Dispatch( |
3733 | 0 | NewNonOwningRunnableMethod("net::HttpChannelChild::TrySendDeletingChannel", |
3734 | 0 | this, |
3735 | 0 | &HttpChannelChild::TrySendDeletingChannel), |
3736 | 0 | NS_DISPATCH_NORMAL); |
3737 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3738 | 0 | } |
3739 | | |
3740 | | void |
3741 | | HttpChannelChild::OnCopyComplete(nsresult aStatus) |
3742 | 0 | { |
3743 | 0 | nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<nsresult>( |
3744 | 0 | "net::HttpBaseChannel::EnsureUploadStreamIsCloneableComplete", |
3745 | 0 | this, |
3746 | 0 | &HttpChannelChild::EnsureUploadStreamIsCloneableComplete, |
3747 | 0 | aStatus); |
3748 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
3749 | 0 | MOZ_ASSERT(neckoTarget); |
3750 | 0 |
|
3751 | 0 | Unused << neckoTarget->Dispatch(runnable, NS_DISPATCH_NORMAL); |
3752 | 0 | } |
3753 | | |
3754 | | nsresult |
3755 | | HttpChannelChild::AsyncCallImpl(void (HttpChannelChild::*funcPtr)(), |
3756 | | nsRunnableMethod<HttpChannelChild> **retval) |
3757 | 0 | { |
3758 | 0 | nsresult rv; |
3759 | 0 |
|
3760 | 0 | RefPtr<nsRunnableMethod<HttpChannelChild>> event = |
3761 | 0 | NewRunnableMethod("net::HttpChannelChild::AsyncCall", this, funcPtr); |
3762 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
3763 | 0 | MOZ_ASSERT(neckoTarget); |
3764 | 0 |
|
3765 | 0 | rv = neckoTarget->Dispatch(event, NS_DISPATCH_NORMAL); |
3766 | 0 |
|
3767 | 0 | if (NS_SUCCEEDED(rv) && retval) { |
3768 | 0 | *retval = event; |
3769 | 0 | } |
3770 | 0 |
|
3771 | 0 | return rv; |
3772 | 0 | } |
3773 | | |
3774 | | class CancelEvent final : public NeckoTargetChannelEvent<HttpChannelChild> |
3775 | | { |
3776 | | public: |
3777 | | CancelEvent(HttpChannelChild* aChild, nsresult aRv) |
3778 | | : NeckoTargetChannelEvent<HttpChannelChild>(aChild) |
3779 | | , mRv(aRv) |
3780 | 0 | { |
3781 | 0 | MOZ_ASSERT(!NS_IsMainThread()); |
3782 | 0 | MOZ_ASSERT(aChild); |
3783 | 0 | } |
3784 | | |
3785 | | void Run() override |
3786 | 0 | { |
3787 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3788 | 0 | mChild->Cancel(mRv); |
3789 | 0 | } |
3790 | | |
3791 | | private: |
3792 | | const nsresult mRv; |
3793 | | }; |
3794 | | |
3795 | | void |
3796 | | HttpChannelChild::CancelOnMainThread(nsresult aRv) |
3797 | 0 | { |
3798 | 0 | LOG(("HttpChannelChild::CancelOnMainThread [this=%p]", this)); |
3799 | 0 |
|
3800 | 0 | if (NS_IsMainThread()) { |
3801 | 0 | Cancel(aRv); |
3802 | 0 | return; |
3803 | 0 | } |
3804 | 0 | |
3805 | 0 | mEventQ->Suspend(); |
3806 | 0 | // Cancel is expected to preempt any other channel events, thus we put this |
3807 | 0 | // event in the front of mEventQ to make sure nsIStreamListener not receiving |
3808 | 0 | // any ODA/OnStopRequest callbacks. |
3809 | 0 | UniquePtr<ChannelEvent> cancelEvent = MakeUnique<CancelEvent>(this, aRv); |
3810 | 0 | mEventQ->PrependEvent(cancelEvent); |
3811 | 0 | mEventQ->Resume(); |
3812 | 0 | } |
3813 | | |
3814 | | void |
3815 | | HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>& aResponseHead, |
3816 | | nsIInputStream* aSynthesizedInput, |
3817 | | nsIInterceptedBodyCallback* aSynthesizedCallback, |
3818 | | InterceptStreamListener* aStreamListener, |
3819 | | nsICacheInfoChannel* aCacheInfoChannel) |
3820 | 0 | { |
3821 | 0 | nsresult rv = NS_OK; |
3822 | 0 | auto autoCleanup = MakeScopeExit([&] { |
3823 | 0 | // Auto-cancel on failure. Do this first to get mStatus set, if necessary. |
3824 | 0 | if (NS_FAILED(rv)) { |
3825 | 0 | Cancel(rv); |
3826 | 0 | } |
3827 | 0 |
|
3828 | 0 | // If we early exit before taking ownership of the body, then automatically |
3829 | 0 | // invoke the callback. This could be due to an error or because we're not |
3830 | 0 | // going to consume it due to a redirect, etc. |
3831 | 0 | if (aSynthesizedCallback) { |
3832 | 0 | aSynthesizedCallback->BodyComplete(mStatus); |
3833 | 0 | } |
3834 | 0 | }); |
3835 | 0 |
|
3836 | 0 | if (NS_FAILED(mStatus)) { |
3837 | 0 | return; |
3838 | 0 | } |
3839 | 0 | |
3840 | 0 | mInterceptListener = aStreamListener; |
3841 | 0 |
|
3842 | 0 | // Intercepted responses should already be decoded. If its a redirect, |
3843 | 0 | // however, we want to respect the encoding of the final result instead. |
3844 | 0 | if (!nsHttpChannel::WillRedirect(aResponseHead)) { |
3845 | 0 | SetApplyConversion(false); |
3846 | 0 | } |
3847 | 0 |
|
3848 | 0 | mResponseHead = aResponseHead; |
3849 | 0 | mSynthesizedResponse = true; |
3850 | 0 |
|
3851 | 0 | mSynthesizedInput = aSynthesizedInput; |
3852 | 0 |
|
3853 | 0 | if (!mSynthesizedInput) { |
3854 | 0 | rv = NS_NewCStringInputStream(getter_AddRefs(mSynthesizedInput), |
3855 | 0 | EmptyCString()); |
3856 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
3857 | 0 | } |
3858 | 0 |
|
3859 | 0 | if (nsHttpChannel::WillRedirect(mResponseHead)) { |
3860 | 0 | // Normally we handle redirect limits in the parent process. The way |
3861 | 0 | // e10s synthesized redirects work, however, the parent process does not |
3862 | 0 | // get an accurate redirect count. Therefore we need to enforce it here. |
3863 | 0 | rv = CheckRedirectLimit(nsIChannelEventSink::REDIRECT_TEMPORARY); |
3864 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
3865 | 0 | Cancel(rv); |
3866 | 0 | return; |
3867 | 0 | } |
3868 | 0 | |
3869 | 0 | mShouldInterceptSubsequentRedirect = true; |
3870 | 0 | if (mInterceptListener) { |
3871 | 0 | mInterceptListener->Cleanup(); |
3872 | 0 | mInterceptListener = nullptr; |
3873 | 0 | } |
3874 | 0 | // Continue with the original cross-process request |
3875 | 0 | rv = ContinueAsyncOpen(); |
3876 | 0 | return; |
3877 | 0 | } |
3878 | 0 |
|
3879 | 0 | // For progress we trust the content-length for the "maximum" size. |
3880 | 0 | // We can't determine the full size from the stream itself since we |
3881 | 0 | // only receive the data incrementally. We can't trust Available() |
3882 | 0 | // here. |
3883 | 0 | // TODO: We could implement an nsIFixedLengthInputStream interface and |
3884 | 0 | // QI to it here. This would let us determine the total length |
3885 | 0 | // for streams that support it. See bug 1388774. |
3886 | 0 | rv = GetContentLength(&mSynthesizedStreamLength); |
3887 | 0 | if (NS_FAILED(rv)) { |
3888 | 0 | mSynthesizedStreamLength = -1; |
3889 | 0 | } |
3890 | 0 |
|
3891 | 0 | nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); |
3892 | 0 | MOZ_ASSERT(neckoTarget); |
3893 | 0 |
|
3894 | 0 | rv = nsInputStreamPump::Create(getter_AddRefs(mSynthesizedResponsePump), |
3895 | 0 | mSynthesizedInput, 0, 0, true, neckoTarget); |
3896 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
3897 | 0 |
|
3898 | 0 | mSynthesizedCacheInfo = aCacheInfoChannel; |
3899 | 0 |
|
3900 | 0 | rv = mSynthesizedResponsePump->AsyncRead(aStreamListener, nullptr); |
3901 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
3902 | 0 |
|
3903 | 0 | // The pump is started, so take ownership of the body callback. We |
3904 | 0 | // clear the argument to avoid auto-completing it via the ScopeExit |
3905 | 0 | // lambda. |
3906 | 0 | mSynthesizedCallback = aSynthesizedCallback; |
3907 | 0 | aSynthesizedCallback = nullptr; |
3908 | 0 |
|
3909 | 0 | // if this channel has been suspended previously, the pump needs to be |
3910 | 0 | // correspondingly suspended now that it exists. |
3911 | 0 | for (uint32_t i = 0; i < mSuspendCount; i++) { |
3912 | 0 | rv = mSynthesizedResponsePump->Suspend(); |
3913 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
3914 | 0 | } |
3915 | 0 |
|
3916 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mCanceled); |
3917 | 0 | } |
3918 | | |
3919 | | NS_IMETHODIMP |
3920 | | HttpChannelChild::ForceIntercepted(bool aPostRedirectChannelShouldIntercept, |
3921 | | bool aPostRedirectChannelShouldUpgrade) |
3922 | 0 | { |
3923 | 0 | mShouldParentIntercept = true; |
3924 | 0 | mPostRedirectChannelShouldIntercept = aPostRedirectChannelShouldIntercept; |
3925 | 0 | mPostRedirectChannelShouldUpgrade = aPostRedirectChannelShouldUpgrade; |
3926 | 0 | return NS_OK; |
3927 | 0 | } |
3928 | | |
3929 | | void |
3930 | | HttpChannelChild::ForceIntercepted(nsIInputStream* aSynthesizedInput, |
3931 | | nsIInterceptedBodyCallback* aSynthesizedCallback, |
3932 | | nsICacheInfoChannel* aCacheInfo) |
3933 | 0 | { |
3934 | 0 | mSynthesizedInput = aSynthesizedInput; |
3935 | 0 | mSynthesizedCallback = aSynthesizedCallback; |
3936 | 0 | mSynthesizedCacheInfo = aCacheInfo; |
3937 | 0 | mSynthesizedResponse = true; |
3938 | 0 | mRedirectingForSubsequentSynthesizedResponse = true; |
3939 | 0 | } |
3940 | | |
3941 | | mozilla::ipc::IPCResult |
3942 | | HttpChannelChild::RecvIssueDeprecationWarning(const uint32_t& warning, |
3943 | | const bool& asError) |
3944 | 0 | { |
3945 | 0 | nsCOMPtr<nsIDeprecationWarner> warner; |
3946 | 0 | GetCallback(warner); |
3947 | 0 | if (warner) { |
3948 | 0 | warner->IssueWarning(warning, asError); |
3949 | 0 | } |
3950 | 0 | return IPC_OK(); |
3951 | 0 | } |
3952 | | |
3953 | | bool |
3954 | | HttpChannelChild::ShouldInterceptURI(nsIURI* aURI, |
3955 | | bool& aShouldUpgrade) |
3956 | 0 | { |
3957 | 0 | bool isHttps = false; |
3958 | 0 | nsresult rv = aURI->SchemeIs("https", &isHttps); |
3959 | 0 | NS_ENSURE_SUCCESS(rv, false); |
3960 | 0 | nsCOMPtr<nsIPrincipal> resultPrincipal; |
3961 | 0 | if (!isHttps && mLoadInfo) { |
3962 | 0 | nsContentUtils::GetSecurityManager()-> |
3963 | 0 | GetChannelResultPrincipal(this, getter_AddRefs(resultPrincipal)); |
3964 | 0 | } |
3965 | 0 | OriginAttributes originAttributes; |
3966 | 0 | NS_ENSURE_TRUE(NS_GetOriginAttributes(this, originAttributes), false); |
3967 | 0 | rv = NS_ShouldSecureUpgrade(aURI, |
3968 | 0 | mLoadInfo, |
3969 | 0 | resultPrincipal, |
3970 | 0 | mPrivateBrowsing, |
3971 | 0 | mAllowSTS, |
3972 | 0 | originAttributes, |
3973 | 0 | aShouldUpgrade); |
3974 | 0 | NS_ENSURE_SUCCESS(rv, false); |
3975 | 0 |
|
3976 | 0 | nsCOMPtr<nsIURI> upgradedURI; |
3977 | 0 | if (aShouldUpgrade) { |
3978 | 0 | rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(upgradedURI)); |
3979 | 0 | NS_ENSURE_SUCCESS(rv, false); |
3980 | 0 | } |
3981 | 0 |
|
3982 | 0 | return ShouldIntercept(upgradedURI ? upgradedURI.get() : aURI); |
3983 | 0 | } |
3984 | | |
3985 | | mozilla::ipc::IPCResult |
3986 | | HttpChannelChild::RecvSetPriority(const int16_t& aPriority) |
3987 | 0 | { |
3988 | 0 | mPriority = aPriority; |
3989 | 0 | return IPC_OK(); |
3990 | 0 | } |
3991 | | |
3992 | | mozilla::ipc::IPCResult |
3993 | | HttpChannelChild::RecvAttachStreamFilter(Endpoint<extensions::PStreamFilterParent>&& aEndpoint) |
3994 | 0 | { |
3995 | 0 | extensions::StreamFilterParent::Attach(this, std::move(aEndpoint)); |
3996 | 0 | return IPC_OK(); |
3997 | 0 | } |
3998 | | |
3999 | | mozilla::ipc::IPCResult |
4000 | | HttpChannelChild::RecvCancelDiversion() |
4001 | 0 | { |
4002 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
4003 | 0 |
|
4004 | 0 | // This method is a very special case for cancellation of a diverted |
4005 | 0 | // intercepted channel. Normally we would go through the mEventQ in order to |
4006 | 0 | // serialize event execution in the face of sync XHR and now background |
4007 | 0 | // channels. However, similar to how CancelOnMainThread describes, Cancel() |
4008 | 0 | // pre-empts everything. (And frankly, we want this stack frame on the stack |
4009 | 0 | // if a crash happens.) |
4010 | 0 | Cancel(NS_ERROR_ABORT); |
4011 | 0 | return IPC_OK(); |
4012 | 0 | } |
4013 | | |
4014 | | void |
4015 | | HttpChannelChild::ActorDestroy(ActorDestroyReason aWhy) |
4016 | 0 | { |
4017 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
4018 | 0 |
|
4019 | 0 | // OnStartRequest might be dropped if IPDL is destroyed abnormally |
4020 | 0 | // and BackgroundChild might have pending IPC messages. |
4021 | 0 | // Clean up BackgroundChild at this time to prevent memleak. |
4022 | 0 | if (aWhy != Deletion) { |
4023 | 0 | CleanupBackgroundChannel(); |
4024 | 0 | } |
4025 | 0 | } |
4026 | | |
4027 | | mozilla::ipc::IPCResult |
4028 | | HttpChannelChild::RecvLogBlockedCORSRequest(const nsString& aMessage, |
4029 | | const nsCString& aCategory) |
4030 | 0 | { |
4031 | 0 | Unused << LogBlockedCORSRequest(aMessage, aCategory); |
4032 | 0 | return IPC_OK(); |
4033 | 0 | } |
4034 | | |
4035 | | NS_IMETHODIMP |
4036 | | HttpChannelChild::LogBlockedCORSRequest(const nsAString & aMessage, |
4037 | | const nsACString& aCategory) |
4038 | 0 | { |
4039 | 0 | if (mLoadInfo) { |
4040 | 0 | uint64_t innerWindowID = mLoadInfo->GetInnerWindowID(); |
4041 | 0 | bool privateBrowsing = !!mLoadInfo->GetOriginAttributes().mPrivateBrowsingId; |
4042 | 0 | nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, privateBrowsing, |
4043 | 0 | aMessage, aCategory); |
4044 | 0 | } |
4045 | 0 | return NS_OK; |
4046 | 0 | } |
4047 | | |
4048 | | void |
4049 | | HttpChannelChild::MaybeCallSynthesizedCallback() |
4050 | 0 | { |
4051 | 0 | if (!mSynthesizedCallback) { |
4052 | 0 | return; |
4053 | 0 | } |
4054 | 0 | |
4055 | 0 | mSynthesizedCallback->BodyComplete(mStatus); |
4056 | 0 | mSynthesizedCallback = nullptr; |
4057 | 0 | } |
4058 | | |
4059 | | nsresult |
4060 | | HttpChannelChild::CrossProcessRedirectFinished(nsresult aStatus) |
4061 | 0 | { |
4062 | 0 | if (!mIPCOpen) { |
4063 | 0 | return NS_BINDING_FAILED; |
4064 | 0 | } |
4065 | 0 | Unused << SendCrossProcessRedirectDone(aStatus); |
4066 | 0 | return NS_OK; |
4067 | 0 | } |
4068 | | |
4069 | | } // namespace net |
4070 | | } // namespace mozilla |