/src/mozilla-central/netwerk/protocol/http/HttpBaseChannel.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set sw=2 ts=8 et tw=80 : */ |
3 | | |
4 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | // HttpLog.h should generally be included first |
9 | | #include "HttpLog.h" |
10 | | |
11 | | #include "mozilla/net/HttpBaseChannel.h" |
12 | | |
13 | | #include "nsGlobalWindowOuter.h" |
14 | | #include "nsHttpHandler.h" |
15 | | #include "nsMimeTypes.h" |
16 | | #include "nsNetCID.h" |
17 | | #include "nsNetUtil.h" |
18 | | #include "nsReadableUtils.h" |
19 | | |
20 | | #include "nsICachingChannel.h" |
21 | | #include "nsIPrincipal.h" |
22 | | #include "nsIScriptError.h" |
23 | | #include "nsISeekableStream.h" |
24 | | #include "nsIStorageStream.h" |
25 | | #include "nsITimedChannel.h" |
26 | | #include "nsIEncodedChannel.h" |
27 | | #include "nsIApplicationCacheChannel.h" |
28 | | #include "nsIMutableArray.h" |
29 | | #include "nsEscape.h" |
30 | | #include "nsStreamListenerWrapper.h" |
31 | | #include "nsISecurityConsoleMessage.h" |
32 | | #include "nsURLHelper.h" |
33 | | #include "nsICookieService.h" |
34 | | #include "nsIStreamConverterService.h" |
35 | | #include "nsCRT.h" |
36 | | #include "nsContentUtils.h" |
37 | | #include "nsIMutableArray.h" |
38 | | #include "nsIScriptSecurityManager.h" |
39 | | #include "nsIObserverService.h" |
40 | | #include "nsProxyRelease.h" |
41 | | #include "nsPIDOMWindow.h" |
42 | | #include "nsIDocShell.h" |
43 | | #include "nsINetworkInterceptController.h" |
44 | | #include "mozilla/dom/Performance.h" |
45 | | #include "mozilla/dom/PerformanceStorage.h" |
46 | | #include "mozilla/NullPrincipal.h" |
47 | | #include "mozilla/Services.h" |
48 | | #include "mozIThirdPartyUtil.h" |
49 | | #include "nsStreamUtils.h" |
50 | | #include "nsThreadUtils.h" |
51 | | #include "nsContentSecurityManager.h" |
52 | | #include "nsIChannelEventSink.h" |
53 | | #include "nsILoadGroupChild.h" |
54 | | #include "mozilla/ConsoleReportCollector.h" |
55 | | #include "LoadInfo.h" |
56 | | #include "nsISSLSocketControl.h" |
57 | | #include "mozilla/Telemetry.h" |
58 | | #include "nsIURL.h" |
59 | | #include "nsIConsoleService.h" |
60 | | #include "mozilla/BinarySearch.h" |
61 | | #include "mozilla/DebugOnly.h" |
62 | | #include "mozilla/Move.h" |
63 | | #include "mozilla/net/PartiallySeekableInputStream.h" |
64 | | #include "mozilla/InputStreamLengthHelper.h" |
65 | | #include "nsIHttpHeaderVisitor.h" |
66 | | #include "nsIMIMEInputStream.h" |
67 | | #include "nsIXULRuntime.h" |
68 | | #include "nsICacheInfoChannel.h" |
69 | | #include "nsIDOMWindowUtils.h" |
70 | | #include "nsHttpChannel.h" |
71 | | #include "nsRedirectHistoryEntry.h" |
72 | | #include "nsServerTiming.h" |
73 | | |
74 | | #include <algorithm> |
75 | | #include "HttpBaseChannel.h" |
76 | | |
77 | | namespace mozilla { |
78 | | namespace net { |
79 | | |
80 | | static |
81 | | bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader) |
82 | 0 | { |
83 | 0 | // IMPORTANT: keep this list ASCII-code sorted |
84 | 0 | static nsHttpAtom const* blackList[] = { |
85 | 0 | &nsHttp::Accept, |
86 | 0 | &nsHttp::Accept_Encoding, |
87 | 0 | &nsHttp::Accept_Language, |
88 | 0 | &nsHttp::Authentication, |
89 | 0 | &nsHttp::Authorization, |
90 | 0 | &nsHttp::Connection, |
91 | 0 | &nsHttp::Content_Length, |
92 | 0 | &nsHttp::Cookie, |
93 | 0 | &nsHttp::Host, |
94 | 0 | &nsHttp::If, |
95 | 0 | &nsHttp::If_Match, |
96 | 0 | &nsHttp::If_Modified_Since, |
97 | 0 | &nsHttp::If_None_Match, |
98 | 0 | &nsHttp::If_None_Match_Any, |
99 | 0 | &nsHttp::If_Range, |
100 | 0 | &nsHttp::If_Unmodified_Since, |
101 | 0 | &nsHttp::Proxy_Authenticate, |
102 | 0 | &nsHttp::Proxy_Authorization, |
103 | 0 | &nsHttp::Range, |
104 | 0 | &nsHttp::TE, |
105 | 0 | &nsHttp::Transfer_Encoding, |
106 | 0 | &nsHttp::Upgrade, |
107 | 0 | &nsHttp::User_Agent, |
108 | 0 | &nsHttp::WWW_Authenticate |
109 | 0 | }; |
110 | 0 |
|
111 | 0 | class HttpAtomComparator |
112 | 0 | { |
113 | 0 | nsHttpAtom const& mTarget; |
114 | 0 | public: |
115 | 0 | explicit HttpAtomComparator(nsHttpAtom const& aTarget) |
116 | 0 | : mTarget(aTarget) {} |
117 | 0 | int operator()(nsHttpAtom const* aVal) const { |
118 | 0 | if (mTarget == *aVal) { |
119 | 0 | return 0; |
120 | 0 | } |
121 | 0 | return strcmp(mTarget._val, aVal->_val); |
122 | 0 | } |
123 | 0 | }; |
124 | 0 |
|
125 | 0 | size_t unused; |
126 | 0 | return BinarySearchIf(blackList, 0, ArrayLength(blackList), |
127 | 0 | HttpAtomComparator(aHeader), &unused); |
128 | 0 | } |
129 | | |
130 | | class AddHeadersToChannelVisitor final : public nsIHttpHeaderVisitor |
131 | | { |
132 | | public: |
133 | | NS_DECL_ISUPPORTS |
134 | | |
135 | | explicit AddHeadersToChannelVisitor(nsIHttpChannel *aChannel) |
136 | | : mChannel(aChannel) |
137 | 0 | { |
138 | 0 | } |
139 | | |
140 | | NS_IMETHOD VisitHeader(const nsACString& aHeader, |
141 | | const nsACString& aValue) override |
142 | 0 | { |
143 | 0 | nsHttpAtom atom = nsHttp::ResolveAtom(aHeader); |
144 | 0 | if (!IsHeaderBlacklistedForRedirectCopy(atom)) { |
145 | 0 | DebugOnly<nsresult> rv = mChannel->SetRequestHeader(aHeader, aValue, false); |
146 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
147 | 0 | } |
148 | 0 | return NS_OK; |
149 | 0 | } |
150 | | private: |
151 | 0 | ~AddHeadersToChannelVisitor() = default; |
152 | | |
153 | | nsCOMPtr<nsIHttpChannel> mChannel; |
154 | | }; |
155 | | |
156 | | NS_IMPL_ISUPPORTS(AddHeadersToChannelVisitor, nsIHttpHeaderVisitor) |
157 | | |
158 | | HttpBaseChannel::HttpBaseChannel() |
159 | | : mReportCollector(new ConsoleReportCollector()) |
160 | | , mHttpHandler(gHttpHandler) |
161 | | , mChannelCreationTime(0) |
162 | | , mStartPos(UINT64_MAX) |
163 | | , mTransferSize(0) |
164 | | , mDecodedBodySize(0) |
165 | | , mEncodedBodySize(0) |
166 | | , mRequestContextID(0) |
167 | | , mContentWindowId(0) |
168 | | , mTopLevelOuterContentWindowId(0) |
169 | | , mAltDataLength(0) |
170 | | , mChannelId(0) |
171 | | , mReqContentLength(0U) |
172 | | , mStatus(NS_OK) |
173 | | , mCanceled(false) |
174 | | , mIsFirstPartyTrackingResource(false) |
175 | | , mIsThirdPartyTrackingResource(false) |
176 | | , mLoadFlags(LOAD_NORMAL) |
177 | | , mCaps(0) |
178 | | , mClassOfService(0) |
179 | | , mUpgradeToSecure(false) |
180 | | , mApplyConversion(true) |
181 | | , mIsPending(false) |
182 | | , mWasOpened(false) |
183 | | , mRequestObserversCalled(false) |
184 | | , mResponseHeadersModified(false) |
185 | | , mAllowSTS(true) |
186 | | , mThirdPartyFlags(0) |
187 | | , mUploadStreamHasHeaders(false) |
188 | | , mInheritApplicationCache(true) |
189 | | , mChooseApplicationCache(false) |
190 | | , mLoadedFromApplicationCache(false) |
191 | | , mChannelIsForDownload(false) |
192 | | , mTracingEnabled(true) |
193 | | , mTimingEnabled(false) |
194 | | , mReportTiming(true) |
195 | | , mAllowSpdy(true) |
196 | | , mAllowAltSvc(true) |
197 | | , mBeConservative(false) |
198 | | , mTRR(false) |
199 | | , mResponseTimeoutEnabled(true) |
200 | | , mAllRedirectsSameOrigin(true) |
201 | | , mAllRedirectsPassTimingAllowCheck(true) |
202 | | , mResponseCouldBeSynthesized(false) |
203 | | , mBlockAuthPrompt(false) |
204 | | , mAllowStaleCacheContent(false) |
205 | | , mAddedAsNonTailRequest(false) |
206 | | , mAsyncOpenWaitingForStreamLength(false) |
207 | | , mUpgradableToSecure(true) |
208 | | , mTlsFlags(0) |
209 | | , mSuspendCount(0) |
210 | | , mInitialRwin(0) |
211 | | , mProxyResolveFlags(0) |
212 | | , mContentDispositionHint(UINT32_MAX) |
213 | | , mReferrerPolicy(NS_GetDefaultReferrerPolicy()) |
214 | | , mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS) |
215 | | , mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW) |
216 | | , mLastRedirectFlags(0) |
217 | | , mPriority(PRIORITY_NORMAL) |
218 | | , mRedirectionLimit(gHttpHandler->RedirectionLimit()) |
219 | | , mRedirectCount(0) |
220 | | , mInternalRedirectCount(0) |
221 | | , mAsyncOpenTimeOverriden(false) |
222 | | , mForcePending(false) |
223 | | , mCorsIncludeCredentials(false) |
224 | | , mOnStartRequestCalled(false) |
225 | | , mOnStopRequestCalled(false) |
226 | | , mAfterOnStartRequestBegun(false) |
227 | | , mRequireCORSPreflight(false) |
228 | | , mAltDataForChild(false) |
229 | | , mForceMainDocumentChannel(false) |
230 | | , mPendingInputStreamLengthOperation(false) |
231 | 0 | { |
232 | 0 | this->mSelfAddr.inet = {}; |
233 | 0 | this->mPeerAddr.inet = {}; |
234 | 0 | LOG(("Creating HttpBaseChannel @%p\n", this)); |
235 | 0 |
|
236 | 0 | // Subfields of unions cannot be targeted in an initializer list. |
237 | | #ifdef MOZ_VALGRIND |
238 | | // Zero the entire unions so that Valgrind doesn't complain when we send them |
239 | | // to another process. |
240 | | memset(&mSelfAddr, 0, sizeof(NetAddr)); |
241 | | memset(&mPeerAddr, 0, sizeof(NetAddr)); |
242 | | #endif |
243 | | mSelfAddr.raw.family = PR_AF_UNSPEC; |
244 | 0 | mPeerAddr.raw.family = PR_AF_UNSPEC; |
245 | 0 | } |
246 | | |
247 | | HttpBaseChannel::~HttpBaseChannel() |
248 | 0 | { |
249 | 0 | LOG(("Destroying HttpBaseChannel @%p\n", this)); |
250 | 0 |
|
251 | 0 | // Make sure we don't leak |
252 | 0 | CleanRedirectCacheChainIfNecessary(); |
253 | 0 |
|
254 | 0 | ReleaseMainThreadOnlyReferences(); |
255 | 0 | } |
256 | | |
257 | | namespace { // anon |
258 | | |
259 | | class NonTailRemover : public nsISupports |
260 | | { |
261 | | NS_DECL_THREADSAFE_ISUPPORTS |
262 | | |
263 | | explicit NonTailRemover(nsIRequestContext* rc) |
264 | | : mRequestContext(rc) |
265 | 0 | { |
266 | 0 | } |
267 | | |
268 | | private: |
269 | | virtual ~NonTailRemover() |
270 | 0 | { |
271 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
272 | 0 | mRequestContext->RemoveNonTailRequest(); |
273 | 0 | } |
274 | | |
275 | | nsCOMPtr<nsIRequestContext> mRequestContext; |
276 | | }; |
277 | | |
278 | | NS_IMPL_ISUPPORTS0(NonTailRemover) |
279 | | |
280 | | } // anon |
281 | | |
282 | | void |
283 | | HttpBaseChannel::ReleaseMainThreadOnlyReferences() |
284 | 0 | { |
285 | 0 | if (NS_IsMainThread()) { |
286 | 0 | // Already on main thread, let dtor to |
287 | 0 | // take care of releasing references |
288 | 0 | RemoveAsNonTailRequest(); |
289 | 0 | return; |
290 | 0 | } |
291 | 0 | |
292 | 0 | nsTArray<nsCOMPtr<nsISupports>> arrayToRelease; |
293 | 0 | arrayToRelease.AppendElement(mURI.forget()); |
294 | 0 | arrayToRelease.AppendElement(mOriginalURI.forget()); |
295 | 0 | arrayToRelease.AppendElement(mDocumentURI.forget()); |
296 | 0 | arrayToRelease.AppendElement(mLoadGroup.forget()); |
297 | 0 | arrayToRelease.AppendElement(mLoadInfo.forget()); |
298 | 0 | arrayToRelease.AppendElement(mCallbacks.forget()); |
299 | 0 | arrayToRelease.AppendElement(mProgressSink.forget()); |
300 | 0 | arrayToRelease.AppendElement(mReferrer.forget()); |
301 | 0 | arrayToRelease.AppendElement(mApplicationCache.forget()); |
302 | 0 | arrayToRelease.AppendElement(mAPIRedirectToURI.forget()); |
303 | 0 | arrayToRelease.AppendElement(mProxyURI.forget()); |
304 | 0 | arrayToRelease.AppendElement(mPrincipal.forget()); |
305 | 0 | arrayToRelease.AppendElement(mTopWindowURI.forget()); |
306 | 0 | arrayToRelease.AppendElement(mListener.forget()); |
307 | 0 | arrayToRelease.AppendElement(mListenerContext.forget()); |
308 | 0 | arrayToRelease.AppendElement(mCompressListener.forget()); |
309 | 0 |
|
310 | 0 | if (mAddedAsNonTailRequest) { |
311 | 0 | // RemoveNonTailRequest() on our request context must be called on the main thread |
312 | 0 | MOZ_RELEASE_ASSERT(mRequestContext, "Someone released rc or set flags w/o having it?"); |
313 | 0 |
|
314 | 0 | nsCOMPtr<nsISupports> nonTailRemover(new NonTailRemover(mRequestContext)); |
315 | 0 | arrayToRelease.AppendElement(nonTailRemover.forget()); |
316 | 0 | } |
317 | 0 |
|
318 | 0 | NS_DispatchToMainThread(new ProxyReleaseRunnable(std::move(arrayToRelease))); |
319 | 0 | } |
320 | | |
321 | | void |
322 | | HttpBaseChannel::SetIsTrackingResource(bool aIsThirdParty) |
323 | 0 | { |
324 | 0 | LOG(("HttpBaseChannel::SetIsTrackingResource thirdparty=%d %p", |
325 | 0 | static_cast<int>(aIsThirdParty), this)); |
326 | 0 |
|
327 | 0 | if (aIsThirdParty) { |
328 | 0 | MOZ_ASSERT(!mIsFirstPartyTrackingResource); |
329 | 0 | mIsThirdPartyTrackingResource = true; |
330 | 0 | } else { |
331 | 0 | MOZ_ASSERT(!mIsThirdPartyTrackingResource); |
332 | 0 | mIsFirstPartyTrackingResource = true; |
333 | 0 | } |
334 | 0 |
|
335 | 0 | if (mLoadInfo) { |
336 | 0 | MOZ_ALWAYS_SUCCEEDS(mLoadInfo->SetIsTracker(true)); |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | | nsresult |
341 | | HttpBaseChannel::Init(nsIURI *aURI, |
342 | | uint32_t aCaps, |
343 | | nsProxyInfo *aProxyInfo, |
344 | | uint32_t aProxyResolveFlags, |
345 | | nsIURI *aProxyURI, |
346 | | uint64_t aChannelId) |
347 | 0 | { |
348 | 0 | LOG(("HttpBaseChannel::Init [this=%p]\n", this)); |
349 | 0 |
|
350 | 0 | MOZ_ASSERT(aURI, "null uri"); |
351 | 0 |
|
352 | 0 | mURI = aURI; |
353 | 0 | mOriginalURI = aURI; |
354 | 0 | mDocumentURI = nullptr; |
355 | 0 | mCaps = aCaps; |
356 | 0 | mProxyResolveFlags = aProxyResolveFlags; |
357 | 0 | mProxyURI = aProxyURI; |
358 | 0 | mChannelId = aChannelId; |
359 | 0 |
|
360 | 0 | // Construct connection info object |
361 | 0 | nsAutoCString host; |
362 | 0 | int32_t port = -1; |
363 | 0 | bool isHTTPS = false; |
364 | 0 |
|
365 | 0 | nsresult rv = mURI->SchemeIs("https", &isHTTPS); |
366 | 0 | if (NS_FAILED(rv)) return rv; |
367 | 0 | |
368 | 0 | rv = mURI->GetAsciiHost(host); |
369 | 0 | if (NS_FAILED(rv)) return rv; |
370 | 0 | |
371 | 0 | // Reject the URL if it doesn't specify a host |
372 | 0 | if (host.IsEmpty()) |
373 | 0 | return NS_ERROR_MALFORMED_URI; |
374 | 0 | |
375 | 0 | rv = mURI->GetPort(&port); |
376 | 0 | if (NS_FAILED(rv)) return rv; |
377 | 0 | |
378 | 0 | LOG(("host=%s port=%d\n", host.get(), port)); |
379 | 0 |
|
380 | 0 | rv = mURI->GetAsciiSpec(mSpec); |
381 | 0 | if (NS_FAILED(rv)) return rv; |
382 | 0 | LOG(("uri=%s\n", mSpec.get())); |
383 | 0 |
|
384 | 0 | // Assert default request method |
385 | 0 | MOZ_ASSERT(mRequestHead.EqualsMethod(nsHttpRequestHead::kMethod_Get)); |
386 | 0 |
|
387 | 0 | // Set request headers |
388 | 0 | nsAutoCString hostLine; |
389 | 0 | rv = nsHttpHandler::GenerateHostPort(host, port, hostLine); |
390 | 0 | if (NS_FAILED(rv)) return rv; |
391 | 0 | |
392 | 0 | rv = mRequestHead.SetHeader(nsHttp::Host, hostLine); |
393 | 0 | if (NS_FAILED(rv)) return rv; |
394 | 0 | |
395 | 0 | rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS); |
396 | 0 | if (NS_FAILED(rv)) return rv; |
397 | 0 | |
398 | 0 | nsAutoCString type; |
399 | 0 | if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) && |
400 | 0 | !type.EqualsLiteral("unknown")) |
401 | 0 | mProxyInfo = aProxyInfo; |
402 | 0 |
|
403 | 0 | return rv; |
404 | 0 | } |
405 | | |
406 | | //----------------------------------------------------------------------------- |
407 | | // HttpBaseChannel::nsISupports |
408 | | //----------------------------------------------------------------------------- |
409 | | |
410 | | NS_IMPL_ADDREF(HttpBaseChannel) |
411 | | NS_IMPL_RELEASE(HttpBaseChannel) |
412 | | |
413 | 0 | NS_INTERFACE_MAP_BEGIN(HttpBaseChannel) |
414 | 0 | NS_INTERFACE_MAP_ENTRY(nsIRequest) |
415 | 0 | NS_INTERFACE_MAP_ENTRY(nsIChannel) |
416 | 0 | NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel) |
417 | 0 | NS_INTERFACE_MAP_ENTRY(nsIHttpChannel) |
418 | 0 | NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal) |
419 | 0 | NS_INTERFACE_MAP_ENTRY(nsIForcePendingChannel) |
420 | 0 | NS_INTERFACE_MAP_ENTRY(nsIUploadChannel) |
421 | 0 | NS_INTERFACE_MAP_ENTRY(nsIFormPOSTActionChannel) |
422 | 0 | NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2) |
423 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsPriority) |
424 | 0 | NS_INTERFACE_MAP_ENTRY(nsITraceableChannel) |
425 | 0 | NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel) |
426 | 0 | NS_INTERFACE_MAP_ENTRY(nsITimedChannel) |
427 | 0 | NS_INTERFACE_MAP_ENTRY(nsIConsoleReportCollector) |
428 | 0 | NS_INTERFACE_MAP_ENTRY(nsIThrottledInputChannel) |
429 | 0 | NS_INTERFACE_MAP_ENTRY(nsIClassifiedChannel) |
430 | 0 | NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpBaseChannel) |
431 | 0 | NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag) |
432 | | |
433 | | //----------------------------------------------------------------------------- |
434 | | // HttpBaseChannel::nsIRequest |
435 | | //----------------------------------------------------------------------------- |
436 | | |
437 | | NS_IMETHODIMP |
438 | | HttpBaseChannel::GetName(nsACString& aName) |
439 | 0 | { |
440 | 0 | aName = mSpec; |
441 | 0 | return NS_OK; |
442 | 0 | } |
443 | | |
444 | | NS_IMETHODIMP |
445 | | HttpBaseChannel::IsPending(bool *aIsPending) |
446 | 0 | { |
447 | 0 | NS_ENSURE_ARG_POINTER(aIsPending); |
448 | 0 | *aIsPending = mIsPending || mForcePending; |
449 | 0 | return NS_OK; |
450 | 0 | } |
451 | | |
452 | | NS_IMETHODIMP |
453 | | HttpBaseChannel::GetStatus(nsresult *aStatus) |
454 | 0 | { |
455 | 0 | NS_ENSURE_ARG_POINTER(aStatus); |
456 | 0 | *aStatus = mStatus; |
457 | 0 | return NS_OK; |
458 | 0 | } |
459 | | |
460 | | NS_IMETHODIMP |
461 | | HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) |
462 | 0 | { |
463 | 0 | NS_ENSURE_ARG_POINTER(aLoadGroup); |
464 | 0 | *aLoadGroup = mLoadGroup; |
465 | 0 | NS_IF_ADDREF(*aLoadGroup); |
466 | 0 | return NS_OK; |
467 | 0 | } |
468 | | |
469 | | NS_IMETHODIMP |
470 | | HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) |
471 | 0 | { |
472 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread."); |
473 | 0 |
|
474 | 0 | if (!CanSetLoadGroup(aLoadGroup)) { |
475 | 0 | return NS_ERROR_FAILURE; |
476 | 0 | } |
477 | 0 | |
478 | 0 | mLoadGroup = aLoadGroup; |
479 | 0 | mProgressSink = nullptr; |
480 | 0 | UpdatePrivateBrowsing(); |
481 | 0 | return NS_OK; |
482 | 0 | } |
483 | | |
484 | | NS_IMETHODIMP |
485 | | HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) |
486 | 0 | { |
487 | 0 | NS_ENSURE_ARG_POINTER(aLoadFlags); |
488 | 0 | *aLoadFlags = mLoadFlags; |
489 | 0 | return NS_OK; |
490 | 0 | } |
491 | | |
492 | | NS_IMETHODIMP |
493 | | HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags) |
494 | 0 | { |
495 | 0 | mLoadFlags = aLoadFlags; |
496 | 0 | return NS_OK; |
497 | 0 | } |
498 | | |
499 | | NS_IMETHODIMP |
500 | | HttpBaseChannel::SetDocshellUserAgentOverride() |
501 | 0 | { |
502 | 0 | // This sets the docshell specific user agent override, it will be overwritten |
503 | 0 | // by UserAgentOverrides.jsm if site-specific user agent overrides are set. |
504 | 0 | nsresult rv; |
505 | 0 | nsCOMPtr<nsILoadContext> loadContext; |
506 | 0 | NS_QueryNotificationCallbacks(this, loadContext); |
507 | 0 | if (!loadContext) { |
508 | 0 | return NS_OK; |
509 | 0 | } |
510 | 0 | |
511 | 0 | nsCOMPtr<mozIDOMWindowProxy> domWindow; |
512 | 0 | loadContext->GetAssociatedWindow(getter_AddRefs(domWindow)); |
513 | 0 | if (!domWindow) { |
514 | 0 | return NS_OK; |
515 | 0 | } |
516 | 0 | |
517 | 0 | auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow); |
518 | 0 | nsIDocShell* docshell = pDomWindow->GetDocShell(); |
519 | 0 | if (!docshell) { |
520 | 0 | return NS_OK; |
521 | 0 | } |
522 | 0 | |
523 | 0 | nsString customUserAgent; |
524 | 0 | docshell->GetCustomUserAgent(customUserAgent); |
525 | 0 | if (customUserAgent.IsEmpty()) { |
526 | 0 | return NS_OK; |
527 | 0 | } |
528 | 0 | |
529 | 0 | NS_ConvertUTF16toUTF8 utf8CustomUserAgent(customUserAgent); |
530 | 0 | rv = SetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), utf8CustomUserAgent, false); |
531 | 0 | if (NS_FAILED(rv)) return rv; |
532 | 0 | |
533 | 0 | return NS_OK; |
534 | 0 | } |
535 | | |
536 | | //----------------------------------------------------------------------------- |
537 | | // HttpBaseChannel::nsIChannel |
538 | | //----------------------------------------------------------------------------- |
539 | | |
540 | | NS_IMETHODIMP |
541 | | HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI) |
542 | 0 | { |
543 | 0 | NS_ENSURE_ARG_POINTER(aOriginalURI); |
544 | 0 | *aOriginalURI = mOriginalURI; |
545 | 0 | NS_ADDREF(*aOriginalURI); |
546 | 0 | return NS_OK; |
547 | 0 | } |
548 | | |
549 | | NS_IMETHODIMP |
550 | | HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI) |
551 | 0 | { |
552 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
553 | 0 |
|
554 | 0 | NS_ENSURE_ARG_POINTER(aOriginalURI); |
555 | 0 | mOriginalURI = aOriginalURI; |
556 | 0 | return NS_OK; |
557 | 0 | } |
558 | | |
559 | | NS_IMETHODIMP |
560 | | HttpBaseChannel::GetURI(nsIURI **aURI) |
561 | 0 | { |
562 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
563 | 0 | *aURI = mURI; |
564 | 0 | NS_ADDREF(*aURI); |
565 | 0 | return NS_OK; |
566 | 0 | } |
567 | | |
568 | | NS_IMETHODIMP |
569 | | HttpBaseChannel::GetOwner(nsISupports **aOwner) |
570 | 0 | { |
571 | 0 | NS_ENSURE_ARG_POINTER(aOwner); |
572 | 0 | *aOwner = mOwner; |
573 | 0 | NS_IF_ADDREF(*aOwner); |
574 | 0 | return NS_OK; |
575 | 0 | } |
576 | | |
577 | | NS_IMETHODIMP |
578 | | HttpBaseChannel::SetOwner(nsISupports *aOwner) |
579 | 0 | { |
580 | 0 | mOwner = aOwner; |
581 | 0 | return NS_OK; |
582 | 0 | } |
583 | | |
584 | | NS_IMETHODIMP |
585 | | HttpBaseChannel::SetLoadInfo(nsILoadInfo *aLoadInfo) |
586 | 0 | { |
587 | 0 | mLoadInfo = aLoadInfo; |
588 | 0 | return NS_OK; |
589 | 0 | } |
590 | | |
591 | | NS_IMETHODIMP |
592 | | HttpBaseChannel::GetLoadInfo(nsILoadInfo **aLoadInfo) |
593 | 0 | { |
594 | 0 | NS_IF_ADDREF(*aLoadInfo = mLoadInfo); |
595 | 0 | return NS_OK; |
596 | 0 | } |
597 | | |
598 | | NS_IMETHODIMP |
599 | | HttpBaseChannel::GetIsDocument(bool *aIsDocument) |
600 | 0 | { |
601 | 0 | return NS_GetIsDocumentChannel(this, aIsDocument); |
602 | 0 | } |
603 | | |
604 | | NS_IMETHODIMP |
605 | | HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) |
606 | 0 | { |
607 | 0 | *aCallbacks = mCallbacks; |
608 | 0 | NS_IF_ADDREF(*aCallbacks); |
609 | 0 | return NS_OK; |
610 | 0 | } |
611 | | |
612 | | NS_IMETHODIMP |
613 | | HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) |
614 | 0 | { |
615 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread."); |
616 | 0 |
|
617 | 0 | if (!CanSetCallbacks(aCallbacks)) { |
618 | 0 | return NS_ERROR_FAILURE; |
619 | 0 | } |
620 | 0 | |
621 | 0 | mCallbacks = aCallbacks; |
622 | 0 | mProgressSink = nullptr; |
623 | 0 |
|
624 | 0 | UpdatePrivateBrowsing(); |
625 | 0 | return NS_OK; |
626 | 0 | } |
627 | | |
628 | | NS_IMETHODIMP |
629 | | HttpBaseChannel::GetContentType(nsACString& aContentType) |
630 | 0 | { |
631 | 0 | if (!mResponseHead) { |
632 | 0 | aContentType.Truncate(); |
633 | 0 | return NS_ERROR_NOT_AVAILABLE; |
634 | 0 | } |
635 | 0 | |
636 | 0 | mResponseHead->ContentType(aContentType); |
637 | 0 | if (!aContentType.IsEmpty()) { |
638 | 0 | return NS_OK; |
639 | 0 | } |
640 | 0 | |
641 | 0 | aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE); |
642 | 0 | return NS_OK; |
643 | 0 | } |
644 | | |
645 | | NS_IMETHODIMP |
646 | | HttpBaseChannel::SetContentType(const nsACString& aContentType) |
647 | 0 | { |
648 | 0 | if (mListener || mWasOpened) { |
649 | 0 | if (!mResponseHead) |
650 | 0 | return NS_ERROR_NOT_AVAILABLE; |
651 | 0 | |
652 | 0 | nsAutoCString contentTypeBuf, charsetBuf; |
653 | 0 | bool hadCharset; |
654 | 0 | net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset); |
655 | 0 |
|
656 | 0 | mResponseHead->SetContentType(contentTypeBuf); |
657 | 0 |
|
658 | 0 | // take care not to stomp on an existing charset |
659 | 0 | if (hadCharset) |
660 | 0 | mResponseHead->SetContentCharset(charsetBuf); |
661 | 0 |
|
662 | 0 | } else { |
663 | 0 | // We are being given a content-type hint. |
664 | 0 | bool dummy; |
665 | 0 | net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint, |
666 | 0 | &dummy); |
667 | 0 | } |
668 | 0 |
|
669 | 0 | return NS_OK; |
670 | 0 | } |
671 | | |
672 | | NS_IMETHODIMP |
673 | | HttpBaseChannel::GetContentCharset(nsACString& aContentCharset) |
674 | 0 | { |
675 | 0 | if (!mResponseHead) |
676 | 0 | return NS_ERROR_NOT_AVAILABLE; |
677 | 0 | |
678 | 0 | mResponseHead->ContentCharset(aContentCharset); |
679 | 0 | return NS_OK; |
680 | 0 | } |
681 | | |
682 | | NS_IMETHODIMP |
683 | | HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset) |
684 | 0 | { |
685 | 0 | if (mListener) { |
686 | 0 | if (!mResponseHead) |
687 | 0 | return NS_ERROR_NOT_AVAILABLE; |
688 | 0 | |
689 | 0 | mResponseHead->SetContentCharset(aContentCharset); |
690 | 0 | } else { |
691 | 0 | // Charset hint |
692 | 0 | mContentCharsetHint = aContentCharset; |
693 | 0 | } |
694 | 0 | return NS_OK; |
695 | 0 | } |
696 | | |
697 | | NS_IMETHODIMP |
698 | | HttpBaseChannel::GetContentDisposition(uint32_t *aContentDisposition) |
699 | 0 | { |
700 | 0 | nsresult rv; |
701 | 0 | nsCString header; |
702 | 0 |
|
703 | 0 | rv = GetContentDispositionHeader(header); |
704 | 0 | if (NS_FAILED(rv)) { |
705 | 0 | if (mContentDispositionHint == UINT32_MAX) |
706 | 0 | return rv; |
707 | 0 | |
708 | 0 | *aContentDisposition = mContentDispositionHint; |
709 | 0 | return NS_OK; |
710 | 0 | } |
711 | 0 | |
712 | 0 | *aContentDisposition = NS_GetContentDispositionFromHeader(header, this); |
713 | 0 | return NS_OK; |
714 | 0 | } |
715 | | |
716 | | NS_IMETHODIMP |
717 | | HttpBaseChannel::SetContentDisposition(uint32_t aContentDisposition) |
718 | 0 | { |
719 | 0 | mContentDispositionHint = aContentDisposition; |
720 | 0 | return NS_OK; |
721 | 0 | } |
722 | | |
723 | | NS_IMETHODIMP |
724 | | HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename) |
725 | 0 | { |
726 | 0 | aContentDispositionFilename.Truncate(); |
727 | 0 | nsresult rv; |
728 | 0 | nsCString header; |
729 | 0 |
|
730 | 0 | rv = GetContentDispositionHeader(header); |
731 | 0 | if (NS_FAILED(rv)) { |
732 | 0 | if (!mContentDispositionFilename) |
733 | 0 | return rv; |
734 | 0 | |
735 | 0 | aContentDispositionFilename = *mContentDispositionFilename; |
736 | 0 | return NS_OK; |
737 | 0 | } |
738 | 0 | |
739 | 0 | return NS_GetFilenameFromDisposition(aContentDispositionFilename, |
740 | 0 | header, mURI); |
741 | 0 | } |
742 | | |
743 | | NS_IMETHODIMP |
744 | | HttpBaseChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename) |
745 | 0 | { |
746 | 0 | mContentDispositionFilename = new nsString(aContentDispositionFilename); |
747 | 0 | return NS_OK; |
748 | 0 | } |
749 | | |
750 | | NS_IMETHODIMP |
751 | | HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader) |
752 | 0 | { |
753 | 0 | if (!mResponseHead) |
754 | 0 | return NS_ERROR_NOT_AVAILABLE; |
755 | 0 | |
756 | 0 | nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition, |
757 | 0 | aContentDispositionHeader); |
758 | 0 | if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty()) |
759 | 0 | return NS_ERROR_NOT_AVAILABLE; |
760 | 0 | |
761 | 0 | return NS_OK; |
762 | 0 | } |
763 | | |
764 | | NS_IMETHODIMP |
765 | | HttpBaseChannel::GetContentLength(int64_t *aContentLength) |
766 | 0 | { |
767 | 0 | NS_ENSURE_ARG_POINTER(aContentLength); |
768 | 0 |
|
769 | 0 | if (!mResponseHead) |
770 | 0 | return NS_ERROR_NOT_AVAILABLE; |
771 | 0 | |
772 | 0 | if (!mAvailableCachedAltDataType.IsEmpty()) { |
773 | 0 | *aContentLength = mAltDataLength; |
774 | 0 | return NS_OK; |
775 | 0 | } |
776 | 0 | |
777 | 0 | *aContentLength = mResponseHead->ContentLength(); |
778 | 0 | return NS_OK; |
779 | 0 | } |
780 | | |
781 | | NS_IMETHODIMP |
782 | | HttpBaseChannel::SetContentLength(int64_t value) |
783 | 0 | { |
784 | 0 | MOZ_ASSERT_UNREACHABLE("HttpBaseChannel::SetContentLength"); |
785 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
786 | 0 | } |
787 | | |
788 | | NS_IMETHODIMP |
789 | | HttpBaseChannel::Open(nsIInputStream **aResult) |
790 | 0 | { |
791 | 0 | NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS); |
792 | 0 |
|
793 | 0 | if (!gHttpHandler->Active()) { |
794 | 0 | LOG(("HttpBaseChannel::Open after HTTP shutdown...")); |
795 | 0 | return NS_ERROR_NOT_AVAILABLE; |
796 | 0 | } |
797 | 0 |
|
798 | 0 | return NS_ImplementChannelOpen(this, aResult); |
799 | 0 | } |
800 | | |
801 | | NS_IMETHODIMP |
802 | | HttpBaseChannel::Open2(nsIInputStream** aStream) |
803 | 0 | { |
804 | 0 | if (!gHttpHandler->Active()) { |
805 | 0 | LOG(("HttpBaseChannel::Open after HTTP shutdown...")); |
806 | 0 | return NS_ERROR_NOT_AVAILABLE; |
807 | 0 | } |
808 | 0 |
|
809 | 0 | nsCOMPtr<nsIStreamListener> listener; |
810 | 0 | nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); |
811 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
812 | 0 | return Open(aStream); |
813 | 0 | } |
814 | | |
815 | | //----------------------------------------------------------------------------- |
816 | | // HttpBaseChannel::nsIUploadChannel |
817 | | //----------------------------------------------------------------------------- |
818 | | |
819 | | NS_IMETHODIMP |
820 | | HttpBaseChannel::GetUploadStream(nsIInputStream **stream) |
821 | 0 | { |
822 | 0 | NS_ENSURE_ARG_POINTER(stream); |
823 | 0 | *stream = mUploadStream; |
824 | 0 | NS_IF_ADDREF(*stream); |
825 | 0 | return NS_OK; |
826 | 0 | } |
827 | | |
828 | | NS_IMETHODIMP |
829 | | HttpBaseChannel::SetUploadStream(nsIInputStream *stream, |
830 | | const nsACString &contentTypeArg, |
831 | | int64_t contentLength) |
832 | 0 | { |
833 | 0 | // NOTE: for backwards compatibility and for compatibility with old style |
834 | 0 | // plugins, |stream| may include headers, specifically Content-Type and |
835 | 0 | // Content-Length headers. in this case, |contentType| and |contentLength| |
836 | 0 | // would be unspecified. this is traditionally the case of a POST request, |
837 | 0 | // and so we select POST as the request method if contentType and |
838 | 0 | // contentLength are unspecified. |
839 | 0 |
|
840 | 0 | if (stream) { |
841 | 0 | nsAutoCString method; |
842 | 0 | bool hasHeaders = false; |
843 | 0 |
|
844 | 0 | // This method and ExplicitSetUploadStream mean different things by "empty |
845 | 0 | // content type string". This method means "no header", but |
846 | 0 | // ExplicitSetUploadStream means "header with empty value". So we have to |
847 | 0 | // massage the contentType argument into the form ExplicitSetUploadStream |
848 | 0 | // expects. |
849 | 0 | nsCOMPtr<nsIMIMEInputStream> mimeStream; |
850 | 0 | nsCString contentType(contentTypeArg); |
851 | 0 | if (contentType.IsEmpty()) { |
852 | 0 | contentType.SetIsVoid(true); |
853 | 0 | method = NS_LITERAL_CSTRING("POST"); |
854 | 0 |
|
855 | 0 | // MIME streams are a special case, and include headers which need to be |
856 | 0 | // copied to the channel. |
857 | 0 | mimeStream = do_QueryInterface(stream); |
858 | 0 | if (mimeStream) { |
859 | 0 | // Copy non-origin related headers to the channel. |
860 | 0 | nsCOMPtr<nsIHttpHeaderVisitor> visitor = |
861 | 0 | new AddHeadersToChannelVisitor(this); |
862 | 0 | mimeStream->VisitHeaders(visitor); |
863 | 0 |
|
864 | 0 | return ExplicitSetUploadStream(stream, contentType, contentLength, |
865 | 0 | method, hasHeaders); |
866 | 0 | } |
867 | 0 | |
868 | 0 | hasHeaders = true; |
869 | 0 | } else { |
870 | 0 | method = NS_LITERAL_CSTRING("PUT"); |
871 | 0 |
|
872 | 0 | MOZ_ASSERT(NS_FAILED(CallQueryInterface(stream, getter_AddRefs(mimeStream))), |
873 | 0 | "nsIMIMEInputStream should not be set with an explicit content type"); |
874 | 0 | } |
875 | 0 | return ExplicitSetUploadStream(stream, contentType, contentLength, |
876 | 0 | method, hasHeaders); |
877 | 0 | } |
878 | 0 | |
879 | 0 | // if stream is null, ExplicitSetUploadStream returns error. |
880 | 0 | // So we need special case for GET method. |
881 | 0 | mUploadStreamHasHeaders = false; |
882 | 0 | mRequestHead.SetMethod(NS_LITERAL_CSTRING("GET")); // revert to GET request |
883 | 0 | mUploadStream = stream; |
884 | 0 | return NS_OK; |
885 | 0 | } |
886 | | |
887 | | namespace { |
888 | | |
889 | | void |
890 | 0 | CopyComplete(void* aClosure, nsresult aStatus) { |
891 | | #ifdef DEBUG |
892 | | // Called on the STS thread by NS_AsyncCopy |
893 | | nsCOMPtr<nsIEventTarget> sts = |
894 | | do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); |
895 | | bool result = false; |
896 | | sts->IsOnCurrentThread(&result); |
897 | | MOZ_ASSERT(result, "Should only be called on the STS thread."); |
898 | | #endif |
899 | |
|
900 | 0 | auto channel = static_cast<HttpBaseChannel*>(aClosure); |
901 | 0 | channel->OnCopyComplete(aStatus); |
902 | 0 | } |
903 | | |
904 | | } // anonymous namespace |
905 | | |
906 | | NS_IMETHODIMP |
907 | | HttpBaseChannel::EnsureUploadStreamIsCloneable(nsIRunnable* aCallback) |
908 | 0 | { |
909 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread."); |
910 | 0 | NS_ENSURE_ARG_POINTER(aCallback); |
911 | 0 |
|
912 | 0 | // We could in theory allow multiple callers to use this method, |
913 | 0 | // but the complexity does not seem worth it yet. Just fail if |
914 | 0 | // this is called more than once simultaneously. |
915 | 0 | NS_ENSURE_FALSE(mUploadCloneableCallback, NS_ERROR_UNEXPECTED); |
916 | 0 |
|
917 | 0 | // If the CloneUploadStream() will succeed, then synchronously invoke |
918 | 0 | // the callback to indicate we're already cloneable. |
919 | 0 | if (!mUploadStream || NS_InputStreamIsCloneable(mUploadStream)) { |
920 | 0 | aCallback->Run(); |
921 | 0 | return NS_OK; |
922 | 0 | } |
923 | 0 | |
924 | 0 | nsCOMPtr<nsIStorageStream> storageStream; |
925 | 0 | nsresult rv = NS_NewStorageStream(4096, UINT32_MAX, |
926 | 0 | getter_AddRefs(storageStream)); |
927 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
928 | 0 |
|
929 | 0 | nsCOMPtr<nsIInputStream> newUploadStream; |
930 | 0 | rv = storageStream->NewInputStream(0, getter_AddRefs(newUploadStream)); |
931 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
932 | 0 |
|
933 | 0 | nsCOMPtr<nsIOutputStream> sink; |
934 | 0 | rv = storageStream->GetOutputStream(0, getter_AddRefs(sink)); |
935 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
936 | 0 |
|
937 | 0 | nsCOMPtr<nsIInputStream> source; |
938 | 0 | if (NS_InputStreamIsBuffered(mUploadStream)) { |
939 | 0 | source = mUploadStream; |
940 | 0 | } else { |
941 | 0 | rv = NS_NewBufferedInputStream(getter_AddRefs(source), |
942 | 0 | mUploadStream.forget(), 4096); |
943 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
944 | 0 | } |
945 | 0 |
|
946 | 0 | nsCOMPtr<nsIEventTarget> target = |
947 | 0 | do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); |
948 | 0 |
|
949 | 0 | mUploadCloneableCallback = aCallback; |
950 | 0 |
|
951 | 0 | rv = NS_AsyncCopy(source, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS, |
952 | 0 | 4096, // copy segment size |
953 | 0 | CopyComplete, this); |
954 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
955 | 0 | mUploadCloneableCallback = nullptr; |
956 | 0 | return rv; |
957 | 0 | } |
958 | 0 | |
959 | 0 | // Since we're consuming the old stream, replace it with the new |
960 | 0 | // stream immediately. |
961 | 0 | mUploadStream = newUploadStream; |
962 | 0 |
|
963 | 0 | // Explicity hold the stream alive until copying is complete. This will |
964 | 0 | // be released in EnsureUploadStreamIsCloneableComplete(). |
965 | 0 | AddRef(); |
966 | 0 |
|
967 | 0 | return NS_OK; |
968 | 0 | } |
969 | | |
970 | | void |
971 | | HttpBaseChannel::OnCopyComplete(nsresult aStatus) |
972 | 0 | { |
973 | 0 | // Assert in parent process because we don't have to label the runnable |
974 | 0 | // in parent process. |
975 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
976 | 0 |
|
977 | 0 | nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<nsresult>( |
978 | 0 | "net::HttpBaseChannel::EnsureUploadStreamIsCloneableComplete", |
979 | 0 | this, |
980 | 0 | &HttpBaseChannel::EnsureUploadStreamIsCloneableComplete, |
981 | 0 | aStatus); |
982 | 0 | NS_DispatchToMainThread(runnable.forget()); |
983 | 0 | } |
984 | | |
985 | | void |
986 | | HttpBaseChannel::EnsureUploadStreamIsCloneableComplete(nsresult aStatus) |
987 | 0 | { |
988 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread."); |
989 | 0 | MOZ_ASSERT(mUploadCloneableCallback); |
990 | 0 |
|
991 | 0 | if (NS_SUCCEEDED(mStatus)) { |
992 | 0 | mStatus = aStatus; |
993 | 0 | } |
994 | 0 |
|
995 | 0 | mUploadCloneableCallback->Run(); |
996 | 0 | mUploadCloneableCallback = nullptr; |
997 | 0 |
|
998 | 0 | // Release the reference we grabbed in EnsureUploadStreamIsCloneable() now |
999 | 0 | // that the copying is complete. |
1000 | 0 | Release(); |
1001 | 0 | } |
1002 | | |
1003 | | NS_IMETHODIMP |
1004 | | HttpBaseChannel::CloneUploadStream(int64_t* aContentLength, |
1005 | | nsIInputStream** aClonedStream) |
1006 | 0 | { |
1007 | 0 | NS_ENSURE_ARG_POINTER(aContentLength); |
1008 | 0 | NS_ENSURE_ARG_POINTER(aClonedStream); |
1009 | 0 | *aClonedStream = nullptr; |
1010 | 0 |
|
1011 | 0 | if (!mUploadStream) { |
1012 | 0 | return NS_OK; |
1013 | 0 | } |
1014 | 0 | |
1015 | 0 | nsCOMPtr<nsIInputStream> clonedStream; |
1016 | 0 | nsresult rv = NS_CloneInputStream(mUploadStream, getter_AddRefs(clonedStream)); |
1017 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1018 | 0 |
|
1019 | 0 | clonedStream.forget(aClonedStream); |
1020 | 0 |
|
1021 | 0 | *aContentLength = mReqContentLength; |
1022 | 0 | return NS_OK; |
1023 | 0 | } |
1024 | | |
1025 | | |
1026 | | //----------------------------------------------------------------------------- |
1027 | | // HttpBaseChannel::nsIUploadChannel2 |
1028 | | //----------------------------------------------------------------------------- |
1029 | | |
1030 | | NS_IMETHODIMP |
1031 | | HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream, |
1032 | | const nsACString &aContentType, |
1033 | | int64_t aContentLength, |
1034 | | const nsACString &aMethod, |
1035 | | bool aStreamHasHeaders) |
1036 | 0 | { |
1037 | 0 | // Ensure stream is set and method is valid |
1038 | 0 | NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE); |
1039 | 0 |
|
1040 | 0 | { |
1041 | 0 | DebugOnly<nsCOMPtr<nsIMIMEInputStream>> mimeStream; |
1042 | 0 | MOZ_ASSERT(!aStreamHasHeaders || |
1043 | 0 | NS_FAILED(CallQueryInterface(aStream, getter_AddRefs(mimeStream.value))), |
1044 | 0 | "nsIMIMEInputStream should not include headers"); |
1045 | 0 | } |
1046 | 0 |
|
1047 | 0 | nsresult rv = SetRequestMethod(aMethod); |
1048 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1049 | 0 |
|
1050 | 0 | if (!aStreamHasHeaders && !aContentType.IsVoid()) { |
1051 | 0 | if (aContentType.IsEmpty()) { |
1052 | 0 | SetEmptyRequestHeader(NS_LITERAL_CSTRING("Content-Type")); |
1053 | 0 | } else { |
1054 | 0 | SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), aContentType, |
1055 | 0 | false); |
1056 | 0 | } |
1057 | 0 | } |
1058 | 0 |
|
1059 | 0 | mUploadStreamHasHeaders = aStreamHasHeaders; |
1060 | 0 |
|
1061 | 0 | nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aStream); |
1062 | 0 | if (!seekable) { |
1063 | 0 | nsCOMPtr<nsIInputStream> stream = aStream; |
1064 | 0 | seekable = new PartiallySeekableInputStream(stream.forget()); |
1065 | 0 | } |
1066 | 0 |
|
1067 | 0 | mUploadStream = do_QueryInterface(seekable); |
1068 | 0 |
|
1069 | 0 | if (aContentLength >= 0) { |
1070 | 0 | ExplicitSetUploadStreamLength(aContentLength, aStreamHasHeaders); |
1071 | 0 | return NS_OK; |
1072 | 0 | } |
1073 | 0 | |
1074 | 0 | // Sync access to the stream length. |
1075 | 0 | int64_t length; |
1076 | 0 | if (InputStreamLengthHelper::GetSyncLength(aStream, &length)) { |
1077 | 0 | ExplicitSetUploadStreamLength(length >= 0 ? length : 0, |
1078 | 0 | aStreamHasHeaders); |
1079 | 0 | return NS_OK; |
1080 | 0 | } |
1081 | 0 |
|
1082 | 0 | // Let's resolve the size of the stream. |
1083 | 0 | RefPtr<HttpBaseChannel> self = this; |
1084 | 0 | InputStreamLengthHelper::GetAsyncLength(aStream, |
1085 | 0 | [self, aStreamHasHeaders](int64_t aLength) { |
1086 | 0 | self->mPendingInputStreamLengthOperation = false; |
1087 | 0 | self->ExplicitSetUploadStreamLength(aLength >= 0 ? aLength : 0, |
1088 | 0 | aStreamHasHeaders); |
1089 | 0 | self->MaybeResumeAsyncOpen(); |
1090 | 0 | }); |
1091 | 0 | mPendingInputStreamLengthOperation = true; |
1092 | 0 | return NS_OK; |
1093 | 0 | } |
1094 | | |
1095 | | nsresult |
1096 | | HttpBaseChannel::ExplicitSetUploadStreamLength(uint64_t aContentLength, |
1097 | | bool aStreamHasHeaders) |
1098 | 0 | { |
1099 | 0 | // We already have the content length. We don't need to determinate it. |
1100 | 0 | mReqContentLength = aContentLength; |
1101 | 0 |
|
1102 | 0 | if (aStreamHasHeaders) { |
1103 | 0 | return NS_OK; |
1104 | 0 | } |
1105 | 0 | |
1106 | 0 | nsAutoCString header; |
1107 | 0 | header.AssignLiteral("Content-Length"); |
1108 | 0 |
|
1109 | 0 | // Maybe the content-length header has been already set. |
1110 | 0 | nsAutoCString value; |
1111 | 0 | nsresult rv = GetRequestHeader(header, value); |
1112 | 0 | if (NS_SUCCEEDED(rv) && !value.IsEmpty()) { |
1113 | 0 | return NS_OK; |
1114 | 0 | } |
1115 | 0 | |
1116 | 0 | // SetRequestHeader propagates headers to chrome if HttpChannelChild |
1117 | 0 | MOZ_ASSERT(!mWasOpened); |
1118 | 0 | nsAutoCString contentLengthStr; |
1119 | 0 | contentLengthStr.AppendInt(aContentLength); |
1120 | 0 | SetRequestHeader(header, contentLengthStr, false); |
1121 | 0 |
|
1122 | 0 | return NS_OK; |
1123 | 0 | } |
1124 | | |
1125 | | NS_IMETHODIMP |
1126 | | HttpBaseChannel::GetUploadStreamHasHeaders(bool *hasHeaders) |
1127 | 0 | { |
1128 | 0 | NS_ENSURE_ARG(hasHeaders); |
1129 | 0 |
|
1130 | 0 | *hasHeaders = mUploadStreamHasHeaders; |
1131 | 0 | return NS_OK; |
1132 | 0 | } |
1133 | | |
1134 | | bool |
1135 | | HttpBaseChannel::MaybeWaitForUploadStreamLength(nsIStreamListener *aListener, |
1136 | | nsISupports *aContext) |
1137 | 0 | { |
1138 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1139 | 0 | MOZ_ASSERT(!mAsyncOpenWaitingForStreamLength, "AsyncOpen() called twice?"); |
1140 | 0 |
|
1141 | 0 | if (!mPendingInputStreamLengthOperation) { |
1142 | 0 | return false; |
1143 | 0 | } |
1144 | 0 | |
1145 | 0 | mListener = aListener; |
1146 | 0 | mListenerContext = aContext; |
1147 | 0 | mAsyncOpenWaitingForStreamLength = true; |
1148 | 0 | return true; |
1149 | 0 | } |
1150 | | |
1151 | | void |
1152 | | HttpBaseChannel::MaybeResumeAsyncOpen() |
1153 | 0 | { |
1154 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1155 | 0 | MOZ_ASSERT(!mPendingInputStreamLengthOperation); |
1156 | 0 |
|
1157 | 0 | if (!mAsyncOpenWaitingForStreamLength) { |
1158 | 0 | return; |
1159 | 0 | } |
1160 | 0 | |
1161 | 0 | nsCOMPtr<nsIStreamListener> listener; |
1162 | 0 | listener.swap(mListener); |
1163 | 0 |
|
1164 | 0 | nsCOMPtr<nsISupports> context; |
1165 | 0 | context.swap(mListenerContext); |
1166 | 0 |
|
1167 | 0 | mAsyncOpenWaitingForStreamLength = false; |
1168 | 0 |
|
1169 | 0 | nsresult rv = AsyncOpen(listener, context); |
1170 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1171 | 0 | DoAsyncAbort(rv); |
1172 | 0 | } |
1173 | 0 | } |
1174 | | |
1175 | | //----------------------------------------------------------------------------- |
1176 | | // HttpBaseChannel::nsIEncodedChannel |
1177 | | //----------------------------------------------------------------------------- |
1178 | | |
1179 | | NS_IMETHODIMP |
1180 | | HttpBaseChannel::GetApplyConversion(bool *value) |
1181 | 0 | { |
1182 | 0 | *value = mApplyConversion; |
1183 | 0 | return NS_OK; |
1184 | 0 | } |
1185 | | |
1186 | | NS_IMETHODIMP |
1187 | | HttpBaseChannel::SetApplyConversion(bool value) |
1188 | 0 | { |
1189 | 0 | LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value)); |
1190 | 0 | mApplyConversion = value; |
1191 | 0 | return NS_OK; |
1192 | 0 | } |
1193 | | |
1194 | | nsresult |
1195 | | HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, |
1196 | | nsIStreamListener** aNewNextListener) |
1197 | 0 | { |
1198 | 0 | return DoApplyContentConversions(aNextListener, |
1199 | 0 | aNewNextListener, |
1200 | 0 | mListenerContext); |
1201 | 0 | } |
1202 | | |
1203 | | // create a listener chain that looks like this |
1204 | | // http-channel -> decompressor (n times) -> InterceptFailedOnSTop -> channel-creator-listener |
1205 | | // |
1206 | | // we need to do this because not every decompressor has fully streamed output so |
1207 | | // may need a call to OnStopRequest to identify its completion state.. and if it |
1208 | | // creates an error there the channel status code needs to be updated before calling |
1209 | | // the terminal listener. Having the decompress do it via cancel() means channels cannot |
1210 | | // effectively be used in two contexts (specifically this one and a peek context for |
1211 | | // sniffing) |
1212 | | // |
1213 | | class InterceptFailedOnStop : public nsIStreamListener |
1214 | | { |
1215 | 0 | virtual ~InterceptFailedOnStop() = default; |
1216 | | nsCOMPtr<nsIStreamListener> mNext; |
1217 | | HttpBaseChannel *mChannel; |
1218 | | |
1219 | | public: |
1220 | | InterceptFailedOnStop(nsIStreamListener *arg, HttpBaseChannel *chan) |
1221 | | : mNext(arg) |
1222 | 0 | , mChannel(chan) {} |
1223 | | NS_DECL_THREADSAFE_ISUPPORTS |
1224 | | |
1225 | | NS_IMETHOD OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) override |
1226 | 0 | { |
1227 | 0 | return mNext->OnStartRequest(aRequest, aContext); |
1228 | 0 | } |
1229 | | |
1230 | | NS_IMETHOD OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) override |
1231 | 0 | { |
1232 | 0 | if (NS_FAILED(aStatusCode) && NS_SUCCEEDED(mChannel->mStatus)) { |
1233 | 0 | LOG(("HttpBaseChannel::InterceptFailedOnStop %p seting status %" PRIx32, |
1234 | 0 | mChannel, static_cast<uint32_t>(aStatusCode))); |
1235 | 0 | mChannel->mStatus = aStatusCode; |
1236 | 0 | } |
1237 | 0 | return mNext->OnStopRequest(aRequest, aContext, aStatusCode); |
1238 | 0 | } |
1239 | | |
1240 | | NS_IMETHOD OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext, |
1241 | | nsIInputStream *aInputStream, uint64_t aOffset, |
1242 | | uint32_t aCount) override |
1243 | 0 | { |
1244 | 0 | return mNext->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount); |
1245 | 0 | } |
1246 | | }; |
1247 | | |
1248 | | NS_IMPL_ISUPPORTS(InterceptFailedOnStop, nsIStreamListener, nsIRequestObserver) |
1249 | | |
1250 | | NS_IMETHODIMP |
1251 | | HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, |
1252 | | nsIStreamListener** aNewNextListener, |
1253 | | nsISupports *aCtxt) |
1254 | 0 | { |
1255 | 0 | *aNewNextListener = nullptr; |
1256 | 0 | if (!mResponseHead || ! aNextListener) { |
1257 | 0 | return NS_OK; |
1258 | 0 | } |
1259 | 0 | |
1260 | 0 | LOG(("HttpBaseChannel::DoApplyContentConversions [this=%p]\n", this)); |
1261 | 0 |
|
1262 | 0 | if (!mApplyConversion) { |
1263 | 0 | LOG(("not applying conversion per mApplyConversion\n")); |
1264 | 0 | return NS_OK; |
1265 | 0 | } |
1266 | 0 |
|
1267 | 0 | if (!mAvailableCachedAltDataType.IsEmpty()) { |
1268 | 0 | LOG(("not applying conversion because delivering alt-data\n")); |
1269 | 0 | return NS_OK; |
1270 | 0 | } |
1271 | 0 |
|
1272 | 0 | nsAutoCString contentEncoding; |
1273 | 0 | nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding); |
1274 | 0 | if (NS_FAILED(rv) || contentEncoding.IsEmpty()) |
1275 | 0 | return NS_OK; |
1276 | 0 | |
1277 | 0 | nsCOMPtr<nsIStreamListener> nextListener = new InterceptFailedOnStop(aNextListener, this); |
1278 | 0 |
|
1279 | 0 | // The encodings are listed in the order they were applied |
1280 | 0 | // (see rfc 2616 section 14.11), so they need to removed in reverse |
1281 | 0 | // order. This is accomplished because the converter chain ends up |
1282 | 0 | // being a stack with the last converter created being the first one |
1283 | 0 | // to accept the raw network data. |
1284 | 0 |
|
1285 | 0 | char* cePtr = contentEncoding.BeginWriting(); |
1286 | 0 | uint32_t count = 0; |
1287 | 0 | while (char* val = nsCRT::strtok(cePtr, HTTP_LWS ",", &cePtr)) { |
1288 | 0 | if (++count > 16) { |
1289 | 0 | // That's ridiculous. We only understand 2 different ones :) |
1290 | 0 | // but for compatibility with old code, we will just carry on without |
1291 | 0 | // removing the encodings |
1292 | 0 | LOG(("Too many Content-Encodings. Ignoring remainder.\n")); |
1293 | 0 | break; |
1294 | 0 | } |
1295 | 0 |
|
1296 | 0 | bool isHTTPS = false; |
1297 | 0 | mURI->SchemeIs("https", &isHTTPS); |
1298 | 0 | if (gHttpHandler->IsAcceptableEncoding(val, isHTTPS)) { |
1299 | 0 | nsCOMPtr<nsIStreamConverterService> serv; |
1300 | 0 | rv = gHttpHandler->GetStreamConverterService(getter_AddRefs(serv)); |
1301 | 0 |
|
1302 | 0 | // we won't fail to load the page just because we couldn't load the |
1303 | 0 | // stream converter service.. carry on.. |
1304 | 0 | if (NS_FAILED(rv)) { |
1305 | 0 | if (val) |
1306 | 0 | LOG(("Unknown content encoding '%s', ignoring\n", val)); |
1307 | 0 | continue; |
1308 | 0 | } |
1309 | 0 |
|
1310 | 0 | nsCOMPtr<nsIStreamListener> converter; |
1311 | 0 | nsAutoCString from(val); |
1312 | 0 | ToLowerCase(from); |
1313 | 0 | rv = serv->AsyncConvertData(from.get(), |
1314 | 0 | "uncompressed", |
1315 | 0 | nextListener, |
1316 | 0 | aCtxt, |
1317 | 0 | getter_AddRefs(converter)); |
1318 | 0 | if (NS_FAILED(rv)) { |
1319 | 0 | LOG(("Unexpected failure of AsyncConvertData %s\n", val)); |
1320 | 0 | return rv; |
1321 | 0 | } |
1322 | 0 |
|
1323 | 0 | LOG(("converter removed '%s' content-encoding\n", val)); |
1324 | 0 | if (gHttpHandler->IsTelemetryEnabled()) { |
1325 | 0 | int mode = 0; |
1326 | 0 | if (from.EqualsLiteral("gzip") || from.EqualsLiteral("x-gzip")) { |
1327 | 0 | mode = 1; |
1328 | 0 | } else if (from.EqualsLiteral("deflate") || from.EqualsLiteral("x-deflate")) { |
1329 | 0 | mode = 2; |
1330 | 0 | } else if (from.EqualsLiteral("br")) { |
1331 | 0 | mode = 3; |
1332 | 0 | } |
1333 | 0 | Telemetry::Accumulate(Telemetry::HTTP_CONTENT_ENCODING, mode); |
1334 | 0 | } |
1335 | 0 | nextListener = converter; |
1336 | 0 | } |
1337 | 0 | else { |
1338 | 0 | if (val) |
1339 | 0 | LOG(("Unknown content encoding '%s', ignoring\n", val)); |
1340 | 0 | } |
1341 | 0 | } |
1342 | 0 | *aNewNextListener = nextListener; |
1343 | 0 | NS_IF_ADDREF(*aNewNextListener); |
1344 | 0 | return NS_OK; |
1345 | 0 | } |
1346 | | |
1347 | | NS_IMETHODIMP |
1348 | | HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings) |
1349 | 0 | { |
1350 | 0 | if (!mResponseHead) { |
1351 | 0 | *aEncodings = nullptr; |
1352 | 0 | return NS_OK; |
1353 | 0 | } |
1354 | 0 | |
1355 | 0 | nsAutoCString encoding; |
1356 | 0 | Unused << mResponseHead->GetHeader(nsHttp::Content_Encoding, encoding); |
1357 | 0 | if (encoding.IsEmpty()) { |
1358 | 0 | *aEncodings = nullptr; |
1359 | 0 | return NS_OK; |
1360 | 0 | } |
1361 | 0 | nsContentEncodings* enumerator = new nsContentEncodings(this, |
1362 | 0 | encoding.get()); |
1363 | 0 | NS_ADDREF(*aEncodings = enumerator); |
1364 | 0 | return NS_OK; |
1365 | 0 | } |
1366 | | |
1367 | | //----------------------------------------------------------------------------- |
1368 | | // HttpBaseChannel::nsContentEncodings <public> |
1369 | | //----------------------------------------------------------------------------- |
1370 | | |
1371 | | HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel, |
1372 | | const char* aEncodingHeader) |
1373 | | : mEncodingHeader(aEncodingHeader) |
1374 | | , mChannel(aChannel) |
1375 | | , mReady(false) |
1376 | 0 | { |
1377 | 0 | mCurEnd = aEncodingHeader + strlen(aEncodingHeader); |
1378 | 0 | mCurStart = mCurEnd; |
1379 | 0 | } |
1380 | | |
1381 | | //----------------------------------------------------------------------------- |
1382 | | // HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator |
1383 | | //----------------------------------------------------------------------------- |
1384 | | |
1385 | | NS_IMETHODIMP |
1386 | | HttpBaseChannel::nsContentEncodings::HasMore(bool* aMoreEncodings) |
1387 | 0 | { |
1388 | 0 | if (mReady) { |
1389 | 0 | *aMoreEncodings = true; |
1390 | 0 | return NS_OK; |
1391 | 0 | } |
1392 | 0 | |
1393 | 0 | nsresult rv = PrepareForNext(); |
1394 | 0 | *aMoreEncodings = NS_SUCCEEDED(rv); |
1395 | 0 | return NS_OK; |
1396 | 0 | } |
1397 | | |
1398 | | NS_IMETHODIMP |
1399 | | HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding) |
1400 | 0 | { |
1401 | 0 | aNextEncoding.Truncate(); |
1402 | 0 | if (!mReady) { |
1403 | 0 | nsresult rv = PrepareForNext(); |
1404 | 0 | if (NS_FAILED(rv)) { |
1405 | 0 | return NS_ERROR_FAILURE; |
1406 | 0 | } |
1407 | 0 | } |
1408 | 0 | |
1409 | 0 | const nsACString & encoding = Substring(mCurStart, mCurEnd); |
1410 | 0 |
|
1411 | 0 | nsACString::const_iterator start, end; |
1412 | 0 | encoding.BeginReading(start); |
1413 | 0 | encoding.EndReading(end); |
1414 | 0 |
|
1415 | 0 | bool haveType = false; |
1416 | 0 | if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) { |
1417 | 0 | aNextEncoding.AssignLiteral(APPLICATION_GZIP); |
1418 | 0 | haveType = true; |
1419 | 0 | } |
1420 | 0 |
|
1421 | 0 | if (!haveType) { |
1422 | 0 | encoding.BeginReading(start); |
1423 | 0 | if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) { |
1424 | 0 | aNextEncoding.AssignLiteral(APPLICATION_COMPRESS); |
1425 | 0 | haveType = true; |
1426 | 0 | } |
1427 | 0 | } |
1428 | 0 |
|
1429 | 0 | if (!haveType) { |
1430 | 0 | encoding.BeginReading(start); |
1431 | 0 | if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) { |
1432 | 0 | aNextEncoding.AssignLiteral(APPLICATION_ZIP); |
1433 | 0 | haveType = true; |
1434 | 0 | } |
1435 | 0 | } |
1436 | 0 |
|
1437 | 0 | if (!haveType) { |
1438 | 0 | encoding.BeginReading(start); |
1439 | 0 | if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("br"), start, end)) { |
1440 | 0 | aNextEncoding.AssignLiteral(APPLICATION_BROTLI); |
1441 | 0 | haveType = true; |
1442 | 0 | } |
1443 | 0 | } |
1444 | 0 |
|
1445 | 0 | // Prepare to fetch the next encoding |
1446 | 0 | mCurEnd = mCurStart; |
1447 | 0 | mReady = false; |
1448 | 0 |
|
1449 | 0 | if (haveType) |
1450 | 0 | return NS_OK; |
1451 | 0 | |
1452 | 0 | NS_WARNING("Unknown encoding type"); |
1453 | 0 | return NS_ERROR_FAILURE; |
1454 | 0 | } |
1455 | | |
1456 | | //----------------------------------------------------------------------------- |
1457 | | // HttpBaseChannel::nsContentEncodings::nsISupports |
1458 | | //----------------------------------------------------------------------------- |
1459 | | |
1460 | | NS_IMPL_ISUPPORTS(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator, |
1461 | | nsIStringEnumerator) |
1462 | | |
1463 | | //----------------------------------------------------------------------------- |
1464 | | // HttpBaseChannel::nsContentEncodings <private> |
1465 | | //----------------------------------------------------------------------------- |
1466 | | |
1467 | | nsresult |
1468 | | HttpBaseChannel::nsContentEncodings::PrepareForNext(void) |
1469 | 0 | { |
1470 | 0 | MOZ_ASSERT(mCurStart == mCurEnd, "Indeterminate state"); |
1471 | 0 |
|
1472 | 0 | // At this point both mCurStart and mCurEnd point to somewhere |
1473 | 0 | // past the end of the next thing we want to return |
1474 | 0 |
|
1475 | 0 | while (mCurEnd != mEncodingHeader) { |
1476 | 0 | --mCurEnd; |
1477 | 0 | if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd)) |
1478 | 0 | break; |
1479 | 0 | } |
1480 | 0 | if (mCurEnd == mEncodingHeader) |
1481 | 0 | return NS_ERROR_NOT_AVAILABLE; // no more encodings |
1482 | 0 | ++mCurEnd; |
1483 | 0 |
|
1484 | 0 | // At this point mCurEnd points to the first char _after_ the |
1485 | 0 | // header we want. Furthermore, mCurEnd - 1 != mEncodingHeader |
1486 | 0 |
|
1487 | 0 | mCurStart = mCurEnd - 1; |
1488 | 0 | while (mCurStart != mEncodingHeader && |
1489 | 0 | *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart)) |
1490 | 0 | --mCurStart; |
1491 | 0 | if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart)) |
1492 | 0 | ++mCurStart; // we stopped because of a weird char, so move up one |
1493 | 0 |
|
1494 | 0 | // At this point mCurStart and mCurEnd bracket the encoding string |
1495 | 0 | // we want. Check that it's not "identity" |
1496 | 0 | if (Substring(mCurStart, mCurEnd).Equals("identity", |
1497 | 0 | nsCaseInsensitiveCStringComparator())) { |
1498 | 0 | mCurEnd = mCurStart; |
1499 | 0 | return PrepareForNext(); |
1500 | 0 | } |
1501 | 0 | |
1502 | 0 | mReady = true; |
1503 | 0 | return NS_OK; |
1504 | 0 | } |
1505 | | |
1506 | | |
1507 | | //----------------------------------------------------------------------------- |
1508 | | // HttpBaseChannel::nsIHttpChannel |
1509 | | //----------------------------------------------------------------------------- |
1510 | | |
1511 | | NS_IMETHODIMP |
1512 | | HttpBaseChannel::GetChannelId(uint64_t *aChannelId) |
1513 | 0 | { |
1514 | 0 | NS_ENSURE_ARG_POINTER(aChannelId); |
1515 | 0 | *aChannelId = mChannelId; |
1516 | 0 | return NS_OK; |
1517 | 0 | } |
1518 | | |
1519 | | NS_IMETHODIMP |
1520 | | HttpBaseChannel::SetChannelId(uint64_t aChannelId) |
1521 | 0 | { |
1522 | 0 | mChannelId = aChannelId; |
1523 | 0 | return NS_OK; |
1524 | 0 | } |
1525 | | |
1526 | | NS_IMETHODIMP HttpBaseChannel::GetTopLevelContentWindowId(uint64_t *aWindowId) |
1527 | 0 | { |
1528 | 0 | if (!mContentWindowId) { |
1529 | 0 | nsCOMPtr<nsILoadContext> loadContext; |
1530 | 0 | GetCallback(loadContext); |
1531 | 0 | if (loadContext) { |
1532 | 0 | nsCOMPtr<mozIDOMWindowProxy> topWindow; |
1533 | 0 | loadContext->GetTopWindow(getter_AddRefs(topWindow)); |
1534 | 0 | nsCOMPtr<nsIDOMWindowUtils> windowUtils; |
1535 | 0 | if (topWindow) { |
1536 | 0 | windowUtils = nsGlobalWindowOuter::Cast(topWindow)->WindowUtils(); |
1537 | 0 | } |
1538 | 0 | if (windowUtils) { |
1539 | 0 | windowUtils->GetCurrentInnerWindowID(&mContentWindowId); |
1540 | 0 | } |
1541 | 0 | } |
1542 | 0 | } |
1543 | 0 | *aWindowId = mContentWindowId; |
1544 | 0 | return NS_OK; |
1545 | 0 | } |
1546 | | |
1547 | | NS_IMETHODIMP HttpBaseChannel::SetTopLevelOuterContentWindowId(uint64_t aWindowId) |
1548 | 0 | { |
1549 | 0 | mTopLevelOuterContentWindowId = aWindowId; |
1550 | 0 | return NS_OK; |
1551 | 0 | } |
1552 | | |
1553 | | NS_IMETHODIMP HttpBaseChannel::GetTopLevelOuterContentWindowId(uint64_t *aWindowId) |
1554 | 0 | { |
1555 | 0 | EnsureTopLevelOuterContentWindowId(); |
1556 | 0 | *aWindowId = mTopLevelOuterContentWindowId; |
1557 | 0 | return NS_OK; |
1558 | 0 | } |
1559 | | |
1560 | | NS_IMETHODIMP HttpBaseChannel::SetTopLevelContentWindowId(uint64_t aWindowId) |
1561 | 0 | { |
1562 | 0 | mContentWindowId = aWindowId; |
1563 | 0 | return NS_OK; |
1564 | 0 | } |
1565 | | |
1566 | | NS_IMETHODIMP |
1567 | | HttpBaseChannel::GetIsTrackingResource(bool* aIsTrackingResource) |
1568 | 0 | { |
1569 | 0 | MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource)); |
1570 | 0 | *aIsTrackingResource = |
1571 | 0 | mIsThirdPartyTrackingResource || mIsFirstPartyTrackingResource; |
1572 | 0 | return NS_OK; |
1573 | 0 | } |
1574 | | |
1575 | | NS_IMETHODIMP |
1576 | | HttpBaseChannel::GetIsThirdPartyTrackingResource(bool* aIsTrackingResource) |
1577 | 0 | { |
1578 | 0 | MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource)); |
1579 | 0 | *aIsTrackingResource = mIsThirdPartyTrackingResource; |
1580 | 0 | return NS_OK; |
1581 | 0 | } |
1582 | | |
1583 | | NS_IMETHODIMP |
1584 | | HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor(nsIHttpChannel* aDocumentChannel) |
1585 | 0 | { |
1586 | 0 | LOG(("HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor() %p " |
1587 | 0 | "mIsFirstPartyTrackingResource=%d mIsThirdPartyTrackingResource=%d", |
1588 | 0 | this, static_cast<int>(mIsFirstPartyTrackingResource), |
1589 | 0 | static_cast<int>(mIsThirdPartyTrackingResource))); |
1590 | 0 |
|
1591 | 0 | // The semantics we'd like to achieve here are that document.cookie |
1592 | 0 | // should follow the same rules that the document is subject to with |
1593 | 0 | // regards to content blocking. Therefore we need to propagate the |
1594 | 0 | // same flags from the document channel to the fake channel here. |
1595 | 0 | if (aDocumentChannel->GetIsThirdPartyTrackingResource()) { |
1596 | 0 | mIsThirdPartyTrackingResource = true; |
1597 | 0 | } else { |
1598 | 0 | mIsFirstPartyTrackingResource = true; |
1599 | 0 | } |
1600 | 0 |
|
1601 | 0 | MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource)); |
1602 | 0 | return NS_OK; |
1603 | 0 | } |
1604 | | |
1605 | | NS_IMETHODIMP |
1606 | | HttpBaseChannel::GetTransferSize(uint64_t *aTransferSize) |
1607 | 0 | { |
1608 | 0 | *aTransferSize = mTransferSize; |
1609 | 0 | return NS_OK; |
1610 | 0 | } |
1611 | | |
1612 | | NS_IMETHODIMP |
1613 | | HttpBaseChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize) |
1614 | 0 | { |
1615 | 0 | *aDecodedBodySize = mDecodedBodySize; |
1616 | 0 | return NS_OK; |
1617 | 0 | } |
1618 | | |
1619 | | NS_IMETHODIMP |
1620 | | HttpBaseChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize) |
1621 | 0 | { |
1622 | 0 | *aEncodedBodySize = mEncodedBodySize; |
1623 | 0 | return NS_OK; |
1624 | 0 | } |
1625 | | |
1626 | | NS_IMETHODIMP |
1627 | | HttpBaseChannel::GetRequestMethod(nsACString& aMethod) |
1628 | 0 | { |
1629 | 0 | mRequestHead.Method(aMethod); |
1630 | 0 | return NS_OK; |
1631 | 0 | } |
1632 | | |
1633 | | NS_IMETHODIMP |
1634 | | HttpBaseChannel::SetRequestMethod(const nsACString& aMethod) |
1635 | 0 | { |
1636 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
1637 | 0 |
|
1638 | 0 | const nsCString& flatMethod = PromiseFlatCString(aMethod); |
1639 | 0 |
|
1640 | 0 | // Method names are restricted to valid HTTP tokens. |
1641 | 0 | if (!nsHttp::IsValidToken(flatMethod)) |
1642 | 0 | return NS_ERROR_INVALID_ARG; |
1643 | 0 | |
1644 | 0 | mRequestHead.SetMethod(flatMethod); |
1645 | 0 | return NS_OK; |
1646 | 0 | } |
1647 | | |
1648 | | NS_IMETHODIMP |
1649 | | HttpBaseChannel::GetReferrer(nsIURI **referrer) |
1650 | 0 | { |
1651 | 0 | NS_ENSURE_ARG_POINTER(referrer); |
1652 | 0 | *referrer = mReferrer; |
1653 | 0 | NS_IF_ADDREF(*referrer); |
1654 | 0 | return NS_OK; |
1655 | 0 | } |
1656 | | |
1657 | | NS_IMETHODIMP |
1658 | | HttpBaseChannel::SetReferrer(nsIURI *referrer) |
1659 | 0 | { |
1660 | 0 | bool isPrivate = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; |
1661 | 0 | return SetReferrerWithPolicy(referrer, NS_GetDefaultReferrerPolicy(isPrivate)); |
1662 | 0 | } |
1663 | | |
1664 | | NS_IMETHODIMP |
1665 | | HttpBaseChannel::GetReferrerPolicy(uint32_t *referrerPolicy) |
1666 | 0 | { |
1667 | 0 | NS_ENSURE_ARG_POINTER(referrerPolicy); |
1668 | 0 | *referrerPolicy = mReferrerPolicy; |
1669 | 0 | return NS_OK; |
1670 | 0 | } |
1671 | | |
1672 | | |
1673 | | /* Computing whether our URI is cross-origin may be expensive, so please do |
1674 | | * that in cases where we're going to use this information later on. |
1675 | | */ |
1676 | | bool |
1677 | | HttpBaseChannel::IsCrossOriginWithReferrer() |
1678 | 0 | { |
1679 | 0 | nsresult rv; |
1680 | 0 | nsCOMPtr<nsIURI> triggeringURI; |
1681 | 0 | if (mLoadInfo) { |
1682 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = mLoadInfo->TriggeringPrincipal(); |
1683 | 0 | if (triggeringPrincipal) { |
1684 | 0 | triggeringPrincipal->GetURI(getter_AddRefs(triggeringURI)); |
1685 | 0 | } |
1686 | 0 | } |
1687 | 0 | if (triggeringURI) { |
1688 | 0 | if (LOG_ENABLED()) { |
1689 | 0 | nsAutoCString triggeringURISpec; |
1690 | 0 | triggeringURI->GetAsciiSpec(triggeringURISpec); |
1691 | 0 | LOG(("triggeringURI=%s\n", triggeringURISpec.get())); |
1692 | 0 | } |
1693 | 0 | nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); |
1694 | 0 | bool isPrivateWin = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; |
1695 | 0 | rv = ssm->CheckSameOriginURI(triggeringURI, mURI, false, isPrivateWin); |
1696 | 0 | return (NS_FAILED(rv)); |
1697 | 0 | } |
1698 | 0 |
|
1699 | 0 | LOG(("no triggering principal available via loadInfo, assuming load is cross-origin")); |
1700 | 0 | return true; |
1701 | 0 | } |
1702 | | |
1703 | | NS_IMETHODIMP |
1704 | | HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer, |
1705 | | uint32_t referrerPolicy) |
1706 | 0 | { |
1707 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
1708 | 0 |
|
1709 | 0 | mReferrerPolicy = referrerPolicy; |
1710 | 0 |
|
1711 | 0 | // clear existing referrer, if any |
1712 | 0 | mReferrer = nullptr; |
1713 | 0 | nsresult rv = mRequestHead.ClearHeader(nsHttp::Referer); |
1714 | 0 | if(NS_FAILED(rv)) { |
1715 | 0 | return rv; |
1716 | 0 | } |
1717 | 0 | |
1718 | 0 | if (mReferrerPolicy == REFERRER_POLICY_UNSET) { |
1719 | 0 | bool isPrivate = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; |
1720 | 0 | mReferrerPolicy = NS_GetDefaultReferrerPolicy(isPrivate); |
1721 | 0 | } |
1722 | 0 |
|
1723 | 0 | if (!referrer) { |
1724 | 0 | return NS_OK; |
1725 | 0 | } |
1726 | 0 | |
1727 | 0 | // Don't send referrer at all when the meta referrer setting is "no-referrer" |
1728 | 0 | if (mReferrerPolicy == REFERRER_POLICY_NO_REFERRER) { |
1729 | 0 | return NS_OK; |
1730 | 0 | } |
1731 | 0 | |
1732 | 0 | // 0: never send referer |
1733 | 0 | // 1: send referer for direct user action |
1734 | 0 | // 2: always send referer |
1735 | 0 | uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel(); |
1736 | 0 |
|
1737 | 0 | // false: use real referrer |
1738 | 0 | // true: spoof with URI of the current request |
1739 | 0 | bool userSpoofReferrerSource = gHttpHandler->SpoofReferrerSource(); |
1740 | 0 |
|
1741 | 0 | // false: use real referrer when leaving .onion |
1742 | 0 | // true: use an empty referrer |
1743 | 0 | bool userHideOnionReferrerSource = gHttpHandler->HideOnionReferrerSource(); |
1744 | 0 |
|
1745 | 0 | // 0: send referer no matter what |
1746 | 0 | // 1: send referer ONLY when base domains match |
1747 | 0 | // 2: send referer ONLY when hosts match |
1748 | 0 | int userReferrerXOriginPolicy = gHttpHandler->ReferrerXOriginPolicy(); |
1749 | 0 |
|
1750 | 0 | // check referrer blocking pref |
1751 | 0 | uint32_t referrerLevel; |
1752 | 0 | if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) { |
1753 | 0 | referrerLevel = 1; // user action |
1754 | 0 | } else { |
1755 | 0 | referrerLevel = 2; // inline content |
1756 | 0 | } |
1757 | 0 | if (userReferrerLevel < referrerLevel) { |
1758 | 0 | return NS_OK; |
1759 | 0 | } |
1760 | 0 | |
1761 | 0 | nsCOMPtr<nsIURI> referrerGrip; |
1762 | 0 | bool match; |
1763 | 0 |
|
1764 | 0 | // |
1765 | 0 | // Strip off "wyciwyg://123/" from wyciwyg referrers. |
1766 | 0 | // |
1767 | 0 | // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko. |
1768 | 0 | // perhaps some sort of generic nsINestedURI could be used. then, if an URI |
1769 | 0 | // fails the whitelist test, then we could check for an inner URI and try |
1770 | 0 | // that instead. though, that might be too automatic. |
1771 | 0 | // |
1772 | 0 | rv = referrer->SchemeIs("wyciwyg", &match); |
1773 | 0 | if (NS_FAILED(rv)) return rv; |
1774 | 0 | if (match) { |
1775 | 0 | nsAutoCString path; |
1776 | 0 | rv = referrer->GetPathQueryRef(path); |
1777 | 0 | if (NS_FAILED(rv)) return rv; |
1778 | 0 | |
1779 | 0 | uint32_t pathLength = path.Length(); |
1780 | 0 | if (pathLength <= 2) return NS_ERROR_FAILURE; |
1781 | 0 | |
1782 | 0 | // Path is of the form "//123/http://foo/bar", with a variable number of |
1783 | 0 | // digits. To figure out where the "real" URL starts, search path for a |
1784 | 0 | // '/', starting at the third character. |
1785 | 0 | int32_t slashIndex = path.FindChar('/', 2); |
1786 | 0 | if (slashIndex == kNotFound) return NS_ERROR_FAILURE; |
1787 | 0 | |
1788 | 0 | // Replace |referrer| with a URI without wyciwyg://123/. |
1789 | 0 | rv = NS_NewURI(getter_AddRefs(referrerGrip), |
1790 | 0 | Substring(path, slashIndex + 1, pathLength - slashIndex - 1)); |
1791 | 0 | if (NS_FAILED(rv)) return rv; |
1792 | 0 | |
1793 | 0 | referrer = referrerGrip.get(); |
1794 | 0 | } |
1795 | 0 |
|
1796 | 0 | // Enforce Referrer whitelist |
1797 | 0 | if (!IsReferrerSchemeAllowed(referrer)) { |
1798 | 0 | return NS_OK; // kick out.... |
1799 | 0 | } |
1800 | 0 | |
1801 | 0 | // |
1802 | 0 | // Handle secure referrals. |
1803 | 0 | // |
1804 | 0 | // Support referrals from a secure server if this is a secure site |
1805 | 0 | // and (optionally) if the host names are the same. |
1806 | 0 | // |
1807 | 0 | rv = referrer->SchemeIs("https", &match); |
1808 | 0 | if (NS_FAILED(rv)) return rv; |
1809 | 0 | |
1810 | 0 | if (match) { |
1811 | 0 | rv = mURI->SchemeIs("https", &match); |
1812 | 0 | if (NS_FAILED(rv)) return rv; |
1813 | 0 | |
1814 | 0 | // It's ok to send referrer for https-to-http scenarios if the referrer |
1815 | 0 | // policy is "unsafe-url", "origin", or "origin-when-cross-origin". |
1816 | 0 | if (mReferrerPolicy != REFERRER_POLICY_UNSAFE_URL && |
1817 | 0 | mReferrerPolicy != REFERRER_POLICY_ORIGIN_WHEN_XORIGIN && |
1818 | 0 | mReferrerPolicy != REFERRER_POLICY_ORIGIN) { |
1819 | 0 |
|
1820 | 0 | // in other referrer policies, https->http is not allowed... |
1821 | 0 | if (!match) return NS_OK; |
1822 | 0 | } |
1823 | 0 | } |
1824 | 0 | |
1825 | 0 | nsCOMPtr<nsIURI> clone; |
1826 | 0 | // |
1827 | 0 | // we need to clone the referrer, so we can: |
1828 | 0 | // (1) modify it |
1829 | 0 | // (2) keep a reference to it after returning from this function |
1830 | 0 | // |
1831 | 0 | // Strip away any fragment per RFC 2616 section 14.36 |
1832 | 0 | // and Referrer Policy section 6.3.5. |
1833 | 0 | rv = NS_GetURIWithoutRef(referrer, getter_AddRefs(clone)); |
1834 | 0 | if (NS_FAILED(rv)) return rv; |
1835 | 0 | |
1836 | 0 | nsAutoCString currentHost; |
1837 | 0 | nsAutoCString referrerHost; |
1838 | 0 |
|
1839 | 0 | rv = mURI->GetAsciiHost(currentHost); |
1840 | 0 | if (NS_FAILED(rv)) return rv; |
1841 | 0 | |
1842 | 0 | rv = clone->GetAsciiHost(referrerHost); |
1843 | 0 | if (NS_FAILED(rv)) return rv; |
1844 | 0 | |
1845 | 0 | // Send an empty referrer if leaving a .onion domain. |
1846 | 0 | if(userHideOnionReferrerSource && |
1847 | 0 | !currentHost.Equals(referrerHost) && |
1848 | 0 | StringEndsWith(referrerHost, NS_LITERAL_CSTRING(".onion"))) { |
1849 | 0 | return NS_OK; |
1850 | 0 | } |
1851 | 0 | |
1852 | 0 | // check policy for sending ref only when hosts match |
1853 | 0 | if (userReferrerXOriginPolicy == 2 && !currentHost.Equals(referrerHost)) |
1854 | 0 | return NS_OK; |
1855 | 0 | |
1856 | 0 | if (userReferrerXOriginPolicy == 1) { |
1857 | 0 | nsAutoCString currentDomain = currentHost; |
1858 | 0 | nsAutoCString referrerDomain = referrerHost; |
1859 | 0 | uint32_t extraDomains = 0; |
1860 | 0 | nsCOMPtr<nsIEffectiveTLDService> eTLDService = do_GetService( |
1861 | 0 | NS_EFFECTIVETLDSERVICE_CONTRACTID); |
1862 | 0 | if (eTLDService) { |
1863 | 0 | rv = eTLDService->GetBaseDomain(mURI, extraDomains, currentDomain); |
1864 | 0 | if (NS_FAILED(rv)) return rv; |
1865 | 0 | rv = eTLDService->GetBaseDomain(clone, extraDomains, referrerDomain); |
1866 | 0 | if (NS_FAILED(rv)) return rv; |
1867 | 0 | } |
1868 | 0 | |
1869 | 0 | // check policy for sending only when effective top level domain matches. |
1870 | 0 | // this falls back on using host if eTLDService does not work |
1871 | 0 | if (!currentDomain.Equals(referrerDomain)) |
1872 | 0 | return NS_OK; |
1873 | 0 | } |
1874 | 0 | |
1875 | 0 | // send spoofed referrer if desired |
1876 | 0 | if (userSpoofReferrerSource) { |
1877 | 0 | nsCOMPtr<nsIURI> mURIclone; |
1878 | 0 | rv = NS_GetURIWithoutRef(mURI, getter_AddRefs(mURIclone)); |
1879 | 0 | if (NS_FAILED(rv)) return rv; |
1880 | 0 | clone = mURIclone; |
1881 | 0 | currentHost = referrerHost; |
1882 | 0 | } |
1883 | 0 |
|
1884 | 0 | // strip away any userpass; we don't want to be giving out passwords ;-) |
1885 | 0 | // This is required by Referrer Policy stripping algorithm. |
1886 | 0 | rv = NS_MutateURI(clone) |
1887 | 0 | .SetUserPass(EmptyCString()) |
1888 | 0 | .Finalize(clone); |
1889 | 0 | if (NS_FAILED(rv)) return rv; |
1890 | 0 | |
1891 | 0 | // 0: full URI |
1892 | 0 | // 1: scheme+host+port+path |
1893 | 0 | // 2: scheme+host+port |
1894 | 0 | int userReferrerTrimmingPolicy = gHttpHandler->ReferrerTrimmingPolicy(); |
1895 | 0 | int userReferrerXOriginTrimmingPolicy = |
1896 | 0 | gHttpHandler->ReferrerXOriginTrimmingPolicy(); |
1897 | 0 |
|
1898 | 0 | switch (mReferrerPolicy) { |
1899 | 0 | case REFERRER_POLICY_SAME_ORIGIN: |
1900 | 0 | // Don't send referrer when the request is cross-origin and policy is "same-origin". |
1901 | 0 | if (IsCrossOriginWithReferrer()) { |
1902 | 0 | return NS_OK; |
1903 | 0 | } |
1904 | 0 | break; |
1905 | 0 |
|
1906 | 0 | case REFERRER_POLICY_ORIGIN: |
1907 | 0 | case REFERRER_POLICY_STRICT_ORIGIN: |
1908 | 0 | userReferrerTrimmingPolicy = 2; |
1909 | 0 | break; |
1910 | 0 |
|
1911 | 0 | case REFERRER_POLICY_ORIGIN_WHEN_XORIGIN: |
1912 | 0 | case REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN: |
1913 | 0 | if (userReferrerTrimmingPolicy != 2 && IsCrossOriginWithReferrer()) { |
1914 | 0 | // Ignore set userReferrerTrimmingPolicy if it is already the strictest |
1915 | 0 | // policy. |
1916 | 0 | userReferrerTrimmingPolicy = 2; |
1917 | 0 | } |
1918 | 0 | break; |
1919 | 0 |
|
1920 | 0 | case REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE: |
1921 | 0 | case REFERRER_POLICY_UNSAFE_URL: |
1922 | 0 | if (userReferrerTrimmingPolicy != 2) { |
1923 | 0 | // Ignore set userReferrerTrimmingPolicy if it is already the strictest |
1924 | 0 | // policy. Apply the user cross-origin trimming policy if it's more |
1925 | 0 | // restrictive than the general one. |
1926 | 0 | if (userReferrerXOriginTrimmingPolicy != 0 && IsCrossOriginWithReferrer()) { |
1927 | 0 | userReferrerTrimmingPolicy = |
1928 | 0 | std::max(userReferrerTrimmingPolicy, userReferrerXOriginTrimmingPolicy); |
1929 | 0 | } |
1930 | 0 | } |
1931 | 0 |
|
1932 | 0 | break; |
1933 | 0 |
|
1934 | 0 | case REFERRER_POLICY_NO_REFERRER: |
1935 | 0 | case REFERRER_POLICY_UNSET: |
1936 | 0 | default: |
1937 | 0 | MOZ_ASSERT_UNREACHABLE("Unexpected value"); |
1938 | 0 | break; |
1939 | 0 | } |
1940 | 0 |
|
1941 | 0 | nsAutoCString spec; |
1942 | 0 | // check how much referer to send |
1943 | 0 | if (userReferrerTrimmingPolicy) { |
1944 | 0 | // All output strings start with: scheme+host+port |
1945 | 0 | // We want the IDN-normalized PrePath. That's not something currently |
1946 | 0 | // available and there doesn't yet seem to be justification for adding it to |
1947 | 0 | // the interfaces, so just build it up ourselves from scheme+AsciiHostPort |
1948 | 0 | nsAutoCString scheme, asciiHostPort; |
1949 | 0 | rv = clone->GetScheme(scheme); |
1950 | 0 | if (NS_FAILED(rv)) return rv; |
1951 | 0 | spec = scheme; |
1952 | 0 | spec.AppendLiteral("://"); |
1953 | 0 | // Note we explicitly cleared UserPass above, so do not need to build it. |
1954 | 0 | rv = clone->GetAsciiHostPort(asciiHostPort); |
1955 | 0 | if (NS_FAILED(rv)) return rv; |
1956 | 0 | spec.Append(asciiHostPort); |
1957 | 0 |
|
1958 | 0 | switch (userReferrerTrimmingPolicy) { |
1959 | 0 | case 1: { // scheme+host+port+path |
1960 | 0 | nsCOMPtr<nsIURL> url(do_QueryInterface(clone)); |
1961 | 0 | if (url) { |
1962 | 0 | nsAutoCString path; |
1963 | 0 | rv = url->GetFilePath(path); |
1964 | 0 | if (NS_FAILED(rv)) return rv; |
1965 | 0 | spec.Append(path); |
1966 | 0 | rv = NS_MutateURI(url) |
1967 | 0 | .SetQuery(EmptyCString()) |
1968 | 0 | .SetRef(EmptyCString()) |
1969 | 0 | .Finalize(clone); |
1970 | 0 | if (NS_FAILED(rv)) return rv; |
1971 | 0 | break; |
1972 | 0 | } |
1973 | 0 | // No URL, so fall through to truncating the path and any query/ref off |
1974 | 0 | // as well. |
1975 | 0 | } |
1976 | 0 | MOZ_FALLTHROUGH; |
1977 | 0 | default: // (Pref limited to [0,2] enforced by clamp, MOZ_CRASH overkill.) |
1978 | 0 | case 2: // scheme+host+port+/ |
1979 | 0 | spec.AppendLiteral("/"); |
1980 | 0 | // This nukes any query/ref present as well in the case of nsStandardURL |
1981 | 0 | rv = NS_MutateURI(clone) |
1982 | 0 | .SetPathQueryRef(EmptyCString()) |
1983 | 0 | .Finalize(clone); |
1984 | 0 | if (NS_FAILED(rv)) return rv; |
1985 | 0 | break; |
1986 | 0 | } |
1987 | 0 | } else { |
1988 | 0 | // use the full URI |
1989 | 0 | rv = clone->GetAsciiSpec(spec); |
1990 | 0 | if (NS_FAILED(rv)) return rv; |
1991 | 0 | } |
1992 | 0 | |
1993 | 0 | // finally, remember the referrer URI and set the Referer header. |
1994 | 0 | rv = SetRequestHeader(NS_LITERAL_CSTRING("Referer"), spec, false); |
1995 | 0 | if (NS_FAILED(rv)) return rv; |
1996 | 0 | |
1997 | 0 | mReferrer = clone; |
1998 | 0 | return NS_OK; |
1999 | 0 | } |
2000 | | |
2001 | | // Return the channel's proxy URI, or if it doesn't exist, the |
2002 | | // channel's main URI. |
2003 | | NS_IMETHODIMP |
2004 | | HttpBaseChannel::GetProxyURI(nsIURI **aOut) |
2005 | 0 | { |
2006 | 0 | NS_ENSURE_ARG_POINTER(aOut); |
2007 | 0 | nsCOMPtr<nsIURI> result(mProxyURI); |
2008 | 0 | result.forget(aOut); |
2009 | 0 | return NS_OK; |
2010 | 0 | } |
2011 | | |
2012 | | NS_IMETHODIMP |
2013 | | HttpBaseChannel::GetRequestHeader(const nsACString& aHeader, |
2014 | | nsACString& aValue) |
2015 | 0 | { |
2016 | 0 | aValue.Truncate(); |
2017 | 0 |
|
2018 | 0 | // XXX might be better to search the header list directly instead of |
2019 | 0 | // hitting the http atom hash table. |
2020 | 0 | nsHttpAtom atom = nsHttp::ResolveAtom(aHeader); |
2021 | 0 | if (!atom) |
2022 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2023 | 0 | |
2024 | 0 | return mRequestHead.GetHeader(atom, aValue); |
2025 | 0 | } |
2026 | | |
2027 | | NS_IMETHODIMP |
2028 | | HttpBaseChannel::SetRequestHeader(const nsACString& aHeader, |
2029 | | const nsACString& aValue, |
2030 | | bool aMerge) |
2031 | 0 | { |
2032 | 0 | const nsCString &flatHeader = PromiseFlatCString(aHeader); |
2033 | 0 | const nsCString &flatValue = PromiseFlatCString(aValue); |
2034 | 0 |
|
2035 | 0 | LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n", |
2036 | 0 | this, flatHeader.get(), flatValue.get(), aMerge)); |
2037 | 0 |
|
2038 | 0 | // Verify header names are valid HTTP tokens and header values are reasonably |
2039 | 0 | // close to whats allowed in RFC 2616. |
2040 | 0 | if (!nsHttp::IsValidToken(flatHeader) || |
2041 | 0 | !nsHttp::IsReasonableHeaderValue(flatValue)) { |
2042 | 0 | return NS_ERROR_INVALID_ARG; |
2043 | 0 | } |
2044 | 0 | |
2045 | 0 | return mRequestHead.SetHeader(aHeader, flatValue, aMerge); |
2046 | 0 | } |
2047 | | |
2048 | | NS_IMETHODIMP |
2049 | | HttpBaseChannel::SetEmptyRequestHeader(const nsACString& aHeader) |
2050 | 0 | { |
2051 | 0 | const nsCString &flatHeader = PromiseFlatCString(aHeader); |
2052 | 0 |
|
2053 | 0 | LOG(("HttpBaseChannel::SetEmptyRequestHeader [this=%p header=\"%s\"]\n", |
2054 | 0 | this, flatHeader.get())); |
2055 | 0 |
|
2056 | 0 | // Verify header names are valid HTTP tokens and header values are reasonably |
2057 | 0 | // close to whats allowed in RFC 2616. |
2058 | 0 | if (!nsHttp::IsValidToken(flatHeader)) { |
2059 | 0 | return NS_ERROR_INVALID_ARG; |
2060 | 0 | } |
2061 | 0 | |
2062 | 0 | return mRequestHead.SetEmptyHeader(aHeader); |
2063 | 0 | } |
2064 | | |
2065 | | NS_IMETHODIMP |
2066 | | HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor) |
2067 | 0 | { |
2068 | 0 | return mRequestHead.VisitHeaders(visitor); |
2069 | 0 | } |
2070 | | |
2071 | | NS_IMETHODIMP |
2072 | | HttpBaseChannel::VisitNonDefaultRequestHeaders(nsIHttpHeaderVisitor *visitor) |
2073 | 0 | { |
2074 | 0 | return mRequestHead.VisitHeaders(visitor, |
2075 | 0 | nsHttpHeaderArray::eFilterSkipDefault); |
2076 | 0 | } |
2077 | | |
2078 | | NS_IMETHODIMP |
2079 | | HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value) |
2080 | 0 | { |
2081 | 0 | value.Truncate(); |
2082 | 0 |
|
2083 | 0 | if (!mResponseHead) |
2084 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2085 | 0 | |
2086 | 0 | nsHttpAtom atom = nsHttp::ResolveAtom(header); |
2087 | 0 | if (!atom) |
2088 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2089 | 0 | |
2090 | 0 | return mResponseHead->GetHeader(atom, value); |
2091 | 0 | } |
2092 | | |
2093 | | NS_IMETHODIMP |
2094 | | HttpBaseChannel::SetResponseHeader(const nsACString& header, |
2095 | | const nsACString& value, |
2096 | | bool merge) |
2097 | 0 | { |
2098 | 0 | LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n", |
2099 | 0 | this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge)); |
2100 | 0 |
|
2101 | 0 | if (!mResponseHead) |
2102 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2103 | 0 | |
2104 | 0 | nsHttpAtom atom = nsHttp::ResolveAtom(header); |
2105 | 0 | if (!atom) |
2106 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2107 | 0 | |
2108 | 0 | // these response headers must not be changed |
2109 | 0 | if (atom == nsHttp::Content_Type || |
2110 | 0 | atom == nsHttp::Content_Length || |
2111 | 0 | atom == nsHttp::Content_Encoding || |
2112 | 0 | atom == nsHttp::Trailer || |
2113 | 0 | atom == nsHttp::Transfer_Encoding) |
2114 | 0 | return NS_ERROR_ILLEGAL_VALUE; |
2115 | 0 | |
2116 | 0 | mResponseHeadersModified = true; |
2117 | 0 |
|
2118 | 0 | return mResponseHead->SetHeader(header, value, merge); |
2119 | 0 | } |
2120 | | |
2121 | | NS_IMETHODIMP |
2122 | | HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor) |
2123 | 0 | { |
2124 | 0 | if (!mResponseHead) { |
2125 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2126 | 0 | } |
2127 | 0 | return mResponseHead->VisitHeaders(visitor, |
2128 | 0 | nsHttpHeaderArray::eFilterResponse); |
2129 | 0 | } |
2130 | | |
2131 | | NS_IMETHODIMP |
2132 | | HttpBaseChannel::GetOriginalResponseHeader(const nsACString& aHeader, |
2133 | | nsIHttpHeaderVisitor *aVisitor) |
2134 | 0 | { |
2135 | 0 | if (!mResponseHead) { |
2136 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2137 | 0 | } |
2138 | 0 | |
2139 | 0 | nsHttpAtom atom = nsHttp::ResolveAtom(aHeader); |
2140 | 0 | if (!atom) { |
2141 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2142 | 0 | } |
2143 | 0 | |
2144 | 0 | return mResponseHead->GetOriginalHeader(atom, aVisitor); |
2145 | 0 | } |
2146 | | |
2147 | | NS_IMETHODIMP |
2148 | | HttpBaseChannel::VisitOriginalResponseHeaders(nsIHttpHeaderVisitor *aVisitor) |
2149 | 0 | { |
2150 | 0 | if (!mResponseHead) { |
2151 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2152 | 0 | } |
2153 | 0 | |
2154 | 0 | return mResponseHead->VisitHeaders(aVisitor, |
2155 | 0 | nsHttpHeaderArray::eFilterResponseOriginal); |
2156 | 0 | } |
2157 | | |
2158 | | NS_IMETHODIMP |
2159 | | HttpBaseChannel::GetAllowPipelining(bool *value) |
2160 | 0 | { |
2161 | 0 | NS_ENSURE_ARG_POINTER(value); |
2162 | 0 | *value = false; |
2163 | 0 | return NS_OK; |
2164 | 0 | } |
2165 | | |
2166 | | NS_IMETHODIMP |
2167 | | HttpBaseChannel::SetAllowPipelining(bool value) |
2168 | 0 | { |
2169 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
2170 | 0 | // nop |
2171 | 0 | return NS_OK; |
2172 | 0 | } |
2173 | | |
2174 | | NS_IMETHODIMP |
2175 | | HttpBaseChannel::GetAllowSTS(bool *value) |
2176 | 0 | { |
2177 | 0 | NS_ENSURE_ARG_POINTER(value); |
2178 | 0 | *value = mAllowSTS; |
2179 | 0 | return NS_OK; |
2180 | 0 | } |
2181 | | |
2182 | | NS_IMETHODIMP |
2183 | | HttpBaseChannel::SetAllowSTS(bool value) |
2184 | 0 | { |
2185 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
2186 | 0 |
|
2187 | 0 | mAllowSTS = value; |
2188 | 0 | return NS_OK; |
2189 | 0 | } |
2190 | | |
2191 | | NS_IMETHODIMP |
2192 | | HttpBaseChannel::GetRedirectionLimit(uint32_t *value) |
2193 | 0 | { |
2194 | 0 | NS_ENSURE_ARG_POINTER(value); |
2195 | 0 | *value = mRedirectionLimit; |
2196 | 0 | return NS_OK; |
2197 | 0 | } |
2198 | | |
2199 | | NS_IMETHODIMP |
2200 | | HttpBaseChannel::SetRedirectionLimit(uint32_t value) |
2201 | 0 | { |
2202 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
2203 | 0 |
|
2204 | 0 | mRedirectionLimit = std::min<uint32_t>(value, 0xff); |
2205 | 0 | return NS_OK; |
2206 | 0 | } |
2207 | | |
2208 | | nsresult |
2209 | | HttpBaseChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo) |
2210 | 0 | { |
2211 | 0 | MOZ_ASSERT(!mSecurityInfo, |
2212 | 0 | "This can only be called when we don't have a security info object already"); |
2213 | 0 | MOZ_RELEASE_ASSERT(aSecurityInfo, |
2214 | 0 | "This can only be called with a valid security info object"); |
2215 | 0 | MOZ_ASSERT(!BypassServiceWorker(), |
2216 | 0 | "This can only be called on channels that are not bypassing interception"); |
2217 | 0 | MOZ_ASSERT(mResponseCouldBeSynthesized, |
2218 | 0 | "This can only be called on channels that can be intercepted"); |
2219 | 0 | if (mSecurityInfo) { |
2220 | 0 | LOG(("HttpBaseChannel::OverrideSecurityInfo mSecurityInfo is null! " |
2221 | 0 | "[this=%p]\n", this)); |
2222 | 0 | return NS_ERROR_UNEXPECTED; |
2223 | 0 | } |
2224 | 0 | if (!mResponseCouldBeSynthesized) { |
2225 | 0 | LOG(("HttpBaseChannel::OverrideSecurityInfo channel cannot be intercepted! " |
2226 | 0 | "[this=%p]\n", this)); |
2227 | 0 | return NS_ERROR_UNEXPECTED; |
2228 | 0 | } |
2229 | 0 |
|
2230 | 0 | mSecurityInfo = aSecurityInfo; |
2231 | 0 | return NS_OK; |
2232 | 0 | } |
2233 | | |
2234 | | NS_IMETHODIMP |
2235 | | HttpBaseChannel::IsNoStoreResponse(bool *value) |
2236 | 0 | { |
2237 | 0 | if (!mResponseHead) |
2238 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2239 | 0 | *value = mResponseHead->NoStore(); |
2240 | 0 | return NS_OK; |
2241 | 0 | } |
2242 | | |
2243 | | NS_IMETHODIMP |
2244 | | HttpBaseChannel::IsNoCacheResponse(bool *value) |
2245 | 0 | { |
2246 | 0 | if (!mResponseHead) |
2247 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2248 | 0 | *value = mResponseHead->NoCache(); |
2249 | 0 | if (!*value) |
2250 | 0 | *value = mResponseHead->ExpiresInPast(); |
2251 | 0 | return NS_OK; |
2252 | 0 | } |
2253 | | |
2254 | | NS_IMETHODIMP |
2255 | | HttpBaseChannel::IsPrivateResponse(bool *value) |
2256 | 0 | { |
2257 | 0 | if (!mResponseHead) |
2258 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2259 | 0 | *value = mResponseHead->Private(); |
2260 | 0 | return NS_OK; |
2261 | 0 | } |
2262 | | |
2263 | | NS_IMETHODIMP |
2264 | | HttpBaseChannel::GetResponseStatus(uint32_t *aValue) |
2265 | 0 | { |
2266 | 0 | if (!mResponseHead) |
2267 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2268 | 0 | *aValue = mResponseHead->Status(); |
2269 | 0 | return NS_OK; |
2270 | 0 | } |
2271 | | |
2272 | | NS_IMETHODIMP |
2273 | | HttpBaseChannel::GetResponseStatusText(nsACString& aValue) |
2274 | 0 | { |
2275 | 0 | if (!mResponseHead) |
2276 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2277 | 0 | mResponseHead->StatusText(aValue); |
2278 | 0 | return NS_OK; |
2279 | 0 | } |
2280 | | |
2281 | | NS_IMETHODIMP |
2282 | | HttpBaseChannel::GetRequestSucceeded(bool *aValue) |
2283 | 0 | { |
2284 | 0 | if (!mResponseHead) |
2285 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2286 | 0 | uint32_t status = mResponseHead->Status(); |
2287 | 0 | *aValue = (status / 100 == 2); |
2288 | 0 | return NS_OK; |
2289 | 0 | } |
2290 | | |
2291 | | NS_IMETHODIMP |
2292 | | HttpBaseChannel::RedirectTo(nsIURI *targetURI) |
2293 | 0 | { |
2294 | 0 | NS_ENSURE_ARG(targetURI); |
2295 | 0 |
|
2296 | 0 | nsAutoCString spec; |
2297 | 0 | targetURI->GetAsciiSpec(spec); |
2298 | 0 | LOG(("HttpBaseChannel::RedirectTo [this=%p, uri=%s]", this, spec.get())); |
2299 | 0 | LogCallingScriptLocation(this); |
2300 | 0 |
|
2301 | 0 | // We cannot redirect after OnStartRequest of the listener |
2302 | 0 | // has been called, since to redirect we have to switch channels |
2303 | 0 | // and the dance with OnStartRequest et al has to start over. |
2304 | 0 | // This would break the nsIStreamListener contract. |
2305 | 0 | NS_ENSURE_FALSE(mOnStartRequestCalled, NS_ERROR_NOT_AVAILABLE); |
2306 | 0 |
|
2307 | 0 | mAPIRedirectToURI = targetURI; |
2308 | 0 | // Only Web Extensions are allowed to redirect a channel to a data: |
2309 | 0 | // URI. To avoid any bypasses after the channel was flagged by |
2310 | 0 | // the WebRequst API, we are dropping the flag here. |
2311 | 0 | if (mLoadInfo) { |
2312 | 0 | mLoadInfo->SetAllowInsecureRedirectToDataURI(false); |
2313 | 0 | } |
2314 | 0 | return NS_OK; |
2315 | 0 | } |
2316 | | |
2317 | | NS_IMETHODIMP |
2318 | | HttpBaseChannel::UpgradeToSecure() |
2319 | 0 | { |
2320 | 0 | // Upgrades are handled internally between http-on-modify-request and |
2321 | 0 | // http-on-before-connect, which means upgrades are only possible during |
2322 | 0 | // on-modify, or WebRequest.onBeforeRequest in Web Extensions. Once we are |
2323 | 0 | // past the code path where upgrades are handled, attempting an upgrade |
2324 | 0 | // will throw an error. |
2325 | 0 | NS_ENSURE_TRUE(mUpgradableToSecure, NS_ERROR_NOT_AVAILABLE); |
2326 | 0 |
|
2327 | 0 | mUpgradeToSecure = true; |
2328 | 0 | return NS_OK; |
2329 | 0 | } |
2330 | | |
2331 | | NS_IMETHODIMP |
2332 | | HttpBaseChannel::GetRequestContextID(uint64_t *aRCID) |
2333 | 0 | { |
2334 | 0 | NS_ENSURE_ARG_POINTER(aRCID); |
2335 | 0 | *aRCID = mRequestContextID; |
2336 | 0 | return NS_OK; |
2337 | 0 | } |
2338 | | |
2339 | | NS_IMETHODIMP |
2340 | | HttpBaseChannel::SetRequestContextID(uint64_t aRCID) |
2341 | 0 | { |
2342 | 0 | mRequestContextID = aRCID; |
2343 | 0 | return NS_OK; |
2344 | 0 | } |
2345 | | |
2346 | | NS_IMETHODIMP |
2347 | | HttpBaseChannel::GetIsMainDocumentChannel(bool* aValue) |
2348 | 0 | { |
2349 | 0 | NS_ENSURE_ARG_POINTER(aValue); |
2350 | 0 | *aValue = IsNavigation(); |
2351 | 0 | return NS_OK; |
2352 | 0 | } |
2353 | | |
2354 | | NS_IMETHODIMP |
2355 | | HttpBaseChannel::SetIsMainDocumentChannel(bool aValue) |
2356 | 0 | { |
2357 | 0 | mForceMainDocumentChannel = aValue; |
2358 | 0 | return NS_OK; |
2359 | 0 | } |
2360 | | |
2361 | | NS_IMETHODIMP |
2362 | | HttpBaseChannel::GetProtocolVersion(nsACString& aProtocolVersion) |
2363 | 0 | { |
2364 | 0 | nsresult rv; |
2365 | 0 | nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(mSecurityInfo, &rv); |
2366 | 0 | nsAutoCString protocol; |
2367 | 0 | if (NS_SUCCEEDED(rv) && ssl && |
2368 | 0 | NS_SUCCEEDED(ssl->GetNegotiatedNPN(protocol)) && |
2369 | 0 | !protocol.IsEmpty()) { |
2370 | 0 | // The negotiated protocol was not empty so we can use it. |
2371 | 0 | aProtocolVersion = protocol; |
2372 | 0 | return NS_OK; |
2373 | 0 | } |
2374 | 0 | |
2375 | 0 | if (mResponseHead) { |
2376 | 0 | HttpVersion version = mResponseHead->Version(); |
2377 | 0 | aProtocolVersion.Assign(nsHttp::GetProtocolVersion(version)); |
2378 | 0 | return NS_OK; |
2379 | 0 | } |
2380 | 0 | |
2381 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2382 | 0 | } |
2383 | | |
2384 | | |
2385 | | //----------------------------------------------------------------------------- |
2386 | | // HttpBaseChannel::nsIHttpChannelInternal |
2387 | | //----------------------------------------------------------------------------- |
2388 | | |
2389 | | NS_IMETHODIMP |
2390 | | HttpBaseChannel::SetTopWindowURIIfUnknown(nsIURI *aTopWindowURI) |
2391 | 0 | { |
2392 | 0 | if (!aTopWindowURI) { |
2393 | 0 | return NS_ERROR_INVALID_ARG; |
2394 | 0 | } |
2395 | 0 | |
2396 | 0 | if (mTopWindowURI) { |
2397 | 0 | LOG(("HttpChannelBase::SetTopWindowURIIfUnknown [this=%p] " |
2398 | 0 | "mTopWindowURI is already set.\n", this)); |
2399 | 0 | return NS_ERROR_FAILURE; |
2400 | 0 | } |
2401 | 0 |
|
2402 | 0 | nsCOMPtr<nsIURI> topWindowURI; |
2403 | 0 | Unused << GetTopWindowURI(getter_AddRefs(topWindowURI)); |
2404 | 0 |
|
2405 | 0 | // Don't modify |mTopWindowURI| if we can get one from GetTopWindowURI(). |
2406 | 0 | if (topWindowURI) { |
2407 | 0 | LOG(("HttpChannelBase::SetTopWindowURIIfUnknown [this=%p] " |
2408 | 0 | "Return an error since we got a top window uri.\n", this)); |
2409 | 0 | return NS_ERROR_FAILURE; |
2410 | 0 | } |
2411 | 0 |
|
2412 | 0 | mTopWindowURI = aTopWindowURI; |
2413 | 0 | return NS_OK; |
2414 | 0 | } |
2415 | | |
2416 | | NS_IMETHODIMP |
2417 | | HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI) |
2418 | 0 | { |
2419 | 0 | nsresult rv = NS_OK; |
2420 | 0 | nsCOMPtr<mozIThirdPartyUtil> util; |
2421 | 0 | // Only compute the top window URI once. In e10s, this must be computed in the |
2422 | 0 | // child. The parent gets the top window URI through HttpChannelOpenArgs. |
2423 | 0 | if (!mTopWindowURI) { |
2424 | 0 | util = services::GetThirdPartyUtil(); |
2425 | 0 | if (!util) { |
2426 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2427 | 0 | } |
2428 | 0 | nsCOMPtr<mozIDOMWindowProxy> win; |
2429 | 0 | rv = util->GetTopWindowForChannel(this, getter_AddRefs(win)); |
2430 | 0 | if (NS_SUCCEEDED(rv)) { |
2431 | 0 | rv = util->GetURIFromWindow(win, getter_AddRefs(mTopWindowURI)); |
2432 | | #if DEBUG |
2433 | | if (mTopWindowURI) { |
2434 | | nsCString spec; |
2435 | | if (NS_SUCCEEDED(mTopWindowURI->GetSpec(spec))) { |
2436 | | LOG(("HttpChannelBase::Setting topwindow URI spec %s [this=%p]\n", |
2437 | | spec.get(), this)); |
2438 | | } |
2439 | | } |
2440 | | #endif |
2441 | | } |
2442 | 0 | } |
2443 | 0 | NS_IF_ADDREF(*aTopWindowURI = mTopWindowURI); |
2444 | 0 | return rv; |
2445 | 0 | } |
2446 | | |
2447 | | NS_IMETHODIMP |
2448 | | HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI) |
2449 | 0 | { |
2450 | 0 | NS_ENSURE_ARG_POINTER(aDocumentURI); |
2451 | 0 | *aDocumentURI = mDocumentURI; |
2452 | 0 | NS_IF_ADDREF(*aDocumentURI); |
2453 | 0 | return NS_OK; |
2454 | 0 | } |
2455 | | |
2456 | | NS_IMETHODIMP |
2457 | | HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI) |
2458 | 0 | { |
2459 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
2460 | 0 |
|
2461 | 0 | mDocumentURI = aDocumentURI; |
2462 | 0 | return NS_OK; |
2463 | 0 | } |
2464 | | |
2465 | | NS_IMETHODIMP |
2466 | | HttpBaseChannel::GetRequestVersion(uint32_t *major, uint32_t *minor) |
2467 | 0 | { |
2468 | 0 | HttpVersion version = mRequestHead.Version(); |
2469 | 0 |
|
2470 | 0 | if (major) { *major = static_cast<uint32_t>(version) / 10; } |
2471 | 0 | if (minor) { *minor = static_cast<uint32_t>(version) % 10; } |
2472 | 0 |
|
2473 | 0 | return NS_OK; |
2474 | 0 | } |
2475 | | |
2476 | | NS_IMETHODIMP |
2477 | | HttpBaseChannel::GetResponseVersion(uint32_t *major, uint32_t *minor) |
2478 | 0 | { |
2479 | 0 | if (!mResponseHead) |
2480 | 0 | { |
2481 | 0 | *major = *minor = 0; // we should at least be kind about it |
2482 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2483 | 0 | } |
2484 | 0 | |
2485 | 0 | HttpVersion version = mResponseHead->Version(); |
2486 | 0 |
|
2487 | 0 | if (major) { *major = static_cast<uint32_t>(version) / 10; } |
2488 | 0 | if (minor) { *minor = static_cast<uint32_t>(version) % 10; } |
2489 | 0 |
|
2490 | 0 | return NS_OK; |
2491 | 0 | } |
2492 | | |
2493 | | void |
2494 | | HttpBaseChannel::NotifySetCookie(char const *aCookie) |
2495 | 0 | { |
2496 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
2497 | 0 | if (obs) { |
2498 | 0 | nsAutoString cookie; |
2499 | 0 | CopyASCIItoUTF16(mozilla::MakeStringSpan(aCookie), cookie); |
2500 | 0 | obs->NotifyObservers(static_cast<nsIChannel*>(this), |
2501 | 0 | "http-on-response-set-cookie", |
2502 | 0 | cookie.get()); |
2503 | 0 | } |
2504 | 0 | } |
2505 | | |
2506 | | NS_IMETHODIMP |
2507 | | HttpBaseChannel::SetCookie(const char *aCookieHeader) |
2508 | 0 | { |
2509 | 0 | if (mLoadFlags & LOAD_ANONYMOUS) |
2510 | 0 | return NS_OK; |
2511 | 0 | |
2512 | 0 | // empty header isn't an error |
2513 | 0 | if (!(aCookieHeader && *aCookieHeader)) |
2514 | 0 | return NS_OK; |
2515 | 0 | |
2516 | 0 | nsICookieService *cs = gHttpHandler->GetCookieService(); |
2517 | 0 | NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE); |
2518 | 0 |
|
2519 | 0 | nsAutoCString date; |
2520 | 0 | // empty date is not an error |
2521 | 0 | Unused << mResponseHead->GetHeader(nsHttp::Date, date); |
2522 | 0 | nsresult rv = cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, |
2523 | 0 | aCookieHeader, date.get(), this); |
2524 | 0 | if (NS_SUCCEEDED(rv)) { |
2525 | 0 | NotifySetCookie(aCookieHeader); |
2526 | 0 | } |
2527 | 0 | return rv; |
2528 | 0 | } |
2529 | | |
2530 | | NS_IMETHODIMP |
2531 | | HttpBaseChannel::GetThirdPartyFlags(uint32_t *aFlags) |
2532 | 0 | { |
2533 | 0 | *aFlags = mThirdPartyFlags; |
2534 | 0 | return NS_OK; |
2535 | 0 | } |
2536 | | |
2537 | | NS_IMETHODIMP |
2538 | | HttpBaseChannel::SetThirdPartyFlags(uint32_t aFlags) |
2539 | 0 | { |
2540 | 0 | ENSURE_CALLED_BEFORE_ASYNC_OPEN(); |
2541 | 0 |
|
2542 | 0 | mThirdPartyFlags = aFlags; |
2543 | 0 | return NS_OK; |
2544 | 0 | } |
2545 | | |
2546 | | NS_IMETHODIMP |
2547 | | HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce) |
2548 | 0 | { |
2549 | 0 | *aForce = !!(mThirdPartyFlags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW); |
2550 | 0 | return NS_OK; |
2551 | 0 | } |
2552 | | |
2553 | | NS_IMETHODIMP |
2554 | | HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce) |
2555 | 0 | { |
2556 | 0 | ENSURE_CALLED_BEFORE_ASYNC_OPEN(); |
2557 | 0 |
|
2558 | 0 | if (aForce) |
2559 | 0 | mThirdPartyFlags |= nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW; |
2560 | 0 | else |
2561 | 0 | mThirdPartyFlags &= ~nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW; |
2562 | 0 |
|
2563 | 0 | return NS_OK; |
2564 | 0 | } |
2565 | | |
2566 | | NS_IMETHODIMP |
2567 | | HttpBaseChannel::GetCanceled(bool *aCanceled) |
2568 | 0 | { |
2569 | 0 | *aCanceled = mCanceled; |
2570 | 0 | return NS_OK; |
2571 | 0 | } |
2572 | | |
2573 | | NS_IMETHODIMP |
2574 | | HttpBaseChannel::GetChannelIsForDownload(bool *aChannelIsForDownload) |
2575 | 0 | { |
2576 | 0 | *aChannelIsForDownload = mChannelIsForDownload; |
2577 | 0 | return NS_OK; |
2578 | 0 | } |
2579 | | |
2580 | | NS_IMETHODIMP |
2581 | | HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload) |
2582 | 0 | { |
2583 | 0 | mChannelIsForDownload = aChannelIsForDownload; |
2584 | 0 | return NS_OK; |
2585 | 0 | } |
2586 | | |
2587 | | NS_IMETHODIMP |
2588 | | HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys) |
2589 | 0 | { |
2590 | 0 | mRedirectedCachekeys = cacheKeys; |
2591 | 0 | return NS_OK; |
2592 | 0 | } |
2593 | | |
2594 | | NS_IMETHODIMP |
2595 | | HttpBaseChannel::GetLocalAddress(nsACString& addr) |
2596 | 0 | { |
2597 | 0 | if (mSelfAddr.raw.family == PR_AF_UNSPEC) |
2598 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2599 | 0 | |
2600 | 0 | addr.SetLength(kIPv6CStrBufSize); |
2601 | 0 | NetAddrToString(&mSelfAddr, addr.BeginWriting(), kIPv6CStrBufSize); |
2602 | 0 | addr.SetLength(strlen(addr.BeginReading())); |
2603 | 0 |
|
2604 | 0 | return NS_OK; |
2605 | 0 | } |
2606 | | |
2607 | | NS_IMETHODIMP |
2608 | | HttpBaseChannel::TakeAllSecurityMessages( |
2609 | | nsCOMArray<nsISecurityConsoleMessage> &aMessages) |
2610 | 0 | { |
2611 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2612 | 0 |
|
2613 | 0 | aMessages.Clear(); |
2614 | 0 | for (auto pair : mSecurityConsoleMessages) { |
2615 | 0 | nsresult rv; |
2616 | 0 | nsCOMPtr<nsISecurityConsoleMessage> message = |
2617 | 0 | do_CreateInstance(NS_SECURITY_CONSOLE_MESSAGE_CONTRACTID, &rv); |
2618 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2619 | 0 |
|
2620 | 0 | message->SetTag(pair.first()); |
2621 | 0 | message->SetCategory(pair.second()); |
2622 | 0 | aMessages.AppendElement(message); |
2623 | 0 | } |
2624 | 0 |
|
2625 | 0 | MOZ_ASSERT(mSecurityConsoleMessages.Length() == aMessages.Length()); |
2626 | 0 | mSecurityConsoleMessages.Clear(); |
2627 | 0 |
|
2628 | 0 | return NS_OK; |
2629 | 0 | } |
2630 | | |
2631 | | /* Please use this method with care. This can cause the message |
2632 | | * queue to grow large and cause the channel to take up a lot |
2633 | | * of memory. Use only static string messages and do not add |
2634 | | * server side data to the queue, as that can be large. |
2635 | | * Add only a limited number of messages to the queue to keep |
2636 | | * the channel size down and do so only in rare erroneous situations. |
2637 | | * More information can be found here: |
2638 | | * https://bugzilla.mozilla.org/show_bug.cgi?id=846918 |
2639 | | */ |
2640 | | nsresult |
2641 | | HttpBaseChannel::AddSecurityMessage(const nsAString &aMessageTag, |
2642 | | const nsAString &aMessageCategory) |
2643 | 0 | { |
2644 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2645 | 0 |
|
2646 | 0 | nsresult rv; |
2647 | 0 |
|
2648 | 0 | // nsSecurityConsoleMessage is not thread-safe refcounted. |
2649 | 0 | // Delay the object construction until requested. |
2650 | 0 | // See TakeAllSecurityMessages() |
2651 | 0 | Pair<nsString, nsString> pair(aMessageTag, aMessageCategory); |
2652 | 0 | mSecurityConsoleMessages.AppendElement(std::move(pair)); |
2653 | 0 |
|
2654 | 0 | nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); |
2655 | 0 | if (!console) { |
2656 | 0 | return NS_ERROR_FAILURE; |
2657 | 0 | } |
2658 | 0 | |
2659 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
2660 | 0 | GetLoadInfo(getter_AddRefs(loadInfo)); |
2661 | 0 | if (!loadInfo) { |
2662 | 0 | return NS_ERROR_FAILURE; |
2663 | 0 | } |
2664 | 0 | |
2665 | 0 | auto innerWindowID = loadInfo->GetInnerWindowID(); |
2666 | 0 |
|
2667 | 0 | nsAutoString errorText; |
2668 | 0 | rv = nsContentUtils::GetLocalizedString( |
2669 | 0 | nsContentUtils::eSECURITY_PROPERTIES, |
2670 | 0 | NS_ConvertUTF16toUTF8(aMessageTag).get(), |
2671 | 0 | errorText); |
2672 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2673 | 0 |
|
2674 | 0 | nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); |
2675 | 0 | error->InitWithSourceURI(errorText, mURI, |
2676 | 0 | EmptyString(), 0, 0, |
2677 | 0 | nsIScriptError::warningFlag, |
2678 | 0 | NS_ConvertUTF16toUTF8(aMessageCategory), |
2679 | 0 | innerWindowID); |
2680 | 0 |
|
2681 | 0 | console->LogMessage(error); |
2682 | 0 |
|
2683 | 0 | return NS_OK; |
2684 | 0 | } |
2685 | | |
2686 | | NS_IMETHODIMP |
2687 | | HttpBaseChannel::GetLocalPort(int32_t* port) |
2688 | 0 | { |
2689 | 0 | NS_ENSURE_ARG_POINTER(port); |
2690 | 0 |
|
2691 | 0 | if (mSelfAddr.raw.family == PR_AF_INET) { |
2692 | 0 | *port = (int32_t)ntohs(mSelfAddr.inet.port); |
2693 | 0 | } |
2694 | 0 | else if (mSelfAddr.raw.family == PR_AF_INET6) { |
2695 | 0 | *port = (int32_t)ntohs(mSelfAddr.inet6.port); |
2696 | 0 | } |
2697 | 0 | else |
2698 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2699 | 0 | |
2700 | 0 | return NS_OK; |
2701 | 0 | } |
2702 | | |
2703 | | NS_IMETHODIMP |
2704 | | HttpBaseChannel::GetRemoteAddress(nsACString& addr) |
2705 | 0 | { |
2706 | 0 | if (mPeerAddr.raw.family == PR_AF_UNSPEC) |
2707 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2708 | 0 | |
2709 | 0 | addr.SetLength(kIPv6CStrBufSize); |
2710 | 0 | NetAddrToString(&mPeerAddr, addr.BeginWriting(), kIPv6CStrBufSize); |
2711 | 0 | addr.SetLength(strlen(addr.BeginReading())); |
2712 | 0 |
|
2713 | 0 | return NS_OK; |
2714 | 0 | } |
2715 | | |
2716 | | NS_IMETHODIMP |
2717 | | HttpBaseChannel::GetRemotePort(int32_t* port) |
2718 | 0 | { |
2719 | 0 | NS_ENSURE_ARG_POINTER(port); |
2720 | 0 |
|
2721 | 0 | if (mPeerAddr.raw.family == PR_AF_INET) { |
2722 | 0 | *port = (int32_t)ntohs(mPeerAddr.inet.port); |
2723 | 0 | } |
2724 | 0 | else if (mPeerAddr.raw.family == PR_AF_INET6) { |
2725 | 0 | *port = (int32_t)ntohs(mPeerAddr.inet6.port); |
2726 | 0 | } |
2727 | 0 | else |
2728 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2729 | 0 | |
2730 | 0 | return NS_OK; |
2731 | 0 | } |
2732 | | |
2733 | | NS_IMETHODIMP |
2734 | | HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName, |
2735 | | nsIHttpUpgradeListener *aListener) |
2736 | 0 | { |
2737 | 0 | NS_ENSURE_ARG(!aProtocolName.IsEmpty()); |
2738 | 0 | NS_ENSURE_ARG_POINTER(aListener); |
2739 | 0 |
|
2740 | 0 | mUpgradeProtocol = aProtocolName; |
2741 | 0 | mUpgradeProtocolCallback = aListener; |
2742 | 0 | return NS_OK; |
2743 | 0 | } |
2744 | | |
2745 | | NS_IMETHODIMP |
2746 | | HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy) |
2747 | 0 | { |
2748 | 0 | NS_ENSURE_ARG_POINTER(aAllowSpdy); |
2749 | 0 |
|
2750 | 0 | *aAllowSpdy = mAllowSpdy; |
2751 | 0 | return NS_OK; |
2752 | 0 | } |
2753 | | |
2754 | | NS_IMETHODIMP |
2755 | | HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy) |
2756 | 0 | { |
2757 | 0 | mAllowSpdy = aAllowSpdy; |
2758 | 0 | return NS_OK; |
2759 | 0 | } |
2760 | | |
2761 | | NS_IMETHODIMP |
2762 | | HttpBaseChannel::GetAllowAltSvc(bool *aAllowAltSvc) |
2763 | 0 | { |
2764 | 0 | NS_ENSURE_ARG_POINTER(aAllowAltSvc); |
2765 | 0 |
|
2766 | 0 | *aAllowAltSvc = mAllowAltSvc; |
2767 | 0 | return NS_OK; |
2768 | 0 | } |
2769 | | |
2770 | | NS_IMETHODIMP |
2771 | | HttpBaseChannel::SetAllowAltSvc(bool aAllowAltSvc) |
2772 | 0 | { |
2773 | 0 | mAllowAltSvc = aAllowAltSvc; |
2774 | 0 | return NS_OK; |
2775 | 0 | } |
2776 | | |
2777 | | NS_IMETHODIMP |
2778 | | HttpBaseChannel::GetBeConservative(bool *aBeConservative) |
2779 | 0 | { |
2780 | 0 | NS_ENSURE_ARG_POINTER(aBeConservative); |
2781 | 0 |
|
2782 | 0 | *aBeConservative = mBeConservative; |
2783 | 0 | return NS_OK; |
2784 | 0 | } |
2785 | | |
2786 | | NS_IMETHODIMP |
2787 | | HttpBaseChannel::SetBeConservative(bool aBeConservative) |
2788 | 0 | { |
2789 | 0 | mBeConservative = aBeConservative; |
2790 | 0 | return NS_OK; |
2791 | 0 | } |
2792 | | |
2793 | | NS_IMETHODIMP |
2794 | | HttpBaseChannel::GetTrr(bool *aTRR) |
2795 | 0 | { |
2796 | 0 | NS_ENSURE_ARG_POINTER(aTRR); |
2797 | 0 |
|
2798 | 0 | *aTRR = mTRR; |
2799 | 0 | return NS_OK; |
2800 | 0 | } |
2801 | | |
2802 | | NS_IMETHODIMP |
2803 | | HttpBaseChannel::SetTrr(bool aTRR) |
2804 | 0 | { |
2805 | 0 | mTRR = aTRR; |
2806 | 0 | return NS_OK; |
2807 | 0 | } |
2808 | | |
2809 | | NS_IMETHODIMP |
2810 | | HttpBaseChannel::GetTlsFlags(uint32_t *aTlsFlags) |
2811 | 0 | { |
2812 | 0 | NS_ENSURE_ARG_POINTER(aTlsFlags); |
2813 | 0 |
|
2814 | 0 | *aTlsFlags = mTlsFlags; |
2815 | 0 | return NS_OK; |
2816 | 0 | } |
2817 | | |
2818 | | NS_IMETHODIMP |
2819 | | HttpBaseChannel::SetTlsFlags(uint32_t aTlsFlags) |
2820 | 0 | { |
2821 | 0 | mTlsFlags = aTlsFlags; |
2822 | 0 | return NS_OK; |
2823 | 0 | } |
2824 | | |
2825 | | NS_IMETHODIMP |
2826 | | HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult) |
2827 | 0 | { |
2828 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
2829 | 0 | NS_IF_ADDREF(*aResult = mAPIRedirectToURI); |
2830 | 0 | return NS_OK; |
2831 | 0 | } |
2832 | | |
2833 | | NS_IMETHODIMP |
2834 | | HttpBaseChannel::GetResponseTimeoutEnabled(bool *aEnable) |
2835 | 0 | { |
2836 | 0 | if (NS_WARN_IF(!aEnable)) { |
2837 | 0 | return NS_ERROR_NULL_POINTER; |
2838 | 0 | } |
2839 | 0 | *aEnable = mResponseTimeoutEnabled; |
2840 | 0 | return NS_OK; |
2841 | 0 | } |
2842 | | |
2843 | | NS_IMETHODIMP |
2844 | | HttpBaseChannel::SetResponseTimeoutEnabled(bool aEnable) |
2845 | 0 | { |
2846 | 0 | mResponseTimeoutEnabled = aEnable; |
2847 | 0 | return NS_OK; |
2848 | 0 | } |
2849 | | |
2850 | | NS_IMETHODIMP |
2851 | | HttpBaseChannel::GetInitialRwin(uint32_t *aRwin) |
2852 | 0 | { |
2853 | 0 | if (NS_WARN_IF(!aRwin)) { |
2854 | 0 | return NS_ERROR_NULL_POINTER; |
2855 | 0 | } |
2856 | 0 | *aRwin = mInitialRwin; |
2857 | 0 | return NS_OK; |
2858 | 0 | } |
2859 | | |
2860 | | NS_IMETHODIMP |
2861 | | HttpBaseChannel::SetInitialRwin(uint32_t aRwin) |
2862 | 0 | { |
2863 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
2864 | 0 | mInitialRwin = aRwin; |
2865 | 0 | return NS_OK; |
2866 | 0 | } |
2867 | | |
2868 | | NS_IMETHODIMP |
2869 | | HttpBaseChannel::ForcePending(bool aForcePending) |
2870 | 0 | { |
2871 | 0 | mForcePending = aForcePending; |
2872 | 0 | return NS_OK; |
2873 | 0 | } |
2874 | | |
2875 | | NS_IMETHODIMP |
2876 | | HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime) |
2877 | 0 | { |
2878 | 0 | if (!mResponseHead) |
2879 | 0 | return NS_ERROR_NOT_AVAILABLE; |
2880 | 0 | uint32_t lastMod; |
2881 | 0 | nsresult rv = mResponseHead->GetLastModifiedValue(&lastMod); |
2882 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2883 | 0 | *lastModifiedTime = lastMod; |
2884 | 0 | return NS_OK; |
2885 | 0 | } |
2886 | | |
2887 | | NS_IMETHODIMP |
2888 | | HttpBaseChannel::GetCorsIncludeCredentials(bool* aInclude) |
2889 | 0 | { |
2890 | 0 | *aInclude = mCorsIncludeCredentials; |
2891 | 0 | return NS_OK; |
2892 | 0 | } |
2893 | | |
2894 | | NS_IMETHODIMP |
2895 | | HttpBaseChannel::SetCorsIncludeCredentials(bool aInclude) |
2896 | 0 | { |
2897 | 0 | mCorsIncludeCredentials = aInclude; |
2898 | 0 | return NS_OK; |
2899 | 0 | } |
2900 | | |
2901 | | NS_IMETHODIMP |
2902 | | HttpBaseChannel::GetCorsMode(uint32_t* aMode) |
2903 | 0 | { |
2904 | 0 | *aMode = mCorsMode; |
2905 | 0 | return NS_OK; |
2906 | 0 | } |
2907 | | |
2908 | | NS_IMETHODIMP |
2909 | | HttpBaseChannel::SetCorsMode(uint32_t aMode) |
2910 | 0 | { |
2911 | 0 | mCorsMode = aMode; |
2912 | 0 | return NS_OK; |
2913 | 0 | } |
2914 | | |
2915 | | NS_IMETHODIMP |
2916 | | HttpBaseChannel::GetRedirectMode(uint32_t* aMode) |
2917 | 0 | { |
2918 | 0 | *aMode = mRedirectMode; |
2919 | 0 | return NS_OK; |
2920 | 0 | } |
2921 | | |
2922 | | NS_IMETHODIMP |
2923 | | HttpBaseChannel::SetRedirectMode(uint32_t aMode) |
2924 | 0 | { |
2925 | 0 | mRedirectMode = aMode; |
2926 | 0 | return NS_OK; |
2927 | 0 | } |
2928 | | |
2929 | | namespace { |
2930 | | |
2931 | | bool |
2932 | | ContainsAllFlags(uint32_t aLoadFlags, uint32_t aMask) |
2933 | 0 | { |
2934 | 0 | return (aLoadFlags & aMask) == aMask; |
2935 | 0 | } |
2936 | | |
2937 | | } // anonymous namespace |
2938 | | |
2939 | | NS_IMETHODIMP |
2940 | | HttpBaseChannel::GetFetchCacheMode(uint32_t* aFetchCacheMode) |
2941 | 0 | { |
2942 | 0 | NS_ENSURE_ARG_POINTER(aFetchCacheMode); |
2943 | 0 |
|
2944 | 0 | // Otherwise try to guess an appropriate cache mode from the load flags. |
2945 | 0 | if (ContainsAllFlags(mLoadFlags, INHIBIT_CACHING | LOAD_BYPASS_CACHE)) { |
2946 | 0 | *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE; |
2947 | 0 | } else if (ContainsAllFlags(mLoadFlags, LOAD_BYPASS_CACHE)) { |
2948 | 0 | *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD; |
2949 | 0 | } else if (ContainsAllFlags(mLoadFlags, VALIDATE_ALWAYS)) { |
2950 | 0 | *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE; |
2951 | 0 | } else if (ContainsAllFlags(mLoadFlags, VALIDATE_NEVER | |
2952 | 0 | nsICachingChannel::LOAD_ONLY_FROM_CACHE)) { |
2953 | 0 | *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED; |
2954 | 0 | } else if (ContainsAllFlags(mLoadFlags, VALIDATE_NEVER)) { |
2955 | 0 | *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE; |
2956 | 0 | } else { |
2957 | 0 | *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT; |
2958 | 0 | } |
2959 | 0 |
|
2960 | 0 | return NS_OK; |
2961 | 0 | } |
2962 | | |
2963 | | namespace { |
2964 | | |
2965 | | void |
2966 | | SetCacheFlags(uint32_t& aLoadFlags, uint32_t aFlags) |
2967 | 0 | { |
2968 | 0 | // First, clear any possible cache related flags. |
2969 | 0 | uint32_t allPossibleFlags = nsIRequest::INHIBIT_CACHING |
2970 | 0 | | nsIRequest::LOAD_BYPASS_CACHE |
2971 | 0 | | nsIRequest::VALIDATE_ALWAYS |
2972 | 0 | | nsIRequest::LOAD_FROM_CACHE |
2973 | 0 | | nsICachingChannel::LOAD_ONLY_FROM_CACHE; |
2974 | 0 | aLoadFlags &= ~allPossibleFlags; |
2975 | 0 |
|
2976 | 0 | // Then set the new flags. |
2977 | 0 | aLoadFlags |= aFlags; |
2978 | 0 | } |
2979 | | |
2980 | | } // anonymous namespace |
2981 | | |
2982 | | NS_IMETHODIMP |
2983 | | HttpBaseChannel::SetFetchCacheMode(uint32_t aFetchCacheMode) |
2984 | 0 | { |
2985 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
2986 | 0 |
|
2987 | 0 | // Now, set the load flags that implement each cache mode. |
2988 | 0 | switch (aFetchCacheMode) { |
2989 | 0 | case nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT: |
2990 | 0 | // The "default" mode means to use the http cache normally and |
2991 | 0 | // respect any http cache-control headers. We effectively want |
2992 | 0 | // to clear our cache related load flags. |
2993 | 0 | SetCacheFlags(mLoadFlags, 0); |
2994 | 0 | break; |
2995 | 0 | case nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE: |
2996 | 0 | // no-store means don't consult the cache on the way to the network, and |
2997 | 0 | // don't store the response in the cache even if it's cacheable. |
2998 | 0 | SetCacheFlags(mLoadFlags, INHIBIT_CACHING | LOAD_BYPASS_CACHE); |
2999 | 0 | break; |
3000 | 0 | case nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD: |
3001 | 0 | // reload means don't consult the cache on the way to the network, but |
3002 | 0 | // do store the response in the cache if possible. |
3003 | 0 | SetCacheFlags(mLoadFlags, LOAD_BYPASS_CACHE); |
3004 | 0 | break; |
3005 | 0 | case nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE: |
3006 | 0 | // no-cache means always validate what's in the cache. |
3007 | 0 | SetCacheFlags(mLoadFlags, VALIDATE_ALWAYS); |
3008 | 0 | break; |
3009 | 0 | case nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE: |
3010 | 0 | // force-cache means don't validate unless if the response would vary. |
3011 | 0 | SetCacheFlags(mLoadFlags, VALIDATE_NEVER); |
3012 | 0 | break; |
3013 | 0 | case nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED: |
3014 | 0 | // only-if-cached means only from cache, no network, no validation, generate |
3015 | 0 | // a network error if the document was't in the cache. |
3016 | 0 | // The privacy implications of these flags (making it fast/easy to check if |
3017 | 0 | // the user has things in their cache without any network traffic side |
3018 | 0 | // effects) are addressed in the Request constructor which enforces/requires |
3019 | 0 | // same-origin request mode. |
3020 | 0 | SetCacheFlags(mLoadFlags, VALIDATE_NEVER | |
3021 | 0 | nsICachingChannel::LOAD_ONLY_FROM_CACHE); |
3022 | 0 | break; |
3023 | 0 | } |
3024 | 0 | |
3025 | 0 | #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED |
3026 | 0 | uint32_t finalMode = 0; |
3027 | 0 | MOZ_ALWAYS_SUCCEEDS(GetFetchCacheMode(&finalMode)); |
3028 | 0 | MOZ_DIAGNOSTIC_ASSERT(finalMode == aFetchCacheMode); |
3029 | 0 | #endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED |
3030 | 0 |
|
3031 | 0 | return NS_OK; |
3032 | 0 | } |
3033 | | |
3034 | | NS_IMETHODIMP |
3035 | | HttpBaseChannel::SetIntegrityMetadata(const nsAString& aIntegrityMetadata) |
3036 | 0 | { |
3037 | 0 | mIntegrityMetadata = aIntegrityMetadata; |
3038 | 0 | return NS_OK; |
3039 | 0 | } |
3040 | | |
3041 | | NS_IMETHODIMP |
3042 | | HttpBaseChannel::GetIntegrityMetadata(nsAString& aIntegrityMetadata) |
3043 | 0 | { |
3044 | 0 | aIntegrityMetadata = mIntegrityMetadata; |
3045 | 0 | return NS_OK; |
3046 | 0 | } |
3047 | | |
3048 | | //----------------------------------------------------------------------------- |
3049 | | // HttpBaseChannel::nsISupportsPriority |
3050 | | //----------------------------------------------------------------------------- |
3051 | | |
3052 | | NS_IMETHODIMP |
3053 | | HttpBaseChannel::GetPriority(int32_t *value) |
3054 | 0 | { |
3055 | 0 | *value = mPriority; |
3056 | 0 | return NS_OK; |
3057 | 0 | } |
3058 | | |
3059 | | NS_IMETHODIMP |
3060 | | HttpBaseChannel::AdjustPriority(int32_t delta) |
3061 | 0 | { |
3062 | 0 | return SetPriority(mPriority + delta); |
3063 | 0 | } |
3064 | | |
3065 | | //----------------------------------------------------------------------------- |
3066 | | // HttpBaseChannel::nsIResumableChannel |
3067 | | //----------------------------------------------------------------------------- |
3068 | | |
3069 | | NS_IMETHODIMP |
3070 | | HttpBaseChannel::GetEntityID(nsACString& aEntityID) |
3071 | 0 | { |
3072 | 0 | // Don't return an entity ID for Non-GET requests which require |
3073 | 0 | // additional data |
3074 | 0 | if (!mRequestHead.IsGet()) { |
3075 | 0 | return NS_ERROR_NOT_RESUMABLE; |
3076 | 0 | } |
3077 | 0 | |
3078 | 0 | uint64_t size = UINT64_MAX; |
3079 | 0 | nsAutoCString etag, lastmod; |
3080 | 0 | if (mResponseHead) { |
3081 | 0 | // Don't return an entity if the server sent the following header: |
3082 | 0 | // Accept-Ranges: none |
3083 | 0 | // Not sending the Accept-Ranges header means we can still try |
3084 | 0 | // sending range requests. |
3085 | 0 | nsAutoCString acceptRanges; |
3086 | 0 | Unused << mResponseHead->GetHeader(nsHttp::Accept_Ranges, acceptRanges); |
3087 | 0 | if (!acceptRanges.IsEmpty() && |
3088 | 0 | !nsHttp::FindToken(acceptRanges.get(), "bytes", HTTP_HEADER_VALUE_SEPS)) { |
3089 | 0 | return NS_ERROR_NOT_RESUMABLE; |
3090 | 0 | } |
3091 | 0 | |
3092 | 0 | size = mResponseHead->TotalEntitySize(); |
3093 | 0 | Unused << mResponseHead->GetHeader(nsHttp::Last_Modified, lastmod); |
3094 | 0 | Unused << mResponseHead->GetHeader(nsHttp::ETag, etag); |
3095 | 0 | } |
3096 | 0 | nsCString entityID; |
3097 | 0 | NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy | |
3098 | 0 | esc_FileBaseName | esc_Forced, entityID); |
3099 | 0 | entityID.Append('/'); |
3100 | 0 | entityID.AppendInt(int64_t(size)); |
3101 | 0 | entityID.Append('/'); |
3102 | 0 | entityID.Append(lastmod); |
3103 | 0 | // NOTE: Appending lastmod as the last part avoids having to escape it |
3104 | 0 |
|
3105 | 0 | aEntityID = entityID; |
3106 | 0 |
|
3107 | 0 | return NS_OK; |
3108 | 0 | } |
3109 | | |
3110 | | //----------------------------------------------------------------------------- |
3111 | | // HttpBaseChannel::nsIConsoleReportCollector |
3112 | | //----------------------------------------------------------------------------- |
3113 | | |
3114 | | void |
3115 | | HttpBaseChannel::AddConsoleReport(uint32_t aErrorFlags, |
3116 | | const nsACString& aCategory, |
3117 | | nsContentUtils::PropertiesFile aPropertiesFile, |
3118 | | const nsACString& aSourceFileURI, |
3119 | | uint32_t aLineNumber, uint32_t aColumnNumber, |
3120 | | const nsACString& aMessageName, |
3121 | | const nsTArray<nsString>& aStringParams) |
3122 | 0 | { |
3123 | 0 | mReportCollector->AddConsoleReport(aErrorFlags, aCategory, aPropertiesFile, |
3124 | 0 | aSourceFileURI, aLineNumber, |
3125 | 0 | aColumnNumber, aMessageName, |
3126 | 0 | aStringParams); |
3127 | 0 | } |
3128 | | |
3129 | | void |
3130 | | HttpBaseChannel::FlushReportsToConsole(uint64_t aInnerWindowID, |
3131 | | ReportAction aAction) |
3132 | 0 | { |
3133 | 0 | mReportCollector->FlushReportsToConsole(aInnerWindowID, aAction); |
3134 | 0 | } |
3135 | | |
3136 | | void |
3137 | | HttpBaseChannel::FlushReportsToConsoleForServiceWorkerScope(const nsACString& aScope, |
3138 | | ReportAction aAction) |
3139 | 0 | { |
3140 | 0 | mReportCollector->FlushReportsToConsoleForServiceWorkerScope(aScope, aAction); |
3141 | 0 | } |
3142 | | |
3143 | | void |
3144 | | HttpBaseChannel::FlushConsoleReports(nsIDocument* aDocument, |
3145 | | ReportAction aAction) |
3146 | 0 | { |
3147 | 0 | mReportCollector->FlushConsoleReports(aDocument, aAction); |
3148 | 0 | } |
3149 | | |
3150 | | void |
3151 | | HttpBaseChannel::FlushConsoleReports(nsILoadGroup* aLoadGroup, |
3152 | | ReportAction aAction) |
3153 | 0 | { |
3154 | 0 | mReportCollector->FlushConsoleReports(aLoadGroup, aAction); |
3155 | 0 | } |
3156 | | |
3157 | | void |
3158 | | HttpBaseChannel::FlushConsoleReports(nsIConsoleReportCollector* aCollector) |
3159 | 0 | { |
3160 | 0 | mReportCollector->FlushConsoleReports(aCollector); |
3161 | 0 | } |
3162 | | |
3163 | | void |
3164 | | HttpBaseChannel::ClearConsoleReports() |
3165 | 0 | { |
3166 | 0 | mReportCollector->ClearConsoleReports(); |
3167 | 0 | } |
3168 | | |
3169 | | nsIPrincipal * |
3170 | | HttpBaseChannel::GetURIPrincipal() |
3171 | 0 | { |
3172 | 0 | if (mPrincipal) { |
3173 | 0 | return mPrincipal; |
3174 | 0 | } |
3175 | 0 | |
3176 | 0 | nsIScriptSecurityManager *securityManager = |
3177 | 0 | nsContentUtils::GetSecurityManager(); |
3178 | 0 |
|
3179 | 0 | if (!securityManager) { |
3180 | 0 | LOG(("HttpBaseChannel::GetURIPrincipal: No security manager [this=%p]", |
3181 | 0 | this)); |
3182 | 0 | return nullptr; |
3183 | 0 | } |
3184 | 0 |
|
3185 | 0 | securityManager->GetChannelURIPrincipal(this, getter_AddRefs(mPrincipal)); |
3186 | 0 | if (!mPrincipal) { |
3187 | 0 | LOG(("HttpBaseChannel::GetURIPrincipal: No channel principal [this=%p]", |
3188 | 0 | this)); |
3189 | 0 | return nullptr; |
3190 | 0 | } |
3191 | 0 |
|
3192 | 0 | return mPrincipal; |
3193 | 0 | } |
3194 | | |
3195 | | bool |
3196 | | HttpBaseChannel::IsNavigation() |
3197 | 0 | { |
3198 | 0 | return mForceMainDocumentChannel || (mLoadFlags & LOAD_DOCUMENT_URI); |
3199 | 0 | } |
3200 | | |
3201 | | bool |
3202 | | HttpBaseChannel::BypassServiceWorker() const |
3203 | 0 | { |
3204 | 0 | return mLoadFlags & LOAD_BYPASS_SERVICE_WORKER; |
3205 | 0 | } |
3206 | | |
3207 | | bool |
3208 | | HttpBaseChannel::ShouldIntercept(nsIURI* aURI) |
3209 | 0 | { |
3210 | 0 | nsCOMPtr<nsINetworkInterceptController> controller; |
3211 | 0 | GetCallback(controller); |
3212 | 0 | bool shouldIntercept = false; |
3213 | 0 |
|
3214 | 0 | // We should never intercept internal redirects. The ServiceWorker code |
3215 | 0 | // can trigger interntal redirects as the result of a FetchEvent. If |
3216 | 0 | // we re-intercept then an infinite loop can occur. |
3217 | 0 | // |
3218 | 0 | // Its also important that we do not set the LOAD_BYPASS_SERVICE_WORKER |
3219 | 0 | // flag because an internal redirect occurs. Its possible that another |
3220 | 0 | // interception should occur after the internal redirect. For example, |
3221 | 0 | // if the ServiceWorker chooses not to call respondWith() the channel |
3222 | 0 | // will be reset with an internal redirect. If the request is a navigation |
3223 | 0 | // and the network then triggers a redirect its possible the new URL |
3224 | 0 | // should be intercepted again. |
3225 | 0 | // |
3226 | 0 | // Note, HSTS upgrade redirects are often treated the same as internal |
3227 | 0 | // redirects. In this case, however, we intentionally allow interception |
3228 | 0 | // of HSTS upgrade redirects. This matches the expected spec behavior and |
3229 | 0 | // does not run the risk of infinite loops as described above. |
3230 | 0 | bool internalRedirect = mLastRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL; |
3231 | 0 |
|
3232 | 0 | if (controller && mLoadInfo && !BypassServiceWorker() && !internalRedirect) { |
3233 | 0 | nsresult rv = controller->ShouldPrepareForIntercept(aURI ? aURI : mURI.get(), |
3234 | 0 | this, |
3235 | 0 | &shouldIntercept); |
3236 | 0 | if (NS_FAILED(rv)) { |
3237 | 0 | return false; |
3238 | 0 | } |
3239 | 0 | } |
3240 | 0 | return shouldIntercept; |
3241 | 0 | } |
3242 | | |
3243 | | void |
3244 | | HttpBaseChannel::AddAsNonTailRequest() |
3245 | 0 | { |
3246 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3247 | 0 |
|
3248 | 0 | if (EnsureRequestContext()) { |
3249 | 0 | LOG(("HttpBaseChannel::AddAsNonTailRequest this=%p, rc=%p, already added=%d", |
3250 | 0 | this, mRequestContext.get(), (bool)mAddedAsNonTailRequest)); |
3251 | 0 |
|
3252 | 0 | if (!mAddedAsNonTailRequest) { |
3253 | 0 | mRequestContext->AddNonTailRequest(); |
3254 | 0 | mAddedAsNonTailRequest = true; |
3255 | 0 | } |
3256 | 0 | } |
3257 | 0 | } |
3258 | | |
3259 | | void |
3260 | | HttpBaseChannel::RemoveAsNonTailRequest() |
3261 | 0 | { |
3262 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3263 | 0 |
|
3264 | 0 | if (mRequestContext) { |
3265 | 0 | LOG(("HttpBaseChannel::RemoveAsNonTailRequest this=%p, rc=%p, already added=%d", |
3266 | 0 | this, mRequestContext.get(), (bool)mAddedAsNonTailRequest)); |
3267 | 0 |
|
3268 | 0 | if (mAddedAsNonTailRequest) { |
3269 | 0 | mRequestContext->RemoveNonTailRequest(); |
3270 | 0 | mAddedAsNonTailRequest = false; |
3271 | 0 | } |
3272 | 0 | } |
3273 | 0 | } |
3274 | | |
3275 | | #ifdef DEBUG |
3276 | | void HttpBaseChannel::AssertPrivateBrowsingId() |
3277 | | { |
3278 | | nsCOMPtr<nsILoadContext> loadContext; |
3279 | | NS_QueryNotificationCallbacks(this, loadContext); |
3280 | | // For addons it's possible that mLoadInfo is null. |
3281 | | if (!mLoadInfo) { |
3282 | | return; |
3283 | | } |
3284 | | |
3285 | | if (!loadContext) { |
3286 | | return; |
3287 | | } |
3288 | | |
3289 | | // We skip testing of favicon loading here since it could be triggered by XUL image |
3290 | | // which uses SystemPrincipal. The SystemPrincpal doesn't have mPrivateBrowsingId. |
3291 | | if (nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal()) && |
3292 | | mLoadInfo->InternalContentPolicyType() == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) { |
3293 | | return; |
3294 | | } |
3295 | | |
3296 | | OriginAttributes docShellAttrs; |
3297 | | loadContext->GetOriginAttributes(docShellAttrs); |
3298 | | MOZ_ASSERT(mLoadInfo->GetOriginAttributes().mPrivateBrowsingId == docShellAttrs.mPrivateBrowsingId, |
3299 | | "PrivateBrowsingId values are not the same between LoadInfo and LoadContext."); |
3300 | | } |
3301 | | #endif |
3302 | | |
3303 | | already_AddRefed<nsILoadInfo> |
3304 | | HttpBaseChannel::CloneLoadInfoForRedirect(nsIURI * newURI, uint32_t redirectFlags) |
3305 | 0 | { |
3306 | 0 | // make a copy of the loadinfo, append to the redirectchain |
3307 | 0 | // this will be set on the newly created channel for the redirect target. |
3308 | 0 | if (!mLoadInfo) { |
3309 | 0 | return nullptr; |
3310 | 0 | } |
3311 | 0 | |
3312 | 0 | nsCOMPtr<nsILoadInfo> newLoadInfo = |
3313 | 0 | static_cast<mozilla::net::LoadInfo*>(mLoadInfo.get())->Clone(); |
3314 | 0 |
|
3315 | 0 | nsContentPolicyType contentPolicyType = mLoadInfo->GetExternalContentPolicyType(); |
3316 | 0 | if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT || |
3317 | 0 | contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) { |
3318 | 0 | nsCOMPtr<nsIPrincipal> nullPrincipalToInherit = NullPrincipal::CreateWithoutOriginAttributes(); |
3319 | 0 | newLoadInfo->SetPrincipalToInherit(nullPrincipalToInherit); |
3320 | 0 | } |
3321 | 0 |
|
3322 | 0 | // re-compute the origin attributes of the loadInfo if it's top-level load. |
3323 | 0 | bool isTopLevelDoc = |
3324 | 0 | newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT; |
3325 | 0 |
|
3326 | 0 | if (isTopLevelDoc) { |
3327 | 0 | nsCOMPtr<nsILoadContext> loadContext; |
3328 | 0 | NS_QueryNotificationCallbacks(this, loadContext); |
3329 | 0 | OriginAttributes docShellAttrs; |
3330 | 0 | if (loadContext) { |
3331 | 0 | loadContext->GetOriginAttributes(docShellAttrs); |
3332 | 0 | } |
3333 | 0 |
|
3334 | 0 | OriginAttributes attrs = newLoadInfo->GetOriginAttributes(); |
3335 | 0 |
|
3336 | 0 | MOZ_ASSERT(docShellAttrs.mUserContextId == attrs.mUserContextId, |
3337 | 0 | "docshell and necko should have the same userContextId attribute."); |
3338 | 0 | MOZ_ASSERT(docShellAttrs.mInIsolatedMozBrowser == attrs.mInIsolatedMozBrowser, |
3339 | 0 | "docshell and necko should have the same inIsolatedMozBrowser attribute."); |
3340 | 0 | MOZ_ASSERT(docShellAttrs.mPrivateBrowsingId == attrs.mPrivateBrowsingId, |
3341 | 0 | "docshell and necko should have the same privateBrowsingId attribute."); |
3342 | 0 |
|
3343 | 0 | attrs = docShellAttrs; |
3344 | 0 | attrs.SetFirstPartyDomain(true, newURI); |
3345 | 0 | newLoadInfo->SetOriginAttributes(attrs); |
3346 | 0 | } |
3347 | 0 |
|
3348 | 0 | // Leave empty, we want a 'clean ground' when creating the new channel. |
3349 | 0 | // This will be ensured to be either set by the protocol handler or set |
3350 | 0 | // to the redirect target URI properly after the channel creation. |
3351 | 0 | newLoadInfo->SetResultPrincipalURI(nullptr); |
3352 | 0 |
|
3353 | 0 | bool isInternalRedirect = |
3354 | 0 | (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL | |
3355 | 0 | nsIChannelEventSink::REDIRECT_STS_UPGRADE)); |
3356 | 0 |
|
3357 | 0 | nsCString remoteAddress; |
3358 | 0 | Unused << GetRemoteAddress(remoteAddress); |
3359 | 0 | nsCOMPtr<nsIRedirectHistoryEntry> entry = |
3360 | 0 | new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress); |
3361 | 0 |
|
3362 | 0 | newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect); |
3363 | 0 |
|
3364 | 0 | return newLoadInfo.forget(); |
3365 | 0 | } |
3366 | | |
3367 | | //----------------------------------------------------------------------------- |
3368 | | // nsHttpChannel::nsITraceableChannel |
3369 | | //----------------------------------------------------------------------------- |
3370 | | |
3371 | | NS_IMETHODIMP |
3372 | | HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval) |
3373 | 0 | { |
3374 | 0 | LOG(("HttpBaseChannel::SetNewListener [this=%p, mListener=%p, newListener=%p]", |
3375 | 0 | this, mListener.get(), aListener)); |
3376 | 0 |
|
3377 | 0 | if (!mTracingEnabled) |
3378 | 0 | return NS_ERROR_FAILURE; |
3379 | 0 | |
3380 | 0 | NS_ENSURE_STATE(mListener); |
3381 | 0 | NS_ENSURE_ARG_POINTER(aListener); |
3382 | 0 |
|
3383 | 0 | nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener); |
3384 | 0 |
|
3385 | 0 | wrapper.forget(_retval); |
3386 | 0 | mListener = aListener; |
3387 | 0 | return NS_OK; |
3388 | 0 | } |
3389 | | |
3390 | | //----------------------------------------------------------------------------- |
3391 | | // HttpBaseChannel helpers |
3392 | | //----------------------------------------------------------------------------- |
3393 | | |
3394 | | void |
3395 | | HttpBaseChannel::ReleaseListeners() |
3396 | 0 | { |
3397 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread."); |
3398 | 0 |
|
3399 | 0 | mListener = nullptr; |
3400 | 0 | mListenerContext = nullptr; |
3401 | 0 | mCallbacks = nullptr; |
3402 | 0 | mProgressSink = nullptr; |
3403 | 0 | mCompressListener = nullptr; |
3404 | 0 | } |
3405 | | |
3406 | | void |
3407 | | HttpBaseChannel::DoNotifyListener() |
3408 | 0 | { |
3409 | 0 | LOG(("HttpBaseChannel::DoNotifyListener this=%p", this)); |
3410 | 0 |
|
3411 | 0 | if (mListener) { |
3412 | 0 | MOZ_ASSERT(!mOnStartRequestCalled, |
3413 | 0 | "We should not call OnStartRequest twice"); |
3414 | 0 |
|
3415 | 0 | nsCOMPtr<nsIStreamListener> listener = mListener; |
3416 | 0 | listener->OnStartRequest(this, mListenerContext); |
3417 | 0 |
|
3418 | 0 | mOnStartRequestCalled = true; |
3419 | 0 | } |
3420 | 0 |
|
3421 | 0 | // Make sure mIsPending is set to false. At this moment we are done from |
3422 | 0 | // the point of view of our consumer and we have to report our self |
3423 | 0 | // as not-pending. |
3424 | 0 | mIsPending = false; |
3425 | 0 |
|
3426 | 0 | if (mListener) { |
3427 | 0 | MOZ_ASSERT(!mOnStopRequestCalled, |
3428 | 0 | "We should not call OnStopRequest twice"); |
3429 | 0 |
|
3430 | 0 | nsCOMPtr<nsIStreamListener> listener = mListener; |
3431 | 0 | listener->OnStopRequest(this, mListenerContext, mStatus); |
3432 | 0 |
|
3433 | 0 | mOnStopRequestCalled = true; |
3434 | 0 | } |
3435 | 0 |
|
3436 | 0 | // notify "http-on-stop-connect" observers |
3437 | 0 | gHttpHandler->OnStopRequest(this); |
3438 | 0 |
|
3439 | 0 | // This channel has finished its job, potentially release any tail-blocked |
3440 | 0 | // requests with this. |
3441 | 0 | RemoveAsNonTailRequest(); |
3442 | 0 |
|
3443 | 0 | // We have to make sure to drop the references to listeners and callbacks |
3444 | 0 | // no longer needed. |
3445 | 0 | ReleaseListeners(); |
3446 | 0 |
|
3447 | 0 | DoNotifyListenerCleanup(); |
3448 | 0 |
|
3449 | 0 | // If this is a navigation, then we must let the docshell flush the reports |
3450 | 0 | // to the console later. The LoadDocument() is pointing at the detached |
3451 | 0 | // document that started the navigation. We want to show the reports on the |
3452 | 0 | // new document. Otherwise the console is wiped and the user never sees |
3453 | 0 | // the information. |
3454 | 0 | if (!IsNavigation()) { |
3455 | 0 | if (mLoadGroup) { |
3456 | 0 | FlushConsoleReports(mLoadGroup); |
3457 | 0 | } else if (mLoadInfo) { |
3458 | 0 | nsCOMPtr<nsIDocument> doc; |
3459 | 0 | mLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); |
3460 | 0 | FlushConsoleReports(doc); |
3461 | 0 | } |
3462 | 0 | } |
3463 | 0 | } |
3464 | | |
3465 | | void |
3466 | | HttpBaseChannel::AddCookiesToRequest() |
3467 | 0 | { |
3468 | 0 | if (mLoadFlags & LOAD_ANONYMOUS) { |
3469 | 0 | return; |
3470 | 0 | } |
3471 | 0 | |
3472 | 0 | bool useCookieService = |
3473 | 0 | (XRE_IsParentProcess()); |
3474 | 0 | nsCString cookie; |
3475 | 0 | if (useCookieService) { |
3476 | 0 | nsICookieService *cs = gHttpHandler->GetCookieService(); |
3477 | 0 | if (cs) { |
3478 | 0 | cs->GetCookieStringFromHttp(mURI, |
3479 | 0 | nullptr, |
3480 | 0 | this, getter_Copies(cookie)); |
3481 | 0 | } |
3482 | 0 |
|
3483 | 0 | if (cookie.IsEmpty()) { |
3484 | 0 | cookie = mUserSetCookieHeader; |
3485 | 0 | } |
3486 | 0 | else if (!mUserSetCookieHeader.IsEmpty()) { |
3487 | 0 | cookie.AppendLiteral("; "); |
3488 | 0 | cookie.Append(mUserSetCookieHeader); |
3489 | 0 | } |
3490 | 0 | } |
3491 | 0 | else { |
3492 | 0 | cookie = mUserSetCookieHeader; |
3493 | 0 | } |
3494 | 0 |
|
3495 | 0 | // If we are in the child process, we want the parent seeing any |
3496 | 0 | // cookie headers that might have been set by SetRequestHeader() |
3497 | 0 | SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false); |
3498 | 0 | } |
3499 | | |
3500 | | /* static */ |
3501 | | bool |
3502 | | HttpBaseChannel::IsReferrerSchemeAllowed(nsIURI *aReferrer) |
3503 | 0 | { |
3504 | 0 | NS_ENSURE_TRUE(aReferrer, false); |
3505 | 0 |
|
3506 | 0 | nsAutoCString scheme; |
3507 | 0 | nsresult rv = aReferrer->GetScheme(scheme); |
3508 | 0 | NS_ENSURE_SUCCESS(rv, false); |
3509 | 0 |
|
3510 | 0 | if (scheme.EqualsIgnoreCase("https") || |
3511 | 0 | scheme.EqualsIgnoreCase("http") || |
3512 | 0 | scheme.EqualsIgnoreCase("ftp")) { |
3513 | 0 | return true; |
3514 | 0 | } |
3515 | 0 | return false; |
3516 | 0 | } |
3517 | | |
3518 | | /* static */ |
3519 | | void |
3520 | | HttpBaseChannel::PropagateReferenceIfNeeded(nsIURI* aURI, nsCOMPtr<nsIURI>& aRedirectURI) |
3521 | 0 | { |
3522 | 0 | bool hasRef = false; |
3523 | 0 | nsresult rv = aRedirectURI->GetHasRef(&hasRef); |
3524 | 0 | if (NS_SUCCEEDED(rv) && !hasRef) { |
3525 | 0 | nsAutoCString ref; |
3526 | 0 | aURI->GetRef(ref); |
3527 | 0 | if (!ref.IsEmpty()) { |
3528 | 0 | // NOTE: SetRef will fail if mRedirectURI is immutable |
3529 | 0 | // (e.g. an about: URI)... Oh well. |
3530 | 0 | Unused << NS_MutateURI(aRedirectURI) |
3531 | 0 | .SetRef(ref) |
3532 | 0 | .Finalize(aRedirectURI); |
3533 | 0 | } |
3534 | 0 | } |
3535 | 0 | } |
3536 | | |
3537 | | bool |
3538 | | HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus, |
3539 | | nsHttpRequestHead::ParsedMethodType method) |
3540 | 0 | { |
3541 | 0 | // for 301 and 302, only rewrite POST |
3542 | 0 | if (httpStatus == 301 || httpStatus == 302) |
3543 | 0 | return method == nsHttpRequestHead::kMethod_Post; |
3544 | 0 | |
3545 | 0 | // rewrite for 303 unless it was HEAD |
3546 | 0 | if (httpStatus == 303) |
3547 | 0 | return method != nsHttpRequestHead::kMethod_Head; |
3548 | 0 | |
3549 | 0 | // otherwise, such as for 307, do not rewrite |
3550 | 0 | return false; |
3551 | 0 | } |
3552 | | |
3553 | | nsresult |
3554 | | HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, |
3555 | | nsIChannel *newChannel, |
3556 | | bool preserveMethod, |
3557 | | uint32_t redirectFlags) |
3558 | 0 | { |
3559 | 0 | nsresult rv; |
3560 | 0 |
|
3561 | 0 | LOG(("HttpBaseChannel::SetupReplacementChannel " |
3562 | 0 | "[this=%p newChannel=%p preserveMethod=%d]", |
3563 | 0 | this, newChannel, preserveMethod)); |
3564 | 0 |
|
3565 | 0 | // Ensure the channel's loadInfo's result principal URI so that it's |
3566 | 0 | // either non-null or updated to the redirect target URI. |
3567 | 0 | // We must do this because in case the loadInfo's result principal URI |
3568 | 0 | // is null, it would be taken from OriginalURI of the channel. But we |
3569 | 0 | // overwrite it with the whole redirect chain first URI before opening |
3570 | 0 | // the target channel, hence the information would be lost. |
3571 | 0 | // If the protocol handler that created the channel wants to use |
3572 | 0 | // the originalURI of the channel as the principal URI, this fulfills |
3573 | 0 | // that request - newURI is the original URI of the channel. |
3574 | 0 | nsCOMPtr<nsILoadInfo> newLoadInfo = newChannel->GetLoadInfo(); |
3575 | 0 | if (newLoadInfo) { |
3576 | 0 | nsCOMPtr<nsIURI> resultPrincipalURI; |
3577 | 0 | rv = newLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); |
3578 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3579 | 0 |
|
3580 | 0 | if (!resultPrincipalURI) { |
3581 | 0 | rv = newLoadInfo->SetResultPrincipalURI(newURI); |
3582 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3583 | 0 | } |
3584 | 0 | } |
3585 | 0 |
|
3586 | 0 | uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE; |
3587 | 0 | // if the original channel was using SSL and this channel is not using |
3588 | 0 | // SSL, then no need to inhibit persistent caching. however, if the |
3589 | 0 | // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING |
3590 | 0 | // set, then allow the flag to apply to the redirected channel as well. |
3591 | 0 | // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels, |
3592 | 0 | // we only need to check if the original channel was using SSL. |
3593 | 0 | bool usingSSL = false; |
3594 | 0 | rv = mURI->SchemeIs("https", &usingSSL); |
3595 | 0 | if (NS_SUCCEEDED(rv) && usingSSL) |
3596 | 0 | newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING; |
3597 | 0 |
|
3598 | 0 | // Do not pass along LOAD_CHECK_OFFLINE_CACHE |
3599 | 0 | newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE; |
3600 | 0 |
|
3601 | 0 | newChannel->SetLoadGroup(mLoadGroup); |
3602 | 0 | newChannel->SetNotificationCallbacks(mCallbacks); |
3603 | 0 | newChannel->SetLoadFlags(newLoadFlags); |
3604 | 0 |
|
3605 | 0 | nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(newChannel)); |
3606 | 0 | if (cos) { |
3607 | 0 | cos->SetClassFlags(mClassOfService); |
3608 | 0 | } |
3609 | 0 |
|
3610 | 0 | // Try to preserve the privacy bit if it has been overridden |
3611 | 0 | if (mPrivateBrowsingOverriden) { |
3612 | 0 | nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel = |
3613 | 0 | do_QueryInterface(newChannel); |
3614 | 0 | if (newPBChannel) { |
3615 | 0 | newPBChannel->SetPrivate(mPrivateBrowsing); |
3616 | 0 | } |
3617 | 0 | } |
3618 | 0 |
|
3619 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel); |
3620 | 0 | if (!httpChannel) |
3621 | 0 | return NS_OK; // no other options to set |
3622 | 0 | |
3623 | 0 | // Preserve the CORS preflight information. |
3624 | 0 | nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel); |
3625 | 0 | if (httpInternal) { |
3626 | 0 | httpInternal->SetLastRedirectFlags(redirectFlags); |
3627 | 0 |
|
3628 | 0 | if (mRequireCORSPreflight) { |
3629 | 0 | httpInternal->SetCorsPreflightParameters(mUnsafeHeaders); |
3630 | 0 | } |
3631 | 0 | } |
3632 | 0 |
|
3633 | 0 | if (preserveMethod) { |
3634 | 0 | nsCOMPtr<nsIUploadChannel> uploadChannel = |
3635 | 0 | do_QueryInterface(httpChannel); |
3636 | 0 | nsCOMPtr<nsIUploadChannel2> uploadChannel2 = |
3637 | 0 | do_QueryInterface(httpChannel); |
3638 | 0 | if (mUploadStream && (uploadChannel2 || uploadChannel)) { |
3639 | 0 | // rewind upload stream |
3640 | 0 | nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream); |
3641 | 0 | MOZ_ASSERT(seekable); |
3642 | 0 |
|
3643 | 0 | seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); |
3644 | 0 |
|
3645 | 0 | // replicate original call to SetUploadStream... |
3646 | 0 | if (uploadChannel2) { |
3647 | 0 | nsAutoCString ctype; |
3648 | 0 | // If header is not present mRequestHead.HasHeaderValue will truncated |
3649 | 0 | // it. But we want to end up with a void string, not an empty string, |
3650 | 0 | // because ExplicitSetUploadStream treats the former as "no header" and |
3651 | 0 | // the latter as "header with empty string value". |
3652 | 0 | nsresult ctypeOK = mRequestHead.GetHeader(nsHttp::Content_Type, ctype); |
3653 | 0 | if (NS_FAILED(ctypeOK)) { |
3654 | 0 | ctype.SetIsVoid(true); |
3655 | 0 | } |
3656 | 0 | nsAutoCString clen; |
3657 | 0 | Unused << mRequestHead.GetHeader(nsHttp::Content_Length, clen); |
3658 | 0 | nsAutoCString method; |
3659 | 0 | mRequestHead.Method(method); |
3660 | 0 | int64_t len = clen.IsEmpty() ? -1 : nsCRT::atoll(clen.get()); |
3661 | 0 | uploadChannel2->ExplicitSetUploadStream( |
3662 | 0 | mUploadStream, ctype, len, |
3663 | 0 | method, |
3664 | 0 | mUploadStreamHasHeaders); |
3665 | 0 | } else { |
3666 | 0 | if (mUploadStreamHasHeaders) { |
3667 | 0 | uploadChannel->SetUploadStream(mUploadStream, EmptyCString(), |
3668 | 0 | -1); |
3669 | 0 | } else { |
3670 | 0 | nsAutoCString ctype; |
3671 | 0 | if (NS_FAILED(mRequestHead.GetHeader(nsHttp::Content_Type, ctype))) { |
3672 | 0 | ctype = NS_LITERAL_CSTRING("application/octet-stream"); |
3673 | 0 | } |
3674 | 0 | nsAutoCString clen; |
3675 | 0 | if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Content_Length, clen)) |
3676 | 0 | && |
3677 | 0 | !clen.IsEmpty()) { |
3678 | 0 | uploadChannel->SetUploadStream(mUploadStream, |
3679 | 0 | ctype, |
3680 | 0 | nsCRT::atoll(clen.get())); |
3681 | 0 | } |
3682 | 0 | } |
3683 | 0 | } |
3684 | 0 | } |
3685 | 0 | // since preserveMethod is true, we need to ensure that the appropriate |
3686 | 0 | // request method gets set on the channel, regardless of whether or not |
3687 | 0 | // we set the upload stream above. This means SetRequestMethod() will |
3688 | 0 | // be called twice if ExplicitSetUploadStream() gets called above. |
3689 | 0 |
|
3690 | 0 | nsAutoCString method; |
3691 | 0 | mRequestHead.Method(method); |
3692 | 0 | rv = httpChannel->SetRequestMethod(method); |
3693 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3694 | 0 | } |
3695 | 0 | // convey the referrer if one was used for this channel to the next one |
3696 | 0 | if (mReferrer) { |
3697 | 0 | rv = httpChannel->SetReferrerWithPolicy(mReferrer, mReferrerPolicy); |
3698 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3699 | 0 | } |
3700 | 0 | // convey the mAllowSTS flags |
3701 | 0 | rv = httpChannel->SetAllowSTS(mAllowSTS); |
3702 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3703 | 0 |
|
3704 | 0 | // convey the Accept header value |
3705 | 0 | { |
3706 | 0 | nsAutoCString oldAcceptValue; |
3707 | 0 | nsresult hasHeader = mRequestHead.GetHeader(nsHttp::Accept, oldAcceptValue); |
3708 | 0 | if (NS_SUCCEEDED(hasHeader)) { |
3709 | 0 | rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"), |
3710 | 0 | oldAcceptValue, |
3711 | 0 | false); |
3712 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3713 | 0 | } |
3714 | 0 | } |
3715 | 0 |
|
3716 | 0 | // share the request context - see bug 1236650 |
3717 | 0 | rv = httpChannel->SetRequestContextID(mRequestContextID); |
3718 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3719 | 0 |
|
3720 | 0 | // When on the parent process, the channel can't attempt to get it itself. |
3721 | 0 | // When on the child process, it would be waste to query it again. |
3722 | 0 | rv = httpChannel->SetTopLevelOuterContentWindowId(mTopLevelOuterContentWindowId); |
3723 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3724 | 0 |
|
3725 | 0 | // Not setting this flag would break carrying permissions down to the child process |
3726 | 0 | // when the channel is artificially forced to be a main document load. |
3727 | 0 | rv = httpChannel->SetIsMainDocumentChannel(mForceMainDocumentChannel); |
3728 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3729 | 0 |
|
3730 | 0 | // Preserve the loading order |
3731 | 0 | nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(newChannel); |
3732 | 0 | if (p) { |
3733 | 0 | p->SetPriority(mPriority); |
3734 | 0 | } |
3735 | 0 |
|
3736 | 0 | if (httpInternal) { |
3737 | 0 | // Convey third party cookie, conservative, and spdy flags. |
3738 | 0 | rv = httpInternal->SetThirdPartyFlags(mThirdPartyFlags); |
3739 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3740 | 0 | rv = httpInternal->SetAllowSpdy(mAllowSpdy); |
3741 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3742 | 0 | rv = httpInternal->SetAllowAltSvc(mAllowAltSvc); |
3743 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3744 | 0 | rv = httpInternal->SetBeConservative(mBeConservative); |
3745 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3746 | 0 | rv = httpInternal->SetTrr(mTRR); |
3747 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3748 | 0 | rv = httpInternal->SetTlsFlags(mTlsFlags); |
3749 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3750 | 0 |
|
3751 | 0 | RefPtr<nsHttpChannel> realChannel; |
3752 | 0 | CallQueryInterface(newChannel, realChannel.StartAssignment()); |
3753 | 0 | if (realChannel) { |
3754 | 0 | rv = realChannel->SetTopWindowURI(mTopWindowURI); |
3755 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3756 | 0 | } |
3757 | 0 |
|
3758 | 0 | // update the DocumentURI indicator since we are being redirected. |
3759 | 0 | // if this was a top-level document channel, then the new channel |
3760 | 0 | // should have its mDocumentURI point to newURI; otherwise, we |
3761 | 0 | // just need to pass along our mDocumentURI to the new channel. |
3762 | 0 | if (newURI && (mURI == mDocumentURI)) |
3763 | 0 | rv = httpInternal->SetDocumentURI(newURI); |
3764 | 0 | else |
3765 | 0 | rv = httpInternal->SetDocumentURI(mDocumentURI); |
3766 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3767 | 0 |
|
3768 | 0 | // if there is a chain of keys for redirect-responses we transfer it to |
3769 | 0 | // the new channel (see bug #561276) |
3770 | 0 | if (mRedirectedCachekeys) { |
3771 | 0 | LOG(("HttpBaseChannel::SetupReplacementChannel " |
3772 | 0 | "[this=%p] transferring chain of redirect cache-keys", this)); |
3773 | 0 | rv = httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget()); |
3774 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3775 | 0 | } |
3776 | 0 |
|
3777 | 0 | // Preserve CORS mode flag. |
3778 | 0 | rv = httpInternal->SetCorsMode(mCorsMode); |
3779 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3780 | 0 |
|
3781 | 0 | // Preserve Redirect mode flag. |
3782 | 0 | rv = httpInternal->SetRedirectMode(mRedirectMode); |
3783 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3784 | 0 |
|
3785 | 0 | // Preserve Integrity metadata. |
3786 | 0 | rv = httpInternal->SetIntegrityMetadata(mIntegrityMetadata); |
3787 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3788 | 0 |
|
3789 | 0 | httpInternal->SetAltDataForChild(mAltDataForChild); |
3790 | 0 | } |
3791 | 0 |
|
3792 | 0 | // transfer application cache information |
3793 | 0 | nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
3794 | 0 | do_QueryInterface(newChannel); |
3795 | 0 | if (appCacheChannel) { |
3796 | 0 | appCacheChannel->SetApplicationCache(mApplicationCache); |
3797 | 0 | appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache); |
3798 | 0 | // We purposely avoid transfering mChooseApplicationCache. |
3799 | 0 | } |
3800 | 0 |
|
3801 | 0 | // transfer any properties |
3802 | 0 | nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel)); |
3803 | 0 | if (bag) { |
3804 | 0 | for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) { |
3805 | 0 | bag->SetProperty(iter.Key(), iter.UserData()); |
3806 | 0 | } |
3807 | 0 | } |
3808 | 0 |
|
3809 | 0 | // Transfer the timing data (if we are dealing with an nsITimedChannel). |
3810 | 0 | nsCOMPtr<nsITimedChannel> newTimedChannel(do_QueryInterface(newChannel)); |
3811 | 0 | nsCOMPtr<nsITimedChannel> oldTimedChannel( |
3812 | 0 | do_QueryInterface(static_cast<nsIHttpChannel*>(this))); |
3813 | 0 | if (oldTimedChannel && newTimedChannel) { |
3814 | 0 | newTimedChannel->SetTimingEnabled(mTimingEnabled); |
3815 | 0 |
|
3816 | 0 | if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { |
3817 | 0 | newTimedChannel->SetRedirectCount(mRedirectCount); |
3818 | 0 | int8_t newCount = mInternalRedirectCount + 1; |
3819 | 0 | newTimedChannel->SetInternalRedirectCount( |
3820 | 0 | std::max(newCount, mInternalRedirectCount)); |
3821 | 0 | } else { |
3822 | 0 | int8_t newCount = mRedirectCount + 1; |
3823 | 0 | newTimedChannel->SetRedirectCount( |
3824 | 0 | std::max(newCount, mRedirectCount)); |
3825 | 0 | newTimedChannel->SetInternalRedirectCount(mInternalRedirectCount); |
3826 | 0 | } |
3827 | 0 |
|
3828 | 0 | TimeStamp oldAsyncOpenTime; |
3829 | 0 | oldTimedChannel->GetAsyncOpen(&oldAsyncOpenTime); |
3830 | 0 |
|
3831 | 0 | if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { |
3832 | 0 | TimeStamp oldChannelCreationTimestamp; |
3833 | 0 | oldTimedChannel->GetChannelCreation(&oldChannelCreationTimestamp); |
3834 | 0 |
|
3835 | 0 | if (!oldChannelCreationTimestamp.IsNull()) { |
3836 | 0 | newTimedChannel->SetChannelCreation(oldChannelCreationTimestamp); |
3837 | 0 | } |
3838 | 0 |
|
3839 | 0 | if (!oldAsyncOpenTime.IsNull()) { |
3840 | 0 | newTimedChannel->SetAsyncOpen(oldAsyncOpenTime); |
3841 | 0 | } |
3842 | 0 | } |
3843 | 0 |
|
3844 | 0 | // If the RedirectStart is null, we will use the AsyncOpen value of the |
3845 | 0 | // previous channel (this is the first redirect in the redirects chain). |
3846 | 0 | if (mRedirectStartTimeStamp.IsNull()) { |
3847 | 0 | // Only do this for real redirects. Internal redirects should be hidden. |
3848 | 0 | if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) { |
3849 | 0 | newTimedChannel->SetRedirectStart(oldAsyncOpenTime); |
3850 | 0 | } |
3851 | 0 | } else { |
3852 | 0 | newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp); |
3853 | 0 | } |
3854 | 0 |
|
3855 | 0 | // For internal redirects just propagate the last redirect end time |
3856 | 0 | // forward. Otherwise the new redirect end time is the last response |
3857 | 0 | // end time. |
3858 | 0 | TimeStamp newRedirectEnd; |
3859 | 0 | if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { |
3860 | 0 | oldTimedChannel->GetRedirectEnd(&newRedirectEnd); |
3861 | 0 | } else { |
3862 | 0 | oldTimedChannel->GetResponseEnd(&newRedirectEnd); |
3863 | 0 | } |
3864 | 0 | newTimedChannel->SetRedirectEnd(newRedirectEnd); |
3865 | 0 |
|
3866 | 0 | nsAutoString initiatorType; |
3867 | 0 | oldTimedChannel->GetInitiatorType(initiatorType); |
3868 | 0 | newTimedChannel->SetInitiatorType(initiatorType); |
3869 | 0 |
|
3870 | 0 | // Check whether or not this was a cross-domain redirect. |
3871 | 0 | newTimedChannel->SetAllRedirectsSameOrigin( |
3872 | 0 | mAllRedirectsSameOrigin && SameOriginWithOriginalUri(newURI)); |
3873 | 0 |
|
3874 | 0 | // Execute the timing allow check to determine whether |
3875 | 0 | // to report the redirect timing info |
3876 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
3877 | 0 | GetLoadInfo(getter_AddRefs(loadInfo)); |
3878 | 0 | // TYPE_DOCUMENT loads don't have a loadingPrincipal, so we can't set |
3879 | 0 | // AllRedirectsPassTimingAllowCheck on them. |
3880 | 0 | if (loadInfo && loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) { |
3881 | 0 | nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal(); |
3882 | 0 | newTimedChannel->SetAllRedirectsPassTimingAllowCheck( |
3883 | 0 | mAllRedirectsPassTimingAllowCheck && |
3884 | 0 | oldTimedChannel->TimingAllowCheck(principal)); |
3885 | 0 | } |
3886 | 0 |
|
3887 | 0 | // Propagate service worker measurements across redirects. The |
3888 | 0 | // PeformanceResourceTiming.workerStart API expects to see the |
3889 | 0 | // worker start time after a redirect. |
3890 | 0 | newTimedChannel->SetLaunchServiceWorkerStart(mLaunchServiceWorkerStart); |
3891 | 0 | newTimedChannel->SetLaunchServiceWorkerEnd(mLaunchServiceWorkerEnd); |
3892 | 0 | newTimedChannel->SetDispatchFetchEventStart(mDispatchFetchEventStart); |
3893 | 0 | newTimedChannel->SetDispatchFetchEventEnd(mDispatchFetchEventEnd); |
3894 | 0 | newTimedChannel->SetHandleFetchEventStart(mHandleFetchEventStart); |
3895 | 0 | newTimedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd); |
3896 | 0 | } |
3897 | 0 |
|
3898 | 0 | // Pass the preferred alt-data type on to the new channel. |
3899 | 0 | nsCOMPtr<nsICacheInfoChannel> cacheInfoChan(do_QueryInterface(newChannel)); |
3900 | 0 | if (cacheInfoChan) { |
3901 | 0 | cacheInfoChan->PreferAlternativeDataType(mPreferredCachedAltDataType); |
3902 | 0 | } |
3903 | 0 |
|
3904 | 0 | if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL | |
3905 | 0 | nsIChannelEventSink::REDIRECT_STS_UPGRADE)) { |
3906 | 0 | // Copy non-origin related headers to the new channel. |
3907 | 0 | nsCOMPtr<nsIHttpHeaderVisitor> visitor = |
3908 | 0 | new AddHeadersToChannelVisitor(httpChannel); |
3909 | 0 | rv = mRequestHead.VisitHeaders(visitor); |
3910 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
3911 | 0 | } |
3912 | 0 |
|
3913 | 0 | // This channel has been redirected. Don't report timing info. |
3914 | 0 | mTimingEnabled = false; |
3915 | 0 | return NS_OK; |
3916 | 0 | } |
3917 | | |
3918 | | // Redirect Tracking |
3919 | | bool |
3920 | | HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI) |
3921 | 0 | { |
3922 | 0 | nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); |
3923 | 0 | bool isPrivateWin = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; |
3924 | 0 | nsresult rv = ssm->CheckSameOriginURI(aURI, mOriginalURI, false, isPrivateWin); |
3925 | 0 | return (NS_SUCCEEDED(rv)); |
3926 | 0 | } |
3927 | | |
3928 | | |
3929 | | //----------------------------------------------------------------------------- |
3930 | | // HttpBaseChannel::nsIClassifiedChannel |
3931 | | |
3932 | | NS_IMETHODIMP |
3933 | | HttpBaseChannel::GetMatchedList(nsACString& aList) |
3934 | 0 | { |
3935 | 0 | aList = mMatchedList; |
3936 | 0 | return NS_OK; |
3937 | 0 | } |
3938 | | |
3939 | | NS_IMETHODIMP |
3940 | | HttpBaseChannel::GetMatchedProvider(nsACString& aProvider) |
3941 | 0 | { |
3942 | 0 | aProvider = mMatchedProvider; |
3943 | 0 | return NS_OK; |
3944 | 0 | } |
3945 | | |
3946 | | NS_IMETHODIMP |
3947 | | HttpBaseChannel::GetMatchedFullHash(nsACString& aFullHash) |
3948 | 0 | { |
3949 | 0 | aFullHash = mMatchedFullHash; |
3950 | 0 | return NS_OK; |
3951 | 0 | } |
3952 | | |
3953 | | NS_IMETHODIMP |
3954 | | HttpBaseChannel::SetMatchedInfo(const nsACString& aList, |
3955 | | const nsACString& aProvider, |
3956 | 0 | const nsACString& aFullHash) { |
3957 | 0 | NS_ENSURE_ARG(!aList.IsEmpty()); |
3958 | 0 |
|
3959 | 0 | mMatchedList = aList; |
3960 | 0 | mMatchedProvider = aProvider; |
3961 | 0 | mMatchedFullHash = aFullHash; |
3962 | 0 | return NS_OK; |
3963 | 0 | } |
3964 | | |
3965 | | //----------------------------------------------------------------------------- |
3966 | | // HttpBaseChannel::nsITimedChannel |
3967 | | //----------------------------------------------------------------------------- |
3968 | | |
3969 | | NS_IMETHODIMP |
3970 | 0 | HttpBaseChannel::SetTimingEnabled(bool enabled) { |
3971 | 0 | mTimingEnabled = enabled; |
3972 | 0 | return NS_OK; |
3973 | 0 | } |
3974 | | |
3975 | | NS_IMETHODIMP |
3976 | 0 | HttpBaseChannel::GetTimingEnabled(bool* _retval) { |
3977 | 0 | *_retval = mTimingEnabled; |
3978 | 0 | return NS_OK; |
3979 | 0 | } |
3980 | | |
3981 | | NS_IMETHODIMP |
3982 | 0 | HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) { |
3983 | 0 | *_retval = mChannelCreationTimestamp; |
3984 | 0 | return NS_OK; |
3985 | 0 | } |
3986 | | |
3987 | | NS_IMETHODIMP |
3988 | 0 | HttpBaseChannel::SetChannelCreation(TimeStamp aValue) { |
3989 | 0 | MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull()); |
3990 | 0 | TimeDuration adjust = aValue - mChannelCreationTimestamp; |
3991 | 0 | mChannelCreationTimestamp = aValue; |
3992 | 0 | mChannelCreationTime += (PRTime)adjust.ToMicroseconds(); |
3993 | 0 | return NS_OK; |
3994 | 0 | } |
3995 | | |
3996 | | NS_IMETHODIMP |
3997 | 0 | HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) { |
3998 | 0 | *_retval = mAsyncOpenTime; |
3999 | 0 | return NS_OK; |
4000 | 0 | } |
4001 | | |
4002 | | NS_IMETHODIMP |
4003 | 0 | HttpBaseChannel::SetAsyncOpen(TimeStamp aValue) { |
4004 | 0 | MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull()); |
4005 | 0 | mAsyncOpenTime = aValue; |
4006 | 0 | mAsyncOpenTimeOverriden = true; |
4007 | 0 | return NS_OK; |
4008 | 0 | } |
4009 | | |
4010 | | /** |
4011 | | * @return the number of redirects. There is no check for cross-domain |
4012 | | * redirects. This check must be done by the consumers. |
4013 | | */ |
4014 | | NS_IMETHODIMP |
4015 | | HttpBaseChannel::GetRedirectCount(uint8_t *aRedirectCount) |
4016 | 0 | { |
4017 | 0 | *aRedirectCount = mRedirectCount; |
4018 | 0 | return NS_OK; |
4019 | 0 | } |
4020 | | |
4021 | | NS_IMETHODIMP |
4022 | | HttpBaseChannel::SetRedirectCount(uint8_t aRedirectCount) |
4023 | 0 | { |
4024 | 0 | mRedirectCount = aRedirectCount; |
4025 | 0 | return NS_OK; |
4026 | 0 | } |
4027 | | |
4028 | | NS_IMETHODIMP |
4029 | | HttpBaseChannel::GetInternalRedirectCount(uint8_t *aRedirectCount) |
4030 | 0 | { |
4031 | 0 | *aRedirectCount = mInternalRedirectCount; |
4032 | 0 | return NS_OK; |
4033 | 0 | } |
4034 | | |
4035 | | NS_IMETHODIMP |
4036 | | HttpBaseChannel::SetInternalRedirectCount(uint8_t aRedirectCount) |
4037 | 0 | { |
4038 | 0 | mInternalRedirectCount = aRedirectCount; |
4039 | 0 | return NS_OK; |
4040 | 0 | } |
4041 | | |
4042 | | NS_IMETHODIMP |
4043 | | HttpBaseChannel::GetRedirectStart(TimeStamp* _retval) |
4044 | 0 | { |
4045 | 0 | *_retval = mRedirectStartTimeStamp; |
4046 | 0 | return NS_OK; |
4047 | 0 | } |
4048 | | |
4049 | | NS_IMETHODIMP |
4050 | | HttpBaseChannel::SetRedirectStart(TimeStamp aRedirectStart) |
4051 | 0 | { |
4052 | 0 | mRedirectStartTimeStamp = aRedirectStart; |
4053 | 0 | return NS_OK; |
4054 | 0 | } |
4055 | | |
4056 | | NS_IMETHODIMP |
4057 | | HttpBaseChannel::GetRedirectEnd(TimeStamp* _retval) |
4058 | 0 | { |
4059 | 0 | *_retval = mRedirectEndTimeStamp; |
4060 | 0 | return NS_OK; |
4061 | 0 | } |
4062 | | |
4063 | | NS_IMETHODIMP |
4064 | | HttpBaseChannel::SetRedirectEnd(TimeStamp aRedirectEnd) |
4065 | 0 | { |
4066 | 0 | mRedirectEndTimeStamp = aRedirectEnd; |
4067 | 0 | return NS_OK; |
4068 | 0 | } |
4069 | | |
4070 | | NS_IMETHODIMP |
4071 | | HttpBaseChannel::GetAllRedirectsSameOrigin(bool *aAllRedirectsSameOrigin) |
4072 | 0 | { |
4073 | 0 | *aAllRedirectsSameOrigin = mAllRedirectsSameOrigin; |
4074 | 0 | return NS_OK; |
4075 | 0 | } |
4076 | | |
4077 | | NS_IMETHODIMP |
4078 | | HttpBaseChannel::SetAllRedirectsSameOrigin(bool aAllRedirectsSameOrigin) |
4079 | 0 | { |
4080 | 0 | mAllRedirectsSameOrigin = aAllRedirectsSameOrigin; |
4081 | 0 | return NS_OK; |
4082 | 0 | } |
4083 | | |
4084 | | NS_IMETHODIMP |
4085 | | HttpBaseChannel::GetAllRedirectsPassTimingAllowCheck(bool *aPassesCheck) |
4086 | 0 | { |
4087 | 0 | *aPassesCheck = mAllRedirectsPassTimingAllowCheck; |
4088 | 0 | return NS_OK; |
4089 | 0 | } |
4090 | | |
4091 | | NS_IMETHODIMP |
4092 | | HttpBaseChannel::SetAllRedirectsPassTimingAllowCheck(bool aPassesCheck) |
4093 | 0 | { |
4094 | 0 | mAllRedirectsPassTimingAllowCheck = aPassesCheck; |
4095 | 0 | return NS_OK; |
4096 | 0 | } |
4097 | | |
4098 | | // http://www.w3.org/TR/resource-timing/#timing-allow-check |
4099 | | NS_IMETHODIMP |
4100 | | HttpBaseChannel::TimingAllowCheck(nsIPrincipal *aOrigin, bool *_retval) |
4101 | 0 | { |
4102 | 0 | nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); |
4103 | 0 | nsCOMPtr<nsIPrincipal> resourcePrincipal; |
4104 | 0 | nsresult rv = ssm->GetChannelURIPrincipal(this, getter_AddRefs(resourcePrincipal)); |
4105 | 0 | if (NS_FAILED(rv) || !resourcePrincipal || !aOrigin) { |
4106 | 0 | *_retval = false; |
4107 | 0 | return NS_OK; |
4108 | 0 | } |
4109 | 0 | |
4110 | 0 | bool sameOrigin = false; |
4111 | 0 | rv = resourcePrincipal->Equals(aOrigin, &sameOrigin); |
4112 | 0 | if (NS_SUCCEEDED(rv) && sameOrigin) { |
4113 | 0 | *_retval = true; |
4114 | 0 | return NS_OK; |
4115 | 0 | } |
4116 | 0 | |
4117 | 0 | nsAutoCString headerValue; |
4118 | 0 | rv = GetResponseHeader(NS_LITERAL_CSTRING("Timing-Allow-Origin"), headerValue); |
4119 | 0 | if (NS_FAILED(rv)) { |
4120 | 0 | *_retval = false; |
4121 | 0 | return NS_OK; |
4122 | 0 | } |
4123 | 0 | |
4124 | 0 | nsAutoCString origin; |
4125 | 0 | nsContentUtils::GetASCIIOrigin(aOrigin, origin); |
4126 | 0 |
|
4127 | 0 | Tokenizer p(headerValue); |
4128 | 0 | Tokenizer::Token t; |
4129 | 0 |
|
4130 | 0 | p.Record(); |
4131 | 0 | nsAutoCString headerItem; |
4132 | 0 | while (p.Next(t)) { |
4133 | 0 | if (t.Type() == Tokenizer::TOKEN_EOF || |
4134 | 0 | t.Equals(Tokenizer::Token::Char(','))) { |
4135 | 0 | p.Claim(headerItem); |
4136 | 0 | headerItem.StripWhitespace(); |
4137 | 0 | // If the list item contains a case-sensitive match for the value of the |
4138 | 0 | // origin, or a wildcard, return pass |
4139 | 0 | if (headerItem == origin || headerItem == "*") { |
4140 | 0 | *_retval = true; |
4141 | 0 | return NS_OK; |
4142 | 0 | } |
4143 | 0 | // We start recording again for the following items in the list |
4144 | 0 | p.Record(); |
4145 | 0 | } |
4146 | 0 | } |
4147 | 0 |
|
4148 | 0 | *_retval = false; |
4149 | 0 | return NS_OK; |
4150 | 0 | } |
4151 | | |
4152 | | NS_IMETHODIMP |
4153 | 0 | HttpBaseChannel::GetLaunchServiceWorkerStart(TimeStamp* _retval) { |
4154 | 0 | MOZ_ASSERT(_retval); |
4155 | 0 | *_retval = mLaunchServiceWorkerStart; |
4156 | 0 | return NS_OK; |
4157 | 0 | } |
4158 | | |
4159 | | NS_IMETHODIMP |
4160 | 0 | HttpBaseChannel::SetLaunchServiceWorkerStart(TimeStamp aTimeStamp) { |
4161 | 0 | mLaunchServiceWorkerStart = aTimeStamp; |
4162 | 0 | return NS_OK; |
4163 | 0 | } |
4164 | | |
4165 | | NS_IMETHODIMP |
4166 | 0 | HttpBaseChannel::GetLaunchServiceWorkerEnd(TimeStamp* _retval) { |
4167 | 0 | MOZ_ASSERT(_retval); |
4168 | 0 | *_retval = mLaunchServiceWorkerEnd; |
4169 | 0 | return NS_OK; |
4170 | 0 | } |
4171 | | |
4172 | | NS_IMETHODIMP |
4173 | 0 | HttpBaseChannel::SetLaunchServiceWorkerEnd(TimeStamp aTimeStamp) { |
4174 | 0 | mLaunchServiceWorkerEnd = aTimeStamp; |
4175 | 0 | return NS_OK; |
4176 | 0 | } |
4177 | | |
4178 | | NS_IMETHODIMP |
4179 | 0 | HttpBaseChannel::GetDispatchFetchEventStart(TimeStamp* _retval) { |
4180 | 0 | MOZ_ASSERT(_retval); |
4181 | 0 | *_retval = mDispatchFetchEventStart; |
4182 | 0 | return NS_OK; |
4183 | 0 | } |
4184 | | |
4185 | | NS_IMETHODIMP |
4186 | 0 | HttpBaseChannel::SetDispatchFetchEventStart(TimeStamp aTimeStamp) { |
4187 | 0 | mDispatchFetchEventStart = aTimeStamp; |
4188 | 0 | return NS_OK; |
4189 | 0 | } |
4190 | | |
4191 | | NS_IMETHODIMP |
4192 | 0 | HttpBaseChannel::GetDispatchFetchEventEnd(TimeStamp* _retval) { |
4193 | 0 | MOZ_ASSERT(_retval); |
4194 | 0 | *_retval = mDispatchFetchEventEnd; |
4195 | 0 | return NS_OK; |
4196 | 0 | } |
4197 | | |
4198 | | NS_IMETHODIMP |
4199 | 0 | HttpBaseChannel::SetDispatchFetchEventEnd(TimeStamp aTimeStamp) { |
4200 | 0 | mDispatchFetchEventEnd = aTimeStamp; |
4201 | 0 | return NS_OK; |
4202 | 0 | } |
4203 | | |
4204 | | NS_IMETHODIMP |
4205 | 0 | HttpBaseChannel::GetHandleFetchEventStart(TimeStamp* _retval) { |
4206 | 0 | MOZ_ASSERT(_retval); |
4207 | 0 | *_retval = mHandleFetchEventStart; |
4208 | 0 | return NS_OK; |
4209 | 0 | } |
4210 | | |
4211 | | NS_IMETHODIMP |
4212 | 0 | HttpBaseChannel::SetHandleFetchEventStart(TimeStamp aTimeStamp) { |
4213 | 0 | mHandleFetchEventStart = aTimeStamp; |
4214 | 0 | return NS_OK; |
4215 | 0 | } |
4216 | | |
4217 | | NS_IMETHODIMP |
4218 | 0 | HttpBaseChannel::GetHandleFetchEventEnd(TimeStamp* _retval) { |
4219 | 0 | MOZ_ASSERT(_retval); |
4220 | 0 | *_retval = mHandleFetchEventEnd; |
4221 | 0 | return NS_OK; |
4222 | 0 | } |
4223 | | |
4224 | | NS_IMETHODIMP |
4225 | 0 | HttpBaseChannel::SetHandleFetchEventEnd(TimeStamp aTimeStamp) { |
4226 | 0 | mHandleFetchEventEnd = aTimeStamp; |
4227 | 0 | return NS_OK; |
4228 | 0 | } |
4229 | | |
4230 | | NS_IMETHODIMP |
4231 | 0 | HttpBaseChannel::GetDomainLookupStart(TimeStamp* _retval) { |
4232 | 0 | *_retval = mTransactionTimings.domainLookupStart; |
4233 | 0 | return NS_OK; |
4234 | 0 | } |
4235 | | |
4236 | | NS_IMETHODIMP |
4237 | 0 | HttpBaseChannel::GetDomainLookupEnd(TimeStamp* _retval) { |
4238 | 0 | *_retval = mTransactionTimings.domainLookupEnd; |
4239 | 0 | return NS_OK; |
4240 | 0 | } |
4241 | | |
4242 | | NS_IMETHODIMP |
4243 | 0 | HttpBaseChannel::GetConnectStart(TimeStamp* _retval) { |
4244 | 0 | *_retval = mTransactionTimings.connectStart; |
4245 | 0 | return NS_OK; |
4246 | 0 | } |
4247 | | |
4248 | | NS_IMETHODIMP |
4249 | 0 | HttpBaseChannel::GetTcpConnectEnd(TimeStamp* _retval) { |
4250 | 0 | *_retval = mTransactionTimings.tcpConnectEnd; |
4251 | 0 | return NS_OK; |
4252 | 0 | } |
4253 | | |
4254 | | NS_IMETHODIMP |
4255 | 0 | HttpBaseChannel::GetSecureConnectionStart(TimeStamp* _retval) { |
4256 | 0 | *_retval = mTransactionTimings.secureConnectionStart; |
4257 | 0 | return NS_OK; |
4258 | 0 | } |
4259 | | |
4260 | | NS_IMETHODIMP |
4261 | 0 | HttpBaseChannel::GetConnectEnd(TimeStamp* _retval) { |
4262 | 0 | *_retval = mTransactionTimings.connectEnd; |
4263 | 0 | return NS_OK; |
4264 | 0 | } |
4265 | | |
4266 | | NS_IMETHODIMP |
4267 | 0 | HttpBaseChannel::GetRequestStart(TimeStamp* _retval) { |
4268 | 0 | *_retval = mTransactionTimings.requestStart; |
4269 | 0 | return NS_OK; |
4270 | 0 | } |
4271 | | |
4272 | | NS_IMETHODIMP |
4273 | 0 | HttpBaseChannel::GetResponseStart(TimeStamp* _retval) { |
4274 | 0 | *_retval = mTransactionTimings.responseStart; |
4275 | 0 | return NS_OK; |
4276 | 0 | } |
4277 | | |
4278 | | NS_IMETHODIMP |
4279 | 0 | HttpBaseChannel::GetResponseEnd(TimeStamp* _retval) { |
4280 | 0 | *_retval = mTransactionTimings.responseEnd; |
4281 | 0 | return NS_OK; |
4282 | 0 | } |
4283 | | |
4284 | | NS_IMETHODIMP |
4285 | 0 | HttpBaseChannel::GetCacheReadStart(TimeStamp* _retval) { |
4286 | 0 | *_retval = mCacheReadStart; |
4287 | 0 | return NS_OK; |
4288 | 0 | } |
4289 | | |
4290 | | NS_IMETHODIMP |
4291 | 0 | HttpBaseChannel::GetCacheReadEnd(TimeStamp* _retval) { |
4292 | 0 | *_retval = mCacheReadEnd; |
4293 | 0 | return NS_OK; |
4294 | 0 | } |
4295 | | |
4296 | | NS_IMETHODIMP |
4297 | | HttpBaseChannel::GetInitiatorType(nsAString & aInitiatorType) |
4298 | 0 | { |
4299 | 0 | aInitiatorType = mInitiatorType; |
4300 | 0 | return NS_OK; |
4301 | 0 | } |
4302 | | |
4303 | | NS_IMETHODIMP |
4304 | | HttpBaseChannel::SetInitiatorType(const nsAString & aInitiatorType) |
4305 | 0 | { |
4306 | 0 | mInitiatorType = aInitiatorType; |
4307 | 0 | return NS_OK; |
4308 | 0 | } |
4309 | | |
4310 | | #define IMPL_TIMING_ATTR(name) \ |
4311 | | NS_IMETHODIMP \ |
4312 | 0 | HttpBaseChannel::Get##name##Time(PRTime* _retval) { \ |
4313 | 0 | TimeStamp stamp; \ |
4314 | 0 | Get##name(&stamp); \ |
4315 | 0 | if (stamp.IsNull()) { \ |
4316 | 0 | *_retval = 0; \ |
4317 | 0 | return NS_OK; \ |
4318 | 0 | } \ |
4319 | 0 | *_retval = mChannelCreationTime + \ |
4320 | 0 | (PRTime) ((stamp - mChannelCreationTimestamp).ToSeconds() * 1e6); \ |
4321 | 0 | return NS_OK; \ |
4322 | 0 | } Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetChannelCreationTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetAsyncOpenTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetLaunchServiceWorkerStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetLaunchServiceWorkerEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDispatchFetchEventStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDispatchFetchEventEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetHandleFetchEventStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetHandleFetchEventEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDomainLookupStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDomainLookupEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetConnectStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetTcpConnectEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetSecureConnectionStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetConnectEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetRequestStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetResponseStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetResponseEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetCacheReadStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetCacheReadEndTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetRedirectStartTime(long*) Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetRedirectEndTime(long*) |
4323 | | |
4324 | | IMPL_TIMING_ATTR(ChannelCreation) |
4325 | | IMPL_TIMING_ATTR(AsyncOpen) |
4326 | | IMPL_TIMING_ATTR(LaunchServiceWorkerStart) |
4327 | | IMPL_TIMING_ATTR(LaunchServiceWorkerEnd) |
4328 | | IMPL_TIMING_ATTR(DispatchFetchEventStart) |
4329 | | IMPL_TIMING_ATTR(DispatchFetchEventEnd) |
4330 | | IMPL_TIMING_ATTR(HandleFetchEventStart) |
4331 | | IMPL_TIMING_ATTR(HandleFetchEventEnd) |
4332 | | IMPL_TIMING_ATTR(DomainLookupStart) |
4333 | | IMPL_TIMING_ATTR(DomainLookupEnd) |
4334 | | IMPL_TIMING_ATTR(ConnectStart) |
4335 | | IMPL_TIMING_ATTR(TcpConnectEnd) |
4336 | | IMPL_TIMING_ATTR(SecureConnectionStart) |
4337 | | IMPL_TIMING_ATTR(ConnectEnd) |
4338 | | IMPL_TIMING_ATTR(RequestStart) |
4339 | | IMPL_TIMING_ATTR(ResponseStart) |
4340 | | IMPL_TIMING_ATTR(ResponseEnd) |
4341 | | IMPL_TIMING_ATTR(CacheReadStart) |
4342 | | IMPL_TIMING_ATTR(CacheReadEnd) |
4343 | | IMPL_TIMING_ATTR(RedirectStart) |
4344 | | IMPL_TIMING_ATTR(RedirectEnd) |
4345 | | |
4346 | | #undef IMPL_TIMING_ATTR |
4347 | | |
4348 | | mozilla::dom::PerformanceStorage* |
4349 | | HttpBaseChannel::GetPerformanceStorage() |
4350 | 0 | { |
4351 | 0 | // If performance timing is disabled, there is no need for the Performance |
4352 | 0 | // object anymore. |
4353 | 0 | if (!mTimingEnabled) { |
4354 | 0 | return nullptr; |
4355 | 0 | } |
4356 | 0 | |
4357 | 0 | // There is no point in continuing, since the performance object in the parent |
4358 | 0 | // isn't the same as the one in the child which will be reporting resource performance. |
4359 | 0 | if (XRE_IsE10sParentProcess()) { |
4360 | 0 | return nullptr; |
4361 | 0 | } |
4362 | 0 | |
4363 | 0 | if (!mLoadInfo) { |
4364 | 0 | return nullptr; |
4365 | 0 | } |
4366 | 0 | |
4367 | 0 | // If a custom performance storage is set, let's use it. |
4368 | 0 | mozilla::dom::PerformanceStorage* performanceStorage = mLoadInfo->GetPerformanceStorage(); |
4369 | 0 | if (performanceStorage) { |
4370 | 0 | return performanceStorage; |
4371 | 0 | } |
4372 | 0 | |
4373 | 0 | nsCOMPtr<nsIDocument> loadingDocument; |
4374 | 0 | mLoadInfo->GetLoadingDocument(getter_AddRefs(loadingDocument)); |
4375 | 0 | if (!loadingDocument) { |
4376 | 0 | return nullptr; |
4377 | 0 | } |
4378 | 0 | |
4379 | 0 | // We only add to the document's performance object if it has the same |
4380 | 0 | // principal as the one triggering the load. This is to prevent navigations |
4381 | 0 | // triggered _by_ the iframe from showing up in the parent document's |
4382 | 0 | // performance entries if they have different origins. |
4383 | 0 | if (!mLoadInfo->TriggeringPrincipal()->Equals(loadingDocument->NodePrincipal())) { |
4384 | 0 | return nullptr; |
4385 | 0 | } |
4386 | 0 | |
4387 | 0 | nsCOMPtr<nsPIDOMWindowInner> innerWindow = loadingDocument->GetInnerWindow(); |
4388 | 0 | if (!innerWindow) { |
4389 | 0 | return nullptr; |
4390 | 0 | } |
4391 | 0 | |
4392 | 0 | mozilla::dom::Performance* performance = innerWindow->GetPerformance(); |
4393 | 0 | if (!performance) { |
4394 | 0 | return nullptr; |
4395 | 0 | } |
4396 | 0 | |
4397 | 0 | return performance->AsPerformanceStorage(); |
4398 | 0 | } |
4399 | | |
4400 | | void |
4401 | | HttpBaseChannel::MaybeReportTimingData() |
4402 | 0 | { |
4403 | 0 | mozilla::dom::PerformanceStorage* documentPerformance = GetPerformanceStorage(); |
4404 | 0 | if (documentPerformance) { |
4405 | 0 | documentPerformance->AddEntry(this, this); |
4406 | 0 | } |
4407 | 0 | } |
4408 | | |
4409 | | NS_IMETHODIMP |
4410 | 0 | HttpBaseChannel::SetReportResourceTiming(bool enabled) { |
4411 | 0 | mReportTiming = enabled; |
4412 | 0 | return NS_OK; |
4413 | 0 | } |
4414 | | |
4415 | | NS_IMETHODIMP |
4416 | 0 | HttpBaseChannel::GetReportResourceTiming(bool* _retval) { |
4417 | 0 | *_retval = mReportTiming; |
4418 | 0 | return NS_OK; |
4419 | 0 | } |
4420 | | |
4421 | | nsIURI* |
4422 | | HttpBaseChannel::GetReferringPage() |
4423 | 0 | { |
4424 | 0 | nsCOMPtr<nsPIDOMWindowInner> pDomWindow = GetInnerDOMWindow(); |
4425 | 0 | if (!pDomWindow) { |
4426 | 0 | return nullptr; |
4427 | 0 | } |
4428 | 0 | return pDomWindow->GetDocumentURI(); |
4429 | 0 | } |
4430 | | |
4431 | | nsPIDOMWindowInner* |
4432 | | HttpBaseChannel::GetInnerDOMWindow() |
4433 | 0 | { |
4434 | 0 | nsCOMPtr<nsILoadContext> loadContext; |
4435 | 0 | NS_QueryNotificationCallbacks(this, loadContext); |
4436 | 0 | if (!loadContext) { |
4437 | 0 | return nullptr; |
4438 | 0 | } |
4439 | 0 | nsCOMPtr<mozIDOMWindowProxy> domWindow; |
4440 | 0 | loadContext->GetAssociatedWindow(getter_AddRefs(domWindow)); |
4441 | 0 | if (!domWindow) { |
4442 | 0 | return nullptr; |
4443 | 0 | } |
4444 | 0 | auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow); |
4445 | 0 | if (!pDomWindow) { |
4446 | 0 | return nullptr; |
4447 | 0 | } |
4448 | 0 | nsCOMPtr<nsPIDOMWindowInner> innerWindow = pDomWindow->GetCurrentInnerWindow(); |
4449 | 0 | if (!innerWindow) { |
4450 | 0 | return nullptr; |
4451 | 0 | } |
4452 | 0 | |
4453 | 0 | return innerWindow; |
4454 | 0 | } |
4455 | | |
4456 | | //----------------------------------------------------------------------------- |
4457 | | // HttpBaseChannel::nsIThrottledInputChannel |
4458 | | //----------------------------------------------------------------------------- |
4459 | | |
4460 | | NS_IMETHODIMP |
4461 | | HttpBaseChannel::SetThrottleQueue(nsIInputChannelThrottleQueue* aQueue) |
4462 | 0 | { |
4463 | 0 | if (!XRE_IsParentProcess()) { |
4464 | 0 | return NS_ERROR_FAILURE; |
4465 | 0 | } |
4466 | 0 | |
4467 | 0 | mThrottleQueue = aQueue; |
4468 | 0 | return NS_OK; |
4469 | 0 | } |
4470 | | |
4471 | | NS_IMETHODIMP |
4472 | | HttpBaseChannel::GetThrottleQueue(nsIInputChannelThrottleQueue** aQueue) |
4473 | 0 | { |
4474 | 0 | *aQueue = mThrottleQueue; |
4475 | 0 | return NS_OK; |
4476 | 0 | } |
4477 | | |
4478 | | //------------------------------------------------------------------------------ |
4479 | | |
4480 | | bool |
4481 | | HttpBaseChannel::EnsureRequestContextID() |
4482 | 0 | { |
4483 | 0 | if (mRequestContextID) { |
4484 | 0 | // Already have a request context ID, no need to do the rest of this work |
4485 | 0 | LOG(("HttpBaseChannel::EnsureRequestContextID this=%p id=%" PRIx64, |
4486 | 0 | this, mRequestContextID)); |
4487 | 0 | return true; |
4488 | 0 | } |
4489 | 0 |
|
4490 | 0 | // Find the loadgroup at the end of the chain in order |
4491 | 0 | // to make sure all channels derived from the load group |
4492 | 0 | // use the same connection scope. |
4493 | 0 | nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(mLoadGroup); |
4494 | 0 | if (!childLoadGroup) { |
4495 | 0 | return false; |
4496 | 0 | } |
4497 | 0 | |
4498 | 0 | nsCOMPtr<nsILoadGroup> rootLoadGroup; |
4499 | 0 | childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup)); |
4500 | 0 | if (!rootLoadGroup) { |
4501 | 0 | return false; |
4502 | 0 | } |
4503 | 0 | |
4504 | 0 | // Set the load group connection scope on this channel and its transaction |
4505 | 0 | rootLoadGroup->GetRequestContextID(&mRequestContextID); |
4506 | 0 |
|
4507 | 0 | LOG(("HttpBaseChannel::EnsureRequestContextID this=%p id=%" PRIx64, |
4508 | 0 | this, mRequestContextID)); |
4509 | 0 |
|
4510 | 0 | return true; |
4511 | 0 | } |
4512 | | |
4513 | | bool |
4514 | | HttpBaseChannel::EnsureRequestContext() |
4515 | 0 | { |
4516 | 0 | if (mRequestContext) { |
4517 | 0 | // Already have a request context, no need to do the rest of this work |
4518 | 0 | return true; |
4519 | 0 | } |
4520 | 0 | |
4521 | 0 | if (!EnsureRequestContextID()) { |
4522 | 0 | return false; |
4523 | 0 | } |
4524 | 0 | |
4525 | 0 | nsIRequestContextService* rcsvc = gHttpHandler->GetRequestContextService(); |
4526 | 0 | if (!rcsvc) { |
4527 | 0 | return false; |
4528 | 0 | } |
4529 | 0 | |
4530 | 0 | rcsvc->GetRequestContext(mRequestContextID, getter_AddRefs(mRequestContext)); |
4531 | 0 | if (!mRequestContext) { |
4532 | 0 | return false; |
4533 | 0 | } |
4534 | 0 | |
4535 | 0 | return true; |
4536 | 0 | } |
4537 | | |
4538 | | void |
4539 | | HttpBaseChannel::EnsureTopLevelOuterContentWindowId() |
4540 | 0 | { |
4541 | 0 | if (mTopLevelOuterContentWindowId) { |
4542 | 0 | return; |
4543 | 0 | } |
4544 | 0 | |
4545 | 0 | nsCOMPtr<nsILoadContext> loadContext; |
4546 | 0 | GetCallback(loadContext); |
4547 | 0 | if (!loadContext) { |
4548 | 0 | return; |
4549 | 0 | } |
4550 | 0 | |
4551 | 0 | nsCOMPtr<mozIDOMWindowProxy> topWindow; |
4552 | 0 | loadContext->GetTopWindow(getter_AddRefs(topWindow)); |
4553 | 0 | if (!topWindow) { |
4554 | 0 | return; |
4555 | 0 | } |
4556 | 0 | |
4557 | 0 | mTopLevelOuterContentWindowId = |
4558 | 0 | nsPIDOMWindowOuter::From(topWindow)->WindowID(); |
4559 | 0 | } |
4560 | | |
4561 | | void |
4562 | | HttpBaseChannel::SetCorsPreflightParameters(const nsTArray<nsCString>& aUnsafeHeaders) |
4563 | 0 | { |
4564 | 0 | MOZ_RELEASE_ASSERT(!mRequestObserversCalled); |
4565 | 0 |
|
4566 | 0 | mRequireCORSPreflight = true; |
4567 | 0 | mUnsafeHeaders = aUnsafeHeaders; |
4568 | 0 | } |
4569 | | |
4570 | | void |
4571 | | HttpBaseChannel::SetAltDataForChild(bool aIsForChild) |
4572 | 0 | { |
4573 | 0 | mAltDataForChild = aIsForChild; |
4574 | 0 | } |
4575 | | |
4576 | | NS_IMETHODIMP |
4577 | | HttpBaseChannel::GetBlockAuthPrompt(bool* aValue) |
4578 | 0 | { |
4579 | 0 | if (!aValue) { |
4580 | 0 | return NS_ERROR_FAILURE; |
4581 | 0 | } |
4582 | 0 | |
4583 | 0 | *aValue = mBlockAuthPrompt; |
4584 | 0 | return NS_OK; |
4585 | 0 | } |
4586 | | |
4587 | | NS_IMETHODIMP |
4588 | | HttpBaseChannel::SetBlockAuthPrompt(bool aValue) |
4589 | 0 | { |
4590 | 0 | ENSURE_CALLED_BEFORE_CONNECT(); |
4591 | 0 |
|
4592 | 0 | mBlockAuthPrompt = aValue; |
4593 | 0 | return NS_OK; |
4594 | 0 | } |
4595 | | |
4596 | | NS_IMETHODIMP |
4597 | | HttpBaseChannel::GetConnectionInfoHashKey(nsACString& aConnectionInfoHashKey) |
4598 | 0 | { |
4599 | 0 | if (!mConnectionInfo) { |
4600 | 0 | return NS_ERROR_FAILURE; |
4601 | 0 | } |
4602 | 0 | aConnectionInfoHashKey.Assign(mConnectionInfo->HashKey()); |
4603 | 0 | return NS_OK; |
4604 | 0 | } |
4605 | | |
4606 | | NS_IMETHODIMP |
4607 | | HttpBaseChannel::GetLastRedirectFlags(uint32_t *aValue) |
4608 | 0 | { |
4609 | 0 | NS_ENSURE_ARG(aValue); |
4610 | 0 | *aValue = mLastRedirectFlags; |
4611 | 0 | return NS_OK; |
4612 | 0 | } |
4613 | | |
4614 | | NS_IMETHODIMP |
4615 | | HttpBaseChannel::SetLastRedirectFlags(uint32_t aValue) |
4616 | 0 | { |
4617 | 0 | mLastRedirectFlags = aValue; |
4618 | 0 | return NS_OK; |
4619 | 0 | } |
4620 | | |
4621 | | NS_IMETHODIMP |
4622 | | HttpBaseChannel::GetNavigationStartTimeStamp(TimeStamp* aTimeStamp) |
4623 | 0 | { |
4624 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
4625 | 0 | } |
4626 | | |
4627 | | NS_IMETHODIMP |
4628 | | HttpBaseChannel::SetNavigationStartTimeStamp(TimeStamp aTimeStamp) |
4629 | 0 | { |
4630 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
4631 | 0 | } |
4632 | | |
4633 | | nsresult |
4634 | | HttpBaseChannel::CheckRedirectLimit(uint32_t aRedirectFlags) const |
4635 | 0 | { |
4636 | 0 | if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { |
4637 | 0 | // Some platform features, like Service Workers, depend on internal |
4638 | 0 | // redirects. We should allow some number of internal redirects above |
4639 | 0 | // and beyond the normal redirect limit so these features continue |
4640 | 0 | // to work. |
4641 | 0 | static const int8_t kMinInternalRedirects = 5; |
4642 | 0 |
|
4643 | 0 | if (mInternalRedirectCount >= (mRedirectionLimit + kMinInternalRedirects)) { |
4644 | 0 | LOG(("internal redirection limit reached!\n")); |
4645 | 0 | return NS_ERROR_REDIRECT_LOOP; |
4646 | 0 | } |
4647 | 0 | return NS_OK; |
4648 | 0 | } |
4649 | 0 | |
4650 | 0 | MOZ_ASSERT(aRedirectFlags & (nsIChannelEventSink::REDIRECT_TEMPORARY | |
4651 | 0 | nsIChannelEventSink::REDIRECT_PERMANENT | |
4652 | 0 | nsIChannelEventSink::REDIRECT_STS_UPGRADE)); |
4653 | 0 |
|
4654 | 0 | if (mRedirectCount >= mRedirectionLimit) { |
4655 | 0 | LOG(("redirection limit reached!\n")); |
4656 | 0 | return NS_ERROR_REDIRECT_LOOP; |
4657 | 0 | } |
4658 | 0 |
|
4659 | 0 | return NS_OK; |
4660 | 0 | } |
4661 | | |
4662 | | // NOTE: This function duplicates code from nsBaseChannel. This will go away |
4663 | | // once HTTP uses nsBaseChannel (part of bug 312760) |
4664 | | /* static */ void |
4665 | | HttpBaseChannel::CallTypeSniffers(void *aClosure, const uint8_t *aData, |
4666 | | uint32_t aCount) |
4667 | 0 | { |
4668 | 0 | nsIChannel *chan = static_cast<nsIChannel*>(aClosure); |
4669 | 0 |
|
4670 | 0 | nsAutoCString newType; |
4671 | 0 | NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType); |
4672 | 0 | if (!newType.IsEmpty()) { |
4673 | 0 | chan->SetContentType(newType); |
4674 | 0 | } |
4675 | 0 | } |
4676 | | |
4677 | | template <class T> |
4678 | | static void |
4679 | | ParseServerTimingHeader(const nsAutoPtr<T> &aHeader, |
4680 | | nsTArray<nsCOMPtr<nsIServerTiming>>& aOutput) |
4681 | 0 | { |
4682 | 0 | if (!aHeader) { |
4683 | 0 | return; |
4684 | 0 | } |
4685 | 0 | |
4686 | 0 | nsAutoCString serverTimingHeader; |
4687 | 0 | Unused << aHeader->GetHeader(nsHttp::Server_Timing, serverTimingHeader); |
4688 | 0 | if (serverTimingHeader.IsEmpty()) { |
4689 | 0 | return; |
4690 | 0 | } |
4691 | 0 | |
4692 | 0 | ServerTimingParser parser(serverTimingHeader); |
4693 | 0 | parser.Parse(); |
4694 | 0 |
|
4695 | 0 | nsTArray<nsCOMPtr<nsIServerTiming>> array = parser.TakeServerTimingHeaders(); |
4696 | 0 | aOutput.AppendElements(array); |
4697 | 0 | } Unexecuted instantiation: Unified_cpp_protocol_http0.cpp:void mozilla::net::ParseServerTimingHeader<mozilla::net::nsHttpResponseHead>(nsAutoPtr<mozilla::net::nsHttpResponseHead> const&, nsTArray<nsCOMPtr<nsIServerTiming> >&) Unexecuted instantiation: Unified_cpp_protocol_http0.cpp:void mozilla::net::ParseServerTimingHeader<mozilla::net::nsHttpHeaderArray>(nsAutoPtr<mozilla::net::nsHttpHeaderArray> const&, nsTArray<nsCOMPtr<nsIServerTiming> >&) |
4698 | | |
4699 | | NS_IMETHODIMP |
4700 | | HttpBaseChannel::GetServerTiming(nsIArray **aServerTiming) |
4701 | 0 | { |
4702 | 0 | nsresult rv; |
4703 | 0 | NS_ENSURE_ARG_POINTER(aServerTiming); |
4704 | 0 |
|
4705 | 0 | nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); |
4706 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4707 | 0 |
|
4708 | 0 | nsTArray<nsCOMPtr<nsIServerTiming>> data; |
4709 | 0 | rv = GetNativeServerTiming(data); |
4710 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4711 | 0 |
|
4712 | 0 | for (const auto &entry : data) { |
4713 | 0 | array->AppendElement(entry); |
4714 | 0 | } |
4715 | 0 |
|
4716 | 0 | array.forget(aServerTiming); |
4717 | 0 | return NS_OK; |
4718 | 0 | } |
4719 | | |
4720 | | NS_IMETHODIMP |
4721 | | HttpBaseChannel::GetNativeServerTiming(nsTArray<nsCOMPtr<nsIServerTiming>>& aServerTiming) |
4722 | 0 | { |
4723 | 0 | aServerTiming.Clear(); |
4724 | 0 |
|
4725 | 0 | bool isHTTPS = false; |
4726 | 0 | if (NS_SUCCEEDED(mURI->SchemeIs("https", &isHTTPS)) && isHTTPS) { |
4727 | 0 | ParseServerTimingHeader(mResponseHead, aServerTiming); |
4728 | 0 | ParseServerTimingHeader(mResponseTrailers, aServerTiming); |
4729 | 0 | } |
4730 | 0 |
|
4731 | 0 | return NS_OK; |
4732 | 0 | } |
4733 | | |
4734 | | NS_IMETHODIMP |
4735 | | HttpBaseChannel::CancelForTrackingProtection() |
4736 | 0 | { |
4737 | 0 | return Cancel(NS_ERROR_TRACKING_URI); |
4738 | 0 | } |
4739 | | |
4740 | | } // namespace net |
4741 | | } // namespace mozilla |