/src/mozilla-central/netwerk/protocol/http/HttpChannelParent.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 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | // HttpLog.h should generally be included first |
8 | | #include "HttpLog.h" |
9 | | |
10 | | #include "mozilla/ipc/FileDescriptorSetParent.h" |
11 | | #include "mozilla/ipc/IPCStreamUtils.h" |
12 | | #include "mozilla/net/HttpChannelParent.h" |
13 | | #include "mozilla/dom/ContentParent.h" |
14 | | #include "mozilla/dom/Element.h" |
15 | | #include "mozilla/dom/ServiceWorkerUtils.h" |
16 | | #include "mozilla/dom/TabParent.h" |
17 | | #include "mozilla/net/NeckoParent.h" |
18 | | #include "mozilla/InputStreamLengthHelper.h" |
19 | | #include "mozilla/IntegerPrintfMacros.h" |
20 | | #include "mozilla/UniquePtr.h" |
21 | | #include "mozilla/Unused.h" |
22 | | #include "HttpBackgroundChannelParent.h" |
23 | | #include "HttpChannelParentListener.h" |
24 | | #include "nsHttpHandler.h" |
25 | | #include "nsNetCID.h" |
26 | | #include "nsNetUtil.h" |
27 | | #include "nsISupportsPriority.h" |
28 | | #include "nsIAuthPromptProvider.h" |
29 | | #include "nsIBackgroundChannelRegistrar.h" |
30 | | #include "nsSerializationHelper.h" |
31 | | #include "nsISerializable.h" |
32 | | #include "nsIApplicationCacheService.h" |
33 | | #include "mozilla/ipc/InputStreamUtils.h" |
34 | | #include "mozilla/ipc/URIUtils.h" |
35 | | #include "SerializedLoadContext.h" |
36 | | #include "nsIAuthInformation.h" |
37 | | #include "nsIAuthPromptCallback.h" |
38 | | #include "nsIContentPolicy.h" |
39 | | #include "mozilla/ipc/BackgroundUtils.h" |
40 | | #include "nsICachingChannel.h" |
41 | | #include "mozilla/LoadInfo.h" |
42 | | #include "nsQueryObject.h" |
43 | | #include "mozilla/BasePrincipal.h" |
44 | | #include "nsCORSListenerProxy.h" |
45 | | #include "nsIIPCSerializableInputStream.h" |
46 | | #include "nsIPrompt.h" |
47 | | #include "mozilla/net/RedirectChannelRegistrar.h" |
48 | | #include "nsIWindowWatcher.h" |
49 | | #include "nsIDocument.h" |
50 | | #include "nsStreamUtils.h" |
51 | | #include "nsStringStream.h" |
52 | | #include "nsIStorageStream.h" |
53 | | #include "nsThreadUtils.h" |
54 | | #include "nsQueryObject.h" |
55 | | #include "nsIURIClassifier.h" |
56 | | |
57 | | using mozilla::BasePrincipal; |
58 | | using namespace mozilla::dom; |
59 | | using namespace mozilla::ipc; |
60 | | |
61 | | namespace mozilla { |
62 | | namespace net { |
63 | | |
64 | | HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding, |
65 | | nsILoadContext* aLoadContext, |
66 | | PBOverrideStatus aOverrideStatus) |
67 | | : mLoadContext(aLoadContext) |
68 | | , mNestedFrameId(0) |
69 | | , mIPCClosed(false) |
70 | | , mPBOverride(aOverrideStatus) |
71 | | , mStatus(NS_OK) |
72 | | , mIgnoreProgress(false) |
73 | | , mSentRedirect1BeginFailed(false) |
74 | | , mReceivedRedirect2Verify(false) |
75 | | , mHasSuspendedByBackPressure(false) |
76 | | , mPendingDiversion(false) |
77 | | , mDivertingFromChild(false) |
78 | | , mDivertedOnStartRequest(false) |
79 | | , mSuspendedForDiversion(false) |
80 | | , mSuspendAfterSynthesizeResponse(false) |
81 | | , mWillSynthesizeResponse(false) |
82 | | , mCacheNeedFlowControlInitialized(false) |
83 | | , mNeedFlowControl(true) |
84 | | , mSuspendedForFlowControl(false) |
85 | | , mDoingCrossProcessRedirect(false) |
86 | 0 | { |
87 | 0 | LOG(("Creating HttpChannelParent [this=%p]\n", this)); |
88 | 0 |
|
89 | 0 | // Ensure gHttpHandler is initialized: we need the atom table up and running. |
90 | 0 | nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer = |
91 | 0 | do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"); |
92 | 0 |
|
93 | 0 | MOZ_ASSERT(gHttpHandler); |
94 | 0 | mHttpHandler = gHttpHandler; |
95 | 0 |
|
96 | 0 | if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) { |
97 | 0 | mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent()); |
98 | 0 | } else { |
99 | 0 | mNestedFrameId = iframeEmbedding.get_TabId(); |
100 | 0 | } |
101 | 0 |
|
102 | 0 | mSendWindowSize = gHttpHandler->SendWindowSize(); |
103 | 0 |
|
104 | 0 | mEventQ = new ChannelEventQueue(static_cast<nsIParentRedirectingChannel*>(this)); |
105 | 0 | } |
106 | | |
107 | | HttpChannelParent::~HttpChannelParent() |
108 | 0 | { |
109 | 0 | LOG(("Destroying HttpChannelParent [this=%p]\n", this)); |
110 | 0 | CleanupBackgroundChannel(); |
111 | 0 | } |
112 | | |
113 | | void |
114 | | HttpChannelParent::ActorDestroy(ActorDestroyReason why) |
115 | 0 | { |
116 | 0 | // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest |
117 | 0 | // yet, but child process has crashed. We must not try to send any more msgs |
118 | 0 | // to child, or IPDL will kill chrome process, too. |
119 | 0 | mIPCClosed = true; |
120 | 0 |
|
121 | 0 | // If this is an intercepted channel, we need to make sure that any resources are |
122 | 0 | // cleaned up to avoid leaks. |
123 | 0 | if (mParentListener) { |
124 | 0 | mParentListener->ClearInterceptedChannel(this); |
125 | 0 | } |
126 | 0 |
|
127 | 0 | CleanupBackgroundChannel(); |
128 | 0 | } |
129 | | |
130 | | bool |
131 | | HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) |
132 | 0 | { |
133 | 0 | LOG(("HttpChannelParent::Init [this=%p]\n", this)); |
134 | 0 | switch (aArgs.type()) { |
135 | 0 | case HttpChannelCreationArgs::THttpChannelOpenArgs: |
136 | 0 | { |
137 | 0 | const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs(); |
138 | 0 | return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(), |
139 | 0 | a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(), |
140 | 0 | a.loadFlags(), a.requestHeaders(), |
141 | 0 | a.requestMethod(), a.uploadStream(), |
142 | 0 | a.uploadStreamHasHeaders(), a.priority(), a.classOfService(), |
143 | 0 | a.redirectionLimit(), a.allowSTS(), |
144 | 0 | a.thirdPartyFlags(), a.resumeAt(), a.startPos(), |
145 | 0 | a.entityID(), a.chooseApplicationCache(), |
146 | 0 | a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.beConservative(), |
147 | 0 | a.tlsFlags(), a.loadInfo(), a.synthesizedResponseHead(), |
148 | 0 | a.synthesizedSecurityInfoSerialization(), |
149 | 0 | a.cacheKey(), a.requestContextID(), a.preflightArgs(), |
150 | 0 | a.initialRwin(), a.blockAuthPrompt(), |
151 | 0 | a.suspendAfterSynthesizeResponse(), |
152 | 0 | a.allowStaleCacheContent(), a.contentTypeHint(), |
153 | 0 | a.corsMode(), a.redirectMode(), |
154 | 0 | a.channelId(), a.integrityMetadata(), |
155 | 0 | a.contentWindowId(), a.preferredAlternativeType(), |
156 | 0 | a.topLevelOuterContentWindowId(), |
157 | 0 | a.launchServiceWorkerStart(), |
158 | 0 | a.launchServiceWorkerEnd(), |
159 | 0 | a.dispatchFetchEventStart(), |
160 | 0 | a.dispatchFetchEventEnd(), |
161 | 0 | a.handleFetchEventStart(), |
162 | 0 | a.handleFetchEventEnd(), |
163 | 0 | a.forceMainDocumentChannel(), |
164 | 0 | a.navigationStartTimeStamp()); |
165 | 0 | } |
166 | 0 | case HttpChannelCreationArgs::THttpChannelConnectArgs: |
167 | 0 | { |
168 | 0 | const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs(); |
169 | 0 | return ConnectChannel(cArgs.registrarId(), cArgs.shouldIntercept()); |
170 | 0 | } |
171 | 0 | default: |
172 | 0 | MOZ_ASSERT_UNREACHABLE("unknown open type"); |
173 | 0 | return false; |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | void |
178 | | HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv) |
179 | 0 | { |
180 | 0 | LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32 |
181 | 0 | "]\n", this, mAsyncOpenBarrier, static_cast<uint32_t>(aRv))); |
182 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
183 | 0 |
|
184 | 0 | // TryInvokeAsyncOpen is called more than we expected. |
185 | 0 | // Assert in nightly build but ignore it in release channel. |
186 | 0 | MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier > 0); |
187 | 0 | if (NS_WARN_IF(!mAsyncOpenBarrier)) { |
188 | 0 | return; |
189 | 0 | } |
190 | 0 | |
191 | 0 | if (--mAsyncOpenBarrier > 0 && NS_SUCCEEDED(aRv)) { |
192 | 0 | // Need to wait for more events. |
193 | 0 | return; |
194 | 0 | } |
195 | 0 | |
196 | 0 | InvokeAsyncOpen(aRv); |
197 | 0 | } |
198 | | |
199 | | void |
200 | | HttpChannelParent::OnBackgroundParentReady( |
201 | | HttpBackgroundChannelParent* aBgParent) |
202 | 0 | { |
203 | 0 | LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n", |
204 | 0 | this, aBgParent)); |
205 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
206 | 0 | MOZ_ASSERT(!mBgParent); |
207 | 0 |
|
208 | 0 | mBgParent = aBgParent; |
209 | 0 |
|
210 | 0 | mPromise.ResolveIfExists(true, __func__); |
211 | 0 | } |
212 | | |
213 | | void |
214 | | HttpChannelParent::OnBackgroundParentDestroyed() |
215 | 0 | { |
216 | 0 | LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this)); |
217 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
218 | 0 |
|
219 | 0 | if (!mPromise.IsEmpty()) { |
220 | 0 | MOZ_ASSERT(!mBgParent); |
221 | 0 | mPromise.Reject(NS_ERROR_FAILURE, __func__); |
222 | 0 | return; |
223 | 0 | } |
224 | 0 |
|
225 | 0 | if (!mBgParent) { |
226 | 0 | return; |
227 | 0 | } |
228 | 0 | |
229 | 0 | // Background channel is closed unexpectly, abort PHttpChannel operation. |
230 | 0 | mBgParent = nullptr; |
231 | 0 | Delete(); |
232 | 0 | } |
233 | | |
234 | | void |
235 | | HttpChannelParent::CleanupBackgroundChannel() |
236 | 0 | { |
237 | 0 | LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n", |
238 | 0 | this, mBgParent.get())); |
239 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
240 | 0 |
|
241 | 0 | if (mBgParent) { |
242 | 0 | RefPtr<HttpBackgroundChannelParent> bgParent = mBgParent.forget(); |
243 | 0 | bgParent->OnChannelClosed(); |
244 | 0 | return; |
245 | 0 | } |
246 | 0 | |
247 | 0 | // The nsHttpChannel may have a reference to this parent, release it |
248 | 0 | // to avoid circular references. |
249 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); |
250 | 0 | if (httpChannelImpl) { |
251 | 0 | httpChannelImpl->SetWarningReporter(nullptr); |
252 | 0 | } |
253 | 0 |
|
254 | 0 | if (!mPromise.IsEmpty()) { |
255 | 0 | mRequest.DisconnectIfExists(); |
256 | 0 | mPromise.Reject(NS_ERROR_FAILURE, __func__); |
257 | 0 |
|
258 | 0 | if (!mChannel) { |
259 | 0 | return; |
260 | 0 | } |
261 | 0 | |
262 | 0 | // This HttpChannelParent might still have a reference from |
263 | 0 | // BackgroundChannelRegistrar. |
264 | 0 | nsCOMPtr<nsIBackgroundChannelRegistrar> registrar = |
265 | 0 | do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID); |
266 | 0 | MOZ_ASSERT(registrar); |
267 | 0 |
|
268 | 0 | registrar->DeleteChannel(mChannel->ChannelId()); |
269 | 0 |
|
270 | 0 | // If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure |
271 | 0 | // is still on going. we need to abort AsyncOpen with failure to destroy |
272 | 0 | // PHttpChannel actor. |
273 | 0 | if (mAsyncOpenBarrier) { |
274 | 0 | TryInvokeAsyncOpen(NS_ERROR_FAILURE); |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | | base::ProcessId |
280 | | HttpChannelParent::OtherPid() const |
281 | 0 | { |
282 | 0 | if (mIPCClosed) { |
283 | 0 | return 0; |
284 | 0 | } |
285 | 0 | return Manager()->OtherPid(); |
286 | 0 | } |
287 | | |
288 | | //----------------------------------------------------------------------------- |
289 | | // HttpChannelParent::nsISupports |
290 | | //----------------------------------------------------------------------------- |
291 | | |
292 | | NS_IMPL_ADDREF(HttpChannelParent) |
293 | | NS_IMPL_RELEASE(HttpChannelParent) |
294 | 0 | NS_INTERFACE_MAP_BEGIN(HttpChannelParent) |
295 | 0 | NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) |
296 | 0 | NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) |
297 | 0 | NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) |
298 | 0 | NS_INTERFACE_MAP_ENTRY(nsIStreamListener) |
299 | 0 | NS_INTERFACE_MAP_ENTRY(nsIParentChannel) |
300 | 0 | NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider) |
301 | 0 | NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel) |
302 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner) |
303 | 0 | NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback) |
304 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel) |
305 | 0 | NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParent) |
306 | 0 | NS_INTERFACE_MAP_END |
307 | | |
308 | | //----------------------------------------------------------------------------- |
309 | | // HttpChannelParent::nsIInterfaceRequestor |
310 | | //----------------------------------------------------------------------------- |
311 | | |
312 | | NS_IMETHODIMP |
313 | | HttpChannelParent::GetInterface(const nsIID& aIID, void **result) |
314 | 0 | { |
315 | 0 | if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) || |
316 | 0 | aIID.Equals(NS_GET_IID(nsISecureBrowserUI)) || |
317 | 0 | aIID.Equals(NS_GET_IID(nsITabParent))) { |
318 | 0 | if (mTabParent) { |
319 | 0 | return mTabParent->QueryInterface(aIID, result); |
320 | 0 | } |
321 | 0 | } |
322 | 0 | |
323 | 0 | // Only support nsIAuthPromptProvider in Content process |
324 | 0 | if (XRE_IsParentProcess() && |
325 | 0 | aIID.Equals(NS_GET_IID(nsIAuthPromptProvider))) { |
326 | 0 | *result = nullptr; |
327 | 0 | return NS_OK; |
328 | 0 | } |
329 | 0 | |
330 | 0 | // Only support nsILoadContext if child channel's callbacks did too |
331 | 0 | if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { |
332 | 0 | nsCOMPtr<nsILoadContext> copy = mLoadContext; |
333 | 0 | copy.forget(result); |
334 | 0 | return NS_OK; |
335 | 0 | } |
336 | 0 | |
337 | 0 | if (mTabParent && aIID.Equals(NS_GET_IID(nsIPrompt))) { |
338 | 0 | nsCOMPtr<Element> frameElement = mTabParent->GetOwnerElement(); |
339 | 0 | if (frameElement) { |
340 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win =frameElement->OwnerDoc()->GetWindow(); |
341 | 0 | NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED); |
342 | 0 |
|
343 | 0 | nsresult rv; |
344 | 0 | nsCOMPtr<nsIWindowWatcher> wwatch = |
345 | 0 | do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); |
346 | 0 |
|
347 | 0 | if (NS_WARN_IF(!NS_SUCCEEDED(rv))) { |
348 | 0 | return rv; |
349 | 0 | } |
350 | 0 | |
351 | 0 | nsCOMPtr<nsIPrompt> prompt; |
352 | 0 | rv = wwatch->GetNewPrompter(win, getter_AddRefs(prompt)); |
353 | 0 | if (NS_WARN_IF(!NS_SUCCEEDED(rv))) { |
354 | 0 | return rv; |
355 | 0 | } |
356 | 0 | |
357 | 0 | prompt.forget(result); |
358 | 0 | return NS_OK; |
359 | 0 | } |
360 | 0 | } |
361 | 0 |
|
362 | 0 | return QueryInterface(aIID, result); |
363 | 0 | } |
364 | | |
365 | | //----------------------------------------------------------------------------- |
366 | | // HttpChannelParent::PHttpChannelParent |
367 | | //----------------------------------------------------------------------------- |
368 | | |
369 | | void |
370 | | HttpChannelParent::AsyncOpenFailed(nsresult aRv) |
371 | 0 | { |
372 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
373 | 0 | MOZ_ASSERT(NS_FAILED(aRv)); |
374 | 0 |
|
375 | 0 | // Break the reference cycle among HttpChannelParent, |
376 | 0 | // HttpChannelParentListener, and nsHttpChannel to avoid memory leakage. |
377 | 0 | mChannel = nullptr; |
378 | 0 | mParentListener = nullptr; |
379 | 0 |
|
380 | 0 | if (!mIPCClosed) { |
381 | 0 | Unused << SendFailedAsyncOpen(aRv); |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | void |
386 | | HttpChannelParent::InvokeAsyncOpen(nsresult rv) |
387 | 0 | { |
388 | 0 | LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32 "]\n", |
389 | 0 | this, static_cast<uint32_t>(rv))); |
390 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
391 | 0 |
|
392 | 0 | if (NS_FAILED(rv)) { |
393 | 0 | AsyncOpenFailed(rv); |
394 | 0 | return; |
395 | 0 | } |
396 | 0 | |
397 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
398 | 0 | rv = mChannel->GetLoadInfo(getter_AddRefs(loadInfo)); |
399 | 0 | if (NS_FAILED(rv)) { |
400 | 0 | AsyncOpenFailed(rv); |
401 | 0 | return; |
402 | 0 | } |
403 | 0 | if (loadInfo && loadInfo->GetEnforceSecurity()) { |
404 | 0 | rv = mChannel->AsyncOpen2(mParentListener); |
405 | 0 | } |
406 | 0 | else { |
407 | 0 | rv = mChannel->AsyncOpen(mParentListener, nullptr); |
408 | 0 | } |
409 | 0 | if (NS_FAILED(rv)) { |
410 | 0 | AsyncOpenFailed(rv); |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | | bool |
415 | | HttpChannelParent::DoAsyncOpen( const URIParams& aURI, |
416 | | const OptionalURIParams& aOriginalURI, |
417 | | const OptionalURIParams& aDocURI, |
418 | | const OptionalURIParams& aReferrerURI, |
419 | | const uint32_t& aReferrerPolicy, |
420 | | const OptionalURIParams& aAPIRedirectToURI, |
421 | | const OptionalURIParams& aTopWindowURI, |
422 | | const uint32_t& aLoadFlags, |
423 | | const RequestHeaderTuples& requestHeaders, |
424 | | const nsCString& requestMethod, |
425 | | const OptionalIPCStream& uploadStream, |
426 | | const bool& uploadStreamHasHeaders, |
427 | | const int16_t& priority, |
428 | | const uint32_t& classOfService, |
429 | | const uint8_t& redirectionLimit, |
430 | | const bool& allowSTS, |
431 | | const uint32_t& thirdPartyFlags, |
432 | | const bool& doResumeAt, |
433 | | const uint64_t& startPos, |
434 | | const nsCString& entityID, |
435 | | const bool& chooseApplicationCache, |
436 | | const nsCString& appCacheClientID, |
437 | | const bool& allowSpdy, |
438 | | const bool& allowAltSvc, |
439 | | const bool& beConservative, |
440 | | const uint32_t& tlsFlags, |
441 | | const OptionalLoadInfoArgs& aLoadInfoArgs, |
442 | | const OptionalHttpResponseHead& aSynthesizedResponseHead, |
443 | | const nsCString& aSecurityInfoSerialization, |
444 | | const uint32_t& aCacheKey, |
445 | | const uint64_t& aRequestContextID, |
446 | | const OptionalCorsPreflightArgs& aCorsPreflightArgs, |
447 | | const uint32_t& aInitialRwin, |
448 | | const bool& aBlockAuthPrompt, |
449 | | const bool& aSuspendAfterSynthesizeResponse, |
450 | | const bool& aAllowStaleCacheContent, |
451 | | const nsCString& aContentTypeHint, |
452 | | const uint32_t& aCorsMode, |
453 | | const uint32_t& aRedirectMode, |
454 | | const uint64_t& aChannelId, |
455 | | const nsString& aIntegrityMetadata, |
456 | | const uint64_t& aContentWindowId, |
457 | | const nsCString& aPreferredAlternativeType, |
458 | | const uint64_t& aTopLevelOuterContentWindowId, |
459 | | const TimeStamp& aLaunchServiceWorkerStart, |
460 | | const TimeStamp& aLaunchServiceWorkerEnd, |
461 | | const TimeStamp& aDispatchFetchEventStart, |
462 | | const TimeStamp& aDispatchFetchEventEnd, |
463 | | const TimeStamp& aHandleFetchEventStart, |
464 | | const TimeStamp& aHandleFetchEventEnd, |
465 | | const bool& aForceMainDocumentChannel, |
466 | | const TimeStamp& aNavigationStartTimeStamp) |
467 | 0 | { |
468 | 0 | nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); |
469 | 0 | if (!uri) { |
470 | 0 | // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from |
471 | 0 | // null deref here. |
472 | 0 | return false; |
473 | 0 | } |
474 | 0 | nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI); |
475 | 0 | nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI); |
476 | 0 | nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI); |
477 | 0 | nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI); |
478 | 0 | nsCOMPtr<nsIURI> topWindowUri = DeserializeURI(aTopWindowURI); |
479 | 0 |
|
480 | 0 | LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64 " topwinid=%" PRIx64 "]\n", |
481 | 0 | this, uri->GetSpecOrDefault().get(), aChannelId, aTopLevelOuterContentWindowId)); |
482 | 0 |
|
483 | 0 | nsresult rv; |
484 | 0 |
|
485 | 0 | nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv)); |
486 | 0 | if (NS_FAILED(rv)) |
487 | 0 | return SendFailedAsyncOpen(rv); |
488 | 0 | |
489 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
490 | 0 | rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs, |
491 | 0 | getter_AddRefs(loadInfo)); |
492 | 0 | if (NS_FAILED(rv)) { |
493 | 0 | return SendFailedAsyncOpen(rv); |
494 | 0 | } |
495 | 0 | |
496 | 0 | if (!loadInfo) { |
497 | 0 | return SendFailedAsyncOpen(NS_ERROR_UNEXPECTED); |
498 | 0 | } |
499 | 0 | |
500 | 0 | nsCOMPtr<nsIChannel> channel; |
501 | 0 | rv = NS_NewChannelInternal(getter_AddRefs(channel), uri, loadInfo, |
502 | 0 | nullptr, nullptr, nullptr, aLoadFlags, ios); |
503 | 0 | if (NS_FAILED(rv)) { |
504 | 0 | return SendFailedAsyncOpen(rv); |
505 | 0 | } |
506 | 0 | |
507 | 0 | RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel, &rv); |
508 | 0 | if (NS_FAILED(rv)) { |
509 | 0 | return SendFailedAsyncOpen(rv); |
510 | 0 | } |
511 | 0 | |
512 | 0 | // Set attributes needed to create a FetchEvent from this channel. |
513 | 0 | httpChannel->SetCorsMode(aCorsMode); |
514 | 0 | httpChannel->SetRedirectMode(aRedirectMode); |
515 | 0 |
|
516 | 0 | // Set the channelId allocated in child to the parent instance |
517 | 0 | httpChannel->SetChannelId(aChannelId); |
518 | 0 | httpChannel->SetTopLevelContentWindowId(aContentWindowId); |
519 | 0 | httpChannel->SetTopLevelOuterContentWindowId(aTopLevelOuterContentWindowId); |
520 | 0 |
|
521 | 0 | httpChannel->SetIntegrityMetadata(aIntegrityMetadata); |
522 | 0 |
|
523 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(httpChannel); |
524 | 0 | if (httpChannelImpl) { |
525 | 0 | httpChannelImpl->SetWarningReporter(this); |
526 | 0 | } |
527 | 0 | httpChannel->SetTimingEnabled(true); |
528 | 0 | if (mPBOverride != kPBOverride_Unset) { |
529 | 0 | httpChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); |
530 | 0 | } |
531 | 0 |
|
532 | 0 | if (doResumeAt) |
533 | 0 | httpChannel->ResumeAt(startPos, entityID); |
534 | 0 |
|
535 | 0 | if (originalUri) |
536 | 0 | httpChannel->SetOriginalURI(originalUri); |
537 | 0 | if (docUri) |
538 | 0 | httpChannel->SetDocumentURI(docUri); |
539 | 0 | if (referrerUri) { |
540 | 0 | rv = httpChannel->SetReferrerWithPolicyInternal(referrerUri, aReferrerPolicy); |
541 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
542 | 0 | } |
543 | 0 | if (apiRedirectToUri) |
544 | 0 | httpChannel->RedirectTo(apiRedirectToUri); |
545 | 0 | if (topWindowUri) { |
546 | 0 | rv = httpChannel->SetTopWindowURI(topWindowUri); |
547 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
548 | 0 | } |
549 | 0 | if (aLoadFlags != nsIRequest::LOAD_NORMAL) |
550 | 0 | httpChannel->SetLoadFlags(aLoadFlags); |
551 | 0 |
|
552 | 0 | if (aForceMainDocumentChannel) { |
553 | 0 | httpChannel->SetIsMainDocumentChannel(true); |
554 | 0 | } |
555 | 0 |
|
556 | 0 | for (uint32_t i = 0; i < requestHeaders.Length(); i++) { |
557 | 0 | if (requestHeaders[i].mEmpty) { |
558 | 0 | httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader); |
559 | 0 | } else { |
560 | 0 | httpChannel->SetRequestHeader(requestHeaders[i].mHeader, |
561 | 0 | requestHeaders[i].mValue, |
562 | 0 | requestHeaders[i].mMerge); |
563 | 0 | } |
564 | 0 | } |
565 | 0 |
|
566 | 0 | RefPtr<HttpChannelParentListener> parentListener |
567 | 0 | = new HttpChannelParentListener(this); |
568 | 0 |
|
569 | 0 | httpChannel->SetRequestMethod(nsDependentCString(requestMethod.get())); |
570 | 0 |
|
571 | 0 | if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) { |
572 | 0 | const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs(); |
573 | 0 | httpChannel->SetCorsPreflightParameters(args.unsafeHeaders()); |
574 | 0 | } |
575 | 0 |
|
576 | 0 | nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream); |
577 | 0 | if (stream) { |
578 | 0 | int64_t length; |
579 | 0 | if (InputStreamLengthHelper::GetSyncLength(stream, &length)) { |
580 | 0 | httpChannel->InternalSetUploadStreamLength(length >= 0 ? length : 0); |
581 | 0 | } else { |
582 | 0 | // Wait for the nputStreamLengthHelper::GetAsyncLength callback. |
583 | 0 | ++mAsyncOpenBarrier; |
584 | 0 |
|
585 | 0 | // Let's resolve the size of the stream. The following operation is always |
586 | 0 | // async. |
587 | 0 | RefPtr<HttpChannelParent> self = this; |
588 | 0 | InputStreamLengthHelper::GetAsyncLength(stream, |
589 | 0 | [self, httpChannel](int64_t aLength) { |
590 | 0 | httpChannel->InternalSetUploadStreamLength(aLength >= 0 ? aLength : 0); |
591 | 0 | self->TryInvokeAsyncOpen(NS_OK); |
592 | 0 | }); |
593 | 0 | } |
594 | 0 |
|
595 | 0 | httpChannel->InternalSetUploadStream(stream); |
596 | 0 | httpChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders); |
597 | 0 | } |
598 | 0 |
|
599 | 0 | if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) { |
600 | 0 | parentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead()); |
601 | 0 | mWillSynthesizeResponse = true; |
602 | 0 | httpChannelImpl->SetCouldBeSynthesized(); |
603 | 0 |
|
604 | 0 | if (!aSecurityInfoSerialization.IsEmpty()) { |
605 | 0 | nsCOMPtr<nsISupports> secInfo; |
606 | 0 | NS_DeserializeObject(aSecurityInfoSerialization, getter_AddRefs(secInfo)); |
607 | 0 | rv = httpChannel->OverrideSecurityInfo(secInfo); |
608 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
609 | 0 | } |
610 | 0 | } |
611 | 0 |
|
612 | 0 | nsCOMPtr<nsICacheInfoChannel> cacheChannel = |
613 | 0 | do_QueryInterface(static_cast<nsIChannel*>(httpChannel.get())); |
614 | 0 | if (cacheChannel) { |
615 | 0 | cacheChannel->SetCacheKey(aCacheKey); |
616 | 0 | cacheChannel->PreferAlternativeDataType(aPreferredAlternativeType); |
617 | 0 |
|
618 | 0 | cacheChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent); |
619 | 0 |
|
620 | 0 | // This is to mark that the results are going to the content process. |
621 | 0 | if (httpChannelImpl) { |
622 | 0 | httpChannelImpl->SetAltDataForChild(true); |
623 | 0 | } |
624 | 0 | } |
625 | 0 |
|
626 | 0 |
|
627 | 0 | httpChannel->SetContentType(aContentTypeHint); |
628 | 0 |
|
629 | 0 | if (priority != nsISupportsPriority::PRIORITY_NORMAL) { |
630 | 0 | httpChannel->SetPriority(priority); |
631 | 0 | } |
632 | 0 | if (classOfService) { |
633 | 0 | httpChannel->SetClassFlags(classOfService); |
634 | 0 | } |
635 | 0 | httpChannel->SetRedirectionLimit(redirectionLimit); |
636 | 0 | httpChannel->SetAllowSTS(allowSTS); |
637 | 0 | httpChannel->SetThirdPartyFlags(thirdPartyFlags); |
638 | 0 | httpChannel->SetAllowSpdy(allowSpdy); |
639 | 0 | httpChannel->SetAllowAltSvc(allowAltSvc); |
640 | 0 | httpChannel->SetBeConservative(beConservative); |
641 | 0 | httpChannel->SetTlsFlags(tlsFlags); |
642 | 0 | httpChannel->SetInitialRwin(aInitialRwin); |
643 | 0 | httpChannel->SetBlockAuthPrompt(aBlockAuthPrompt); |
644 | 0 |
|
645 | 0 | httpChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart); |
646 | 0 | httpChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd); |
647 | 0 | httpChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart); |
648 | 0 | httpChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd); |
649 | 0 | httpChannel->SetHandleFetchEventStart(aHandleFetchEventStart); |
650 | 0 | httpChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd); |
651 | 0 |
|
652 | 0 | httpChannel->SetNavigationStartTimeStamp(aNavigationStartTimeStamp); |
653 | 0 |
|
654 | 0 | nsCOMPtr<nsIApplicationCacheChannel> appCacheChan = |
655 | 0 | do_QueryObject(httpChannel); |
656 | 0 | nsCOMPtr<nsIApplicationCacheService> appCacheService = |
657 | 0 | do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID); |
658 | 0 |
|
659 | 0 | bool setChooseApplicationCache = chooseApplicationCache; |
660 | 0 | if (appCacheChan && appCacheService) { |
661 | 0 | // We might potentially want to drop this flag (that is TRUE by default) |
662 | 0 | // after we successfully associate the channel with an application cache |
663 | 0 | // reported by the channel child. Dropping it here may be too early. |
664 | 0 | appCacheChan->SetInheritApplicationCache(false); |
665 | 0 | if (!appCacheClientID.IsEmpty()) { |
666 | 0 | nsCOMPtr<nsIApplicationCache> appCache; |
667 | 0 | rv = appCacheService->GetApplicationCache(appCacheClientID, |
668 | 0 | getter_AddRefs(appCache)); |
669 | 0 | if (NS_SUCCEEDED(rv)) { |
670 | 0 | appCacheChan->SetApplicationCache(appCache); |
671 | 0 | setChooseApplicationCache = false; |
672 | 0 | } |
673 | 0 | } |
674 | 0 |
|
675 | 0 | if (setChooseApplicationCache) { |
676 | 0 | OriginAttributes attrs; |
677 | 0 | NS_GetOriginAttributes(httpChannel, attrs); |
678 | 0 |
|
679 | 0 | nsCOMPtr<nsIPrincipal> principal = |
680 | 0 | BasePrincipal::CreateCodebasePrincipal(uri, attrs); |
681 | 0 |
|
682 | 0 | bool chooseAppCache = false; |
683 | 0 | // This works because we've already called SetNotificationCallbacks and |
684 | 0 | // done mPBOverride logic by this point. |
685 | 0 | chooseAppCache = NS_ShouldCheckAppCache(principal); |
686 | 0 |
|
687 | 0 | appCacheChan->SetChooseApplicationCache(chooseAppCache); |
688 | 0 | } |
689 | 0 | } |
690 | 0 |
|
691 | 0 | httpChannel->SetRequestContextID(aRequestContextID); |
692 | 0 |
|
693 | 0 | // Store the strong reference of channel and parent listener object until |
694 | 0 | // all the initialization procedure is complete without failure, to remove |
695 | 0 | // cycle reference in fail case and to avoid memory leakage. |
696 | 0 | mChannel = httpChannel.forget(); |
697 | 0 | mParentListener = parentListener.forget(); |
698 | 0 | mChannel->SetNotificationCallbacks(mParentListener); |
699 | 0 |
|
700 | 0 |
|
701 | 0 | mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse; |
702 | 0 |
|
703 | 0 | MOZ_ASSERT(!mBgParent); |
704 | 0 | MOZ_ASSERT(mPromise.IsEmpty()); |
705 | 0 | // Wait for HttpBackgrounChannel to continue the async open procedure. |
706 | 0 | ++mAsyncOpenBarrier; |
707 | 0 | RefPtr<GenericPromise> promise = WaitForBgParent(); |
708 | 0 | RefPtr<HttpChannelParent> self = this; |
709 | 0 | promise->Then(GetMainThreadSerialEventTarget(), __func__, |
710 | 0 | [self]() { |
711 | 0 | self->mRequest.Complete(); |
712 | 0 | self->TryInvokeAsyncOpen(NS_OK); |
713 | 0 | }, |
714 | 0 | [self](nsresult aStatus) { |
715 | 0 | self->mRequest.Complete(); |
716 | 0 | self->TryInvokeAsyncOpen(aStatus); |
717 | 0 | }) |
718 | 0 | ->Track(mRequest); |
719 | 0 |
|
720 | 0 | return true; |
721 | 0 | } |
722 | | |
723 | | already_AddRefed<GenericPromise> |
724 | | HttpChannelParent::WaitForBgParent() |
725 | 0 | { |
726 | 0 | LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this)); |
727 | 0 | MOZ_ASSERT(!mBgParent); |
728 | 0 | MOZ_ASSERT(mChannel); |
729 | 0 |
|
730 | 0 |
|
731 | 0 | nsCOMPtr<nsIBackgroundChannelRegistrar> registrar = |
732 | 0 | do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID); |
733 | 0 | MOZ_ASSERT(registrar); |
734 | 0 | registrar->LinkHttpChannel(mChannel->ChannelId(), this); |
735 | 0 |
|
736 | 0 | if (mBgParent) { |
737 | 0 | RefPtr<GenericPromise> promise = mPromise.Ensure(__func__); |
738 | 0 | // resolve promise immediatedly if bg channel is ready. |
739 | 0 | mPromise.Resolve(true, __func__); |
740 | 0 | return promise.forget(); |
741 | 0 | } |
742 | 0 | |
743 | 0 | return mPromise.Ensure(__func__);; |
744 | 0 | } |
745 | | |
746 | | bool |
747 | | HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept) |
748 | 0 | { |
749 | 0 | nsresult rv; |
750 | 0 |
|
751 | 0 | LOG(("HttpChannelParent::ConnectChannel: Looking for a registered channel " |
752 | 0 | "[this=%p, id=%" PRIu32 "]\n", this, registrarId)); |
753 | 0 | nsCOMPtr<nsIChannel> channel; |
754 | 0 | rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(channel)); |
755 | 0 | if (NS_FAILED(rv)) { |
756 | 0 | NS_ERROR("Could not find the http channel to connect its IPC parent"); |
757 | 0 | // This makes the channel delete itself safely. It's the only thing |
758 | 0 | // we can do now, since this parent channel cannot be used and there is |
759 | 0 | // no other way to tell the child side there were something wrong. |
760 | 0 | Delete(); |
761 | 0 | return true; |
762 | 0 | } |
763 | 0 |
|
764 | 0 | LOG((" found channel %p, rv=%08" PRIx32, channel.get(), static_cast<uint32_t>(rv))); |
765 | 0 | mChannel = do_QueryObject(channel); |
766 | 0 | if (!mChannel) { |
767 | 0 | LOG((" but it's not HttpBaseChannel")); |
768 | 0 | Delete(); |
769 | 0 | return true; |
770 | 0 | } |
771 | 0 |
|
772 | 0 | LOG((" and it is HttpBaseChannel %p", mChannel.get())); |
773 | 0 |
|
774 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); |
775 | 0 | if (httpChannelImpl) { |
776 | 0 | httpChannelImpl->SetWarningReporter(this); |
777 | 0 | } |
778 | 0 |
|
779 | 0 | nsCOMPtr<nsINetworkInterceptController> controller; |
780 | 0 | NS_QueryNotificationCallbacks(channel, controller); |
781 | 0 | RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller); |
782 | 0 | MOZ_ASSERT(parentListener); |
783 | 0 | parentListener->SetupInterceptionAfterRedirect(shouldIntercept); |
784 | 0 |
|
785 | 0 | if (mPBOverride != kPBOverride_Unset) { |
786 | 0 | // redirected-to channel may not support PB |
787 | 0 | nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel); |
788 | 0 | if (pbChannel) { |
789 | 0 | pbChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); |
790 | 0 | } |
791 | 0 | } |
792 | 0 |
|
793 | 0 | MOZ_ASSERT(!mBgParent); |
794 | 0 | MOZ_ASSERT(mPromise.IsEmpty()); |
795 | 0 | // Waiting for background channel |
796 | 0 | RefPtr<GenericPromise> promise = WaitForBgParent(); |
797 | 0 | RefPtr<HttpChannelParent> self = this; |
798 | 0 | promise->Then(GetMainThreadSerialEventTarget(), __func__, |
799 | 0 | [self]() { |
800 | 0 | self->mRequest.Complete(); |
801 | 0 | }, |
802 | 0 | [self](const nsresult& aResult) { |
803 | 0 | NS_ERROR("failed to establish the background channel"); |
804 | 0 | self->mRequest.Complete(); |
805 | 0 | }) |
806 | 0 | ->Track(mRequest); |
807 | 0 | return true; |
808 | 0 | } |
809 | | |
810 | | mozilla::ipc::IPCResult |
811 | | HttpChannelParent::RecvSetPriority(const int16_t& priority) |
812 | 0 | { |
813 | 0 | LOG(("HttpChannelParent::RecvSetPriority [this=%p, priority=%d]\n", |
814 | 0 | this, priority)); |
815 | 0 |
|
816 | 0 | if (mChannel) { |
817 | 0 | mChannel->SetPriority(priority); |
818 | 0 | } |
819 | 0 |
|
820 | 0 | nsCOMPtr<nsISupportsPriority> priorityRedirectChannel = |
821 | 0 | do_QueryInterface(mRedirectChannel); |
822 | 0 | if (priorityRedirectChannel) |
823 | 0 | priorityRedirectChannel->SetPriority(priority); |
824 | 0 |
|
825 | 0 | return IPC_OK(); |
826 | 0 | } |
827 | | |
828 | | mozilla::ipc::IPCResult |
829 | | HttpChannelParent::RecvSetClassOfService(const uint32_t& cos) |
830 | 0 | { |
831 | 0 | if (mChannel) { |
832 | 0 | mChannel->SetClassFlags(cos); |
833 | 0 | } |
834 | 0 | return IPC_OK(); |
835 | 0 | } |
836 | | |
837 | | mozilla::ipc::IPCResult |
838 | | HttpChannelParent::RecvSuspend() |
839 | 0 | { |
840 | 0 | LOG(("HttpChannelParent::RecvSuspend [this=%p]\n", this)); |
841 | 0 |
|
842 | 0 | if (mChannel) { |
843 | 0 | mChannel->Suspend(); |
844 | 0 | } |
845 | 0 | return IPC_OK(); |
846 | 0 | } |
847 | | |
848 | | mozilla::ipc::IPCResult |
849 | | HttpChannelParent::RecvResume() |
850 | 0 | { |
851 | 0 | LOG(("HttpChannelParent::RecvResume [this=%p]\n", this)); |
852 | 0 |
|
853 | 0 | if (mChannel) { |
854 | 0 | mChannel->Resume(); |
855 | 0 | } |
856 | 0 | return IPC_OK(); |
857 | 0 | } |
858 | | |
859 | | mozilla::ipc::IPCResult |
860 | | HttpChannelParent::RecvCancel(const nsresult& status) |
861 | 0 | { |
862 | 0 | LOG(("HttpChannelParent::RecvCancel [this=%p]\n", this)); |
863 | 0 |
|
864 | 0 | // May receive cancel before channel has been constructed! |
865 | 0 | if (mChannel) { |
866 | 0 | mChannel->Cancel(status); |
867 | 0 | } |
868 | 0 | return IPC_OK(); |
869 | 0 | } |
870 | | |
871 | | |
872 | | mozilla::ipc::IPCResult |
873 | | HttpChannelParent::RecvSetCacheTokenCachedCharset(const nsCString& charset) |
874 | 0 | { |
875 | 0 | if (mCacheEntry) |
876 | 0 | mCacheEntry->SetMetaDataElement("charset", charset.get()); |
877 | 0 | return IPC_OK(); |
878 | 0 | } |
879 | | |
880 | | mozilla::ipc::IPCResult |
881 | | HttpChannelParent::RecvRedirect2Verify(const nsresult& aResult, |
882 | | const RequestHeaderTuples& changedHeaders, |
883 | | const ChildLoadInfoForwarderArgs& aLoadInfoForwarder, |
884 | | const uint32_t& loadFlags, |
885 | | const uint32_t& referrerPolicy, |
886 | | const OptionalURIParams& aReferrerURI, |
887 | | const OptionalURIParams& aAPIRedirectURI, |
888 | | const OptionalCorsPreflightArgs& aCorsPreflightArgs, |
889 | | const bool& aChooseAppcache) |
890 | 0 | { |
891 | 0 | LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n", |
892 | 0 | this, static_cast<uint32_t>(aResult))); |
893 | 0 |
|
894 | 0 | // Result from the child. If something fails here, we might overwrite a |
895 | 0 | // success with a further failure. |
896 | 0 | nsresult result = aResult; |
897 | 0 |
|
898 | 0 | // Local results. |
899 | 0 | nsresult rv; |
900 | 0 |
|
901 | 0 | if (NS_SUCCEEDED(result)) { |
902 | 0 | nsCOMPtr<nsIHttpChannel> newHttpChannel = |
903 | 0 | do_QueryInterface(mRedirectChannel); |
904 | 0 |
|
905 | 0 | if (newHttpChannel) { |
906 | 0 | nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI); |
907 | 0 |
|
908 | 0 | if (apiRedirectUri) { |
909 | 0 | rv = newHttpChannel->RedirectTo(apiRedirectUri); |
910 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
911 | 0 | } |
912 | 0 |
|
913 | 0 | for (uint32_t i = 0; i < changedHeaders.Length(); i++) { |
914 | 0 | if (changedHeaders[i].mEmpty) { |
915 | 0 | rv = newHttpChannel->SetEmptyRequestHeader(changedHeaders[i].mHeader); |
916 | 0 | } else { |
917 | 0 | rv = newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader, |
918 | 0 | changedHeaders[i].mValue, |
919 | 0 | changedHeaders[i].mMerge); |
920 | 0 | } |
921 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
922 | 0 | } |
923 | 0 |
|
924 | 0 | // A successfully redirected channel must have the LOAD_REPLACE flag. |
925 | 0 | MOZ_ASSERT(loadFlags & nsIChannel::LOAD_REPLACE); |
926 | 0 | if (loadFlags & nsIChannel::LOAD_REPLACE) { |
927 | 0 | newHttpChannel->SetLoadFlags(loadFlags); |
928 | 0 | } |
929 | 0 |
|
930 | 0 | if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) { |
931 | 0 | nsCOMPtr<nsIHttpChannelInternal> newInternalChannel = |
932 | 0 | do_QueryInterface(newHttpChannel); |
933 | 0 | MOZ_RELEASE_ASSERT(newInternalChannel); |
934 | 0 | const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs(); |
935 | 0 | newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders()); |
936 | 0 | } |
937 | 0 |
|
938 | 0 | nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI); |
939 | 0 | rv = newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy); |
940 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
941 | 0 |
|
942 | 0 | nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
943 | 0 | do_QueryInterface(newHttpChannel); |
944 | 0 | if (appCacheChannel) { |
945 | 0 | appCacheChannel->SetChooseApplicationCache(aChooseAppcache); |
946 | 0 | } |
947 | 0 |
|
948 | 0 | nsCOMPtr<nsILoadInfo> newLoadInfo; |
949 | 0 | Unused << newHttpChannel->GetLoadInfo(getter_AddRefs(newLoadInfo)); |
950 | 0 | rv = MergeChildLoadInfoForwarder(aLoadInfoForwarder, newLoadInfo); |
951 | 0 | if (NS_FAILED(rv) && NS_SUCCEEDED(result)) { |
952 | 0 | result = rv; |
953 | 0 | } |
954 | 0 | } |
955 | 0 | } |
956 | 0 |
|
957 | 0 | // Continue the verification procedure if child has veto the redirection. |
958 | 0 | if (NS_FAILED(result)) { |
959 | 0 | ContinueRedirect2Verify(result); |
960 | 0 | return IPC_OK(); |
961 | 0 | } |
962 | 0 |
|
963 | 0 | // Wait for background channel ready on target channel |
964 | 0 | nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg = |
965 | 0 | RedirectChannelRegistrar::GetOrCreate(); |
966 | 0 | MOZ_ASSERT(redirectReg); |
967 | 0 |
|
968 | 0 | nsCOMPtr<nsIParentChannel> redirectParentChannel; |
969 | 0 | rv = redirectReg->GetParentChannel(mRedirectRegistrarId, |
970 | 0 | getter_AddRefs(redirectParentChannel)); |
971 | 0 | MOZ_ASSERT(redirectParentChannel); |
972 | 0 | if (!redirectParentChannel) { |
973 | 0 | ContinueRedirect2Verify(rv); |
974 | 0 | return IPC_OK(); |
975 | 0 | } |
976 | 0 |
|
977 | 0 | nsCOMPtr<nsIParentRedirectingChannel> redirectedParent = |
978 | 0 | do_QueryInterface(redirectParentChannel); |
979 | 0 | if (!redirectedParent) { |
980 | 0 | // Continue verification procedure if redirecting to non-Http protocol |
981 | 0 | ContinueRedirect2Verify(result); |
982 | 0 | return IPC_OK(); |
983 | 0 | } |
984 | 0 |
|
985 | 0 | // Ask redirected channel if verification can proceed. |
986 | 0 | // ContinueRedirect2Verify will be invoked when redirected channel is ready. |
987 | 0 | redirectedParent->ContinueVerification(this); |
988 | 0 |
|
989 | 0 | return IPC_OK(); |
990 | 0 | } |
991 | | |
992 | | // from nsIParentRedirectingChannel |
993 | | NS_IMETHODIMP |
994 | | HttpChannelParent::ContinueVerification(nsIAsyncVerifyRedirectReadyCallback* aCallback) |
995 | 0 | { |
996 | 0 | LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n", |
997 | 0 | this, aCallback)); |
998 | 0 |
|
999 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1000 | 0 | MOZ_ASSERT(aCallback); |
1001 | 0 |
|
1002 | 0 | // Continue the verification procedure if background channel is ready. |
1003 | 0 | if (mBgParent) { |
1004 | 0 | aCallback->ReadyToVerify(NS_OK); |
1005 | 0 | return NS_OK; |
1006 | 0 | } |
1007 | 0 | |
1008 | 0 | // ConnectChannel must be received before Redirect2Verify. |
1009 | 0 | MOZ_ASSERT(!mPromise.IsEmpty()); |
1010 | 0 |
|
1011 | 0 | // Otherwise, wait for the background channel. |
1012 | 0 | RefPtr<GenericPromise> promise = WaitForBgParent(); |
1013 | 0 | nsCOMPtr<nsIAsyncVerifyRedirectReadyCallback> callback = aCallback; |
1014 | 0 | promise->Then(GetMainThreadSerialEventTarget(), __func__, |
1015 | 0 | [callback]() { |
1016 | 0 | callback->ReadyToVerify(NS_OK); |
1017 | 0 | }, |
1018 | 0 | [callback](const nsresult& aResult) { |
1019 | 0 | NS_ERROR("failed to establish the background channel"); |
1020 | 0 | callback->ReadyToVerify(aResult); |
1021 | 0 | }); |
1022 | 0 | return NS_OK; |
1023 | 0 | } |
1024 | | |
1025 | | void |
1026 | | HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult) |
1027 | 0 | { |
1028 | 0 | LOG(("HttpChannelParent::ContinueRedirect2Verify [this=%p result=%" PRIx32 "]\n", |
1029 | 0 | this, static_cast<uint32_t>(aResult))); |
1030 | 0 |
|
1031 | 0 | if (!mRedirectCallback) { |
1032 | 0 | // This should according the logic never happen, log the situation. |
1033 | 0 | if (mReceivedRedirect2Verify) |
1034 | 0 | LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this)); |
1035 | 0 | if (mSentRedirect1BeginFailed) |
1036 | 0 | LOG(("RecvRedirect2Verify[%p]: Send to child failed", this)); |
1037 | 0 | if ((mRedirectRegistrarId > 0) && NS_FAILED(aResult)) |
1038 | 0 | LOG(("RecvRedirect2Verify[%p]: Redirect failed", this)); |
1039 | 0 | if ((mRedirectRegistrarId > 0) && NS_SUCCEEDED(aResult)) |
1040 | 0 | LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this)); |
1041 | 0 | if (!mRedirectChannel) |
1042 | 0 | LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this)); |
1043 | 0 |
|
1044 | 0 | NS_ERROR("Unexpcted call to HttpChannelParent::RecvRedirect2Verify, " |
1045 | 0 | "mRedirectCallback null"); |
1046 | 0 | } |
1047 | 0 |
|
1048 | 0 | mReceivedRedirect2Verify = true; |
1049 | 0 |
|
1050 | 0 | if (mRedirectCallback) { |
1051 | 0 | LOG(("HttpChannelParent::ContinueRedirect2Verify call OnRedirectVerifyCallback" |
1052 | 0 | " [this=%p result=%" PRIx32 ", mRedirectCallback=%p]\n", |
1053 | 0 | this, static_cast<uint32_t>(aResult), mRedirectCallback.get())); |
1054 | 0 | mRedirectCallback->OnRedirectVerifyCallback(aResult); |
1055 | 0 | mRedirectCallback = nullptr; |
1056 | 0 | } |
1057 | 0 | } |
1058 | | |
1059 | | mozilla::ipc::IPCResult |
1060 | | HttpChannelParent::RecvDocumentChannelCleanup(const bool& clearCacheEntry) |
1061 | 0 | { |
1062 | 0 | CleanupBackgroundChannel(); // Background channel can be closed. |
1063 | 0 | mChannel = nullptr; // Reclaim some memory sooner. |
1064 | 0 | if (clearCacheEntry) { |
1065 | 0 | mCacheEntry = nullptr; // Else we'll block other channels reading same URI |
1066 | 0 | } |
1067 | 0 | return IPC_OK(); |
1068 | 0 | } |
1069 | | |
1070 | | mozilla::ipc::IPCResult |
1071 | | HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign() |
1072 | 0 | { |
1073 | 0 | if (mOfflineForeignMarker) { |
1074 | 0 | mOfflineForeignMarker->MarkAsForeign(); |
1075 | 0 | mOfflineForeignMarker = nullptr; |
1076 | 0 | } |
1077 | 0 |
|
1078 | 0 | return IPC_OK(); |
1079 | 0 | } |
1080 | | |
1081 | | class DivertDataAvailableEvent : public MainThreadChannelEvent |
1082 | | { |
1083 | | public: |
1084 | | DivertDataAvailableEvent(HttpChannelParent* aParent, |
1085 | | const nsCString& data, |
1086 | | const uint64_t& offset, |
1087 | | const uint32_t& count) |
1088 | | : mParent(aParent) |
1089 | | , mData(data) |
1090 | | , mOffset(offset) |
1091 | | , mCount(count) |
1092 | 0 | { |
1093 | 0 | } |
1094 | | |
1095 | | void Run() override |
1096 | 0 | { |
1097 | 0 | mParent->DivertOnDataAvailable(mData, mOffset, mCount); |
1098 | 0 | } |
1099 | | |
1100 | | private: |
1101 | | HttpChannelParent* mParent; |
1102 | | nsCString mData; |
1103 | | uint64_t mOffset; |
1104 | | uint32_t mCount; |
1105 | | }; |
1106 | | |
1107 | | mozilla::ipc::IPCResult |
1108 | | HttpChannelParent::RecvDivertOnDataAvailable(const nsCString& data, |
1109 | | const uint64_t& offset, |
1110 | | const uint32_t& count) |
1111 | 0 | { |
1112 | 0 | LOG(("HttpChannelParent::RecvDivertOnDataAvailable [this=%p]\n", this)); |
1113 | 0 |
|
1114 | 0 | MOZ_ASSERT(mParentListener); |
1115 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
1116 | 0 | MOZ_ASSERT(mDivertingFromChild, |
1117 | 0 | "Cannot RecvDivertOnDataAvailable if diverting is not set!"); |
1118 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1119 | 0 | return IPC_FAIL_NO_REASON(this); |
1120 | 0 | } |
1121 | 0 |
|
1122 | 0 | // Drop OnDataAvailables if the parent was canceled already. |
1123 | 0 | if (NS_FAILED(mStatus)) { |
1124 | 0 | return IPC_OK(); |
1125 | 0 | } |
1126 | 0 |
|
1127 | 0 | mEventQ->RunOrEnqueue(new DivertDataAvailableEvent(this, data, offset, |
1128 | 0 | count)); |
1129 | 0 | return IPC_OK(); |
1130 | 0 | } |
1131 | | |
1132 | | void |
1133 | | HttpChannelParent::DivertOnDataAvailable(const nsCString& data, |
1134 | | const uint64_t& offset, |
1135 | | const uint32_t& count) |
1136 | 0 | { |
1137 | 0 | LOG(("HttpChannelParent::DivertOnDataAvailable [this=%p]\n", this)); |
1138 | 0 |
|
1139 | 0 | MOZ_ASSERT(mParentListener); |
1140 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
1141 | 0 | MOZ_ASSERT(mDivertingFromChild, |
1142 | 0 | "Cannot DivertOnDataAvailable if diverting is not set!"); |
1143 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1144 | 0 | return; |
1145 | 0 | } |
1146 | 0 |
|
1147 | 0 | // Drop OnDataAvailables if the parent was canceled already. |
1148 | 0 | if (NS_FAILED(mStatus)) { |
1149 | 0 | return; |
1150 | 0 | } |
1151 | 0 | |
1152 | 0 | nsCOMPtr<nsIInputStream> stringStream; |
1153 | 0 | nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), |
1154 | 0 | count, NS_ASSIGNMENT_DEPEND); |
1155 | 0 | if (NS_FAILED(rv)) { |
1156 | 0 | if (mChannel) { |
1157 | 0 | mChannel->Cancel(rv); |
1158 | 0 | } |
1159 | 0 | mStatus = rv; |
1160 | 0 | return; |
1161 | 0 | } |
1162 | 0 |
|
1163 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
1164 | 0 |
|
1165 | 0 | rv = mParentListener->OnDataAvailable(mChannel, nullptr, stringStream, |
1166 | 0 | offset, count); |
1167 | 0 | stringStream->Close(); |
1168 | 0 | if (NS_FAILED(rv)) { |
1169 | 0 | if (mChannel) { |
1170 | 0 | mChannel->Cancel(rv); |
1171 | 0 | } |
1172 | 0 | mStatus = rv; |
1173 | 0 | } |
1174 | 0 | } |
1175 | | |
1176 | | class DivertStopRequestEvent : public MainThreadChannelEvent |
1177 | | { |
1178 | | public: |
1179 | | DivertStopRequestEvent(HttpChannelParent* aParent, |
1180 | | const nsresult& statusCode) |
1181 | | : mParent(aParent) |
1182 | | , mStatusCode(statusCode) |
1183 | 0 | { |
1184 | 0 | } |
1185 | | |
1186 | | void Run() override |
1187 | 0 | { |
1188 | 0 | mParent->DivertOnStopRequest(mStatusCode); |
1189 | 0 | } |
1190 | | |
1191 | | private: |
1192 | | HttpChannelParent* mParent; |
1193 | | nsresult mStatusCode; |
1194 | | }; |
1195 | | |
1196 | | mozilla::ipc::IPCResult |
1197 | | HttpChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode) |
1198 | 0 | { |
1199 | 0 | LOG(("HttpChannelParent::RecvDivertOnStopRequest [this=%p]\n", this)); |
1200 | 0 |
|
1201 | 0 | MOZ_ASSERT(mParentListener); |
1202 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
1203 | 0 | MOZ_ASSERT(mDivertingFromChild, |
1204 | 0 | "Cannot RecvDivertOnStopRequest if diverting is not set!"); |
1205 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1206 | 0 | return IPC_FAIL_NO_REASON(this); |
1207 | 0 | } |
1208 | 0 |
|
1209 | 0 | mEventQ->RunOrEnqueue(new DivertStopRequestEvent(this, statusCode)); |
1210 | 0 | return IPC_OK(); |
1211 | 0 | } |
1212 | | |
1213 | | void |
1214 | | HttpChannelParent::DivertOnStopRequest(const nsresult& statusCode) |
1215 | 0 | { |
1216 | 0 | LOG(("HttpChannelParent::DivertOnStopRequest [this=%p]\n", this)); |
1217 | 0 |
|
1218 | 0 | MOZ_ASSERT(mParentListener); |
1219 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
1220 | 0 | MOZ_ASSERT(mDivertingFromChild, |
1221 | 0 | "Cannot DivertOnStopRequest if diverting is not set!"); |
1222 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1223 | 0 | return; |
1224 | 0 | } |
1225 | 0 |
|
1226 | 0 | // Honor the channel's status even if the underlying transaction completed. |
1227 | 0 | nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode; |
1228 | 0 |
|
1229 | 0 | // Reset fake pending status in case OnStopRequest has already been called. |
1230 | 0 | if (mChannel) { |
1231 | 0 | mChannel->ForcePending(false); |
1232 | 0 | } |
1233 | 0 |
|
1234 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
1235 | 0 | mParentListener->OnStopRequest(mChannel, nullptr, status); |
1236 | 0 | } |
1237 | | |
1238 | | class DivertCompleteEvent : public MainThreadChannelEvent |
1239 | | { |
1240 | | public: |
1241 | | explicit DivertCompleteEvent(HttpChannelParent* aParent) |
1242 | | : mParent(aParent) |
1243 | 0 | { |
1244 | 0 | } |
1245 | | |
1246 | | void Run() override |
1247 | 0 | { |
1248 | 0 | mParent->DivertComplete(); |
1249 | 0 | } |
1250 | | |
1251 | | private: |
1252 | | HttpChannelParent* mParent; |
1253 | | }; |
1254 | | |
1255 | | mozilla::ipc::IPCResult |
1256 | | HttpChannelParent::RecvDivertComplete() |
1257 | 0 | { |
1258 | 0 | LOG(("HttpChannelParent::RecvDivertComplete [this=%p]\n", this)); |
1259 | 0 |
|
1260 | 0 | MOZ_ASSERT(mParentListener); |
1261 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
1262 | 0 | MOZ_ASSERT(mDivertingFromChild, |
1263 | 0 | "Cannot RecvDivertComplete if diverting is not set!"); |
1264 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1265 | 0 | return IPC_FAIL_NO_REASON(this); |
1266 | 0 | } |
1267 | 0 |
|
1268 | 0 | mEventQ->RunOrEnqueue(new DivertCompleteEvent(this)); |
1269 | 0 | return IPC_OK(); |
1270 | 0 | } |
1271 | | |
1272 | | void |
1273 | | HttpChannelParent::DivertComplete() |
1274 | 0 | { |
1275 | 0 | LOG(("HttpChannelParent::DivertComplete [this=%p]\n", this)); |
1276 | 0 |
|
1277 | 0 | MOZ_ASSERT(mParentListener); |
1278 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
1279 | 0 | MOZ_ASSERT(mDivertingFromChild, |
1280 | 0 | "Cannot DivertComplete if diverting is not set!"); |
1281 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1282 | 0 | return; |
1283 | 0 | } |
1284 | 0 |
|
1285 | 0 | nsresult rv = ResumeForDiversion(); |
1286 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1287 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
1288 | 0 | return; |
1289 | 0 | } |
1290 | 0 | |
1291 | 0 | mParentListener = nullptr; |
1292 | 0 | } |
1293 | | |
1294 | | void |
1295 | | HttpChannelParent::MaybeFlushPendingDiversion() |
1296 | 0 | { |
1297 | 0 | if (!mPendingDiversion) { |
1298 | 0 | return; |
1299 | 0 | } |
1300 | 0 | |
1301 | 0 | mPendingDiversion = false; |
1302 | 0 |
|
1303 | 0 | nsresult rv = SuspendForDiversion(); |
1304 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1305 | 0 | return; |
1306 | 0 | } |
1307 | 0 | |
1308 | 0 | if (mDivertListener) { |
1309 | 0 | DivertTo(mDivertListener); |
1310 | 0 | } |
1311 | 0 |
|
1312 | 0 | } |
1313 | | |
1314 | | static void |
1315 | | FinishCrossProcessRedirect(nsHttpChannel *channel, nsresult status) |
1316 | 0 | { |
1317 | 0 | if (NS_SUCCEEDED(status)) { |
1318 | 0 | nsCOMPtr<nsINetworkInterceptController> controller; |
1319 | 0 | NS_QueryNotificationCallbacks(channel, controller); |
1320 | 0 | RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller); |
1321 | 0 | MOZ_ASSERT(parentListener); |
1322 | 0 |
|
1323 | 0 | // This updates HttpChannelParentListener to point to this parent and at |
1324 | 0 | // the same time cancels the old channel. |
1325 | 0 | parentListener->OnRedirectResult(status == NS_OK); |
1326 | 0 | } |
1327 | 0 |
|
1328 | 0 | channel->OnRedirectVerifyCallback(status); |
1329 | 0 | } |
1330 | | |
1331 | | mozilla::ipc::IPCResult |
1332 | | HttpChannelParent::RecvCrossProcessRedirectDone(const nsresult& aResult) |
1333 | 0 | { |
1334 | 0 | RefPtr<nsHttpChannel> chan = do_QueryObject(mChannel); |
1335 | 0 | if (!mBgParent) { |
1336 | 0 | RefPtr<GenericPromise> promise = WaitForBgParent(); |
1337 | 0 | RefPtr<HttpChannelParent> self = this; |
1338 | 0 | promise->Then(GetMainThreadSerialEventTarget(), __func__, |
1339 | 0 | [self, chan, aResult]() { |
1340 | 0 | FinishCrossProcessRedirect(chan, aResult); |
1341 | 0 | }, |
1342 | 0 | [self, chan](const nsresult& aRejectionRv) { |
1343 | 0 | MOZ_ASSERT(NS_FAILED(aRejectionRv), "This should be an error code"); |
1344 | 0 | FinishCrossProcessRedirect(chan, aRejectionRv); |
1345 | 0 | }); |
1346 | 0 | } else { |
1347 | 0 | FinishCrossProcessRedirect(chan, aResult); |
1348 | 0 | } |
1349 | 0 |
|
1350 | 0 | return IPC_OK(); |
1351 | 0 | } |
1352 | | |
1353 | | void |
1354 | | HttpChannelParent::ResponseSynthesized() |
1355 | 0 | { |
1356 | 0 | // Suspend now even though the FinishSynthesizeResponse runnable has |
1357 | 0 | // not executed. We want to suspend after we get far enough to trigger |
1358 | 0 | // the synthesis, but not actually allow the nsHttpChannel to trigger |
1359 | 0 | // any OnStartRequests(). |
1360 | 0 | if (mSuspendAfterSynthesizeResponse) { |
1361 | 0 | mChannel->Suspend(); |
1362 | 0 | } |
1363 | 0 |
|
1364 | 0 | mWillSynthesizeResponse = false; |
1365 | 0 |
|
1366 | 0 | MaybeFlushPendingDiversion(); |
1367 | 0 | } |
1368 | | |
1369 | | mozilla::ipc::IPCResult |
1370 | | HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(const URIParams& uri, |
1371 | | const mozilla::ipc::PrincipalInfo& requestingPrincipal) |
1372 | 0 | { |
1373 | 0 | nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(uri); |
1374 | 0 | if (!deserializedURI) { |
1375 | 0 | return IPC_FAIL_NO_REASON(this); |
1376 | 0 | } |
1377 | 0 | nsCOMPtr<nsIPrincipal> principal = |
1378 | 0 | PrincipalInfoToPrincipal(requestingPrincipal); |
1379 | 0 | if (!principal) { |
1380 | 0 | return IPC_FAIL_NO_REASON(this); |
1381 | 0 | } |
1382 | 0 | nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI, |
1383 | 0 | principal); |
1384 | 0 | return IPC_OK(); |
1385 | 0 | } |
1386 | | |
1387 | | //----------------------------------------------------------------------------- |
1388 | | // HttpChannelParent::nsIRequestObserver |
1389 | | //----------------------------------------------------------------------------- |
1390 | | |
1391 | | static void |
1392 | | GetTimingAttributes(HttpBaseChannel* aChannel, ResourceTimingStruct& aTiming) |
1393 | 0 | { |
1394 | 0 | aChannel->GetDomainLookupStart(&aTiming.domainLookupStart); |
1395 | 0 | aChannel->GetDomainLookupEnd(&aTiming.domainLookupEnd); |
1396 | 0 | aChannel->GetConnectStart(&aTiming.connectStart); |
1397 | 0 | aChannel->GetTcpConnectEnd(&aTiming.tcpConnectEnd); |
1398 | 0 | aChannel->GetSecureConnectionStart(&aTiming.secureConnectionStart); |
1399 | 0 | aChannel->GetConnectEnd(&aTiming.connectEnd); |
1400 | 0 | aChannel->GetRequestStart(&aTiming.requestStart); |
1401 | 0 | aChannel->GetResponseStart(&aTiming.responseStart); |
1402 | 0 | aChannel->GetResponseEnd(&aTiming.responseEnd); |
1403 | 0 | aChannel->GetAsyncOpen(&aTiming.fetchStart); |
1404 | 0 | aChannel->GetRedirectStart(&aTiming.redirectStart); |
1405 | 0 | aChannel->GetRedirectEnd(&aTiming.redirectEnd); |
1406 | 0 | aChannel->GetTransferSize(&aTiming.transferSize); |
1407 | 0 | aChannel->GetEncodedBodySize(&aTiming.encodedBodySize); |
1408 | 0 | // decodedBodySize can be computed in the child process so it doesn't need |
1409 | 0 | // to be passed down. |
1410 | 0 | aChannel->GetProtocolVersion(aTiming.protocolVersion); |
1411 | 0 |
|
1412 | 0 | aChannel->GetCacheReadStart(&aTiming.cacheReadStart); |
1413 | 0 | aChannel->GetCacheReadEnd(&aTiming.cacheReadEnd); |
1414 | 0 | } |
1415 | | |
1416 | | NS_IMETHODIMP |
1417 | | HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) |
1418 | 0 | { |
1419 | 0 | nsresult rv; |
1420 | 0 |
|
1421 | 0 | LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n", |
1422 | 0 | this, aRequest)); |
1423 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1424 | 0 |
|
1425 | 0 | MOZ_RELEASE_ASSERT(!mDivertingFromChild, |
1426 | 0 | "Cannot call OnStartRequest if diverting is set!"); |
1427 | 0 |
|
1428 | 0 | RefPtr<HttpBaseChannel> chan = do_QueryObject(aRequest); |
1429 | 0 | if (!chan) { |
1430 | 0 | LOG((" aRequest is not HttpBaseChannel")); |
1431 | 0 | NS_ERROR("Expecting only HttpBaseChannel as aRequest in HttpChannelParent::OnStartRequest"); |
1432 | 0 | return NS_ERROR_UNEXPECTED; |
1433 | 0 | } |
1434 | 0 |
|
1435 | 0 | MOZ_ASSERT(mChannel == chan, |
1436 | 0 | "HttpChannelParent getting OnStartRequest from a different HttpBaseChannel instance"); |
1437 | 0 |
|
1438 | 0 | // Send down any permissions which are relevant to this URL if we are |
1439 | 0 | // performing a document load. We can't do that if mIPCClosed is set. |
1440 | 0 | if (!mIPCClosed) { |
1441 | 0 | PContentParent* pcp = Manager()->Manager(); |
1442 | 0 | MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed"); |
1443 | 0 | DebugOnly<nsresult> rv = |
1444 | 0 | static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan); |
1445 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1446 | 0 | } |
1447 | 0 |
|
1448 | 0 | bool isFromCache = false; |
1449 | 0 | uint64_t cacheEntryId = 0; |
1450 | 0 | int32_t fetchCount = 0; |
1451 | 0 | uint32_t expirationTime = nsICacheEntry::NO_EXPIRATION_TIME; |
1452 | 0 | nsCString cachedCharset; |
1453 | 0 |
|
1454 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(chan); |
1455 | 0 |
|
1456 | 0 | if (httpChannelImpl) { |
1457 | 0 | httpChannelImpl->IsFromCache(&isFromCache); |
1458 | 0 | httpChannelImpl->GetCacheEntryId(&cacheEntryId); |
1459 | 0 | httpChannelImpl->GetCacheTokenFetchCount(&fetchCount); |
1460 | 0 | httpChannelImpl->GetCacheTokenExpirationTime(&expirationTime); |
1461 | 0 | httpChannelImpl->GetCacheTokenCachedCharset(cachedCharset); |
1462 | 0 | } |
1463 | 0 |
|
1464 | 0 | bool loadedFromApplicationCache = false; |
1465 | 0 |
|
1466 | 0 | if (httpChannelImpl) { |
1467 | 0 | httpChannelImpl->GetLoadedFromApplicationCache(&loadedFromApplicationCache); |
1468 | 0 | if (loadedFromApplicationCache) { |
1469 | 0 | mOfflineForeignMarker = httpChannelImpl->GetOfflineCacheEntryAsForeignMarker(); |
1470 | 0 | nsCOMPtr<nsIApplicationCache> appCache; |
1471 | 0 | httpChannelImpl->GetApplicationCache(getter_AddRefs(appCache)); |
1472 | 0 | nsCString appCacheGroupId; |
1473 | 0 | nsCString appCacheClientId; |
1474 | 0 | appCache->GetGroupID(appCacheGroupId); |
1475 | 0 | appCache->GetClientID(appCacheClientId); |
1476 | 0 | if (mIPCClosed || |
1477 | 0 | !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId)) |
1478 | 0 | { |
1479 | 0 | return NS_ERROR_UNEXPECTED; |
1480 | 0 | } |
1481 | 0 | } |
1482 | 0 | } |
1483 | 0 | |
1484 | 0 | // Propagate whether or not conversion should occur from the parent-side |
1485 | 0 | // channel to the child-side channel. Then disable the parent-side |
1486 | 0 | // conversion so that it only occurs in the child. |
1487 | 0 | bool applyConversion = true; |
1488 | 0 | Unused << chan->GetApplyConversion(&applyConversion); |
1489 | 0 | chan->SetApplyConversion(false); |
1490 | 0 |
|
1491 | 0 | nsresult channelStatus = NS_OK; |
1492 | 0 | chan->GetStatus(&channelStatus); |
1493 | 0 |
|
1494 | 0 | // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset(). |
1495 | 0 | // It could be already released by nsHttpChannel at that time. |
1496 | 0 | nsCOMPtr<nsISupports> cacheEntry; |
1497 | 0 | uint32_t cacheKey = 0; |
1498 | 0 | nsAutoCString altDataType; |
1499 | 0 |
|
1500 | 0 | if (httpChannelImpl) { |
1501 | 0 | httpChannelImpl->GetCacheToken(getter_AddRefs(cacheEntry)); |
1502 | 0 | mCacheEntry = do_QueryInterface(cacheEntry); |
1503 | 0 |
|
1504 | 0 | httpChannelImpl->GetCacheKey(&cacheKey); |
1505 | 0 |
|
1506 | 0 | httpChannelImpl->GetAlternativeDataType(altDataType); |
1507 | 0 | } |
1508 | 0 |
|
1509 | 0 | nsCString secInfoSerialization; |
1510 | 0 | UpdateAndSerializeSecurityInfo(secInfoSerialization); |
1511 | 0 |
|
1512 | 0 | uint8_t redirectCount = 0; |
1513 | 0 | chan->GetRedirectCount(&redirectCount); |
1514 | 0 |
|
1515 | 0 | int64_t altDataLen = chan->GetAltDataLength(); |
1516 | 0 |
|
1517 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
1518 | 0 | Unused << chan->GetLoadInfo(getter_AddRefs(loadInfo)); |
1519 | 0 |
|
1520 | 0 | ParentLoadInfoForwarderArgs loadInfoForwarderArg; |
1521 | 0 | mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo, &loadInfoForwarderArg); |
1522 | 0 |
|
1523 | 0 | nsHttpResponseHead *responseHead = chan->GetResponseHead(); |
1524 | 0 | bool useResponseHead = !!responseHead; |
1525 | 0 | nsHttpResponseHead cleanedUpResponseHead; |
1526 | 0 | if (responseHead && responseHead->HasHeader(nsHttp::Set_Cookie)) { |
1527 | 0 | cleanedUpResponseHead = *responseHead; |
1528 | 0 | cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie); |
1529 | 0 | responseHead = &cleanedUpResponseHead; |
1530 | 0 | } |
1531 | 0 |
|
1532 | 0 | if (!responseHead) { |
1533 | 0 | responseHead = &cleanedUpResponseHead; |
1534 | 0 | } |
1535 | 0 |
|
1536 | 0 | nsHttpRequestHead *requestHead = chan->GetRequestHead(); |
1537 | 0 | // !!! We need to lock headers and please don't forget to unlock them !!! |
1538 | 0 | requestHead->Enter(); |
1539 | 0 |
|
1540 | 0 | nsHttpHeaderArray cleanedUpRequestHeaders; |
1541 | 0 | bool cleanedUpRequest = false; |
1542 | 0 | if (requestHead->HasHeader(nsHttp::Cookie)) { |
1543 | 0 | cleanedUpRequestHeaders = requestHead->Headers(); |
1544 | 0 | cleanedUpRequestHeaders.ClearHeader(nsHttp::Cookie); |
1545 | 0 | cleanedUpRequest = true; |
1546 | 0 | } |
1547 | 0 |
|
1548 | 0 | ResourceTimingStruct timing; |
1549 | 0 | GetTimingAttributes(mChannel, timing); |
1550 | 0 |
|
1551 | 0 | rv = NS_OK; |
1552 | 0 | if (mIPCClosed || |
1553 | 0 | !SendOnStartRequest(channelStatus, |
1554 | 0 | *responseHead, |
1555 | 0 | useResponseHead, |
1556 | 0 | cleanedUpRequest ? cleanedUpRequestHeaders : requestHead->Headers(), |
1557 | 0 | loadInfoForwarderArg, |
1558 | 0 | isFromCache, |
1559 | 0 | mCacheEntry ? true : false, |
1560 | 0 | cacheEntryId, |
1561 | 0 | fetchCount, expirationTime, |
1562 | 0 | cachedCharset, secInfoSerialization, |
1563 | 0 | chan->GetSelfAddr(), chan->GetPeerAddr(), |
1564 | 0 | redirectCount, |
1565 | 0 | cacheKey, |
1566 | 0 | altDataType, |
1567 | 0 | altDataLen, |
1568 | 0 | applyConversion, |
1569 | 0 | timing)) |
1570 | 0 | { |
1571 | 0 | rv = NS_ERROR_UNEXPECTED; |
1572 | 0 | } |
1573 | 0 | requestHead->Exit(); |
1574 | 0 |
|
1575 | 0 | // OnStartRequest is sent to content process successfully. |
1576 | 0 | // Notify PHttpBackgroundChannelChild that all following IPC mesasges |
1577 | 0 | // should be run after OnStartRequest is handled. |
1578 | 0 | if (NS_SUCCEEDED(rv)) { |
1579 | 0 | MOZ_ASSERT(mBgParent); |
1580 | 0 | if (!mBgParent->OnStartRequestSent()) { |
1581 | 0 | rv = NS_ERROR_UNEXPECTED; |
1582 | 0 | } |
1583 | 0 | } |
1584 | 0 |
|
1585 | 0 | return rv; |
1586 | 0 | } |
1587 | | |
1588 | | NS_IMETHODIMP |
1589 | | HttpChannelParent::OnStopRequest(nsIRequest *aRequest, |
1590 | | nsISupports *aContext, |
1591 | | nsresult aStatusCode) |
1592 | 0 | { |
1593 | 0 | LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32 "]\n", |
1594 | 0 | this, aRequest, static_cast<uint32_t>(aStatusCode))); |
1595 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1596 | 0 |
|
1597 | 0 | MOZ_RELEASE_ASSERT(!mDivertingFromChild, |
1598 | 0 | "Cannot call OnStopRequest if diverting is set!"); |
1599 | 0 | ResourceTimingStruct timing; |
1600 | 0 | GetTimingAttributes(mChannel, timing); |
1601 | 0 |
|
1602 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); |
1603 | 0 | if (httpChannelImpl) { |
1604 | 0 | httpChannelImpl->SetWarningReporter(nullptr); |
1605 | 0 | } |
1606 | 0 |
|
1607 | 0 | nsHttpHeaderArray *responseTrailer = mChannel->GetResponseTrailers(); |
1608 | 0 |
|
1609 | 0 | // Either IPC channel is closed or background channel |
1610 | 0 | // is ready to send OnStopRequest. |
1611 | 0 | MOZ_ASSERT(mIPCClosed || mBgParent); |
1612 | 0 |
|
1613 | 0 | if (mIPCClosed || |
1614 | 0 | !mBgParent || |
1615 | 0 | !mBgParent->OnStopRequest(aStatusCode, timing, |
1616 | 0 | responseTrailer ? *responseTrailer : nsHttpHeaderArray())) { |
1617 | 0 | return NS_ERROR_UNEXPECTED; |
1618 | 0 | } |
1619 | 0 | |
1620 | 0 | if (NeedFlowControl()) { |
1621 | 0 | Telemetry::Accumulate(Telemetry::NETWORK_BACK_PRESSURE_SUSPENSION_RATE, mHasSuspendedByBackPressure); |
1622 | 0 | } |
1623 | 0 |
|
1624 | 0 | return NS_OK; |
1625 | 0 | } |
1626 | | |
1627 | | //----------------------------------------------------------------------------- |
1628 | | // HttpChannelParent::nsIStreamListener |
1629 | | //----------------------------------------------------------------------------- |
1630 | | |
1631 | | NS_IMETHODIMP |
1632 | | HttpChannelParent::OnDataAvailable(nsIRequest *aRequest, |
1633 | | nsISupports *aContext, |
1634 | | nsIInputStream *aInputStream, |
1635 | | uint64_t aOffset, |
1636 | | uint32_t aCount) |
1637 | 0 | { |
1638 | 0 | LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64 |
1639 | 0 | " count=%" PRIu32 "]\n", this, aRequest, aOffset, aCount)); |
1640 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1641 | 0 |
|
1642 | 0 | MOZ_RELEASE_ASSERT(!mDivertingFromChild, |
1643 | 0 | "Cannot call OnDataAvailable if diverting is set!"); |
1644 | 0 |
|
1645 | 0 | nsresult channelStatus = NS_OK; |
1646 | 0 | mChannel->GetStatus(&channelStatus); |
1647 | 0 |
|
1648 | 0 | nsresult transportStatus = NS_NET_STATUS_RECEIVING_FROM; |
1649 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); |
1650 | 0 | if (httpChannelImpl && httpChannelImpl->IsReadingFromCache()) { |
1651 | 0 | transportStatus = NS_NET_STATUS_READING; |
1652 | 0 | } |
1653 | 0 |
|
1654 | 0 | static uint32_t const kCopyChunkSize = 128 * 1024; |
1655 | 0 | uint32_t toRead = std::min<uint32_t>(aCount, kCopyChunkSize); |
1656 | 0 |
|
1657 | 0 | nsCString data; |
1658 | 0 | if (!data.SetCapacity(toRead, fallible)) { |
1659 | 0 | LOG((" out of memory!")); |
1660 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
1661 | 0 | } |
1662 | 0 |
|
1663 | 0 | int32_t count = static_cast<int32_t>(aCount); |
1664 | 0 |
|
1665 | 0 | while (aCount) { |
1666 | 0 | nsresult rv = NS_ReadInputStreamToString(aInputStream, data, toRead); |
1667 | 0 | if (NS_FAILED(rv)) { |
1668 | 0 | return rv; |
1669 | 0 | } |
1670 | 0 | |
1671 | 0 | // Either IPC channel is closed or background channel |
1672 | 0 | // is ready to send OnTransportAndData. |
1673 | 0 | MOZ_ASSERT(mIPCClosed || mBgParent); |
1674 | 0 |
|
1675 | 0 | if (mIPCClosed || !mBgParent || |
1676 | 0 | !mBgParent->OnTransportAndData(channelStatus, transportStatus, |
1677 | 0 | aOffset, toRead, data)) { |
1678 | 0 | return NS_ERROR_UNEXPECTED; |
1679 | 0 | } |
1680 | 0 | |
1681 | 0 | aOffset += toRead; |
1682 | 0 | aCount -= toRead; |
1683 | 0 | toRead = std::min<uint32_t>(aCount, kCopyChunkSize); |
1684 | 0 | } |
1685 | 0 |
|
1686 | 0 | if (NeedFlowControl()) { |
1687 | 0 | // We're going to run out of sending window size |
1688 | 0 | if (mSendWindowSize > 0 && mSendWindowSize <= count) { |
1689 | 0 | MOZ_ASSERT(!mSuspendedForFlowControl); |
1690 | 0 | Unused << mChannel->Suspend(); |
1691 | 0 | mSuspendedForFlowControl = true; |
1692 | 0 | mHasSuspendedByBackPressure = true; |
1693 | 0 | } |
1694 | 0 | mSendWindowSize -= count; |
1695 | 0 | } |
1696 | 0 |
|
1697 | 0 | return NS_OK; |
1698 | 0 | } |
1699 | | |
1700 | | bool |
1701 | | HttpChannelParent::NeedFlowControl() |
1702 | 0 | { |
1703 | 0 | if (mCacheNeedFlowControlInitialized) { |
1704 | 0 | return mNeedFlowControl; |
1705 | 0 | } |
1706 | 0 | |
1707 | 0 | int64_t contentLength = -1; |
1708 | 0 |
|
1709 | 0 | RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); |
1710 | 0 |
|
1711 | 0 | // By design, we won't trigger the flow control if |
1712 | 0 | // a. pref-out |
1713 | 0 | // b. the resource is from cache or partial cache |
1714 | 0 | // c. the resource is small |
1715 | 0 | // Note that we served the cached resource first for partical cache, which is |
1716 | 0 | // ignored here since we only take the first ODA into consideration. |
1717 | 0 | if (gHttpHandler->SendWindowSize() == 0 || |
1718 | 0 | !httpChannelImpl || |
1719 | 0 | httpChannelImpl->IsReadingFromCache() || |
1720 | 0 | NS_FAILED(httpChannelImpl->GetContentLength(&contentLength)) || |
1721 | 0 | contentLength < gHttpHandler->SendWindowSize()) { |
1722 | 0 | mNeedFlowControl = false; |
1723 | 0 | } |
1724 | 0 | mCacheNeedFlowControlInitialized = true; |
1725 | 0 | return mNeedFlowControl; |
1726 | 0 | } |
1727 | | |
1728 | | mozilla::ipc::IPCResult |
1729 | | HttpChannelParent::RecvBytesRead(const int32_t& aCount) |
1730 | 0 | { |
1731 | 0 | if (!NeedFlowControl()) { |
1732 | 0 | return IPC_OK(); |
1733 | 0 | } |
1734 | 0 |
|
1735 | 0 | LOG(("HttpChannelParent::RecvBytesRead [this=%p count=%" PRId32 "]\n", this, aCount)); |
1736 | 0 |
|
1737 | 0 | if (mSendWindowSize <= 0 && mSendWindowSize + aCount > 0) { |
1738 | 0 | MOZ_ASSERT(mSuspendedForFlowControl); |
1739 | 0 | Unused << mChannel->Resume(); |
1740 | 0 | mSuspendedForFlowControl = false; |
1741 | 0 | } |
1742 | 0 | mSendWindowSize += aCount; |
1743 | 0 | return IPC_OK(); |
1744 | 0 | } |
1745 | | |
1746 | | //----------------------------------------------------------------------------- |
1747 | | // HttpChannelParent::nsIProgressEventSink |
1748 | | //----------------------------------------------------------------------------- |
1749 | | |
1750 | | NS_IMETHODIMP |
1751 | | HttpChannelParent::OnProgress(nsIRequest *aRequest, |
1752 | | nsISupports *aContext, |
1753 | | int64_t aProgress, |
1754 | | int64_t aProgressMax) |
1755 | 0 | { |
1756 | 0 | LOG(("HttpChannelParent::OnStatus [this=%p progress=%" PRId64 "max=%" PRId64 |
1757 | 0 | "]\n", this, aProgress, aProgressMax)); |
1758 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1759 | 0 |
|
1760 | 0 | // If it indicates this precedes OnDataAvailable, child can derive the value in ODA. |
1761 | 0 | if (mIgnoreProgress) { |
1762 | 0 | mIgnoreProgress = false; |
1763 | 0 | return NS_OK; |
1764 | 0 | } |
1765 | 0 | |
1766 | 0 | // Either IPC channel is closed or background channel |
1767 | 0 | // is ready to send OnProgress. |
1768 | 0 | MOZ_ASSERT(mIPCClosed || mBgParent); |
1769 | 0 |
|
1770 | 0 | // Send OnProgress events to the child for data upload progress notifications |
1771 | 0 | // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has |
1772 | 0 | // LOAD_BACKGROUND set. |
1773 | 0 | if (mIPCClosed || !mBgParent |
1774 | 0 | || !mBgParent->OnProgress(aProgress, aProgressMax)) { |
1775 | 0 | return NS_ERROR_UNEXPECTED; |
1776 | 0 | } |
1777 | 0 | |
1778 | 0 | return NS_OK; |
1779 | 0 | } |
1780 | | |
1781 | | NS_IMETHODIMP |
1782 | | HttpChannelParent::OnStatus(nsIRequest *aRequest, |
1783 | | nsISupports *aContext, |
1784 | | nsresult aStatus, |
1785 | | const char16_t *aStatusArg) |
1786 | 0 | { |
1787 | 0 | LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n", |
1788 | 0 | this, static_cast<uint32_t>(aStatus))); |
1789 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1790 | 0 |
|
1791 | 0 | // If this precedes OnDataAvailable, transportStatus will be derived in ODA. |
1792 | 0 | if (aStatus == NS_NET_STATUS_RECEIVING_FROM || |
1793 | 0 | aStatus == NS_NET_STATUS_READING) { |
1794 | 0 | // The transport status and progress generated by ODA will be coalesced |
1795 | 0 | // into one IPC message. Therefore, we can ignore the next OnProgress event |
1796 | 0 | // since it is generated by ODA as well. |
1797 | 0 | mIgnoreProgress = true; |
1798 | 0 | return NS_OK; |
1799 | 0 | } |
1800 | 0 | |
1801 | 0 | // Either IPC channel is closed or background channel |
1802 | 0 | // is ready to send OnStatus. |
1803 | 0 | MOZ_ASSERT(mIPCClosed || mBgParent); |
1804 | 0 |
|
1805 | 0 | // Otherwise, send to child now |
1806 | 0 | if (mIPCClosed || !mBgParent || !mBgParent->OnStatus(aStatus)) { |
1807 | 0 | return NS_ERROR_UNEXPECTED; |
1808 | 0 | } |
1809 | 0 | |
1810 | 0 | return NS_OK; |
1811 | 0 | } |
1812 | | |
1813 | | //----------------------------------------------------------------------------- |
1814 | | // HttpChannelParent::nsIParentChannel |
1815 | | //----------------------------------------------------------------------------- |
1816 | | |
1817 | | NS_IMETHODIMP |
1818 | | HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener) |
1819 | 0 | { |
1820 | 0 | LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n", |
1821 | 0 | this, aListener)); |
1822 | 0 | MOZ_ASSERT(aListener); |
1823 | 0 | MOZ_ASSERT(!mParentListener, "SetParentListener should only be called for " |
1824 | 0 | "new HttpChannelParents after a redirect, when " |
1825 | 0 | "mParentListener is null."); |
1826 | 0 | mParentListener = aListener; |
1827 | 0 | return NS_OK; |
1828 | 0 | } |
1829 | | |
1830 | | NS_IMETHODIMP |
1831 | | HttpChannelParent::NotifyTrackingProtectionDisabled() |
1832 | 0 | { |
1833 | 0 | LOG(("HttpChannelParent::NotifyTrackingProtectionDisabled [this=%p]\n", this)); |
1834 | 0 | if (!mIPCClosed) { |
1835 | 0 | MOZ_ASSERT(mBgParent); |
1836 | 0 | Unused << NS_WARN_IF(!mBgParent->OnNotifyTrackingProtectionDisabled()); |
1837 | 0 | } |
1838 | 0 | return NS_OK; |
1839 | 0 | } |
1840 | | |
1841 | | NS_IMETHODIMP |
1842 | | HttpChannelParent::NotifyTrackingCookieBlocked(uint32_t aRejectedReason) |
1843 | 0 | { |
1844 | 0 | LOG(("HttpChannelParent::NotifyTrackingCookieBlocked [this=%p]\n", this)); |
1845 | 0 | if (!mIPCClosed) { |
1846 | 0 | MOZ_ASSERT(mBgParent); |
1847 | 0 | Unused << NS_WARN_IF(!mBgParent->OnNotifyTrackingCookieBlocked(aRejectedReason)); |
1848 | 0 | } |
1849 | 0 | return NS_OK; |
1850 | 0 | } |
1851 | | |
1852 | | NS_IMETHODIMP |
1853 | | HttpChannelParent::SetClassifierMatchedInfo(const nsACString& aList, |
1854 | | const nsACString& aProvider, |
1855 | | const nsACString& aFullHash) |
1856 | 0 | { |
1857 | 0 | LOG(("HttpChannelParent::SetClassifierMatchedInfo [this=%p]\n", this)); |
1858 | 0 | if (!mIPCClosed) { |
1859 | 0 | MOZ_ASSERT(mBgParent); |
1860 | 0 | Unused << mBgParent->OnSetClassifierMatchedInfo(aList, aProvider, aFullHash); |
1861 | 0 | } |
1862 | 0 | return NS_OK; |
1863 | 0 | } |
1864 | | |
1865 | | NS_IMETHODIMP |
1866 | | HttpChannelParent::NotifyTrackingResource(bool aIsThirdParty) |
1867 | 0 | { |
1868 | 0 | LOG(("HttpChannelParent::NotifyTrackingResource thirdparty=%d [this=%p]\n", |
1869 | 0 | static_cast<int>(aIsThirdParty), this)); |
1870 | 0 | if (!mIPCClosed) { |
1871 | 0 | MOZ_ASSERT(mBgParent); |
1872 | 0 | Unused << mBgParent->OnNotifyTrackingResource(aIsThirdParty); |
1873 | 0 | } |
1874 | 0 | return NS_OK; |
1875 | 0 | } |
1876 | | |
1877 | | NS_IMETHODIMP |
1878 | | HttpChannelParent::Delete() |
1879 | 0 | { |
1880 | 0 | if (!mIPCClosed) |
1881 | 0 | Unused << DoSendDeleteSelf(); |
1882 | 0 |
|
1883 | 0 | return NS_OK; |
1884 | 0 | } |
1885 | | |
1886 | | //----------------------------------------------------------------------------- |
1887 | | // HttpChannelParent::nsIParentRedirectingChannel |
1888 | | //----------------------------------------------------------------------------- |
1889 | | |
1890 | | NS_IMETHODIMP |
1891 | | HttpChannelParent::StartRedirect(uint32_t registrarId, |
1892 | | nsIChannel* newChannel, |
1893 | | uint32_t redirectFlags, |
1894 | | nsIAsyncVerifyRedirectCallback* callback) |
1895 | 0 | { |
1896 | 0 | nsresult rv; |
1897 | 0 |
|
1898 | 0 | LOG(("HttpChannelParent::StartRedirect [this=%p, registrarId=%" PRIu32 " " |
1899 | 0 | "newChannel=%p callback=%p]\n", this, registrarId, newChannel, |
1900 | 0 | callback)); |
1901 | 0 |
|
1902 | 0 | if (mIPCClosed) { |
1903 | 0 | return NS_BINDING_ABORTED; |
1904 | 0 | } |
1905 | 0 | |
1906 | 0 | // If this is an internal redirect for service worker interception, then |
1907 | 0 | // hide it from the child process. The original e10s interception code |
1908 | 0 | // was not designed with this in mind and its not necessary to replace |
1909 | 0 | // the HttpChannelChild/Parent objects in this case. |
1910 | 0 | if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { |
1911 | 0 | nsCOMPtr<nsIInterceptedChannel> oldIntercepted = |
1912 | 0 | do_QueryInterface(static_cast<nsIChannel*>(mChannel.get())); |
1913 | 0 | nsCOMPtr<nsIInterceptedChannel> newIntercepted = do_QueryInterface(newChannel); |
1914 | 0 |
|
1915 | 0 | // We only want to hide the special internal redirect from nsHttpChannel |
1916 | 0 | // to InterceptedHttpChannel. We want to allow through internal redirects |
1917 | 0 | // initiated from the InterceptedHttpChannel even if they are to another |
1918 | 0 | // InterceptedHttpChannel. |
1919 | 0 | if (!oldIntercepted && newIntercepted) { |
1920 | 0 | // We need to move across the reserved and initial client information |
1921 | 0 | // to the new channel. Normally this would be handled by the child |
1922 | 0 | // ClientChannelHelper, but that is not notified of this redirect since |
1923 | 0 | // we're not propagating it back to the child process. |
1924 | 0 | nsCOMPtr<nsILoadInfo> oldLoadInfo; |
1925 | 0 | Unused << mChannel->GetLoadInfo(getter_AddRefs(oldLoadInfo)); |
1926 | 0 | nsCOMPtr<nsILoadInfo> newLoadInfo; |
1927 | 0 | Unused << newChannel->GetLoadInfo(getter_AddRefs(newLoadInfo)); |
1928 | 0 | if (oldLoadInfo && newLoadInfo) { |
1929 | 0 | Maybe<ClientInfo> reservedClientInfo(oldLoadInfo->GetReservedClientInfo()); |
1930 | 0 | if (reservedClientInfo.isSome()) { |
1931 | 0 | newLoadInfo->SetReservedClientInfo(reservedClientInfo.ref()); |
1932 | 0 | } |
1933 | 0 |
|
1934 | 0 | Maybe<ClientInfo> initialClientInfo(oldLoadInfo->GetInitialClientInfo()); |
1935 | 0 | if (initialClientInfo.isSome()) { |
1936 | 0 | newLoadInfo->SetInitialClientInfo(initialClientInfo.ref()); |
1937 | 0 | } |
1938 | 0 | } |
1939 | 0 |
|
1940 | 0 | // Re-link the HttpChannelParent to the new InterceptedHttpChannel. |
1941 | 0 | nsCOMPtr<nsIChannel> linkedChannel; |
1942 | 0 | rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(linkedChannel)); |
1943 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1944 | 0 | MOZ_ASSERT(linkedChannel == newChannel); |
1945 | 0 |
|
1946 | 0 | // We immediately store the InterceptedHttpChannel as our nested |
1947 | 0 | // mChannel. None of the redirect IPC messaging takes place. |
1948 | 0 | mChannel = do_QueryObject(newChannel); |
1949 | 0 |
|
1950 | 0 | callback->OnRedirectVerifyCallback(NS_OK); |
1951 | 0 | return NS_OK; |
1952 | 0 | } |
1953 | 0 | } |
1954 | 0 | |
1955 | 0 | // Sending down the original URI, because that is the URI we have |
1956 | 0 | // to construct the channel from - this is the URI we've been actually |
1957 | 0 | // redirected to. URI of the channel may be an inner channel URI. |
1958 | 0 | // URI of the channel will be reconstructed by the protocol handler |
1959 | 0 | // on the child process, no need to send it then. |
1960 | 0 | nsCOMPtr<nsIURI> newOriginalURI; |
1961 | 0 | newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); |
1962 | 0 |
|
1963 | 0 | URIParams uriParams; |
1964 | 0 | SerializeURI(newOriginalURI, uriParams); |
1965 | 0 |
|
1966 | 0 | uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL; |
1967 | 0 | MOZ_ALWAYS_SUCCEEDS(newChannel->GetLoadFlags(&newLoadFlags)); |
1968 | 0 |
|
1969 | 0 | nsCString secInfoSerialization; |
1970 | 0 | UpdateAndSerializeSecurityInfo(secInfoSerialization); |
1971 | 0 |
|
1972 | 0 | // If the channel is a HTTP channel, we also want to inform the child |
1973 | 0 | // about the parent's channelId attribute, so that both parent and child |
1974 | 0 | // share the same ID. Useful for monitoring channel activity in devtools. |
1975 | 0 | uint64_t channelId = 0; |
1976 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel); |
1977 | 0 | if (httpChannel) { |
1978 | 0 | rv = httpChannel->GetChannelId(&channelId); |
1979 | 0 | NS_ENSURE_SUCCESS(rv, NS_BINDING_ABORTED); |
1980 | 0 | } |
1981 | 0 |
|
1982 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
1983 | 0 | Unused << mChannel->GetLoadInfo(getter_AddRefs(loadInfo)); |
1984 | 0 |
|
1985 | 0 | ParentLoadInfoForwarderArgs loadInfoForwarderArg; |
1986 | 0 | mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo, &loadInfoForwarderArg); |
1987 | 0 |
|
1988 | 0 | nsHttpResponseHead *responseHead = mChannel->GetResponseHead(); |
1989 | 0 |
|
1990 | 0 | nsHttpResponseHead cleanedUpResponseHead; |
1991 | 0 | if (responseHead && responseHead->HasHeader(nsHttp::Set_Cookie)) { |
1992 | 0 | cleanedUpResponseHead = *responseHead; |
1993 | 0 | cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie); |
1994 | 0 | responseHead = &cleanedUpResponseHead; |
1995 | 0 | } |
1996 | 0 |
|
1997 | 0 | if (!responseHead) { |
1998 | 0 | responseHead = &cleanedUpResponseHead; |
1999 | 0 | } |
2000 | 0 |
|
2001 | 0 | bool result = false; |
2002 | 0 | if (!mIPCClosed) { |
2003 | 0 | result = SendRedirect1Begin(registrarId, uriParams, newLoadFlags, |
2004 | 0 | redirectFlags, loadInfoForwarderArg, |
2005 | 0 | *responseHead, |
2006 | 0 | secInfoSerialization, |
2007 | 0 | channelId, |
2008 | 0 | mChannel->GetPeerAddr()); |
2009 | 0 | } |
2010 | 0 | if (!result) { |
2011 | 0 | // Bug 621446 investigation |
2012 | 0 | mSentRedirect1BeginFailed = true; |
2013 | 0 | return NS_BINDING_ABORTED; |
2014 | 0 | } |
2015 | 0 | |
2016 | 0 | // Bug 621446 investigation |
2017 | 0 | // Store registrar Id of the new channel to find the redirect |
2018 | 0 | // HttpChannelParent later in verification phase. |
2019 | 0 | mRedirectRegistrarId = registrarId; |
2020 | 0 |
|
2021 | 0 | // Result is handled in RecvRedirect2Verify above |
2022 | 0 |
|
2023 | 0 | mRedirectChannel = newChannel; |
2024 | 0 | mRedirectCallback = callback; |
2025 | 0 | return NS_OK; |
2026 | 0 | } |
2027 | | |
2028 | | NS_IMETHODIMP |
2029 | | HttpChannelParent::CompleteRedirect(bool succeeded) |
2030 | 0 | { |
2031 | 0 | LOG(("HttpChannelParent::CompleteRedirect [this=%p succeeded=%d]\n", |
2032 | 0 | this, succeeded)); |
2033 | 0 |
|
2034 | 0 | // The channel was redirected to another process, and the channel parent |
2035 | 0 | // is about to be deleted. We send a CancelRedirected message in order to |
2036 | 0 | // inform the listener that this child is going away. |
2037 | 0 | if (mDoingCrossProcessRedirect && !mIPCClosed) { |
2038 | 0 | MOZ_ASSERT(!mRedirectChannel); |
2039 | 0 | Unused << SendCancelRedirected(); |
2040 | 0 | return NS_OK; |
2041 | 0 | } |
2042 | 0 |
|
2043 | 0 | // If this was an internal redirect for a service worker interception then |
2044 | 0 | // we will not have a redirecting channel here. Hide this redirect from |
2045 | 0 | // the child. |
2046 | 0 | if (!mRedirectChannel) { |
2047 | 0 | return NS_OK; |
2048 | 0 | } |
2049 | 0 | |
2050 | 0 | if (succeeded && !mIPCClosed) { |
2051 | 0 | // TODO: check return value: assume child dead if failed |
2052 | 0 | Unused << SendRedirect3Complete(); |
2053 | 0 | } |
2054 | 0 |
|
2055 | 0 | mRedirectChannel = nullptr; |
2056 | 0 | return NS_OK; |
2057 | 0 | } |
2058 | | |
2059 | | //----------------------------------------------------------------------------- |
2060 | | // HttpChannelParent::ADivertableParentChannel |
2061 | | //----------------------------------------------------------------------------- |
2062 | | nsresult |
2063 | | HttpChannelParent::SuspendForDiversion() |
2064 | 0 | { |
2065 | 0 | LOG(("HttpChannelParent::SuspendForDiversion [this=%p]\n", this)); |
2066 | 0 | MOZ_ASSERT(mChannel); |
2067 | 0 | MOZ_ASSERT(mParentListener); |
2068 | 0 |
|
2069 | 0 | // If we're in the process of opening a synthesized response, we must wait |
2070 | 0 | // to perform the diversion. Some of our diversion listeners clear callbacks |
2071 | 0 | // which breaks the synthesis process. |
2072 | 0 | if (mWillSynthesizeResponse) { |
2073 | 0 | mPendingDiversion = true; |
2074 | 0 | return NS_OK; |
2075 | 0 | } |
2076 | 0 | |
2077 | 0 | if (NS_WARN_IF(mDivertingFromChild)) { |
2078 | 0 | MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!"); |
2079 | 0 | return NS_ERROR_UNEXPECTED; |
2080 | 0 | } |
2081 | 0 |
|
2082 | 0 | // MessageDiversionStarted call will suspend mEventQ as many times as the |
2083 | 0 | // channel has been suspended, so that channel and this queue are in sync. |
2084 | 0 | nsCOMPtr<nsIChannelWithDivertableParentListener> divertChannel = |
2085 | 0 | do_QueryInterface(static_cast<nsIChannel*>(mChannel.get())); |
2086 | 0 | divertChannel->MessageDiversionStarted(this); |
2087 | 0 |
|
2088 | 0 | nsresult rv = NS_OK; |
2089 | 0 |
|
2090 | 0 | // Try suspending the channel. Allow it to fail, since OnStopRequest may have |
2091 | 0 | // been called and thus the channel may not be pending. If we've already |
2092 | 0 | // automatically suspended after synthesizing the response, then we don't |
2093 | 0 | // need to suspend again here. |
2094 | 0 | if (!mSuspendAfterSynthesizeResponse) { |
2095 | 0 | // We need to suspend only nsHttpChannel (i.e. we should not suspend |
2096 | 0 | // mEventQ). Therefore we call mChannel->SuspendInternal() and not |
2097 | 0 | // mChannel->Suspend(). |
2098 | 0 | // We are suspending only nsHttpChannel here because we want to stop |
2099 | 0 | // OnDataAvailable until diversion is over. At the same time we should |
2100 | 0 | // send the diverted OnDataAvailable-s to the listeners and not queue them |
2101 | 0 | // in mEventQ. |
2102 | 0 | rv = divertChannel->SuspendInternal(); |
2103 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE); |
2104 | 0 | mSuspendedForDiversion = NS_SUCCEEDED(rv); |
2105 | 0 | } else { |
2106 | 0 | // Take ownership of the automatic suspend that occurred after synthesizing |
2107 | 0 | // the response. |
2108 | 0 | mSuspendedForDiversion = true; |
2109 | 0 |
|
2110 | 0 | // If mSuspendAfterSynthesizeResponse is true channel has been already |
2111 | 0 | // suspended. From comment above mSuspendedForDiversion takes the ownership |
2112 | 0 | // of this suspend, therefore mEventQ should not be suspened so we need to |
2113 | 0 | // resume it once. |
2114 | 0 | mEventQ->Resume(); |
2115 | 0 | } |
2116 | 0 |
|
2117 | 0 | rv = mParentListener->SuspendForDiversion(); |
2118 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
2119 | 0 |
|
2120 | 0 | // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent |
2121 | 0 | // to the child. |
2122 | 0 | mDivertingFromChild = true; |
2123 | 0 |
|
2124 | 0 | return NS_OK; |
2125 | 0 | } |
2126 | | |
2127 | | nsresult |
2128 | | HttpChannelParent::SuspendMessageDiversion() |
2129 | 0 | { |
2130 | 0 | LOG(("HttpChannelParent::SuspendMessageDiversion [this=%p]", this)); |
2131 | 0 | // This only needs to suspend message queue. |
2132 | 0 | mEventQ->Suspend(); |
2133 | 0 | return NS_OK; |
2134 | 0 | } |
2135 | | |
2136 | | nsresult |
2137 | | HttpChannelParent::ResumeMessageDiversion() |
2138 | 0 | { |
2139 | 0 | LOG(("HttpChannelParent::SuspendMessageDiversion [this=%p]", this)); |
2140 | 0 | // This only needs to resumes message queue. |
2141 | 0 | mEventQ->Resume(); |
2142 | 0 | return NS_OK; |
2143 | 0 | } |
2144 | | |
2145 | | nsresult |
2146 | | HttpChannelParent::CancelDiversion() |
2147 | 0 | { |
2148 | 0 | LOG(("HttpChannelParent::CancelDiversion [this=%p]", this)); |
2149 | 0 | if (!mIPCClosed) { |
2150 | 0 | Unused << SendCancelDiversion(); |
2151 | 0 | } |
2152 | 0 | return NS_OK; |
2153 | 0 | } |
2154 | | |
2155 | | /* private, supporting function for ADivertableParentChannel */ |
2156 | | nsresult |
2157 | | HttpChannelParent::ResumeForDiversion() |
2158 | 0 | { |
2159 | 0 | LOG(("HttpChannelParent::ResumeForDiversion [this=%p]\n", this)); |
2160 | 0 | MOZ_ASSERT(mChannel); |
2161 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
2162 | 0 | MOZ_ASSERT(mDivertingFromChild, |
2163 | 0 | "Cannot ResumeForDiversion if not diverting!"); |
2164 | 0 | return NS_ERROR_UNEXPECTED; |
2165 | 0 | } |
2166 | 0 |
|
2167 | 0 | nsCOMPtr<nsIChannelWithDivertableParentListener> divertChannel = |
2168 | 0 | do_QueryInterface(static_cast<nsIChannel*>(mChannel.get())); |
2169 | 0 | divertChannel->MessageDiversionStop(); |
2170 | 0 |
|
2171 | 0 | if (mSuspendedForDiversion) { |
2172 | 0 | // The nsHttpChannel will deliver remaining OnData/OnStop for the transfer. |
2173 | 0 | nsresult rv = divertChannel->ResumeInternal(); |
2174 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
2175 | 0 | return rv; |
2176 | 0 | } |
2177 | 0 | mSuspendedForDiversion = false; |
2178 | 0 | } |
2179 | 0 |
|
2180 | 0 | if (NS_WARN_IF(mIPCClosed || !DoSendDeleteSelf())) { |
2181 | 0 | return NS_ERROR_UNEXPECTED; |
2182 | 0 | } |
2183 | 0 | return NS_OK; |
2184 | 0 | } |
2185 | | |
2186 | | void |
2187 | | HttpChannelParent::DivertTo(nsIStreamListener *aListener) |
2188 | 0 | { |
2189 | 0 | LOG(("HttpChannelParent::DivertTo [this=%p aListener=%p]\n", |
2190 | 0 | this, aListener)); |
2191 | 0 | MOZ_ASSERT(mParentListener); |
2192 | 0 |
|
2193 | 0 | // If we're in the process of opening a synthesized response, we must wait |
2194 | 0 | // to perform the diversion. Some of our diversion listeners clear callbacks |
2195 | 0 | // which breaks the synthesis process. |
2196 | 0 | if (mWillSynthesizeResponse) { |
2197 | 0 | // We should already have started pending the diversion when |
2198 | 0 | // SuspendForDiversion() was called. |
2199 | 0 | MOZ_ASSERT(mPendingDiversion); |
2200 | 0 | mDivertListener = aListener; |
2201 | 0 | return; |
2202 | 0 | } |
2203 | 0 |
|
2204 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
2205 | 0 | MOZ_ASSERT(mDivertingFromChild, |
2206 | 0 | "Cannot DivertTo new listener if diverting is not set!"); |
2207 | 0 | return; |
2208 | 0 | } |
2209 | 0 |
|
2210 | 0 | mDivertListener = aListener; |
2211 | 0 |
|
2212 | 0 | // Call OnStartRequest and SendDivertMessages asynchronously to avoid |
2213 | 0 | // reentering client context. |
2214 | 0 | NS_DispatchToCurrentThread( |
2215 | 0 | NewRunnableMethod("net::HttpChannelParent::StartDiversion", |
2216 | 0 | this, |
2217 | 0 | &HttpChannelParent::StartDiversion)); |
2218 | 0 | } |
2219 | | |
2220 | | void |
2221 | | HttpChannelParent::StartDiversion() |
2222 | 0 | { |
2223 | 0 | LOG(("HttpChannelParent::StartDiversion [this=%p]\n", this)); |
2224 | 0 | if (NS_WARN_IF(!mDivertingFromChild)) { |
2225 | 0 | MOZ_ASSERT(mDivertingFromChild, |
2226 | 0 | "Cannot StartDiversion if diverting is not set!"); |
2227 | 0 | return; |
2228 | 0 | } |
2229 | 0 |
|
2230 | 0 | // Fake pending status in case OnStopRequest has already been called. |
2231 | 0 | if (mChannel) { |
2232 | 0 | mChannel->ForcePending(true); |
2233 | 0 | } |
2234 | 0 |
|
2235 | 0 | { |
2236 | 0 | AutoEventEnqueuer ensureSerialDispatch(mEventQ); |
2237 | 0 |
|
2238 | 0 | // Call OnStartRequest for the "DivertTo" listener. |
2239 | 0 | nsresult rv = mDivertListener->OnStartRequest(mChannel, nullptr); |
2240 | 0 | if (NS_FAILED(rv)) { |
2241 | 0 | if (mChannel) { |
2242 | 0 | mChannel->Cancel(rv); |
2243 | 0 | } |
2244 | 0 | mStatus = rv; |
2245 | 0 | } |
2246 | 0 | } |
2247 | 0 | mDivertedOnStartRequest = true; |
2248 | 0 |
|
2249 | 0 | // After OnStartRequest has been called, setup content decoders if needed. |
2250 | 0 | // |
2251 | 0 | // Create a content conversion chain based on mDivertListener and update |
2252 | 0 | // mDivertListener. |
2253 | 0 | nsCOMPtr<nsIStreamListener> converterListener; |
2254 | 0 | Unused << mChannel->DoApplyContentConversions(mDivertListener, |
2255 | 0 | getter_AddRefs(converterListener)); |
2256 | 0 | if (converterListener) { |
2257 | 0 | mDivertListener = converterListener.forget(); |
2258 | 0 | } |
2259 | 0 |
|
2260 | 0 | // Now mParentListener can be diverted to mDivertListener. |
2261 | 0 | DebugOnly<nsresult> rvdbg = mParentListener->DivertTo(mDivertListener); |
2262 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rvdbg)); |
2263 | 0 | mDivertListener = nullptr; |
2264 | 0 |
|
2265 | 0 | // Either IPC channel is closed or background channel |
2266 | 0 | // is ready to send FlushedForDiversion and DivertMessages. |
2267 | 0 | MOZ_ASSERT(mIPCClosed || mBgParent); |
2268 | 0 |
|
2269 | 0 | if (NS_WARN_IF(mIPCClosed || !mBgParent || !mBgParent->OnDiversion())) { |
2270 | 0 | FailDiversion(NS_ERROR_UNEXPECTED); |
2271 | 0 | return; |
2272 | 0 | } |
2273 | 0 | } |
2274 | | |
2275 | | class HTTPFailDiversionEvent : public Runnable |
2276 | | { |
2277 | | public: |
2278 | | HTTPFailDiversionEvent(HttpChannelParent *aChannelParent, |
2279 | | nsresult aErrorCode) |
2280 | | : Runnable("net::HTTPFailDiversionEvent") |
2281 | | , mChannelParent(aChannelParent) |
2282 | | , mErrorCode(aErrorCode) |
2283 | 0 | { |
2284 | 0 | MOZ_RELEASE_ASSERT(aChannelParent); |
2285 | 0 | MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); |
2286 | 0 | } |
2287 | | NS_IMETHOD Run() override |
2288 | 0 | { |
2289 | 0 | mChannelParent->NotifyDiversionFailed(mErrorCode); |
2290 | 0 | return NS_OK; |
2291 | 0 | } |
2292 | | private: |
2293 | | RefPtr<HttpChannelParent> mChannelParent; |
2294 | | nsresult mErrorCode; |
2295 | | }; |
2296 | | |
2297 | | void |
2298 | | HttpChannelParent::FailDiversion(nsresult aErrorCode) |
2299 | 0 | { |
2300 | 0 | MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); |
2301 | 0 | MOZ_RELEASE_ASSERT(mDivertingFromChild); |
2302 | 0 | MOZ_RELEASE_ASSERT(mParentListener); |
2303 | 0 | MOZ_RELEASE_ASSERT(mChannel); |
2304 | 0 |
|
2305 | 0 | NS_DispatchToCurrentThread( |
2306 | 0 | new HTTPFailDiversionEvent(this, aErrorCode)); |
2307 | 0 | } |
2308 | | |
2309 | | void |
2310 | | HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode) |
2311 | 0 | { |
2312 | 0 | LOG(("HttpChannelParent::NotifyDiversionFailed [this=%p aErrorCode=%" PRIx32 "]\n", |
2313 | 0 | this, static_cast<uint32_t>(aErrorCode))); |
2314 | 0 | MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); |
2315 | 0 | MOZ_RELEASE_ASSERT(mDivertingFromChild); |
2316 | 0 | MOZ_RELEASE_ASSERT(mParentListener); |
2317 | 0 | MOZ_RELEASE_ASSERT(mChannel); |
2318 | 0 |
|
2319 | 0 | mChannel->Cancel(aErrorCode); |
2320 | 0 |
|
2321 | 0 | mChannel->ForcePending(false); |
2322 | 0 |
|
2323 | 0 | bool isPending = false; |
2324 | 0 | nsresult rv = mChannel->IsPending(&isPending); |
2325 | 0 | MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
2326 | 0 |
|
2327 | 0 | // Resume only if we suspended earlier. |
2328 | 0 | if (mSuspendedForDiversion) { |
2329 | 0 | nsCOMPtr<nsIChannelWithDivertableParentListener> divertChannel = |
2330 | 0 | do_QueryInterface(static_cast<nsIChannel*>(mChannel.get())); |
2331 | 0 | divertChannel->ResumeInternal(); |
2332 | 0 | } |
2333 | 0 | // Channel has already sent OnStartRequest to the child, so ensure that we |
2334 | 0 | // call it here if it hasn't already been called. |
2335 | 0 | if (!mDivertedOnStartRequest) { |
2336 | 0 | mChannel->ForcePending(true); |
2337 | 0 | mParentListener->OnStartRequest(mChannel, nullptr); |
2338 | 0 | mChannel->ForcePending(false); |
2339 | 0 | } |
2340 | 0 | // If the channel is pending, it will call OnStopRequest itself; otherwise, do |
2341 | 0 | // it here. |
2342 | 0 | if (!isPending) { |
2343 | 0 | mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode); |
2344 | 0 | } |
2345 | 0 |
|
2346 | 0 | if (!mIPCClosed) { |
2347 | 0 | Unused << DoSendDeleteSelf(); |
2348 | 0 | } |
2349 | 0 |
|
2350 | 0 | // DoSendDeleteSelf will need channel Id to remove the strong reference in |
2351 | 0 | // BackgroundChannelRegistrar if channel pairing is aborted. |
2352 | 0 | // Thus we need to keep mChannel until DoSendDeleteSelf is done. |
2353 | 0 | mParentListener = nullptr; |
2354 | 0 | mChannel = nullptr; |
2355 | 0 | } |
2356 | | |
2357 | | nsresult |
2358 | | HttpChannelParent::OpenAlternativeOutputStream(const nsACString & type, int64_t predictedSize, nsIOutputStream * *_retval) |
2359 | 0 | { |
2360 | 0 | // We need to make sure the child does not call SendDocumentChannelCleanup() |
2361 | 0 | // before opening the altOutputStream, because that clears mCacheEntry. |
2362 | 0 | if (!mCacheEntry) { |
2363 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2364 | 0 | } |
2365 | 0 | nsresult rv = mCacheEntry->OpenAlternativeOutputStream(type, predictedSize, _retval); |
2366 | 0 | if (NS_SUCCEEDED(rv)) { |
2367 | 0 | mCacheEntry->SetMetaDataElement("alt-data-from-child", "1"); |
2368 | 0 | } |
2369 | 0 | return rv; |
2370 | 0 | } |
2371 | | |
2372 | | NS_IMETHODIMP |
2373 | | HttpChannelParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid, |
2374 | | void** aResult) |
2375 | 0 | { |
2376 | 0 | nsCOMPtr<nsIAuthPrompt2> prompt = |
2377 | 0 | new NeckoParent::NestedFrameAuthPrompt(Manager(), mNestedFrameId); |
2378 | 0 | prompt.forget(aResult); |
2379 | 0 | return NS_OK; |
2380 | 0 | } |
2381 | | |
2382 | | void |
2383 | | HttpChannelParent::UpdateAndSerializeSecurityInfo(nsACString& aSerializedSecurityInfoOut) |
2384 | 0 | { |
2385 | 0 | nsCOMPtr<nsISupports> secInfoSupp; |
2386 | 0 | mChannel->GetSecurityInfo(getter_AddRefs(secInfoSupp)); |
2387 | 0 | if (secInfoSupp) { |
2388 | 0 | nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp); |
2389 | 0 | if (secInfoSer) { |
2390 | 0 | NS_SerializeToString(secInfoSer, aSerializedSecurityInfoOut); |
2391 | 0 | } |
2392 | 0 | } |
2393 | 0 | } |
2394 | | |
2395 | | bool |
2396 | | HttpChannelParent::DoSendDeleteSelf() |
2397 | 0 | { |
2398 | 0 | mIPCClosed = true; |
2399 | 0 | bool rv = SendDeleteSelf(); |
2400 | 0 |
|
2401 | 0 | CleanupBackgroundChannel(); |
2402 | 0 |
|
2403 | 0 | return rv; |
2404 | 0 | } |
2405 | | |
2406 | | mozilla::ipc::IPCResult |
2407 | | HttpChannelParent::RecvDeletingChannel() |
2408 | 0 | { |
2409 | 0 | // We need to ensure that the parent channel will not be sending any more IPC |
2410 | 0 | // messages after this, as the child is going away. DoSendDeleteSelf will |
2411 | 0 | // set mIPCClosed = true; |
2412 | 0 | if (!DoSendDeleteSelf()) { |
2413 | 0 | return IPC_FAIL_NO_REASON(this); |
2414 | 0 | } |
2415 | 0 | return IPC_OK(); |
2416 | 0 | } |
2417 | | |
2418 | | mozilla::ipc::IPCResult |
2419 | | HttpChannelParent::RecvFinishInterceptedRedirect() |
2420 | 0 | { |
2421 | 0 | // We make sure not to send any more messages until the IPC channel is torn |
2422 | 0 | // down by the child. |
2423 | 0 | mIPCClosed = true; |
2424 | 0 | if (!SendFinishInterceptedRedirect()) { |
2425 | 0 | return IPC_FAIL_NO_REASON(this); |
2426 | 0 | } |
2427 | 0 | return IPC_OK(); |
2428 | 0 | } |
2429 | | |
2430 | | //----------------------------------------------------------------------------- |
2431 | | // HttpChannelSecurityWarningReporter |
2432 | | //----------------------------------------------------------------------------- |
2433 | | |
2434 | | nsresult |
2435 | | HttpChannelParent::ReportSecurityMessage(const nsAString& aMessageTag, |
2436 | | const nsAString& aMessageCategory) |
2437 | 0 | { |
2438 | 0 | if (mIPCClosed || |
2439 | 0 | NS_WARN_IF(!SendReportSecurityMessage(nsString(aMessageTag), |
2440 | 0 | nsString(aMessageCategory)))) { |
2441 | 0 | return NS_ERROR_UNEXPECTED; |
2442 | 0 | } |
2443 | 0 | return NS_OK; |
2444 | 0 | } |
2445 | | |
2446 | | NS_IMETHODIMP |
2447 | | HttpChannelParent::IssueWarning(uint32_t aWarning, bool aAsError) |
2448 | 0 | { |
2449 | 0 | Unused << SendIssueDeprecationWarning(aWarning, aAsError); |
2450 | 0 | return NS_OK; |
2451 | 0 | } |
2452 | | |
2453 | | //----------------------------------------------------------------------------- |
2454 | | // nsIAsyncVerifyRedirectReadyCallback |
2455 | | //----------------------------------------------------------------------------- |
2456 | | |
2457 | | NS_IMETHODIMP |
2458 | | HttpChannelParent::ReadyToVerify(nsresult aResult) |
2459 | 0 | { |
2460 | 0 | LOG(("HttpChannelParent::ReadyToVerify [this=%p result=%" PRIx32 "]\n", |
2461 | 0 | this, static_cast<uint32_t>(aResult))); |
2462 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2463 | 0 |
|
2464 | 0 | ContinueRedirect2Verify(aResult); |
2465 | 0 |
|
2466 | 0 | return NS_OK; |
2467 | 0 | } |
2468 | | |
2469 | | void |
2470 | | HttpChannelParent::DoSendSetPriority(int16_t aValue) |
2471 | 0 | { |
2472 | 0 | if (!mIPCClosed) { |
2473 | 0 | Unused << SendSetPriority(aValue); |
2474 | 0 | } |
2475 | 0 | } |
2476 | | |
2477 | | nsresult |
2478 | | HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage, |
2479 | | const nsACString& aCategory) |
2480 | 0 | { |
2481 | 0 | if (mIPCClosed || |
2482 | 0 | NS_WARN_IF(!SendLogBlockedCORSRequest(nsString(aMessage), |
2483 | 0 | nsCString(aCategory)))) { |
2484 | 0 | return NS_ERROR_UNEXPECTED; |
2485 | 0 | } |
2486 | 0 | return NS_OK; |
2487 | 0 | } |
2488 | | |
2489 | | } // namespace net |
2490 | | } // namespace mozilla |