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