Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsDocShell.h"
8 :
9 : #include <algorithm>
10 :
11 : #include "mozilla/ArrayUtils.h"
12 : #include "mozilla/Attributes.h"
13 : #include "mozilla/AutoRestore.h"
14 : #include "mozilla/BasePrincipal.h"
15 : #include "mozilla/Casting.h"
16 : #include "mozilla/dom/ContentChild.h"
17 : #include "mozilla/dom/Element.h"
18 : #include "mozilla/dom/PendingGlobalHistoryEntry.h"
19 : #include "mozilla/dom/TabChild.h"
20 : #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
21 : #include "mozilla/dom/ScreenOrientation.h"
22 : #include "mozilla/dom/ToJSValue.h"
23 : #include "mozilla/dom/PermissionMessageUtils.h"
24 : #include "mozilla/dom/workers/ServiceWorkerManager.h"
25 : #include "mozilla/EventStateManager.h"
26 : #include "mozilla/LoadInfo.h"
27 : #include "mozilla/Preferences.h"
28 : #include "mozilla/Services.h"
29 : #include "mozilla/StartupTimeline.h"
30 : #include "mozilla/Telemetry.h"
31 : #include "mozilla/Unused.h"
32 : #include "Navigator.h"
33 : #include "URIUtils.h"
34 : #include "mozilla/dom/DocGroup.h"
35 : #include "mozilla/dom/TabGroup.h"
36 :
37 : #include "nsIContent.h"
38 : #include "nsIContentInlines.h"
39 : #include "nsIDocument.h"
40 : #include "nsIDOMDocument.h"
41 : #include "nsIDOMElement.h"
42 :
43 : #include "nsArray.h"
44 : #include "nsArrayUtils.h"
45 : #include "nsICaptivePortalService.h"
46 : #include "nsIDOMStorage.h"
47 : #include "nsIContentViewer.h"
48 : #include "nsIDocumentLoaderFactory.h"
49 : #include "nsCURILoader.h"
50 : #include "nsDocShellCID.h"
51 : #include "nsDOMCID.h"
52 : #include "nsNetCID.h"
53 : #include "nsNetUtil.h"
54 : #include "mozilla/net/ReferrerPolicy.h"
55 : #include "nsRect.h"
56 : #include "prenv.h"
57 : #include "nsIDOMWindow.h"
58 : #include "nsIGlobalObject.h"
59 : #include "nsIViewSourceChannel.h"
60 : #include "nsIWebBrowserChrome.h"
61 : #include "nsPoint.h"
62 : #include "nsIObserverService.h"
63 : #include "nsIPrompt.h"
64 : #include "nsIAuthPrompt.h"
65 : #include "nsIAuthPrompt2.h"
66 : #include "nsIChannelEventSink.h"
67 : #include "nsIAsyncVerifyRedirectCallback.h"
68 : #include "nsIScriptSecurityManager.h"
69 : #include "nsIScriptObjectPrincipal.h"
70 : #include "nsIScrollableFrame.h"
71 : #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
72 : #include "nsISeekableStream.h"
73 : #include "nsAutoPtr.h"
74 : #include "nsQueryObject.h"
75 : #include "nsIWritablePropertyBag2.h"
76 : #include "nsIAppShell.h"
77 : #include "nsWidgetsCID.h"
78 : #include "nsIInterfaceRequestorUtils.h"
79 : #include "nsView.h"
80 : #include "nsViewManager.h"
81 : #include "nsIScriptChannel.h"
82 : #include "nsITimedChannel.h"
83 : #include "nsIPrivacyTransitionObserver.h"
84 : #include "nsIReflowObserver.h"
85 : #include "nsIScrollObserver.h"
86 : #include "nsIDocShellTreeItem.h"
87 : #include "nsIChannel.h"
88 : #include "IHistory.h"
89 : #include "nsViewSourceHandler.h"
90 : #include "nsWhitespaceTokenizer.h"
91 : #include "nsICookieService.h"
92 : #include "nsIConsoleReportCollector.h"
93 : #include "nsObjectLoadingContent.h"
94 :
95 : // we want to explore making the document own the load group
96 : // so we can associate the document URI with the load group.
97 : // until this point, we have an evil hack:
98 : #include "nsIHttpChannelInternal.h"
99 : #include "nsPILoadGroupInternal.h"
100 :
101 : // Local Includes
102 : #include "nsDocShellLoadInfo.h"
103 : #include "nsCDefaultURIFixup.h"
104 : #include "nsDocShellEnumerator.h"
105 : #include "nsSHistory.h"
106 : #include "nsDocShellEditorData.h"
107 : #include "GeckoProfiler.h"
108 : #include "timeline/JavascriptTimelineMarker.h"
109 :
110 : // Helper Classes
111 : #include "nsError.h"
112 : #include "nsEscape.h"
113 :
114 : // Interfaces Needed
115 : #include "nsIFormPOSTActionChannel.h"
116 : #include "nsIUploadChannel.h"
117 : #include "nsIUploadChannel2.h"
118 : #include "nsIWebProgress.h"
119 : #include "nsILayoutHistoryState.h"
120 : #include "nsITimer.h"
121 : #include "nsISHistoryInternal.h"
122 : #include "nsIPrincipal.h"
123 : #include "NullPrincipal.h"
124 : #include "nsISHEntry.h"
125 : #include "nsIWindowWatcher.h"
126 : #include "nsIPromptFactory.h"
127 : #include "nsITransportSecurityInfo.h"
128 : #include "nsINode.h"
129 : #include "nsINSSErrorsService.h"
130 : #include "nsIApplicationCacheChannel.h"
131 : #include "nsIApplicationCacheContainer.h"
132 : #include "nsStreamUtils.h"
133 : #include "nsIController.h"
134 : #include "nsPICommandUpdater.h"
135 : #include "nsIDOMHTMLAnchorElement.h"
136 : #include "nsIWebBrowserChrome3.h"
137 : #include "nsITabChild.h"
138 : #include "nsISiteSecurityService.h"
139 : #include "nsStructuredCloneContainer.h"
140 : #include "nsIStructuredCloneContainer.h"
141 : #include "nsISupportsPrimitives.h"
142 : #ifdef MOZ_PLACES
143 : #include "nsIFaviconService.h"
144 : #include "mozIPlacesPendingOperation.h"
145 : #include "mozIAsyncFavicons.h"
146 : #endif
147 : #include "nsINetworkPredictor.h"
148 :
149 : // Editor-related
150 : #include "nsIEditingSession.h"
151 :
152 : #include "nsPIDOMWindow.h"
153 : #include "nsGlobalWindow.h"
154 : #include "nsPIWindowRoot.h"
155 : #include "nsICachingChannel.h"
156 : #include "nsIMultiPartChannel.h"
157 : #include "nsIWyciwygChannel.h"
158 :
159 : // For reporting errors with the console service.
160 : // These can go away if error reporting is propagated up past nsDocShell.
161 : #include "nsIScriptError.h"
162 :
163 : // used to dispatch urls to default protocol handlers
164 : #include "nsCExternalHandlerService.h"
165 : #include "nsIExternalProtocolService.h"
166 :
167 : #include "nsFocusManager.h"
168 :
169 : #include "nsITextToSubURI.h"
170 :
171 : #include "nsIJARChannel.h"
172 :
173 : #include "mozilla/Logging.h"
174 :
175 : #include "nsISelectionDisplay.h"
176 :
177 : #include "nsIGlobalHistory2.h"
178 :
179 : #include "nsIFrame.h"
180 : #include "nsSubDocumentFrame.h"
181 :
182 : // for embedding
183 : #include "nsIWebBrowserChromeFocus.h"
184 :
185 : #if NS_PRINT_PREVIEW
186 : #include "nsIDocumentViewerPrint.h"
187 : #include "nsIWebBrowserPrint.h"
188 : #endif
189 :
190 : #include "nsContentUtils.h"
191 : #include "nsIContentSecurityPolicy.h"
192 : #include "nsILoadInfo.h"
193 : #include "nsSandboxFlags.h"
194 : #include "nsXULAppAPI.h"
195 : #include "nsDOMNavigationTiming.h"
196 : #include "nsISecurityUITelemetry.h"
197 : #include "nsDSURIContentListener.h"
198 : #include "nsDocShellLoadTypes.h"
199 : #include "nsDocShellTransferableHooks.h"
200 : #include "nsICommandManager.h"
201 : #include "nsIDOMNode.h"
202 : #include "nsIClassOfService.h"
203 : #include "nsIDocShellTreeOwner.h"
204 : #include "nsIHttpChannel.h"
205 : #include "nsIIDNService.h"
206 : #include "nsIInputStreamChannel.h"
207 : #include "nsINestedURI.h"
208 : #include "nsIOService.h"
209 : #include "nsISHContainer.h"
210 : #include "nsISHistory.h"
211 : #include "nsISecureBrowserUI.h"
212 : #include "nsISocketProvider.h"
213 : #include "nsIStringBundle.h"
214 : #include "nsIURIFixup.h"
215 : #include "nsIURILoader.h"
216 : #include "nsIURL.h"
217 : #include "nsIWebBrowserFind.h"
218 : #include "nsIWidget.h"
219 : #include "mozilla/dom/PerformanceNavigation.h"
220 : #include "mozilla/dom/ScriptSettings.h"
221 : #include "mozilla/Encoding.h"
222 :
223 : #ifdef MOZ_TOOLKIT_SEARCH
224 : #include "nsIBrowserSearchService.h"
225 : #endif
226 :
227 : #include "mozIThirdPartyUtil.h"
228 :
229 : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
230 :
231 : #if defined(DEBUG_bryner) || defined(DEBUG_chb)
232 : //#define DEBUG_DOCSHELL_FOCUS
233 : #define DEBUG_PAGE_CACHE
234 : #endif
235 :
236 : #ifdef XP_WIN
237 : #include <process.h>
238 : #define getpid _getpid
239 : #else
240 : #include <unistd.h> // for getpid()
241 : #endif
242 :
243 : using namespace mozilla;
244 : using namespace mozilla::dom;
245 : using mozilla::dom::workers::ServiceWorkerManager;
246 :
247 : // True means sUseErrorPages has been added to
248 : // preferences var cache.
249 : static bool gAddedPreferencesVarCache = false;
250 :
251 : bool nsDocShell::sUseErrorPages = false;
252 :
253 : // Number of documents currently loading
254 : static int32_t gNumberOfDocumentsLoading = 0;
255 :
256 : // Global count of existing docshells.
257 : static int32_t gDocShellCount = 0;
258 :
259 : // Global count of docshells with the private attribute set
260 : static uint32_t gNumberOfPrivateDocShells = 0;
261 :
262 : // Global reference to the URI fixup service.
263 : nsIURIFixup* nsDocShell::sURIFixup = 0;
264 :
265 : // True means we validate window targets to prevent frameset
266 : // spoofing. Initialize this to a non-bolean value so we know to check
267 : // the pref on the creation of the first docshell.
268 : static uint32_t gValidateOrigin = 0xffffffff;
269 :
270 : // Hint for native dispatch of events on how long to delay after
271 : // all documents have loaded in milliseconds before favoring normal
272 : // native event dispatch priorites over performance
273 : // Can be overridden with docshell.event_starvation_delay_hint pref.
274 : #define NS_EVENT_STARVATION_DELAY_HINT 2000
275 :
276 : #ifdef DEBUG
277 : static mozilla::LazyLogModule gDocShellLog("nsDocShell");
278 : #endif
279 : static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");;
280 :
281 : const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
282 : const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
283 :
284 : static void
285 4 : FavorPerformanceHint(bool aPerfOverStarvation)
286 : {
287 8 : nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
288 4 : if (appShell) {
289 8 : appShell->FavorPerformanceHint(
290 : aPerfOverStarvation,
291 : Preferences::GetUint("docshell.event_starvation_delay_hint",
292 8 : NS_EVENT_STARVATION_DELAY_HINT));
293 : }
294 4 : }
295 :
296 : //*****************************************************************************
297 : // <a ping> support
298 : //*****************************************************************************
299 :
300 : #define PREF_PINGS_ENABLED "browser.send_pings"
301 : #define PREF_PINGS_MAX_PER_LINK "browser.send_pings.max_per_link"
302 : #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
303 :
304 : // Check prefs to see if pings are enabled and if so what restrictions might
305 : // be applied.
306 : //
307 : // @param maxPerLink
308 : // This parameter returns the number of pings that are allowed per link click
309 : //
310 : // @param requireSameHost
311 : // This parameter returns true if pings are restricted to the same host as
312 : // the document in which the click occurs. If the same host restriction is
313 : // imposed, then we still allow for pings to cross over to different
314 : // protocols and ports for flexibility and because it is not possible to send
315 : // a ping via FTP.
316 : //
317 : // @returns
318 : // true if pings are enabled and false otherwise.
319 : //
320 : static bool
321 0 : PingsEnabled(int32_t* aMaxPerLink, bool* aRequireSameHost)
322 : {
323 0 : bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false);
324 :
325 0 : *aMaxPerLink = 1;
326 0 : *aRequireSameHost = true;
327 :
328 0 : if (allow) {
329 0 : Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, aMaxPerLink);
330 0 : Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, aRequireSameHost);
331 : }
332 :
333 0 : return allow;
334 : }
335 :
336 : typedef void (*ForEachPingCallback)(void* closure, nsIContent* content,
337 : nsIURI* uri, nsIIOService* ios);
338 :
339 : static bool
340 0 : IsElementAnchor(nsIContent* aContent)
341 : {
342 : // Make sure we are dealing with either an <A> or <AREA> element in the HTML
343 : // or XHTML namespace.
344 0 : return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area);
345 : }
346 :
347 : static void
348 0 : ForEachPing(nsIContent* aContent, ForEachPingCallback aCallback, void* aClosure)
349 : {
350 : // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
351 : // since we'd still need to parse the resulting string. Instead, we
352 : // just parse the raw attribute. It might be nice if the content node
353 : // implemented an interface that exposed an enumeration of nsIURIs.
354 :
355 : // Make sure we are dealing with either an <A> or <AREA> element in the HTML
356 : // or XHTML namespace.
357 0 : if (!IsElementAnchor(aContent)) {
358 0 : return;
359 : }
360 :
361 0 : nsCOMPtr<nsIAtom> pingAtom = NS_Atomize("ping");
362 0 : if (!pingAtom) {
363 0 : return;
364 : }
365 :
366 0 : nsAutoString value;
367 0 : aContent->GetAttr(kNameSpaceID_None, pingAtom, value);
368 0 : if (value.IsEmpty()) {
369 0 : return;
370 : }
371 :
372 0 : nsCOMPtr<nsIIOService> ios = do_GetIOService();
373 0 : if (!ios) {
374 0 : return;
375 : }
376 :
377 0 : nsIDocument* doc = aContent->OwnerDoc();
378 0 : nsAutoCString charset;
379 0 : doc->GetDocumentCharacterSet()->Name(charset);
380 :
381 0 : nsWhitespaceTokenizer tokenizer(value);
382 :
383 0 : while (tokenizer.hasMoreTokens()) {
384 0 : nsCOMPtr<nsIURI> uri, baseURI = aContent->GetBaseURI();
385 0 : ios->NewURI(NS_ConvertUTF16toUTF8(tokenizer.nextToken()),
386 0 : charset.get(), baseURI, getter_AddRefs(uri));
387 : // if we can't generate a valid URI, then there is nothing to do
388 0 : if (!uri) {
389 0 : continue;
390 : }
391 : // Explicitly not allow loading data: URIs
392 : bool isDataScheme =
393 0 : (NS_SUCCEEDED(uri->SchemeIs("data", &isDataScheme)) && isDataScheme);
394 :
395 0 : if (!isDataScheme) {
396 0 : aCallback(aClosure, aContent, uri, ios);
397 : }
398 : }
399 : }
400 :
401 : //----------------------------------------------------------------------
402 :
403 : // We wait this many milliseconds before killing the ping channel...
404 : #define PING_TIMEOUT 10000
405 :
406 : static void
407 0 : OnPingTimeout(nsITimer* aTimer, void* aClosure)
408 : {
409 0 : nsILoadGroup* loadGroup = static_cast<nsILoadGroup*>(aClosure);
410 0 : if (loadGroup) {
411 0 : loadGroup->Cancel(NS_ERROR_ABORT);
412 : }
413 0 : }
414 :
415 : class nsPingListener final
416 : : public nsIStreamListener
417 : {
418 : public:
419 : NS_DECL_ISUPPORTS
420 : NS_DECL_NSIREQUESTOBSERVER
421 : NS_DECL_NSISTREAMLISTENER
422 :
423 0 : nsPingListener()
424 0 : {
425 0 : }
426 :
427 0 : void SetLoadGroup(nsILoadGroup* aLoadGroup) {
428 0 : mLoadGroup = aLoadGroup;
429 0 : }
430 :
431 : nsresult StartTimeout(DocGroup* aDocGroup);
432 :
433 : private:
434 : ~nsPingListener();
435 :
436 : nsCOMPtr<nsILoadGroup> mLoadGroup;
437 : nsCOMPtr<nsITimer> mTimer;
438 : };
439 :
440 0 : NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver)
441 :
442 0 : nsPingListener::~nsPingListener()
443 : {
444 0 : if (mTimer) {
445 0 : mTimer->Cancel();
446 0 : mTimer = nullptr;
447 : }
448 0 : }
449 :
450 : nsresult
451 0 : nsPingListener::StartTimeout(DocGroup* aDocGroup)
452 : {
453 0 : NS_ENSURE_ARG(aDocGroup);
454 :
455 0 : nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
456 0 : timer->SetTarget(aDocGroup->EventTargetFor(TaskCategory::Network));
457 :
458 0 : if (timer) {
459 : nsresult rv =
460 0 : timer->InitWithNamedFuncCallback(OnPingTimeout,
461 : mLoadGroup,
462 : PING_TIMEOUT,
463 : nsITimer::TYPE_ONE_SHOT,
464 0 : "nsPingListener::StartTimeout");
465 0 : if (NS_SUCCEEDED(rv)) {
466 0 : mTimer = timer;
467 0 : return NS_OK;
468 : }
469 : }
470 :
471 0 : return NS_ERROR_OUT_OF_MEMORY;
472 : }
473 :
474 : NS_IMETHODIMP
475 0 : nsPingListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
476 : {
477 0 : return NS_OK;
478 : }
479 :
480 : NS_IMETHODIMP
481 0 : nsPingListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
482 : nsIInputStream* aStream, uint64_t aOffset,
483 : uint32_t aCount)
484 : {
485 : uint32_t result;
486 0 : return aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &result);
487 : }
488 :
489 : NS_IMETHODIMP
490 0 : nsPingListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
491 : nsresult aStatus)
492 : {
493 0 : mLoadGroup = nullptr;
494 :
495 0 : if (mTimer) {
496 0 : mTimer->Cancel();
497 0 : mTimer = nullptr;
498 : }
499 :
500 0 : return NS_OK;
501 : }
502 :
503 : struct MOZ_STACK_CLASS SendPingInfo
504 : {
505 : int32_t numPings;
506 : int32_t maxPings;
507 : bool requireSameHost;
508 : nsIURI* target;
509 : nsIURI* referrer;
510 : nsIDocShell* docShell;
511 : uint32_t referrerPolicy;
512 : };
513 :
514 : static void
515 0 : SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
516 : nsIIOService* aIOService)
517 : {
518 0 : SendPingInfo* info = static_cast<SendPingInfo*>(aClosure);
519 0 : if (info->maxPings > -1 && info->numPings >= info->maxPings) {
520 0 : return;
521 : }
522 :
523 0 : nsIDocument* doc = aContent->OwnerDoc();
524 :
525 0 : nsCOMPtr<nsIChannel> chan;
526 0 : NS_NewChannel(getter_AddRefs(chan),
527 : aURI,
528 : doc,
529 0 : info->requireSameHost
530 : ? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
531 : : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
532 : nsIContentPolicy::TYPE_PING,
533 : nullptr, // aLoadGroup
534 : nullptr, // aCallbacks
535 : nsIRequest::LOAD_NORMAL, // aLoadFlags,
536 0 : aIOService);
537 :
538 0 : if (!chan) {
539 0 : return;
540 : }
541 :
542 : // Don't bother caching the result of this URI load, but do not exempt
543 : // it from Safe Browsing.
544 0 : chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING | nsIChannel::LOAD_CLASSIFY_URI);
545 :
546 0 : nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
547 0 : if (!httpChan) {
548 0 : return;
549 : }
550 :
551 : // This is needed in order for 3rd-party cookie blocking to work.
552 0 : nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
553 : nsresult rv;
554 0 : if (httpInternal) {
555 0 : rv = httpInternal->SetDocumentURI(doc->GetDocumentURI());
556 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
557 : }
558 :
559 0 : rv = httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
560 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
561 :
562 : // Remove extraneous request headers (to reduce request size)
563 0 : rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
564 0 : EmptyCString(), false);
565 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
566 0 : rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
567 0 : EmptyCString(), false);
568 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
569 0 : rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
570 0 : EmptyCString(), false);
571 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
572 :
573 : // Always send a Ping-To header.
574 0 : nsAutoCString pingTo;
575 0 : if (NS_SUCCEEDED(info->target->GetSpec(pingTo))) {
576 0 : rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
577 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
578 : }
579 :
580 : nsCOMPtr<nsIScriptSecurityManager> sm =
581 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
582 :
583 0 : if (sm && info->referrer) {
584 : bool referrerIsSecure;
585 0 : uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
586 0 : rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
587 :
588 : // Default to sending less data if NS_URIChainHasFlags() fails.
589 0 : referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
590 :
591 : bool sameOrigin =
592 0 : NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, aURI, false));
593 :
594 : // If both the address of the document containing the hyperlink being
595 : // audited and "ping URL" have the same origin or the document containing
596 : // the hyperlink being audited was not retrieved over an encrypted
597 : // connection, send a Ping-From header.
598 0 : if (sameOrigin || !referrerIsSecure) {
599 0 : nsAutoCString pingFrom;
600 0 : if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom))) {
601 0 : rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"),
602 0 : pingFrom, false);
603 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
604 : }
605 : }
606 :
607 : // If the document containing the hyperlink being audited was not retrieved
608 : // over an encrypted connection and its address does not have the same
609 : // origin as "ping URL", send a referrer.
610 0 : if (!sameOrigin && !referrerIsSecure) {
611 0 : rv = httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
612 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
613 : }
614 : }
615 :
616 0 : nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan);
617 0 : if (!uploadChan) {
618 0 : return;
619 : }
620 :
621 0 : NS_NAMED_LITERAL_CSTRING(uploadData, "PING");
622 :
623 0 : nsCOMPtr<nsIInputStream> uploadStream;
624 0 : NS_NewPostDataStream(getter_AddRefs(uploadStream), false, uploadData);
625 0 : if (!uploadStream) {
626 0 : return;
627 : }
628 :
629 0 : uploadChan->ExplicitSetUploadStream(uploadStream,
630 0 : NS_LITERAL_CSTRING("text/ping"),
631 0 : uploadData.Length(),
632 0 : NS_LITERAL_CSTRING("POST"), false);
633 :
634 : // The channel needs to have a loadgroup associated with it, so that we can
635 : // cancel the channel and any redirected channels it may create.
636 0 : nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
637 0 : if (!loadGroup) {
638 0 : return;
639 : }
640 0 : nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(info->docShell);
641 0 : loadGroup->SetNotificationCallbacks(callbacks);
642 0 : chan->SetLoadGroup(loadGroup);
643 :
644 0 : RefPtr<nsPingListener> pingListener = new nsPingListener();
645 0 : chan->AsyncOpen2(pingListener);
646 :
647 : // Even if AsyncOpen failed, we still count this as a successful ping. It's
648 : // possible that AsyncOpen may have failed after triggering some background
649 : // process that may have written something to the network.
650 0 : info->numPings++;
651 :
652 : // Prevent ping requests from stalling and never being garbage collected...
653 0 : if (NS_FAILED(pingListener->StartTimeout(doc->GetDocGroup()))) {
654 : // If we failed to setup the timer, then we should just cancel the channel
655 : // because we won't be able to ensure that it goes away in a timely manner.
656 0 : chan->Cancel(NS_ERROR_ABORT);
657 0 : return;
658 : }
659 : // if the channel openend successfully, then make the pingListener hold
660 : // a strong reference to the loadgroup which is released in ::OnStopRequest
661 0 : pingListener->SetLoadGroup(loadGroup);
662 : }
663 :
664 : // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
665 : static void
666 0 : DispatchPings(nsIDocShell* aDocShell,
667 : nsIContent* aContent,
668 : nsIURI* aTarget,
669 : nsIURI* aReferrer,
670 : uint32_t aReferrerPolicy)
671 : {
672 : SendPingInfo info;
673 :
674 0 : if (!PingsEnabled(&info.maxPings, &info.requireSameHost)) {
675 0 : return;
676 : }
677 0 : if (info.maxPings == 0) {
678 0 : return;
679 : }
680 :
681 0 : info.numPings = 0;
682 0 : info.target = aTarget;
683 0 : info.referrer = aReferrer;
684 0 : info.referrerPolicy = aReferrerPolicy;
685 0 : info.docShell = aDocShell;
686 :
687 0 : ForEachPing(aContent, SendPing, &info);
688 : }
689 :
690 : static nsDOMNavigationTiming::Type
691 6 : ConvertLoadTypeToNavigationType(uint32_t aLoadType)
692 : {
693 : // Not initialized, assume it's normal load.
694 6 : if (aLoadType == 0) {
695 0 : aLoadType = LOAD_NORMAL;
696 : }
697 :
698 6 : auto result = nsDOMNavigationTiming::TYPE_RESERVED;
699 6 : switch (aLoadType) {
700 : case LOAD_NORMAL:
701 : case LOAD_NORMAL_EXTERNAL:
702 : case LOAD_NORMAL_BYPASS_CACHE:
703 : case LOAD_NORMAL_BYPASS_PROXY:
704 : case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
705 : case LOAD_NORMAL_REPLACE:
706 : case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
707 : case LOAD_LINK:
708 : case LOAD_STOP_CONTENT:
709 : case LOAD_REPLACE_BYPASS_CACHE:
710 6 : result = nsDOMNavigationTiming::TYPE_NAVIGATE;
711 6 : break;
712 : case LOAD_HISTORY:
713 0 : result = nsDOMNavigationTiming::TYPE_BACK_FORWARD;
714 0 : break;
715 : case LOAD_RELOAD_NORMAL:
716 : case LOAD_RELOAD_CHARSET_CHANGE:
717 : case LOAD_RELOAD_BYPASS_CACHE:
718 : case LOAD_RELOAD_BYPASS_PROXY:
719 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
720 : case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
721 0 : result = nsDOMNavigationTiming::TYPE_RELOAD;
722 0 : break;
723 : case LOAD_STOP_CONTENT_AND_REPLACE:
724 : case LOAD_REFRESH:
725 : case LOAD_BYPASS_HISTORY:
726 : case LOAD_ERROR_PAGE:
727 : case LOAD_PUSHSTATE:
728 0 : result = nsDOMNavigationTiming::TYPE_RESERVED;
729 0 : break;
730 : default:
731 : // NS_NOTREACHED("Unexpected load type value");
732 0 : result = nsDOMNavigationTiming::TYPE_RESERVED;
733 0 : break;
734 : }
735 :
736 6 : return result;
737 : }
738 :
739 : static nsISHEntry* GetRootSHEntry(nsISHEntry* aEntry);
740 :
741 : static void
742 0 : IncreasePrivateDocShellCount()
743 : {
744 0 : gNumberOfPrivateDocShells++;
745 0 : if (gNumberOfPrivateDocShells > 1 ||
746 0 : !XRE_IsContentProcess()) {
747 0 : return;
748 : }
749 :
750 0 : mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
751 0 : cc->SendPrivateDocShellsExist(true);
752 : }
753 :
754 : static void
755 0 : DecreasePrivateDocShellCount()
756 : {
757 0 : MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
758 0 : gNumberOfPrivateDocShells--;
759 0 : if (!gNumberOfPrivateDocShells) {
760 0 : if (XRE_IsContentProcess()) {
761 0 : dom::ContentChild* cc = dom::ContentChild::GetSingleton();
762 0 : cc->SendPrivateDocShellsExist(false);
763 0 : return;
764 : }
765 :
766 0 : nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
767 0 : if (obsvc) {
768 0 : obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
769 : }
770 : }
771 : }
772 :
773 5 : nsDocShell::nsDocShell()
774 : : nsDocLoader()
775 : , mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto)
776 : , mReferrerPolicy(0)
777 : , mFailedLoadType(0)
778 : , mTreeOwner(nullptr)
779 : , mChromeEventHandler(nullptr)
780 : , mCharsetReloadState(eCharsetReloadInit)
781 : , mChildOffset(0)
782 : , mBusyFlags(BUSY_FLAGS_NONE)
783 : , mAppType(nsIDocShell::APP_TYPE_UNKNOWN)
784 : , mLoadType(0)
785 : , mMarginWidth(-1)
786 : , mMarginHeight(-1)
787 : , mItemType(typeContent)
788 : , mPreviousTransIndex(-1)
789 : , mLoadedTransIndex(-1)
790 : , mSandboxFlags(0)
791 : , mOrientationLock(eScreenOrientation_None)
792 : , mFullscreenAllowed(CHECK_ATTRIBUTES)
793 : , mCreated(false)
794 : , mAllowSubframes(true)
795 : , mAllowPlugins(true)
796 : , mAllowJavascript(true)
797 : , mAllowMetaRedirects(true)
798 : , mAllowImages(true)
799 : , mAllowMedia(true)
800 : , mAllowDNSPrefetch(true)
801 : , mAllowWindowControl(true)
802 : , mAllowContentRetargeting(true)
803 : , mAllowContentRetargetingOnChildren(true)
804 : , mUseErrorPages(false)
805 : , mObserveErrorPages(true)
806 : , mAllowAuth(true)
807 : , mAllowKeywordFixup(false)
808 : , mIsOffScreenBrowser(false)
809 : , mIsActive(true)
810 : , mDisableMetaRefreshWhenInactive(false)
811 : , mIsPrerendered(false)
812 : , mIsAppTab(false)
813 : , mUseGlobalHistory(false)
814 : , mUseRemoteTabs(false)
815 : , mUseTrackingProtection(false)
816 : , mDeviceSizeIsPageSize(false)
817 : , mWindowDraggingAllowed(false)
818 : , mInFrameSwap(false)
819 : , mInheritPrivateBrowsingId(true)
820 : , mCanExecuteScripts(false)
821 : , mFiredUnloadEvent(false)
822 : , mEODForCurrentDocument(false)
823 : , mURIResultedInDocument(false)
824 : , mIsBeingDestroyed(false)
825 : , mIsExecutingOnLoadHandler(false)
826 : , mIsPrintingOrPP(false)
827 : , mSavingOldViewer(false)
828 : , mDynamicallyCreated(false)
829 : , mAffectPrivateSessionLifetime(true)
830 : , mInvisible(false)
831 : , mHasLoadedNonBlankURI(false)
832 : , mBlankTiming(false)
833 : , mCreatingDocument(false)
834 : #ifdef DEBUG
835 : , mInEnsureScriptEnv(false)
836 : #endif
837 : , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL)
838 : , mFrameType(FRAME_TYPE_REGULAR)
839 : , mPrivateBrowsingId(0)
840 : , mForcedCharset(nullptr)
841 : , mParentCharset(nullptr)
842 : , mParentCharsetSource(0)
843 : , mJSRunToCompletionDepth(0)
844 5 : , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE)
845 : {
846 5 : AssertOriginAttributesMatchPrivateBrowsing();
847 :
848 5 : nsContentUtils::GenerateUUIDInPlace(mHistoryID);
849 :
850 5 : if (gDocShellCount++ == 0) {
851 2 : NS_ASSERTION(sURIFixup == nullptr,
852 : "Huh, sURIFixup not null in first nsDocShell ctor!");
853 :
854 2 : CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
855 : }
856 :
857 5 : MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
858 :
859 : #ifdef DEBUG
860 : // We're counting the number of |nsDocShells| to help find leaks
861 5 : ++gNumberOfDocShells;
862 5 : if (!PR_GetEnv("MOZ_QUIET")) {
863 5 : printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %s]\n",
864 : (void*)this,
865 : gNumberOfDocShells,
866 : getpid(),
867 10 : nsIDToCString(mHistoryID).get());
868 : }
869 : #endif
870 5 : }
871 :
872 0 : nsDocShell::~nsDocShell()
873 : {
874 0 : MOZ_ASSERT(!mObserved);
875 :
876 0 : Destroy();
877 :
878 0 : nsCOMPtr<nsISHistoryInternal> shPrivate(do_QueryInterface(mSessionHistory));
879 0 : if (shPrivate) {
880 0 : shPrivate->SetRootDocShell(nullptr);
881 : }
882 :
883 0 : if (--gDocShellCount == 0) {
884 0 : NS_IF_RELEASE(sURIFixup);
885 : }
886 :
887 0 : MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this));
888 :
889 : #ifdef DEBUG
890 : // We're counting the number of |nsDocShells| to help find leaks
891 0 : --gNumberOfDocShells;
892 0 : if (!PR_GetEnv("MOZ_QUIET")) {
893 0 : printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %s]\n",
894 : (void*)this,
895 : gNumberOfDocShells,
896 : getpid(),
897 0 : nsIDToCString(mHistoryID).get());
898 : }
899 : #endif
900 0 : }
901 :
902 : nsresult
903 5 : nsDocShell::Init()
904 : {
905 5 : nsresult rv = nsDocLoader::Init();
906 5 : NS_ENSURE_SUCCESS(rv, rv);
907 :
908 5 : NS_ASSERTION(mLoadGroup, "Something went wrong!");
909 :
910 5 : mContentListener = new nsDSURIContentListener(this);
911 5 : rv = mContentListener->Init();
912 5 : NS_ENSURE_SUCCESS(rv, rv);
913 :
914 : // We want to hold a strong ref to the loadgroup, so it better hold a weak
915 : // ref to us... use an InterfaceRequestorProxy to do this.
916 : nsCOMPtr<nsIInterfaceRequestor> proxy =
917 10 : new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
918 5 : mLoadGroup->SetNotificationCallbacks(proxy);
919 :
920 5 : rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
921 5 : NS_ENSURE_SUCCESS(rv, rv);
922 :
923 : // Add as |this| a progress listener to itself. A little weird, but
924 : // simpler than reproducing all the listener-notification logic in
925 : // overrides of the various methods via which nsDocLoader can be
926 : // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
927 10 : return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
928 10 : nsIWebProgress::NOTIFY_STATE_NETWORK);
929 : }
930 :
931 : void
932 9 : nsDocShell::DestroyChildren()
933 : {
934 18 : nsCOMPtr<nsIDocShellTreeItem> shell;
935 18 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
936 9 : while (iter.HasMore()) {
937 0 : shell = do_QueryObject(iter.GetNext());
938 0 : NS_ASSERTION(shell, "docshell has null child");
939 :
940 0 : if (shell) {
941 0 : shell->SetTreeOwner(nullptr);
942 : }
943 : }
944 :
945 9 : nsDocLoader::DestroyChildren();
946 9 : }
947 :
948 6958 : NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
949 6885 : NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
950 :
951 6011 : NS_INTERFACE_MAP_BEGIN(nsDocShell)
952 6011 : NS_INTERFACE_MAP_ENTRY(nsIDocShell)
953 5171 : NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
954 4584 : NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
955 4110 : NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
956 4037 : NS_INTERFACE_MAP_ENTRY(nsIScrollable)
957 3985 : NS_INTERFACE_MAP_ENTRY(nsITextScroll)
958 3984 : NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
959 3984 : NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
960 3984 : NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
961 3902 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
962 3882 : NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
963 3882 : NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
964 3882 : NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
965 3882 : NS_INTERFACE_MAP_ENTRY(nsILoadContext)
966 2565 : NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
967 2565 : NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
968 2551 : NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
969 2551 : NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
970 2549 : NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
971 2541 : NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
972 2541 : NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
973 :
974 : NS_IMETHODIMP
975 971 : nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
976 : {
977 971 : NS_PRECONDITION(aSink, "null out param");
978 :
979 971 : *aSink = nullptr;
980 :
981 971 : if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
982 0 : NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
983 0 : *aSink = mCommandManager;
984 971 : } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
985 18 : *aSink = mContentListener;
986 2859 : } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
987 1906 : aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
988 1815 : aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
989 1628 : aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
990 1530 : aIID.Equals(NS_GET_IID(nsIDOMWindow)) ||
991 1906 : aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) &&
992 189 : NS_SUCCEEDED(EnsureScriptEnvironment())) {
993 189 : return mScriptGlobal->QueryInterface(aIID, aSink);
994 770 : } else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
995 6 : NS_SUCCEEDED(EnsureContentViewer())) {
996 6 : mContentViewer->GetDOMDocument((nsIDOMDocument**)aSink);
997 6 : return *aSink ? NS_OK : NS_NOINTERFACE;
998 758 : } else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
999 0 : NS_SUCCEEDED(EnsureContentViewer())) {
1000 0 : nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
1001 0 : doc.forget(aSink);
1002 0 : return *aSink ? NS_OK : NS_NOINTERFACE;
1003 758 : } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
1004 3 : *aSink = nullptr;
1005 :
1006 : // Return application cache associated with this docshell, if any
1007 :
1008 6 : nsCOMPtr<nsIContentViewer> contentViewer;
1009 3 : GetContentViewer(getter_AddRefs(contentViewer));
1010 3 : if (!contentViewer) {
1011 0 : return NS_ERROR_NO_INTERFACE;
1012 : }
1013 :
1014 6 : nsCOMPtr<nsIDOMDocument> domDoc;
1015 3 : contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
1016 3 : NS_ASSERTION(domDoc, "Should have a document.");
1017 3 : if (!domDoc) {
1018 0 : return NS_ERROR_NO_INTERFACE;
1019 : }
1020 :
1021 : #if defined(DEBUG)
1022 3 : MOZ_LOG(gDocShellLog, LogLevel::Debug,
1023 : ("nsDocShell[%p]: returning app cache container %p",
1024 : this, domDoc.get()));
1025 : #endif
1026 3 : return domDoc->QueryInterface(aIID, aSink);
1027 755 : } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
1028 0 : NS_SUCCEEDED(EnsureScriptEnvironment())) {
1029 : nsresult rv;
1030 : nsCOMPtr<nsIWindowWatcher> wwatch =
1031 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
1032 0 : NS_ENSURE_SUCCESS(rv, rv);
1033 :
1034 : // Get the an auth prompter for our window so that the parenting
1035 : // of the dialogs works as it should when using tabs.
1036 : nsIPrompt* prompt;
1037 0 : rv = wwatch->GetNewPrompter(mScriptGlobal->AsOuter(), &prompt);
1038 0 : NS_ENSURE_SUCCESS(rv, rv);
1039 :
1040 0 : *aSink = prompt;
1041 0 : return NS_OK;
1042 1510 : } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
1043 755 : aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
1044 0 : return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
1045 0 : NS_OK : NS_NOINTERFACE;
1046 755 : } else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
1047 0 : nsCOMPtr<nsISHistory> shistory;
1048 0 : nsresult rv = GetSessionHistory(getter_AddRefs(shistory));
1049 0 : if (NS_SUCCEEDED(rv) && shistory) {
1050 0 : shistory.forget(aSink);
1051 0 : return NS_OK;
1052 : }
1053 0 : return NS_NOINTERFACE;
1054 755 : } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
1055 0 : nsresult rv = EnsureFind();
1056 0 : if (NS_FAILED(rv)) {
1057 0 : return rv;
1058 : }
1059 :
1060 0 : *aSink = mFind;
1061 0 : NS_ADDREF((nsISupports*)*aSink);
1062 0 : return NS_OK;
1063 755 : } else if (aIID.Equals(NS_GET_IID(nsIEditingSession))) {
1064 0 : nsCOMPtr<nsIEditingSession> es;
1065 0 : GetEditingSession(getter_AddRefs(es));
1066 0 : es.forget(aSink);
1067 0 : return *aSink ? NS_OK : NS_NOINTERFACE;
1068 755 : } else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) &&
1069 0 : NS_SUCCEEDED(EnsureTransferableHookData())) {
1070 0 : *aSink = mTransferableHookData;
1071 0 : NS_ADDREF((nsISupports*)*aSink);
1072 0 : return NS_OK;
1073 755 : } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
1074 0 : nsIPresShell* shell = GetPresShell();
1075 0 : if (shell) {
1076 0 : return shell->QueryInterface(aIID, aSink);
1077 : }
1078 755 : } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
1079 1 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1080 1 : nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
1081 1 : if (NS_SUCCEEDED(rv) && treeOwner) {
1082 1 : return treeOwner->QueryInterface(aIID, aSink);
1083 : }
1084 754 : } else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
1085 7 : *aSink = GetTabChild().take();
1086 7 : return *aSink ? NS_OK : NS_ERROR_FAILURE;
1087 747 : } else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
1088 : nsCOMPtr<nsITabChild> tabChild =
1089 6 : do_GetInterface(static_cast<nsIDocShell*>(this));
1090 6 : nsCOMPtr<nsIContentFrameMessageManager> mm;
1091 3 : if (tabChild) {
1092 3 : tabChild->GetMessageManager(getter_AddRefs(mm));
1093 : } else {
1094 0 : if (nsPIDOMWindowOuter* win = GetWindow()) {
1095 0 : mm = do_QueryInterface(win->GetParentTarget());
1096 : }
1097 : }
1098 3 : *aSink = mm.get();
1099 : } else {
1100 744 : return nsDocLoader::GetInterface(aIID, aSink);
1101 : }
1102 :
1103 21 : NS_IF_ADDREF(((nsISupports*)*aSink));
1104 21 : return *aSink ? NS_OK : NS_NOINTERFACE;
1105 : }
1106 :
1107 : uint32_t
1108 6 : nsDocShell::ConvertDocShellLoadInfoToLoadType(
1109 : nsDocShellInfoLoadType aDocShellLoadType)
1110 : {
1111 6 : uint32_t loadType = LOAD_NORMAL;
1112 :
1113 6 : switch (aDocShellLoadType) {
1114 : case nsIDocShellLoadInfo::loadNormal:
1115 6 : loadType = LOAD_NORMAL;
1116 6 : break;
1117 : case nsIDocShellLoadInfo::loadNormalReplace:
1118 0 : loadType = LOAD_NORMAL_REPLACE;
1119 0 : break;
1120 : case nsIDocShellLoadInfo::loadNormalExternal:
1121 0 : loadType = LOAD_NORMAL_EXTERNAL;
1122 0 : break;
1123 : case nsIDocShellLoadInfo::loadHistory:
1124 0 : loadType = LOAD_HISTORY;
1125 0 : break;
1126 : case nsIDocShellLoadInfo::loadNormalBypassCache:
1127 0 : loadType = LOAD_NORMAL_BYPASS_CACHE;
1128 0 : break;
1129 : case nsIDocShellLoadInfo::loadNormalBypassProxy:
1130 0 : loadType = LOAD_NORMAL_BYPASS_PROXY;
1131 0 : break;
1132 : case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
1133 0 : loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
1134 0 : break;
1135 : case nsIDocShellLoadInfo::loadNormalAllowMixedContent:
1136 0 : loadType = LOAD_NORMAL_ALLOW_MIXED_CONTENT;
1137 0 : break;
1138 : case nsIDocShellLoadInfo::loadReloadNormal:
1139 0 : loadType = LOAD_RELOAD_NORMAL;
1140 0 : break;
1141 : case nsIDocShellLoadInfo::loadReloadCharsetChange:
1142 0 : loadType = LOAD_RELOAD_CHARSET_CHANGE;
1143 0 : break;
1144 : case nsIDocShellLoadInfo::loadReloadBypassCache:
1145 0 : loadType = LOAD_RELOAD_BYPASS_CACHE;
1146 0 : break;
1147 : case nsIDocShellLoadInfo::loadReloadBypassProxy:
1148 0 : loadType = LOAD_RELOAD_BYPASS_PROXY;
1149 0 : break;
1150 : case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
1151 0 : loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
1152 0 : break;
1153 : case nsIDocShellLoadInfo::loadLink:
1154 0 : loadType = LOAD_LINK;
1155 0 : break;
1156 : case nsIDocShellLoadInfo::loadRefresh:
1157 0 : loadType = LOAD_REFRESH;
1158 0 : break;
1159 : case nsIDocShellLoadInfo::loadBypassHistory:
1160 0 : loadType = LOAD_BYPASS_HISTORY;
1161 0 : break;
1162 : case nsIDocShellLoadInfo::loadStopContent:
1163 0 : loadType = LOAD_STOP_CONTENT;
1164 0 : break;
1165 : case nsIDocShellLoadInfo::loadStopContentAndReplace:
1166 0 : loadType = LOAD_STOP_CONTENT_AND_REPLACE;
1167 0 : break;
1168 : case nsIDocShellLoadInfo::loadPushState:
1169 0 : loadType = LOAD_PUSHSTATE;
1170 0 : break;
1171 : case nsIDocShellLoadInfo::loadReplaceBypassCache:
1172 0 : loadType = LOAD_REPLACE_BYPASS_CACHE;
1173 0 : break;
1174 : case nsIDocShellLoadInfo::loadReloadMixedContent:
1175 0 : loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
1176 0 : break;
1177 : default:
1178 0 : NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
1179 : }
1180 :
1181 6 : return loadType;
1182 : }
1183 :
1184 : nsDocShellInfoLoadType
1185 3 : nsDocShell::ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType)
1186 : {
1187 3 : nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
1188 3 : switch (aLoadType) {
1189 : case LOAD_NORMAL:
1190 3 : docShellLoadType = nsIDocShellLoadInfo::loadNormal;
1191 3 : break;
1192 : case LOAD_NORMAL_REPLACE:
1193 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
1194 0 : break;
1195 : case LOAD_NORMAL_EXTERNAL:
1196 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
1197 0 : break;
1198 : case LOAD_NORMAL_BYPASS_CACHE:
1199 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
1200 0 : break;
1201 : case LOAD_NORMAL_BYPASS_PROXY:
1202 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
1203 0 : break;
1204 : case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
1205 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
1206 0 : break;
1207 : case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
1208 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalAllowMixedContent;
1209 0 : break;
1210 : case LOAD_HISTORY:
1211 0 : docShellLoadType = nsIDocShellLoadInfo::loadHistory;
1212 0 : break;
1213 : case LOAD_RELOAD_NORMAL:
1214 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
1215 0 : break;
1216 : case LOAD_RELOAD_CHARSET_CHANGE:
1217 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
1218 0 : break;
1219 : case LOAD_RELOAD_BYPASS_CACHE:
1220 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
1221 0 : break;
1222 : case LOAD_RELOAD_BYPASS_PROXY:
1223 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
1224 0 : break;
1225 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
1226 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
1227 0 : break;
1228 : case LOAD_LINK:
1229 0 : docShellLoadType = nsIDocShellLoadInfo::loadLink;
1230 0 : break;
1231 : case LOAD_REFRESH:
1232 0 : docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
1233 0 : break;
1234 : case LOAD_BYPASS_HISTORY:
1235 : case LOAD_ERROR_PAGE:
1236 0 : docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
1237 0 : break;
1238 : case LOAD_STOP_CONTENT:
1239 0 : docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
1240 0 : break;
1241 : case LOAD_STOP_CONTENT_AND_REPLACE:
1242 0 : docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
1243 0 : break;
1244 : case LOAD_PUSHSTATE:
1245 0 : docShellLoadType = nsIDocShellLoadInfo::loadPushState;
1246 0 : break;
1247 : case LOAD_REPLACE_BYPASS_CACHE:
1248 0 : docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
1249 0 : break;
1250 : case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
1251 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadMixedContent;
1252 0 : break;
1253 : default:
1254 0 : NS_NOTREACHED("Unexpected load type value");
1255 : }
1256 :
1257 3 : return docShellLoadType;
1258 : }
1259 :
1260 : NS_IMETHODIMP
1261 6 : nsDocShell::LoadURI(nsIURI* aURI,
1262 : nsIDocShellLoadInfo* aLoadInfo,
1263 : uint32_t aLoadFlags,
1264 : bool aFirstParty)
1265 : {
1266 6 : NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
1267 : "Unexpected flags");
1268 6 : NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
1269 :
1270 : // Note: we allow loads to get through here even if mFiredUnloadEvent is
1271 : // true; that case will get handled in LoadInternal or LoadHistoryEntry,
1272 : // so we pass false as the second parameter to IsNavigationAllowed.
1273 : // However, we don't allow the page to change location *in the middle of*
1274 : // firing beforeunload, so we do need to check if *beforeunload* is currently
1275 : // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
1276 6 : if (!IsNavigationAllowed(true, false)) {
1277 0 : return NS_OK; // JS may not handle returning of an error code
1278 : }
1279 :
1280 12 : nsCOMPtr<nsIURI> referrer;
1281 12 : nsCOMPtr<nsIURI> originalURI;
1282 12 : Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
1283 6 : bool loadReplace = false;
1284 12 : nsCOMPtr<nsIInputStream> postStream;
1285 12 : nsCOMPtr<nsIInputStream> headersStream;
1286 12 : nsCOMPtr<nsIPrincipal> triggeringPrincipal;
1287 6 : bool inheritPrincipal = false;
1288 6 : bool principalIsExplicit = false;
1289 6 : bool sendReferrer = true;
1290 6 : uint32_t referrerPolicy = mozilla::net::RP_Unset;
1291 6 : bool isSrcdoc = false;
1292 12 : nsCOMPtr<nsISHEntry> shEntry;
1293 12 : nsXPIDLString target;
1294 12 : nsAutoString srcdoc;
1295 12 : nsCOMPtr<nsIDocShell> sourceDocShell;
1296 12 : nsCOMPtr<nsIURI> baseURI;
1297 :
1298 6 : uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
1299 :
1300 6 : NS_ENSURE_ARG(aURI);
1301 :
1302 18 : if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
1303 9 : mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
1304 1 : StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
1305 : }
1306 :
1307 : // Extract the info from the DocShellLoadInfo struct...
1308 6 : if (aLoadInfo) {
1309 6 : aLoadInfo->GetReferrer(getter_AddRefs(referrer));
1310 6 : aLoadInfo->GetOriginalURI(getter_AddRefs(originalURI));
1311 6 : GetMaybeResultPrincipalURI(aLoadInfo, resultPrincipalURI);
1312 6 : aLoadInfo->GetLoadReplace(&loadReplace);
1313 6 : nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
1314 6 : aLoadInfo->GetLoadType(<);
1315 : // Get the appropriate loadType from nsIDocShellLoadInfo type
1316 6 : loadType = ConvertDocShellLoadInfoToLoadType(lt);
1317 :
1318 6 : aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
1319 6 : aLoadInfo->GetInheritPrincipal(&inheritPrincipal);
1320 6 : aLoadInfo->GetPrincipalIsExplicit(&principalIsExplicit);
1321 6 : aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
1322 6 : aLoadInfo->GetTarget(getter_Copies(target));
1323 6 : aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
1324 6 : aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
1325 6 : aLoadInfo->GetSendReferrer(&sendReferrer);
1326 6 : aLoadInfo->GetReferrerPolicy(&referrerPolicy);
1327 6 : aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
1328 6 : aLoadInfo->GetSrcdocData(srcdoc);
1329 6 : aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
1330 6 : aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
1331 : }
1332 :
1333 6 : MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
1334 : ("nsDocShell[%p]: loading %s with flags 0x%08x",
1335 : this, aURI->GetSpecOrDefault().get(), aLoadFlags));
1336 :
1337 12 : if (!shEntry &&
1338 6 : !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
1339 : // First verify if this is a subframe.
1340 12 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
1341 6 : GetSameTypeParent(getter_AddRefs(parentAsItem));
1342 12 : nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
1343 : uint32_t parentLoadType;
1344 :
1345 6 : if (parentDS && parentDS != static_cast<nsIDocShell*>(this)) {
1346 : /* OK. It is a subframe. Checkout the
1347 : * parent's loadtype. If the parent was loaded thro' a history
1348 : * mechanism, then get the SH entry for the child from the parent.
1349 : * This is done to restore frameset navigation while going back/forward.
1350 : * If the parent was loaded through any other loadType, set the
1351 : * child's loadType too accordingly, so that session history does not
1352 : * get confused.
1353 : */
1354 :
1355 : // Get the parent's load type
1356 1 : parentDS->GetLoadType(&parentLoadType);
1357 :
1358 : // Get the ShEntry for the child from the parent
1359 2 : nsCOMPtr<nsISHEntry> currentSH;
1360 1 : bool oshe = false;
1361 1 : parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
1362 1 : bool dynamicallyAddedChild = mDynamicallyCreated;
1363 1 : if (!dynamicallyAddedChild && !oshe && currentSH) {
1364 0 : currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
1365 : }
1366 1 : if (!dynamicallyAddedChild) {
1367 : // Only use the old SHEntry, if we're sure enough that
1368 : // it wasn't originally for some other frame.
1369 0 : parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
1370 : }
1371 :
1372 : // Make some decisions on the child frame's loadType based on the
1373 : // parent's loadType.
1374 1 : if (!mCurrentURI) {
1375 : // This is a newly created frame. Check for exception cases first.
1376 : // By default the subframe will inherit the parent's loadType.
1377 1 : if (shEntry && (parentLoadType == LOAD_NORMAL ||
1378 0 : parentLoadType == LOAD_LINK ||
1379 1 : parentLoadType == LOAD_NORMAL_EXTERNAL)) {
1380 : // The parent was loaded normally. In this case, this *brand new*
1381 : // child really shouldn't have a SHEntry. If it does, it could be
1382 : // because the parent is replacing an existing frame with a new frame,
1383 : // in the onLoadHandler. We don't want this url to get into session
1384 : // history. Clear off shEntry, and set load type to
1385 : // LOAD_BYPASS_HISTORY.
1386 0 : bool inOnLoadHandler = false;
1387 0 : parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
1388 0 : if (inOnLoadHandler) {
1389 0 : loadType = LOAD_NORMAL_REPLACE;
1390 0 : shEntry = nullptr;
1391 : }
1392 1 : } else if (parentLoadType == LOAD_REFRESH) {
1393 : // Clear shEntry. For refresh loads, we have to load
1394 : // what comes thro' the pipe, not what's in history.
1395 0 : shEntry = nullptr;
1396 2 : } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
1397 0 : (shEntry &&
1398 0 : ((parentLoadType & LOAD_CMD_HISTORY) ||
1399 0 : (parentLoadType == LOAD_RELOAD_NORMAL) ||
1400 1 : (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
1401 : // If the parent url, bypassed history or was loaded from
1402 : // history, pass on the parent's loadType to the new child
1403 : // frame too, so that the child frame will also
1404 : // avoid getting into history.
1405 0 : loadType = parentLoadType;
1406 1 : } else if (parentLoadType == LOAD_ERROR_PAGE) {
1407 : // If the parent document is an error page, we don't
1408 : // want to update global/session history. However,
1409 : // this child frame is not an error page.
1410 0 : loadType = LOAD_BYPASS_HISTORY;
1411 2 : } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
1412 2 : (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
1413 1 : (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
1414 : // the new frame should inherit the parent's load type so that it also
1415 : // bypasses the cache and/or proxy
1416 0 : loadType = parentLoadType;
1417 : }
1418 : } else {
1419 : // This is a pre-existing subframe. If the load was not originally
1420 : // initiated by session history, (if (!shEntry) condition succeeded) and
1421 : // mCurrentURI is not null, it is possible that a parent's onLoadHandler
1422 : // or even self's onLoadHandler is loading a new page in this child.
1423 : // Check parent's and self's busy flag and if it is set, we don't want
1424 : // this onLoadHandler load to get in to session history.
1425 0 : uint32_t parentBusy = BUSY_FLAGS_NONE;
1426 0 : uint32_t selfBusy = BUSY_FLAGS_NONE;
1427 0 : parentDS->GetBusyFlags(&parentBusy);
1428 0 : GetBusyFlags(&selfBusy);
1429 0 : if (parentBusy & BUSY_FLAGS_BUSY ||
1430 0 : selfBusy & BUSY_FLAGS_BUSY) {
1431 0 : loadType = LOAD_NORMAL_REPLACE;
1432 0 : shEntry = nullptr;
1433 : }
1434 : }
1435 : } // parentDS
1436 : else {
1437 : // This is the root docshell. If we got here while
1438 : // executing an onLoad Handler,this load will not go
1439 : // into session history.
1440 5 : bool inOnLoadHandler = false;
1441 5 : GetIsExecutingOnLoadHandler(&inOnLoadHandler);
1442 5 : if (inOnLoadHandler) {
1443 0 : loadType = LOAD_NORMAL_REPLACE;
1444 : }
1445 : }
1446 : } // !shEntry
1447 :
1448 6 : if (shEntry) {
1449 : #ifdef DEBUG
1450 0 : MOZ_LOG(gDocShellLog, LogLevel::Debug,
1451 : ("nsDocShell[%p]: loading from session history", this));
1452 : #endif
1453 :
1454 0 : return LoadHistoryEntry(shEntry, loadType);
1455 : }
1456 :
1457 : // On history navigation via Back/Forward buttons, don't execute
1458 : // automatic JavaScript redirection such as |location.href = ...| or
1459 : // |window.open()|
1460 : //
1461 : // LOAD_NORMAL: window.open(...) etc.
1462 : // LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
1463 12 : if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
1464 6 : ShouldBlockLoadingForBackButton()) {
1465 0 : return NS_OK;
1466 : }
1467 :
1468 : // Perform the load...
1469 :
1470 : // We need a principalToInherit.
1471 : //
1472 : // If principalIsExplicit is not set there are 4 possibilities:
1473 : // (1) If the system principal or an expanded principal was passed
1474 : // in and we're a typeContent docshell, inherit the principal
1475 : // from the current document instead.
1476 : // (2) In all other cases when the principal passed in is not null,
1477 : // use that principal.
1478 : // (3) If the caller has allowed inheriting from the current document,
1479 : // or if we're being called from system code (eg chrome JS or pure
1480 : // C++) then inheritPrincipal should be true and InternalLoad will get
1481 : // a principal from the current document. If none of these things are
1482 : // true, then
1483 : // (4) we don't pass a principal into the channel, and a principal will be
1484 : // created later from the channel's internal data.
1485 : //
1486 : // If principalIsExplicit *is* set, there are 4 possibilities
1487 : // (1) If the system principal or an expanded principal was passed in
1488 : // and we're a typeContent docshell, return an error.
1489 : // (2) In all other cases when the principal passed in is not null,
1490 : // use that principal.
1491 : // (3) If the caller has allowed inheriting from the current document,
1492 : // then inheritPrincipal should be true and InternalLoad will get
1493 : // a principal from the current document. If none of these things are
1494 : // true, then
1495 : // (4) we dont' pass a principal into the channel, and a principal will be
1496 : // created later from the channel's internal data.
1497 12 : nsCOMPtr<nsIPrincipal> principalToInherit = triggeringPrincipal;
1498 6 : if (principalToInherit && mItemType != typeChrome) {
1499 3 : if (nsContentUtils::IsSystemPrincipal(principalToInherit)) {
1500 3 : if (principalIsExplicit) {
1501 0 : return NS_ERROR_DOM_SECURITY_ERR;
1502 : }
1503 3 : principalToInherit = nullptr;
1504 3 : inheritPrincipal = true;
1505 0 : } else if (nsContentUtils::IsExpandedPrincipal(principalToInherit)) {
1506 0 : if (principalIsExplicit) {
1507 0 : return NS_ERROR_DOM_SECURITY_ERR;
1508 : }
1509 : // Don't inherit from the current page. Just do the safe thing
1510 : // and pretend that we were loaded by a nullprincipal.
1511 : //
1512 : // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
1513 : // have origin attributes.
1514 0 : principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this);
1515 0 : inheritPrincipal = false;
1516 : }
1517 : }
1518 6 : if (!principalToInherit && !inheritPrincipal && !principalIsExplicit) {
1519 : // See if there's system or chrome JS code running
1520 0 : inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
1521 : }
1522 :
1523 6 : if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
1524 1 : inheritPrincipal = false;
1525 : // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is
1526 : // enabled, we will set firstPartyDomain on the origin attributes.
1527 1 : principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty);
1528 : }
1529 :
1530 : // If the triggeringPrincipal is not passed explicitly, we first try to create
1531 : // a principal from the referrer, since the referrer URI reflects the web origin
1532 : // that triggered the load. If there is no referrer URI, we fall back to using
1533 : // the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
1534 : // and no referrer simulate a load that was triggered by the system.
1535 : // It's important to note that this block of code needs to appear *after* the block
1536 : // where we munge the principalToInherit, because otherwise we would never enter
1537 : // code blocks checking if the principalToInherit is null and we will end up with
1538 : // a wrong inheritPrincipal flag.
1539 6 : if (!triggeringPrincipal) {
1540 0 : if (referrer) {
1541 0 : nsresult rv = CreatePrincipalFromReferrer(referrer,
1542 0 : getter_AddRefs(triggeringPrincipal));
1543 0 : NS_ENSURE_SUCCESS(rv, rv);
1544 : }
1545 : else {
1546 0 : triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
1547 : }
1548 : }
1549 :
1550 6 : uint32_t flags = 0;
1551 :
1552 6 : if (inheritPrincipal) {
1553 2 : flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
1554 : }
1555 :
1556 6 : if (!sendReferrer) {
1557 0 : flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
1558 : }
1559 :
1560 6 : if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
1561 0 : flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
1562 : }
1563 :
1564 6 : if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) {
1565 1 : flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
1566 : }
1567 :
1568 6 : if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) {
1569 0 : flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
1570 : }
1571 :
1572 6 : if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
1573 0 : flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
1574 : }
1575 :
1576 6 : if (isSrcdoc) {
1577 0 : flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
1578 : }
1579 :
1580 12 : return InternalLoad(aURI,
1581 : originalURI,
1582 : resultPrincipalURI,
1583 : loadReplace,
1584 : referrer,
1585 : referrerPolicy,
1586 : triggeringPrincipal,
1587 : principalToInherit,
1588 : flags,
1589 : target,
1590 : nullptr, // No type hint
1591 6 : NullString(), // No forced download
1592 : postStream,
1593 : headersStream,
1594 : loadType,
1595 : nullptr, // No SHEntry
1596 : aFirstParty,
1597 : srcdoc,
1598 : sourceDocShell,
1599 : baseURI,
1600 : false,
1601 : nullptr, // No nsIDocShell
1602 6 : nullptr); // No nsIRequest
1603 : }
1604 :
1605 : NS_IMETHODIMP
1606 0 : nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
1607 : const nsACString& aContentType,
1608 : const nsACString& aContentCharset,
1609 : nsIDocShellLoadInfo* aLoadInfo)
1610 : {
1611 0 : NS_ENSURE_ARG(aStream);
1612 :
1613 0 : mAllowKeywordFixup = false;
1614 :
1615 : // if the caller doesn't pass in a URI we need to create a dummy URI. necko
1616 : // currently requires a URI in various places during the load. Some consumers
1617 : // do as well.
1618 0 : nsCOMPtr<nsIURI> uri = aURI;
1619 0 : if (!uri) {
1620 : // HACK ALERT
1621 0 : nsresult rv = NS_OK;
1622 0 : uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
1623 0 : if (NS_FAILED(rv)) {
1624 0 : return rv;
1625 : }
1626 : // Make sure that the URI spec "looks" like a protocol and path...
1627 : // For now, just use a bogus protocol called "internal"
1628 0 : rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
1629 0 : if (NS_FAILED(rv)) {
1630 0 : return rv;
1631 : }
1632 : }
1633 :
1634 0 : uint32_t loadType = LOAD_NORMAL;
1635 0 : nsCOMPtr<nsIPrincipal> triggeringPrincipal;
1636 0 : if (aLoadInfo) {
1637 0 : nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
1638 0 : (void)aLoadInfo->GetLoadType(<);
1639 : // Get the appropriate LoadType from nsIDocShellLoadInfo type
1640 0 : loadType = ConvertDocShellLoadInfoToLoadType(lt);
1641 0 : aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
1642 : }
1643 :
1644 0 : NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
1645 :
1646 0 : mLoadType = loadType;
1647 :
1648 0 : if (!triggeringPrincipal) {
1649 0 : triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
1650 : }
1651 :
1652 : // build up a channel for this stream.
1653 0 : nsCOMPtr<nsIChannel> channel;
1654 0 : nsresult rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
1655 : uri,
1656 : aStream,
1657 : triggeringPrincipal,
1658 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1659 : nsIContentPolicy::TYPE_OTHER,
1660 : aContentType,
1661 0 : aContentCharset);
1662 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1663 :
1664 0 : nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
1665 0 : NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
1666 :
1667 0 : NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
1668 : NS_ERROR_FAILURE);
1669 0 : return NS_OK;
1670 : }
1671 :
1672 : NS_IMETHODIMP
1673 6 : nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo)
1674 : {
1675 6 : nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
1676 12 : nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
1677 :
1678 6 : localRef.forget(aLoadInfo);
1679 12 : return NS_OK;
1680 : }
1681 :
1682 : /*
1683 : * Reset state to a new content model within the current document and the
1684 : * document viewer. Called by the document before initiating an out of band
1685 : * document.write().
1686 : */
1687 : NS_IMETHODIMP
1688 0 : nsDocShell::PrepareForNewContentModel()
1689 : {
1690 0 : mEODForCurrentDocument = false;
1691 0 : return NS_OK;
1692 : }
1693 :
1694 : NS_IMETHODIMP
1695 5 : nsDocShell::FirePageHideNotification(bool aIsUnload)
1696 : {
1697 5 : FirePageHideNotificationInternal(aIsUnload, false);
1698 5 : return NS_OK;
1699 : }
1700 :
1701 : void
1702 5 : nsDocShell::FirePageHideNotificationInternal(bool aIsUnload,
1703 : bool aSkipCheckingDynEntries)
1704 : {
1705 5 : if (mContentViewer && !mFiredUnloadEvent) {
1706 : // Keep an explicit reference since calling PageHide could release
1707 : // mContentViewer
1708 8 : nsCOMPtr<nsIContentViewer> contentViewer(mContentViewer);
1709 4 : mFiredUnloadEvent = true;
1710 :
1711 4 : if (mTiming) {
1712 4 : mTiming->NotifyUnloadEventStart();
1713 : }
1714 :
1715 4 : contentViewer->PageHide(aIsUnload);
1716 :
1717 4 : if (mTiming) {
1718 4 : mTiming->NotifyUnloadEventEnd();
1719 : }
1720 :
1721 8 : AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
1722 4 : uint32_t n = mChildList.Length();
1723 4 : kids.SetCapacity(n);
1724 4 : for (uint32_t i = 0; i < n; i++) {
1725 0 : kids.AppendElement(do_QueryInterface(ChildAt(i)));
1726 : }
1727 :
1728 4 : n = kids.Length();
1729 4 : for (uint32_t i = 0; i < n; ++i) {
1730 0 : RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get());
1731 0 : if (child) {
1732 : // Skip checking dynamic subframe entries in our children.
1733 0 : child->FirePageHideNotificationInternal(aIsUnload, true);
1734 : }
1735 : }
1736 :
1737 : // If the document is unloading, remove all dynamic subframe entries.
1738 4 : if (aIsUnload && !aSkipCheckingDynEntries) {
1739 8 : nsCOMPtr<nsISHistory> rootSH;
1740 4 : GetRootSessionHistory(getter_AddRefs(rootSH));
1741 8 : nsCOMPtr<nsISHistoryInternal> shPrivate = do_QueryInterface(rootSH);
1742 8 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE));
1743 4 : if (shPrivate && container) {
1744 0 : int32_t index = -1;
1745 0 : rootSH->GetIndex(&index);
1746 0 : shPrivate->RemoveDynEntries(index, container);
1747 : }
1748 : }
1749 :
1750 : // Now make sure our editor, if any, is detached before we go
1751 : // any farther.
1752 4 : DetachEditorFromWindow();
1753 : }
1754 5 : }
1755 :
1756 : nsresult
1757 0 : nsDocShell::DispatchToTabGroup(const char* aName,
1758 : TaskCategory aCategory,
1759 : already_AddRefed<nsIRunnable>&& aRunnable)
1760 : {
1761 : // Hold the ref so we won't forget to release it.
1762 0 : nsCOMPtr<nsIRunnable> runnable(aRunnable);
1763 0 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
1764 0 : if (!win) {
1765 : // Window should only be unavailable after destroyed.
1766 0 : MOZ_ASSERT(mIsBeingDestroyed);
1767 0 : return NS_ERROR_FAILURE;
1768 : }
1769 :
1770 0 : RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup();
1771 0 : return tabGroup->Dispatch(aName, aCategory, runnable.forget());
1772 : }
1773 :
1774 : NS_IMETHODIMP
1775 0 : nsDocShell::DispatchLocationChangeEvent()
1776 : {
1777 0 : return DispatchToTabGroup(
1778 : "nsDocShell::FireDummyOnLocationChange",
1779 : TaskCategory::Other,
1780 0 : NewRunnableMethod("nsDocShell::FireDummyOnLocationChange",
1781 : this,
1782 0 : &nsDocShell::FireDummyOnLocationChange));
1783 : }
1784 :
1785 : bool
1786 16 : nsDocShell::MaybeInitTiming()
1787 : {
1788 16 : if (mTiming && !mBlankTiming) {
1789 6 : return false;
1790 : }
1791 :
1792 10 : bool canBeReset = false;
1793 :
1794 10 : if (mScriptGlobal && mBlankTiming) {
1795 : nsPIDOMWindowInner* innerWin =
1796 4 : mScriptGlobal->AsOuter()->GetCurrentInnerWindow();
1797 4 : if (innerWin && innerWin->GetPerformance()) {
1798 4 : mTiming = innerWin->GetPerformance()->GetDOMTiming();
1799 4 : mBlankTiming = false;
1800 : }
1801 : }
1802 :
1803 10 : if (!mTiming) {
1804 6 : mTiming = new nsDOMNavigationTiming(this);
1805 6 : canBeReset = true;
1806 : }
1807 :
1808 10 : mTiming->NotifyNavigationStart(
1809 10 : mIsActive ? nsDOMNavigationTiming::DocShellState::eActive
1810 10 : : nsDOMNavigationTiming::DocShellState::eInactive);
1811 :
1812 10 : return canBeReset;
1813 : }
1814 :
1815 : void
1816 0 : nsDocShell::MaybeResetInitTiming(bool aReset)
1817 : {
1818 0 : if (aReset) {
1819 0 : mTiming = nullptr;
1820 : }
1821 0 : }
1822 :
1823 : //
1824 : // Bug 13871: Prevent frameset spoofing
1825 : //
1826 : // This routine answers: 'Is origin's document from same domain as
1827 : // target's document?'
1828 : //
1829 : // file: uris are considered the same domain for the purpose of
1830 : // frame navigation regardless of script accessibility (bug 420425)
1831 : //
1832 : /* static */ bool
1833 0 : nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
1834 : nsIDocShellTreeItem* aTargetTreeItem)
1835 : {
1836 : // We want to bypass this check for chrome callers, but only if there's
1837 : // JS on the stack. System callers still need to do it.
1838 0 : if (nsContentUtils::GetCurrentJSContext() &&
1839 0 : nsContentUtils::IsCallerChrome()) {
1840 0 : return true;
1841 : }
1842 :
1843 0 : MOZ_ASSERT(aOriginTreeItem && aTargetTreeItem, "need two docshells");
1844 :
1845 : // Get origin document principal
1846 0 : nsCOMPtr<nsIDocument> originDocument = aOriginTreeItem->GetDocument();
1847 0 : NS_ENSURE_TRUE(originDocument, false);
1848 :
1849 : // Get target principal
1850 0 : nsCOMPtr<nsIDocument> targetDocument = aTargetTreeItem->GetDocument();
1851 0 : NS_ENSURE_TRUE(targetDocument, false);
1852 :
1853 : bool equal;
1854 0 : nsresult rv = originDocument->NodePrincipal()->Equals(
1855 0 : targetDocument->NodePrincipal(), &equal);
1856 0 : if (NS_SUCCEEDED(rv) && equal) {
1857 0 : return true;
1858 : }
1859 :
1860 : // Not strictly equal, special case if both are file: uris
1861 0 : bool originIsFile = false;
1862 0 : bool targetIsFile = false;
1863 0 : nsCOMPtr<nsIURI> originURI;
1864 0 : nsCOMPtr<nsIURI> targetURI;
1865 0 : nsCOMPtr<nsIURI> innerOriginURI;
1866 0 : nsCOMPtr<nsIURI> innerTargetURI;
1867 :
1868 0 : rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
1869 0 : if (NS_SUCCEEDED(rv) && originURI) {
1870 0 : innerOriginURI = NS_GetInnermostURI(originURI);
1871 : }
1872 :
1873 0 : rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
1874 0 : if (NS_SUCCEEDED(rv) && targetURI) {
1875 0 : innerTargetURI = NS_GetInnermostURI(targetURI);
1876 : }
1877 :
1878 0 : return innerOriginURI && innerTargetURI &&
1879 0 : NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
1880 0 : NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
1881 0 : originIsFile && targetIsFile;
1882 : }
1883 :
1884 : nsresult
1885 0 : nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
1886 : {
1887 0 : NS_ENSURE_ARG_POINTER(aPresContext);
1888 0 : *aPresContext = nullptr;
1889 :
1890 0 : nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
1891 0 : while (viewer) {
1892 0 : nsCOMPtr<nsIContentViewer> prevViewer;
1893 0 : viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
1894 0 : if (!prevViewer) {
1895 0 : return viewer->GetPresContext(aPresContext);
1896 : }
1897 0 : viewer = prevViewer;
1898 : }
1899 :
1900 0 : return NS_OK;
1901 : }
1902 :
1903 : NS_IMETHODIMP
1904 54 : nsDocShell::GetPresContext(nsPresContext** aPresContext)
1905 : {
1906 54 : NS_ENSURE_ARG_POINTER(aPresContext);
1907 54 : *aPresContext = nullptr;
1908 :
1909 54 : if (!mContentViewer) {
1910 7 : return NS_OK;
1911 : }
1912 :
1913 47 : return mContentViewer->GetPresContext(aPresContext);
1914 : }
1915 :
1916 : NS_IMETHODIMP_(nsIPresShell*)
1917 34 : nsDocShell::GetPresShell()
1918 : {
1919 68 : RefPtr<nsPresContext> presContext;
1920 34 : (void)GetPresContext(getter_AddRefs(presContext));
1921 68 : return presContext ? presContext->GetPresShell() : nullptr;
1922 : }
1923 :
1924 : NS_IMETHODIMP
1925 0 : nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
1926 : {
1927 0 : nsresult rv = NS_OK;
1928 :
1929 0 : NS_ENSURE_ARG_POINTER(aPresShell);
1930 0 : *aPresShell = nullptr;
1931 :
1932 0 : RefPtr<nsPresContext> presContext;
1933 0 : (void)GetEldestPresContext(getter_AddRefs(presContext));
1934 :
1935 0 : if (presContext) {
1936 0 : NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
1937 : }
1938 :
1939 0 : return rv;
1940 : }
1941 :
1942 : NS_IMETHODIMP
1943 58 : nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer)
1944 : {
1945 58 : NS_ENSURE_ARG_POINTER(aContentViewer);
1946 :
1947 58 : *aContentViewer = mContentViewer;
1948 58 : NS_IF_ADDREF(*aContentViewer);
1949 58 : return NS_OK;
1950 : }
1951 :
1952 : NS_IMETHODIMP
1953 3 : nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
1954 : {
1955 : // Weak reference. Don't addref.
1956 6 : nsCOMPtr<EventTarget> handler = do_QueryInterface(aChromeEventHandler);
1957 3 : mChromeEventHandler = handler.get();
1958 :
1959 3 : if (mScriptGlobal) {
1960 1 : mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
1961 : }
1962 :
1963 6 : return NS_OK;
1964 : }
1965 :
1966 : NS_IMETHODIMP
1967 12 : nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
1968 : {
1969 12 : NS_ENSURE_ARG_POINTER(aChromeEventHandler);
1970 24 : nsCOMPtr<EventTarget> handler = mChromeEventHandler;
1971 12 : handler.forget(aChromeEventHandler);
1972 12 : return NS_OK;
1973 : }
1974 :
1975 : NS_IMETHODIMP
1976 0 : nsDocShell::SetCurrentURI(nsIURI* aURI)
1977 : {
1978 : // Note that securityUI will set STATE_IS_INSECURE, even if
1979 : // the scheme of |aURI| is "https".
1980 0 : SetCurrentURI(aURI, nullptr, true, 0);
1981 0 : return NS_OK;
1982 : }
1983 :
1984 : bool
1985 8 : nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
1986 : bool aFireOnLocationChange, uint32_t aLocationFlags)
1987 : {
1988 8 : MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
1989 : ("DOCSHELL %p SetCurrentURI %s\n",
1990 : this, aURI ? aURI->GetSpecOrDefault().get() : ""));
1991 :
1992 : // We don't want to send a location change when we're displaying an error
1993 : // page, and we don't want to change our idea of "current URI" either
1994 8 : if (mLoadType == LOAD_ERROR_PAGE) {
1995 0 : return false;
1996 : }
1997 :
1998 8 : mCurrentURI = NS_TryToMakeImmutable(aURI);
1999 :
2000 8 : if (!NS_IsAboutBlank(mCurrentURI)) {
2001 3 : mHasLoadedNonBlankURI = true;
2002 : }
2003 :
2004 8 : bool isRoot = false; // Is this the root docshell
2005 8 : bool isSubFrame = false; // Is this a subframe navigation?
2006 :
2007 16 : nsCOMPtr<nsIDocShellTreeItem> root;
2008 :
2009 8 : GetSameTypeRootTreeItem(getter_AddRefs(root));
2010 8 : if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
2011 : // This is the root docshell
2012 7 : isRoot = true;
2013 : }
2014 8 : if (mLSHE) {
2015 1 : mLSHE->GetIsSubFrame(&isSubFrame);
2016 : }
2017 :
2018 8 : if (!isSubFrame && !isRoot) {
2019 : /*
2020 : * We don't want to send OnLocationChange notifications when
2021 : * a subframe is being loaded for the first time, while
2022 : * visiting a frameset page
2023 : */
2024 1 : return false;
2025 : }
2026 :
2027 7 : if (aFireOnLocationChange) {
2028 4 : FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
2029 : }
2030 7 : return !aFireOnLocationChange;
2031 : }
2032 :
2033 : NS_IMETHODIMP
2034 0 : nsDocShell::GetCharset(nsACString& aCharset)
2035 : {
2036 0 : aCharset.Truncate();
2037 :
2038 0 : nsIPresShell* presShell = GetPresShell();
2039 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
2040 0 : nsIDocument* doc = presShell->GetDocument();
2041 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
2042 0 : doc->GetDocumentCharacterSet()->Name(aCharset);
2043 0 : return NS_OK;
2044 : }
2045 :
2046 : NS_IMETHODIMP
2047 0 : nsDocShell::GatherCharsetMenuTelemetry()
2048 : {
2049 0 : nsCOMPtr<nsIContentViewer> viewer;
2050 0 : GetContentViewer(getter_AddRefs(viewer));
2051 0 : if (!viewer) {
2052 0 : return NS_OK;
2053 : }
2054 :
2055 0 : nsIDocument* doc = viewer->GetDocument();
2056 0 : if (!doc || doc->WillIgnoreCharsetOverride()) {
2057 0 : return NS_OK;
2058 : }
2059 :
2060 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true);
2061 :
2062 0 : bool isFileURL = false;
2063 0 : nsIURI* url = doc->GetOriginalURI();
2064 0 : if (url) {
2065 0 : url->SchemeIs("file", &isFileURL);
2066 : }
2067 :
2068 0 : int32_t charsetSource = doc->GetDocumentCharacterSetSource();
2069 0 : switch (charsetSource) {
2070 : case kCharsetFromTopLevelDomain:
2071 : // Unlabeled doc on a domain that we map to a fallback encoding
2072 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7);
2073 0 : break;
2074 : case kCharsetFromFallback:
2075 : case kCharsetFromDocTypeDefault:
2076 : case kCharsetFromCache:
2077 : case kCharsetFromParentFrame:
2078 : case kCharsetFromHintPrevDoc:
2079 : // Changing charset on an unlabeled doc.
2080 0 : if (isFileURL) {
2081 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
2082 : } else {
2083 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1);
2084 : }
2085 0 : break;
2086 : case kCharsetFromAutoDetection:
2087 : // Changing charset on unlabeled doc where chardet fired
2088 0 : if (isFileURL) {
2089 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2);
2090 : } else {
2091 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3);
2092 : }
2093 0 : break;
2094 : case kCharsetFromMetaPrescan:
2095 : case kCharsetFromMetaTag:
2096 : case kCharsetFromChannel:
2097 : // Changing charset on a doc that had a charset label.
2098 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4);
2099 0 : break;
2100 : case kCharsetFromParentForced:
2101 : case kCharsetFromUserForced:
2102 : // Changing charset on a document that already had an override.
2103 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5);
2104 0 : break;
2105 : case kCharsetFromIrreversibleAutoDetection:
2106 : case kCharsetFromOtherComponent:
2107 : case kCharsetFromByteOrderMark:
2108 : case kCharsetUninitialized:
2109 : default:
2110 : // Bug. This isn't supposed to happen.
2111 0 : Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6);
2112 0 : break;
2113 : }
2114 0 : return NS_OK;
2115 : }
2116 :
2117 : NS_IMETHODIMP
2118 0 : nsDocShell::SetCharset(const nsACString& aCharset)
2119 : {
2120 : // set the charset override
2121 0 : return SetForcedCharset(aCharset);
2122 : }
2123 :
2124 : NS_IMETHODIMP
2125 0 : nsDocShell::SetForcedCharset(const nsACString& aCharset)
2126 : {
2127 0 : if (aCharset.IsEmpty()) {
2128 0 : mForcedCharset = nullptr;
2129 0 : return NS_OK;
2130 : }
2131 0 : const Encoding* encoding = Encoding::ForLabel(aCharset);
2132 0 : if (!encoding) {
2133 : // Reject unknown labels
2134 0 : return NS_ERROR_INVALID_ARG;
2135 : }
2136 0 : if (!encoding->IsAsciiCompatible() && encoding != ISO_2022_JP_ENCODING) {
2137 : // Reject XSS hazards
2138 0 : return NS_ERROR_INVALID_ARG;
2139 : }
2140 0 : mForcedCharset = encoding;
2141 0 : return NS_OK;
2142 : }
2143 :
2144 : NS_IMETHODIMP
2145 0 : nsDocShell::GetForcedCharset(nsACString& aResult)
2146 : {
2147 0 : mForcedCharset->Name(aResult);
2148 0 : return NS_OK;
2149 : }
2150 :
2151 : void
2152 0 : nsDocShell::SetParentCharset(const Encoding*& aCharset,
2153 : int32_t aCharsetSource,
2154 : nsIPrincipal* aPrincipal)
2155 : {
2156 0 : mParentCharset = aCharset;
2157 0 : mParentCharsetSource = aCharsetSource;
2158 0 : mParentCharsetPrincipal = aPrincipal;
2159 0 : }
2160 :
2161 : void
2162 3 : nsDocShell::GetParentCharset(const Encoding*& aCharset,
2163 : int32_t* aCharsetSource,
2164 : nsIPrincipal** aPrincipal)
2165 : {
2166 3 : aCharset = mParentCharset;
2167 3 : *aCharsetSource = mParentCharsetSource;
2168 3 : NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
2169 3 : }
2170 :
2171 : NS_IMETHODIMP
2172 8 : nsDocShell::GetChannelIsUnsafe(bool* aUnsafe)
2173 : {
2174 8 : *aUnsafe = false;
2175 :
2176 8 : nsIChannel* channel = GetCurrentDocChannel();
2177 8 : if (!channel) {
2178 3 : return NS_OK;
2179 : }
2180 :
2181 10 : nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
2182 5 : if (!jarChannel) {
2183 5 : return NS_OK;
2184 : }
2185 :
2186 0 : return jarChannel->GetIsUnsafe(aUnsafe);
2187 : }
2188 :
2189 : NS_IMETHODIMP
2190 4 : nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded)
2191 : {
2192 8 : nsCOMPtr<nsIDocument> doc(GetDocument());
2193 4 : *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
2194 8 : return NS_OK;
2195 : }
2196 :
2197 : NS_IMETHODIMP
2198 2 : nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked)
2199 : {
2200 4 : nsCOMPtr<nsIDocument> doc(GetDocument());
2201 2 : *aHasMixedActiveContentBlocked =
2202 2 : doc && doc->GetHasMixedActiveContentBlocked();
2203 4 : return NS_OK;
2204 : }
2205 :
2206 : NS_IMETHODIMP
2207 2 : nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded)
2208 : {
2209 4 : nsCOMPtr<nsIDocument> doc(GetDocument());
2210 2 : *aHasMixedDisplayContentLoaded =
2211 2 : doc && doc->GetHasMixedDisplayContentLoaded();
2212 4 : return NS_OK;
2213 : }
2214 :
2215 : NS_IMETHODIMP
2216 2 : nsDocShell::GetHasMixedDisplayContentBlocked(
2217 : bool* aHasMixedDisplayContentBlocked)
2218 : {
2219 4 : nsCOMPtr<nsIDocument> doc(GetDocument());
2220 2 : *aHasMixedDisplayContentBlocked =
2221 2 : doc && doc->GetHasMixedDisplayContentBlocked();
2222 4 : return NS_OK;
2223 : }
2224 :
2225 : NS_IMETHODIMP
2226 2 : nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked)
2227 : {
2228 4 : nsCOMPtr<nsIDocument> doc(GetDocument());
2229 2 : *aHasTrackingContentBlocked = doc && doc->GetHasTrackingContentBlocked();
2230 4 : return NS_OK;
2231 : }
2232 :
2233 : NS_IMETHODIMP
2234 2 : nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded)
2235 : {
2236 4 : nsCOMPtr<nsIDocument> doc(GetDocument());
2237 2 : *aHasTrackingContentLoaded = doc && doc->GetHasTrackingContentLoaded();
2238 4 : return NS_OK;
2239 : }
2240 :
2241 : NS_IMETHODIMP
2242 2 : nsDocShell::GetAllowPlugins(bool* aAllowPlugins)
2243 : {
2244 2 : NS_ENSURE_ARG_POINTER(aAllowPlugins);
2245 :
2246 2 : *aAllowPlugins = mAllowPlugins;
2247 2 : if (!mAllowPlugins) {
2248 0 : return NS_OK;
2249 : }
2250 :
2251 : bool unsafe;
2252 2 : *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
2253 2 : return NS_OK;
2254 : }
2255 :
2256 : NS_IMETHODIMP
2257 2 : nsDocShell::SetAllowPlugins(bool aAllowPlugins)
2258 : {
2259 2 : mAllowPlugins = aAllowPlugins;
2260 : // XXX should enable or disable a plugin host
2261 2 : return NS_OK;
2262 : }
2263 :
2264 : NS_IMETHODIMP
2265 10 : nsDocShell::GetAllowJavascript(bool* aAllowJavascript)
2266 : {
2267 10 : NS_ENSURE_ARG_POINTER(aAllowJavascript);
2268 :
2269 10 : *aAllowJavascript = mAllowJavascript;
2270 10 : return NS_OK;
2271 : }
2272 :
2273 : NS_IMETHODIMP
2274 2 : nsDocShell::SetAllowJavascript(bool aAllowJavascript)
2275 : {
2276 2 : mAllowJavascript = aAllowJavascript;
2277 2 : RecomputeCanExecuteScripts();
2278 2 : return NS_OK;
2279 : }
2280 :
2281 : NS_IMETHODIMP
2282 2259 : nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
2283 : {
2284 2259 : NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
2285 2259 : AssertOriginAttributesMatchPrivateBrowsing();
2286 2259 : *aUsePrivateBrowsing = mPrivateBrowsingId > 0;
2287 2259 : return NS_OK;
2288 : }
2289 :
2290 : NS_IMETHODIMP
2291 0 : nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
2292 : {
2293 0 : nsContentUtils::ReportToConsoleNonLocalized(
2294 0 : NS_LITERAL_STRING("Only internal code is allowed to set the usePrivateBrowsing attribute"),
2295 : nsIScriptError::warningFlag,
2296 0 : NS_LITERAL_CSTRING("Internal API Used"),
2297 0 : mContentViewer ? mContentViewer->GetDocument() : nullptr);
2298 :
2299 0 : if (!CanSetOriginAttributes()) {
2300 0 : bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
2301 :
2302 0 : return changed ? NS_ERROR_FAILURE : NS_OK;
2303 : }
2304 :
2305 0 : return SetPrivateBrowsing(aUsePrivateBrowsing);
2306 : }
2307 :
2308 : NS_IMETHODIMP
2309 9 : nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
2310 : {
2311 9 : bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
2312 9 : if (changed) {
2313 0 : mPrivateBrowsingId = aUsePrivateBrowsing ? 1 : 0;
2314 :
2315 0 : if (mItemType != typeChrome) {
2316 0 : mOriginAttributes.SyncAttributesWithPrivateBrowsing(aUsePrivateBrowsing);
2317 : }
2318 :
2319 0 : if (mAffectPrivateSessionLifetime) {
2320 0 : if (aUsePrivateBrowsing) {
2321 0 : IncreasePrivateDocShellCount();
2322 : } else {
2323 0 : DecreasePrivateDocShellCount();
2324 : }
2325 : }
2326 : }
2327 :
2328 18 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2329 9 : while (iter.HasMore()) {
2330 0 : nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext());
2331 0 : if (shell) {
2332 0 : shell->SetPrivateBrowsing(aUsePrivateBrowsing);
2333 : }
2334 : }
2335 :
2336 9 : if (changed) {
2337 0 : nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
2338 0 : while (iter.HasMore()) {
2339 0 : nsWeakPtr ref = iter.GetNext();
2340 0 : nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
2341 0 : if (!obs) {
2342 0 : mPrivacyObservers.RemoveElement(ref);
2343 : } else {
2344 0 : obs->PrivateModeChanged(aUsePrivateBrowsing);
2345 : }
2346 : }
2347 : }
2348 :
2349 9 : AssertOriginAttributesMatchPrivateBrowsing();
2350 18 : return NS_OK;
2351 : }
2352 :
2353 : NS_IMETHODIMP
2354 4 : nsDocShell::GetHasLoadedNonBlankURI(bool* aResult)
2355 : {
2356 4 : NS_ENSURE_ARG_POINTER(aResult);
2357 :
2358 4 : *aResult = mHasLoadedNonBlankURI;
2359 4 : return NS_OK;
2360 : }
2361 :
2362 : NS_IMETHODIMP
2363 5 : nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
2364 : {
2365 5 : NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
2366 :
2367 5 : *aUseRemoteTabs = mUseRemoteTabs;
2368 5 : return NS_OK;
2369 : }
2370 :
2371 : NS_IMETHODIMP
2372 4 : nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
2373 : {
2374 : #ifdef MOZ_CRASHREPORTER
2375 4 : if (aUseRemoteTabs) {
2376 12 : CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
2377 16 : NS_LITERAL_CSTRING("1"));
2378 : }
2379 : #endif
2380 :
2381 4 : mUseRemoteTabs = aUseRemoteTabs;
2382 4 : return NS_OK;
2383 : }
2384 :
2385 : NS_IMETHODIMP
2386 3 : nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
2387 : {
2388 3 : bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
2389 3 : if (change && UsePrivateBrowsing()) {
2390 0 : AssertOriginAttributesMatchPrivateBrowsing();
2391 0 : if (aAffectLifetime) {
2392 0 : IncreasePrivateDocShellCount();
2393 : } else {
2394 0 : DecreasePrivateDocShellCount();
2395 : }
2396 : }
2397 3 : mAffectPrivateSessionLifetime = aAffectLifetime;
2398 :
2399 6 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2400 3 : while (iter.HasMore()) {
2401 0 : nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2402 0 : if (shell) {
2403 0 : shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
2404 : }
2405 : }
2406 6 : return NS_OK;
2407 : }
2408 :
2409 : NS_IMETHODIMP
2410 3 : nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime)
2411 : {
2412 3 : *aAffectLifetime = mAffectPrivateSessionLifetime;
2413 3 : return NS_OK;
2414 : }
2415 :
2416 : NS_IMETHODIMP
2417 1 : nsDocShell::AddWeakPrivacyTransitionObserver(
2418 : nsIPrivacyTransitionObserver* aObserver)
2419 : {
2420 2 : nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2421 1 : if (!weakObs) {
2422 0 : return NS_ERROR_NOT_AVAILABLE;
2423 : }
2424 1 : return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
2425 : }
2426 :
2427 : NS_IMETHODIMP
2428 0 : nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver)
2429 : {
2430 0 : nsWeakPtr weakObs = do_GetWeakReference(aObserver);
2431 0 : if (!weakObs) {
2432 0 : return NS_ERROR_FAILURE;
2433 : }
2434 0 : return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
2435 : }
2436 :
2437 : NS_IMETHODIMP
2438 0 : nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver)
2439 : {
2440 0 : nsWeakPtr obs = do_GetWeakReference(aObserver);
2441 0 : return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
2442 : }
2443 :
2444 : NS_IMETHODIMP
2445 29 : nsDocShell::NotifyReflowObservers(bool aInterruptible,
2446 : DOMHighResTimeStamp aStart,
2447 : DOMHighResTimeStamp aEnd)
2448 : {
2449 58 : nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
2450 29 : while (iter.HasMore()) {
2451 0 : nsWeakPtr ref = iter.GetNext();
2452 0 : nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
2453 0 : if (!obs) {
2454 0 : mReflowObservers.RemoveElement(ref);
2455 0 : } else if (aInterruptible) {
2456 0 : obs->ReflowInterruptible(aStart, aEnd);
2457 : } else {
2458 0 : obs->Reflow(aStart, aEnd);
2459 : }
2460 : }
2461 58 : return NS_OK;
2462 : }
2463 :
2464 : NS_IMETHODIMP
2465 2 : nsDocShell::GetAllowMetaRedirects(bool* aReturn)
2466 : {
2467 2 : NS_ENSURE_ARG_POINTER(aReturn);
2468 :
2469 2 : *aReturn = mAllowMetaRedirects;
2470 2 : if (!mAllowMetaRedirects) {
2471 0 : return NS_OK;
2472 : }
2473 :
2474 : bool unsafe;
2475 2 : *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
2476 2 : return NS_OK;
2477 : }
2478 :
2479 : NS_IMETHODIMP
2480 2 : nsDocShell::SetAllowMetaRedirects(bool aValue)
2481 : {
2482 2 : mAllowMetaRedirects = aValue;
2483 2 : return NS_OK;
2484 : }
2485 :
2486 : NS_IMETHODIMP
2487 9 : nsDocShell::GetAllowSubframes(bool* aAllowSubframes)
2488 : {
2489 9 : NS_ENSURE_ARG_POINTER(aAllowSubframes);
2490 :
2491 9 : *aAllowSubframes = mAllowSubframes;
2492 9 : return NS_OK;
2493 : }
2494 :
2495 : NS_IMETHODIMP
2496 2 : nsDocShell::SetAllowSubframes(bool aAllowSubframes)
2497 : {
2498 2 : mAllowSubframes = aAllowSubframes;
2499 2 : return NS_OK;
2500 : }
2501 :
2502 : NS_IMETHODIMP
2503 3 : nsDocShell::GetAllowImages(bool* aAllowImages)
2504 : {
2505 3 : NS_ENSURE_ARG_POINTER(aAllowImages);
2506 :
2507 3 : *aAllowImages = mAllowImages;
2508 3 : return NS_OK;
2509 : }
2510 :
2511 : NS_IMETHODIMP
2512 2 : nsDocShell::SetAllowImages(bool aAllowImages)
2513 : {
2514 2 : mAllowImages = aAllowImages;
2515 2 : return NS_OK;
2516 : }
2517 :
2518 : NS_IMETHODIMP
2519 2 : nsDocShell::GetAllowMedia(bool* aAllowMedia)
2520 : {
2521 2 : *aAllowMedia = mAllowMedia;
2522 2 : return NS_OK;
2523 : }
2524 :
2525 : NS_IMETHODIMP
2526 2 : nsDocShell::SetAllowMedia(bool aAllowMedia)
2527 : {
2528 2 : mAllowMedia = aAllowMedia;
2529 :
2530 : // Mute or unmute audio contexts attached to the inner window.
2531 2 : if (mScriptGlobal) {
2532 0 : if (nsPIDOMWindowInner* innerWin =
2533 0 : mScriptGlobal->AsOuter()->GetCurrentInnerWindow()) {
2534 0 : if (aAllowMedia) {
2535 0 : innerWin->UnmuteAudioContexts();
2536 : } else {
2537 0 : innerWin->MuteAudioContexts();
2538 : }
2539 : }
2540 : }
2541 :
2542 2 : return NS_OK;
2543 : }
2544 :
2545 : NS_IMETHODIMP
2546 6 : nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch)
2547 : {
2548 6 : *aAllowDNSPrefetch = mAllowDNSPrefetch;
2549 6 : return NS_OK;
2550 : }
2551 :
2552 : NS_IMETHODIMP
2553 4 : nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
2554 : {
2555 4 : mAllowDNSPrefetch = aAllowDNSPrefetch;
2556 4 : return NS_OK;
2557 : }
2558 :
2559 : NS_IMETHODIMP
2560 2 : nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl)
2561 : {
2562 2 : *aAllowWindowControl = mAllowWindowControl;
2563 2 : return NS_OK;
2564 : }
2565 :
2566 : NS_IMETHODIMP
2567 2 : nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
2568 : {
2569 2 : mAllowWindowControl = aAllowWindowControl;
2570 2 : return NS_OK;
2571 : }
2572 :
2573 : NS_IMETHODIMP
2574 0 : nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting)
2575 : {
2576 0 : *aAllowContentRetargeting = mAllowContentRetargeting;
2577 0 : return NS_OK;
2578 : }
2579 :
2580 : NS_IMETHODIMP
2581 2 : nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting)
2582 : {
2583 2 : mAllowContentRetargetingOnChildren = aAllowContentRetargeting;
2584 2 : mAllowContentRetargeting = aAllowContentRetargeting;
2585 2 : return NS_OK;
2586 : }
2587 :
2588 : NS_IMETHODIMP
2589 2 : nsDocShell::GetAllowContentRetargetingOnChildren(
2590 : bool* aAllowContentRetargetingOnChildren)
2591 : {
2592 2 : *aAllowContentRetargetingOnChildren = mAllowContentRetargetingOnChildren;
2593 2 : return NS_OK;
2594 : }
2595 :
2596 : NS_IMETHODIMP
2597 0 : nsDocShell::SetAllowContentRetargetingOnChildren(
2598 : bool aAllowContentRetargetingOnChildren)
2599 : {
2600 0 : mAllowContentRetargetingOnChildren = aAllowContentRetargetingOnChildren;
2601 0 : return NS_OK;
2602 : }
2603 :
2604 : NS_IMETHODIMP
2605 0 : nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId)
2606 : {
2607 0 : *aInheritPrivateBrowsingId = mInheritPrivateBrowsingId;
2608 0 : return NS_OK;
2609 : }
2610 :
2611 : NS_IMETHODIMP
2612 0 : nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId)
2613 : {
2614 0 : mInheritPrivateBrowsingId = aInheritPrivateBrowsingId;
2615 0 : return NS_OK;
2616 : }
2617 :
2618 : NS_IMETHODIMP
2619 0 : nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
2620 : {
2621 0 : NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
2622 :
2623 : // Browsers and apps have their mFullscreenAllowed retrieved from their
2624 : // corresponding iframe in their parent upon creation.
2625 0 : if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
2626 0 : *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
2627 0 : return NS_OK;
2628 : }
2629 :
2630 : // Assume false until we determine otherwise...
2631 0 : *aFullscreenAllowed = false;
2632 :
2633 0 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
2634 0 : if (!win) {
2635 0 : return NS_OK;
2636 : }
2637 0 : if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) {
2638 0 : if (frameElement->IsXULElement()) {
2639 0 : if (frameElement->HasAttr(kNameSpaceID_None,
2640 : nsGkAtoms::disablefullscreen)) {
2641 : // Document inside this frame is explicitly disabled.
2642 0 : return NS_OK;
2643 : }
2644 : } else {
2645 : // We do not allow document inside any containing element other
2646 : // than iframe to enter fullscreen.
2647 0 : if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
2648 : // If any ancestor iframe does not have allowfullscreen attribute
2649 : // set, then fullscreen is not allowed.
2650 0 : if (!frameElement->HasAttr(kNameSpaceID_None,
2651 0 : nsGkAtoms::allowfullscreen) &&
2652 0 : !frameElement->HasAttr(kNameSpaceID_None,
2653 : nsGkAtoms::mozallowfullscreen)) {
2654 0 : return NS_OK;
2655 : }
2656 0 : } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
2657 : // Respect allowfullscreen only if this is a rewritten YouTube embed.
2658 : nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
2659 0 : do_QueryInterface(frameElement);
2660 0 : if (!objectLoadingContent) {
2661 0 : return NS_OK;
2662 : }
2663 : nsObjectLoadingContent* olc =
2664 0 : static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
2665 0 : if (!olc->IsRewrittenYoutubeEmbed()) {
2666 0 : return NS_OK;
2667 : }
2668 : // We don't have to check prefixed attributes because Flash does not
2669 : // support them.
2670 0 : if (!frameElement->HasAttr(kNameSpaceID_None,
2671 : nsGkAtoms::allowfullscreen)) {
2672 0 : return NS_OK;
2673 : }
2674 : } else {
2675 : // neither iframe nor embed
2676 0 : return NS_OK;
2677 : }
2678 : }
2679 : }
2680 :
2681 : // If we have no parent then we're the root docshell; no ancestor of the
2682 : // original docshell doesn't have a allowfullscreen attribute, so
2683 : // report fullscreen as allowed.
2684 0 : RefPtr<nsDocShell> parent = GetParentDocshell();
2685 0 : if (!parent) {
2686 0 : *aFullscreenAllowed = true;
2687 0 : return NS_OK;
2688 : }
2689 :
2690 : // Otherwise, we have a parent, continue the checking for
2691 : // mozFullscreenAllowed in the parent docshell's ancestors.
2692 0 : return parent->GetFullscreenAllowed(aFullscreenAllowed);
2693 : }
2694 :
2695 : NS_IMETHODIMP
2696 1 : nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
2697 : {
2698 1 : if (!nsIDocShell::GetIsMozBrowser()) {
2699 : // Only allow setting of fullscreenAllowed on content/process boundaries.
2700 : // At non-boundaries the fullscreenAllowed attribute is calculated based on
2701 : // whether all enclosing frames have the "mozFullscreenAllowed" attribute
2702 : // set to "true". fullscreenAllowed is set at the process boundaries to
2703 : // propagate the value of the parent's "mozFullscreenAllowed" attribute
2704 : // across process boundaries.
2705 1 : return NS_ERROR_UNEXPECTED;
2706 : }
2707 0 : mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS);
2708 0 : return NS_OK;
2709 : }
2710 :
2711 : ScreenOrientationInternal
2712 6 : nsDocShell::OrientationLock()
2713 : {
2714 6 : return mOrientationLock;
2715 : }
2716 :
2717 : void
2718 0 : nsDocShell::SetOrientationLock(ScreenOrientationInternal aOrientationLock)
2719 : {
2720 0 : mOrientationLock = aOrientationLock;
2721 0 : }
2722 :
2723 : NS_IMETHODIMP
2724 5 : nsDocShell::GetMayEnableCharacterEncodingMenu(
2725 : bool* aMayEnableCharacterEncodingMenu)
2726 : {
2727 5 : *aMayEnableCharacterEncodingMenu = false;
2728 5 : if (!mContentViewer) {
2729 0 : return NS_OK;
2730 : }
2731 5 : nsIDocument* doc = mContentViewer->GetDocument();
2732 5 : if (!doc) {
2733 0 : return NS_OK;
2734 : }
2735 5 : if (doc->WillIgnoreCharsetOverride()) {
2736 3 : return NS_OK;
2737 : }
2738 :
2739 2 : *aMayEnableCharacterEncodingMenu = true;
2740 2 : return NS_OK;
2741 : }
2742 :
2743 : NS_IMETHODIMP
2744 0 : nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection,
2745 : nsISimpleEnumerator** aResult)
2746 : {
2747 0 : NS_ENSURE_ARG_POINTER(aResult);
2748 0 : *aResult = nullptr;
2749 :
2750 0 : RefPtr<nsDocShellEnumerator> docShellEnum;
2751 0 : if (aDirection == ENUMERATE_FORWARDS) {
2752 0 : docShellEnum = new nsDocShellForwardsEnumerator;
2753 : } else {
2754 0 : docShellEnum = new nsDocShellBackwardsEnumerator;
2755 : }
2756 :
2757 0 : nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
2758 0 : if (NS_FAILED(rv)) {
2759 0 : return rv;
2760 : }
2761 :
2762 0 : rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this);
2763 0 : if (NS_FAILED(rv)) {
2764 0 : return rv;
2765 : }
2766 :
2767 0 : rv = docShellEnum->First();
2768 0 : if (NS_FAILED(rv)) {
2769 0 : return rv;
2770 : }
2771 :
2772 0 : rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator),
2773 0 : (void**)aResult);
2774 :
2775 0 : return rv;
2776 : }
2777 :
2778 : NS_IMETHODIMP
2779 39 : nsDocShell::GetAppType(uint32_t* aAppType)
2780 : {
2781 39 : *aAppType = mAppType;
2782 39 : return NS_OK;
2783 : }
2784 :
2785 : NS_IMETHODIMP
2786 0 : nsDocShell::SetAppType(uint32_t aAppType)
2787 : {
2788 0 : mAppType = aAppType;
2789 0 : return NS_OK;
2790 : }
2791 :
2792 : NS_IMETHODIMP
2793 0 : nsDocShell::GetAllowAuth(bool* aAllowAuth)
2794 : {
2795 0 : *aAllowAuth = mAllowAuth;
2796 0 : return NS_OK;
2797 : }
2798 :
2799 : NS_IMETHODIMP
2800 0 : nsDocShell::SetAllowAuth(bool aAllowAuth)
2801 : {
2802 0 : mAllowAuth = aAllowAuth;
2803 0 : return NS_OK;
2804 : }
2805 :
2806 : NS_IMETHODIMP
2807 0 : nsDocShell::GetZoom(float* aZoom)
2808 : {
2809 0 : NS_ENSURE_ARG_POINTER(aZoom);
2810 0 : *aZoom = 1.0f;
2811 0 : return NS_OK;
2812 : }
2813 :
2814 : NS_IMETHODIMP
2815 0 : nsDocShell::SetZoom(float aZoom)
2816 : {
2817 0 : return NS_ERROR_NOT_IMPLEMENTED;
2818 : }
2819 :
2820 : NS_IMETHODIMP
2821 3 : nsDocShell::GetMarginWidth(int32_t* aWidth)
2822 : {
2823 3 : NS_ENSURE_ARG_POINTER(aWidth);
2824 :
2825 3 : *aWidth = mMarginWidth;
2826 3 : return NS_OK;
2827 : }
2828 :
2829 : NS_IMETHODIMP
2830 1 : nsDocShell::SetMarginWidth(int32_t aWidth)
2831 : {
2832 1 : mMarginWidth = aWidth;
2833 1 : return NS_OK;
2834 : }
2835 :
2836 : NS_IMETHODIMP
2837 3 : nsDocShell::GetMarginHeight(int32_t* aHeight)
2838 : {
2839 3 : NS_ENSURE_ARG_POINTER(aHeight);
2840 :
2841 3 : *aHeight = mMarginHeight;
2842 3 : return NS_OK;
2843 : }
2844 :
2845 : NS_IMETHODIMP
2846 1 : nsDocShell::SetMarginHeight(int32_t aHeight)
2847 : {
2848 1 : mMarginHeight = aHeight;
2849 1 : return NS_OK;
2850 : }
2851 :
2852 : NS_IMETHODIMP
2853 0 : nsDocShell::GetBusyFlags(uint32_t* aBusyFlags)
2854 : {
2855 0 : NS_ENSURE_ARG_POINTER(aBusyFlags);
2856 :
2857 0 : *aBusyFlags = mBusyFlags;
2858 0 : return NS_OK;
2859 : }
2860 :
2861 : NS_IMETHODIMP
2862 0 : nsDocShell::TabToTreeOwner(bool aForward, bool aForDocumentNavigation, bool* aTookFocus)
2863 : {
2864 0 : NS_ENSURE_ARG_POINTER(aTookFocus);
2865 :
2866 0 : nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
2867 0 : if (chromeFocus) {
2868 0 : if (aForward) {
2869 0 : *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement(aForDocumentNavigation));
2870 : } else {
2871 0 : *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement(aForDocumentNavigation));
2872 : }
2873 : } else {
2874 0 : *aTookFocus = false;
2875 : }
2876 :
2877 0 : return NS_OK;
2878 : }
2879 :
2880 : NS_IMETHODIMP
2881 3 : nsDocShell::GetSecurityUI(nsISecureBrowserUI** aSecurityUI)
2882 : {
2883 3 : NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
2884 3 : return NS_OK;
2885 : }
2886 :
2887 : NS_IMETHODIMP
2888 2 : nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI)
2889 : {
2890 2 : mSecurityUI = aSecurityUI;
2891 2 : mSecurityUI->SetDocShell(this);
2892 2 : return NS_OK;
2893 : }
2894 :
2895 : NS_IMETHODIMP
2896 0 : nsDocShell::GetUseErrorPages(bool* aUseErrorPages)
2897 : {
2898 0 : *aUseErrorPages = UseErrorPages();
2899 0 : return NS_OK;
2900 : }
2901 :
2902 : NS_IMETHODIMP
2903 0 : nsDocShell::SetUseErrorPages(bool aUseErrorPages)
2904 : {
2905 : // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
2906 0 : if (mObserveErrorPages) {
2907 0 : mObserveErrorPages = false;
2908 : }
2909 0 : mUseErrorPages = aUseErrorPages;
2910 0 : return NS_OK;
2911 : }
2912 :
2913 : NS_IMETHODIMP
2914 1 : nsDocShell::GetPreviousTransIndex(int32_t* aPreviousTransIndex)
2915 : {
2916 1 : *aPreviousTransIndex = mPreviousTransIndex;
2917 1 : return NS_OK;
2918 : }
2919 :
2920 : NS_IMETHODIMP
2921 1 : nsDocShell::GetLoadedTransIndex(int32_t* aLoadedTransIndex)
2922 : {
2923 1 : *aLoadedTransIndex = mLoadedTransIndex;
2924 1 : return NS_OK;
2925 : }
2926 :
2927 : NS_IMETHODIMP
2928 0 : nsDocShell::HistoryPurged(int32_t aNumEntries)
2929 : {
2930 : // These indices are used for fastback cache eviction, to determine
2931 : // which session history entries are candidates for content viewer
2932 : // eviction. We need to adjust by the number of entries that we
2933 : // just purged from history, so that we look at the right session history
2934 : // entries during eviction.
2935 0 : mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries);
2936 0 : mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries);
2937 :
2938 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2939 0 : while (iter.HasMore()) {
2940 0 : nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2941 0 : if (shell) {
2942 0 : shell->HistoryPurged(aNumEntries);
2943 : }
2944 : }
2945 :
2946 0 : return NS_OK;
2947 : }
2948 :
2949 : nsresult
2950 0 : nsDocShell::HistoryTransactionRemoved(int32_t aIndex)
2951 : {
2952 : // These indices are used for fastback cache eviction, to determine
2953 : // which session history entries are candidates for content viewer
2954 : // eviction. We need to adjust by the number of entries that we
2955 : // just purged from history, so that we look at the right session history
2956 : // entries during eviction.
2957 0 : if (aIndex == mPreviousTransIndex) {
2958 0 : mPreviousTransIndex = -1;
2959 0 : } else if (aIndex < mPreviousTransIndex) {
2960 0 : --mPreviousTransIndex;
2961 : }
2962 0 : if (mLoadedTransIndex == aIndex) {
2963 0 : mLoadedTransIndex = 0;
2964 0 : } else if (aIndex < mLoadedTransIndex) {
2965 0 : --mLoadedTransIndex;
2966 : }
2967 :
2968 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
2969 0 : while (iter.HasMore()) {
2970 0 : nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
2971 0 : if (shell) {
2972 0 : static_cast<nsDocShell*>(shell.get())->HistoryTransactionRemoved(aIndex);
2973 : }
2974 : }
2975 :
2976 0 : return NS_OK;
2977 : }
2978 :
2979 : NS_IMETHODIMP
2980 1 : nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
2981 : {
2982 1 : bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
2983 1 : if (currentValue == aValue) {
2984 1 : return NS_OK;
2985 : }
2986 :
2987 0 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
2988 0 : if (!timelines) {
2989 0 : return NS_OK;
2990 : }
2991 :
2992 0 : if (aValue) {
2993 0 : MOZ_ASSERT(!timelines->HasConsumer(this));
2994 0 : timelines->AddConsumer(this);
2995 0 : MOZ_ASSERT(timelines->HasConsumer(this));
2996 0 : UseEntryScriptProfiling();
2997 : } else {
2998 0 : MOZ_ASSERT(timelines->HasConsumer(this));
2999 0 : timelines->RemoveConsumer(this);
3000 0 : MOZ_ASSERT(!timelines->HasConsumer(this));
3001 0 : UnuseEntryScriptProfiling();
3002 : }
3003 :
3004 0 : return NS_OK;
3005 : }
3006 :
3007 : NS_IMETHODIMP
3008 260 : nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
3009 : {
3010 260 : *aValue = !!mObserved;
3011 260 : return NS_OK;
3012 : }
3013 :
3014 : nsresult
3015 0 : nsDocShell::PopProfileTimelineMarkers(
3016 : JSContext* aCx,
3017 : JS::MutableHandle<JS::Value> aOut)
3018 : {
3019 0 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
3020 0 : if (!timelines) {
3021 0 : return NS_OK;
3022 : }
3023 :
3024 0 : nsTArray<dom::ProfileTimelineMarker> store;
3025 0 : SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
3026 :
3027 0 : timelines->PopMarkers(this, aCx, store);
3028 :
3029 0 : if (!ToJSValue(aCx, store, aOut)) {
3030 0 : JS_ClearPendingException(aCx);
3031 0 : return NS_ERROR_UNEXPECTED;
3032 : }
3033 :
3034 0 : return NS_OK;
3035 : }
3036 :
3037 : nsresult
3038 0 : nsDocShell::Now(DOMHighResTimeStamp* aWhen)
3039 : {
3040 0 : *aWhen = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
3041 0 : return NS_OK;
3042 : }
3043 :
3044 : NS_IMETHODIMP
3045 0 : nsDocShell::SetWindowDraggingAllowed(bool aValue)
3046 : {
3047 0 : RefPtr<nsDocShell> parent = GetParentDocshell();
3048 0 : if (!aValue && mItemType == typeChrome && !parent) {
3049 : // Window dragging is always allowed for top level
3050 : // chrome docshells.
3051 0 : return NS_ERROR_FAILURE;
3052 : }
3053 0 : mWindowDraggingAllowed = aValue;
3054 0 : return NS_OK;
3055 : }
3056 :
3057 : NS_IMETHODIMP
3058 26 : nsDocShell::GetWindowDraggingAllowed(bool* aValue)
3059 : {
3060 : // window dragging regions in CSS (-moz-window-drag:drag)
3061 : // can be slow. Default behavior is to only allow it for
3062 : // chrome top level windows.
3063 52 : RefPtr<nsDocShell> parent = GetParentDocshell();
3064 26 : if (mItemType == typeChrome && !parent) {
3065 : // Top level chrome window
3066 24 : *aValue = true;
3067 : } else {
3068 2 : *aValue = mWindowDraggingAllowed;
3069 : }
3070 52 : return NS_OK;
3071 : }
3072 :
3073 : nsIDOMStorageManager*
3074 2 : nsDocShell::TopSessionStorageManager()
3075 : {
3076 : nsresult rv;
3077 :
3078 4 : nsCOMPtr<nsIDocShellTreeItem> topItem;
3079 2 : rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
3080 2 : if (NS_FAILED(rv)) {
3081 0 : return nullptr;
3082 : }
3083 :
3084 2 : if (!topItem) {
3085 0 : return nullptr;
3086 : }
3087 :
3088 2 : nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
3089 2 : if (topDocShell != this) {
3090 0 : return topDocShell->TopSessionStorageManager();
3091 : }
3092 :
3093 2 : if (!mSessionStorageManager) {
3094 : mSessionStorageManager =
3095 1 : do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1");
3096 : }
3097 :
3098 2 : return mSessionStorageManager;
3099 : }
3100 :
3101 : NS_IMETHODIMP
3102 0 : nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
3103 : {
3104 0 : NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
3105 0 : return NS_OK;
3106 : }
3107 :
3108 : nsIChannel*
3109 8 : nsDocShell::GetCurrentDocChannel()
3110 : {
3111 8 : if (mContentViewer) {
3112 7 : nsIDocument* doc = mContentViewer->GetDocument();
3113 7 : if (doc) {
3114 7 : return doc->GetChannel();
3115 : }
3116 : }
3117 1 : return nullptr;
3118 : }
3119 :
3120 : NS_IMETHODIMP
3121 0 : nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver)
3122 : {
3123 0 : nsWeakPtr weakObs = do_GetWeakReference(aObserver);
3124 0 : if (!weakObs) {
3125 0 : return NS_ERROR_FAILURE;
3126 : }
3127 0 : return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
3128 : }
3129 :
3130 : NS_IMETHODIMP
3131 0 : nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
3132 : {
3133 0 : nsWeakPtr obs = do_GetWeakReference(aObserver);
3134 0 : return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
3135 : }
3136 :
3137 : void
3138 0 : nsDocShell::NotifyAsyncPanZoomStarted()
3139 : {
3140 0 : nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
3141 0 : while (iter.HasMore()) {
3142 0 : nsWeakPtr ref = iter.GetNext();
3143 0 : nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
3144 0 : if (obs) {
3145 0 : obs->AsyncPanZoomStarted();
3146 : } else {
3147 0 : mScrollObservers.RemoveElement(ref);
3148 : }
3149 : }
3150 0 : }
3151 :
3152 : void
3153 0 : nsDocShell::NotifyAsyncPanZoomStopped()
3154 : {
3155 0 : nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
3156 0 : while (iter.HasMore()) {
3157 0 : nsWeakPtr ref = iter.GetNext();
3158 0 : nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
3159 0 : if (obs) {
3160 0 : obs->AsyncPanZoomStopped();
3161 : } else {
3162 0 : mScrollObservers.RemoveElement(ref);
3163 : }
3164 : }
3165 0 : }
3166 :
3167 : NS_IMETHODIMP
3168 0 : nsDocShell::NotifyScrollObservers()
3169 : {
3170 0 : nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
3171 0 : while (iter.HasMore()) {
3172 0 : nsWeakPtr ref = iter.GetNext();
3173 0 : nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
3174 0 : if (obs) {
3175 0 : obs->ScrollPositionChanged();
3176 : } else {
3177 0 : mScrollObservers.RemoveElement(ref);
3178 : }
3179 : }
3180 0 : return NS_OK;
3181 : }
3182 :
3183 : //*****************************************************************************
3184 : // nsDocShell::nsIDocShellTreeItem
3185 : //*****************************************************************************
3186 :
3187 : NS_IMETHODIMP
3188 0 : nsDocShell::GetName(nsAString& aName)
3189 : {
3190 0 : aName = mName;
3191 0 : return NS_OK;
3192 : }
3193 :
3194 : NS_IMETHODIMP
3195 3 : nsDocShell::SetName(const nsAString& aName)
3196 : {
3197 3 : mName = aName;
3198 3 : return NS_OK;
3199 : }
3200 :
3201 : NS_IMETHODIMP
3202 80 : nsDocShell::NameEquals(const nsAString& aName, bool* aResult)
3203 : {
3204 80 : NS_ENSURE_ARG_POINTER(aResult);
3205 80 : *aResult = mName.Equals(aName);
3206 80 : return NS_OK;
3207 : }
3208 :
3209 : NS_IMETHODIMP
3210 6 : nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent)
3211 : {
3212 6 : aCustomUserAgent = mCustomUserAgent;
3213 6 : return NS_OK;
3214 : }
3215 :
3216 : NS_IMETHODIMP
3217 0 : nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent)
3218 : {
3219 0 : mCustomUserAgent = aCustomUserAgent;
3220 : RefPtr<nsGlobalWindow> win = mScriptGlobal ?
3221 0 : mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
3222 0 : if (win) {
3223 0 : Navigator* navigator = win->Navigator();
3224 0 : if (navigator) {
3225 0 : navigator->ClearUserAgentCache();
3226 : }
3227 : }
3228 :
3229 0 : uint32_t childCount = mChildList.Length();
3230 0 : for (uint32_t i = 0; i < childCount; ++i) {
3231 0 : nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
3232 0 : if (childShell) {
3233 0 : childShell->SetCustomUserAgent(aCustomUserAgent);
3234 : }
3235 : }
3236 0 : return NS_OK;
3237 : }
3238 :
3239 : NS_IMETHODIMP
3240 49 : nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride)
3241 : {
3242 49 : NS_ENSURE_ARG_POINTER(aTouchEventsOverride);
3243 :
3244 49 : *aTouchEventsOverride = mTouchEventsOverride;
3245 49 : return NS_OK;
3246 : }
3247 :
3248 : NS_IMETHODIMP
3249 2 : nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride)
3250 : {
3251 2 : if (!(aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE ||
3252 : aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED ||
3253 : aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED)) {
3254 0 : return NS_ERROR_INVALID_ARG;
3255 : }
3256 :
3257 2 : mTouchEventsOverride = aTouchEventsOverride;
3258 :
3259 2 : uint32_t childCount = mChildList.Length();
3260 2 : for (uint32_t i = 0; i < childCount; ++i) {
3261 0 : nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
3262 0 : if (childShell) {
3263 0 : childShell->SetTouchEventsOverride(aTouchEventsOverride);
3264 : }
3265 : }
3266 2 : return NS_OK;
3267 : }
3268 :
3269 : /* virtual */ int32_t
3270 417 : nsDocShell::ItemType()
3271 : {
3272 417 : return mItemType;
3273 : }
3274 :
3275 : NS_IMETHODIMP
3276 0 : nsDocShell::GetItemType(int32_t* aItemType)
3277 : {
3278 0 : NS_ENSURE_ARG_POINTER(aItemType);
3279 :
3280 0 : *aItemType = ItemType();
3281 0 : return NS_OK;
3282 : }
3283 :
3284 : NS_IMETHODIMP
3285 5 : nsDocShell::SetItemType(int32_t aItemType)
3286 : {
3287 5 : NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
3288 :
3289 : // Only allow setting the type on root docshells. Those would be the ones
3290 : // that have the docloader service as mParent or have no mParent at all.
3291 : nsCOMPtr<nsIDocumentLoader> docLoaderService =
3292 10 : do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
3293 5 : NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
3294 :
3295 5 : NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
3296 :
3297 5 : mItemType = aItemType;
3298 :
3299 : // disable auth prompting for anything but content
3300 5 : mAllowAuth = mItemType == typeContent;
3301 :
3302 10 : RefPtr<nsPresContext> presContext = nullptr;
3303 5 : GetPresContext(getter_AddRefs(presContext));
3304 5 : if (presContext) {
3305 0 : presContext->UpdateIsChrome();
3306 : }
3307 :
3308 5 : return NS_OK;
3309 : }
3310 :
3311 : NS_IMETHODIMP
3312 10 : nsDocShell::GetParent(nsIDocShellTreeItem** aParent)
3313 : {
3314 10 : if (!mParent) {
3315 0 : *aParent = nullptr;
3316 : } else {
3317 10 : CallQueryInterface(mParent, aParent);
3318 : }
3319 : // Note that in the case when the parent is not an nsIDocShellTreeItem we
3320 : // don't want to throw; we just want to return null.
3321 10 : return NS_OK;
3322 : }
3323 :
3324 : already_AddRefed<nsDocShell>
3325 126 : nsDocShell::GetParentDocshell()
3326 : {
3327 252 : nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
3328 252 : return docshell.forget().downcast<nsDocShell>();
3329 : }
3330 :
3331 : void
3332 23 : nsDocShell::RecomputeCanExecuteScripts()
3333 : {
3334 23 : bool old = mCanExecuteScripts;
3335 46 : RefPtr<nsDocShell> parent = GetParentDocshell();
3336 :
3337 : // If we have no tree owner, that means that we've been detached from the
3338 : // docshell tree (this is distinct from having no parent dochshell, which
3339 : // is the case for root docshells). It would be nice to simply disallow
3340 : // script in detached docshells, but bug 986542 demonstrates that this
3341 : // behavior breaks at least one website.
3342 : //
3343 : // So instead, we use our previous value, unless mAllowJavascript has been
3344 : // explicitly set to false.
3345 23 : if (!mTreeOwner) {
3346 17 : mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
3347 : // If scripting has been explicitly disabled on our docshell, we're done.
3348 6 : } else if (!mAllowJavascript) {
3349 0 : mCanExecuteScripts = false;
3350 : // If we have a parent, inherit.
3351 6 : } else if (parent) {
3352 2 : mCanExecuteScripts = parent->mCanExecuteScripts;
3353 : // Otherwise, we're the root of the tree, and we haven't explicitly disabled
3354 : // script. Allow.
3355 : } else {
3356 4 : mCanExecuteScripts = true;
3357 : }
3358 :
3359 : // Inform our active DOM window.
3360 : //
3361 : // This will pass the outer, which will be in the scope of the active inner.
3362 23 : if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
3363 : xpc::Scriptability& scriptability =
3364 4 : xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
3365 4 : scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
3366 : }
3367 :
3368 : // If our value has changed, our children might be affected. Recompute their
3369 : // value as well.
3370 23 : if (old != mCanExecuteScripts) {
3371 10 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
3372 5 : while (iter.HasMore()) {
3373 0 : static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
3374 : }
3375 : }
3376 23 : }
3377 :
3378 : nsresult
3379 12 : nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
3380 : {
3381 12 : bool wasFrame = IsFrame();
3382 : #ifdef DEBUG
3383 12 : bool wasPrivate = UsePrivateBrowsing();
3384 : #endif
3385 :
3386 12 : nsresult rv = nsDocLoader::SetDocLoaderParent(aParent);
3387 12 : NS_ENSURE_SUCCESS(rv, rv);
3388 :
3389 24 : nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
3390 12 : if (wasFrame != IsFrame() && priorityGroup) {
3391 1 : priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
3392 : }
3393 :
3394 : // Curse ambiguous nsISupports inheritance!
3395 12 : nsISupports* parent = GetAsSupports(aParent);
3396 :
3397 : // If parent is another docshell, we inherit all their flags for
3398 : // allowing plugins, scripting etc.
3399 : bool value;
3400 24 : nsString customUserAgent;
3401 24 : nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
3402 12 : if (parentAsDocShell) {
3403 2 : if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
3404 2 : SetAllowPlugins(value);
3405 : }
3406 2 : if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
3407 2 : SetAllowJavascript(value);
3408 : }
3409 2 : if (mAllowMetaRedirects && NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
3410 2 : SetAllowMetaRedirects(value);
3411 : }
3412 2 : if (mAllowSubframes && NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) {
3413 2 : SetAllowSubframes(value);
3414 : }
3415 2 : if (mAllowImages && NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) {
3416 2 : SetAllowImages(value);
3417 : }
3418 2 : SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
3419 2 : if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
3420 2 : SetAllowWindowControl(value);
3421 : }
3422 4 : SetAllowContentRetargeting(mAllowContentRetargeting &&
3423 4 : parentAsDocShell->GetAllowContentRetargetingOnChildren());
3424 2 : if (parentAsDocShell->GetIsPrerendered()) {
3425 0 : SetIsPrerendered();
3426 : }
3427 2 : if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
3428 : // a prerendered docshell is not active yet
3429 2 : SetIsActive(value && !mIsPrerendered);
3430 : }
3431 4 : if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) &&
3432 2 : !customUserAgent.IsEmpty()) {
3433 0 : SetCustomUserAgent(customUserAgent);
3434 : }
3435 2 : if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
3436 0 : value = false;
3437 : }
3438 2 : SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
3439 2 : if (mInheritPrivateBrowsingId) {
3440 2 : value = parentAsDocShell->GetAffectPrivateSessionLifetime();
3441 2 : SetAffectPrivateSessionLifetime(value);
3442 : }
3443 : uint32_t flags;
3444 2 : if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
3445 2 : SetDefaultLoadFlags(flags);
3446 : }
3447 : uint32_t touchEventsOverride;
3448 2 : if (NS_SUCCEEDED(parentAsDocShell->GetTouchEventsOverride(&touchEventsOverride))) {
3449 2 : SetTouchEventsOverride(touchEventsOverride);
3450 : }
3451 : }
3452 :
3453 24 : nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
3454 14 : if (parentAsLoadContext && mInheritPrivateBrowsingId &&
3455 2 : NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) {
3456 2 : SetPrivateBrowsing(value);
3457 : }
3458 :
3459 24 : nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
3460 12 : if (parentURIListener) {
3461 2 : mContentListener->SetParentContentListener(parentURIListener);
3462 : }
3463 :
3464 : // Our parent has changed. Recompute scriptability.
3465 12 : RecomputeCanExecuteScripts();
3466 :
3467 12 : NS_ASSERTION(mInheritPrivateBrowsingId || wasPrivate == UsePrivateBrowsing(),
3468 : "Private browsing state changed while inheritance was disabled");
3469 :
3470 12 : return NS_OK;
3471 : }
3472 :
3473 : NS_IMETHODIMP
3474 162 : nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent)
3475 : {
3476 162 : NS_ENSURE_ARG_POINTER(aParent);
3477 162 : *aParent = nullptr;
3478 :
3479 162 : if (nsIDocShell::GetIsMozBrowser()) {
3480 0 : return NS_OK;
3481 : }
3482 :
3483 : nsCOMPtr<nsIDocShellTreeItem> parent =
3484 324 : do_QueryInterface(GetAsSupports(mParent));
3485 162 : if (!parent) {
3486 120 : return NS_OK;
3487 : }
3488 :
3489 42 : if (parent->ItemType() == mItemType) {
3490 20 : parent.swap(*aParent);
3491 : }
3492 42 : return NS_OK;
3493 : }
3494 :
3495 : NS_IMETHODIMP
3496 315 : nsDocShell::GetSameTypeParentIgnoreBrowserBoundaries(nsIDocShell** aParent)
3497 : {
3498 315 : NS_ENSURE_ARG_POINTER(aParent);
3499 315 : *aParent = nullptr;
3500 :
3501 : nsCOMPtr<nsIDocShellTreeItem> parent =
3502 630 : do_QueryInterface(GetAsSupports(mParent));
3503 315 : if (!parent) {
3504 281 : return NS_OK;
3505 : }
3506 :
3507 34 : if (parent->ItemType() == mItemType) {
3508 26 : nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent);
3509 13 : parentDS.forget(aParent);
3510 : }
3511 34 : return NS_OK;
3512 : }
3513 :
3514 : NS_IMETHODIMP
3515 49 : nsDocShell::GetRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
3516 : {
3517 49 : NS_ENSURE_ARG_POINTER(aRootTreeItem);
3518 :
3519 98 : RefPtr<nsDocShell> root = this;
3520 98 : RefPtr<nsDocShell> parent = root->GetParentDocshell();
3521 49 : while (parent) {
3522 0 : root = parent;
3523 0 : parent = root->GetParentDocshell();
3524 : }
3525 :
3526 49 : root.forget(aRootTreeItem);
3527 49 : return NS_OK;
3528 : }
3529 :
3530 : NS_IMETHODIMP
3531 54 : nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
3532 : {
3533 54 : NS_ENSURE_ARG_POINTER(aRootTreeItem);
3534 54 : *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
3535 :
3536 108 : nsCOMPtr<nsIDocShellTreeItem> parent;
3537 54 : NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
3538 : NS_ERROR_FAILURE);
3539 70 : while (parent) {
3540 8 : *aRootTreeItem = parent;
3541 8 : NS_ENSURE_SUCCESS(
3542 : (*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)),
3543 : NS_ERROR_FAILURE);
3544 : }
3545 54 : NS_ADDREF(*aRootTreeItem);
3546 54 : return NS_OK;
3547 : }
3548 :
3549 : NS_IMETHODIMP
3550 0 : nsDocShell::GetSameTypeRootTreeItemIgnoreBrowserBoundaries(nsIDocShell** aRootTreeItem)
3551 : {
3552 0 : NS_ENSURE_ARG_POINTER(aRootTreeItem);
3553 0 : *aRootTreeItem = static_cast<nsIDocShell *>(this);
3554 :
3555 0 : nsCOMPtr<nsIDocShell> parent;
3556 0 : NS_ENSURE_SUCCESS(GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)),
3557 : NS_ERROR_FAILURE);
3558 0 : while (parent) {
3559 0 : *aRootTreeItem = parent;
3560 0 : NS_ENSURE_SUCCESS((*aRootTreeItem)->
3561 : GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)),
3562 : NS_ERROR_FAILURE);
3563 : }
3564 0 : NS_ADDREF(*aRootTreeItem);
3565 0 : return NS_OK;
3566 : }
3567 :
3568 : /* static */
3569 : bool
3570 0 : nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
3571 : nsIDocShellTreeItem* aAccessingItem,
3572 : bool aConsiderOpener)
3573 : {
3574 0 : NS_PRECONDITION(aTargetItem, "Must have target item!");
3575 :
3576 0 : if (!gValidateOrigin || !aAccessingItem) {
3577 : // Good to go
3578 0 : return true;
3579 : }
3580 :
3581 : // XXXbz should we care if aAccessingItem or the document therein is
3582 : // chrome? Should those get extra privileges?
3583 :
3584 : // For historical context, see:
3585 : //
3586 : // Bug 13871: Prevent frameset spoofing
3587 : // Bug 103638: Targets with same name in different windows open in wrong
3588 : // window with javascript
3589 : // Bug 408052: Adopt "ancestor" frame navigation policy
3590 :
3591 : // Now do a security check.
3592 : //
3593 : // Disallow navigation if the two frames are not part of the same app, or if
3594 : // they have different is-in-browser-element states.
3595 : //
3596 : // Allow navigation if
3597 : // 1) aAccessingItem can script aTargetItem or one of its ancestors in
3598 : // the frame hierarchy or
3599 : // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
3600 : // 3) aTargetItem is a top-level frame and aAccessingItem can target
3601 : // its opener per rule (1) or (2).
3602 :
3603 0 : if (aTargetItem == aAccessingItem) {
3604 : // A frame is allowed to navigate itself.
3605 0 : return true;
3606 : }
3607 :
3608 0 : nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
3609 0 : nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
3610 0 : if (!targetDS || !accessingDS) {
3611 : // We must be able to convert both to nsIDocShell.
3612 0 : return false;
3613 : }
3614 :
3615 0 : if (targetDS->GetIsInIsolatedMozBrowserElement() !=
3616 0 : accessingDS->GetIsInIsolatedMozBrowserElement()) {
3617 0 : return false;
3618 : }
3619 :
3620 0 : nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
3621 0 : aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
3622 0 : nsCOMPtr<nsIDocShell> accessingRootDS = do_QueryInterface(accessingRoot);
3623 :
3624 0 : nsCOMPtr<nsIDocShellTreeItem> targetRoot;
3625 0 : aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
3626 0 : nsCOMPtr<nsIDocShell> targetRootDS = do_QueryInterface(targetRoot);
3627 :
3628 : OriginAttributes targetOA =
3629 0 : static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes();
3630 : OriginAttributes accessingOA =
3631 0 : static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes();
3632 :
3633 : // When the first party isolation is on, the top-level docShell may not have
3634 : // the firstPartyDomain in its originAttributes, but its document will have
3635 : // it. So we get the firstPartyDomain from the nodePrincipal of the document
3636 : // before we compare the originAttributes.
3637 0 : if (OriginAttributes::IsFirstPartyEnabled()) {
3638 0 : if (aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
3639 0 : (accessingDS == accessingRootDS || accessingDS->GetIsMozBrowser())) {
3640 :
3641 0 : nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
3642 :
3643 0 : if (accessingDoc) {
3644 0 : nsCOMPtr<nsIPrincipal> accessingPrincipal = accessingDoc->NodePrincipal();
3645 :
3646 : accessingOA.mFirstPartyDomain =
3647 0 : accessingPrincipal->OriginAttributesRef().mFirstPartyDomain;
3648 : }
3649 : }
3650 :
3651 0 : if (aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
3652 0 : (targetDS == targetRootDS || targetDS->GetIsMozBrowser())) {
3653 :
3654 0 : nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
3655 :
3656 0 : if (targetDoc) {
3657 0 : nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal();
3658 :
3659 : targetOA.mFirstPartyDomain =
3660 0 : targetPrincipal->OriginAttributesRef().mFirstPartyDomain;
3661 : }
3662 : }
3663 : }
3664 :
3665 0 : if (targetOA != accessingOA) {
3666 0 : return false;
3667 : }
3668 :
3669 : // A private document can't access a non-private one, and vice versa.
3670 0 : if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
3671 0 : static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
3672 0 : return false;
3673 : }
3674 :
3675 0 : if (aTargetItem == accessingRoot) {
3676 : // A frame can navigate its root.
3677 0 : return true;
3678 : }
3679 :
3680 : // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
3681 0 : nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
3682 0 : do {
3683 0 : if (ValidateOrigin(aAccessingItem, target)) {
3684 0 : return true;
3685 : }
3686 :
3687 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
3688 0 : target->GetSameTypeParent(getter_AddRefs(parent));
3689 0 : parent.swap(target);
3690 : } while (target);
3691 :
3692 0 : if (aTargetItem != targetRoot) {
3693 : // target is a subframe, not in accessor's frame hierarchy, and all its
3694 : // ancestors have origins different from that of the accessor. Don't
3695 : // allow access.
3696 0 : return false;
3697 : }
3698 :
3699 0 : if (!aConsiderOpener) {
3700 : // All done here
3701 0 : return false;
3702 : }
3703 :
3704 0 : nsCOMPtr<nsPIDOMWindowOuter> targetWindow = aTargetItem->GetWindow();
3705 0 : if (!targetWindow) {
3706 0 : NS_ERROR("This should not happen, really");
3707 0 : return false;
3708 : }
3709 :
3710 0 : nsCOMPtr<mozIDOMWindowProxy> targetOpener = targetWindow->GetOpener();
3711 0 : nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
3712 0 : nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
3713 :
3714 0 : if (!openerItem) {
3715 0 : return false;
3716 : }
3717 :
3718 0 : return CanAccessItem(openerItem, aAccessingItem, false);
3719 : }
3720 :
3721 : static bool
3722 0 : ItemIsActive(nsIDocShellTreeItem* aItem)
3723 : {
3724 0 : if (nsCOMPtr<nsPIDOMWindowOuter> window = aItem->GetWindow()) {
3725 0 : auto* win = nsGlobalWindow::Cast(window);
3726 0 : MOZ_ASSERT(win->IsOuterWindow());
3727 0 : if (!win->GetClosedOuter()) {
3728 0 : return true;
3729 : }
3730 : }
3731 :
3732 0 : return false;
3733 : }
3734 :
3735 : NS_IMETHODIMP
3736 0 : nsDocShell::FindItemWithName(const nsAString& aName,
3737 : nsIDocShellTreeItem* aRequestor,
3738 : nsIDocShellTreeItem* aOriginalRequestor,
3739 : bool aSkipTabGroup,
3740 : nsIDocShellTreeItem** aResult)
3741 : {
3742 0 : NS_ENSURE_ARG_POINTER(aResult);
3743 :
3744 : // If we don't find one, we return NS_OK and a null result
3745 0 : *aResult = nullptr;
3746 :
3747 0 : if (aName.IsEmpty()) {
3748 0 : return NS_OK;
3749 : }
3750 :
3751 0 : if (aRequestor) {
3752 : // If aRequestor is not null we don't need to check special names, so
3753 : // just hand straight off to the search by actual name function.
3754 0 : return DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
3755 0 : aSkipTabGroup, aResult);
3756 : } else {
3757 : // This is the entry point into the target-finding algorithm. Check
3758 : // for special names. This should only be done once, hence the check
3759 : // for a null aRequestor.
3760 :
3761 0 : nsCOMPtr<nsIDocShellTreeItem> foundItem;
3762 0 : if (aName.LowerCaseEqualsLiteral("_self")) {
3763 0 : foundItem = this;
3764 0 : } else if (aName.LowerCaseEqualsLiteral("_blank")) {
3765 : // Just return null. Caller must handle creating a new window with
3766 : // a blank name himself.
3767 0 : return NS_OK;
3768 0 : } else if (aName.LowerCaseEqualsLiteral("_parent")) {
3769 0 : GetSameTypeParent(getter_AddRefs(foundItem));
3770 0 : if (!foundItem) {
3771 0 : foundItem = this;
3772 : }
3773 0 : } else if (aName.LowerCaseEqualsLiteral("_top")) {
3774 0 : GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
3775 0 : NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
3776 : } else {
3777 : // Do the search for item by an actual name.
3778 0 : DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
3779 0 : aSkipTabGroup, getter_AddRefs(foundItem));
3780 : }
3781 :
3782 0 : if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
3783 0 : foundItem = nullptr;
3784 : }
3785 :
3786 : // DoFindItemWithName only returns active items and we don't check if
3787 : // the item is active for the special cases.
3788 0 : if (foundItem) {
3789 0 : foundItem.swap(*aResult);
3790 : }
3791 0 : return NS_OK;
3792 : }
3793 : }
3794 :
3795 : void
3796 2283 : nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
3797 : // Chrome docshells must not have a private browsing OriginAttribute
3798 : // Content docshells must maintain the equality:
3799 : // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
3800 2283 : if (mItemType == typeChrome) {
3801 2104 : MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
3802 : } else {
3803 179 : MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId);
3804 : }
3805 2283 : }
3806 :
3807 : nsresult
3808 0 : nsDocShell::DoFindItemWithName(const nsAString& aName,
3809 : nsIDocShellTreeItem* aRequestor,
3810 : nsIDocShellTreeItem* aOriginalRequestor,
3811 : bool aSkipTabGroup,
3812 : nsIDocShellTreeItem** aResult)
3813 : {
3814 : // First we check our name.
3815 0 : if (mName.Equals(aName) && ItemIsActive(this) &&
3816 0 : CanAccessItem(this, aOriginalRequestor)) {
3817 0 : NS_ADDREF(*aResult = this);
3818 0 : return NS_OK;
3819 : }
3820 :
3821 : // Second we check our children making sure not to ask a child if
3822 : // it is the aRequestor.
3823 : #ifdef DEBUG
3824 : nsresult rv =
3825 : #endif
3826 : FindChildWithName(aName, true, true, aRequestor, aOriginalRequestor,
3827 0 : aResult);
3828 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
3829 : "FindChildWithName should not be failing here.");
3830 0 : if (*aResult) {
3831 0 : return NS_OK;
3832 : }
3833 :
3834 : // Third if we have a parent and it isn't the requestor then we
3835 : // should ask it to do the search. If it is the requestor we
3836 : // should just stop here and let the parent do the rest. If we
3837 : // don't have a parent, then we should ask the
3838 : // docShellTreeOwner to do the search.
3839 : nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
3840 0 : do_QueryInterface(GetAsSupports(mParent));
3841 0 : if (parentAsTreeItem) {
3842 0 : if (parentAsTreeItem == aRequestor) {
3843 0 : return NS_OK;
3844 : }
3845 :
3846 : // If we have a same-type parent, respecting browser and app boundaries.
3847 : // NOTE: Could use GetSameTypeParent if the issues described in bug 1310344 are fixed.
3848 0 : if (!GetIsMozBrowser() && parentAsTreeItem->ItemType() == mItemType) {
3849 0 : return parentAsTreeItem->FindItemWithName(
3850 : aName,
3851 : static_cast<nsIDocShellTreeItem*>(this),
3852 : aOriginalRequestor,
3853 : /* aSkipTabGroup = */ false,
3854 0 : aResult);
3855 : }
3856 : }
3857 :
3858 : // If we have a null parent or the parent is not of the same type, we need to
3859 : // give up on finding it in our tree, and start looking in our TabGroup.
3860 0 : nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
3861 0 : if (window && !aSkipTabGroup) {
3862 0 : RefPtr<mozilla::dom::TabGroup> tabGroup = window->TabGroup();
3863 0 : tabGroup->FindItemWithName(aName, aRequestor, aOriginalRequestor, aResult);
3864 : }
3865 :
3866 0 : return NS_OK;
3867 : }
3868 :
3869 : bool
3870 0 : nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell)
3871 : {
3872 : // If no target then not sandboxed.
3873 0 : if (!aTargetDocShell) {
3874 0 : return false;
3875 : }
3876 :
3877 : // We cannot be sandboxed from ourselves.
3878 0 : if (aTargetDocShell == this) {
3879 0 : return false;
3880 : }
3881 :
3882 : // Default the sandbox flags to our flags, so that if we can't retrieve the
3883 : // active document, we will still enforce our own.
3884 0 : uint32_t sandboxFlags = mSandboxFlags;
3885 0 : if (mContentViewer) {
3886 0 : nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
3887 0 : if (doc) {
3888 0 : sandboxFlags = doc->GetSandboxFlags();
3889 : }
3890 : }
3891 :
3892 : // If no flags, we are not sandboxed at all.
3893 0 : if (!sandboxFlags) {
3894 0 : return false;
3895 : }
3896 :
3897 : // If aTargetDocShell has an ancestor, it is not top level.
3898 0 : nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
3899 0 : aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
3900 0 : if (ancestorOfTarget) {
3901 0 : do {
3902 : // We are not sandboxed if we are an ancestor of target.
3903 0 : if (ancestorOfTarget == this) {
3904 0 : return false;
3905 : }
3906 0 : nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
3907 0 : ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
3908 0 : tempTreeItem.swap(ancestorOfTarget);
3909 : } while (ancestorOfTarget);
3910 :
3911 : // Otherwise, we are sandboxed from aTargetDocShell.
3912 0 : return true;
3913 : }
3914 :
3915 : // aTargetDocShell is top level, are we the "one permitted sandboxed
3916 : // navigator", i.e. did we open aTargetDocShell?
3917 0 : nsCOMPtr<nsIDocShell> permittedNavigator;
3918 0 : aTargetDocShell->GetOnePermittedSandboxedNavigator(
3919 0 : getter_AddRefs(permittedNavigator));
3920 0 : if (permittedNavigator == this) {
3921 0 : return false;
3922 : }
3923 :
3924 : // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
3925 : // from our top.
3926 0 : if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
3927 0 : nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
3928 0 : GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
3929 0 : if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) {
3930 0 : return false;
3931 : }
3932 : }
3933 :
3934 : // Otherwise, we are sandboxed from aTargetDocShell.
3935 0 : return true;
3936 : }
3937 :
3938 : NS_IMETHODIMP
3939 80 : nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
3940 : {
3941 80 : NS_ENSURE_ARG_POINTER(aTreeOwner);
3942 :
3943 80 : *aTreeOwner = mTreeOwner;
3944 80 : NS_IF_ADDREF(*aTreeOwner);
3945 80 : return NS_OK;
3946 : }
3947 :
3948 : #ifdef DEBUG_DOCSHELL_FOCUS
3949 : static void
3950 : PrintDocTree(nsIDocShellTreeItem* aParentNode, int aLevel)
3951 : {
3952 : for (int32_t i = 0; i < aLevel; i++) {
3953 : printf(" ");
3954 : }
3955 :
3956 : int32_t childWebshellCount;
3957 : aParentNode->GetChildCount(&childWebshellCount);
3958 : nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
3959 : int32_t type = aParentNode->ItemType();
3960 : nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
3961 : RefPtr<nsPresContext> presContext;
3962 : parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
3963 : nsIDocument* doc = presShell->GetDocument();
3964 :
3965 : nsCOMPtr<nsPIDOMWindowOuter> domwin(doc->GetWindow());
3966 :
3967 : nsCOMPtr<nsIWidget> widget;
3968 : nsViewManager* vm = presShell->GetViewManager();
3969 : if (vm) {
3970 : vm->GetWidget(getter_AddRefs(widget));
3971 : }
3972 : dom::Element* rootElement = doc->GetRootElement();
3973 :
3974 : printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
3975 : (void*)parentAsDocShell.get(),
3976 : type == nsIDocShellTreeItem::typeChrome ? "Chr" : "Con",
3977 : (void*)doc, (void*)domwin.get(),
3978 : (void*)presContext->EventStateManager(), (void*)rootElement);
3979 :
3980 : if (childWebshellCount > 0) {
3981 : for (int32_t i = 0; i < childWebshellCount; i++) {
3982 : nsCOMPtr<nsIDocShellTreeItem> child;
3983 : aParentNode->GetChildAt(i, getter_AddRefs(child));
3984 : PrintDocTree(child, aLevel + 1);
3985 : }
3986 : }
3987 : }
3988 :
3989 : static void
3990 : PrintDocTree(nsIDocShellTreeItem* aParentNode)
3991 : {
3992 : NS_ASSERTION(aParentNode, "Pointer is null!");
3993 :
3994 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
3995 : aParentNode->GetParent(getter_AddRefs(parentItem));
3996 : while (parentItem) {
3997 : nsCOMPtr<nsIDocShellTreeItem> tmp;
3998 : parentItem->GetParent(getter_AddRefs(tmp));
3999 : if (!tmp) {
4000 : break;
4001 : }
4002 : parentItem = tmp;
4003 : }
4004 :
4005 : if (!parentItem) {
4006 : parentItem = aParentNode;
4007 : }
4008 :
4009 : PrintDocTree(parentItem, 0);
4010 : }
4011 : #endif
4012 :
4013 : NS_IMETHODIMP
4014 9 : nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
4015 : {
4016 : #ifdef DEBUG_DOCSHELL_FOCUS
4017 : nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
4018 : if (item) {
4019 : PrintDocTree(item);
4020 : }
4021 : #endif
4022 :
4023 : // Don't automatically set the progress based on the tree owner for frames
4024 9 : if (!IsFrame()) {
4025 : nsCOMPtr<nsIWebProgress> webProgress =
4026 16 : do_QueryInterface(GetAsSupports(this));
4027 :
4028 8 : if (webProgress) {
4029 : nsCOMPtr<nsIWebProgressListener> oldListener =
4030 16 : do_QueryInterface(mTreeOwner);
4031 : nsCOMPtr<nsIWebProgressListener> newListener =
4032 16 : do_QueryInterface(aTreeOwner);
4033 :
4034 8 : if (oldListener) {
4035 0 : webProgress->RemoveProgressListener(oldListener);
4036 : }
4037 :
4038 8 : if (newListener) {
4039 6 : webProgress->AddProgressListener(newListener,
4040 6 : nsIWebProgress::NOTIFY_ALL);
4041 : }
4042 : }
4043 : }
4044 :
4045 9 : mTreeOwner = aTreeOwner; // Weak reference per API
4046 :
4047 18 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
4048 9 : while (iter.HasMore()) {
4049 0 : nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
4050 0 : NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
4051 :
4052 0 : if (child->ItemType() == mItemType) {
4053 0 : child->SetTreeOwner(aTreeOwner);
4054 : }
4055 : }
4056 :
4057 : // Our tree owner has changed. Recompute scriptability.
4058 : //
4059 : // Note that this is near-redundant with the recomputation in
4060 : // SetDocLoaderParent(), but not so for the root DocShell, where the call to
4061 : // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
4062 : // and we never set another parent. Given that this is neither expensive nor
4063 : // performance-critical, let's be safe and unconditionally recompute this
4064 : // state whenever dependent state changes.
4065 9 : RecomputeCanExecuteScripts();
4066 :
4067 9 : return NS_OK;
4068 : }
4069 :
4070 : NS_IMETHODIMP
4071 2 : nsDocShell::SetChildOffset(uint32_t aChildOffset)
4072 : {
4073 2 : mChildOffset = aChildOffset;
4074 2 : return NS_OK;
4075 : }
4076 :
4077 : NS_IMETHODIMP
4078 0 : nsDocShell::GetHistoryID(nsID** aID)
4079 : {
4080 0 : *aID = static_cast<nsID*>(nsMemory::Clone(&mHistoryID, sizeof(nsID)));
4081 0 : return NS_OK;
4082 : }
4083 :
4084 : const nsID
4085 1 : nsDocShell::HistoryID()
4086 : {
4087 1 : return mHistoryID;
4088 : }
4089 :
4090 : NS_IMETHODIMP
4091 9 : nsDocShell::GetIsInUnload(bool* aIsInUnload)
4092 : {
4093 9 : *aIsInUnload = mFiredUnloadEvent;
4094 9 : return NS_OK;
4095 : }
4096 :
4097 : NS_IMETHODIMP
4098 425 : nsDocShell::GetChildCount(int32_t* aChildCount)
4099 : {
4100 425 : NS_ENSURE_ARG_POINTER(aChildCount);
4101 425 : *aChildCount = mChildList.Length();
4102 425 : return NS_OK;
4103 : }
4104 :
4105 : NS_IMETHODIMP
4106 2 : nsDocShell::AddChild(nsIDocShellTreeItem* aChild)
4107 : {
4108 2 : NS_ENSURE_ARG_POINTER(aChild);
4109 :
4110 4 : RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
4111 2 : NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
4112 :
4113 : // Make sure we're not creating a loop in the docshell tree
4114 2 : nsDocLoader* ancestor = this;
4115 2 : do {
4116 4 : if (childAsDocLoader == ancestor) {
4117 0 : return NS_ERROR_ILLEGAL_VALUE;
4118 : }
4119 4 : ancestor = ancestor->GetParent();
4120 4 : } while (ancestor);
4121 :
4122 : // Make sure to remove the child from its current parent.
4123 2 : nsDocLoader* childsParent = childAsDocLoader->GetParent();
4124 2 : if (childsParent) {
4125 2 : nsresult rv = childsParent->RemoveChildLoader(childAsDocLoader);
4126 2 : NS_ENSURE_SUCCESS(rv, rv);
4127 : }
4128 :
4129 : // Make sure to clear the treeowner in case this child is a different type
4130 : // from us.
4131 2 : aChild->SetTreeOwner(nullptr);
4132 :
4133 2 : nsresult res = AddChildLoader(childAsDocLoader);
4134 2 : NS_ENSURE_SUCCESS(res, res);
4135 2 : NS_ASSERTION(!mChildList.IsEmpty(),
4136 : "child list must not be empty after a successful add");
4137 :
4138 4 : nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
4139 2 : bool dynamic = false;
4140 2 : childDocShell->GetCreatedDynamically(&dynamic);
4141 2 : if (!dynamic) {
4142 0 : nsCOMPtr<nsISHEntry> currentSH;
4143 0 : bool oshe = false;
4144 0 : GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
4145 0 : if (currentSH) {
4146 0 : currentSH->HasDynamicallyAddedChild(&dynamic);
4147 : }
4148 : }
4149 2 : childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
4150 :
4151 : /* Set the child's global history if the parent has one */
4152 2 : if (mUseGlobalHistory) {
4153 0 : childDocShell->SetUseGlobalHistory(true);
4154 : }
4155 :
4156 2 : if (aChild->ItemType() != mItemType) {
4157 1 : return NS_OK;
4158 : }
4159 :
4160 1 : aChild->SetTreeOwner(mTreeOwner);
4161 :
4162 2 : nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
4163 1 : if (!childAsDocShell) {
4164 0 : return NS_OK;
4165 : }
4166 :
4167 : // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
4168 :
4169 : // Now take this document's charset and set the child's parentCharset field
4170 : // to it. We'll later use that field, in the loading process, for the
4171 : // charset choosing algorithm.
4172 : // If we fail, at any point, we just return NS_OK.
4173 : // This code has some performance impact. But this will be reduced when
4174 : // the current charset will finally be stored as an Atom, avoiding the
4175 : // alias resolution extra look-up.
4176 :
4177 : // we are NOT going to propagate the charset is this Chrome's docshell
4178 1 : if (mItemType == nsIDocShellTreeItem::typeChrome) {
4179 1 : return NS_OK;
4180 : }
4181 :
4182 : // get the parent's current charset
4183 0 : if (!mContentViewer) {
4184 0 : return NS_OK;
4185 : }
4186 0 : nsIDocument* doc = mContentViewer->GetDocument();
4187 0 : if (!doc) {
4188 0 : return NS_OK;
4189 : }
4190 :
4191 0 : bool isWyciwyg = false;
4192 :
4193 0 : if (mCurrentURI) {
4194 : // Check if the url is wyciwyg
4195 0 : mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
4196 : }
4197 :
4198 0 : if (!isWyciwyg) {
4199 : // If this docshell is loaded from a wyciwyg: URI, don't
4200 : // advertise our charset since it does not in any way reflect
4201 : // the actual source charset, which is what we're trying to
4202 : // expose here.
4203 :
4204 0 : const Encoding* parentCS = doc->GetDocumentCharacterSet();
4205 0 : int32_t charsetSource = doc->GetDocumentCharacterSetSource();
4206 : // set the child's parentCharset
4207 0 : childAsDocShell->SetParentCharset(parentCS,
4208 : charsetSource,
4209 0 : doc->NodePrincipal());
4210 : }
4211 :
4212 : // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n",
4213 : // NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
4214 :
4215 0 : return NS_OK;
4216 : }
4217 :
4218 : NS_IMETHODIMP
4219 1 : nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild)
4220 : {
4221 1 : NS_ENSURE_ARG_POINTER(aChild);
4222 :
4223 2 : RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
4224 1 : NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
4225 :
4226 1 : nsresult rv = RemoveChildLoader(childAsDocLoader);
4227 1 : NS_ENSURE_SUCCESS(rv, rv);
4228 :
4229 1 : aChild->SetTreeOwner(nullptr);
4230 :
4231 1 : return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
4232 : }
4233 :
4234 : NS_IMETHODIMP
4235 0 : nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild)
4236 : {
4237 0 : NS_ENSURE_ARG_POINTER(aChild);
4238 :
4239 : #ifdef DEBUG
4240 0 : if (aIndex < 0) {
4241 0 : NS_WARNING("Negative index passed to GetChildAt");
4242 0 : } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
4243 0 : NS_WARNING("Too large an index passed to GetChildAt");
4244 : }
4245 : #endif
4246 :
4247 0 : nsIDocumentLoader* child = ChildAt(aIndex);
4248 0 : NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
4249 :
4250 0 : return CallQueryInterface(child, aChild);
4251 : }
4252 :
4253 : NS_IMETHODIMP
4254 80 : nsDocShell::FindChildWithName(const nsAString& aName,
4255 : bool aRecurse, bool aSameType,
4256 : nsIDocShellTreeItem* aRequestor,
4257 : nsIDocShellTreeItem* aOriginalRequestor,
4258 : nsIDocShellTreeItem** aResult)
4259 : {
4260 80 : NS_ENSURE_ARG_POINTER(aResult);
4261 :
4262 : // if we don't find one, we return NS_OK and a null result
4263 80 : *aResult = nullptr;
4264 :
4265 80 : if (aName.IsEmpty()) {
4266 0 : return NS_OK;
4267 : }
4268 :
4269 160 : nsXPIDLString childName;
4270 160 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
4271 242 : while (iter.HasMore()) {
4272 161 : nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
4273 81 : NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
4274 81 : int32_t childType = child->ItemType();
4275 :
4276 81 : if (aSameType && (childType != mItemType)) {
4277 1 : continue;
4278 : }
4279 :
4280 80 : bool childNameEquals = false;
4281 80 : child->NameEquals(aName, &childNameEquals);
4282 80 : if (childNameEquals && ItemIsActive(child) &&
4283 0 : CanAccessItem(child, aOriginalRequestor)) {
4284 0 : child.swap(*aResult);
4285 0 : break;
4286 : }
4287 :
4288 : // Only ask it to check children if it is same type
4289 80 : if (childType != mItemType) {
4290 0 : continue;
4291 : }
4292 :
4293 : // Only ask the child if it isn't the requestor
4294 80 : if (aRecurse && (aRequestor != child)) {
4295 : // See if child contains the shell with the given name
4296 : #ifdef DEBUG
4297 : nsresult rv =
4298 : #endif
4299 0 : child->FindChildWithName(aName, true, aSameType,
4300 : static_cast<nsIDocShellTreeItem*>(this),
4301 0 : aOriginalRequestor, aResult);
4302 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "FindChildWithName should not fail here");
4303 0 : if (*aResult) {
4304 : // found it
4305 0 : return NS_OK;
4306 : }
4307 : }
4308 : }
4309 80 : return NS_OK;
4310 : }
4311 :
4312 : NS_IMETHODIMP
4313 0 : nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry** aResult)
4314 : {
4315 0 : nsresult rv = NS_OK;
4316 :
4317 0 : NS_ENSURE_ARG_POINTER(aResult);
4318 0 : *aResult = nullptr;
4319 :
4320 : // A nsISHEntry for a child is *only* available when the parent is in
4321 : // the progress of loading a document too...
4322 :
4323 0 : if (mLSHE) {
4324 : /* Before looking for the subframe's url, check
4325 : * the expiration status of the parent. If the parent
4326 : * has expired from cache, then subframes will not be
4327 : * loaded from history in certain situations.
4328 : */
4329 0 : bool parentExpired = false;
4330 0 : mLSHE->GetExpirationStatus(&parentExpired);
4331 :
4332 : /* Get the parent's Load Type so that it can be set on the child too.
4333 : * By default give a loadHistory value
4334 : */
4335 0 : uint32_t loadType = nsIDocShellLoadInfo::loadHistory;
4336 0 : mLSHE->GetLoadType(&loadType);
4337 : // If the user did a shift-reload on this frameset page,
4338 : // we don't want to load the subframes from history.
4339 0 : if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
4340 0 : loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
4341 0 : loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
4342 0 : loadType == nsIDocShellLoadInfo::loadRefresh) {
4343 0 : return rv;
4344 : }
4345 :
4346 : /* If the user pressed reload and the parent frame has expired
4347 : * from cache, we do not want to load the child frame from history.
4348 : */
4349 0 : if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
4350 : // The parent has expired. Return null.
4351 0 : *aResult = nullptr;
4352 0 : return rv;
4353 : }
4354 :
4355 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
4356 0 : if (container) {
4357 : // Get the child subframe from session history.
4358 0 : rv = container->GetChildAt(aChildOffset, aResult);
4359 0 : if (*aResult) {
4360 0 : (*aResult)->SetLoadType(loadType);
4361 : }
4362 : }
4363 : }
4364 0 : return rv;
4365 : }
4366 :
4367 : NS_IMETHODIMP
4368 0 : nsDocShell::AddChildSHEntry(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
4369 : int32_t aChildOffset, uint32_t aLoadType,
4370 : bool aCloneChildren)
4371 : {
4372 0 : nsresult rv = NS_OK;
4373 :
4374 0 : if (mLSHE && aLoadType != LOAD_PUSHSTATE) {
4375 : /* You get here if you are currently building a
4376 : * hierarchy ie.,you just visited a frameset page
4377 : */
4378 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
4379 0 : if (container) {
4380 0 : if (NS_FAILED(container->ReplaceChild(aNewEntry))) {
4381 0 : rv = container->AddChild(aNewEntry, aChildOffset);
4382 : }
4383 : }
4384 0 : } else if (!aCloneRef) {
4385 : /* This is an initial load in some subframe. Just append it if we can */
4386 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
4387 0 : if (container) {
4388 0 : rv = container->AddChild(aNewEntry, aChildOffset);
4389 : }
4390 : } else {
4391 0 : rv = AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset,
4392 : aLoadType, aCloneChildren);
4393 : }
4394 0 : return rv;
4395 : }
4396 :
4397 : nsresult
4398 0 : nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef,
4399 : nsISHEntry* aNewEntry,
4400 : int32_t aChildOffset,
4401 : uint32_t aLoadType,
4402 : bool aCloneChildren)
4403 : {
4404 0 : nsresult rv = NS_OK;
4405 0 : if (mSessionHistory) {
4406 : /* You are currently in the rootDocShell.
4407 : * You will get here when a subframe has a new url
4408 : * to load and you have walked up the tree all the
4409 : * way to the top to clone the current SHEntry hierarchy
4410 : * and replace the subframe where a new url was loaded with
4411 : * a new entry.
4412 : */
4413 0 : int32_t index = -1;
4414 0 : nsCOMPtr<nsISHEntry> currentHE;
4415 0 : mSessionHistory->GetIndex(&index);
4416 0 : if (index < 0) {
4417 0 : return NS_ERROR_FAILURE;
4418 : }
4419 :
4420 0 : rv = mSessionHistory->GetEntryAtIndex(index, false,
4421 0 : getter_AddRefs(currentHE));
4422 0 : NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
4423 :
4424 0 : nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
4425 0 : if (currentEntry) {
4426 0 : uint32_t cloneID = 0;
4427 0 : nsCOMPtr<nsISHEntry> nextEntry;
4428 0 : aCloneRef->GetID(&cloneID);
4429 0 : rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
4430 0 : aCloneChildren, getter_AddRefs(nextEntry));
4431 :
4432 0 : if (NS_SUCCEEDED(rv)) {
4433 : nsCOMPtr<nsISHistoryInternal> shPrivate =
4434 0 : do_QueryInterface(mSessionHistory);
4435 0 : NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
4436 0 : rv = shPrivate->AddEntry(nextEntry, true);
4437 : }
4438 : }
4439 : } else {
4440 : /* Just pass this along */
4441 : nsCOMPtr<nsIDocShell> parent =
4442 0 : do_QueryInterface(GetAsSupports(mParent), &rv);
4443 0 : if (parent) {
4444 0 : rv = static_cast<nsDocShell*>(parent.get())->AddChildSHEntryInternal(
4445 : aCloneRef, aNewEntry, aChildOffset, aLoadType, aCloneChildren);
4446 : }
4447 : }
4448 0 : return rv;
4449 : }
4450 :
4451 : nsresult
4452 0 : nsDocShell::AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
4453 : bool aCloneChildren)
4454 : {
4455 : /* You will get here when you are in a subframe and
4456 : * a new url has been loaded on you.
4457 : * The mOSHE in this subframe will be the previous url's
4458 : * mOSHE. This mOSHE will be used as the identification
4459 : * for this subframe in the CloneAndReplace function.
4460 : */
4461 :
4462 : // In this case, we will end up calling AddEntry, which increases the
4463 : // current index by 1
4464 0 : nsCOMPtr<nsISHistory> rootSH;
4465 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
4466 0 : if (rootSH) {
4467 0 : rootSH->GetIndex(&mPreviousTransIndex);
4468 : }
4469 :
4470 : nsresult rv;
4471 0 : nsCOMPtr<nsIDocShell> parent = do_QueryInterface(GetAsSupports(mParent), &rv);
4472 0 : if (parent) {
4473 0 : rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
4474 0 : aCloneChildren);
4475 : }
4476 :
4477 0 : if (rootSH) {
4478 0 : rootSH->GetIndex(&mLoadedTransIndex);
4479 : #ifdef DEBUG_PAGE_CACHE
4480 : printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
4481 : mLoadedTransIndex);
4482 : #endif
4483 : }
4484 :
4485 0 : return rv;
4486 : }
4487 :
4488 : NS_IMETHODIMP
4489 2 : nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
4490 : {
4491 : nsresult rv;
4492 :
4493 2 : mUseGlobalHistory = aUseGlobalHistory;
4494 :
4495 2 : if (!aUseGlobalHistory) {
4496 0 : mGlobalHistory = nullptr;
4497 0 : return NS_OK;
4498 : }
4499 :
4500 : // No need to initialize mGlobalHistory if IHistory is available.
4501 4 : nsCOMPtr<IHistory> history = services::GetHistoryService();
4502 2 : if (history) {
4503 2 : return NS_OK;
4504 : }
4505 :
4506 0 : if (mGlobalHistory) {
4507 0 : return NS_OK;
4508 : }
4509 :
4510 0 : mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
4511 0 : return rv;
4512 : }
4513 :
4514 : NS_IMETHODIMP
4515 0 : nsDocShell::GetUseGlobalHistory(bool* aUseGlobalHistory)
4516 : {
4517 0 : *aUseGlobalHistory = mUseGlobalHistory;
4518 0 : return NS_OK;
4519 : }
4520 :
4521 : NS_IMETHODIMP
4522 0 : nsDocShell::RemoveFromSessionHistory()
4523 : {
4524 0 : nsCOMPtr<nsISHistoryInternal> internalHistory;
4525 0 : nsCOMPtr<nsISHistory> sessionHistory;
4526 0 : nsCOMPtr<nsIDocShellTreeItem> root;
4527 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
4528 0 : if (root) {
4529 0 : nsCOMPtr<nsIWebNavigation> rootAsWebnav = do_QueryInterface(root);
4530 0 : if (rootAsWebnav) {
4531 0 : rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
4532 0 : internalHistory = do_QueryInterface(sessionHistory);
4533 : }
4534 : }
4535 0 : if (!internalHistory) {
4536 0 : return NS_OK;
4537 : }
4538 :
4539 0 : int32_t index = 0;
4540 0 : sessionHistory->GetIndex(&index);
4541 0 : AutoTArray<nsID, 16> ids({mHistoryID});
4542 0 : internalHistory->RemoveEntries(ids, index);
4543 0 : return NS_OK;
4544 : }
4545 :
4546 : NS_IMETHODIMP
4547 2 : nsDocShell::SetCreatedDynamically(bool aDynamic)
4548 : {
4549 2 : mDynamicallyCreated = aDynamic;
4550 2 : return NS_OK;
4551 : }
4552 :
4553 : NS_IMETHODIMP
4554 2 : nsDocShell::GetCreatedDynamically(bool* aDynamic)
4555 : {
4556 2 : *aDynamic = mDynamicallyCreated;
4557 2 : return NS_OK;
4558 : }
4559 :
4560 : NS_IMETHODIMP
4561 1 : nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
4562 : {
4563 1 : *aOSHE = false;
4564 1 : *aEntry = nullptr;
4565 1 : if (mLSHE) {
4566 0 : NS_ADDREF(*aEntry = mLSHE);
4567 1 : } else if (mOSHE) {
4568 0 : NS_ADDREF(*aEntry = mOSHE);
4569 0 : *aOSHE = true;
4570 : }
4571 1 : return NS_OK;
4572 : }
4573 :
4574 : nsIScriptGlobalObject*
4575 0 : nsDocShell::GetScriptGlobalObject()
4576 : {
4577 0 : NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
4578 0 : return mScriptGlobal;
4579 : }
4580 :
4581 : nsIDocument*
4582 195 : nsDocShell::GetDocument()
4583 : {
4584 195 : NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr);
4585 195 : return mContentViewer->GetDocument();
4586 : }
4587 :
4588 : nsPIDOMWindowOuter*
4589 130 : nsDocShell::GetWindow()
4590 : {
4591 130 : if (NS_FAILED(EnsureScriptEnvironment())) {
4592 1 : return nullptr;
4593 : }
4594 129 : return mScriptGlobal->AsOuter();
4595 : }
4596 :
4597 : NS_IMETHODIMP
4598 0 : nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
4599 : {
4600 0 : if (mDeviceSizeIsPageSize != aValue) {
4601 0 : mDeviceSizeIsPageSize = aValue;
4602 0 : RefPtr<nsPresContext> presContext;
4603 0 : GetPresContext(getter_AddRefs(presContext));
4604 0 : if (presContext) {
4605 0 : presContext->MediaFeatureValuesChanged(nsRestyleHint(0));
4606 : }
4607 : }
4608 0 : return NS_OK;
4609 : }
4610 :
4611 : NS_IMETHODIMP
4612 6 : nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
4613 : {
4614 6 : *aValue = mDeviceSizeIsPageSize;
4615 6 : return NS_OK;
4616 : }
4617 :
4618 : void
4619 0 : nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
4620 : {
4621 0 : nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
4622 0 : nsCOMPtr<nsISHistory> rootSH;
4623 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
4624 0 : nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
4625 0 : if (!history || !shcontainer) {
4626 0 : return;
4627 : }
4628 :
4629 0 : int32_t count = 0;
4630 0 : shcontainer->GetChildCount(&count);
4631 0 : AutoTArray<nsID, 16> ids;
4632 0 : for (int32_t i = 0; i < count; ++i) {
4633 0 : nsCOMPtr<nsISHEntry> child;
4634 0 : shcontainer->GetChildAt(i, getter_AddRefs(child));
4635 0 : if (child) {
4636 0 : ids.AppendElement(child->DocshellID());
4637 : }
4638 : }
4639 0 : int32_t index = 0;
4640 0 : rootSH->GetIndex(&index);
4641 0 : history->RemoveEntries(ids, index);
4642 : }
4643 :
4644 : //-------------------------------------
4645 : //-- Helper Method for Print discovery
4646 : //-------------------------------------
4647 : bool
4648 11 : nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
4649 : {
4650 11 : if (mIsPrintingOrPP && aDisplayErrorDialog) {
4651 0 : DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
4652 : }
4653 :
4654 11 : return mIsPrintingOrPP;
4655 : }
4656 :
4657 : bool
4658 11 : nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog,
4659 : bool aCheckIfUnloadFired)
4660 : {
4661 33 : bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) &&
4662 27 : (!aCheckIfUnloadFired || !mFiredUnloadEvent);
4663 11 : if (!isAllowed) {
4664 0 : return false;
4665 : }
4666 11 : if (!mContentViewer) {
4667 1 : return true;
4668 : }
4669 : bool firingBeforeUnload;
4670 10 : mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
4671 10 : return !firingBeforeUnload;
4672 : }
4673 :
4674 : //*****************************************************************************
4675 : // nsDocShell::nsIWebNavigation
4676 : //*****************************************************************************
4677 :
4678 : NS_IMETHODIMP
4679 1 : nsDocShell::GetCanGoBack(bool* aCanGoBack)
4680 : {
4681 1 : if (!IsNavigationAllowed(false)) {
4682 0 : *aCanGoBack = false;
4683 0 : return NS_OK; // JS may not handle returning of an error code
4684 : }
4685 : nsresult rv;
4686 2 : nsCOMPtr<nsISHistory> rootSH;
4687 1 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4688 2 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4689 1 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4690 1 : rv = webnav->GetCanGoBack(aCanGoBack);
4691 1 : return rv;
4692 : }
4693 :
4694 : NS_IMETHODIMP
4695 1 : nsDocShell::GetCanGoForward(bool* aCanGoForward)
4696 : {
4697 1 : if (!IsNavigationAllowed(false)) {
4698 0 : *aCanGoForward = false;
4699 0 : return NS_OK; // JS may not handle returning of an error code
4700 : }
4701 : nsresult rv;
4702 2 : nsCOMPtr<nsISHistory> rootSH;
4703 1 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4704 2 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4705 1 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4706 1 : rv = webnav->GetCanGoForward(aCanGoForward);
4707 1 : return rv;
4708 : }
4709 :
4710 : NS_IMETHODIMP
4711 0 : nsDocShell::GoBack()
4712 : {
4713 0 : if (!IsNavigationAllowed()) {
4714 0 : return NS_OK; // JS may not handle returning of an error code
4715 : }
4716 : nsresult rv;
4717 0 : nsCOMPtr<nsISHistory> rootSH;
4718 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4719 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4720 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4721 0 : rv = webnav->GoBack();
4722 0 : return rv;
4723 : }
4724 :
4725 : NS_IMETHODIMP
4726 0 : nsDocShell::GoForward()
4727 : {
4728 0 : if (!IsNavigationAllowed()) {
4729 0 : return NS_OK; // JS may not handle returning of an error code
4730 : }
4731 : nsresult rv;
4732 0 : nsCOMPtr<nsISHistory> rootSH;
4733 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4734 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4735 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4736 0 : rv = webnav->GoForward();
4737 0 : return rv;
4738 : }
4739 :
4740 : NS_IMETHODIMP
4741 0 : nsDocShell::GotoIndex(int32_t aIndex)
4742 : {
4743 0 : if (!IsNavigationAllowed()) {
4744 0 : return NS_OK; // JS may not handle returning of an error code
4745 : }
4746 : nsresult rv;
4747 0 : nsCOMPtr<nsISHistory> rootSH;
4748 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4749 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
4750 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
4751 0 : rv = webnav->GotoIndex(aIndex);
4752 0 : return rv;
4753 : }
4754 :
4755 : NS_IMETHODIMP
4756 2 : nsDocShell::LoadURI(const char16_t* aURI,
4757 : uint32_t aLoadFlags,
4758 : nsIURI* aReferringURI,
4759 : nsIInputStream* aPostStream,
4760 : nsIInputStream* aHeaderStream,
4761 : nsIPrincipal* aTriggeringPrincipal)
4762 : {
4763 : return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI,
4764 : mozilla::net::RP_Unset, aPostStream,
4765 2 : aHeaderStream, nullptr, aTriggeringPrincipal);
4766 : }
4767 :
4768 : NS_IMETHODIMP
4769 3 : nsDocShell::LoadURIWithOptions(const char16_t* aURI,
4770 : uint32_t aLoadFlags,
4771 : nsIURI* aReferringURI,
4772 : uint32_t aReferrerPolicy,
4773 : nsIInputStream* aPostStream,
4774 : nsIInputStream* aHeaderStream,
4775 : nsIURI* aBaseURI,
4776 : nsIPrincipal* aTriggeringPrincipal)
4777 : {
4778 3 : NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
4779 :
4780 3 : if (!IsNavigationAllowed()) {
4781 0 : return NS_OK; // JS may not handle returning of an error code
4782 : }
4783 6 : nsCOMPtr<nsIURI> uri;
4784 6 : nsCOMPtr<nsIInputStream> postStream(aPostStream);
4785 3 : nsresult rv = NS_OK;
4786 :
4787 : // Create a URI from our string; if that succeeds, we want to
4788 : // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
4789 : // flag.
4790 :
4791 6 : NS_ConvertUTF16toUTF8 uriString(aURI);
4792 : // Cleanup the empty spaces that might be on each end.
4793 3 : uriString.Trim(" ");
4794 : // Eliminate embedded newlines, which single-line text fields now allow:
4795 3 : uriString.StripCRLF();
4796 3 : NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
4797 :
4798 3 : rv = NS_NewURI(getter_AddRefs(uri), uriString);
4799 3 : if (uri) {
4800 3 : aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
4801 : }
4802 :
4803 6 : nsCOMPtr<nsIURIFixupInfo> fixupInfo;
4804 3 : if (sURIFixup) {
4805 : // Call the fixup object. This will clobber the rv from NS_NewURI
4806 : // above, but that's fine with us. Note that we need to do this even
4807 : // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
4808 : // (things like view-source:mozilla.org for example).
4809 3 : uint32_t fixupFlags = 0;
4810 3 : if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
4811 0 : fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
4812 : }
4813 3 : if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
4814 0 : fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
4815 : }
4816 6 : nsCOMPtr<nsIInputStream> fixupStream;
4817 9 : rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
4818 6 : getter_AddRefs(fixupStream),
4819 9 : getter_AddRefs(fixupInfo));
4820 :
4821 3 : if (NS_SUCCEEDED(rv)) {
4822 3 : fixupInfo->GetPreferredURI(getter_AddRefs(uri));
4823 3 : fixupInfo->SetConsumer(GetAsSupports(this));
4824 : }
4825 :
4826 3 : if (fixupStream) {
4827 : // GetFixupURIInfo only returns a post data stream if it succeeded
4828 : // and changed the URI, in which case we should override the
4829 : // passed-in post data.
4830 0 : postStream = fixupStream;
4831 : }
4832 :
4833 3 : if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
4834 0 : nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
4835 0 : if (serv) {
4836 0 : serv->NotifyObservers(fixupInfo, "keyword-uri-fixup", aURI);
4837 : }
4838 : }
4839 : }
4840 : // else no fixup service so just use the URI we created and see
4841 : // what happens
4842 :
4843 3 : if (NS_ERROR_MALFORMED_URI == rv) {
4844 0 : if (DisplayLoadError(rv, uri, aURI, nullptr) &&
4845 0 : (aLoadFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
4846 0 : return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
4847 : }
4848 : }
4849 :
4850 3 : if (NS_FAILED(rv) || !uri) {
4851 0 : return NS_ERROR_FAILURE;
4852 : }
4853 :
4854 : PopupControlState popupState;
4855 3 : if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
4856 0 : popupState = openAllowed;
4857 0 : aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
4858 : } else {
4859 3 : popupState = openOverridden;
4860 : }
4861 6 : nsAutoPopupStatePusher statePusher(popupState);
4862 :
4863 : // Don't pass certain flags that aren't needed and end up confusing
4864 : // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
4865 : // passed to LoadURI though, since it uses them.
4866 3 : uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
4867 3 : aLoadFlags &= ~EXTRA_LOAD_FLAGS;
4868 :
4869 6 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
4870 3 : rv = CreateLoadInfo(getter_AddRefs(loadInfo));
4871 3 : if (NS_FAILED(rv)) {
4872 0 : return rv;
4873 : }
4874 :
4875 : /*
4876 : * If the user "Disables Protection on This Page", we have to make sure to
4877 : * remember the users decision when opening links in child tabs [Bug 906190]
4878 : */
4879 : uint32_t loadType;
4880 3 : if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
4881 0 : loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
4882 : } else {
4883 3 : loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
4884 : }
4885 :
4886 3 : loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
4887 3 : loadInfo->SetPostDataStream(postStream);
4888 3 : loadInfo->SetReferrer(aReferringURI);
4889 3 : loadInfo->SetReferrerPolicy(aReferrerPolicy);
4890 3 : loadInfo->SetHeadersStream(aHeaderStream);
4891 3 : loadInfo->SetBaseURI(aBaseURI);
4892 3 : loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
4893 :
4894 3 : if (fixupInfo) {
4895 6 : nsAutoString searchProvider, keyword;
4896 3 : fixupInfo->GetKeywordProviderName(searchProvider);
4897 3 : fixupInfo->GetKeywordAsSent(keyword);
4898 3 : MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
4899 : }
4900 :
4901 3 : rv = LoadURI(uri, loadInfo, extraFlags, true);
4902 :
4903 : // Save URI string in case it's needed later when
4904 : // sending to search engine service in EndPageLoad()
4905 3 : mOriginalUriString = uriString;
4906 :
4907 3 : return rv;
4908 : }
4909 :
4910 : NS_IMETHODIMP
4911 0 : nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
4912 : const char16_t* aURL,
4913 : nsIChannel* aFailedChannel,
4914 : bool* aDisplayedErrorPage)
4915 : {
4916 0 : *aDisplayedErrorPage = false;
4917 : // Get prompt and string bundle servcies
4918 0 : nsCOMPtr<nsIPrompt> prompter;
4919 0 : nsCOMPtr<nsIStringBundle> stringBundle;
4920 0 : GetPromptAndStringBundle(getter_AddRefs(prompter),
4921 0 : getter_AddRefs(stringBundle));
4922 :
4923 0 : NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
4924 0 : NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
4925 :
4926 0 : nsAutoString error;
4927 0 : const uint32_t kMaxFormatStrArgs = 3;
4928 0 : nsAutoString formatStrs[kMaxFormatStrArgs];
4929 0 : uint32_t formatStrCount = 0;
4930 0 : bool addHostPort = false;
4931 0 : nsresult rv = NS_OK;
4932 0 : nsAutoString messageStr;
4933 0 : nsAutoCString cssClass;
4934 0 : nsAutoCString errorPage;
4935 :
4936 0 : errorPage.AssignLiteral("neterror");
4937 :
4938 : // Turn the error code into a human readable error message.
4939 0 : if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
4940 0 : NS_ENSURE_ARG_POINTER(aURI);
4941 :
4942 : // Extract the schemes into a comma delimited list.
4943 0 : nsAutoCString scheme;
4944 0 : aURI->GetScheme(scheme);
4945 0 : CopyASCIItoUTF16(scheme, formatStrs[0]);
4946 0 : nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
4947 0 : while (nestedURI) {
4948 0 : nsCOMPtr<nsIURI> tempURI;
4949 : nsresult rv2;
4950 0 : rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
4951 0 : if (NS_SUCCEEDED(rv2) && tempURI) {
4952 0 : tempURI->GetScheme(scheme);
4953 0 : formatStrs[0].AppendLiteral(", ");
4954 0 : AppendASCIItoUTF16(scheme, formatStrs[0]);
4955 : }
4956 0 : nestedURI = do_QueryInterface(tempURI);
4957 : }
4958 0 : formatStrCount = 1;
4959 0 : error.AssignLiteral("unknownProtocolFound");
4960 0 : } else if (NS_ERROR_FILE_NOT_FOUND == aError) {
4961 0 : NS_ENSURE_ARG_POINTER(aURI);
4962 0 : error.AssignLiteral("fileNotFound");
4963 0 : } else if (NS_ERROR_FILE_ACCESS_DENIED == aError) {
4964 0 : NS_ENSURE_ARG_POINTER(aURI);
4965 0 : error.AssignLiteral("fileAccessDenied");
4966 0 : } else if (NS_ERROR_UNKNOWN_HOST == aError) {
4967 0 : NS_ENSURE_ARG_POINTER(aURI);
4968 : // Get the host
4969 0 : nsAutoCString host;
4970 0 : nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
4971 0 : innermostURI->GetHost(host);
4972 0 : CopyUTF8toUTF16(host, formatStrs[0]);
4973 0 : formatStrCount = 1;
4974 0 : error.AssignLiteral("dnsNotFound");
4975 0 : } else if (NS_ERROR_CONNECTION_REFUSED == aError) {
4976 0 : NS_ENSURE_ARG_POINTER(aURI);
4977 0 : addHostPort = true;
4978 0 : error.AssignLiteral("connectionFailure");
4979 0 : } else if (NS_ERROR_NET_INTERRUPT == aError) {
4980 0 : NS_ENSURE_ARG_POINTER(aURI);
4981 0 : addHostPort = true;
4982 0 : error.AssignLiteral("netInterrupt");
4983 0 : } else if (NS_ERROR_NET_TIMEOUT == aError) {
4984 0 : NS_ENSURE_ARG_POINTER(aURI);
4985 : // Get the host
4986 0 : nsAutoCString host;
4987 0 : aURI->GetHost(host);
4988 0 : CopyUTF8toUTF16(host, formatStrs[0]);
4989 0 : formatStrCount = 1;
4990 0 : error.AssignLiteral("netTimeout");
4991 0 : } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError ||
4992 : NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) {
4993 : // CSP error
4994 0 : cssClass.AssignLiteral("neterror");
4995 0 : error.AssignLiteral("cspBlocked");
4996 0 : } else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
4997 : nsCOMPtr<nsINSSErrorsService> nsserr =
4998 0 : do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
4999 :
5000 : uint32_t errorClass;
5001 0 : if (!nsserr || NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
5002 0 : errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
5003 : }
5004 :
5005 0 : nsCOMPtr<nsISupports> securityInfo;
5006 0 : nsCOMPtr<nsITransportSecurityInfo> tsi;
5007 0 : if (aFailedChannel) {
5008 0 : aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
5009 : }
5010 0 : tsi = do_QueryInterface(securityInfo);
5011 0 : if (tsi) {
5012 : uint32_t securityState;
5013 0 : tsi->GetSecurityState(&securityState);
5014 0 : if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) {
5015 0 : error.AssignLiteral("sslv3Used");
5016 0 : addHostPort = true;
5017 0 : } else if (securityState & nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) {
5018 0 : error.AssignLiteral("weakCryptoUsed");
5019 0 : addHostPort = true;
5020 : } else {
5021 : // Usually we should have aFailedChannel and get a detailed message
5022 0 : tsi->GetErrorMessage(getter_Copies(messageStr));
5023 : }
5024 : } else {
5025 : // No channel, let's obtain the generic error message
5026 0 : if (nsserr) {
5027 0 : nsserr->GetErrorMessage(aError, messageStr);
5028 : }
5029 : }
5030 0 : if (!messageStr.IsEmpty()) {
5031 0 : if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
5032 0 : error.AssignLiteral("nssBadCert");
5033 :
5034 : // If this is an HTTP Strict Transport Security host or a pinned host
5035 : // and the certificate is bad, don't allow overrides (RFC 6797 section
5036 : // 12.1, HPKP draft spec section 2.6).
5037 : uint32_t flags =
5038 0 : UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
5039 0 : bool isStsHost = false;
5040 0 : bool isPinnedHost = false;
5041 0 : if (XRE_IsParentProcess()) {
5042 : nsCOMPtr<nsISiteSecurityService> sss =
5043 0 : do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
5044 0 : NS_ENSURE_SUCCESS(rv, rv);
5045 0 : rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
5046 : flags, mOriginAttributes, nullptr, nullptr,
5047 0 : &isStsHost);
5048 0 : NS_ENSURE_SUCCESS(rv, rv);
5049 0 : rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
5050 : flags, mOriginAttributes, nullptr, nullptr,
5051 0 : &isPinnedHost);
5052 0 : NS_ENSURE_SUCCESS(rv, rv);
5053 : } else {
5054 : mozilla::dom::ContentChild* cc =
5055 0 : mozilla::dom::ContentChild::GetSingleton();
5056 0 : mozilla::ipc::URIParams uri;
5057 0 : SerializeURI(aURI, uri);
5058 0 : cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
5059 0 : mOriginAttributes, &isStsHost);
5060 0 : cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
5061 0 : mOriginAttributes, &isPinnedHost);
5062 : }
5063 :
5064 0 : if (Preferences::GetBool(
5065 : "browser.xul.error_pages.expert_bad_cert", false)) {
5066 0 : cssClass.AssignLiteral("expertBadCert");
5067 : }
5068 :
5069 : // HSTS/pinning takes precedence over the expert bad cert pref. We
5070 : // never want to show the "Add Exception" button for these sites.
5071 : // In the future we should differentiate between an HSTS host and a
5072 : // pinned host and display a more informative message to the user.
5073 0 : if (isStsHost || isPinnedHost) {
5074 0 : cssClass.AssignLiteral("badStsCert");
5075 : }
5076 :
5077 : uint32_t bucketId;
5078 0 : if (isStsHost) {
5079 : // measuring STS separately allows us to measure click through
5080 : // rates easily
5081 0 : bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
5082 : } else {
5083 0 : bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
5084 : }
5085 :
5086 : // See if an alternate cert error page is registered
5087 : nsAdoptingCString alternateErrorPage =
5088 0 : Preferences::GetCString("security.alternate_certificate_error_page");
5089 0 : if (alternateErrorPage) {
5090 0 : errorPage.Assign(alternateErrorPage);
5091 : }
5092 :
5093 0 : if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) {
5094 0 : Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
5095 : }
5096 :
5097 : } else {
5098 0 : error.AssignLiteral("nssFailure2");
5099 : }
5100 : }
5101 0 : } else if (NS_ERROR_PHISHING_URI == aError ||
5102 0 : NS_ERROR_MALWARE_URI == aError ||
5103 : NS_ERROR_UNWANTED_URI == aError) {
5104 0 : nsAutoCString host;
5105 0 : aURI->GetHost(host);
5106 0 : CopyUTF8toUTF16(host, formatStrs[0]);
5107 0 : formatStrCount = 1;
5108 :
5109 : // Malware and phishing detectors may want to use an alternate error
5110 : // page, but if the pref's not set, we'll fall back on the standard page
5111 : nsAdoptingCString alternateErrorPage =
5112 0 : Preferences::GetCString("urlclassifier.alternate_error_page");
5113 0 : if (alternateErrorPage) {
5114 0 : errorPage.Assign(alternateErrorPage);
5115 : }
5116 :
5117 : uint32_t bucketId;
5118 0 : bool sendTelemetry = false;
5119 0 : if (NS_ERROR_PHISHING_URI == aError) {
5120 0 : sendTelemetry = true;
5121 0 : error.AssignLiteral("deceptiveBlocked");
5122 0 : bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME
5123 : : nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP;
5124 0 : } else if (NS_ERROR_MALWARE_URI == aError) {
5125 0 : sendTelemetry = true;
5126 0 : error.AssignLiteral("malwareBlocked");
5127 0 : bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME
5128 : : nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP;
5129 0 : } else if (NS_ERROR_UNWANTED_URI == aError) {
5130 0 : sendTelemetry = true;
5131 0 : error.AssignLiteral("unwantedBlocked");
5132 0 : bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_UNWANTED_PAGE_FRAME
5133 : : nsISecurityUITelemetry::WARNING_UNWANTED_PAGE_TOP;
5134 : }
5135 :
5136 0 : if (sendTelemetry && errorPage.EqualsIgnoreCase("blocked")) {
5137 0 : Telemetry::Accumulate(Telemetry::SECURITY_UI, bucketId);
5138 : }
5139 :
5140 0 : cssClass.AssignLiteral("blacklist");
5141 0 : } else if (NS_ERROR_CONTENT_CRASHED == aError) {
5142 0 : errorPage.AssignLiteral("tabcrashed");
5143 0 : error.AssignLiteral("tabcrashed");
5144 :
5145 0 : nsCOMPtr<EventTarget> handler = mChromeEventHandler;
5146 0 : if (handler) {
5147 0 : nsCOMPtr<Element> element = do_QueryInterface(handler);
5148 0 : element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
5149 : }
5150 :
5151 : // DisplayLoadError requires a non-empty messageStr to proceed and call
5152 : // LoadErrorPage. If the page doesn't have a title, we will use a blank
5153 : // space which will be trimmed and thus treated as empty by the front-end.
5154 0 : if (messageStr.IsEmpty()) {
5155 0 : messageStr.AssignLiteral(u" ");
5156 : }
5157 : } else {
5158 : // Errors requiring simple formatting
5159 0 : switch (aError) {
5160 : case NS_ERROR_MALFORMED_URI:
5161 : // URI is malformed
5162 0 : error.AssignLiteral("malformedURI");
5163 0 : break;
5164 : case NS_ERROR_REDIRECT_LOOP:
5165 : // Doc failed to load because the server generated too many redirects
5166 0 : error.AssignLiteral("redirectLoop");
5167 0 : break;
5168 : case NS_ERROR_UNKNOWN_SOCKET_TYPE:
5169 : // Doc failed to load because PSM is not installed
5170 0 : error.AssignLiteral("unknownSocketType");
5171 0 : break;
5172 : case NS_ERROR_NET_RESET:
5173 : // Doc failed to load because the server kept reseting the connection
5174 : // before we could read any data from it
5175 0 : error.AssignLiteral("netReset");
5176 0 : break;
5177 : case NS_ERROR_DOCUMENT_NOT_CACHED:
5178 : // Doc failed to load because the cache does not contain a copy of
5179 : // the document.
5180 0 : error.AssignLiteral("notCached");
5181 0 : break;
5182 : case NS_ERROR_OFFLINE:
5183 : // Doc failed to load because we are offline.
5184 0 : error.AssignLiteral("netOffline");
5185 0 : break;
5186 : case NS_ERROR_DOCUMENT_IS_PRINTMODE:
5187 : // Doc navigation attempted while Printing or Print Preview
5188 0 : error.AssignLiteral("isprinting");
5189 0 : break;
5190 : case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
5191 : // Port blocked for security reasons
5192 0 : addHostPort = true;
5193 0 : error.AssignLiteral("deniedPortAccess");
5194 0 : break;
5195 : case NS_ERROR_UNKNOWN_PROXY_HOST:
5196 : // Proxy hostname could not be resolved.
5197 0 : error.AssignLiteral("proxyResolveFailure");
5198 0 : break;
5199 : case NS_ERROR_PROXY_CONNECTION_REFUSED:
5200 : // Proxy connection was refused.
5201 0 : error.AssignLiteral("proxyConnectFailure");
5202 0 : break;
5203 : case NS_ERROR_INVALID_CONTENT_ENCODING:
5204 : // Bad Content Encoding.
5205 0 : error.AssignLiteral("contentEncodingError");
5206 0 : break;
5207 : case NS_ERROR_REMOTE_XUL:
5208 0 : error.AssignLiteral("remoteXUL");
5209 0 : break;
5210 : case NS_ERROR_UNSAFE_CONTENT_TYPE:
5211 : // Channel refused to load from an unrecognized content type.
5212 0 : error.AssignLiteral("unsafeContentType");
5213 0 : break;
5214 : case NS_ERROR_CORRUPTED_CONTENT:
5215 : // Broken Content Detected. e.g. Content-MD5 check failure.
5216 0 : error.AssignLiteral("corruptedContentErrorv2");
5217 0 : break;
5218 : case NS_ERROR_INTERCEPTION_FAILED:
5219 : // ServiceWorker intercepted request, but something went wrong.
5220 0 : error.AssignLiteral("corruptedContentErrorv2");
5221 0 : break;
5222 : case NS_ERROR_NET_INADEQUATE_SECURITY:
5223 : // Server negotiated bad TLS for HTTP/2.
5224 0 : error.AssignLiteral("inadequateSecurityError");
5225 0 : addHostPort = true;
5226 0 : break;
5227 : default:
5228 0 : break;
5229 : }
5230 : }
5231 :
5232 : // Test if the error should be displayed
5233 0 : if (error.IsEmpty()) {
5234 0 : return NS_OK;
5235 : }
5236 :
5237 : // Test if the error needs to be formatted
5238 0 : if (!messageStr.IsEmpty()) {
5239 : // already obtained message
5240 : } else {
5241 0 : if (addHostPort) {
5242 : // Build up the host:port string.
5243 0 : nsAutoCString hostport;
5244 0 : if (aURI) {
5245 0 : aURI->GetHostPort(hostport);
5246 : } else {
5247 0 : hostport.Assign('?');
5248 : }
5249 0 : CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
5250 : }
5251 :
5252 0 : nsAutoCString spec;
5253 0 : rv = NS_ERROR_NOT_AVAILABLE;
5254 0 : if (aURI) {
5255 : // displaying "file://" is aesthetically unpleasing and could even be
5256 : // confusing to the user
5257 0 : bool isFileURI = false;
5258 0 : rv = aURI->SchemeIs("file", &isFileURI);
5259 0 : if (NS_SUCCEEDED(rv) && isFileURI) {
5260 0 : aURI->GetPath(spec);
5261 : } else {
5262 0 : aURI->GetSpec(spec);
5263 : }
5264 :
5265 0 : nsAutoCString charset;
5266 : // unescape and convert from origin charset
5267 0 : aURI->GetOriginCharset(charset);
5268 : nsCOMPtr<nsITextToSubURI> textToSubURI(
5269 0 : do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
5270 0 : if (NS_SUCCEEDED(rv)) {
5271 0 : rv = textToSubURI->UnEscapeURIForUI(charset, spec,
5272 0 : formatStrs[formatStrCount]);
5273 : }
5274 : } else {
5275 0 : spec.Assign('?');
5276 : }
5277 0 : if (NS_FAILED(rv)) {
5278 0 : CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
5279 : }
5280 0 : rv = NS_OK;
5281 0 : ++formatStrCount;
5282 :
5283 : const char16_t* strs[kMaxFormatStrArgs];
5284 0 : for (uint32_t i = 0; i < formatStrCount; i++) {
5285 0 : strs[i] = formatStrs[i].get();
5286 : }
5287 0 : nsXPIDLString str;
5288 0 : rv = stringBundle->FormatStringFromName(error.get(), strs, formatStrCount,
5289 0 : getter_Copies(str));
5290 0 : NS_ENSURE_SUCCESS(rv, rv);
5291 0 : messageStr.Assign(str.get());
5292 : }
5293 :
5294 : // Display the error as a page or an alert prompt
5295 0 : NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
5296 :
5297 0 : if (NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) {
5298 0 : bool isSecureURI = false;
5299 0 : rv = aURI->SchemeIs("https", &isSecureURI);
5300 0 : if (NS_SUCCEEDED(rv) && isSecureURI) {
5301 : // Maybe TLS intolerant. Treat this as an SSL error.
5302 0 : error.AssignLiteral("nssFailure2");
5303 : }
5304 : }
5305 :
5306 0 : if (UseErrorPages()) {
5307 : // Display an error page
5308 0 : nsresult loadedPage = LoadErrorPage(aURI, aURL, errorPage.get(),
5309 : error.get(), messageStr.get(),
5310 0 : cssClass.get(), aFailedChannel);
5311 0 : *aDisplayedErrorPage = NS_SUCCEEDED(loadedPage);
5312 : } else {
5313 : // The prompter reqires that our private window has a document (or it
5314 : // asserts). Satisfy that assertion now since GetDoc will force
5315 : // creation of one if it hasn't already been created.
5316 0 : if (mScriptGlobal) {
5317 0 : Unused << mScriptGlobal->GetDoc();
5318 : }
5319 :
5320 : // Display a message box
5321 0 : prompter->Alert(nullptr, messageStr.get());
5322 : }
5323 :
5324 0 : return NS_OK;
5325 : }
5326 :
5327 : #define PREF_SAFEBROWSING_ALLOWOVERRIDE "browser.safebrowsing.allowOverride"
5328 :
5329 : NS_IMETHODIMP
5330 0 : nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
5331 : const char* aErrorPage,
5332 : const char16_t* aErrorType,
5333 : const char16_t* aDescription,
5334 : const char* aCSSClass,
5335 : nsIChannel* aFailedChannel)
5336 : {
5337 : #if defined(DEBUG)
5338 0 : if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
5339 0 : nsAutoCString chanName;
5340 0 : if (aFailedChannel) {
5341 0 : aFailedChannel->GetName(chanName);
5342 : } else {
5343 0 : chanName.AssignLiteral("<no channel>");
5344 : }
5345 :
5346 0 : MOZ_LOG(gDocShellLog, LogLevel::Debug,
5347 : ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
5348 : aURI ? aURI->GetSpecOrDefault().get() : "",
5349 : NS_ConvertUTF16toUTF8(aURL).get(),
5350 : chanName.get()));
5351 : }
5352 : #endif
5353 0 : mFailedChannel = aFailedChannel;
5354 0 : mFailedURI = aURI;
5355 0 : mFailedLoadType = mLoadType;
5356 :
5357 0 : if (mLSHE) {
5358 : // Abandon mLSHE's BFCache entry and create a new one. This way, if
5359 : // we go back or forward to another SHEntry with the same doc
5360 : // identifier, the error page won't persist.
5361 0 : mLSHE->AbandonBFCacheEntry();
5362 : }
5363 :
5364 0 : nsAutoCString url;
5365 0 : nsAutoCString charset;
5366 0 : if (aURI) {
5367 0 : nsresult rv = aURI->GetSpec(url);
5368 0 : NS_ENSURE_SUCCESS(rv, rv);
5369 0 : rv = aURI->GetOriginCharset(charset);
5370 0 : NS_ENSURE_SUCCESS(rv, rv);
5371 0 : } else if (aURL) {
5372 0 : CopyUTF16toUTF8(aURL, url);
5373 : } else {
5374 0 : return NS_ERROR_INVALID_POINTER;
5375 : }
5376 :
5377 : // Create a URL to pass all the error information through to the page.
5378 :
5379 : #undef SAFE_ESCAPE
5380 : #define SAFE_ESCAPE(output, input, params) \
5381 : if (NS_WARN_IF(!NS_Escape(input, output, params))) { \
5382 : return NS_ERROR_OUT_OF_MEMORY; \
5383 : }
5384 :
5385 0 : nsCString escapedUrl, escapedCharset, escapedError, escapedDescription,
5386 0 : escapedCSSClass;
5387 0 : SAFE_ESCAPE(escapedUrl, url, url_Path);
5388 0 : SAFE_ESCAPE(escapedCharset, charset, url_Path);
5389 0 : SAFE_ESCAPE(escapedError, NS_ConvertUTF16toUTF8(aErrorType), url_Path);
5390 0 : SAFE_ESCAPE(escapedDescription,
5391 : NS_ConvertUTF16toUTF8(aDescription), url_Path);
5392 0 : if (aCSSClass) {
5393 0 : nsCString cssClass(aCSSClass);
5394 0 : SAFE_ESCAPE(escapedCSSClass, cssClass, url_Path);
5395 : }
5396 0 : nsCString errorPageUrl("about:");
5397 0 : errorPageUrl.AppendASCII(aErrorPage);
5398 0 : errorPageUrl.AppendLiteral("?e=");
5399 :
5400 0 : errorPageUrl.AppendASCII(escapedError.get());
5401 0 : errorPageUrl.AppendLiteral("&u=");
5402 0 : errorPageUrl.AppendASCII(escapedUrl.get());
5403 0 : if ((strcmp(aErrorPage, "blocked") == 0) &&
5404 0 : Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE, true)) {
5405 0 : errorPageUrl.AppendLiteral("&o=1");
5406 : }
5407 0 : if (!escapedCSSClass.IsEmpty()) {
5408 0 : errorPageUrl.AppendLiteral("&s=");
5409 0 : errorPageUrl.AppendASCII(escapedCSSClass.get());
5410 : }
5411 0 : errorPageUrl.AppendLiteral("&c=");
5412 0 : errorPageUrl.AppendASCII(escapedCharset.get());
5413 :
5414 0 : nsAutoCString frameType(FrameTypeToString(mFrameType));
5415 0 : errorPageUrl.AppendLiteral("&f=");
5416 0 : errorPageUrl.AppendASCII(frameType.get());
5417 :
5418 0 : nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
5419 : int32_t cpsState;
5420 0 : if (cps && NS_SUCCEEDED(cps->GetState(&cpsState)) &&
5421 0 : cpsState == nsICaptivePortalService::LOCKED_PORTAL) {
5422 0 : errorPageUrl.AppendLiteral("&captive=true");
5423 : }
5424 :
5425 : // netError.xhtml's getDescription only handles the "d" parameter at the
5426 : // end of the URL, so append it last.
5427 0 : errorPageUrl.AppendLiteral("&d=");
5428 0 : errorPageUrl.AppendASCII(escapedDescription.get());
5429 :
5430 0 : nsCOMPtr<nsIURI> errorPageURI;
5431 0 : nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
5432 0 : NS_ENSURE_SUCCESS(rv, rv);
5433 :
5434 0 : return InternalLoad(errorPageURI, nullptr, Nothing(), false, nullptr,
5435 : mozilla::net::RP_Unset,
5436 : nsContentUtils::GetSystemPrincipal(), nullptr,
5437 0 : INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
5438 0 : nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
5439 0 : nullptr, true, NullString(), this, nullptr, false,
5440 0 : nullptr, nullptr);
5441 : }
5442 :
5443 : NS_IMETHODIMP
5444 0 : nsDocShell::Reload(uint32_t aReloadFlags)
5445 : {
5446 0 : if (!IsNavigationAllowed()) {
5447 0 : return NS_OK; // JS may not handle returning of an error code
5448 : }
5449 : nsresult rv;
5450 0 : NS_ASSERTION(((aReloadFlags & 0xf) == 0),
5451 : "Reload command not updated to use load flags!");
5452 0 : NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
5453 : "Don't pass these flags to Reload");
5454 :
5455 0 : uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
5456 0 : NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
5457 :
5458 : // Send notifications to the HistoryListener if any, about the impending
5459 : // reload
5460 0 : nsCOMPtr<nsISHistory> rootSH;
5461 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
5462 0 : nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
5463 0 : bool canReload = true;
5464 0 : if (rootSH) {
5465 0 : shistInt->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
5466 : }
5467 :
5468 0 : if (!canReload) {
5469 0 : return NS_OK;
5470 : }
5471 :
5472 : /* If you change this part of code, make sure bug 45297 does not re-occur */
5473 0 : if (mOSHE) {
5474 0 : rv = LoadHistoryEntry(mOSHE, loadType);
5475 0 : } else if (mLSHE) { // In case a reload happened before the current load is done
5476 0 : rv = LoadHistoryEntry(mLSHE, loadType);
5477 : } else {
5478 0 : nsCOMPtr<nsIDocument> doc(GetDocument());
5479 :
5480 0 : if (!doc) {
5481 0 : return NS_OK;
5482 : }
5483 :
5484 : // Do not inherit owner from document
5485 0 : uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
5486 0 : nsAutoString srcdoc;
5487 0 : nsCOMPtr<nsIURI> baseURI;
5488 0 : nsCOMPtr<nsIURI> originalURI;
5489 0 : nsCOMPtr<nsIURI> resultPrincipalURI;
5490 0 : bool loadReplace = false;
5491 :
5492 0 : nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
5493 0 : nsAutoString contentTypeHint;
5494 0 : doc->GetContentType(contentTypeHint);
5495 :
5496 0 : if (doc->IsSrcdocDocument()) {
5497 0 : doc->GetSrcdocData(srcdoc);
5498 0 : flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
5499 0 : baseURI = doc->GetBaseURI();
5500 : }
5501 0 : nsCOMPtr<nsIChannel> chan = doc->GetChannel();
5502 0 : if (chan) {
5503 : uint32_t loadFlags;
5504 0 : chan->GetLoadFlags(&loadFlags);
5505 0 : loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
5506 0 : nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
5507 0 : if (httpChan) {
5508 0 : httpChan->GetOriginalURI(getter_AddRefs(originalURI));
5509 : }
5510 :
5511 0 : nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo();
5512 0 : if (loadInfo) {
5513 0 : loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
5514 : }
5515 : }
5516 :
5517 0 : MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal");
5518 :
5519 : // Stack variables to ensure changes to the member variables don't affect to
5520 : // the call.
5521 0 : nsCOMPtr<nsIURI> currentURI = mCurrentURI;
5522 0 : nsCOMPtr<nsIURI> referrerURI = mReferrerURI;
5523 0 : uint32_t referrerPolicy = mReferrerPolicy;
5524 :
5525 : // Reload always rewrites result principal URI.
5526 0 : Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
5527 0 : emplacedResultPrincipalURI.emplace(Move(resultPrincipalURI));
5528 0 : rv = InternalLoad(currentURI,
5529 : originalURI,
5530 : emplacedResultPrincipalURI,
5531 : loadReplace,
5532 : referrerURI,
5533 : referrerPolicy,
5534 : triggeringPrincipal,
5535 : triggeringPrincipal,
5536 : flags,
5537 0 : EmptyString(), // No window target
5538 0 : NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
5539 0 : NullString(), // No forced download
5540 : nullptr, // No post data
5541 : nullptr, // No headers data
5542 : loadType, // Load type
5543 : nullptr, // No SHEntry
5544 : true,
5545 : srcdoc, // srcdoc argument for iframe
5546 : this, // For reloads we are the source
5547 : baseURI,
5548 : false,
5549 : nullptr, // No nsIDocShell
5550 0 : nullptr); // No nsIRequest
5551 : }
5552 :
5553 0 : return rv;
5554 : }
5555 :
5556 : NS_IMETHODIMP
5557 7 : nsDocShell::Stop(uint32_t aStopFlags)
5558 : {
5559 : // Revoke any pending event related to content viewer restoration
5560 7 : mRestorePresentationEvent.Revoke();
5561 :
5562 7 : if (mLoadType == LOAD_ERROR_PAGE) {
5563 0 : if (mLSHE) {
5564 : // Since error page loads never unset mLSHE, do so now
5565 0 : SetHistoryEntry(&mOSHE, mLSHE);
5566 0 : SetHistoryEntry(&mLSHE, nullptr);
5567 : }
5568 :
5569 0 : mFailedChannel = nullptr;
5570 0 : mFailedURI = nullptr;
5571 : }
5572 :
5573 7 : if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
5574 : // Stop the document loading
5575 1 : if (mContentViewer) {
5576 2 : nsCOMPtr<nsIContentViewer> cv = mContentViewer;
5577 1 : cv->Stop();
5578 : }
5579 : }
5580 :
5581 7 : if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
5582 : // Suspend any timers that were set for this loader. We'll clear
5583 : // them out for good in CreateContentViewer.
5584 7 : if (mRefreshURIList) {
5585 0 : SuspendRefreshURIs();
5586 0 : mSavedRefreshURIList.swap(mRefreshURIList);
5587 0 : mRefreshURIList = nullptr;
5588 : }
5589 :
5590 : // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
5591 : // just call Stop() on us as an nsIDocumentLoader... We need fewer
5592 : // redundant apis!
5593 7 : Stop();
5594 : }
5595 :
5596 14 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
5597 7 : while (iter.HasMore()) {
5598 0 : nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext()));
5599 0 : if (shellAsNav) {
5600 0 : shellAsNav->Stop(aStopFlags);
5601 : }
5602 : }
5603 :
5604 14 : return NS_OK;
5605 : }
5606 :
5607 : NS_IMETHODIMP
5608 393 : nsDocShell::GetDocument(nsIDOMDocument** aDocument)
5609 : {
5610 393 : NS_ENSURE_ARG_POINTER(aDocument);
5611 393 : NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
5612 :
5613 393 : return mContentViewer->GetDOMDocument(aDocument);
5614 : }
5615 :
5616 : NS_IMETHODIMP
5617 12 : nsDocShell::GetCurrentURI(nsIURI** aURI)
5618 : {
5619 12 : NS_ENSURE_ARG_POINTER(aURI);
5620 :
5621 12 : if (mCurrentURI) {
5622 12 : return NS_EnsureSafeToReturn(mCurrentURI, aURI);
5623 : }
5624 :
5625 0 : *aURI = nullptr;
5626 0 : return NS_OK;
5627 : }
5628 :
5629 : NS_IMETHODIMP
5630 0 : nsDocShell::GetReferringURI(nsIURI** aURI)
5631 : {
5632 0 : NS_ENSURE_ARG_POINTER(aURI);
5633 :
5634 0 : *aURI = mReferrerURI;
5635 0 : NS_IF_ADDREF(*aURI);
5636 :
5637 0 : return NS_OK;
5638 : }
5639 :
5640 : NS_IMETHODIMP
5641 2 : nsDocShell::SetSessionHistory(nsISHistory* aSessionHistory)
5642 : {
5643 2 : NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
5644 : // make sure that we are the root docshell and
5645 : // set a handle to root docshell in SH.
5646 :
5647 4 : nsCOMPtr<nsIDocShellTreeItem> root;
5648 : /* Get the root docshell. If *this* is the root docshell
5649 : * then save a handle to *this* in SH. SH needs it to do
5650 : * traversions thro' its entries
5651 : */
5652 2 : GetSameTypeRootTreeItem(getter_AddRefs(root));
5653 2 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
5654 2 : if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
5655 2 : mSessionHistory = aSessionHistory;
5656 : nsCOMPtr<nsISHistoryInternal> shPrivate =
5657 4 : do_QueryInterface(mSessionHistory);
5658 2 : NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
5659 2 : shPrivate->SetRootDocShell(this);
5660 2 : return NS_OK;
5661 : }
5662 0 : return NS_ERROR_FAILURE;
5663 : }
5664 :
5665 : NS_IMETHODIMP
5666 19 : nsDocShell::GetSessionHistory(nsISHistory** aSessionHistory)
5667 : {
5668 19 : NS_ENSURE_ARG_POINTER(aSessionHistory);
5669 19 : *aSessionHistory = mSessionHistory;
5670 19 : NS_IF_ADDREF(*aSessionHistory);
5671 19 : return NS_OK;
5672 : }
5673 :
5674 : //*****************************************************************************
5675 : // nsDocShell::nsIWebPageDescriptor
5676 : //*****************************************************************************
5677 :
5678 : NS_IMETHODIMP
5679 0 : nsDocShell::LoadPage(nsISupports* aPageDescriptor, uint32_t aDisplayType)
5680 : {
5681 0 : nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
5682 :
5683 : // Currently, the opaque 'page descriptor' is an nsISHEntry...
5684 0 : if (!shEntryIn) {
5685 0 : return NS_ERROR_INVALID_POINTER;
5686 : }
5687 :
5688 : // Now clone shEntryIn, since we might end up modifying it later on, and we
5689 : // want a page descriptor to be reusable.
5690 0 : nsCOMPtr<nsISHEntry> shEntry;
5691 0 : nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
5692 0 : NS_ENSURE_SUCCESS(rv, rv);
5693 :
5694 : // Give our cloned shEntry a new bfcache entry so this load is independent
5695 : // of all other loads. (This is important, in particular, for bugs 582795
5696 : // and 585298.)
5697 0 : rv = shEntry->AbandonBFCacheEntry();
5698 0 : NS_ENSURE_SUCCESS(rv, rv);
5699 :
5700 : //
5701 : // load the page as view-source
5702 : //
5703 0 : if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
5704 0 : nsCOMPtr<nsIURI> oldUri, newUri;
5705 0 : nsCString spec, newSpec;
5706 :
5707 : // Create a new view-source URI and replace the original.
5708 0 : rv = shEntry->GetURI(getter_AddRefs(oldUri));
5709 0 : if (NS_FAILED(rv)) {
5710 0 : return rv;
5711 : }
5712 :
5713 0 : oldUri->GetSpec(spec);
5714 0 : newSpec.AppendLiteral("view-source:");
5715 0 : newSpec.Append(spec);
5716 :
5717 0 : rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
5718 0 : if (NS_FAILED(rv)) {
5719 0 : return rv;
5720 : }
5721 0 : shEntry->SetURI(newUri);
5722 0 : shEntry->SetOriginalURI(nullptr);
5723 : // shEntry's current triggering principal is whoever loaded that page initially.
5724 : // But now we're doing another load of the page, via an API that is only exposed
5725 : // to system code. The triggering principal for this load should be the system
5726 : // principal.
5727 0 : shEntry->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
5728 : }
5729 :
5730 0 : rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
5731 0 : return rv;
5732 : }
5733 :
5734 : NS_IMETHODIMP
5735 0 : nsDocShell::GetCurrentDescriptor(nsISupports** aPageDescriptor)
5736 : {
5737 0 : NS_PRECONDITION(aPageDescriptor, "Null out param?");
5738 :
5739 0 : *aPageDescriptor = nullptr;
5740 :
5741 0 : nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
5742 0 : if (src) {
5743 0 : nsCOMPtr<nsISHEntry> dest;
5744 :
5745 0 : nsresult rv = src->Clone(getter_AddRefs(dest));
5746 0 : if (NS_FAILED(rv)) {
5747 0 : return rv;
5748 : }
5749 :
5750 : // null out inappropriate cloned attributes...
5751 0 : dest->SetParent(nullptr);
5752 0 : dest->SetIsSubFrame(false);
5753 :
5754 0 : return CallQueryInterface(dest, aPageDescriptor);
5755 : }
5756 :
5757 0 : return NS_ERROR_NOT_AVAILABLE;
5758 : }
5759 :
5760 : //*****************************************************************************
5761 : // nsDocShell::nsIBaseWindow
5762 : //*****************************************************************************
5763 :
5764 : NS_IMETHODIMP
5765 3 : nsDocShell::InitWindow(nativeWindow aParentNativeWindow,
5766 : nsIWidget* aParentWidget, int32_t aX, int32_t aY,
5767 : int32_t aWidth, int32_t aHeight)
5768 : {
5769 3 : SetParentWidget(aParentWidget);
5770 3 : SetPositionAndSize(aX, aY, aWidth, aHeight, 0);
5771 :
5772 3 : return NS_OK;
5773 : }
5774 :
5775 : NS_IMETHODIMP
5776 5 : nsDocShell::Create()
5777 : {
5778 5 : if (mCreated) {
5779 : // We've already been created
5780 0 : return NS_OK;
5781 : }
5782 :
5783 5 : NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
5784 : "Unexpected item type in docshell");
5785 :
5786 5 : NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
5787 5 : mCreated = true;
5788 :
5789 5 : if (gValidateOrigin == 0xffffffff) {
5790 : // Check pref to see if we should prevent frameset spoofing
5791 2 : gValidateOrigin =
5792 2 : Preferences::GetBool("browser.frame.validate_origin", true);
5793 : }
5794 :
5795 : // Should we use XUL error pages instead of alerts if possible?
5796 5 : mUseErrorPages =
5797 5 : Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
5798 :
5799 5 : if (!gAddedPreferencesVarCache) {
5800 2 : Preferences::AddBoolVarCache(&sUseErrorPages,
5801 : "browser.xul.error_pages.enabled",
5802 4 : mUseErrorPages);
5803 2 : gAddedPreferencesVarCache = true;
5804 : }
5805 :
5806 5 : mDisableMetaRefreshWhenInactive =
5807 5 : Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
5808 5 : mDisableMetaRefreshWhenInactive);
5809 :
5810 5 : mDeviceSizeIsPageSize =
5811 5 : Preferences::GetBool("docshell.device_size_is_page_size",
5812 5 : mDeviceSizeIsPageSize);
5813 :
5814 10 : nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
5815 5 : if (serv) {
5816 5 : const char* msg = mItemType == typeContent ?
5817 5 : NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
5818 5 : serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
5819 : }
5820 :
5821 5 : return NS_OK;
5822 : }
5823 :
5824 : NS_IMETHODIMP
5825 1 : nsDocShell::Destroy()
5826 : {
5827 1 : NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
5828 : "Unexpected item type in docshell");
5829 :
5830 1 : AssertOriginAttributesMatchPrivateBrowsing();
5831 :
5832 1 : if (!mIsBeingDestroyed) {
5833 2 : nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
5834 1 : if (serv) {
5835 1 : const char* msg = mItemType == typeContent ?
5836 1 : NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
5837 1 : serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
5838 : }
5839 : }
5840 :
5841 1 : mIsBeingDestroyed = true;
5842 :
5843 : // Make sure we don't record profile timeline markers anymore
5844 1 : SetRecordProfileTimelineMarkers(false);
5845 :
5846 : // Remove our pref observers
5847 1 : if (mObserveErrorPages) {
5848 1 : mObserveErrorPages = false;
5849 : }
5850 :
5851 : // Make sure to blow away our mLoadingURI just in case. No loads
5852 : // from inside this pagehide.
5853 1 : mLoadingURI = nullptr;
5854 :
5855 : // Fire unload event before we blow anything away.
5856 1 : (void)FirePageHideNotification(true);
5857 :
5858 : // Clear pointers to any detached nsEditorData that's lying
5859 : // around in shistory entries. Breaks cycle. See bug 430921.
5860 1 : if (mOSHE) {
5861 0 : mOSHE->SetEditorData(nullptr);
5862 : }
5863 1 : if (mLSHE) {
5864 0 : mLSHE->SetEditorData(nullptr);
5865 : }
5866 :
5867 : // Note: mContentListener can be null if Init() failed and we're being
5868 : // called from the destructor.
5869 1 : if (mContentListener) {
5870 1 : mContentListener->DropDocShellReference();
5871 1 : mContentListener->SetParentContentListener(nullptr);
5872 : // Note that we do NOT set mContentListener to null here; that
5873 : // way if someone tries to do a load in us after this point
5874 : // the nsDSURIContentListener will block it. All of which
5875 : // means that we should do this before calling Stop(), of
5876 : // course.
5877 : }
5878 :
5879 : // Stop any URLs that are currently being loaded...
5880 1 : Stop(nsIWebNavigation::STOP_ALL);
5881 :
5882 1 : mEditorData = nullptr;
5883 :
5884 1 : mTransferableHookData = nullptr;
5885 :
5886 : // Save the state of the current document, before destroying the window.
5887 : // This is needed to capture the state of a frameset when the new document
5888 : // causes the frameset to be destroyed...
5889 1 : PersistLayoutHistoryState();
5890 :
5891 : // Remove this docshell from its parent's child list
5892 : nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
5893 2 : do_QueryInterface(GetAsSupports(mParent));
5894 1 : if (docShellParentAsItem) {
5895 1 : docShellParentAsItem->RemoveChild(this);
5896 : }
5897 :
5898 1 : if (mContentViewer) {
5899 1 : mContentViewer->Close(nullptr);
5900 1 : mContentViewer->Destroy();
5901 1 : mContentViewer = nullptr;
5902 : }
5903 :
5904 1 : nsDocLoader::Destroy();
5905 :
5906 1 : mParentWidget = nullptr;
5907 1 : mCurrentURI = nullptr;
5908 :
5909 1 : if (mScriptGlobal) {
5910 1 : mScriptGlobal->DetachFromDocShell();
5911 1 : mScriptGlobal = nullptr;
5912 : }
5913 :
5914 1 : if (mSessionHistory) {
5915 : // We want to destroy these content viewers now rather than
5916 : // letting their destruction wait for the session history
5917 : // entries to get garbage collected. (Bug 488394)
5918 : nsCOMPtr<nsISHistoryInternal> shPrivate =
5919 2 : do_QueryInterface(mSessionHistory);
5920 1 : if (shPrivate) {
5921 1 : shPrivate->EvictAllContentViewers();
5922 : }
5923 1 : mSessionHistory = nullptr;
5924 : }
5925 :
5926 1 : SetTreeOwner(nullptr);
5927 :
5928 1 : mOnePermittedSandboxedNavigator = nullptr;
5929 :
5930 : // required to break ref cycle
5931 1 : mSecurityUI = nullptr;
5932 :
5933 : // Cancel any timers that were set for this docshell; this is needed
5934 : // to break the cycle between us and the timers.
5935 1 : CancelRefreshURITimers();
5936 :
5937 1 : if (UsePrivateBrowsing()) {
5938 0 : mPrivateBrowsingId = 0;
5939 0 : mOriginAttributes.SyncAttributesWithPrivateBrowsing(false);
5940 0 : if (mAffectPrivateSessionLifetime) {
5941 0 : DecreasePrivateDocShellCount();
5942 : }
5943 : }
5944 :
5945 2 : return NS_OK;
5946 : }
5947 :
5948 : NS_IMETHODIMP
5949 0 : nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double* aScale)
5950 : {
5951 0 : if (mParentWidget) {
5952 0 : *aScale = mParentWidget->GetDefaultScale().scale;
5953 0 : return NS_OK;
5954 : }
5955 :
5956 0 : nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5957 0 : if (ownerWindow) {
5958 0 : return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
5959 : }
5960 :
5961 0 : *aScale = 1.0;
5962 0 : return NS_OK;
5963 : }
5964 :
5965 : NS_IMETHODIMP
5966 0 : nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale)
5967 : {
5968 0 : if (mParentWidget) {
5969 0 : *aScale = mParentWidget->GetDesktopToDeviceScale().scale;
5970 0 : return NS_OK;
5971 : }
5972 :
5973 0 : nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5974 0 : if (ownerWindow) {
5975 0 : return ownerWindow->GetDevicePixelsPerDesktopPixel(aScale);
5976 : }
5977 :
5978 0 : *aScale = 1.0;
5979 0 : return NS_OK;
5980 : }
5981 :
5982 : NS_IMETHODIMP
5983 0 : nsDocShell::SetPosition(int32_t aX, int32_t aY)
5984 : {
5985 0 : mBounds.x = aX;
5986 0 : mBounds.y = aY;
5987 :
5988 0 : if (mContentViewer) {
5989 0 : NS_ENSURE_SUCCESS(mContentViewer->Move(aX, aY), NS_ERROR_FAILURE);
5990 : }
5991 :
5992 0 : return NS_OK;
5993 : }
5994 :
5995 : NS_IMETHODIMP
5996 0 : nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY)
5997 : {
5998 0 : nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
5999 0 : if (ownerWindow) {
6000 0 : return ownerWindow->SetPositionDesktopPix(aX, aY);
6001 : }
6002 :
6003 0 : double scale = 1.0;
6004 0 : GetDevicePixelsPerDesktopPixel(&scale);
6005 0 : return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
6006 : }
6007 :
6008 : NS_IMETHODIMP
6009 0 : nsDocShell::GetPosition(int32_t* aX, int32_t* aY)
6010 : {
6011 0 : return GetPositionAndSize(aX, aY, nullptr, nullptr);
6012 : }
6013 :
6014 : NS_IMETHODIMP
6015 0 : nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint)
6016 : {
6017 0 : int32_t x = 0, y = 0;
6018 0 : GetPosition(&x, &y);
6019 0 : return SetPositionAndSize(x, y, aWidth, aHeight,
6020 0 : aRepaint ? nsIBaseWindow::eRepaint : 0);
6021 : }
6022 :
6023 : NS_IMETHODIMP
6024 1 : nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight)
6025 : {
6026 1 : return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight);
6027 : }
6028 :
6029 : NS_IMETHODIMP
6030 9 : nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth,
6031 : int32_t aHeight, uint32_t aFlags)
6032 : {
6033 9 : mBounds.x = aX;
6034 9 : mBounds.y = aY;
6035 9 : mBounds.width = aWidth;
6036 9 : mBounds.height = aHeight;
6037 :
6038 : // Hold strong ref, since SetBounds can make us null out mContentViewer
6039 18 : nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
6040 9 : if (viewer) {
6041 6 : uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize) ?
6042 6 : nsIContentViewer::eDelayResize : 0;
6043 : // XXX Border figured in here or is that handled elsewhere?
6044 6 : nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags);
6045 6 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
6046 : }
6047 :
6048 9 : return NS_OK;
6049 : }
6050 :
6051 : NS_IMETHODIMP
6052 1 : nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
6053 : int32_t* aHeight)
6054 : {
6055 1 : if (mParentWidget) {
6056 : // ensure size is up-to-date if window has changed resolution
6057 1 : LayoutDeviceIntRect r = mParentWidget->GetClientBounds();
6058 1 : SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, 0);
6059 : }
6060 :
6061 : // We should really consider just getting this information from
6062 : // our window instead of duplicating the storage and code...
6063 1 : if (aWidth || aHeight) {
6064 : // Caller wants to know our size; make sure to give them up to
6065 : // date information.
6066 2 : nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
6067 1 : if (doc) {
6068 0 : doc->FlushPendingNotifications(FlushType::Layout);
6069 : }
6070 : }
6071 :
6072 1 : DoGetPositionAndSize(aX, aY, aWidth, aHeight);
6073 1 : return NS_OK;
6074 : }
6075 :
6076 : void
6077 9 : nsDocShell::DoGetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
6078 : int32_t* aHeight)
6079 : {
6080 9 : if (aX) {
6081 8 : *aX = mBounds.x;
6082 : }
6083 9 : if (aY) {
6084 8 : *aY = mBounds.y;
6085 : }
6086 9 : if (aWidth) {
6087 9 : *aWidth = mBounds.width;
6088 : }
6089 9 : if (aHeight) {
6090 9 : *aHeight = mBounds.height;
6091 : }
6092 9 : }
6093 :
6094 : NS_IMETHODIMP
6095 0 : nsDocShell::Repaint(bool aForce)
6096 : {
6097 0 : nsCOMPtr<nsIPresShell> presShell = GetPresShell();
6098 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
6099 :
6100 0 : nsViewManager* viewManager = presShell->GetViewManager();
6101 0 : NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
6102 :
6103 0 : viewManager->InvalidateAllViews();
6104 0 : return NS_OK;
6105 : }
6106 :
6107 : NS_IMETHODIMP
6108 59 : nsDocShell::GetParentWidget(nsIWidget** aParentWidget)
6109 : {
6110 59 : NS_ENSURE_ARG_POINTER(aParentWidget);
6111 :
6112 59 : *aParentWidget = mParentWidget;
6113 59 : NS_IF_ADDREF(*aParentWidget);
6114 :
6115 59 : return NS_OK;
6116 : }
6117 :
6118 : NS_IMETHODIMP
6119 5 : nsDocShell::SetParentWidget(nsIWidget* aParentWidget)
6120 : {
6121 5 : mParentWidget = aParentWidget;
6122 :
6123 5 : return NS_OK;
6124 : }
6125 :
6126 : NS_IMETHODIMP
6127 0 : nsDocShell::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
6128 : {
6129 0 : NS_ENSURE_ARG_POINTER(aParentNativeWindow);
6130 :
6131 0 : if (mParentWidget) {
6132 0 : *aParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
6133 : } else {
6134 0 : *aParentNativeWindow = nullptr;
6135 : }
6136 :
6137 0 : return NS_OK;
6138 : }
6139 :
6140 : NS_IMETHODIMP
6141 0 : nsDocShell::SetParentNativeWindow(nativeWindow aParentNativeWindow)
6142 : {
6143 0 : return NS_ERROR_NOT_IMPLEMENTED;
6144 : }
6145 :
6146 : NS_IMETHODIMP
6147 0 : nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
6148 : {
6149 : // the nativeHandle should be accessed from nsIXULWindow
6150 0 : return NS_ERROR_NOT_IMPLEMENTED;
6151 : }
6152 :
6153 : NS_IMETHODIMP
6154 7 : nsDocShell::GetVisibility(bool* aVisibility)
6155 : {
6156 7 : NS_ENSURE_ARG_POINTER(aVisibility);
6157 :
6158 7 : *aVisibility = false;
6159 :
6160 7 : if (!mContentViewer) {
6161 0 : return NS_OK;
6162 : }
6163 :
6164 14 : nsCOMPtr<nsIPresShell> presShell = GetPresShell();
6165 7 : if (!presShell) {
6166 0 : return NS_OK;
6167 : }
6168 :
6169 : // get the view manager
6170 7 : nsViewManager* vm = presShell->GetViewManager();
6171 7 : NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
6172 :
6173 : // get the root view
6174 7 : nsView* view = vm->GetRootView(); // views are not ref counted
6175 7 : NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
6176 :
6177 : // if our root view is hidden, we are not visible
6178 7 : if (view->GetVisibility() == nsViewVisibility_kHide) {
6179 0 : return NS_OK;
6180 : }
6181 :
6182 : // otherwise, we must walk up the document and view trees checking
6183 : // for a hidden view, unless we're an off screen browser, which
6184 : // would make this test meaningless.
6185 :
6186 14 : RefPtr<nsDocShell> docShell = this;
6187 14 : RefPtr<nsDocShell> parentItem = docShell->GetParentDocshell();
6188 7 : while (parentItem) {
6189 0 : presShell = docShell->GetPresShell();
6190 :
6191 0 : nsCOMPtr<nsIPresShell> pPresShell = parentItem->GetPresShell();
6192 :
6193 : // Null-check for crash in bug 267804
6194 0 : if (!pPresShell) {
6195 0 : NS_NOTREACHED("parent docshell has null pres shell");
6196 0 : return NS_OK;
6197 : }
6198 :
6199 0 : vm = presShell->GetViewManager();
6200 0 : if (vm) {
6201 0 : view = vm->GetRootView();
6202 : }
6203 :
6204 0 : if (view) {
6205 0 : view = view->GetParent(); // anonymous inner view
6206 0 : if (view) {
6207 0 : view = view->GetParent(); // subdocumentframe's view
6208 : }
6209 : }
6210 :
6211 0 : nsIFrame* frame = view ? view->GetFrame() : nullptr;
6212 0 : bool isDocShellOffScreen = false;
6213 0 : docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
6214 0 : if (frame &&
6215 0 : !frame->IsVisibleConsideringAncestors(
6216 0 : nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
6217 0 : !isDocShellOffScreen) {
6218 0 : return NS_OK;
6219 : }
6220 :
6221 0 : docShell = parentItem;
6222 0 : parentItem = docShell->GetParentDocshell();
6223 : }
6224 :
6225 14 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
6226 7 : if (!treeOwnerAsWin) {
6227 0 : *aVisibility = true;
6228 0 : return NS_OK;
6229 : }
6230 :
6231 : // Check with the tree owner as well to give embedders a chance to
6232 : // expose visibility as well.
6233 7 : return treeOwnerAsWin->GetVisibility(aVisibility);
6234 : }
6235 :
6236 : NS_IMETHODIMP
6237 0 : nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen)
6238 : {
6239 0 : mIsOffScreenBrowser = aIsOffScreen;
6240 0 : return NS_OK;
6241 : }
6242 :
6243 : NS_IMETHODIMP
6244 0 : nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen)
6245 : {
6246 0 : *aIsOffScreen = mIsOffScreenBrowser;
6247 0 : return NS_OK;
6248 : }
6249 :
6250 : NS_IMETHODIMP
6251 4 : nsDocShell::SetIsActive(bool aIsActive)
6252 : {
6253 : // We disallow setting active on chrome docshells.
6254 4 : if (mItemType == nsIDocShellTreeItem::typeChrome) {
6255 2 : return NS_ERROR_INVALID_ARG;
6256 : }
6257 :
6258 : // Keep track ourselves.
6259 2 : mIsActive = aIsActive;
6260 :
6261 : // Clear prerender flag if necessary.
6262 2 : if (mIsPrerendered && aIsActive) {
6263 0 : MOZ_ASSERT(mPrerenderGlobalHistory.get());
6264 0 : mIsPrerendered = false;
6265 0 : nsCOMPtr<IHistory> history = services::GetHistoryService();
6266 0 : nsresult rv = NS_OK;
6267 0 : if (history) {
6268 0 : rv = mPrerenderGlobalHistory->ApplyChanges(history);
6269 0 : } else if (mGlobalHistory) {
6270 0 : rv = mPrerenderGlobalHistory->ApplyChanges(mGlobalHistory);
6271 : }
6272 0 : mPrerenderGlobalHistory = nullptr;
6273 0 : NS_ENSURE_SUCCESS(rv, rv);
6274 : }
6275 :
6276 : // Tell the PresShell about it.
6277 4 : nsCOMPtr<nsIPresShell> pshell = GetPresShell();
6278 2 : if (pshell) {
6279 0 : pshell->SetIsActive(aIsActive);
6280 : }
6281 :
6282 : // Tell the window about it
6283 2 : if (mScriptGlobal) {
6284 0 : mScriptGlobal->SetIsBackground(!aIsActive);
6285 0 : if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
6286 : // Update orientation when the top-level browsing context becomes active.
6287 0 : if (aIsActive) {
6288 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
6289 0 : GetSameTypeParent(getter_AddRefs(parent));
6290 0 : if (!parent) {
6291 : // We only care about the top-level browsing context.
6292 0 : uint16_t orientation = OrientationLock();
6293 0 : ScreenOrientation::UpdateActiveOrientationLock(orientation);
6294 : }
6295 : }
6296 :
6297 0 : doc->PostVisibilityUpdateEvent();
6298 : }
6299 : }
6300 :
6301 : // Tell the nsDOMNavigationTiming about it
6302 4 : RefPtr<nsDOMNavigationTiming> timing = mTiming;
6303 2 : if (!timing && mContentViewer) {
6304 0 : nsIDocument* doc = mContentViewer->GetDocument();
6305 0 : if (doc) {
6306 0 : timing = doc->GetNavigationTiming();
6307 : }
6308 : }
6309 2 : if (timing) {
6310 0 : timing->NotifyDocShellStateChanged(
6311 : aIsActive ? nsDOMNavigationTiming::DocShellState::eActive
6312 0 : : nsDOMNavigationTiming::DocShellState::eInactive);
6313 : }
6314 :
6315 : // Recursively tell all of our children, but don't tell <iframe mozbrowser>
6316 : // children; they handle their state separately.
6317 4 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
6318 2 : while (iter.HasMore()) {
6319 0 : nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
6320 0 : if (!docshell) {
6321 0 : continue;
6322 : }
6323 :
6324 0 : if (!docshell->GetIsMozBrowser()) {
6325 0 : docshell->SetIsActive(aIsActive);
6326 : }
6327 : }
6328 :
6329 : // Restart or stop meta refresh timers if necessary
6330 2 : if (mDisableMetaRefreshWhenInactive) {
6331 0 : if (mIsActive) {
6332 0 : ResumeRefreshURIs();
6333 : } else {
6334 0 : SuspendRefreshURIs();
6335 : }
6336 : }
6337 :
6338 2 : return NS_OK;
6339 : }
6340 :
6341 : NS_IMETHODIMP
6342 16 : nsDocShell::GetIsActive(bool* aIsActive)
6343 : {
6344 16 : *aIsActive = mIsActive;
6345 16 : return NS_OK;
6346 : }
6347 :
6348 : NS_IMETHODIMP
6349 0 : nsDocShell::SetIsPrerendered()
6350 : {
6351 0 : MOZ_ASSERT(!mIsPrerendered,
6352 : "SetIsPrerendered() called on already prerendered docshell");
6353 0 : SetIsActive(false);
6354 0 : mIsPrerendered = true;
6355 0 : mPrerenderGlobalHistory = mozilla::MakeUnique<PendingGlobalHistoryEntry>();
6356 0 : return NS_OK;
6357 : }
6358 :
6359 : NS_IMETHODIMP
6360 15 : nsDocShell::GetIsPrerendered(bool* aIsPrerendered)
6361 : {
6362 15 : *aIsPrerendered = mIsPrerendered;
6363 15 : return NS_OK;
6364 : }
6365 :
6366 : NS_IMETHODIMP
6367 1 : nsDocShell::SetIsAppTab(bool aIsAppTab)
6368 : {
6369 1 : mIsAppTab = aIsAppTab;
6370 1 : return NS_OK;
6371 : }
6372 :
6373 : NS_IMETHODIMP
6374 0 : nsDocShell::GetIsAppTab(bool* aIsAppTab)
6375 : {
6376 0 : *aIsAppTab = mIsAppTab;
6377 0 : return NS_OK;
6378 : }
6379 :
6380 : NS_IMETHODIMP
6381 2 : nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags)
6382 : {
6383 2 : mSandboxFlags = aSandboxFlags;
6384 2 : return NS_OK;
6385 : }
6386 :
6387 : NS_IMETHODIMP
6388 3 : nsDocShell::GetSandboxFlags(uint32_t* aSandboxFlags)
6389 : {
6390 3 : *aSandboxFlags = mSandboxFlags;
6391 3 : return NS_OK;
6392 : }
6393 :
6394 : NS_IMETHODIMP
6395 0 : nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
6396 : {
6397 0 : if (mOnePermittedSandboxedNavigator) {
6398 0 : NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
6399 0 : return NS_OK;
6400 : }
6401 :
6402 0 : mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
6403 0 : NS_ASSERTION(mOnePermittedSandboxedNavigator,
6404 : "One Permitted Sandboxed Navigator must support weak references.");
6405 :
6406 0 : return NS_OK;
6407 : }
6408 :
6409 : NS_IMETHODIMP
6410 0 : nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator)
6411 : {
6412 0 : NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
6413 : nsCOMPtr<nsIDocShell> permittedNavigator =
6414 0 : do_QueryReferent(mOnePermittedSandboxedNavigator);
6415 0 : permittedNavigator.forget(aSandboxedNavigator);
6416 0 : return NS_OK;
6417 : }
6418 :
6419 : NS_IMETHODIMP
6420 2 : nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)
6421 : {
6422 2 : mDefaultLoadFlags = aDefaultLoadFlags;
6423 :
6424 : // Tell the load group to set these flags all requests in the group
6425 2 : if (mLoadGroup) {
6426 2 : mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
6427 : } else {
6428 0 : NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to");
6429 : }
6430 :
6431 : // Recursively tell all of our children. We *do not* skip
6432 : // <iframe mozbrowser> children - if someone sticks custom flags in this
6433 : // docShell then they too get the same flags.
6434 4 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
6435 2 : while (iter.HasMore()) {
6436 0 : nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
6437 0 : if (!docshell) {
6438 0 : continue;
6439 : }
6440 0 : docshell->SetDefaultLoadFlags(aDefaultLoadFlags);
6441 : }
6442 4 : return NS_OK;
6443 : }
6444 :
6445 : NS_IMETHODIMP
6446 2 : nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags)
6447 : {
6448 2 : *aDefaultLoadFlags = mDefaultLoadFlags;
6449 2 : return NS_OK;
6450 : }
6451 :
6452 : NS_IMETHODIMP
6453 0 : nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
6454 : {
6455 : #ifdef DEBUG
6456 : // if the channel is non-null
6457 0 : if (aMixedContentChannel) {
6458 : // Get the root docshell.
6459 0 : nsCOMPtr<nsIDocShellTreeItem> root;
6460 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
6461 0 : NS_WARNING_ASSERTION(root.get() == static_cast<nsIDocShellTreeItem*>(this),
6462 : "Setting mMixedContentChannel on a docshell that is "
6463 : "not the root docshell");
6464 : }
6465 : #endif
6466 0 : mMixedContentChannel = aMixedContentChannel;
6467 0 : return NS_OK;
6468 : }
6469 :
6470 : NS_IMETHODIMP
6471 0 : nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel)
6472 : {
6473 0 : NS_ENSURE_ARG_POINTER(aFailedChannel);
6474 0 : nsIDocument* doc = GetDocument();
6475 0 : if (!doc) {
6476 0 : *aFailedChannel = nullptr;
6477 0 : return NS_OK;
6478 : }
6479 0 : NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel());
6480 0 : return NS_OK;
6481 : }
6482 :
6483 : NS_IMETHODIMP
6484 0 : nsDocShell::GetMixedContentChannel(nsIChannel** aMixedContentChannel)
6485 : {
6486 0 : NS_ENSURE_ARG_POINTER(aMixedContentChannel);
6487 0 : NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
6488 0 : return NS_OK;
6489 : }
6490 :
6491 : NS_IMETHODIMP
6492 0 : nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection,
6493 : bool* aAllowMixedContent,
6494 : bool* aIsRootDocShell)
6495 : {
6496 0 : *aRootHasSecureConnection = true;
6497 0 : *aAllowMixedContent = false;
6498 0 : *aIsRootDocShell = false;
6499 :
6500 0 : nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
6501 0 : GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
6502 0 : NS_ASSERTION(sameTypeRoot,
6503 : "No document shell root tree item from document shell tree item!");
6504 0 : *aIsRootDocShell =
6505 0 : sameTypeRoot.get() == static_cast<nsIDocShellTreeItem*>(this);
6506 :
6507 : // now get the document from sameTypeRoot
6508 0 : nsCOMPtr<nsIDocument> rootDoc = sameTypeRoot->GetDocument();
6509 0 : if (rootDoc) {
6510 0 : nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
6511 :
6512 : // For things with system principal (e.g. scratchpad) there is no uri
6513 : // aRootHasSecureConnection should be false.
6514 0 : nsCOMPtr<nsIURI> rootUri;
6515 0 : if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
6516 0 : NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
6517 0 : NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) {
6518 0 : *aRootHasSecureConnection = false;
6519 : }
6520 :
6521 : // Check the root doc's channel against the root docShell's
6522 : // mMixedContentChannel to see if they are the same. If they are the same,
6523 : // the user has overriden the block.
6524 0 : nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot);
6525 0 : nsCOMPtr<nsIChannel> mixedChannel;
6526 0 : rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
6527 0 : *aAllowMixedContent =
6528 0 : mixedChannel && (mixedChannel == rootDoc->GetChannel());
6529 : }
6530 :
6531 0 : return NS_OK;
6532 : }
6533 :
6534 : NS_IMETHODIMP
6535 3 : nsDocShell::SetVisibility(bool aVisibility)
6536 : {
6537 : // Show()/Hide() may change mContentViewer.
6538 6 : nsCOMPtr<nsIContentViewer> cv = mContentViewer;
6539 3 : if (!cv) {
6540 0 : return NS_OK;
6541 : }
6542 3 : if (aVisibility) {
6543 2 : cv->Show();
6544 : } else {
6545 1 : cv->Hide();
6546 : }
6547 :
6548 3 : return NS_OK;
6549 : }
6550 :
6551 : NS_IMETHODIMP
6552 0 : nsDocShell::GetEnabled(bool* aEnabled)
6553 : {
6554 0 : NS_ENSURE_ARG_POINTER(aEnabled);
6555 0 : *aEnabled = true;
6556 0 : return NS_ERROR_NOT_IMPLEMENTED;
6557 : }
6558 :
6559 : NS_IMETHODIMP
6560 0 : nsDocShell::SetEnabled(bool aEnabled)
6561 : {
6562 0 : return NS_ERROR_NOT_IMPLEMENTED;
6563 : }
6564 :
6565 : NS_IMETHODIMP
6566 0 : nsDocShell::SetFocus()
6567 : {
6568 0 : return NS_OK;
6569 : }
6570 :
6571 : NS_IMETHODIMP
6572 59 : nsDocShell::GetMainWidget(nsIWidget** aMainWidget)
6573 : {
6574 : // We don't create our own widget, so simply return the parent one.
6575 59 : return GetParentWidget(aMainWidget);
6576 : }
6577 :
6578 : NS_IMETHODIMP
6579 0 : nsDocShell::GetTitle(char16_t** aTitle)
6580 : {
6581 0 : NS_ENSURE_ARG_POINTER(aTitle);
6582 :
6583 0 : *aTitle = ToNewUnicode(mTitle);
6584 0 : return NS_OK;
6585 : }
6586 :
6587 : NS_IMETHODIMP
6588 3 : nsDocShell::SetTitle(const char16_t* aTitle)
6589 : {
6590 : // Store local title
6591 3 : mTitle = aTitle;
6592 :
6593 6 : nsCOMPtr<nsIDocShellTreeItem> parent;
6594 3 : GetSameTypeParent(getter_AddRefs(parent));
6595 :
6596 : // When title is set on the top object it should then be passed to the
6597 : // tree owner.
6598 3 : if (!parent) {
6599 6 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
6600 3 : if (treeOwnerAsWin) {
6601 3 : treeOwnerAsWin->SetTitle(aTitle);
6602 : }
6603 : }
6604 :
6605 3 : AssertOriginAttributesMatchPrivateBrowsing();
6606 3 : if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
6607 3 : UpdateGlobalHistoryTitle(mCurrentURI);
6608 : }
6609 :
6610 : // Update SessionHistory with the document's title.
6611 4 : if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
6612 1 : mLoadType != LOAD_ERROR_PAGE) {
6613 1 : mOSHE->SetTitle(mTitle);
6614 : }
6615 :
6616 6 : return NS_OK;
6617 : }
6618 :
6619 : nsresult
6620 0 : nsDocShell::GetCurScrollPos(int32_t aScrollOrientation, int32_t* aCurPos)
6621 : {
6622 0 : NS_ENSURE_ARG_POINTER(aCurPos);
6623 :
6624 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
6625 0 : if (!sf) {
6626 0 : return NS_ERROR_FAILURE;
6627 : }
6628 :
6629 0 : nsPoint pt = sf->GetScrollPosition();
6630 :
6631 0 : switch (aScrollOrientation) {
6632 : case ScrollOrientation_X:
6633 0 : *aCurPos = pt.x;
6634 0 : return NS_OK;
6635 :
6636 : case ScrollOrientation_Y:
6637 0 : *aCurPos = pt.y;
6638 0 : return NS_OK;
6639 :
6640 : default:
6641 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
6642 : }
6643 : }
6644 :
6645 : nsresult
6646 0 : nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos,
6647 : int32_t aCurVerticalPos)
6648 : {
6649 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
6650 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6651 :
6652 0 : sf->ScrollTo(nsPoint(aCurHorizontalPos, aCurVerticalPos),
6653 0 : nsIScrollableFrame::INSTANT);
6654 0 : return NS_OK;
6655 : }
6656 :
6657 : //*****************************************************************************
6658 : // nsDocShell::nsIScrollable
6659 : //*****************************************************************************
6660 :
6661 : NS_IMETHODIMP
6662 98 : nsDocShell::GetDefaultScrollbarPreferences(int32_t aScrollOrientation,
6663 : int32_t* aScrollbarPref)
6664 : {
6665 98 : NS_ENSURE_ARG_POINTER(aScrollbarPref);
6666 98 : switch (aScrollOrientation) {
6667 : case ScrollOrientation_X:
6668 49 : *aScrollbarPref = mDefaultScrollbarPref.x;
6669 49 : return NS_OK;
6670 :
6671 : case ScrollOrientation_Y:
6672 49 : *aScrollbarPref = mDefaultScrollbarPref.y;
6673 49 : return NS_OK;
6674 :
6675 : default:
6676 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
6677 : }
6678 : return NS_ERROR_FAILURE;
6679 : }
6680 :
6681 : NS_IMETHODIMP
6682 4 : nsDocShell::SetDefaultScrollbarPreferences(int32_t aScrollOrientation,
6683 : int32_t aScrollbarPref)
6684 : {
6685 4 : switch (aScrollOrientation) {
6686 : case ScrollOrientation_X:
6687 2 : mDefaultScrollbarPref.x = aScrollbarPref;
6688 2 : return NS_OK;
6689 :
6690 : case ScrollOrientation_Y:
6691 2 : mDefaultScrollbarPref.y = aScrollbarPref;
6692 2 : return NS_OK;
6693 :
6694 : default:
6695 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
6696 : }
6697 : return NS_ERROR_FAILURE;
6698 : }
6699 :
6700 : NS_IMETHODIMP
6701 0 : nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible,
6702 : bool* aHorizontalVisible)
6703 : {
6704 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
6705 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6706 :
6707 0 : uint32_t scrollbarVisibility = sf->GetScrollbarVisibility();
6708 0 : if (aVerticalVisible) {
6709 0 : *aVerticalVisible =
6710 0 : (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
6711 : }
6712 0 : if (aHorizontalVisible) {
6713 0 : *aHorizontalVisible =
6714 0 : (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
6715 : }
6716 :
6717 0 : return NS_OK;
6718 : }
6719 :
6720 : //*****************************************************************************
6721 : // nsDocShell::nsITextScroll
6722 : //*****************************************************************************
6723 :
6724 : NS_IMETHODIMP
6725 0 : nsDocShell::ScrollByLines(int32_t aNumLines)
6726 : {
6727 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
6728 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6729 :
6730 0 : sf->ScrollBy(nsIntPoint(0, aNumLines), nsIScrollableFrame::LINES,
6731 0 : nsIScrollableFrame::SMOOTH);
6732 0 : return NS_OK;
6733 : }
6734 :
6735 : NS_IMETHODIMP
6736 0 : nsDocShell::ScrollByPages(int32_t aNumPages)
6737 : {
6738 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
6739 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
6740 :
6741 0 : sf->ScrollBy(nsIntPoint(0, aNumPages), nsIScrollableFrame::PAGES,
6742 0 : nsIScrollableFrame::SMOOTH);
6743 0 : return NS_OK;
6744 : }
6745 :
6746 : //*****************************************************************************
6747 : // nsDocShell::nsIRefreshURI
6748 : //*****************************************************************************
6749 :
6750 : NS_IMETHODIMP
6751 0 : nsDocShell::RefreshURI(nsIURI* aURI, int32_t aDelay, bool aRepeat,
6752 : bool aMetaRefresh)
6753 : {
6754 0 : NS_ENSURE_ARG(aURI);
6755 :
6756 : /* Check if Meta refresh/redirects are permitted. Some
6757 : * embedded applications may not want to do this.
6758 : * Must do this before sending out NOTIFY_REFRESH events
6759 : * because listeners may have side effects (e.g. displaying a
6760 : * button to manually trigger the refresh later).
6761 : */
6762 0 : bool allowRedirects = true;
6763 0 : GetAllowMetaRedirects(&allowRedirects);
6764 0 : if (!allowRedirects) {
6765 0 : return NS_OK;
6766 : }
6767 :
6768 : // If any web progress listeners are listening for NOTIFY_REFRESH events,
6769 : // give them a chance to block this refresh.
6770 : bool sameURI;
6771 0 : nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
6772 0 : if (NS_FAILED(rv)) {
6773 0 : sameURI = false;
6774 : }
6775 0 : if (!RefreshAttempted(this, aURI, aDelay, sameURI)) {
6776 0 : return NS_OK;
6777 : }
6778 :
6779 0 : nsRefreshTimer* refreshTimer = new nsRefreshTimer();
6780 0 : uint32_t busyFlags = 0;
6781 0 : GetBusyFlags(&busyFlags);
6782 :
6783 0 : nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1
6784 :
6785 0 : refreshTimer->mDocShell = this;
6786 0 : refreshTimer->mURI = aURI;
6787 0 : refreshTimer->mDelay = aDelay;
6788 0 : refreshTimer->mRepeat = aRepeat;
6789 0 : refreshTimer->mMetaRefresh = aMetaRefresh;
6790 :
6791 0 : if (!mRefreshURIList) {
6792 0 : mRefreshURIList = nsArray::Create();
6793 : }
6794 :
6795 0 : if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) {
6796 : // We don't want to create the timer right now. Instead queue up the request
6797 : // and trigger the timer in EndPageLoad() or whenever we become active.
6798 0 : mRefreshURIList->AppendElement(refreshTimer, /*weak =*/ false);
6799 : } else {
6800 : // There is no page loading going on right now. Create the
6801 : // timer and fire it right away.
6802 0 : nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
6803 0 : NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
6804 0 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
6805 0 : NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
6806 :
6807 0 : mRefreshURIList->AppendElement(timer, /*weak =*/ false); // owning timer ref
6808 0 : timer->SetTarget(win->TabGroup()->EventTargetFor(TaskCategory::Network));
6809 0 : timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
6810 : }
6811 0 : return NS_OK;
6812 : }
6813 :
6814 : nsresult
6815 0 : nsDocShell::ForceRefreshURIFromTimer(nsIURI* aURI,
6816 : int32_t aDelay,
6817 : bool aMetaRefresh,
6818 : nsITimer* aTimer)
6819 : {
6820 0 : NS_PRECONDITION(aTimer, "Must have a timer here");
6821 :
6822 : // Remove aTimer from mRefreshURIList if needed
6823 0 : if (mRefreshURIList) {
6824 0 : uint32_t n = 0;
6825 0 : mRefreshURIList->GetLength(&n);
6826 :
6827 0 : for (uint32_t i = 0; i < n; ++i) {
6828 0 : nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
6829 0 : if (timer == aTimer) {
6830 0 : mRefreshURIList->RemoveElementAt(i);
6831 0 : break;
6832 : }
6833 : }
6834 : }
6835 :
6836 0 : return ForceRefreshURI(aURI, aDelay, aMetaRefresh);
6837 : }
6838 :
6839 : NS_IMETHODIMP
6840 0 : nsDocShell::ForceRefreshURI(nsIURI* aURI, int32_t aDelay, bool aMetaRefresh)
6841 : {
6842 0 : NS_ENSURE_ARG(aURI);
6843 :
6844 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
6845 0 : CreateLoadInfo(getter_AddRefs(loadInfo));
6846 0 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
6847 :
6848 : /* We do need to pass in a referrer, but we don't want it to
6849 : * be sent to the server.
6850 : */
6851 0 : loadInfo->SetSendReferrer(false);
6852 :
6853 : /* for most refreshes the current URI is an appropriate
6854 : * internal referrer
6855 : */
6856 0 : loadInfo->SetReferrer(mCurrentURI);
6857 :
6858 : /* Don't ever "guess" on which principal to use to avoid picking
6859 : * the current principal.
6860 : */
6861 0 : loadInfo->SetPrincipalIsExplicit(true);
6862 :
6863 : /* Check if this META refresh causes a redirection
6864 : * to another site.
6865 : */
6866 0 : bool equalUri = false;
6867 0 : nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
6868 0 : if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
6869 : aDelay <= REFRESH_REDIRECT_TIMER) {
6870 : /* It is a META refresh based redirection within the threshold time
6871 : * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
6872 : * Pass a REPLACE flag to LoadURI().
6873 : */
6874 0 : loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
6875 :
6876 : /* for redirects we mimic HTTP, which passes the
6877 : * original referrer
6878 : */
6879 0 : nsCOMPtr<nsIURI> internalReferrer;
6880 0 : GetReferringURI(getter_AddRefs(internalReferrer));
6881 0 : if (internalReferrer) {
6882 0 : loadInfo->SetReferrer(internalReferrer);
6883 : }
6884 : } else {
6885 0 : loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
6886 : }
6887 :
6888 : /*
6889 : * LoadURI(...) will cancel all refresh timers... This causes the
6890 : * Timer and its refreshData instance to be released...
6891 : */
6892 0 : LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
6893 :
6894 0 : return NS_OK;
6895 : }
6896 :
6897 : nsresult
6898 0 : nsDocShell::SetupRefreshURIFromHeader(nsIURI* aBaseURI,
6899 : nsIPrincipal* aPrincipal,
6900 : const nsACString& aHeader)
6901 : {
6902 : // Refresh headers are parsed with the following format in mind
6903 : // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
6904 : // By the time we are here, the following is true:
6905 : // header = "REFRESH"
6906 : // content = "5; URL=http://uri" // note the URL attribute is
6907 : // optional, if it is absent, the currently loaded url is used.
6908 : // Also note that the seconds and URL separator can be either
6909 : // a ';' or a ','. The ',' separator should be illegal but CNN
6910 : // is using it.
6911 : //
6912 : // We need to handle the following strings, where
6913 : // - X is a set of digits
6914 : // - URI is either a relative or absolute URI
6915 : //
6916 : // Note that URI should start with "url=" but we allow omission
6917 : //
6918 : // "" || ";" || ","
6919 : // empty string. use the currently loaded URI
6920 : // and refresh immediately.
6921 : // "X" || "X;" || "X,"
6922 : // Refresh the currently loaded URI in X seconds.
6923 : // "X; URI" || "X, URI"
6924 : // Refresh using URI as the destination in X seconds.
6925 : // "URI" || "; URI" || ", URI"
6926 : // Refresh immediately using URI as the destination.
6927 : //
6928 : // Currently, anything immediately following the URI, if
6929 : // separated by any char in the set "'\"\t\r\n " will be
6930 : // ignored. So "10; url=go.html ; foo=bar" will work,
6931 : // and so will "10; url='go.html'; foo=bar". However,
6932 : // "10; url=go.html; foo=bar" will result in the uri
6933 : // "go.html;" since ';' and ',' are valid uri characters.
6934 : //
6935 : // Note that we need to remove any tokens wrapping the URI.
6936 : // These tokens currently include spaces, double and single
6937 : // quotes.
6938 :
6939 : // when done, seconds is 0 or the given number of seconds
6940 : // uriAttrib is empty or the URI specified
6941 0 : MOZ_ASSERT(aPrincipal);
6942 :
6943 0 : nsAutoCString uriAttrib;
6944 0 : int32_t seconds = 0;
6945 0 : bool specifiesSeconds = false;
6946 :
6947 0 : nsACString::const_iterator iter, tokenStart, doneIterating;
6948 :
6949 0 : aHeader.BeginReading(iter);
6950 0 : aHeader.EndReading(doneIterating);
6951 :
6952 : // skip leading whitespace
6953 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
6954 0 : ++iter;
6955 : }
6956 :
6957 0 : tokenStart = iter;
6958 :
6959 : // skip leading + and -
6960 0 : if (iter != doneIterating && (*iter == '-' || *iter == '+')) {
6961 0 : ++iter;
6962 : }
6963 :
6964 : // parse number
6965 0 : while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
6966 0 : seconds = seconds * 10 + (*iter - '0');
6967 0 : specifiesSeconds = true;
6968 0 : ++iter;
6969 : }
6970 :
6971 0 : if (iter != doneIterating) {
6972 : // if we started with a '-', number is negative
6973 0 : if (*tokenStart == '-') {
6974 0 : seconds = -seconds;
6975 : }
6976 :
6977 : // skip to next ';' or ','
6978 0 : nsACString::const_iterator iterAfterDigit = iter;
6979 0 : while (iter != doneIterating && !(*iter == ';' || *iter == ',')) {
6980 0 : if (specifiesSeconds) {
6981 : // Non-whitespace characters here mean that the string is
6982 : // malformed but tolerate sites that specify a decimal point,
6983 : // even though meta refresh only works on whole seconds.
6984 0 : if (iter == iterAfterDigit &&
6985 0 : !nsCRT::IsAsciiSpace(*iter) && *iter != '.') {
6986 : // The characters between the seconds and the next
6987 : // section are just garbage!
6988 : // e.g. content="2a0z+,URL=http://www.mozilla.org/"
6989 : // Just ignore this redirect.
6990 0 : return NS_ERROR_FAILURE;
6991 0 : } else if (nsCRT::IsAsciiSpace(*iter)) {
6992 : // We've had at least one whitespace so tolerate the mistake
6993 : // and drop through.
6994 : // e.g. content="10 foo"
6995 0 : ++iter;
6996 0 : break;
6997 : }
6998 : }
6999 0 : ++iter;
7000 : }
7001 :
7002 : // skip any remaining whitespace
7003 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
7004 0 : ++iter;
7005 : }
7006 :
7007 : // skip ';' or ','
7008 0 : if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
7009 0 : ++iter;
7010 : }
7011 :
7012 : // skip whitespace
7013 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
7014 0 : ++iter;
7015 : }
7016 : }
7017 :
7018 : // possible start of URI
7019 0 : tokenStart = iter;
7020 :
7021 : // skip "url = " to real start of URI
7022 0 : if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
7023 0 : ++iter;
7024 0 : if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
7025 0 : ++iter;
7026 0 : if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
7027 0 : ++iter;
7028 :
7029 : // skip whitespace
7030 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
7031 0 : ++iter;
7032 : }
7033 :
7034 0 : if (iter != doneIterating && *iter == '=') {
7035 0 : ++iter;
7036 :
7037 : // skip whitespace
7038 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
7039 0 : ++iter;
7040 : }
7041 :
7042 : // found real start of URI
7043 0 : tokenStart = iter;
7044 : }
7045 : }
7046 : }
7047 : }
7048 :
7049 : // skip a leading '"' or '\''.
7050 :
7051 0 : bool isQuotedURI = false;
7052 0 : if (tokenStart != doneIterating &&
7053 0 : (*tokenStart == '"' || *tokenStart == '\'')) {
7054 0 : isQuotedURI = true;
7055 0 : ++tokenStart;
7056 : }
7057 :
7058 : // set iter to start of URI
7059 0 : iter = tokenStart;
7060 :
7061 : // tokenStart here points to the beginning of URI
7062 :
7063 : // grab the rest of the URI
7064 0 : while (iter != doneIterating) {
7065 0 : if (isQuotedURI && (*iter == '"' || *iter == '\'')) {
7066 0 : break;
7067 : }
7068 0 : ++iter;
7069 : }
7070 :
7071 : // move iter one back if the last character is a '"' or '\''
7072 0 : if (iter != tokenStart && isQuotedURI) {
7073 0 : --iter;
7074 0 : if (!(*iter == '"' || *iter == '\'')) {
7075 0 : ++iter;
7076 : }
7077 : }
7078 :
7079 : // URI is whatever's contained from tokenStart to iter.
7080 : // note: if tokenStart == doneIterating, so is iter.
7081 :
7082 0 : nsresult rv = NS_OK;
7083 :
7084 0 : nsCOMPtr<nsIURI> uri;
7085 0 : bool specifiesURI = false;
7086 0 : if (tokenStart == iter) {
7087 0 : uri = aBaseURI;
7088 : } else {
7089 0 : uriAttrib = Substring(tokenStart, iter);
7090 : // NS_NewURI takes care of any whitespace surrounding the URL
7091 0 : rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI);
7092 0 : specifiesURI = true;
7093 : }
7094 :
7095 : // No URI or seconds were specified
7096 0 : if (!specifiesSeconds && !specifiesURI) {
7097 : // Do nothing because the alternative is to spin around in a refresh
7098 : // loop forever!
7099 0 : return NS_ERROR_FAILURE;
7100 : }
7101 :
7102 0 : if (NS_SUCCEEDED(rv)) {
7103 : nsCOMPtr<nsIScriptSecurityManager> securityManager(
7104 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
7105 0 : if (NS_SUCCEEDED(rv)) {
7106 0 : rv = securityManager->CheckLoadURIWithPrincipal(
7107 : aPrincipal, uri,
7108 0 : nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
7109 :
7110 0 : if (NS_SUCCEEDED(rv)) {
7111 0 : bool isjs = true;
7112 0 : rv = NS_URIChainHasFlags(
7113 : uri, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
7114 0 : NS_ENSURE_SUCCESS(rv, rv);
7115 :
7116 0 : if (isjs) {
7117 0 : return NS_ERROR_FAILURE;
7118 : }
7119 : }
7120 :
7121 0 : if (NS_SUCCEEDED(rv)) {
7122 : // Since we can't travel back in time yet, just pretend
7123 : // negative numbers do nothing at all.
7124 0 : if (seconds < 0) {
7125 0 : return NS_ERROR_FAILURE;
7126 : }
7127 :
7128 0 : rv = RefreshURI(uri, seconds * 1000, false, true);
7129 : }
7130 : }
7131 : }
7132 0 : return rv;
7133 : }
7134 :
7135 : NS_IMETHODIMP
7136 0 : nsDocShell::SetupRefreshURI(nsIChannel* aChannel)
7137 : {
7138 : nsresult rv;
7139 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
7140 0 : if (NS_SUCCEEDED(rv)) {
7141 0 : nsAutoCString refreshHeader;
7142 0 : rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
7143 0 : refreshHeader);
7144 :
7145 0 : if (!refreshHeader.IsEmpty()) {
7146 : nsCOMPtr<nsIScriptSecurityManager> secMan =
7147 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
7148 0 : NS_ENSURE_SUCCESS(rv, rv);
7149 :
7150 0 : nsCOMPtr<nsIPrincipal> principal;
7151 0 : rv = secMan->GetChannelResultPrincipal(aChannel,
7152 0 : getter_AddRefs(principal));
7153 0 : NS_ENSURE_SUCCESS(rv, rv);
7154 :
7155 0 : SetupReferrerFromChannel(aChannel);
7156 0 : rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader);
7157 0 : if (NS_SUCCEEDED(rv)) {
7158 0 : return NS_REFRESHURI_HEADER_FOUND;
7159 : }
7160 : }
7161 : }
7162 0 : return rv;
7163 : }
7164 :
7165 : static void
7166 2 : DoCancelRefreshURITimers(nsIMutableArray* aTimerList)
7167 : {
7168 2 : if (!aTimerList) {
7169 2 : return;
7170 : }
7171 :
7172 0 : uint32_t n = 0;
7173 0 : aTimerList->GetLength(&n);
7174 :
7175 0 : while (n) {
7176 0 : nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
7177 :
7178 0 : aTimerList->RemoveElementAt(n); // bye bye owning timer ref
7179 :
7180 0 : if (timer) {
7181 0 : timer->Cancel();
7182 : }
7183 : }
7184 : }
7185 :
7186 : NS_IMETHODIMP
7187 1 : nsDocShell::CancelRefreshURITimers()
7188 : {
7189 1 : DoCancelRefreshURITimers(mRefreshURIList);
7190 1 : DoCancelRefreshURITimers(mSavedRefreshURIList);
7191 1 : mRefreshURIList = nullptr;
7192 1 : mSavedRefreshURIList = nullptr;
7193 :
7194 1 : return NS_OK;
7195 : }
7196 :
7197 : NS_IMETHODIMP
7198 0 : nsDocShell::GetRefreshPending(bool* aResult)
7199 : {
7200 0 : if (!mRefreshURIList) {
7201 0 : *aResult = false;
7202 0 : return NS_OK;
7203 : }
7204 :
7205 : uint32_t count;
7206 0 : nsresult rv = mRefreshURIList->GetLength(&count);
7207 0 : if (NS_SUCCEEDED(rv)) {
7208 0 : *aResult = (count != 0);
7209 : }
7210 0 : return rv;
7211 : }
7212 :
7213 : NS_IMETHODIMP
7214 0 : nsDocShell::SuspendRefreshURIs()
7215 : {
7216 0 : if (mRefreshURIList) {
7217 0 : uint32_t n = 0;
7218 0 : mRefreshURIList->GetLength(&n);
7219 :
7220 0 : for (uint32_t i = 0; i < n; ++i) {
7221 0 : nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
7222 0 : if (!timer) {
7223 0 : continue; // this must be a nsRefreshURI already
7224 : }
7225 :
7226 : // Replace this timer object with a nsRefreshTimer object.
7227 0 : nsCOMPtr<nsITimerCallback> callback;
7228 0 : timer->GetCallback(getter_AddRefs(callback));
7229 :
7230 0 : timer->Cancel();
7231 :
7232 0 : nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
7233 0 : NS_ASSERTION(rt,
7234 : "RefreshURIList timer callbacks should only be RefreshTimer objects");
7235 :
7236 0 : mRefreshURIList->ReplaceElementAt(rt, i, /*weak =*/ false);
7237 : }
7238 : }
7239 :
7240 : // Suspend refresh URIs for our child shells as well.
7241 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
7242 0 : while (iter.HasMore()) {
7243 0 : nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
7244 0 : if (shell) {
7245 0 : shell->SuspendRefreshURIs();
7246 : }
7247 : }
7248 :
7249 0 : return NS_OK;
7250 : }
7251 :
7252 : NS_IMETHODIMP
7253 0 : nsDocShell::ResumeRefreshURIs()
7254 : {
7255 0 : RefreshURIFromQueue();
7256 :
7257 : // Resume refresh URIs for our child shells as well.
7258 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
7259 0 : while (iter.HasMore()) {
7260 0 : nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
7261 0 : if (shell) {
7262 0 : shell->ResumeRefreshURIs();
7263 : }
7264 : }
7265 :
7266 0 : return NS_OK;
7267 : }
7268 :
7269 : nsresult
7270 6 : nsDocShell::RefreshURIFromQueue()
7271 : {
7272 6 : if (!mRefreshURIList) {
7273 6 : return NS_OK;
7274 : }
7275 0 : uint32_t n = 0;
7276 0 : mRefreshURIList->GetLength(&n);
7277 :
7278 0 : while (n) {
7279 : nsCOMPtr<nsITimerCallback> refreshInfo =
7280 0 : do_QueryElementAt(mRefreshURIList, --n);
7281 :
7282 0 : if (refreshInfo) {
7283 : // This is the nsRefreshTimer object, waiting to be
7284 : // setup in a timer object and fired.
7285 : // Create the timer and trigger it.
7286 : uint32_t delay =
7287 : static_cast<nsRefreshTimer*>(
7288 0 : static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
7289 0 : nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
7290 0 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
7291 0 : if (timer && win) {
7292 : // Replace the nsRefreshTimer element in the queue with
7293 : // its corresponding timer object, so that in case another
7294 : // load comes through before the timer can go off, the timer will
7295 : // get cancelled in CancelRefreshURITimer()
7296 0 : mRefreshURIList->ReplaceElementAt(timer, n, /*weak =*/ false);
7297 0 : timer->SetTarget(win->TabGroup()->EventTargetFor(TaskCategory::Network));
7298 0 : timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
7299 : }
7300 : }
7301 : }
7302 :
7303 0 : return NS_OK;
7304 : }
7305 :
7306 : //*****************************************************************************
7307 : // nsDocShell::nsIContentViewerContainer
7308 : //*****************************************************************************
7309 :
7310 : NS_IMETHODIMP
7311 8 : nsDocShell::Embed(nsIContentViewer* aContentViewer,
7312 : const char* aCommand, nsISupports* aExtraInfo)
7313 : {
7314 : // Save the LayoutHistoryState of the previous document, before
7315 : // setting up new document
7316 8 : PersistLayoutHistoryState();
7317 :
7318 8 : nsresult rv = SetupNewViewer(aContentViewer);
7319 8 : NS_ENSURE_SUCCESS(rv, rv);
7320 :
7321 : // If we are loading a wyciwyg url from history, change the base URI for
7322 : // the document to the original http url that created the document.write().
7323 : // This makes sure that all relative urls in a document.written page loaded
7324 : // via history work properly.
7325 12 : if (mCurrentURI &&
7326 8 : (mLoadType & LOAD_CMD_HISTORY ||
7327 8 : mLoadType == LOAD_RELOAD_NORMAL ||
7328 12 : mLoadType == LOAD_RELOAD_CHARSET_CHANGE)) {
7329 0 : bool isWyciwyg = false;
7330 : // Check if the url is wyciwyg
7331 0 : rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
7332 0 : if (isWyciwyg && NS_SUCCEEDED(rv)) {
7333 0 : SetBaseUrlForWyciwyg(aContentViewer);
7334 : }
7335 : }
7336 : // XXX What if SetupNewViewer fails?
7337 8 : if (mLSHE) {
7338 : // Restore the editing state, if it's stored in session history.
7339 1 : if (mLSHE->HasDetachedEditor()) {
7340 0 : ReattachEditorToWindow(mLSHE);
7341 : }
7342 : // Set history.state
7343 1 : SetDocCurrentStateObj(mLSHE);
7344 :
7345 1 : SetHistoryEntry(&mOSHE, mLSHE);
7346 : }
7347 :
7348 8 : bool updateHistory = true;
7349 :
7350 : // Determine if this type of load should update history
7351 8 : switch (mLoadType) {
7352 : case LOAD_NORMAL_REPLACE:
7353 : case LOAD_STOP_CONTENT_AND_REPLACE:
7354 : case LOAD_RELOAD_BYPASS_CACHE:
7355 : case LOAD_RELOAD_BYPASS_PROXY:
7356 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
7357 : case LOAD_REPLACE_BYPASS_CACHE:
7358 0 : updateHistory = false;
7359 0 : break;
7360 : default:
7361 8 : break;
7362 : }
7363 :
7364 8 : if (!updateHistory) {
7365 0 : SetLayoutHistoryState(nullptr);
7366 : }
7367 :
7368 8 : return NS_OK;
7369 : }
7370 :
7371 : NS_IMETHODIMP
7372 0 : nsDocShell::SetIsPrinting(bool aIsPrinting)
7373 : {
7374 0 : mIsPrintingOrPP = aIsPrinting;
7375 0 : return NS_OK;
7376 : }
7377 :
7378 : //*****************************************************************************
7379 : // nsDocShell::nsIWebProgressListener
7380 : //*****************************************************************************
7381 :
7382 : NS_IMETHODIMP
7383 0 : nsDocShell::OnProgressChange(nsIWebProgress* aProgress,
7384 : nsIRequest* aRequest,
7385 : int32_t aCurSelfProgress,
7386 : int32_t aMaxSelfProgress,
7387 : int32_t aCurTotalProgress,
7388 : int32_t aMaxTotalProgress)
7389 : {
7390 0 : return NS_OK;
7391 : }
7392 :
7393 : NS_IMETHODIMP
7394 27 : nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
7395 : uint32_t aStateFlags, nsresult aStatus)
7396 : {
7397 27 : if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
7398 : // Save timing statistics.
7399 12 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
7400 12 : nsCOMPtr<nsIURI> uri;
7401 6 : channel->GetURI(getter_AddRefs(uri));
7402 12 : nsAutoCString aURI;
7403 6 : uri->GetAsciiSpec(aURI);
7404 :
7405 12 : nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
7406 : nsCOMPtr<nsIWebProgress> webProgress =
7407 12 : do_QueryInterface(GetAsSupports(this));
7408 :
7409 : // We don't update navigation timing for wyciwyg channels
7410 6 : if (this == aProgress && !wcwgChannel) {
7411 6 : mozilla::Unused << MaybeInitTiming();
7412 6 : mTiming->NotifyFetchStart(uri,
7413 6 : ConvertLoadTypeToNavigationType(mLoadType));
7414 : }
7415 :
7416 : // Was the wyciwyg document loaded on this docshell?
7417 6 : if (wcwgChannel && !mLSHE && (mItemType == typeContent) &&
7418 0 : aProgress == webProgress.get()) {
7419 0 : bool equalUri = true;
7420 : // Store the wyciwyg url in session history, only if it is
7421 : // being loaded fresh for the first time. We don't want
7422 : // multiple entries for successive loads
7423 0 : if (mCurrentURI &&
7424 0 : NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
7425 0 : !equalUri) {
7426 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
7427 0 : GetSameTypeParent(getter_AddRefs(parentAsItem));
7428 0 : nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
7429 0 : bool inOnLoadHandler = false;
7430 0 : if (parentDS) {
7431 0 : parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
7432 : }
7433 0 : if (inOnLoadHandler) {
7434 : // We're handling parent's load event listener, which causes
7435 : // document.write in a subdocument.
7436 : // Need to clear the session history for all child
7437 : // docshells so that we can handle them like they would
7438 : // all be added dynamically.
7439 0 : nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
7440 0 : if (parent) {
7441 0 : bool oshe = false;
7442 0 : nsCOMPtr<nsISHEntry> entry;
7443 0 : parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
7444 0 : static_cast<nsDocShell*>(parent.get())->ClearFrameHistory(entry);
7445 : }
7446 : }
7447 :
7448 : // This is a document.write(). Get the made-up url
7449 : // from the channel and store it in session history.
7450 : // Pass false for aCloneChildren, since we're creating
7451 : // a new DOM here.
7452 0 : AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, false,
7453 0 : getter_AddRefs(mLSHE));
7454 0 : SetCurrentURI(uri, aRequest, true, 0);
7455 : // Save history state of the previous page
7456 0 : PersistLayoutHistoryState();
7457 : // We'll never get an Embed() for this load, so just go ahead
7458 : // and SetHistoryEntry now.
7459 0 : SetHistoryEntry(&mOSHE, mLSHE);
7460 : }
7461 : }
7462 : // Page has begun to load
7463 6 : mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
7464 :
7465 6 : if ((aStateFlags & STATE_RESTORING) == 0) {
7466 : // Show the progress cursor if the pref is set
7467 6 : if (nsContentUtils::UseActivityCursor()) {
7468 0 : nsCOMPtr<nsIWidget> mainWidget;
7469 0 : GetMainWidget(getter_AddRefs(mainWidget));
7470 0 : if (mainWidget) {
7471 0 : mainWidget->SetCursor(eCursor_spinning);
7472 : }
7473 : }
7474 : }
7475 21 : } else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
7476 : // Page is loading
7477 5 : mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
7478 16 : } else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
7479 : // Page has finished loading
7480 6 : mBusyFlags = BUSY_FLAGS_NONE;
7481 :
7482 : // Hide the progress cursor if the pref is set
7483 6 : if (nsContentUtils::UseActivityCursor()) {
7484 0 : nsCOMPtr<nsIWidget> mainWidget;
7485 0 : GetMainWidget(getter_AddRefs(mainWidget));
7486 0 : if (mainWidget) {
7487 0 : mainWidget->SetCursor(eCursor_standard);
7488 : }
7489 : }
7490 : }
7491 27 : if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
7492 : nsCOMPtr<nsIWebProgress> webProgress =
7493 16 : do_QueryInterface(GetAsSupports(this));
7494 : // Is the document stop notification for this document?
7495 8 : if (aProgress == webProgress.get()) {
7496 12 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
7497 6 : EndPageLoad(aProgress, channel, aStatus);
7498 : }
7499 : }
7500 : // note that redirect state changes will go through here as well, but it
7501 : // is better to handle those in OnRedirectStateChange where more
7502 : // information is available.
7503 27 : return NS_OK;
7504 : }
7505 :
7506 : NS_IMETHODIMP
7507 0 : nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
7508 : nsIURI* aURI, uint32_t aFlags)
7509 : {
7510 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
7511 0 : return NS_OK;
7512 : }
7513 :
7514 : void
7515 0 : nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
7516 : nsIChannel* aNewChannel,
7517 : uint32_t aRedirectFlags,
7518 : uint32_t aStateFlags)
7519 : {
7520 0 : NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
7521 : "Calling OnRedirectStateChange when there is no redirect");
7522 :
7523 : // If mixed content is allowed for the old channel, we forward
7524 : // the permission to the new channel if it has the same origin
7525 : // as the old one.
7526 0 : if (mMixedContentChannel && mMixedContentChannel == aOldChannel) {
7527 0 : nsresult rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, aNewChannel);
7528 0 : if (NS_SUCCEEDED(rv)) {
7529 0 : SetMixedContentChannel(aNewChannel); // Same origin: forward permission.
7530 : } else {
7531 0 : SetMixedContentChannel(nullptr); // Different origin: clear mMixedContentChannel.
7532 : }
7533 : }
7534 :
7535 0 : if (!(aStateFlags & STATE_IS_DOCUMENT)) {
7536 0 : return; // not a toplevel document
7537 : }
7538 :
7539 0 : nsCOMPtr<nsIURI> oldURI, newURI;
7540 0 : aOldChannel->GetURI(getter_AddRefs(oldURI));
7541 0 : aNewChannel->GetURI(getter_AddRefs(newURI));
7542 0 : if (!oldURI || !newURI) {
7543 0 : return;
7544 : }
7545 :
7546 : // Below a URI visit is saved (see AddURIVisit method doc).
7547 : // The visit chain looks something like:
7548 : // ...
7549 : // Site N - 1
7550 : // => Site N
7551 : // (redirect to =>) Site N + 1 (we are here!)
7552 :
7553 : // Get N - 1 and transition type
7554 0 : nsCOMPtr<nsIURI> previousURI;
7555 0 : uint32_t previousFlags = 0;
7556 0 : ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
7557 :
7558 0 : if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
7559 0 : ChannelIsPost(aOldChannel)) {
7560 : // 1. Internal redirects are ignored because they are specific to the
7561 : // channel implementation.
7562 : // 2. POSTs are not saved by global history.
7563 : //
7564 : // Regardless, we need to propagate the previous visit to the new
7565 : // channel.
7566 0 : SaveLastVisit(aNewChannel, previousURI, previousFlags);
7567 : } else {
7568 0 : nsCOMPtr<nsIURI> referrer;
7569 : // Treat referrer as null if there is an error getting it.
7570 0 : (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer));
7571 :
7572 : // Get the HTTP response code, if available.
7573 0 : uint32_t responseStatus = 0;
7574 0 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
7575 0 : if (httpChannel) {
7576 0 : Unused << httpChannel->GetResponseStatus(&responseStatus);
7577 : }
7578 :
7579 : // Add visit N -1 => N
7580 0 : AddURIVisit(oldURI, referrer, previousURI, previousFlags, responseStatus);
7581 :
7582 : // Since N + 1 could be the final destination, we will not save N => N + 1
7583 : // here. OnNewURI will do that, so we will cache it.
7584 0 : SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
7585 : }
7586 :
7587 : // check if the new load should go through the application cache.
7588 : nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
7589 0 : do_QueryInterface(aNewChannel);
7590 0 : if (appCacheChannel) {
7591 0 : if (GeckoProcessType_Default != XRE_GetProcessType()) {
7592 : // Permission will be checked in the parent process.
7593 0 : appCacheChannel->SetChooseApplicationCache(true);
7594 : } else {
7595 : nsCOMPtr<nsIScriptSecurityManager> secMan =
7596 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
7597 :
7598 0 : if (secMan) {
7599 0 : nsCOMPtr<nsIPrincipal> principal;
7600 0 : secMan->GetDocShellCodebasePrincipal(newURI, this,
7601 0 : getter_AddRefs(principal));
7602 0 : appCacheChannel->SetChooseApplicationCache(
7603 0 : NS_ShouldCheckAppCache(principal));
7604 : }
7605 : }
7606 : }
7607 :
7608 0 : if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
7609 0 : mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
7610 0 : mLoadType = LOAD_NORMAL_REPLACE;
7611 0 : SetHistoryEntry(&mLSHE, nullptr);
7612 : }
7613 : }
7614 :
7615 : NS_IMETHODIMP
7616 0 : nsDocShell::OnStatusChange(nsIWebProgress* aWebProgress,
7617 : nsIRequest* aRequest,
7618 : nsresult aStatus, const char16_t* aMessage)
7619 : {
7620 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
7621 0 : return NS_OK;
7622 : }
7623 :
7624 : NS_IMETHODIMP
7625 0 : nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress,
7626 : nsIRequest* aRequest, uint32_t aState)
7627 : {
7628 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
7629 0 : return NS_OK;
7630 : }
7631 :
7632 : nsresult
7633 6 : nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
7634 : nsIChannel* aChannel, nsresult aStatus)
7635 : {
7636 6 : if (!aChannel) {
7637 0 : return NS_ERROR_NULL_POINTER;
7638 : }
7639 :
7640 12 : nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
7641 6 : if (reporter) {
7642 2 : nsCOMPtr<nsILoadGroup> loadGroup;
7643 1 : aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
7644 1 : if (loadGroup) {
7645 1 : reporter->FlushConsoleReports(loadGroup);
7646 : } else {
7647 0 : reporter->FlushConsoleReports(GetDocument());
7648 : }
7649 : }
7650 :
7651 12 : nsCOMPtr<nsIURI> url;
7652 6 : nsresult rv = aChannel->GetURI(getter_AddRefs(url));
7653 6 : if (NS_FAILED(rv)) {
7654 0 : return rv;
7655 : }
7656 :
7657 12 : nsCOMPtr<nsITimedChannel> timingChannel = do_QueryInterface(aChannel);
7658 6 : if (timingChannel) {
7659 1 : TimeStamp channelCreationTime;
7660 1 : rv = timingChannel->GetChannelCreation(&channelCreationTime);
7661 1 : if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
7662 1 : Telemetry::AccumulateTimeDelta(Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
7663 1 : channelCreationTime);
7664 : nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup =
7665 2 : do_QueryInterface(mLoadGroup);
7666 1 : if (internalLoadGroup) {
7667 1 : internalLoadGroup->OnEndPageLoad(aChannel);
7668 : }
7669 : }
7670 : }
7671 :
7672 : // Timing is picked up by the window, we don't need it anymore
7673 6 : mTiming = nullptr;
7674 :
7675 : // clean up reload state for meta charset
7676 6 : if (eCharsetReloadRequested == mCharsetReloadState) {
7677 0 : mCharsetReloadState = eCharsetReloadStopOrigional;
7678 : } else {
7679 6 : mCharsetReloadState = eCharsetReloadInit;
7680 : }
7681 :
7682 : // Save a pointer to the currently-loading history entry.
7683 : // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
7684 : // entry further down in this method.
7685 12 : nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
7686 : mozilla::Unused << loadingSHE; // XXX: Not sure if we need this anymore
7687 :
7688 : //
7689 : // one of many safeguards that prevent death and destruction if
7690 : // someone is so very very rude as to bring this window down
7691 : // during this load handler.
7692 : //
7693 12 : nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
7694 :
7695 : // Notify the ContentViewer that the Document has finished loading. This
7696 : // will cause any OnLoad(...) and PopState(...) handlers to fire.
7697 6 : if (!mEODForCurrentDocument && mContentViewer) {
7698 6 : mIsExecutingOnLoadHandler = true;
7699 6 : mContentViewer->LoadComplete(aStatus);
7700 6 : mIsExecutingOnLoadHandler = false;
7701 :
7702 6 : mEODForCurrentDocument = true;
7703 :
7704 : // If all documents have completed their loading
7705 : // favor native event dispatch priorities
7706 : // over performance
7707 6 : if (--gNumberOfDocumentsLoading == 0) {
7708 : // Hint to use normal native event dispatch priorities
7709 2 : FavorPerformanceHint(false);
7710 : }
7711 : }
7712 : /* Check if the httpChannel has any cache-control related response headers,
7713 : * like no-store, no-cache. If so, update SHEntry so that
7714 : * when a user goes back/forward to this page, we appropriately do
7715 : * form value restoration or load from server.
7716 : */
7717 12 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
7718 6 : if (!httpChannel) {
7719 : // HttpChannel could be hiding underneath a Multipart channel.
7720 5 : GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
7721 : }
7722 :
7723 6 : if (httpChannel) {
7724 : // figure out if SH should be saving layout state.
7725 1 : bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
7726 3 : if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
7727 1 : (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) {
7728 0 : mLSHE->SetSaveLayoutStateFlag(false);
7729 : }
7730 : }
7731 :
7732 : // Clear mLSHE after calling the onLoadHandlers. This way, if the
7733 : // onLoadHandler tries to load something different in
7734 : // itself or one of its children, we can deal with it appropriately.
7735 6 : if (mLSHE) {
7736 1 : mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
7737 :
7738 : // Clear the mLSHE reference to indicate document loading is done one
7739 : // way or another.
7740 1 : SetHistoryEntry(&mLSHE, nullptr);
7741 : }
7742 : // if there's a refresh header in the channel, this method
7743 : // will set it up for us.
7744 6 : if (mIsActive || !mDisableMetaRefreshWhenInactive)
7745 6 : RefreshURIFromQueue();
7746 :
7747 : // Test whether this is the top frame or a subframe
7748 6 : bool isTopFrame = true;
7749 12 : nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
7750 6 : rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
7751 6 : if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
7752 1 : isTopFrame = false;
7753 : }
7754 :
7755 : //
7756 : // If the page load failed, then deal with the error condition...
7757 : // Errors are handled as follows:
7758 : // 1. Check to see if it's a file not found error or bad content
7759 : // encoding error.
7760 : // 2. Send the URI to a keyword server (if enabled)
7761 : // 3. If the error was DNS failure, then add www and .com to the URI
7762 : // (if appropriate).
7763 : // 4. Throw an error dialog box...
7764 : //
7765 6 : if (url && NS_FAILED(aStatus)) {
7766 3 : if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
7767 3 : aStatus == NS_ERROR_FILE_ACCESS_DENIED ||
7768 3 : aStatus == NS_ERROR_CORRUPTED_CONTENT ||
7769 : aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
7770 0 : DisplayLoadError(aStatus, url, nullptr, aChannel);
7771 0 : return NS_OK;
7772 : }
7773 :
7774 : // Handle iframe document not loading error because source was
7775 : // a tracking URL. We make a note of this iframe node by including
7776 : // it in a dedicated array of blocked tracking nodes under its parent
7777 : // document. (document of parent window of blocked document)
7778 3 : if (isTopFrame == false && aStatus == NS_ERROR_TRACKING_URI) {
7779 : // frameElement is our nsIContent to be annotated
7780 0 : nsCOMPtr<nsIDOMElement> frameElement;
7781 0 : nsPIDOMWindowOuter* thisWindow = GetWindow();
7782 0 : if (!thisWindow) {
7783 0 : return NS_OK;
7784 : }
7785 :
7786 0 : frameElement = thisWindow->GetFrameElement();
7787 0 : if (!frameElement) {
7788 0 : return NS_OK;
7789 : }
7790 :
7791 : // Parent window
7792 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
7793 0 : GetSameTypeParent(getter_AddRefs(parentItem));
7794 0 : if (!parentItem) {
7795 0 : return NS_OK;
7796 : }
7797 :
7798 0 : nsCOMPtr<nsIDocument> parentDoc;
7799 0 : parentDoc = parentItem->GetDocument();
7800 0 : if (!parentDoc) {
7801 0 : return NS_OK;
7802 : }
7803 :
7804 0 : nsCOMPtr<nsIContent> cont = do_QueryInterface(frameElement);
7805 0 : parentDoc->AddBlockedTrackingNode(cont);
7806 :
7807 0 : return NS_OK;
7808 : }
7809 :
7810 3 : if (sURIFixup) {
7811 : //
7812 : // Try and make an alternative URI from the old one
7813 : //
7814 6 : nsCOMPtr<nsIURI> newURI;
7815 6 : nsCOMPtr<nsIInputStream> newPostData;
7816 :
7817 6 : nsAutoCString oldSpec;
7818 3 : url->GetSpec(oldSpec);
7819 :
7820 : //
7821 : // First try keyword fixup
7822 : //
7823 6 : nsAutoString keywordProviderName, keywordAsSent;
7824 3 : if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
7825 0 : bool keywordsEnabled = Preferences::GetBool("keyword.enabled", false);
7826 :
7827 0 : nsAutoCString host;
7828 0 : url->GetHost(host);
7829 :
7830 0 : nsAutoCString scheme;
7831 0 : url->GetScheme(scheme);
7832 :
7833 0 : int32_t dotLoc = host.FindChar('.');
7834 :
7835 : // we should only perform a keyword search under the following
7836 : // conditions:
7837 : // (0) Pref keyword.enabled is true
7838 : // (1) the url scheme is http (or https)
7839 : // (2) the url does not have a protocol scheme
7840 : // If we don't enforce such a policy, then we end up doing
7841 : // keyword searchs on urls we don't intend like imap, file,
7842 : // mailbox, etc. This could lead to a security problem where we
7843 : // send data to the keyword server that we shouldn't be.
7844 : // Someone needs to clean up keywords in general so we can
7845 : // determine on a per url basis if we want keywords
7846 : // enabled...this is just a bandaid...
7847 0 : if (keywordsEnabled && !scheme.IsEmpty() &&
7848 0 : (scheme.Find("http") != 0)) {
7849 0 : keywordsEnabled = false;
7850 : }
7851 :
7852 0 : if (keywordsEnabled && (kNotFound == dotLoc)) {
7853 0 : nsCOMPtr<nsIURIFixupInfo> info;
7854 : // only send non-qualified hosts to the keyword server
7855 0 : if (!mOriginalUriString.IsEmpty()) {
7856 0 : sURIFixup->KeywordToURI(mOriginalUriString,
7857 0 : getter_AddRefs(newPostData),
7858 0 : getter_AddRefs(info));
7859 : } else {
7860 : //
7861 : // If this string was passed through nsStandardURL by
7862 : // chance, then it may have been converted from UTF-8 to
7863 : // ACE, which would result in a completely bogus keyword
7864 : // query. Here we try to recover the original Unicode
7865 : // value, but this is not 100% correct since the value may
7866 : // have been normalized per the IDN normalization rules.
7867 : //
7868 : // Since we don't have access to the exact original string
7869 : // that was entered by the user, this will just have to do.
7870 : bool isACE;
7871 0 : nsAutoCString utf8Host;
7872 : nsCOMPtr<nsIIDNService> idnSrv =
7873 0 : do_GetService(NS_IDNSERVICE_CONTRACTID);
7874 0 : if (idnSrv &&
7875 0 : NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
7876 0 : NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
7877 0 : sURIFixup->KeywordToURI(utf8Host,
7878 0 : getter_AddRefs(newPostData),
7879 0 : getter_AddRefs(info));
7880 : } else {
7881 0 : sURIFixup->KeywordToURI(host,
7882 0 : getter_AddRefs(newPostData),
7883 0 : getter_AddRefs(info));
7884 : }
7885 : }
7886 :
7887 0 : info->GetPreferredURI(getter_AddRefs(newURI));
7888 0 : if (newURI) {
7889 0 : info->GetKeywordAsSent(keywordAsSent);
7890 0 : info->GetKeywordProviderName(keywordProviderName);
7891 : }
7892 : } // end keywordsEnabled
7893 : }
7894 :
7895 : //
7896 : // Now try change the address, e.g. turn http://foo into
7897 : // http://www.foo.com
7898 : //
7899 3 : if (aStatus == NS_ERROR_UNKNOWN_HOST ||
7900 : aStatus == NS_ERROR_NET_RESET) {
7901 0 : bool doCreateAlternate = true;
7902 :
7903 : // Skip fixup for anything except a normal document load
7904 : // operation on the topframe.
7905 :
7906 0 : if (mLoadType != LOAD_NORMAL || !isTopFrame) {
7907 0 : doCreateAlternate = false;
7908 : } else {
7909 : // Test if keyword lookup produced a new URI or not
7910 0 : if (newURI) {
7911 0 : bool sameURI = false;
7912 0 : url->Equals(newURI, &sameURI);
7913 0 : if (!sameURI) {
7914 : // Keyword lookup made a new URI so no need to try
7915 : // an alternate one.
7916 0 : doCreateAlternate = false;
7917 : }
7918 : }
7919 :
7920 0 : if (doCreateAlternate) {
7921 : // Skip doing this if our channel was redirected, because we
7922 : // shouldn't be guessing things about the post-redirect URI.
7923 0 : nsLoadFlags loadFlags = 0;
7924 0 : if (NS_FAILED(aChannel->GetLoadFlags(&loadFlags)) ||
7925 0 : (loadFlags & nsIChannel::LOAD_REPLACE)) {
7926 0 : doCreateAlternate = false;
7927 : }
7928 : }
7929 : }
7930 0 : if (doCreateAlternate) {
7931 0 : newURI = nullptr;
7932 0 : newPostData = nullptr;
7933 0 : keywordProviderName.Truncate();
7934 0 : keywordAsSent.Truncate();
7935 0 : sURIFixup->CreateFixupURI(oldSpec,
7936 : nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
7937 0 : getter_AddRefs(newPostData),
7938 0 : getter_AddRefs(newURI));
7939 : }
7940 : }
7941 :
7942 : // Did we make a new URI that is different to the old one? If so
7943 : // load it.
7944 : //
7945 3 : if (newURI) {
7946 : // Make sure the new URI is different from the old one,
7947 : // otherwise there's little point trying to load it again.
7948 0 : bool sameURI = false;
7949 0 : url->Equals(newURI, &sameURI);
7950 0 : if (!sameURI) {
7951 0 : nsAutoCString newSpec;
7952 0 : newURI->GetSpec(newSpec);
7953 0 : NS_ConvertUTF8toUTF16 newSpecW(newSpec);
7954 :
7955 : // This notification is meant for Firefox Health Report so it
7956 : // can increment counts from the search engine
7957 0 : MaybeNotifyKeywordSearchLoading(keywordProviderName, keywordAsSent);
7958 :
7959 0 : nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
7960 : nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo
7961 0 : ? loadInfo->TriggeringPrincipal()
7962 0 : : nsContentUtils::GetSystemPrincipal();
7963 0 : return LoadURI(newSpecW.get(), // URI string
7964 : LOAD_FLAGS_NONE, // Load flags
7965 : nullptr, // Referring URI
7966 : newPostData, // Post data stream
7967 : nullptr, // Headers stream
7968 0 : triggeringPrincipal); // TriggeringPrincipal
7969 : }
7970 : }
7971 : }
7972 :
7973 : // Well, fixup didn't work :-(
7974 : // It is time to throw an error dialog box, and be done with it...
7975 :
7976 : // Errors to be shown only on top-level frames
7977 6 : if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
7978 3 : aStatus == NS_ERROR_CONNECTION_REFUSED ||
7979 3 : aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
7980 3 : aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
7981 0 : (isTopFrame || UseErrorPages())) {
7982 0 : DisplayLoadError(aStatus, url, nullptr, aChannel);
7983 6 : } else if (aStatus == NS_ERROR_NET_TIMEOUT ||
7984 3 : aStatus == NS_ERROR_REDIRECT_LOOP ||
7985 3 : aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
7986 3 : aStatus == NS_ERROR_NET_INTERRUPT ||
7987 3 : aStatus == NS_ERROR_NET_RESET ||
7988 3 : aStatus == NS_ERROR_OFFLINE ||
7989 3 : aStatus == NS_ERROR_MALWARE_URI ||
7990 3 : aStatus == NS_ERROR_PHISHING_URI ||
7991 3 : aStatus == NS_ERROR_UNWANTED_URI ||
7992 3 : aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
7993 3 : aStatus == NS_ERROR_REMOTE_XUL ||
7994 3 : aStatus == NS_ERROR_INTERCEPTION_FAILED ||
7995 6 : aStatus == NS_ERROR_NET_INADEQUATE_SECURITY ||
7996 3 : NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
7997 : // Errors to be shown for any frame
7998 0 : DisplayLoadError(aStatus, url, nullptr, aChannel);
7999 3 : } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
8000 : // Non-caching channels will simply return NS_ERROR_OFFLINE.
8001 : // Caching channels would have to look at their flags to work
8002 : // out which error to return. Or we can fix up the error here.
8003 0 : if (!(mLoadType & LOAD_CMD_HISTORY)) {
8004 0 : aStatus = NS_ERROR_OFFLINE;
8005 : }
8006 0 : DisplayLoadError(aStatus, url, nullptr, aChannel);
8007 : }
8008 3 : } else if (url && NS_SUCCEEDED(aStatus)) {
8009 : // If we have a host
8010 6 : nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
8011 3 : if (loadInfo) {
8012 3 : mozilla::net::PredictorLearnRedirect(url, aChannel,
8013 6 : loadInfo->GetOriginAttributes());
8014 : }
8015 : }
8016 :
8017 6 : return NS_OK;
8018 : }
8019 :
8020 : //*****************************************************************************
8021 : // nsDocShell: Content Viewer Management
8022 : //*****************************************************************************
8023 :
8024 : nsresult
8025 594 : nsDocShell::EnsureContentViewer()
8026 : {
8027 594 : if (mContentViewer) {
8028 592 : return NS_OK;
8029 : }
8030 2 : if (mIsBeingDestroyed) {
8031 0 : return NS_ERROR_FAILURE;
8032 : }
8033 :
8034 4 : nsCOMPtr<nsIURI> baseURI;
8035 2 : nsIPrincipal* principal = GetInheritedPrincipal(false);
8036 4 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
8037 2 : GetSameTypeParent(getter_AddRefs(parentItem));
8038 2 : if (parentItem) {
8039 0 : if (nsCOMPtr<nsPIDOMWindowOuter> domWin = GetWindow()) {
8040 0 : nsCOMPtr<Element> parentElement = domWin->GetFrameElementInternal();
8041 0 : if (parentElement) {
8042 0 : baseURI = parentElement->GetBaseURI();
8043 : }
8044 : }
8045 : }
8046 :
8047 2 : nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
8048 :
8049 2 : NS_ENSURE_STATE(mContentViewer);
8050 :
8051 2 : if (NS_SUCCEEDED(rv)) {
8052 4 : nsCOMPtr<nsIDocument> doc(GetDocument());
8053 2 : NS_ASSERTION(doc,
8054 : "Should have doc if CreateAboutBlankContentViewer "
8055 : "succeeded!");
8056 :
8057 2 : doc->SetIsInitialDocument(true);
8058 :
8059 : // Documents created using EnsureContentViewer may be transient
8060 : // placeholders created by framescripts before content has a chance to
8061 : // load. In some cases, window.open(..., "noopener") will create such a
8062 : // document (in a new TabGroup) and then synchronously tear it down, firing
8063 : // a "pagehide" event. Doing so violates our assertions about
8064 : // DocGroups. It's easier to silence the assertion here than to avoid
8065 : // creating the extra document.
8066 2 : doc->IgnoreDocGroupMismatches();
8067 : }
8068 :
8069 2 : return rv;
8070 : }
8071 :
8072 : nsresult
8073 4 : nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
8074 : nsIURI* aBaseURI,
8075 : bool aTryToSaveOldPresentation,
8076 : bool aCheckPermitUnload)
8077 : {
8078 8 : nsCOMPtr<nsIDocument> blankDoc;
8079 8 : nsCOMPtr<nsIContentViewer> viewer;
8080 4 : nsresult rv = NS_ERROR_FAILURE;
8081 :
8082 : /* mCreatingDocument should never be true at this point. However, it's
8083 : a theoretical possibility. We want to know about it and make it stop,
8084 : and this sounds like a job for an assertion. */
8085 4 : NS_ASSERTION(!mCreatingDocument,
8086 : "infinite(?) loop creating document averted");
8087 4 : if (mCreatingDocument) {
8088 0 : return NS_ERROR_FAILURE;
8089 : }
8090 :
8091 : // mContentViewer->PermitUnload may release |this| docshell.
8092 8 : nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
8093 :
8094 8 : AutoRestore<bool> creatingDocument(mCreatingDocument);
8095 4 : mCreatingDocument = true;
8096 :
8097 4 : if (aPrincipal && !nsContentUtils::IsSystemPrincipal(aPrincipal) &&
8098 0 : mItemType != typeChrome) {
8099 0 : MOZ_ASSERT(aPrincipal->OriginAttributesRef() == mOriginAttributes);
8100 : }
8101 :
8102 : // Make sure timing is created. But first record whether we had it
8103 : // already, so we don't clobber the timing for an in-progress load.
8104 4 : bool hadTiming = mTiming;
8105 4 : bool toBeReset = MaybeInitTiming();
8106 4 : if (mContentViewer) {
8107 0 : if (aCheckPermitUnload) {
8108 : // We've got a content viewer already. Make sure the user
8109 : // permits us to discard the current document and replace it
8110 : // with about:blank. And also ensure we fire the unload events
8111 : // in the current document.
8112 :
8113 : // Unload gets fired first for
8114 : // document loaded from the session history.
8115 0 : mTiming->NotifyBeforeUnload();
8116 :
8117 : bool okToUnload;
8118 0 : rv = mContentViewer->PermitUnload(&okToUnload);
8119 :
8120 0 : if (NS_SUCCEEDED(rv) && !okToUnload) {
8121 : // The user chose not to unload the page, interrupt the load.
8122 0 : MaybeResetInitTiming(toBeReset);
8123 0 : return NS_ERROR_FAILURE;
8124 : }
8125 0 : if (mTiming) {
8126 0 : mTiming->NotifyUnloadAccepted(mCurrentURI);
8127 : }
8128 : }
8129 :
8130 0 : mSavingOldViewer = aTryToSaveOldPresentation &&
8131 0 : CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
8132 :
8133 : // Make sure to blow away our mLoadingURI just in case. No loads
8134 : // from inside this pagehide.
8135 0 : mLoadingURI = nullptr;
8136 :
8137 : // Stop any in-progress loading, so that we don't accidentally trigger any
8138 : // PageShow notifications from Embed() interrupting our loading below.
8139 0 : Stop();
8140 :
8141 : // Notify the current document that it is about to be unloaded!!
8142 : //
8143 : // It is important to fire the unload() notification *before* any state
8144 : // is changed within the DocShell - otherwise, javascript will get the
8145 : // wrong information :-(
8146 : //
8147 0 : (void)FirePageHideNotification(!mSavingOldViewer);
8148 : }
8149 :
8150 : // Now make sure we don't think we're in the middle of firing unload after
8151 : // this point. This will make us fire unload when the about:blank document
8152 : // unloads... but that's ok, more or less. Would be nice if it fired load
8153 : // too, of course.
8154 4 : mFiredUnloadEvent = false;
8155 :
8156 : nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
8157 8 : nsContentUtils::FindInternalContentViewer(NS_LITERAL_CSTRING("text/html"));
8158 :
8159 4 : if (docFactory) {
8160 8 : nsCOMPtr<nsIPrincipal> principal;
8161 4 : if (mSandboxFlags & SANDBOXED_ORIGIN) {
8162 0 : if (aPrincipal) {
8163 0 : principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal);
8164 : } else {
8165 0 : principal = NullPrincipal::CreateWithInheritedAttributes(this);
8166 : }
8167 : } else {
8168 4 : principal = aPrincipal;
8169 : }
8170 : // generate (about:blank) document to load
8171 8 : docFactory->CreateBlankDocument(mLoadGroup, principal,
8172 8 : getter_AddRefs(blankDoc));
8173 4 : if (blankDoc) {
8174 : // Hack: set the base URI manually, since this document never
8175 : // got Reset() with a channel.
8176 4 : blankDoc->SetBaseURI(aBaseURI);
8177 :
8178 4 : blankDoc->SetContainer(this);
8179 :
8180 : // Copy our sandbox flags to the document. These are immutable
8181 : // after being set here.
8182 4 : blankDoc->SetSandboxFlags(mSandboxFlags);
8183 :
8184 : // create a content viewer for us and the new document
8185 8 : docFactory->CreateInstanceForDocument(
8186 : NS_ISUPPORTS_CAST(nsIDocShell*, this), blankDoc, "view",
8187 8 : getter_AddRefs(viewer));
8188 :
8189 : // hook 'em up
8190 4 : if (viewer) {
8191 4 : viewer->SetContainer(this);
8192 4 : rv = Embed(viewer, "", 0);
8193 4 : NS_ENSURE_SUCCESS(rv, rv);
8194 :
8195 4 : SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
8196 4 : rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
8197 : }
8198 : }
8199 : }
8200 :
8201 : // The transient about:blank viewer doesn't have a session history entry.
8202 4 : SetHistoryEntry(&mOSHE, nullptr);
8203 :
8204 : // Clear out our mTiming like we would in EndPageLoad, if we didn't
8205 : // have one before entering this function.
8206 4 : if (!hadTiming) {
8207 4 : mTiming = nullptr;
8208 4 : mBlankTiming = true;
8209 : }
8210 :
8211 4 : return rv;
8212 : }
8213 :
8214 : NS_IMETHODIMP
8215 2 : nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
8216 : {
8217 2 : return CreateAboutBlankContentViewer(aPrincipal, nullptr);
8218 : }
8219 :
8220 : NS_IMETHODIMP
8221 0 : nsDocShell::ForceCreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
8222 : {
8223 0 : return CreateAboutBlankContentViewer(aPrincipal, nullptr, true, false);
8224 : }
8225 :
8226 : bool
8227 6 : nsDocShell::CanSavePresentation(uint32_t aLoadType,
8228 : nsIRequest* aNewRequest,
8229 : nsIDocument* aNewDocument)
8230 : {
8231 6 : if (!mOSHE) {
8232 6 : return false; // no entry to save into
8233 : }
8234 :
8235 0 : nsCOMPtr<nsIContentViewer> viewer;
8236 0 : mOSHE->GetContentViewer(getter_AddRefs(viewer));
8237 0 : if (viewer) {
8238 0 : NS_WARNING("mOSHE already has a content viewer!");
8239 0 : return false;
8240 : }
8241 :
8242 : // Only save presentation for "normal" loads and link loads. Anything else
8243 : // probably wants to refetch the page, so caching the old presentation
8244 : // would be incorrect.
8245 0 : if (aLoadType != LOAD_NORMAL &&
8246 0 : aLoadType != LOAD_HISTORY &&
8247 0 : aLoadType != LOAD_LINK &&
8248 0 : aLoadType != LOAD_STOP_CONTENT &&
8249 0 : aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
8250 : aLoadType != LOAD_ERROR_PAGE) {
8251 0 : return false;
8252 : }
8253 :
8254 : // If the session history entry has the saveLayoutState flag set to false,
8255 : // then we should not cache the presentation.
8256 : bool canSaveState;
8257 0 : mOSHE->GetSaveLayoutStateFlag(&canSaveState);
8258 0 : if (!canSaveState) {
8259 0 : return false;
8260 : }
8261 :
8262 : // If the document is not done loading, don't cache it.
8263 0 : if (!mScriptGlobal || mScriptGlobal->IsLoading()) {
8264 0 : return false;
8265 : }
8266 :
8267 0 : if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument)) {
8268 0 : return false;
8269 : }
8270 :
8271 : // Avoid doing the work of saving the presentation state in the case where
8272 : // the content viewer cache is disabled.
8273 0 : if (nsSHistory::GetMaxTotalViewers() == 0) {
8274 0 : return false;
8275 : }
8276 :
8277 : // Don't cache the content viewer if we're in a subframe and the subframe
8278 : // pref is disabled.
8279 : bool cacheFrames =
8280 0 : Preferences::GetBool("browser.sessionhistory.cache_subframes", false);
8281 0 : if (!cacheFrames) {
8282 0 : nsCOMPtr<nsIDocShellTreeItem> root;
8283 0 : GetSameTypeParent(getter_AddRefs(root));
8284 0 : if (root && root != this) {
8285 0 : return false; // this is a subframe load
8286 : }
8287 : }
8288 :
8289 : // If the document does not want its presentation cached, then don't.
8290 0 : nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
8291 0 : return doc && doc->CanSavePresentation(aNewRequest);
8292 : }
8293 :
8294 : void
8295 0 : nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry)
8296 : {
8297 0 : NS_ASSERTION(!mEditorData,
8298 : "Why reattach an editor when we already have one?");
8299 0 : NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
8300 : "Reattaching when there's not a detached editor.");
8301 :
8302 0 : if (mEditorData || !aSHEntry) {
8303 0 : return;
8304 : }
8305 :
8306 0 : mEditorData = aSHEntry->ForgetEditorData();
8307 0 : if (mEditorData) {
8308 : #ifdef DEBUG
8309 : nsresult rv =
8310 : #endif
8311 0 : mEditorData->ReattachToWindow(this);
8312 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
8313 : }
8314 : }
8315 :
8316 : void
8317 4 : nsDocShell::DetachEditorFromWindow()
8318 : {
8319 4 : if (!mEditorData || mEditorData->WaitingForLoad()) {
8320 : // If there's nothing to detach, or if the editor data is actually set
8321 : // up for the _new_ page that's coming in, don't detach.
8322 4 : return;
8323 : }
8324 :
8325 0 : NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
8326 : "Detaching editor when it's already detached.");
8327 :
8328 0 : nsresult res = mEditorData->DetachFromWindow();
8329 0 : NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
8330 :
8331 0 : if (NS_SUCCEEDED(res)) {
8332 : // Make mOSHE hold the owning ref to the editor data.
8333 0 : if (mOSHE) {
8334 0 : mOSHE->SetEditorData(mEditorData.forget());
8335 : } else {
8336 0 : mEditorData = nullptr;
8337 : }
8338 : }
8339 :
8340 : #ifdef DEBUG
8341 : {
8342 : bool isEditable;
8343 0 : GetEditable(&isEditable);
8344 0 : NS_ASSERTION(!isEditable,
8345 : "Window is still editable after detaching editor.");
8346 : }
8347 : #endif // DEBUG
8348 : }
8349 :
8350 : nsresult
8351 0 : nsDocShell::CaptureState()
8352 : {
8353 0 : if (!mOSHE || mOSHE == mLSHE) {
8354 : // No entry to save into, or we're replacing the existing entry.
8355 0 : return NS_ERROR_FAILURE;
8356 : }
8357 :
8358 0 : if (!mScriptGlobal) {
8359 0 : return NS_ERROR_FAILURE;
8360 : }
8361 :
8362 0 : nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState();
8363 0 : NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE);
8364 :
8365 : #ifdef DEBUG_PAGE_CACHE
8366 : nsCOMPtr<nsIURI> uri;
8367 : mOSHE->GetURI(getter_AddRefs(uri));
8368 : nsAutoCString spec;
8369 : if (uri) {
8370 : uri->GetSpec(spec);
8371 : }
8372 : printf("Saving presentation into session history\n");
8373 : printf(" SH URI: %s\n", spec.get());
8374 : #endif
8375 :
8376 0 : nsresult rv = mOSHE->SetWindowState(windowState);
8377 0 : NS_ENSURE_SUCCESS(rv, rv);
8378 :
8379 : // Suspend refresh URIs and save off the timer queue
8380 0 : rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
8381 0 : NS_ENSURE_SUCCESS(rv, rv);
8382 :
8383 : // Capture the current content viewer bounds.
8384 0 : if (mContentViewer) {
8385 0 : nsIntRect bounds;
8386 0 : mContentViewer->GetBounds(bounds);
8387 0 : rv = mOSHE->SetViewerBounds(bounds);
8388 0 : NS_ENSURE_SUCCESS(rv, rv);
8389 : }
8390 :
8391 : // Capture the docshell hierarchy.
8392 0 : mOSHE->ClearChildShells();
8393 :
8394 0 : uint32_t childCount = mChildList.Length();
8395 0 : for (uint32_t i = 0; i < childCount; ++i) {
8396 0 : nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
8397 0 : NS_ASSERTION(childShell, "null child shell");
8398 :
8399 0 : mOSHE->AddChildShell(childShell);
8400 : }
8401 :
8402 0 : return NS_OK;
8403 : }
8404 :
8405 : NS_IMETHODIMP
8406 0 : nsDocShell::RestorePresentationEvent::Run()
8407 : {
8408 0 : if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory())) {
8409 0 : NS_WARNING("RestoreFromHistory failed");
8410 : }
8411 0 : return NS_OK;
8412 : }
8413 :
8414 : NS_IMETHODIMP
8415 0 : nsDocShell::BeginRestore(nsIContentViewer* aContentViewer, bool aTop)
8416 : {
8417 : nsresult rv;
8418 0 : if (!aContentViewer) {
8419 0 : rv = EnsureContentViewer();
8420 0 : NS_ENSURE_SUCCESS(rv, rv);
8421 :
8422 0 : aContentViewer = mContentViewer;
8423 : }
8424 :
8425 : // Dispatch events for restoring the presentation. We try to simulate
8426 : // the progress notifications loading the document would cause, so we add
8427 : // the document's channel to the loadgroup to initiate stateChange
8428 : // notifications.
8429 :
8430 0 : nsCOMPtr<nsIDOMDocument> domDoc;
8431 0 : aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
8432 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
8433 0 : if (doc) {
8434 0 : nsIChannel* channel = doc->GetChannel();
8435 0 : if (channel) {
8436 0 : mEODForCurrentDocument = false;
8437 0 : mIsRestoringDocument = true;
8438 0 : mLoadGroup->AddRequest(channel, nullptr);
8439 0 : mIsRestoringDocument = false;
8440 : }
8441 : }
8442 :
8443 0 : if (!aTop) {
8444 : // This point corresponds to us having gotten OnStartRequest or
8445 : // STATE_START, so do the same thing that CreateContentViewer does at
8446 : // this point to ensure that unload/pagehide events for this document
8447 : // will fire when it's unloaded again.
8448 0 : mFiredUnloadEvent = false;
8449 :
8450 : // For non-top frames, there is no notion of making sure that the
8451 : // previous document is in the domwindow when STATE_START notifications
8452 : // happen. We can just call BeginRestore for all of the child shells
8453 : // now.
8454 0 : rv = BeginRestoreChildren();
8455 0 : NS_ENSURE_SUCCESS(rv, rv);
8456 : }
8457 :
8458 0 : return NS_OK;
8459 : }
8460 :
8461 : nsresult
8462 0 : nsDocShell::BeginRestoreChildren()
8463 : {
8464 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
8465 0 : while (iter.HasMore()) {
8466 0 : nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
8467 0 : if (child) {
8468 0 : nsresult rv = child->BeginRestore(nullptr, false);
8469 0 : NS_ENSURE_SUCCESS(rv, rv);
8470 : }
8471 : }
8472 0 : return NS_OK;
8473 : }
8474 :
8475 : NS_IMETHODIMP
8476 0 : nsDocShell::FinishRestore()
8477 : {
8478 : // First we call finishRestore() on our children. In the simulated load,
8479 : // all of the child frames finish loading before the main document.
8480 :
8481 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
8482 0 : while (iter.HasMore()) {
8483 0 : nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
8484 0 : if (child) {
8485 0 : child->FinishRestore();
8486 : }
8487 : }
8488 :
8489 0 : if (mOSHE && mOSHE->HasDetachedEditor()) {
8490 0 : ReattachEditorToWindow(mOSHE);
8491 : }
8492 :
8493 0 : nsCOMPtr<nsIDocument> doc = GetDocument();
8494 0 : if (doc) {
8495 : // Finally, we remove the request from the loadgroup. This will
8496 : // cause onStateChange(STATE_STOP) to fire, which will fire the
8497 : // pageshow event to the chrome.
8498 :
8499 0 : nsIChannel* channel = doc->GetChannel();
8500 0 : if (channel) {
8501 0 : mIsRestoringDocument = true;
8502 0 : mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
8503 0 : mIsRestoringDocument = false;
8504 : }
8505 : }
8506 :
8507 0 : return NS_OK;
8508 : }
8509 :
8510 : NS_IMETHODIMP
8511 66 : nsDocShell::GetRestoringDocument(bool* aRestoring)
8512 : {
8513 66 : *aRestoring = mIsRestoringDocument;
8514 66 : return NS_OK;
8515 : }
8516 :
8517 : nsresult
8518 0 : nsDocShell::RestorePresentation(nsISHEntry* aSHEntry, bool* aRestoring)
8519 : {
8520 0 : NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
8521 : "RestorePresentation should only be called for history loads");
8522 :
8523 0 : nsCOMPtr<nsIContentViewer> viewer;
8524 0 : aSHEntry->GetContentViewer(getter_AddRefs(viewer));
8525 :
8526 : #ifdef DEBUG_PAGE_CACHE
8527 : nsCOMPtr<nsIURI> uri;
8528 : aSHEntry->GetURI(getter_AddRefs(uri));
8529 :
8530 : nsAutoCString spec;
8531 : if (uri) {
8532 : uri->GetSpec(spec);
8533 : }
8534 : #endif
8535 :
8536 0 : *aRestoring = false;
8537 :
8538 0 : if (!viewer) {
8539 : #ifdef DEBUG_PAGE_CACHE
8540 : printf("no saved presentation for uri: %s\n", spec.get());
8541 : #endif
8542 0 : return NS_OK;
8543 : }
8544 :
8545 : // We need to make sure the content viewer's container is this docshell.
8546 : // In subframe navigation, it's possible for the docshell that the
8547 : // content viewer was originally loaded into to be replaced with a
8548 : // different one. We don't currently support restoring the presentation
8549 : // in that case.
8550 :
8551 0 : nsCOMPtr<nsIDocShell> container;
8552 0 : viewer->GetContainer(getter_AddRefs(container));
8553 0 : if (!::SameCOMIdentity(container, GetAsSupports(this))) {
8554 : #ifdef DEBUG_PAGE_CACHE
8555 : printf("No valid container, clearing presentation\n");
8556 : #endif
8557 0 : aSHEntry->SetContentViewer(nullptr);
8558 0 : return NS_ERROR_FAILURE;
8559 : }
8560 :
8561 0 : NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
8562 :
8563 : #ifdef DEBUG_PAGE_CACHE
8564 : printf("restoring presentation from session history: %s\n", spec.get());
8565 : #endif
8566 :
8567 0 : SetHistoryEntry(&mLSHE, aSHEntry);
8568 :
8569 : // Post an event that will remove the request after we've returned
8570 : // to the event loop. This mimics the way it is called by nsIChannel
8571 : // implementations.
8572 :
8573 : // Revoke any pending restore (just in case)
8574 0 : NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
8575 : "should only have one RestorePresentationEvent");
8576 0 : mRestorePresentationEvent.Revoke();
8577 :
8578 0 : RefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
8579 0 : nsresult rv = DispatchToTabGroup("nsDocShell::RestorePresentationEvent",
8580 : TaskCategory::Other,
8581 0 : RefPtr<RestorePresentationEvent>(evt).forget());
8582 0 : if (NS_SUCCEEDED(rv)) {
8583 0 : mRestorePresentationEvent = evt.get();
8584 : // The rest of the restore processing will happen on our event
8585 : // callback.
8586 0 : *aRestoring = true;
8587 : }
8588 :
8589 0 : return rv;
8590 : }
8591 :
8592 : namespace {
8593 : class MOZ_STACK_CLASS PresentationEventForgetter
8594 : {
8595 : public:
8596 0 : explicit PresentationEventForgetter(
8597 : nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
8598 : aRestorePresentationEvent)
8599 0 : : mRestorePresentationEvent(aRestorePresentationEvent)
8600 0 : , mEvent(aRestorePresentationEvent.get())
8601 : {
8602 0 : }
8603 :
8604 0 : ~PresentationEventForgetter()
8605 0 : {
8606 0 : Forget();
8607 0 : }
8608 :
8609 0 : void Forget()
8610 : {
8611 0 : if (mRestorePresentationEvent.get() == mEvent) {
8612 0 : mRestorePresentationEvent.Forget();
8613 0 : mEvent = nullptr;
8614 : }
8615 0 : }
8616 :
8617 : private:
8618 : nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
8619 : mRestorePresentationEvent;
8620 : RefPtr<nsDocShell::RestorePresentationEvent> mEvent;
8621 : };
8622 :
8623 : } // namespace
8624 :
8625 : nsresult
8626 0 : nsDocShell::RestoreFromHistory()
8627 : {
8628 0 : MOZ_ASSERT(mRestorePresentationEvent.IsPending());
8629 0 : PresentationEventForgetter forgetter(mRestorePresentationEvent);
8630 :
8631 : // This section of code follows the same ordering as CreateContentViewer.
8632 0 : if (!mLSHE) {
8633 0 : return NS_ERROR_FAILURE;
8634 : }
8635 :
8636 0 : nsCOMPtr<nsIContentViewer> viewer;
8637 0 : mLSHE->GetContentViewer(getter_AddRefs(viewer));
8638 0 : if (!viewer) {
8639 0 : return NS_ERROR_FAILURE;
8640 : }
8641 :
8642 0 : if (mSavingOldViewer) {
8643 : // We determined that it was safe to cache the document presentation
8644 : // at the time we initiated the new load. We need to check whether
8645 : // it's still safe to do so, since there may have been DOM mutations
8646 : // or new requests initiated.
8647 0 : nsCOMPtr<nsIDOMDocument> domDoc;
8648 0 : viewer->GetDOMDocument(getter_AddRefs(domDoc));
8649 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
8650 0 : nsIRequest* request = nullptr;
8651 0 : if (doc) {
8652 0 : request = doc->GetChannel();
8653 : }
8654 0 : mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
8655 : }
8656 :
8657 0 : nsCOMPtr<nsIContentViewer> oldCv(mContentViewer);
8658 0 : nsCOMPtr<nsIContentViewer> newCv(viewer);
8659 0 : int32_t minFontSize = 0;
8660 0 : float textZoom = 1.0f;
8661 0 : float pageZoom = 1.0f;
8662 0 : float overrideDPPX = 0.0f;
8663 :
8664 0 : bool styleDisabled = false;
8665 0 : if (oldCv && newCv) {
8666 0 : oldCv->GetMinFontSize(&minFontSize);
8667 0 : oldCv->GetTextZoom(&textZoom);
8668 0 : oldCv->GetFullZoom(&pageZoom);
8669 0 : oldCv->GetOverrideDPPX(&overrideDPPX);
8670 0 : oldCv->GetAuthorStyleDisabled(&styleDisabled);
8671 : }
8672 :
8673 : // Protect against mLSHE going away via a load triggered from
8674 : // pagehide or unload.
8675 0 : nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
8676 :
8677 : // Make sure to blow away our mLoadingURI just in case. No loads
8678 : // from inside this pagehide.
8679 0 : mLoadingURI = nullptr;
8680 :
8681 : // Notify the old content viewer that it's being hidden.
8682 0 : FirePageHideNotification(!mSavingOldViewer);
8683 :
8684 : // If mLSHE was changed as a result of the pagehide event, then
8685 : // something else was loaded. Don't finish restoring.
8686 0 : if (mLSHE != origLSHE) {
8687 0 : return NS_OK;
8688 : }
8689 :
8690 : // Add the request to our load group. We do this before swapping out
8691 : // the content viewers so that consumers of STATE_START can access
8692 : // the old document. We only deal with the toplevel load at this time --
8693 : // to be consistent with normal document loading, subframes cannot start
8694 : // loading until after data arrives, which is after STATE_START completes.
8695 :
8696 : RefPtr<RestorePresentationEvent> currentPresentationRestoration =
8697 0 : mRestorePresentationEvent.get();
8698 0 : Stop();
8699 : // Make sure we're still restoring the same presentation.
8700 : // If we aren't, docshell is in process doing another load already.
8701 0 : NS_ENSURE_STATE(currentPresentationRestoration ==
8702 : mRestorePresentationEvent.get());
8703 0 : BeginRestore(viewer, true);
8704 0 : NS_ENSURE_STATE(currentPresentationRestoration ==
8705 : mRestorePresentationEvent.get());
8706 0 : forgetter.Forget();
8707 :
8708 : // Set mFiredUnloadEvent = false so that the unload handler for the
8709 : // *new* document will fire.
8710 0 : mFiredUnloadEvent = false;
8711 :
8712 0 : mURIResultedInDocument = true;
8713 0 : nsCOMPtr<nsISHistory> rootSH;
8714 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
8715 0 : if (rootSH) {
8716 0 : nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
8717 0 : rootSH->GetIndex(&mPreviousTransIndex);
8718 0 : hist->UpdateIndex();
8719 0 : rootSH->GetIndex(&mLoadedTransIndex);
8720 : #ifdef DEBUG_PAGE_CACHE
8721 : printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
8722 : mLoadedTransIndex);
8723 : #endif
8724 : }
8725 :
8726 : // Rather than call Embed(), we will retrieve the viewer from the session
8727 : // history entry and swap it in.
8728 : // XXX can we refactor this so that we can just call Embed()?
8729 0 : PersistLayoutHistoryState();
8730 : nsresult rv;
8731 0 : if (mContentViewer) {
8732 0 : if (mSavingOldViewer && NS_FAILED(CaptureState())) {
8733 0 : if (mOSHE) {
8734 0 : mOSHE->SyncPresentationState();
8735 : }
8736 0 : mSavingOldViewer = false;
8737 : }
8738 : }
8739 :
8740 0 : mSavedRefreshURIList = nullptr;
8741 :
8742 : // In cases where we use a transient about:blank viewer between loads,
8743 : // we never show the transient viewer, so _its_ previous viewer is never
8744 : // unhooked from the view hierarchy. Destroy any such previous viewer now,
8745 : // before we grab the root view sibling, so that we don't grab a view
8746 : // that's about to go away.
8747 :
8748 0 : if (mContentViewer) {
8749 0 : nsCOMPtr<nsIContentViewer> previousViewer;
8750 0 : mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
8751 0 : if (previousViewer) {
8752 0 : mContentViewer->SetPreviousViewer(nullptr);
8753 0 : previousViewer->Destroy();
8754 : }
8755 : }
8756 :
8757 : // Save off the root view's parent and sibling so that we can insert the
8758 : // new content viewer's root view at the same position. Also save the
8759 : // bounds of the root view's widget.
8760 :
8761 0 : nsView* rootViewSibling = nullptr;
8762 0 : nsView* rootViewParent = nullptr;
8763 0 : nsIntRect newBounds(0, 0, 0, 0);
8764 :
8765 0 : nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell();
8766 0 : if (oldPresShell) {
8767 0 : nsViewManager* vm = oldPresShell->GetViewManager();
8768 0 : if (vm) {
8769 0 : nsView* oldRootView = vm->GetRootView();
8770 :
8771 0 : if (oldRootView) {
8772 0 : rootViewSibling = oldRootView->GetNextSibling();
8773 0 : rootViewParent = oldRootView->GetParent();
8774 :
8775 0 : mContentViewer->GetBounds(newBounds);
8776 : }
8777 : }
8778 : }
8779 :
8780 0 : nsCOMPtr<nsIContent> container;
8781 0 : nsCOMPtr<nsIDocument> sibling;
8782 0 : if (rootViewParent && rootViewParent->GetParent()) {
8783 0 : nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
8784 0 : container = frame ? frame->GetContent() : nullptr;
8785 : }
8786 0 : if (rootViewSibling) {
8787 0 : nsIFrame* frame = rootViewSibling->GetFrame();
8788 : sibling =
8789 0 : frame ? frame->PresContext()->PresShell()->GetDocument() : nullptr;
8790 : }
8791 :
8792 : // Transfer ownership to mContentViewer. By ensuring that either the
8793 : // docshell or the session history, but not both, have references to the
8794 : // content viewer, we prevent the viewer from being torn down after
8795 : // Destroy() is called.
8796 :
8797 0 : if (mContentViewer) {
8798 0 : mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
8799 0 : viewer->SetPreviousViewer(mContentViewer);
8800 : }
8801 0 : if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
8802 : // We don't plan to save a viewer in mOSHE; tell it to drop
8803 : // any other state it's holding.
8804 0 : mOSHE->SyncPresentationState();
8805 : }
8806 :
8807 : // Order the mContentViewer setup just like Embed does.
8808 0 : mContentViewer = nullptr;
8809 :
8810 : // Now that we're about to switch documents, forget all of our children.
8811 : // Note that we cached them as needed up in CaptureState above.
8812 0 : DestroyChildren();
8813 :
8814 0 : mContentViewer.swap(viewer);
8815 :
8816 : // Grab all of the related presentation from the SHEntry now.
8817 : // Clearing the viewer from the SHEntry will clear all of this state.
8818 0 : nsCOMPtr<nsISupports> windowState;
8819 0 : mLSHE->GetWindowState(getter_AddRefs(windowState));
8820 0 : mLSHE->SetWindowState(nullptr);
8821 :
8822 : bool sticky;
8823 0 : mLSHE->GetSticky(&sticky);
8824 :
8825 0 : nsCOMPtr<nsIDOMDocument> domDoc;
8826 0 : mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
8827 :
8828 0 : nsCOMArray<nsIDocShellTreeItem> childShells;
8829 0 : int32_t i = 0;
8830 0 : nsCOMPtr<nsIDocShellTreeItem> child;
8831 0 : while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
8832 0 : child) {
8833 0 : childShells.AppendObject(child);
8834 : }
8835 :
8836 : // get the previous content viewer size
8837 0 : nsIntRect oldBounds(0, 0, 0, 0);
8838 0 : mLSHE->GetViewerBounds(oldBounds);
8839 :
8840 : // Restore the refresh URI list. The refresh timers will be restarted
8841 : // when EndPageLoad() is called.
8842 0 : nsCOMPtr<nsIMutableArray> refreshURIList;
8843 0 : mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
8844 :
8845 : // Reattach to the window object.
8846 0 : mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive
8847 0 : rv = mContentViewer->Open(windowState, mLSHE);
8848 0 : mIsRestoringDocument = false;
8849 :
8850 : // Hack to keep nsDocShellEditorData alive across the
8851 : // SetContentViewer(nullptr) call below.
8852 0 : nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
8853 :
8854 : // Now remove it from the cached presentation.
8855 0 : mLSHE->SetContentViewer(nullptr);
8856 0 : mEODForCurrentDocument = false;
8857 :
8858 0 : mLSHE->SetEditorData(data.forget());
8859 :
8860 : #ifdef DEBUG
8861 : {
8862 0 : nsCOMPtr<nsIMutableArray> refreshURIs;
8863 0 : mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
8864 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
8865 0 : mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
8866 0 : NS_ASSERTION(!refreshURIs && !childShell,
8867 : "SHEntry should have cleared presentation state");
8868 : }
8869 : #endif
8870 :
8871 : // Restore the sticky state of the viewer. The viewer has set this state
8872 : // on the history entry in Destroy() just before marking itself non-sticky,
8873 : // to avoid teardown of the presentation.
8874 0 : mContentViewer->SetSticky(sticky);
8875 :
8876 0 : NS_ENSURE_SUCCESS(rv, rv);
8877 :
8878 : // mLSHE is now our currently-loaded document.
8879 0 : SetHistoryEntry(&mOSHE, mLSHE);
8880 :
8881 : // XXX special wyciwyg handling in Embed()?
8882 :
8883 : // We aren't going to restore any items from the LayoutHistoryState,
8884 : // but we don't want them to stay around in case the page is reloaded.
8885 0 : SetLayoutHistoryState(nullptr);
8886 :
8887 : // This is the end of our Embed() replacement
8888 :
8889 0 : mSavingOldViewer = false;
8890 0 : mEODForCurrentDocument = false;
8891 :
8892 : // Tell the event loop to favor plevents over user events, see comments
8893 : // in CreateContentViewer.
8894 0 : if (++gNumberOfDocumentsLoading == 1) {
8895 0 : FavorPerformanceHint(true);
8896 : }
8897 :
8898 0 : if (oldCv && newCv) {
8899 0 : newCv->SetMinFontSize(minFontSize);
8900 0 : newCv->SetTextZoom(textZoom);
8901 0 : newCv->SetFullZoom(pageZoom);
8902 0 : newCv->SetOverrideDPPX(overrideDPPX);
8903 0 : newCv->SetAuthorStyleDisabled(styleDisabled);
8904 : }
8905 :
8906 0 : nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
8907 0 : if (document) {
8908 0 : RefPtr<nsDocShell> parent = GetParentDocshell();
8909 0 : if (parent) {
8910 0 : nsCOMPtr<nsIDocument> d = parent->GetDocument();
8911 0 : if (d) {
8912 0 : if (d->EventHandlingSuppressed()) {
8913 0 : document->SuppressEventHandling(d->EventHandlingSuppressed());
8914 : }
8915 : }
8916 : }
8917 :
8918 : // Use the uri from the mLSHE we had when we entered this function
8919 : // (which need not match the document's URI if anchors are involved),
8920 : // since that's the history entry we're loading. Note that if we use
8921 : // origLSHE we don't have to worry about whether the entry in question
8922 : // is still mLSHE or whether it's now mOSHE.
8923 0 : nsCOMPtr<nsIURI> uri;
8924 0 : origLSHE->GetURI(getter_AddRefs(uri));
8925 0 : SetCurrentURI(uri, document->GetChannel(), true, 0);
8926 : }
8927 :
8928 : // This is the end of our CreateContentViewer() replacement.
8929 : // Now we simulate a load. First, we restore the state of the javascript
8930 : // window object.
8931 0 : nsCOMPtr<nsPIDOMWindowOuter> privWin = GetWindow();
8932 0 : NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
8933 :
8934 : // Now, dispatch a title change event which would happen as the
8935 : // <head> is parsed.
8936 0 : document->NotifyPossibleTitleChange(false);
8937 :
8938 : // Now we simulate appending child docshells for subframes.
8939 0 : for (i = 0; i < childShells.Count(); ++i) {
8940 0 : nsIDocShellTreeItem* childItem = childShells.ObjectAt(i);
8941 0 : nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
8942 :
8943 : // Make sure to not clobber the state of the child. Since AddChild
8944 : // always clobbers it, save it off first.
8945 : bool allowPlugins;
8946 0 : childShell->GetAllowPlugins(&allowPlugins);
8947 :
8948 : bool allowJavascript;
8949 0 : childShell->GetAllowJavascript(&allowJavascript);
8950 :
8951 : bool allowRedirects;
8952 0 : childShell->GetAllowMetaRedirects(&allowRedirects);
8953 :
8954 : bool allowSubframes;
8955 0 : childShell->GetAllowSubframes(&allowSubframes);
8956 :
8957 : bool allowImages;
8958 0 : childShell->GetAllowImages(&allowImages);
8959 :
8960 0 : bool allowMedia = childShell->GetAllowMedia();
8961 :
8962 : bool allowDNSPrefetch;
8963 0 : childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
8964 :
8965 0 : bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
8966 : bool allowContentRetargetingOnChildren =
8967 0 : childShell->GetAllowContentRetargetingOnChildren();
8968 :
8969 : uint32_t defaultLoadFlags;
8970 0 : childShell->GetDefaultLoadFlags(&defaultLoadFlags);
8971 :
8972 : // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that
8973 : // the child inherits our state. Among other things, this means that the
8974 : // child inherits our mIsActive, mIsPrerendered and mPrivateBrowsingId,
8975 : // which is what we want.
8976 0 : AddChild(childItem);
8977 :
8978 0 : childShell->SetAllowPlugins(allowPlugins);
8979 0 : childShell->SetAllowJavascript(allowJavascript);
8980 0 : childShell->SetAllowMetaRedirects(allowRedirects);
8981 0 : childShell->SetAllowSubframes(allowSubframes);
8982 0 : childShell->SetAllowImages(allowImages);
8983 0 : childShell->SetAllowMedia(allowMedia);
8984 0 : childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
8985 0 : childShell->SetAllowContentRetargeting(allowContentRetargeting);
8986 0 : childShell->SetAllowContentRetargetingOnChildren(
8987 0 : allowContentRetargetingOnChildren);
8988 0 : childShell->SetDefaultLoadFlags(defaultLoadFlags);
8989 :
8990 0 : rv = childShell->BeginRestore(nullptr, false);
8991 0 : NS_ENSURE_SUCCESS(rv, rv);
8992 : }
8993 :
8994 : // Make sure to restore the window state after adding the child shells back
8995 : // to the tree. This is necessary for Thaw() and Resume() to propagate
8996 : // properly.
8997 0 : rv = privWin->RestoreWindowState(windowState);
8998 0 : NS_ENSURE_SUCCESS(rv, rv);
8999 :
9000 0 : nsCOMPtr<nsIPresShell> shell = GetPresShell();
9001 :
9002 : // We may be displayed on a different monitor (or in a different
9003 : // HiDPI mode) than when we got into the history list. So we need
9004 : // to check if this has happened. See bug 838239.
9005 :
9006 : // Because the prescontext normally handles resolution changes via
9007 : // a runnable (see nsPresContext::UIResolutionChanged), its device
9008 : // context won't be -immediately- updated as a result of calling
9009 : // shell->BackingScaleFactorChanged().
9010 :
9011 : // But we depend on that device context when adjusting the view size
9012 : // via mContentViewer->SetBounds(newBounds) below. So we need to
9013 : // explicitly tell it to check for changed resolution here.
9014 0 : if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) {
9015 0 : shell->BackingScaleFactorChanged();
9016 : }
9017 :
9018 0 : nsViewManager* newVM = shell ? shell->GetViewManager() : nullptr;
9019 0 : nsView* newRootView = newVM ? newVM->GetRootView() : nullptr;
9020 :
9021 : // Insert the new root view at the correct location in the view tree.
9022 0 : if (container) {
9023 : nsSubDocumentFrame* subDocFrame =
9024 0 : do_QueryFrame(container->GetPrimaryFrame());
9025 0 : rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr;
9026 : } else {
9027 0 : rootViewParent = nullptr;
9028 : }
9029 0 : if (sibling &&
9030 0 : sibling->GetShell() &&
9031 0 : sibling->GetShell()->GetViewManager()) {
9032 0 : rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView();
9033 : } else {
9034 0 : rootViewSibling = nullptr;
9035 : }
9036 0 : if (rootViewParent && newRootView &&
9037 0 : newRootView->GetParent() != rootViewParent) {
9038 0 : nsViewManager* parentVM = rootViewParent->GetViewManager();
9039 0 : if (parentVM) {
9040 : // InsertChild(parent, child, sib, true) inserts the child after
9041 : // sib in content order, which is before sib in view order. BUT
9042 : // when sib is null it inserts at the end of the the document
9043 : // order, i.e., first in view order. But when oldRootSibling is
9044 : // null, the old root as at the end of the view list --- last in
9045 : // content order --- and we want to call InsertChild(parent, child,
9046 : // nullptr, false) in that case.
9047 0 : parentVM->InsertChild(rootViewParent, newRootView,
9048 : rootViewSibling,
9049 0 : rootViewSibling ? true : false);
9050 :
9051 0 : NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
9052 : "error in InsertChild");
9053 : }
9054 : }
9055 :
9056 0 : nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow();
9057 :
9058 : // If parent is suspended, increase suspension count.
9059 : // This can't be done as early as event suppression since this
9060 : // depends on docshell tree.
9061 0 : privWinInner->SyncStateFromParentWindow();
9062 :
9063 : // Now that all of the child docshells have been put into place, we can
9064 : // restart the timers for the window and all of the child frames.
9065 0 : privWinInner->Resume();
9066 :
9067 : // Restore the refresh URI list. The refresh timers will be restarted
9068 : // when EndPageLoad() is called.
9069 0 : mRefreshURIList = refreshURIList;
9070 :
9071 : // Meta-refresh timers have been restarted for this shell, but not
9072 : // for our children. Walk the child shells and restart their timers.
9073 0 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
9074 0 : while (iter.HasMore()) {
9075 0 : nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
9076 0 : if (child) {
9077 0 : child->ResumeRefreshURIs();
9078 : }
9079 : }
9080 :
9081 : // Make sure this presentation is the same size as the previous
9082 : // presentation. If this is not the same size we showed it at last time,
9083 : // then we need to resize the widget.
9084 :
9085 : // XXXbryner This interacts poorly with Firefox's infobar. If the old
9086 : // presentation had the infobar visible, then we will resize the new
9087 : // presentation to that smaller size. However, firing the locationchanged
9088 : // event will hide the infobar, which will immediately resize the window
9089 : // back to the larger size. A future optimization might be to restore
9090 : // the presentation at the "wrong" size, then fire the locationchanged
9091 : // event and check whether the docshell's new size is the same as the
9092 : // cached viewer size (skipping the resize if they are equal).
9093 :
9094 0 : if (newRootView) {
9095 0 : if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
9096 : #ifdef DEBUG_PAGE_CACHE
9097 : printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
9098 : newBounds.y, newBounds.width, newBounds.height);
9099 : #endif
9100 0 : mContentViewer->SetBounds(newBounds);
9101 : } else {
9102 : nsIScrollableFrame* rootScrollFrame =
9103 0 : shell->GetRootScrollFrameAsScrollableExternal();
9104 0 : if (rootScrollFrame) {
9105 0 : rootScrollFrame->PostScrolledAreaEventForCurrentArea();
9106 : }
9107 : }
9108 : }
9109 :
9110 : // The FinishRestore call below can kill these, null them out so we don't
9111 : // have invalid pointer lying around.
9112 0 : newRootView = rootViewSibling = rootViewParent = nullptr;
9113 0 : newVM = nullptr;
9114 :
9115 : // Simulate the completion of the load.
9116 0 : nsDocShell::FinishRestore();
9117 :
9118 : // Restart plugins, and paint the content.
9119 0 : if (shell) {
9120 0 : shell->Thaw();
9121 : }
9122 :
9123 0 : return privWin->FireDelayedDOMEvents();
9124 : }
9125 :
9126 : nsresult
9127 4 : nsDocShell::CreateContentViewer(const nsACString& aContentType,
9128 : nsIRequest* aRequest,
9129 : nsIStreamListener** aContentHandler)
9130 : {
9131 4 : *aContentHandler = nullptr;
9132 :
9133 4 : if (!mTreeOwner) {
9134 : // If we don't have a tree owner, then we're in the process of being
9135 : // destroyed. Rather than continue trying to load something, just give up.
9136 0 : return NS_ERROR_DOCSHELL_DYING;
9137 : }
9138 :
9139 : // Can we check the content type of the current content viewer
9140 : // and reuse it without destroying it and re-creating it?
9141 :
9142 4 : NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
9143 :
9144 : // Instantiate the content viewer object
9145 8 : nsCOMPtr<nsIContentViewer> viewer;
9146 4 : nsresult rv = NewContentViewerObj(aContentType, aRequest, mLoadGroup,
9147 8 : aContentHandler, getter_AddRefs(viewer));
9148 :
9149 4 : if (NS_FAILED(rv)) {
9150 0 : return rv;
9151 : }
9152 :
9153 : // Notify the current document that it is about to be unloaded!!
9154 : //
9155 : // It is important to fire the unload() notification *before* any state
9156 : // is changed within the DocShell - otherwise, javascript will get the
9157 : // wrong information :-(
9158 : //
9159 :
9160 4 : if (mSavingOldViewer) {
9161 : // We determined that it was safe to cache the document presentation
9162 : // at the time we initiated the new load. We need to check whether
9163 : // it's still safe to do so, since there may have been DOM mutations
9164 : // or new requests initiated.
9165 0 : nsCOMPtr<nsIDOMDocument> domDoc;
9166 0 : viewer->GetDOMDocument(getter_AddRefs(domDoc));
9167 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
9168 0 : mSavingOldViewer = CanSavePresentation(mLoadType, aRequest, doc);
9169 : }
9170 :
9171 4 : NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
9172 :
9173 8 : nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
9174 4 : if (aOpenedChannel) {
9175 4 : aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
9176 : }
9177 4 : FirePageHideNotification(!mSavingOldViewer);
9178 4 : mLoadingURI = nullptr;
9179 :
9180 : // Set mFiredUnloadEvent = false so that the unload handler for the
9181 : // *new* document will fire.
9182 4 : mFiredUnloadEvent = false;
9183 :
9184 : // we've created a new document so go ahead and call
9185 : // OnLoadingSite(), but don't fire OnLocationChange()
9186 : // notifications before we've called Embed(). See bug 284993.
9187 4 : mURIResultedInDocument = true;
9188 :
9189 4 : if (mLoadType == LOAD_ERROR_PAGE) {
9190 : // We need to set the SH entry and our current URI here and not
9191 : // at the moment we load the page. We want the same behavior
9192 : // of Stop() as for a normal page load. See bug 514232 for details.
9193 :
9194 : // Revert mLoadType to load type to state the page load failed,
9195 : // following function calls need it.
9196 0 : mLoadType = mFailedLoadType;
9197 :
9198 0 : nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
9199 :
9200 0 : nsIDocument* doc = viewer->GetDocument();
9201 0 : if (doc) {
9202 0 : doc->SetFailedChannel(failedChannel);
9203 : }
9204 :
9205 : // Make sure we have a URI to set currentURI.
9206 0 : nsCOMPtr<nsIURI> failedURI;
9207 0 : nsCOMPtr<nsIPrincipal> triggeringPrincipal;
9208 0 : if (failedChannel) {
9209 0 : NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
9210 : }
9211 : else {
9212 : // if there is no failed channel we have to explicitly provide
9213 : // a triggeringPrincipal for the history entry.
9214 0 : triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
9215 : }
9216 :
9217 0 : if (!failedURI) {
9218 0 : failedURI = mFailedURI;
9219 : }
9220 0 : if (!failedURI) {
9221 : // We need a URI object to store a session history entry, so make up a URI
9222 0 : NS_NewURI(getter_AddRefs(failedURI), "about:blank");
9223 : }
9224 :
9225 : // When we don't have failedURI, something wrong will happen. See
9226 : // bug 291876.
9227 0 : MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
9228 :
9229 0 : mFailedChannel = nullptr;
9230 0 : mFailedURI = nullptr;
9231 :
9232 : // Create an shistory entry for the old load.
9233 0 : if (failedURI) {
9234 0 : bool errorOnLocationChangeNeeded = OnNewURI(
9235 : failedURI, failedChannel, triggeringPrincipal,
9236 0 : nullptr, mLoadType, false, false, false);
9237 :
9238 0 : if (errorOnLocationChangeNeeded) {
9239 0 : FireOnLocationChange(this, failedChannel, failedURI,
9240 0 : LOCATION_CHANGE_ERROR_PAGE);
9241 : }
9242 : }
9243 :
9244 : // Be sure to have a correct mLSHE, it may have been cleared by
9245 : // EndPageLoad. See bug 302115.
9246 0 : if (mSessionHistory && !mLSHE) {
9247 : int32_t idx;
9248 0 : mSessionHistory->GetRequestedIndex(&idx);
9249 0 : if (idx == -1) {
9250 0 : mSessionHistory->GetIndex(&idx);
9251 : }
9252 0 : mSessionHistory->GetEntryAtIndex(idx, false, getter_AddRefs(mLSHE));
9253 : }
9254 :
9255 0 : mLoadType = LOAD_ERROR_PAGE;
9256 : }
9257 :
9258 4 : bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
9259 :
9260 : // let's try resetting the load group if we need to...
9261 8 : nsCOMPtr<nsILoadGroup> currentLoadGroup;
9262 4 : NS_ENSURE_SUCCESS(
9263 : aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)),
9264 : NS_ERROR_FAILURE);
9265 :
9266 4 : if (currentLoadGroup != mLoadGroup) {
9267 0 : nsLoadFlags loadFlags = 0;
9268 :
9269 : // Cancel any URIs that are currently loading...
9270 : // XXX: Need to do this eventually Stop();
9271 : //
9272 : // Retarget the document to this loadgroup...
9273 : //
9274 : /* First attach the channel to the right loadgroup
9275 : * and then remove from the old loadgroup. This
9276 : * puts the notifications in the right order and
9277 : * we don't null-out mLSHE in OnStateChange() for
9278 : * all redirected urls
9279 : */
9280 0 : aOpenedChannel->SetLoadGroup(mLoadGroup);
9281 :
9282 : // Mark the channel as being a document URI...
9283 0 : aOpenedChannel->GetLoadFlags(&loadFlags);
9284 0 : loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
9285 :
9286 0 : aOpenedChannel->SetLoadFlags(loadFlags);
9287 :
9288 0 : mLoadGroup->AddRequest(aRequest, nullptr);
9289 0 : if (currentLoadGroup) {
9290 0 : currentLoadGroup->RemoveRequest(aRequest, nullptr, NS_BINDING_RETARGETED);
9291 : }
9292 :
9293 : // Update the notification callbacks, so that progress and
9294 : // status information are sent to the right docshell...
9295 0 : aOpenedChannel->SetNotificationCallbacks(this);
9296 : }
9297 :
9298 4 : NS_ENSURE_SUCCESS(Embed(viewer, "", nullptr), NS_ERROR_FAILURE);
9299 :
9300 4 : mSavedRefreshURIList = nullptr;
9301 4 : mSavingOldViewer = false;
9302 4 : mEODForCurrentDocument = false;
9303 :
9304 : // if this document is part of a multipart document,
9305 : // the ID can be used to distinguish it from the other parts.
9306 8 : nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
9307 4 : if (multiPartChannel) {
9308 0 : nsCOMPtr<nsIPresShell> shell = GetPresShell();
9309 0 : if (NS_SUCCEEDED(rv) && shell) {
9310 0 : nsIDocument* doc = shell->GetDocument();
9311 0 : if (doc) {
9312 : uint32_t partID;
9313 0 : multiPartChannel->GetPartID(&partID);
9314 0 : doc->SetPartID(partID);
9315 : }
9316 : }
9317 : }
9318 :
9319 : // Give hint to native plevent dispatch mechanism. If a document
9320 : // is loading the native plevent dispatch mechanism should favor
9321 : // performance over normal native event dispatch priorities.
9322 4 : if (++gNumberOfDocumentsLoading == 1) {
9323 : // Hint to favor performance for the plevent notification mechanism.
9324 : // We want the pages to load as fast as possible even if its means
9325 : // native messages might be starved.
9326 2 : FavorPerformanceHint(true);
9327 : }
9328 :
9329 4 : if (onLocationChangeNeeded) {
9330 3 : FireOnLocationChange(this, aRequest, mCurrentURI, 0);
9331 : }
9332 :
9333 4 : return NS_OK;
9334 : }
9335 :
9336 : nsresult
9337 4 : nsDocShell::NewContentViewerObj(const nsACString& aContentType,
9338 : nsIRequest* aRequest, nsILoadGroup* aLoadGroup,
9339 : nsIStreamListener** aContentHandler,
9340 : nsIContentViewer** aViewer)
9341 : {
9342 8 : nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
9343 :
9344 : nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
9345 8 : nsContentUtils::FindInternalContentViewer(aContentType);
9346 4 : if (!docLoaderFactory) {
9347 0 : return NS_ERROR_FAILURE;
9348 : }
9349 :
9350 : // Now create an instance of the content viewer nsLayoutDLF makes the
9351 : // determination if it should be a "view-source" instead of "view"
9352 8 : nsresult rv = docLoaderFactory->CreateInstance("view",
9353 : aOpenedChannel,
9354 : aLoadGroup, aContentType,
9355 : this,
9356 : nullptr,
9357 : aContentHandler,
9358 8 : aViewer);
9359 4 : NS_ENSURE_SUCCESS(rv, rv);
9360 :
9361 4 : (*aViewer)->SetContainer(this);
9362 4 : return NS_OK;
9363 : }
9364 :
9365 : nsresult
9366 8 : nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer)
9367 : {
9368 : //
9369 : // Copy content viewer state from previous or parent content viewer.
9370 : //
9371 : // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
9372 : //
9373 : // Do NOT to maintain a reference to the old content viewer outside
9374 : // of this "copying" block, or it will not be destroyed until the end of
9375 : // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
9376 : //
9377 : // In this block of code, if we get an error result, we return it
9378 : // but if we get a null pointer, that's perfectly legal for parent
9379 : // and parentContentViewer.
9380 : //
9381 :
9382 8 : int32_t x = 0;
9383 8 : int32_t y = 0;
9384 8 : int32_t cx = 0;
9385 8 : int32_t cy = 0;
9386 :
9387 : // This will get the size from the current content viewer or from the
9388 : // Init settings
9389 8 : DoGetPositionAndSize(&x, &y, &cx, &cy);
9390 :
9391 16 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
9392 8 : NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
9393 : NS_ERROR_FAILURE);
9394 16 : nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
9395 :
9396 8 : const Encoding* forceCharset = nullptr;
9397 8 : const Encoding* hintCharset = nullptr;
9398 : int32_t hintCharsetSource;
9399 : int32_t minFontSize;
9400 : float textZoom;
9401 : float pageZoom;
9402 : float overrideDPPX;
9403 : bool styleDisabled;
9404 : // |newMUDV| also serves as a flag to set the data from the above vars
9405 16 : nsCOMPtr<nsIContentViewer> newCv;
9406 :
9407 8 : if (mContentViewer || parent) {
9408 8 : nsCOMPtr<nsIContentViewer> oldCv;
9409 4 : if (mContentViewer) {
9410 : // Get any interesting state from old content viewer
9411 : // XXX: it would be far better to just reuse the document viewer ,
9412 : // since we know we're just displaying the same document as before
9413 3 : oldCv = mContentViewer;
9414 :
9415 : // Tell the old content viewer to hibernate in session history when
9416 : // it is destroyed.
9417 :
9418 3 : if (mSavingOldViewer && NS_FAILED(CaptureState())) {
9419 0 : if (mOSHE) {
9420 0 : mOSHE->SyncPresentationState();
9421 : }
9422 0 : mSavingOldViewer = false;
9423 : }
9424 : } else {
9425 : // No old content viewer, so get state from parent's content viewer
9426 1 : parent->GetContentViewer(getter_AddRefs(oldCv));
9427 : }
9428 :
9429 4 : if (oldCv) {
9430 4 : newCv = aNewViewer;
9431 4 : if (newCv) {
9432 4 : forceCharset = oldCv->GetForceCharset();
9433 4 : hintCharset = oldCv->GetHintCharset();
9434 4 : NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSetSource(&hintCharsetSource),
9435 : NS_ERROR_FAILURE);
9436 4 : NS_ENSURE_SUCCESS(oldCv->GetMinFontSize(&minFontSize),
9437 : NS_ERROR_FAILURE);
9438 4 : NS_ENSURE_SUCCESS(oldCv->GetTextZoom(&textZoom),
9439 : NS_ERROR_FAILURE);
9440 4 : NS_ENSURE_SUCCESS(oldCv->GetFullZoom(&pageZoom),
9441 : NS_ERROR_FAILURE);
9442 4 : NS_ENSURE_SUCCESS(oldCv->GetOverrideDPPX(&overrideDPPX),
9443 : NS_ERROR_FAILURE);
9444 4 : NS_ENSURE_SUCCESS(oldCv->GetAuthorStyleDisabled(&styleDisabled),
9445 : NS_ERROR_FAILURE);
9446 : }
9447 : }
9448 : }
9449 :
9450 8 : nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
9451 : // Ensure that the content viewer is destroyed *after* the GC - bug 71515
9452 16 : nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer;
9453 8 : if (contentViewer) {
9454 : // Stop any activity that may be happening in the old document before
9455 : // releasing it...
9456 3 : contentViewer->Stop();
9457 :
9458 : // Try to extract the canvas background color from the old
9459 : // presentation shell, so we can use it for the next document.
9460 6 : nsCOMPtr<nsIPresShell> shell;
9461 3 : contentViewer->GetPresShell(getter_AddRefs(shell));
9462 :
9463 3 : if (shell) {
9464 3 : bgcolor = shell->GetCanvasBackground();
9465 : }
9466 :
9467 3 : contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
9468 3 : aNewViewer->SetPreviousViewer(contentViewer);
9469 : }
9470 8 : if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
9471 : // We don't plan to save a viewer in mOSHE; tell it to drop
9472 : // any other state it's holding.
9473 0 : mOSHE->SyncPresentationState();
9474 : }
9475 :
9476 8 : mContentViewer = nullptr;
9477 :
9478 : // Now that we're about to switch documents, forget all of our children.
9479 : // Note that we cached them as needed up in CaptureState above.
9480 8 : DestroyChildren();
9481 :
9482 8 : mContentViewer = aNewViewer;
9483 :
9484 16 : nsCOMPtr<nsIWidget> widget;
9485 8 : NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
9486 :
9487 8 : nsIntRect bounds(x, y, cx, cy);
9488 :
9489 8 : mContentViewer->SetNavigationTiming(mTiming);
9490 :
9491 8 : if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
9492 0 : mContentViewer = nullptr;
9493 0 : NS_WARNING("ContentViewer Initialization failed");
9494 0 : return NS_ERROR_FAILURE;
9495 : }
9496 :
9497 : // If we have old state to copy, set the old state onto the new content
9498 : // viewer
9499 8 : if (newCv) {
9500 4 : newCv->SetForceCharset(forceCharset);
9501 4 : newCv->SetHintCharset(hintCharset);
9502 4 : NS_ENSURE_SUCCESS(newCv->SetHintCharacterSetSource(hintCharsetSource),
9503 : NS_ERROR_FAILURE);
9504 4 : NS_ENSURE_SUCCESS(newCv->SetMinFontSize(minFontSize),
9505 : NS_ERROR_FAILURE);
9506 4 : NS_ENSURE_SUCCESS(newCv->SetTextZoom(textZoom),
9507 : NS_ERROR_FAILURE);
9508 4 : NS_ENSURE_SUCCESS(newCv->SetFullZoom(pageZoom),
9509 : NS_ERROR_FAILURE);
9510 4 : NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX),
9511 : NS_ERROR_FAILURE);
9512 4 : NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled),
9513 : NS_ERROR_FAILURE);
9514 : }
9515 :
9516 : // Stuff the bgcolor from the old pres shell into the new
9517 : // pres shell. This improves page load continuity.
9518 16 : nsCOMPtr<nsIPresShell> shell;
9519 8 : mContentViewer->GetPresShell(getter_AddRefs(shell));
9520 :
9521 8 : if (shell) {
9522 7 : shell->SetCanvasBackground(bgcolor);
9523 : }
9524 :
9525 : // XXX: It looks like the LayoutState gets restored again in Embed()
9526 : // right after the call to SetupNewViewer(...)
9527 :
9528 : // We don't show the mContentViewer yet, since we want to draw the old page
9529 : // until we have enough of the new page to show. Just return with the new
9530 : // viewer still set to hidden.
9531 :
9532 8 : return NS_OK;
9533 : }
9534 :
9535 : nsresult
9536 1 : nsDocShell::SetDocCurrentStateObj(nsISHEntry* aShEntry)
9537 : {
9538 1 : NS_ENSURE_STATE(mContentViewer);
9539 2 : nsCOMPtr<nsIDocument> document = GetDocument();
9540 1 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
9541 :
9542 2 : nsCOMPtr<nsIStructuredCloneContainer> scContainer;
9543 1 : if (aShEntry) {
9544 1 : nsresult rv = aShEntry->GetStateData(getter_AddRefs(scContainer));
9545 1 : NS_ENSURE_SUCCESS(rv, rv);
9546 :
9547 : // If aShEntry is null, just set the document's state object to null.
9548 : }
9549 :
9550 : // It's OK for scContainer too be null here; that just means there's no
9551 : // state data associated with this history entry.
9552 1 : document->SetStateObject(scContainer);
9553 :
9554 1 : return NS_OK;
9555 : }
9556 :
9557 : nsresult
9558 6 : nsDocShell::CheckLoadingPermissions()
9559 : {
9560 : // This method checks whether the caller may load content into
9561 : // this docshell. Even though we've done our best to hide windows
9562 : // from code that doesn't have the right to access them, it's
9563 : // still possible for an evil site to open a window and access
9564 : // frames in the new window through window.frames[] (which is
9565 : // allAccess for historic reasons), so we still need to do this
9566 : // check on load.
9567 6 : nsresult rv = NS_OK;
9568 :
9569 6 : if (!gValidateOrigin || !IsFrame()) {
9570 : // Origin validation was turned off, or we're not a frame.
9571 : // Permit all loads.
9572 :
9573 5 : return rv;
9574 : }
9575 :
9576 : // Note - The check for a current JSContext here isn't necessarily sensical.
9577 : // It's just designed to preserve the old semantics during a mass-conversion
9578 : // patch.
9579 1 : if (!nsContentUtils::GetCurrentJSContext()) {
9580 1 : return NS_OK;
9581 : }
9582 :
9583 : // Check if the caller is from the same origin as this docshell,
9584 : // or any of its ancestors.
9585 0 : nsCOMPtr<nsIDocShellTreeItem> item(this);
9586 0 : do {
9587 0 : nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(item);
9588 0 : nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
9589 :
9590 : nsIPrincipal* p;
9591 0 : if (!sop || !(p = sop->GetPrincipal())) {
9592 0 : return NS_ERROR_UNEXPECTED;
9593 : }
9594 :
9595 0 : if (nsContentUtils::SubjectPrincipal()->Subsumes(p)) {
9596 : // Same origin, permit load
9597 0 : return NS_OK;
9598 : }
9599 :
9600 0 : nsCOMPtr<nsIDocShellTreeItem> tmp;
9601 0 : item->GetSameTypeParent(getter_AddRefs(tmp));
9602 0 : item.swap(tmp);
9603 : } while (item);
9604 :
9605 0 : return NS_ERROR_DOM_PROP_ACCESS_DENIED;
9606 : }
9607 :
9608 : //*****************************************************************************
9609 : // nsDocShell: Site Loading
9610 : //*****************************************************************************
9611 :
9612 : void
9613 0 : nsDocShell::CopyFavicon(nsIURI* aOldURI,
9614 : nsIURI* aNewURI,
9615 : nsIPrincipal* aLoadingPrincipal,
9616 : bool aInPrivateBrowsing)
9617 : {
9618 0 : if (XRE_IsContentProcess()) {
9619 0 : dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
9620 0 : if (contentChild) {
9621 0 : mozilla::ipc::URIParams oldURI, newURI;
9622 0 : SerializeURI(aOldURI, oldURI);
9623 0 : SerializeURI(aNewURI, newURI);
9624 0 : contentChild->SendCopyFavicon(oldURI, newURI,
9625 0 : IPC::Principal(aLoadingPrincipal),
9626 0 : aInPrivateBrowsing);
9627 : }
9628 0 : return;
9629 : }
9630 :
9631 : #ifdef MOZ_PLACES
9632 : nsCOMPtr<mozIAsyncFavicons> favSvc =
9633 0 : do_GetService("@mozilla.org/browser/favicon-service;1");
9634 0 : if (favSvc) {
9635 0 : favSvc->CopyFavicons(aOldURI, aNewURI,
9636 : aInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE
9637 0 : : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, nullptr);
9638 : }
9639 : #endif
9640 : }
9641 :
9642 0 : class InternalLoadEvent : public Runnable
9643 : {
9644 : public:
9645 0 : InternalLoadEvent(nsDocShell* aDocShell,
9646 : nsIURI* aURI,
9647 : nsIURI* aOriginalURI,
9648 : Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
9649 : bool aLoadReplace,
9650 : nsIURI* aReferrer, uint32_t aReferrerPolicy,
9651 : nsIPrincipal* aTriggeringPrincipal,
9652 : nsIPrincipal* aPrincipalToInherit,
9653 : uint32_t aFlags,
9654 : const char* aTypeHint,
9655 : nsIInputStream* aPostData,
9656 : nsIInputStream* aHeadersData,
9657 : uint32_t aLoadType,
9658 : nsISHEntry* aSHEntry,
9659 : bool aFirstParty,
9660 : const nsAString& aSrcdoc,
9661 : nsIDocShell* aSourceDocShell,
9662 : nsIURI* aBaseURI,
9663 : bool aCheckForPrerender)
9664 0 : : mozilla::Runnable("InternalLoadEvent")
9665 : , mSrcdoc(aSrcdoc)
9666 : , mDocShell(aDocShell)
9667 : , mURI(aURI)
9668 : , mOriginalURI(aOriginalURI)
9669 : , mResultPrincipalURI(aResultPrincipalURI)
9670 : , mLoadReplace(aLoadReplace)
9671 : , mReferrer(aReferrer)
9672 : , mReferrerPolicy(aReferrerPolicy)
9673 : , mTriggeringPrincipal(aTriggeringPrincipal)
9674 : , mPrincipalToInherit(aPrincipalToInherit)
9675 : , mPostData(aPostData)
9676 : , mHeadersData(aHeadersData)
9677 : , mSHEntry(aSHEntry)
9678 : , mFlags(aFlags)
9679 : , mLoadType(aLoadType)
9680 : , mFirstParty(aFirstParty)
9681 : , mSourceDocShell(aSourceDocShell)
9682 : , mBaseURI(aBaseURI)
9683 0 : , mCheckForPrerender(aCheckForPrerender)
9684 : {
9685 : // Make sure to keep null things null as needed
9686 0 : if (aTypeHint) {
9687 0 : mTypeHint = aTypeHint;
9688 : }
9689 0 : }
9690 :
9691 : NS_IMETHOD
9692 0 : Run() override
9693 : {
9694 0 : return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI,
9695 0 : mLoadReplace,
9696 : mReferrer,
9697 : mReferrerPolicy,
9698 : mTriggeringPrincipal, mPrincipalToInherit,
9699 0 : mFlags, EmptyString(), mTypeHint.get(),
9700 0 : NullString(), mPostData, mHeadersData,
9701 0 : mLoadType, mSHEntry, mFirstParty,
9702 : mSrcdoc, mSourceDocShell, mBaseURI,
9703 0 : mCheckForPrerender, nullptr, nullptr);
9704 : }
9705 :
9706 : private:
9707 : // Use IDL strings so .get() returns null by default
9708 : nsXPIDLString mWindowTarget;
9709 : nsXPIDLCString mTypeHint;
9710 : nsString mSrcdoc;
9711 :
9712 : RefPtr<nsDocShell> mDocShell;
9713 : nsCOMPtr<nsIURI> mURI;
9714 : nsCOMPtr<nsIURI> mOriginalURI;
9715 : Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
9716 : bool mLoadReplace;
9717 : nsCOMPtr<nsIURI> mReferrer;
9718 : uint32_t mReferrerPolicy;
9719 : nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
9720 : nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
9721 : nsCOMPtr<nsIInputStream> mPostData;
9722 : nsCOMPtr<nsIInputStream> mHeadersData;
9723 : nsCOMPtr<nsISHEntry> mSHEntry;
9724 : uint32_t mFlags;
9725 : uint32_t mLoadType;
9726 : bool mFirstParty;
9727 : nsCOMPtr<nsIDocShell> mSourceDocShell;
9728 : nsCOMPtr<nsIURI> mBaseURI;
9729 : bool mCheckForPrerender;
9730 : };
9731 :
9732 : /**
9733 : * Returns true if we started an asynchronous load (i.e., from the network), but
9734 : * the document we're loading there hasn't yet become this docshell's active
9735 : * document.
9736 : *
9737 : * When JustStartedNetworkLoad is true, you should be careful about modifying
9738 : * mLoadType and mLSHE. These are both set when the asynchronous load first
9739 : * starts, and the load expects that, when it eventually runs InternalLoad,
9740 : * mLoadType and mLSHE will have their original values.
9741 : */
9742 : bool
9743 0 : nsDocShell::JustStartedNetworkLoad()
9744 : {
9745 0 : return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
9746 : }
9747 :
9748 : nsresult
9749 0 : nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
9750 : nsIPrincipal** aResult)
9751 : {
9752 : nsCOMPtr<nsIPrincipal> prin =
9753 0 : BasePrincipal::CreateCodebasePrincipal(aReferrer, mOriginAttributes);
9754 0 : prin.forget(aResult);
9755 :
9756 0 : return *aResult ? NS_OK : NS_ERROR_FAILURE;
9757 : }
9758 :
9759 : NS_IMETHODIMP
9760 6 : nsDocShell::InternalLoad(nsIURI* aURI,
9761 : nsIURI* aOriginalURI,
9762 : Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
9763 : bool aLoadReplace,
9764 : nsIURI* aReferrer,
9765 : uint32_t aReferrerPolicy,
9766 : nsIPrincipal* aTriggeringPrincipal,
9767 : nsIPrincipal* aPrincipalToInherit,
9768 : uint32_t aFlags,
9769 : const nsAString& aWindowTarget,
9770 : const char* aTypeHint,
9771 : const nsAString& aFileName,
9772 : nsIInputStream* aPostData,
9773 : nsIInputStream* aHeadersData,
9774 : uint32_t aLoadType,
9775 : nsISHEntry* aSHEntry,
9776 : bool aFirstParty,
9777 : const nsAString& aSrcdoc,
9778 : nsIDocShell* aSourceDocShell,
9779 : nsIURI* aBaseURI,
9780 : bool aCheckForPrerender,
9781 : nsIDocShell** aDocShell,
9782 : nsIRequest** aRequest)
9783 : {
9784 6 : MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal");
9785 :
9786 6 : nsresult rv = NS_OK;
9787 6 : mOriginalUriString.Truncate();
9788 :
9789 6 : MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
9790 : ("DOCSHELL %p InternalLoad %s\n",
9791 : this, aURI ? aURI->GetSpecOrDefault().get() : ""));
9792 : // Initialize aDocShell/aRequest
9793 6 : if (aDocShell) {
9794 0 : *aDocShell = nullptr;
9795 : }
9796 6 : if (aRequest) {
9797 0 : *aRequest = nullptr;
9798 : }
9799 :
9800 6 : if (!aURI) {
9801 0 : return NS_ERROR_NULL_POINTER;
9802 : }
9803 :
9804 6 : NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
9805 :
9806 6 : NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
9807 :
9808 6 : rv = EnsureScriptEnvironment();
9809 6 : if (NS_FAILED(rv)) {
9810 0 : return rv;
9811 : }
9812 :
9813 : // wyciwyg urls can only be loaded through history. Any normal load of
9814 : // wyciwyg through docshell is illegal. Disallow such loads.
9815 6 : if (aLoadType & LOAD_CMD_NORMAL) {
9816 6 : bool isWyciwyg = false;
9817 6 : rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
9818 6 : if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) {
9819 0 : return NS_ERROR_FAILURE;
9820 : }
9821 : }
9822 :
9823 6 : bool isJavaScript = false;
9824 6 : if (NS_FAILED(aURI->SchemeIs("javascript", &isJavaScript))) {
9825 0 : isJavaScript = false;
9826 : }
9827 :
9828 6 : bool isTargetTopLevelDocShell = false;
9829 12 : nsCOMPtr<nsIDocShell> targetDocShell;
9830 6 : if (!aWindowTarget.IsEmpty()) {
9831 : // Locate the target DocShell.
9832 0 : nsCOMPtr<nsIDocShellTreeItem> targetItem;
9833 : // Only _self, _parent, and _top are supported in noopener case. But we
9834 : // have to be careful to not apply that to the noreferrer case. See bug
9835 : // 1358469.
9836 0 : bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
9837 0 : (aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
9838 0 : if (allowNamedTarget ||
9839 0 : aWindowTarget.LowerCaseEqualsLiteral("_self") ||
9840 0 : aWindowTarget.LowerCaseEqualsLiteral("_parent") ||
9841 0 : aWindowTarget.LowerCaseEqualsLiteral("_top")) {
9842 0 : rv = FindItemWithName(aWindowTarget, nullptr, this, false,
9843 0 : getter_AddRefs(targetItem));
9844 0 : NS_ENSURE_SUCCESS(rv, rv);
9845 : }
9846 :
9847 0 : targetDocShell = do_QueryInterface(targetItem);
9848 0 : if (targetDocShell) {
9849 : // If the targetDocShell and the rootDocShell are the same, then the
9850 : // targetDocShell is the top level document and hence we should
9851 : // consider this TYPE_DOCUMENT
9852 : //
9853 : // For example:
9854 : // 1. target="_top"
9855 : // 2. target="_parent", where this docshell is in the 2nd level of
9856 : // docshell tree.
9857 0 : nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
9858 0 : targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
9859 0 : NS_ASSERTION(sameTypeRoot,
9860 : "No document shell root tree item from targetDocShell!");
9861 0 : nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
9862 0 : NS_ASSERTION(rootShell,
9863 : "No root docshell from document shell root tree item.");
9864 0 : isTargetTopLevelDocShell = targetDocShell == rootShell;
9865 : } else {
9866 : // If the targetDocShell doesn't exist, then this is a new docShell
9867 : // and we should consider this a TYPE_DOCUMENT load
9868 : //
9869 : // For example, when target="_blank"
9870 0 : isTargetTopLevelDocShell = true;
9871 : }
9872 : }
9873 :
9874 : // The contentType will be INTERNAL_(I)FRAME if:
9875 : // 1. This docshell is for iframe.
9876 : // 2. AND aWindowTarget is not a new window, nor a top-level window.
9877 : //
9878 : // This variable will be used when we call NS_CheckContentLoadPolicy, and
9879 : // later when we call DoURILoad.
9880 : uint32_t contentType;
9881 6 : if (IsFrame() && !isTargetTopLevelDocShell) {
9882 : nsCOMPtr<Element> requestingElement =
9883 2 : mScriptGlobal->AsOuter()->GetFrameElementInternal();
9884 1 : if (requestingElement) {
9885 1 : contentType = requestingElement->IsHTMLElement(nsGkAtoms::iframe) ?
9886 : nsIContentPolicy::TYPE_INTERNAL_IFRAME : nsIContentPolicy::TYPE_INTERNAL_FRAME;
9887 : } else {
9888 : // If we have lost our frame element by now, just assume we're
9889 : // an iframe since that's more common.
9890 0 : contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME;
9891 : }
9892 : } else {
9893 5 : contentType = nsIContentPolicy::TYPE_DOCUMENT;
9894 5 : isTargetTopLevelDocShell = true;
9895 : }
9896 :
9897 : // If there's no targetDocShell, that means we are about to create a new window,
9898 : // perform a content policy check before creating the window.
9899 6 : if (!targetDocShell) {
9900 12 : nsCOMPtr<Element> requestingElement;
9901 6 : nsISupports* requestingContext = nullptr;
9902 :
9903 6 : if (contentType == nsIContentPolicy::TYPE_DOCUMENT) {
9904 5 : if (XRE_IsContentProcess()) {
9905 : // In e10s the child process doesn't have access to the element that
9906 : // contains the browsing context (because that element is in the chrome
9907 : // process). So we just pass mScriptGlobal.
9908 2 : requestingContext = ToSupports(mScriptGlobal);
9909 : } else {
9910 : // This is for loading non-e10s tabs and toplevel windows of various
9911 : // sorts.
9912 : // For the toplevel window cases, requestingElement will be null.
9913 3 : requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal();
9914 3 : requestingContext = requestingElement;
9915 : }
9916 : } else {
9917 1 : requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal();
9918 1 : requestingContext = requestingElement;
9919 :
9920 : #ifdef DEBUG
9921 1 : if (requestingElement) {
9922 : // Get the docshell type for requestingElement.
9923 2 : nsCOMPtr<nsIDocument> requestingDoc = requestingElement->OwnerDoc();
9924 2 : nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
9925 :
9926 : // requestingElement docshell type = current docshell type.
9927 1 : MOZ_ASSERT(mItemType == elementDocShell->ItemType(),
9928 : "subframes should have the same docshell type as their parent");
9929 : }
9930 : #endif
9931 : }
9932 :
9933 : // Since Content Policy checks are performed within docShell as well as
9934 : // the ContentSecurityManager we need a reliable way to let certain
9935 : // nsIContentPolicy consumers ignore duplicate calls. Let's use the 'extra'
9936 : // argument to pass a specific identifier.
9937 : nsCOMPtr<nsISupportsString> extraStr =
9938 12 : do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
9939 6 : NS_ENSURE_SUCCESS(rv, rv);
9940 6 : NS_NAMED_LITERAL_STRING(msg, "conPolCheckFromDocShell");
9941 6 : rv = extraStr->SetData(msg);
9942 6 : NS_ENSURE_SUCCESS(rv, rv);
9943 :
9944 6 : int16_t shouldLoad = nsIContentPolicy::ACCEPT;
9945 6 : rv = NS_CheckContentLoadPolicy(contentType,
9946 : aURI,
9947 : aTriggeringPrincipal,
9948 : requestingContext,
9949 6 : EmptyCString(), // mime guess
9950 : extraStr, // extra
9951 6 : &shouldLoad);
9952 :
9953 6 : if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
9954 0 : if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
9955 0 : return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
9956 : }
9957 :
9958 0 : return NS_ERROR_CONTENT_BLOCKED;
9959 : }
9960 :
9961 : // If HSTS priming was set by nsMixedContentBlocker::ShouldLoad, and we
9962 : // would block due to mixed content, go ahead and block here. If we try to
9963 : // proceed with priming, we will error out later on.
9964 12 : nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(requestingContext);
9965 : // When loading toplevel windows, requestingContext can be null. We don't
9966 : // really care about HSTS in that situation, though; loads in toplevel
9967 : // windows should all be browser UI.
9968 6 : if (docShell) {
9969 4 : nsIDocument* document = docShell->GetDocument();
9970 4 : NS_ENSURE_TRUE(document, NS_OK);
9971 :
9972 4 : HSTSPrimingState state = document->GetHSTSPrimingStateForLocation(aURI);
9973 4 : if (state == HSTSPrimingState::eHSTS_PRIMING_BLOCK) {
9974 : // HSTS Priming currently disabled for InternalLoad, so we need to clear
9975 : // the location that was added by nsMixedContentBlocker::ShouldLoad
9976 : // Bug 1269815 will address images loaded via InternalLoad
9977 0 : document->ClearHSTSPrimingLocation(aURI);
9978 0 : return NS_ERROR_CONTENT_BLOCKED;
9979 : }
9980 : }
9981 : }
9982 :
9983 12 : nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
9984 : //
9985 : // Get a principal from the current document if necessary. Note that we only
9986 : // do this for URIs that inherit a security context and local file URIs;
9987 : // in particular we do NOT do this for about:blank. This way, random
9988 : // about:blank loads that have no principal (which basically means they were
9989 : // done by someone from chrome manually messing with our nsIWebNavigation
9990 : // or by C++ setting document.location) don't get a funky principal. If
9991 : // callers want something interesting to happen with the about:blank
9992 : // principal in this case, they should pass aPrincipalToInherit in.
9993 : //
9994 : {
9995 : bool inherits;
9996 : // One more twist: Don't inherit the principal for external loads.
9997 14 : if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit &&
9998 4 : (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&
9999 2 : NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
10000 8 : &inherits)) &&
10001 : inherits) {
10002 0 : principalToInherit = GetInheritedPrincipal(true);
10003 : }
10004 : }
10005 :
10006 : // Don't allow loads that would inherit our security context
10007 : // if this document came from an unsafe channel.
10008 : {
10009 : bool willInherit;
10010 : // This condition needs to match the one in
10011 : // nsContentUtils::ChannelShouldInheritPrincipal.
10012 : // Except we reverse the rv check to be safe in case
10013 : // nsContentUtils::URIInheritsSecurityContext fails here and
10014 : // succeeds there.
10015 6 : rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
10016 6 : if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
10017 6 : nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
10018 4 : do {
10019 8 : nsCOMPtr<nsIDocShell> itemDocShell = do_QueryInterface(treeItem);
10020 : bool isUnsafe;
10021 8 : if (itemDocShell &&
10022 8 : NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
10023 : isUnsafe) {
10024 0 : return NS_ERROR_DOM_SECURITY_ERR;
10025 : }
10026 :
10027 8 : nsCOMPtr<nsIDocShellTreeItem> parent;
10028 4 : treeItem->GetSameTypeParent(getter_AddRefs(parent));
10029 4 : parent.swap(treeItem);
10030 : } while (treeItem);
10031 : }
10032 : }
10033 :
10034 : //
10035 : // Resolve the window target before going any further...
10036 : // If the load has been targeted to another DocShell, then transfer the
10037 : // load to it...
10038 : //
10039 6 : if (!aWindowTarget.IsEmpty()) {
10040 : // We've already done our owner-inheriting. Mask out that bit, so we
10041 : // don't try inheriting an owner from the target window if we came up
10042 : // with a null owner above.
10043 0 : aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
10044 :
10045 0 : bool isNewWindow = false;
10046 0 : if (!targetDocShell) {
10047 : // If the docshell's document is sandboxed, only open a new window
10048 : // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
10049 : // (i.e. if allow-popups is specified)
10050 0 : NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
10051 0 : nsIDocument* doc = mContentViewer->GetDocument();
10052 0 : uint32_t sandboxFlags = 0;
10053 :
10054 0 : if (doc) {
10055 0 : sandboxFlags = doc->GetSandboxFlags();
10056 0 : if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
10057 0 : return NS_ERROR_DOM_INVALID_ACCESS_ERR;
10058 : }
10059 : }
10060 :
10061 0 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
10062 0 : NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
10063 :
10064 0 : nsCOMPtr<nsPIDOMWindowOuter> newWin;
10065 0 : nsAutoCString spec;
10066 0 : if (aURI) {
10067 0 : aURI->GetSpec(spec);
10068 : }
10069 : // If we are a noopener load, we just hand the whole thing over to our
10070 : // window.
10071 0 : if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
10072 : // Various asserts that we know to hold because NO_OPENER loads can only
10073 : // happen for links.
10074 0 : MOZ_ASSERT(!aLoadReplace);
10075 0 : MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal);
10076 0 : MOZ_ASSERT(aFlags == INTERNAL_LOAD_FLAGS_NO_OPENER ||
10077 : aFlags == (INTERNAL_LOAD_FLAGS_NO_OPENER |
10078 : INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
10079 0 : MOZ_ASSERT(!aPostData);
10080 0 : MOZ_ASSERT(!aHeadersData);
10081 0 : MOZ_ASSERT(aLoadType == LOAD_LINK);
10082 0 : MOZ_ASSERT(!aSHEntry);
10083 0 : MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
10084 :
10085 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
10086 0 : rv = CreateLoadInfo(getter_AddRefs(loadInfo));
10087 0 : if (NS_FAILED(rv)) {
10088 0 : return rv;
10089 : }
10090 :
10091 : // Set up our loadinfo so it will do the load as much like we would have
10092 : // as possible.
10093 0 : loadInfo->SetReferrer(aReferrer);
10094 0 : loadInfo->SetReferrerPolicy(aReferrerPolicy);
10095 0 : loadInfo->SetSendReferrer(!(aFlags &
10096 0 : INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
10097 0 : loadInfo->SetOriginalURI(aOriginalURI);
10098 0 : SetMaybeResultPrincipalURI(loadInfo, aResultPrincipalURI);
10099 0 : loadInfo->SetLoadReplace(aLoadReplace);
10100 0 : loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
10101 0 : loadInfo->SetInheritPrincipal(
10102 0 : aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
10103 : // Explicit principal because we do not want any guesses as to what the
10104 : // principal to inherit is: it should be aTriggeringPrincipal.
10105 0 : loadInfo->SetPrincipalIsExplicit(true);
10106 0 : loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK));
10107 :
10108 0 : rv = win->Open(NS_ConvertUTF8toUTF16(spec),
10109 : aWindowTarget, // window name
10110 0 : EmptyString(), // Features
10111 : loadInfo,
10112 : true, // aForceNoOpener
10113 0 : getter_AddRefs(newWin));
10114 0 : MOZ_ASSERT(!newWin);
10115 0 : return rv;
10116 : }
10117 :
10118 0 : rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
10119 : aWindowTarget, // window name
10120 0 : EmptyString(), // Features
10121 0 : getter_AddRefs(newWin));
10122 :
10123 : // In some cases the Open call doesn't actually result in a new
10124 : // window being opened. We can detect these cases by examining the
10125 : // document in |newWin|, if any.
10126 0 : nsCOMPtr<nsPIDOMWindowOuter> piNewWin = do_QueryInterface(newWin);
10127 0 : if (piNewWin) {
10128 0 : nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
10129 0 : if (!newDoc || newDoc->IsInitialDocument()) {
10130 0 : isNewWindow = true;
10131 0 : aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
10132 : }
10133 : }
10134 :
10135 0 : nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
10136 0 : targetDocShell = do_QueryInterface(webNav);
10137 : }
10138 :
10139 : //
10140 : // Transfer the load to the target DocShell... Pass nullptr as the
10141 : // window target name from to prevent recursive retargeting!
10142 : //
10143 0 : if (NS_SUCCEEDED(rv) && targetDocShell) {
10144 0 : rv = targetDocShell->InternalLoad(aURI,
10145 : aOriginalURI,
10146 : aResultPrincipalURI,
10147 : aLoadReplace,
10148 : aReferrer,
10149 : aReferrerPolicy,
10150 : aTriggeringPrincipal,
10151 : principalToInherit,
10152 : aFlags,
10153 0 : EmptyString(), // No window target
10154 : aTypeHint,
10155 0 : NullString(), // No forced download
10156 : aPostData,
10157 : aHeadersData,
10158 : aLoadType,
10159 : aSHEntry,
10160 : aFirstParty,
10161 : aSrcdoc,
10162 : aSourceDocShell,
10163 : aBaseURI,
10164 : aCheckForPrerender,
10165 : aDocShell,
10166 0 : aRequest);
10167 0 : if (rv == NS_ERROR_NO_CONTENT) {
10168 : // XXXbz except we never reach this code!
10169 0 : if (isNewWindow) {
10170 : //
10171 : // At this point, a new window has been created, but the
10172 : // URI did not have any data associated with it...
10173 : //
10174 : // So, the best we can do, is to tear down the new window
10175 : // that was just created!
10176 : //
10177 0 : if (nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow()) {
10178 0 : domWin->Close();
10179 : }
10180 : }
10181 : //
10182 : // NS_ERROR_NO_CONTENT should not be returned to the
10183 : // caller... This is an internal error code indicating that
10184 : // the URI had no data associated with it - probably a
10185 : // helper-app style protocol (ie. mailto://)
10186 : //
10187 0 : rv = NS_OK;
10188 : } else if (isNewWindow) {
10189 : // XXX: Once new windows are created hidden, the new
10190 : // window will need to be made visible... For now,
10191 : // do nothing.
10192 : }
10193 :
10194 0 : if (NS_SUCCEEDED(rv)) {
10195 : // Switch to target tab if we're currently focused window.
10196 : // Take loadDivertedInBackground into account so the behavior would be
10197 : // the same as how the tab first opened.
10198 0 : bool isTargetActive = false;
10199 0 : targetDocShell->GetIsActive(&isTargetActive);
10200 0 : nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow();
10201 0 : if (mIsActive && !isTargetActive && domWin &&
10202 0 : !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false)) {
10203 0 : if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin))) {
10204 0 : return NS_ERROR_FAILURE;
10205 : }
10206 : }
10207 : }
10208 : }
10209 :
10210 : // Else we ran out of memory, or were a popup and got blocked,
10211 : // or something.
10212 :
10213 0 : return rv;
10214 : }
10215 :
10216 : //
10217 : // Load is being targetted at this docshell so return an error if the
10218 : // docshell is in the process of being destroyed.
10219 : //
10220 6 : if (mIsBeingDestroyed) {
10221 0 : return NS_ERROR_FAILURE;
10222 : }
10223 :
10224 6 : NS_ENSURE_STATE(!HasUnloadedParent());
10225 :
10226 6 : rv = CheckLoadingPermissions();
10227 6 : if (NS_FAILED(rv)) {
10228 0 : return rv;
10229 : }
10230 :
10231 6 : if (mFiredUnloadEvent) {
10232 0 : if (IsOKToLoadURI(aURI)) {
10233 0 : NS_PRECONDITION(aWindowTarget.IsEmpty(),
10234 : "Shouldn't have a window target here!");
10235 :
10236 : // If this is a replace load, make whatever load triggered
10237 : // the unload event also a replace load, so we don't
10238 : // create extra history entries.
10239 0 : if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
10240 0 : mLoadType = LOAD_NORMAL_REPLACE;
10241 : }
10242 :
10243 : // Do this asynchronously
10244 : nsCOMPtr<nsIRunnable> ev =
10245 : new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI,
10246 : aLoadReplace, aReferrer, aReferrerPolicy,
10247 : aTriggeringPrincipal, principalToInherit,
10248 : aFlags, aTypeHint, aPostData, aHeadersData,
10249 : aLoadType, aSHEntry, aFirstParty, aSrcdoc,
10250 0 : aSourceDocShell, aBaseURI, false);
10251 : return DispatchToTabGroup("nsDocShell::InternalLoadEvent",
10252 0 : TaskCategory::Other, ev.forget());
10253 : }
10254 :
10255 : // Just ignore this load attempt
10256 0 : return NS_OK;
10257 : }
10258 :
10259 : // If a source docshell has been passed, check to see if we are sandboxed
10260 : // from it as the result of an iframe or CSP sandbox.
10261 6 : if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
10262 0 : return NS_ERROR_DOM_INVALID_ACCESS_ERR;
10263 : }
10264 :
10265 : // If this docshell is owned by a frameloader, make sure to cancel
10266 : // possible frameloader initialization before loading a new page.
10267 12 : nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
10268 6 : if (parent) {
10269 4 : nsCOMPtr<nsIDocument> doc = parent->GetDocument();
10270 2 : if (doc) {
10271 2 : doc->TryCancelFrameLoaderInitialization(this);
10272 : }
10273 : }
10274 :
10275 : // Before going any further vet loads initiated by external programs.
10276 6 : if (aLoadType == LOAD_NORMAL_EXTERNAL) {
10277 : // Disallow external chrome: loads targetted at content windows
10278 0 : bool isChrome = false;
10279 0 : if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
10280 0 : NS_WARNING("blocked external chrome: url -- use '--chrome' option");
10281 0 : return NS_ERROR_FAILURE;
10282 : }
10283 :
10284 : // clear the decks to prevent context bleed-through (bug 298255)
10285 0 : rv = CreateAboutBlankContentViewer(nullptr, nullptr);
10286 0 : if (NS_FAILED(rv)) {
10287 0 : return NS_ERROR_FAILURE;
10288 : }
10289 :
10290 : // reset loadType so we don't have to add lots of tests for
10291 : // LOAD_NORMAL_EXTERNAL after this point
10292 0 : aLoadType = LOAD_NORMAL;
10293 : }
10294 :
10295 6 : mAllowKeywordFixup =
10296 6 : (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
10297 6 : mURIResultedInDocument = false; // reset the clock...
10298 :
10299 6 : if (aLoadType == LOAD_NORMAL ||
10300 0 : aLoadType == LOAD_STOP_CONTENT ||
10301 0 : LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
10302 0 : aLoadType == LOAD_HISTORY ||
10303 : aLoadType == LOAD_LINK) {
10304 12 : nsCOMPtr<nsIURI> currentURI = mCurrentURI;
10305 :
10306 12 : nsAutoCString curHash, newHash;
10307 6 : bool curURIHasRef = false, newURIHasRef = false;
10308 :
10309 6 : nsresult rvURINew = aURI->GetRef(newHash);
10310 6 : if (NS_SUCCEEDED(rvURINew)) {
10311 6 : rvURINew = aURI->GetHasRef(&newURIHasRef);
10312 : }
10313 :
10314 6 : bool sameExceptHashes = false;
10315 6 : if (currentURI && NS_SUCCEEDED(rvURINew)) {
10316 5 : nsresult rvURIOld = currentURI->GetRef(curHash);
10317 5 : if (NS_SUCCEEDED(rvURIOld)) {
10318 5 : rvURIOld = currentURI->GetHasRef(&curURIHasRef);
10319 : }
10320 5 : if (NS_SUCCEEDED(rvURIOld)) {
10321 5 : if (NS_FAILED(currentURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
10322 0 : sameExceptHashes = false;
10323 : }
10324 : }
10325 : }
10326 :
10327 9 : if (!sameExceptHashes && sURIFixup && currentURI &&
10328 3 : NS_SUCCEEDED(rvURINew)) {
10329 : // Maybe aURI came from the exposable form of currentURI?
10330 6 : nsCOMPtr<nsIURI> currentExposableURI;
10331 6 : rv = sURIFixup->CreateExposableURI(currentURI,
10332 6 : getter_AddRefs(currentExposableURI));
10333 3 : NS_ENSURE_SUCCESS(rv, rv);
10334 3 : nsresult rvURIOld = currentExposableURI->GetRef(curHash);
10335 3 : if (NS_SUCCEEDED(rvURIOld)) {
10336 3 : rvURIOld = currentExposableURI->GetHasRef(&curURIHasRef);
10337 : }
10338 3 : if (NS_SUCCEEDED(rvURIOld)) {
10339 3 : if (NS_FAILED(currentExposableURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
10340 0 : sameExceptHashes = false;
10341 : }
10342 : }
10343 : }
10344 :
10345 6 : bool historyNavBetweenSameDoc = false;
10346 6 : if (mOSHE && aSHEntry) {
10347 : // We're doing a history load.
10348 :
10349 0 : mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
10350 :
10351 : #ifdef DEBUG
10352 0 : if (historyNavBetweenSameDoc) {
10353 0 : nsCOMPtr<nsIInputStream> currentPostData;
10354 0 : mOSHE->GetPostData(getter_AddRefs(currentPostData));
10355 0 : NS_ASSERTION(currentPostData == aPostData,
10356 : "Different POST data for entries for the same page?");
10357 : }
10358 : #endif
10359 : }
10360 :
10361 : // A short-circuited load happens when we navigate between two SHEntries
10362 : // for the same document. We do a short-circuited load under two
10363 : // circumstances. Either
10364 : //
10365 : // a) we're navigating between two different SHEntries which share a
10366 : // document, or
10367 : //
10368 : // b) we're navigating to a new shentry whose URI differs from the
10369 : // current URI only in its hash, the new hash is non-empty, and
10370 : // we're not doing a POST.
10371 : //
10372 : // The restriction tha the SHEntries in (a) must be different ensures
10373 : // that history.go(0) and the like trigger full refreshes, rather than
10374 : // short-circuited loads.
10375 : bool doShortCircuitedLoad =
10376 6 : (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
10377 6 : (!aSHEntry && !aPostData &&
10378 8 : sameExceptHashes && newURIHasRef);
10379 :
10380 6 : if (doShortCircuitedLoad) {
10381 : // Save the position of the scrollers.
10382 0 : nscoord cx = 0, cy = 0;
10383 0 : GetCurScrollPos(ScrollOrientation_X, &cx);
10384 0 : GetCurScrollPos(ScrollOrientation_Y, &cy);
10385 :
10386 : // Reset mLoadType to its original value once we exit this block,
10387 : // because this short-circuited load might have started after a
10388 : // normal, network load, and we don't want to clobber its load type.
10389 : // See bug 737307.
10390 0 : AutoRestore<uint32_t> loadTypeResetter(mLoadType);
10391 :
10392 : // If a non-short-circuit load (i.e., a network load) is pending,
10393 : // make this a replacement load, so that we don't add a SHEntry here
10394 : // and the network load goes into the SHEntry it expects to.
10395 0 : if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
10396 0 : mLoadType = LOAD_NORMAL_REPLACE;
10397 : } else {
10398 0 : mLoadType = aLoadType;
10399 : }
10400 :
10401 0 : mURIResultedInDocument = true;
10402 :
10403 0 : nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
10404 :
10405 : /* we need to assign mLSHE to aSHEntry right here, so that on History
10406 : * loads, SetCurrentURI() called from OnNewURI() will send proper
10407 : * onLocationChange() notifications to the browser to update
10408 : * back/forward buttons.
10409 : */
10410 0 : SetHistoryEntry(&mLSHE, aSHEntry);
10411 :
10412 : // Set the doc's URI according to the new history entry's URI.
10413 0 : nsCOMPtr<nsIDocument> doc = GetDocument();
10414 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
10415 0 : doc->SetDocumentURI(aURI);
10416 :
10417 : /* This is a anchor traversal with in the same page.
10418 : * call OnNewURI() so that, this traversal will be
10419 : * recorded in session and global history.
10420 : */
10421 0 : nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit;
10422 0 : if (mOSHE) {
10423 0 : mOSHE->GetTriggeringPrincipal(getter_AddRefs(newURITriggeringPrincipal));
10424 0 : mOSHE->GetPrincipalToInherit(getter_AddRefs(newURIPrincipalToInherit));
10425 : } else {
10426 0 : newURITriggeringPrincipal = aTriggeringPrincipal;
10427 0 : newURIPrincipalToInherit = doc->NodePrincipal();
10428 : }
10429 : // Pass true for aCloneSHChildren, since we're not
10430 : // changing documents here, so all of our subframes are
10431 : // still relevant to the new session history entry.
10432 : //
10433 : // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
10434 : // flag on firing onLocationChange(...).
10435 : // Anyway, aCloneSHChildren param is simply reflecting
10436 : // doShortCircuitedLoad in this scope.
10437 0 : OnNewURI(aURI, nullptr, newURITriggeringPrincipal, newURIPrincipalToInherit,
10438 0 : mLoadType, true, true, true);
10439 :
10440 0 : nsCOMPtr<nsIInputStream> postData;
10441 0 : nsCOMPtr<nsISupports> cacheKey;
10442 :
10443 0 : bool scrollRestorationIsManual = false;
10444 0 : if (mOSHE) {
10445 : /* save current position of scroller(s) (bug 59774) */
10446 0 : mOSHE->SetScrollPosition(cx, cy);
10447 0 : mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
10448 : // Get the postdata and page ident from the current page, if
10449 : // the new load is being done via normal means. Note that
10450 : // "normal means" can be checked for just by checking for
10451 : // LOAD_CMD_NORMAL, given the loadType and allowScroll check
10452 : // above -- it filters out some LOAD_CMD_NORMAL cases that we
10453 : // wouldn't want here.
10454 0 : if (aLoadType & LOAD_CMD_NORMAL) {
10455 0 : mOSHE->GetPostData(getter_AddRefs(postData));
10456 0 : mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
10457 :
10458 : // Link our new SHEntry to the old SHEntry's back/forward
10459 : // cache data, since the two SHEntries correspond to the
10460 : // same document.
10461 0 : if (mLSHE) {
10462 0 : if (!aSHEntry) {
10463 : // If we're not doing a history load, scroll restoration
10464 : // should be inherited from the previous session history entry.
10465 0 : mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual);
10466 : }
10467 0 : mLSHE->AdoptBFCacheEntry(mOSHE);
10468 : }
10469 : }
10470 : }
10471 :
10472 : // If we're doing a history load, use its scroll restoration state.
10473 0 : if (aSHEntry) {
10474 0 : aSHEntry->GetScrollRestorationIsManual(&scrollRestorationIsManual);
10475 : }
10476 :
10477 : /* Assign mOSHE to mLSHE. This will either be a new entry created
10478 : * by OnNewURI() for normal loads or aSHEntry for history loads.
10479 : */
10480 0 : if (mLSHE) {
10481 0 : SetHistoryEntry(&mOSHE, mLSHE);
10482 : // Save the postData obtained from the previous page
10483 : // in to the session history entry created for the
10484 : // anchor page, so that any history load of the anchor
10485 : // page will restore the appropriate postData.
10486 0 : if (postData) {
10487 0 : mOSHE->SetPostData(postData);
10488 : }
10489 :
10490 : // Make sure we won't just repost without hitting the
10491 : // cache first
10492 0 : if (cacheKey) {
10493 0 : mOSHE->SetCacheKey(cacheKey);
10494 : }
10495 : }
10496 :
10497 : /* Restore the original LSHE if we were loading something
10498 : * while short-circuited load was initiated.
10499 : */
10500 0 : SetHistoryEntry(&mLSHE, oldLSHE);
10501 : /* Set the title for the SH entry for this target url. so that
10502 : * SH menus in go/back/forward buttons won't be empty for this.
10503 : */
10504 0 : if (mSessionHistory) {
10505 0 : int32_t index = -1;
10506 0 : mSessionHistory->GetIndex(&index);
10507 0 : nsCOMPtr<nsISHEntry> shEntry;
10508 0 : mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(shEntry));
10509 0 : NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
10510 0 : shEntry->SetTitle(mTitle);
10511 : }
10512 :
10513 : /* Set the title for the Global History entry for this anchor url.
10514 : */
10515 0 : UpdateGlobalHistoryTitle(aURI);
10516 :
10517 0 : SetDocCurrentStateObj(mOSHE);
10518 :
10519 : // Inform the favicon service that the favicon for oldURI also
10520 : // applies to aURI.
10521 0 : CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing());
10522 :
10523 0 : RefPtr<nsGlobalWindow> scriptGlobal = mScriptGlobal;
10524 : RefPtr<nsGlobalWindow> win = scriptGlobal ?
10525 0 : scriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
10526 :
10527 : // ScrollToAnchor doesn't necessarily cause us to scroll the window;
10528 : // the function decides whether a scroll is appropriate based on the
10529 : // arguments it receives. But even if we don't end up scrolling,
10530 : // ScrollToAnchor performs other important tasks, such as informing
10531 : // the presShell that we have a new hash. See bug 680257.
10532 0 : rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType);
10533 0 : NS_ENSURE_SUCCESS(rv, rv);
10534 :
10535 : /* restore previous position of scroller(s), if we're moving
10536 : * back in history (bug 59774)
10537 : */
10538 0 : nscoord bx = 0;
10539 0 : nscoord by = 0;
10540 0 : bool needsScrollPosUpdate = false;
10541 0 : if (mOSHE && (aLoadType == LOAD_HISTORY ||
10542 0 : aLoadType == LOAD_RELOAD_NORMAL) &&
10543 0 : !scrollRestorationIsManual) {
10544 0 : needsScrollPosUpdate = true;
10545 0 : mOSHE->GetScrollPosition(&bx, &by);
10546 : }
10547 :
10548 : // Dispatch the popstate and hashchange events, as appropriate.
10549 : //
10550 : // The event dispatch below can cause us to re-enter script and
10551 : // destroy the docshell, nulling out mScriptGlobal. Hold a stack
10552 : // reference to avoid null derefs. See bug 914521.
10553 0 : if (win) {
10554 : // Fire a hashchange event URIs differ, and only in their hashes.
10555 0 : bool doHashchange = sameExceptHashes &&
10556 0 : (curURIHasRef != newURIHasRef || !curHash.Equals(newHash));
10557 :
10558 0 : if (historyNavBetweenSameDoc || doHashchange) {
10559 0 : win->DispatchSyncPopState();
10560 : }
10561 :
10562 0 : if (needsScrollPosUpdate && win->AsInner()->HasActiveDocument()) {
10563 0 : SetCurScrollPosEx(bx, by);
10564 : }
10565 :
10566 0 : if (doHashchange) {
10567 : // Note that currentURI hasn't changed because it's on the
10568 : // stack, so we can just use it directly as the old URI.
10569 0 : win->DispatchAsyncHashchange(currentURI, aURI);
10570 : }
10571 : }
10572 :
10573 0 : return NS_OK;
10574 : }
10575 : }
10576 :
10577 : // mContentViewer->PermitUnload can destroy |this| docShell, which
10578 : // causes the next call of CanSavePresentation to crash.
10579 : // Hold onto |this| until we return, to prevent a crash from happening.
10580 : // (bug#331040)
10581 12 : nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
10582 :
10583 : // Don't init timing for javascript:, since it generally doesn't
10584 : // actually start a load or anything. If it does, we'll init
10585 : // timing then, from OnStateChange.
10586 :
10587 : // XXXbz mTiming should know what channel it's for, so we don't
10588 : // need this hackery.
10589 6 : bool toBeReset = false;
10590 6 : if (!isJavaScript) {
10591 6 : toBeReset = MaybeInitTiming();
10592 : }
10593 6 : bool timeBeforeUnload = aFileName.IsVoid();
10594 6 : if (mTiming && timeBeforeUnload) {
10595 6 : mTiming->NotifyBeforeUnload();
10596 : }
10597 : // Check if the page doesn't want to be unloaded. The javascript:
10598 : // protocol handler deals with this for javascript: URLs.
10599 6 : if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
10600 : bool okToUnload;
10601 5 : rv = mContentViewer->PermitUnload(&okToUnload);
10602 :
10603 5 : if (NS_SUCCEEDED(rv) && !okToUnload) {
10604 : // The user chose not to unload the page, interrupt the
10605 : // load.
10606 0 : MaybeResetInitTiming(toBeReset);
10607 0 : return NS_OK;
10608 : }
10609 : }
10610 :
10611 6 : if (mTiming && timeBeforeUnload) {
10612 6 : mTiming->NotifyUnloadAccepted(mCurrentURI);
10613 : }
10614 :
10615 : // Check if the webbrowser chrome wants the load to proceed; this can be
10616 : // used to cancel attempts to load URIs in the wrong process.
10617 12 : nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
10618 6 : if (browserChrome3) {
10619 : bool shouldLoad;
10620 4 : rv = browserChrome3->ShouldLoadURI(this, aURI, aReferrer, !!aPostData,
10621 2 : aTriggeringPrincipal, &shouldLoad);
10622 2 : if (NS_SUCCEEDED(rv) && !shouldLoad) {
10623 0 : return NS_OK;
10624 : }
10625 : }
10626 :
10627 6 : if (browserChrome3 && aCheckForPrerender) {
10628 : nsCOMPtr<nsIRunnable> ev =
10629 : new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI,
10630 : aLoadReplace, aReferrer, aReferrerPolicy,
10631 : aTriggeringPrincipal, principalToInherit,
10632 : aFlags, aTypeHint, aPostData, aHeadersData,
10633 : aLoadType, aSHEntry, aFirstParty, aSrcdoc,
10634 0 : aSourceDocShell, aBaseURI, false);
10635 : // We don't need any success handler since in that case
10636 : // OnPartialSHistoryDeactive would be called, and it would ensure
10637 : // docshell loads about:blank.
10638 0 : bool shouldSwitch = false;
10639 0 : rv = browserChrome3->ShouldSwitchToPrerenderedDocument(
10640 0 : aURI, mCurrentURI, nullptr, ev, &shouldSwitch);
10641 0 : if (NS_SUCCEEDED(rv) && shouldSwitch) {
10642 0 : return NS_OK;
10643 : }
10644 : }
10645 :
10646 : // Whenever a top-level browsing context is navigated, the user agent MUST
10647 : // lock the orientation of the document to the document's default
10648 : // orientation. We don't explicitly check for a top-level browsing context
10649 : // here because orientation is only set on top-level browsing contexts.
10650 6 : if (OrientationLock() != eScreenOrientation_None) {
10651 : #ifdef DEBUG
10652 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
10653 0 : GetSameTypeParent(getter_AddRefs(parent));
10654 0 : MOZ_ASSERT(!parent);
10655 : #endif
10656 0 : SetOrientationLock(eScreenOrientation_None);
10657 0 : if (mIsActive) {
10658 0 : ScreenOrientation::UpdateActiveOrientationLock(eScreenOrientation_None);
10659 : }
10660 : }
10661 :
10662 : // Check for saving the presentation here, before calling Stop().
10663 : // This is necessary so that we can catch any pending requests.
10664 : // Since the new request has not been created yet, we pass null for the
10665 : // new request parameter.
10666 : // Also pass nullptr for the document, since it doesn't affect the return
10667 : // value for our purposes here.
10668 6 : bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
10669 :
10670 : // Don't stop current network activity for javascript: URL's since
10671 : // they might not result in any data, and thus nothing should be
10672 : // stopped in those cases. In the case where they do result in
10673 : // data, the javascript: URL channel takes care of stopping
10674 : // current network activity.
10675 6 : if (!isJavaScript && aFileName.IsVoid()) {
10676 : // Stop any current network activity.
10677 : // Also stop content if this is a zombie doc. otherwise
10678 : // the onload will be delayed by other loads initiated in the
10679 : // background by the first document that
10680 : // didn't fully load before the next load was initiated.
10681 : // If not a zombie, don't stop content until data
10682 : // starts arriving from the new URI...
10683 :
10684 12 : nsCOMPtr<nsIContentViewer> zombieViewer;
10685 6 : if (mContentViewer) {
10686 5 : mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
10687 : }
10688 :
10689 12 : if (zombieViewer ||
10690 12 : LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
10691 0 : rv = Stop(nsIWebNavigation::STOP_ALL);
10692 : } else {
10693 6 : rv = Stop(nsIWebNavigation::STOP_NETWORK);
10694 : }
10695 :
10696 6 : if (NS_FAILED(rv)) {
10697 0 : return rv;
10698 : }
10699 : }
10700 :
10701 6 : mLoadType = aLoadType;
10702 :
10703 : // mLSHE should be assigned to aSHEntry, only after Stop() has
10704 : // been called. But when loading an error page, do not clear the
10705 : // mLSHE for the real page.
10706 6 : if (mLoadType != LOAD_ERROR_PAGE) {
10707 6 : SetHistoryEntry(&mLSHE, aSHEntry);
10708 : }
10709 :
10710 6 : mSavingOldViewer = savePresentation;
10711 :
10712 : // If we have a saved content viewer in history, restore and show it now.
10713 6 : if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
10714 : // Make sure our history ID points to the same ID as
10715 : // SHEntry's docshell ID.
10716 0 : mHistoryID = aSHEntry->DocshellID();
10717 :
10718 : // It's possible that the previous viewer of mContentViewer is the
10719 : // viewer that will end up in aSHEntry when it gets closed. If that's
10720 : // the case, we need to go ahead and force it into its shentry so we
10721 : // can restore it.
10722 0 : if (mContentViewer) {
10723 0 : nsCOMPtr<nsIContentViewer> prevViewer;
10724 0 : mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
10725 0 : if (prevViewer) {
10726 : #ifdef DEBUG
10727 0 : nsCOMPtr<nsIContentViewer> prevPrevViewer;
10728 0 : prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
10729 0 : NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
10730 : #endif
10731 0 : nsCOMPtr<nsISHEntry> viewerEntry;
10732 0 : prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
10733 0 : if (viewerEntry == aSHEntry) {
10734 : // Make sure this viewer ends up in the right place
10735 0 : mContentViewer->SetPreviousViewer(nullptr);
10736 0 : prevViewer->Destroy();
10737 : }
10738 : }
10739 : }
10740 0 : nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
10741 : bool restoring;
10742 0 : rv = RestorePresentation(aSHEntry, &restoring);
10743 0 : if (restoring) {
10744 0 : return rv;
10745 : }
10746 :
10747 : // We failed to restore the presentation, so clean up.
10748 : // Both the old and new history entries could potentially be in
10749 : // an inconsistent state.
10750 0 : if (NS_FAILED(rv)) {
10751 0 : if (oldEntry) {
10752 0 : oldEntry->SyncPresentationState();
10753 : }
10754 :
10755 0 : aSHEntry->SyncPresentationState();
10756 : }
10757 : }
10758 :
10759 12 : nsAutoString srcdoc;
10760 6 : if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) {
10761 0 : srcdoc = aSrcdoc;
10762 : } else {
10763 6 : srcdoc = NullString();
10764 : }
10765 :
10766 9 : bool isTopLevelDoc = mItemType == typeContent &&
10767 0 : (isTargetTopLevelDocShell ||
10768 6 : GetIsMozBrowser());
10769 :
10770 12 : OriginAttributes attrs = GetOriginAttributes();
10771 6 : attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
10772 :
10773 : net::PredictorLearn(aURI, nullptr,
10774 6 : nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
10775 : net::PredictorPredict(aURI, nullptr,
10776 6 : nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
10777 :
10778 12 : nsCOMPtr<nsIRequest> req;
10779 30 : rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI, aLoadReplace, aReferrer,
10780 6 : !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
10781 : aReferrerPolicy,
10782 : aTriggeringPrincipal, principalToInherit, aTypeHint,
10783 : aFileName, aPostData, aHeadersData,
10784 12 : aFirstParty, aDocShell, getter_AddRefs(req),
10785 6 : (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
10786 6 : (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
10787 6 : (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
10788 : srcdoc, aBaseURI, contentType);
10789 6 : if (req && aRequest) {
10790 0 : NS_ADDREF(*aRequest = req);
10791 : }
10792 :
10793 6 : if (NS_FAILED(rv)) {
10794 0 : nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
10795 0 : if (DisplayLoadError(rv, aURI, nullptr, chan) &&
10796 0 : (aFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
10797 0 : return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
10798 : }
10799 : }
10800 :
10801 6 : return rv;
10802 : }
10803 :
10804 : nsIPrincipal*
10805 2 : nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
10806 : {
10807 4 : nsCOMPtr<nsIDocument> document;
10808 2 : bool inheritedFromCurrent = false;
10809 :
10810 2 : if (aConsiderCurrentDocument && mContentViewer) {
10811 0 : document = mContentViewer->GetDocument();
10812 0 : inheritedFromCurrent = true;
10813 : }
10814 :
10815 2 : if (!document) {
10816 4 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
10817 2 : GetSameTypeParent(getter_AddRefs(parentItem));
10818 2 : if (parentItem) {
10819 0 : document = parentItem->GetDocument();
10820 : }
10821 : }
10822 :
10823 2 : if (!document) {
10824 2 : if (!aConsiderCurrentDocument) {
10825 2 : return nullptr;
10826 : }
10827 :
10828 : // Make sure we end up with _something_ as the principal no matter
10829 : // what.If this fails, we'll just get a null docViewer and bail.
10830 0 : EnsureContentViewer();
10831 0 : if (!mContentViewer) {
10832 0 : return nullptr;
10833 : }
10834 0 : document = mContentViewer->GetDocument();
10835 : }
10836 :
10837 : //-- Get the document's principal
10838 0 : if (document) {
10839 0 : nsIPrincipal* docPrincipal = document->NodePrincipal();
10840 :
10841 : // Don't allow loads in typeContent docShells to inherit the system
10842 : // principal from existing documents.
10843 0 : if (inheritedFromCurrent &&
10844 0 : mItemType == typeContent &&
10845 0 : nsContentUtils::IsSystemPrincipal(docPrincipal)) {
10846 0 : return nullptr;
10847 : }
10848 :
10849 0 : return docPrincipal;
10850 : }
10851 :
10852 0 : return nullptr;
10853 : }
10854 :
10855 : nsresult
10856 6 : nsDocShell::DoURILoad(nsIURI* aURI,
10857 : nsIURI* aOriginalURI,
10858 : Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
10859 : bool aLoadReplace,
10860 : nsIURI* aReferrerURI,
10861 : bool aSendReferrer,
10862 : uint32_t aReferrerPolicy,
10863 : nsIPrincipal* aTriggeringPrincipal,
10864 : nsIPrincipal* aPrincipalToInherit,
10865 : const char* aTypeHint,
10866 : const nsAString& aFileName,
10867 : nsIInputStream* aPostData,
10868 : nsIInputStream* aHeadersData,
10869 : bool aFirstParty,
10870 : nsIDocShell** aDocShell,
10871 : nsIRequest** aRequest,
10872 : bool aIsNewWindowTarget,
10873 : bool aBypassClassifier,
10874 : bool aForceAllowCookies,
10875 : const nsAString& aSrcdoc,
10876 : nsIURI* aBaseURI,
10877 : nsContentPolicyType aContentPolicyType)
10878 : {
10879 : // Double-check that we're still around to load this URI.
10880 6 : if (mIsBeingDestroyed) {
10881 : // Return NS_OK despite not doing anything to avoid throwing exceptions from
10882 : // nsLocation::SetHref if the unload handler of the existing page tears us
10883 : // down.
10884 0 : return NS_OK;
10885 : }
10886 :
10887 : nsresult rv;
10888 12 : nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
10889 6 : if (NS_FAILED(rv)) {
10890 0 : return rv;
10891 : }
10892 :
10893 6 : if (IsFrame()) {
10894 :
10895 1 : MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
10896 : aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME,
10897 : "DoURILoad thinks this is a frame and InternalLoad does not");
10898 :
10899 : // Only allow view-source scheme in top-level docshells. view-source is
10900 : // the only scheme to which this applies at the moment due to potential
10901 : // timing attacks to read data from cross-origin iframes. If this widens
10902 : // we should add a protocol flag for whether the scheme is allowed in
10903 : // frames and use something like nsNetUtil::NS_URIChainHasFlags.
10904 2 : nsCOMPtr<nsIURI> tempURI = aURI;
10905 2 : nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
10906 3 : while (nestedURI) {
10907 : // view-source should always be an nsINestedURI, loop and check the
10908 : // scheme on this and all inner URIs that are also nested URIs.
10909 1 : bool isViewSource = false;
10910 1 : rv = tempURI->SchemeIs("view-source", &isViewSource);
10911 1 : if (NS_FAILED(rv) || isViewSource) {
10912 0 : return NS_ERROR_UNKNOWN_PROTOCOL;
10913 : }
10914 1 : nestedURI->GetInnerURI(getter_AddRefs(tempURI));
10915 1 : nestedURI = do_QueryInterface(tempURI);
10916 : }
10917 : } else {
10918 5 : MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
10919 : "DoURILoad thinks this is a document and InternalLoad does not");
10920 : }
10921 :
10922 : // open a channel for the url
10923 12 : nsCOMPtr<nsIChannel> channel;
10924 :
10925 6 : bool isSrcdoc = !aSrcdoc.IsVoid();
10926 :
10927 : // There are two cases we care about:
10928 : // * Top-level load: In this case, loadingNode is null, but loadingWindow
10929 : // is our mScriptGlobal. We pass null for loadingPrincipal in this case.
10930 : // * Subframe load: loadingWindow is null, but loadingNode is the frame
10931 : // element for the load. loadingPrincipal is the NodePrincipal of the frame
10932 : // element.
10933 12 : nsCOMPtr<nsINode> loadingNode;
10934 12 : nsCOMPtr<nsPIDOMWindowOuter> loadingWindow;
10935 12 : nsCOMPtr<nsIPrincipal> loadingPrincipal;
10936 :
10937 6 : if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
10938 5 : loadingNode = nullptr;
10939 5 : loadingPrincipal = nullptr;
10940 5 : loadingWindow = mScriptGlobal->AsOuter();
10941 : } else {
10942 1 : loadingWindow = nullptr;
10943 1 : loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal();
10944 1 : if (loadingNode) {
10945 : // If we have a loading node, then use that as our loadingPrincipal.
10946 1 : loadingPrincipal = loadingNode->NodePrincipal();
10947 : } else {
10948 : // If this isn't a top-level load and mScriptGlobal's frame element is
10949 : // null, then the element got removed from the DOM while we were trying
10950 : // to load this resource. This docshell is scheduled for destruction
10951 : // already, so bail out here.
10952 0 : return NS_OK;
10953 : }
10954 : }
10955 :
10956 : // Getting the right triggeringPrincipal needs to be updated and is only
10957 : // ready for use once bug 1182569 landed. Until then, we cannot rely on
10958 : // the triggeringPrincipal for TYPE_DOCUMENT loads.
10959 6 : MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
10960 :
10961 6 : bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
10962 : // only inherit if we have a aPrincipalToInherit
10963 6 : bool inherit = false;
10964 :
10965 6 : if (aPrincipalToInherit) {
10966 : bool isData;
10967 4 : bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() &&
10968 4 : NS_SUCCEEDED(aURI->SchemeIs("data", &isData)) &&
10969 4 : isData;
10970 : // If aURI is data: URI and is treated as a unique opaque origin, we don't
10971 : // want to inherit principal.
10972 8 : inherit = nsContentUtils::ChannelShouldInheritPrincipal(
10973 : aPrincipalToInherit,
10974 : aURI,
10975 : true, // aInheritForAboutBlank
10976 4 : isSrcdoc) && !isURIUniqueOrigin ;
10977 : }
10978 :
10979 6 : nsLoadFlags loadFlags = mDefaultLoadFlags;
10980 : nsSecurityFlags securityFlags =
10981 6 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
10982 :
10983 6 : if (aFirstParty) {
10984 : // tag first party URL loads
10985 4 : loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
10986 : }
10987 :
10988 6 : if (mLoadType == LOAD_ERROR_PAGE) {
10989 : // Error pages are LOAD_BACKGROUND
10990 0 : loadFlags |= nsIChannel::LOAD_BACKGROUND;
10991 0 : securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
10992 : }
10993 :
10994 6 : if (inherit) {
10995 2 : securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
10996 : }
10997 6 : if (isSandBoxed) {
10998 0 : securityFlags |= nsILoadInfo::SEC_SANDBOXED;
10999 : }
11000 :
11001 : nsCOMPtr<nsILoadInfo> loadInfo =
11002 : (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
11003 : new LoadInfo(loadingWindow, aTriggeringPrincipal,
11004 10 : securityFlags) :
11005 : new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
11006 18 : securityFlags, aContentPolicyType);
11007 :
11008 6 : if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
11009 : enum TopLevelDataState {
11010 : DATA_NAVIGATED = 0,
11011 : DATA_TYPED = 1,
11012 : NO_DATA = 2,
11013 : };
11014 5 : bool isDataURI = (NS_SUCCEEDED(aURI->SchemeIs("data", &isDataURI)) && isDataURI);
11015 5 : if (isDataURI) {
11016 : // In all cases where the toplevel document is navigated to a data: URI
11017 : // the triggeringPrincipal is a CodeBasePrincipal. In all other cases
11018 : // e.g. typing a data: URL into the URL-Bar or also clicking a bookmark
11019 : // uses a SystemPrincipal as the triggeringPrincipal.
11020 0 : if (aTriggeringPrincipal->GetIsCodebasePrincipal()) {
11021 0 : Telemetry::Accumulate(Telemetry::DOCUMENT_DATA_URI_LOADS, DATA_NAVIGATED);
11022 : } else {
11023 0 : Telemetry::Accumulate(Telemetry::DOCUMENT_DATA_URI_LOADS, DATA_TYPED);
11024 : }
11025 : } else {
11026 5 : Telemetry::Accumulate(Telemetry::DOCUMENT_DATA_URI_LOADS, NO_DATA);
11027 : }
11028 : }
11029 :
11030 6 : if (aPrincipalToInherit) {
11031 4 : loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
11032 : }
11033 :
11034 : // We have to do this in case our OriginAttributes are different from the
11035 : // OriginAttributes of the parent document. Or in case there isn't a
11036 : // parent document.
11037 9 : bool isTopLevelDoc = mItemType == typeContent &&
11038 0 : (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
11039 6 : GetIsMozBrowser());
11040 :
11041 12 : OriginAttributes attrs;
11042 :
11043 : // If inherit is true, which means loadInfo will have SEC_FORCE_INHERIT_PRINCIPAL
11044 : // set, so later when we create principal of the document from
11045 : // nsScriptSecurityManager::GetChannelResultPrincipal, we will use
11046 : // principalToInherit of the loadInfo as the document principal.
11047 : // Therefore we use the origin attributes from aPrincipalToInherit.
11048 : //
11049 : // Otherwise we just use the origin attributes from docshell.
11050 6 : if (inherit) {
11051 2 : MOZ_ASSERT(aPrincipalToInherit, "We should have aPrincipalToInherit here.");
11052 2 : attrs = aPrincipalToInherit->OriginAttributesRef();
11053 : // If firstPartyIsolation is not enabled, then PrincipalToInherit should
11054 : // have the same origin attributes with docshell.
11055 2 : MOZ_ASSERT_IF(!OriginAttributes::IsFirstPartyEnabled(), attrs == GetOriginAttributes());
11056 : } else {
11057 4 : attrs = GetOriginAttributes();
11058 4 : attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
11059 : }
11060 :
11061 6 : rv = loadInfo->SetOriginAttributes(attrs);
11062 6 : if (NS_WARN_IF(NS_FAILED(rv))) {
11063 0 : return rv;
11064 : }
11065 :
11066 6 : if (!isSrcdoc) {
11067 6 : rv = NS_NewChannelInternal(getter_AddRefs(channel),
11068 : aURI,
11069 : loadInfo,
11070 : nullptr, // loadGroup
11071 : static_cast<nsIInterfaceRequestor*>(this),
11072 : loadFlags);
11073 :
11074 6 : if (NS_FAILED(rv)) {
11075 0 : if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
11076 : // This is a uri with a protocol scheme we don't know how
11077 : // to handle. Embedders might still be interested in
11078 : // handling the load, though, so we fire a notification
11079 : // before throwing the load away.
11080 0 : bool abort = false;
11081 0 : nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
11082 0 : if (NS_SUCCEEDED(rv2) && abort) {
11083 : // Hey, they're handling the load for us! How convenient!
11084 0 : return NS_OK;
11085 : }
11086 : }
11087 0 : return rv;
11088 : }
11089 :
11090 6 : if (aBaseURI) {
11091 0 : nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
11092 0 : if (vsc) {
11093 0 : rv = vsc->SetBaseURI(aBaseURI);
11094 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
11095 : }
11096 : }
11097 : } else {
11098 0 : nsAutoCString scheme;
11099 0 : rv = aURI->GetScheme(scheme);
11100 0 : NS_ENSURE_SUCCESS(rv, rv);
11101 : bool isViewSource;
11102 0 : aURI->SchemeIs("view-source", &isViewSource);
11103 :
11104 0 : if (isViewSource) {
11105 0 : nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance();
11106 0 : NS_ENSURE_TRUE(vsh, NS_ERROR_FAILURE);
11107 :
11108 0 : rv = vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc,
11109 0 : loadInfo, getter_AddRefs(channel));
11110 : } else {
11111 0 : rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
11112 : aURI,
11113 : aSrcdoc,
11114 0 : NS_LITERAL_CSTRING("text/html"),
11115 : loadInfo,
11116 0 : true);
11117 0 : NS_ENSURE_SUCCESS(rv, rv);
11118 0 : nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
11119 0 : MOZ_ASSERT(isc);
11120 0 : isc->SetBaseURI(aBaseURI);
11121 : }
11122 : }
11123 :
11124 : // Navigational requests that are same origin need to be upgraded in case
11125 : // upgrade-insecure-requests is present. Please note that in that case
11126 : // the triggeringPrincipal is holding the CSP that potentially
11127 : // holds upgrade-insecure-requests.
11128 12 : nsCOMPtr<nsIContentSecurityPolicy> csp;
11129 6 : aTriggeringPrincipal->GetCsp(getter_AddRefs(csp));
11130 6 : if (csp) {
11131 0 : bool upgradeInsecureRequests = false;
11132 0 : csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
11133 0 : if (upgradeInsecureRequests) {
11134 : // only upgrade if the navigation is same origin
11135 0 : nsCOMPtr<nsIPrincipal> resultPrincipal;
11136 0 : rv = nsContentUtils::GetSecurityManager()->
11137 0 : GetChannelResultPrincipal(channel,
11138 0 : getter_AddRefs(resultPrincipal));
11139 0 : NS_ENSURE_SUCCESS(rv, rv);
11140 0 : if (resultPrincipal->Equals(aTriggeringPrincipal)) {
11141 0 : static_cast<mozilla::LoadInfo*>(loadInfo.get())->SetUpgradeInsecureRequests();
11142 : }
11143 : }
11144 : }
11145 :
11146 :
11147 : nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
11148 12 : do_QueryInterface(channel);
11149 6 : if (appCacheChannel) {
11150 : // Any document load should not inherit application cache.
11151 1 : appCacheChannel->SetInheritApplicationCache(false);
11152 :
11153 : // Loads with the correct permissions should check for a matching
11154 : // application cache.
11155 1 : if (GeckoProcessType_Default != XRE_GetProcessType()) {
11156 : // Permission will be checked in the parent process
11157 1 : appCacheChannel->SetChooseApplicationCache(true);
11158 : } else {
11159 : nsCOMPtr<nsIScriptSecurityManager> secMan =
11160 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
11161 :
11162 0 : if (secMan) {
11163 0 : nsCOMPtr<nsIPrincipal> principal;
11164 0 : secMan->GetDocShellCodebasePrincipal(aURI, this,
11165 0 : getter_AddRefs(principal));
11166 0 : appCacheChannel->SetChooseApplicationCache(
11167 0 : NS_ShouldCheckAppCache(principal));
11168 : }
11169 : }
11170 : }
11171 :
11172 : // Make sure to give the caller a channel if we managed to create one
11173 : // This is important for correct error page/session history interaction
11174 6 : if (aRequest) {
11175 6 : NS_ADDREF(*aRequest = channel);
11176 : }
11177 :
11178 6 : if (aOriginalURI) {
11179 0 : channel->SetOriginalURI(aOriginalURI);
11180 : // The LOAD_REPLACE flag and its handling here will be removed as part
11181 : // of bug 1319110. For now preserve its restoration here to not break
11182 : // any code expecting it being set specially on redirected channels.
11183 : // If the flag has originally been set to change result of
11184 : // NS_GetFinalChannelURI it won't have any effect and also won't cause
11185 : // any harm.
11186 0 : if (aLoadReplace) {
11187 : uint32_t loadFlags;
11188 0 : channel->GetLoadFlags(&loadFlags);
11189 0 : NS_ENSURE_SUCCESS(rv, rv);
11190 0 : channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
11191 : }
11192 : } else {
11193 6 : channel->SetOriginalURI(aURI);
11194 : }
11195 :
11196 6 : if (aResultPrincipalURI) {
11197 : // Unconditionally override, we want the replay to be equal to what has
11198 : // been captured.
11199 0 : loadInfo->SetResultPrincipalURI(aResultPrincipalURI.ref());
11200 : }
11201 :
11202 6 : if (aTypeHint && *aTypeHint) {
11203 0 : channel->SetContentType(nsDependentCString(aTypeHint));
11204 0 : mContentTypeHint = aTypeHint;
11205 : } else {
11206 6 : mContentTypeHint.Truncate();
11207 : }
11208 :
11209 6 : if (!aFileName.IsVoid()) {
11210 0 : rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
11211 0 : NS_ENSURE_SUCCESS(rv, rv);
11212 0 : if (!aFileName.IsEmpty()) {
11213 0 : rv = channel->SetContentDispositionFilename(aFileName);
11214 0 : NS_ENSURE_SUCCESS(rv, rv);
11215 : }
11216 : }
11217 :
11218 12 : if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
11219 6 : mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
11220 0 : rv = SetMixedContentChannel(channel);
11221 0 : NS_ENSURE_SUCCESS(rv, rv);
11222 6 : } else if (mMixedContentChannel) {
11223 : /*
11224 : * If the user "Disables Protection on This Page", we call
11225 : * SetMixedContentChannel for the first time, otherwise
11226 : * mMixedContentChannel is still null.
11227 : * Later, if the new channel passes a same orign check, we remember the
11228 : * users decision by calling SetMixedContentChannel using the new channel.
11229 : * This way, the user does not have to click the disable protection button
11230 : * over and over for browsing the same site.
11231 : */
11232 0 : rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel);
11233 0 : if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) {
11234 0 : SetMixedContentChannel(nullptr);
11235 : }
11236 : }
11237 :
11238 : // hack
11239 12 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
11240 : nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
11241 12 : do_QueryInterface(channel));
11242 6 : if (httpChannelInternal) {
11243 1 : if (aForceAllowCookies) {
11244 0 : rv = httpChannelInternal->SetThirdPartyFlags(
11245 0 : nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
11246 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
11247 : }
11248 1 : if (aFirstParty) {
11249 1 : rv = httpChannelInternal->SetDocumentURI(aURI);
11250 1 : MOZ_ASSERT(NS_SUCCEEDED(rv));
11251 : } else {
11252 0 : rv = httpChannelInternal->SetDocumentURI(aReferrerURI);
11253 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
11254 : }
11255 2 : rv = httpChannelInternal->SetRedirectMode(
11256 1 : nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
11257 1 : MOZ_ASSERT(NS_SUCCEEDED(rv));
11258 : }
11259 :
11260 12 : nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
11261 6 : if (props) {
11262 : // save true referrer for those who need it (e.g. xpinstall whitelisting)
11263 : // Currently only http and ftp channels support this.
11264 24 : props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
11265 18 : aReferrerURI);
11266 : }
11267 :
11268 12 : nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel));
11269 : /* Get the cache Key from SH */
11270 12 : nsCOMPtr<nsISupports> cacheKey;
11271 6 : if (cacheChannel) {
11272 1 : if (mLSHE) {
11273 0 : mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
11274 1 : } else if (mOSHE) { // for reload cases
11275 0 : mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
11276 : }
11277 : }
11278 :
11279 : // figure out if we need to set the post data stream on the channel...
11280 6 : if (aPostData) {
11281 0 : nsCOMPtr<nsIFormPOSTActionChannel> postChannel(do_QueryInterface(channel));
11282 0 : if (postChannel) {
11283 : // XXX it's a bit of a hack to rewind the postdata stream here but
11284 : // it has to be done in case the post data is being reused multiple
11285 : // times.
11286 : nsCOMPtr<nsISeekableStream> postDataSeekable =
11287 0 : do_QueryInterface(aPostData);
11288 0 : if (postDataSeekable) {
11289 0 : rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
11290 0 : NS_ENSURE_SUCCESS(rv, rv);
11291 : }
11292 :
11293 : // we really need to have a content type associated with this stream!!
11294 0 : postChannel->SetUploadStream(aPostData, EmptyCString(), -1);
11295 : }
11296 :
11297 : /* If there is a valid postdata *and* it is a History Load,
11298 : * set up the cache key on the channel, to retrieve the
11299 : * data *only* from the cache. If it is a normal reload, the
11300 : * cache is free to go to the server for updated postdata.
11301 : */
11302 0 : if (cacheChannel && cacheKey) {
11303 0 : if (mLoadType == LOAD_HISTORY ||
11304 0 : mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
11305 0 : cacheChannel->SetCacheKey(cacheKey);
11306 : uint32_t loadFlags;
11307 0 : if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) {
11308 0 : channel->SetLoadFlags(
11309 0 : loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
11310 0 : }
11311 0 : } else if (mLoadType == LOAD_RELOAD_NORMAL) {
11312 0 : cacheChannel->SetCacheKey(cacheKey);
11313 : }
11314 : }
11315 : } else {
11316 : /* If there is no postdata, set the cache key on the channel, and
11317 : * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
11318 : * will be free to get it from net if it is not found in cache.
11319 : * New cache may use it creatively on CGI pages with GET
11320 : * method and even on those that say "no-cache"
11321 : */
11322 12 : if (mLoadType == LOAD_HISTORY ||
11323 12 : mLoadType == LOAD_RELOAD_NORMAL ||
11324 6 : mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
11325 0 : if (cacheChannel && cacheKey) {
11326 0 : cacheChannel->SetCacheKey(cacheKey);
11327 : }
11328 : }
11329 : }
11330 :
11331 6 : if (httpChannel) {
11332 1 : if (aHeadersData) {
11333 0 : rv = AddHeadersToChannel(aHeadersData, httpChannel);
11334 : }
11335 : // Set the referrer explicitly
11336 1 : if (aReferrerURI && aSendReferrer) {
11337 : // Referrer is currenly only set for link clicks here.
11338 0 : rv = httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
11339 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
11340 : }
11341 : }
11342 :
11343 12 : nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
11344 6 : if (scriptChannel) {
11345 : // Allow execution against our context if the principals match
11346 0 : scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
11347 : }
11348 :
11349 6 : if (aIsNewWindowTarget) {
11350 2 : nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
11351 1 : if (props) {
11352 4 : props->SetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
11353 3 : true);
11354 : }
11355 : }
11356 :
11357 12 : nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
11358 6 : if (timedChannel) {
11359 1 : timedChannel->SetTimingEnabled(true);
11360 :
11361 2 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
11362 1 : if (IsFrame() && win) {
11363 0 : nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
11364 0 : if (frameElement) {
11365 0 : timedChannel->SetInitiatorType(frameElement->LocalName());
11366 : }
11367 : }
11368 : }
11369 :
11370 : // Mark the http channel as UrgentStart for top level document loading
11371 : // in active tab.
11372 6 : if (mIsActive || (mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY))) {
11373 6 : if (httpChannel && isTopLevelDoc) {
11374 2 : nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
11375 1 : if (cos) {
11376 1 : cos->AddClassFlags(nsIClassOfService::UrgentStart);
11377 : }
11378 : }
11379 : }
11380 :
11381 6 : rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
11382 :
11383 : //
11384 : // If the channel load failed, we failed and nsIWebProgress just ain't
11385 : // gonna happen.
11386 : //
11387 6 : if (NS_SUCCEEDED(rv)) {
11388 6 : if (aDocShell) {
11389 0 : *aDocShell = this;
11390 0 : NS_ADDREF(*aDocShell);
11391 : }
11392 : }
11393 :
11394 6 : return rv;
11395 : }
11396 :
11397 : static nsresult
11398 0 : AppendSegmentToString(nsIInputStream* aIn,
11399 : void* aClosure,
11400 : const char* aFromRawSegment,
11401 : uint32_t aToOffset,
11402 : uint32_t aCount,
11403 : uint32_t* aWriteCount)
11404 : {
11405 : // aFromSegment now contains aCount bytes of data.
11406 :
11407 0 : nsAutoCString* buf = static_cast<nsAutoCString*>(aClosure);
11408 0 : buf->Append(aFromRawSegment, aCount);
11409 :
11410 : // Indicate that we have consumed all of aFromSegment
11411 0 : *aWriteCount = aCount;
11412 0 : return NS_OK;
11413 : }
11414 :
11415 : nsresult
11416 0 : nsDocShell::AddHeadersToChannel(nsIInputStream* aHeadersData,
11417 : nsIChannel* aGenericChannel)
11418 : {
11419 0 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
11420 0 : NS_ENSURE_STATE(httpChannel);
11421 :
11422 : uint32_t numRead;
11423 0 : nsAutoCString headersString;
11424 : nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
11425 : &headersString,
11426 : UINT32_MAX,
11427 0 : &numRead);
11428 0 : NS_ENSURE_SUCCESS(rv, rv);
11429 :
11430 : // used during the manipulation of the String from the InputStream
11431 0 : nsAutoCString headerName;
11432 0 : nsAutoCString headerValue;
11433 : int32_t crlf;
11434 : int32_t colon;
11435 :
11436 : //
11437 : // Iterate over the headersString: for each "\r\n" delimited chunk,
11438 : // add the value as a header to the nsIHttpChannel
11439 : //
11440 :
11441 : static const char kWhitespace[] = "\b\t\r\n ";
11442 : while (true) {
11443 0 : crlf = headersString.Find("\r\n");
11444 0 : if (crlf == kNotFound) {
11445 0 : return NS_OK;
11446 : }
11447 :
11448 0 : const nsACString& oneHeader = StringHead(headersString, crlf);
11449 :
11450 0 : colon = oneHeader.FindChar(':');
11451 0 : if (colon == kNotFound) {
11452 0 : return NS_ERROR_UNEXPECTED;
11453 : }
11454 :
11455 0 : headerName = StringHead(oneHeader, colon);
11456 0 : headerValue = Substring(oneHeader, colon + 1);
11457 :
11458 0 : headerName.Trim(kWhitespace);
11459 0 : headerValue.Trim(kWhitespace);
11460 :
11461 0 : headersString.Cut(0, crlf + 2);
11462 :
11463 : //
11464 : // FINALLY: we can set the header!
11465 : //
11466 :
11467 0 : rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
11468 0 : NS_ENSURE_SUCCESS(rv, rv);
11469 0 : }
11470 :
11471 : NS_NOTREACHED("oops");
11472 : return NS_ERROR_UNEXPECTED;
11473 : }
11474 :
11475 : nsresult
11476 6 : nsDocShell::DoChannelLoad(nsIChannel* aChannel,
11477 : nsIURILoader* aURILoader,
11478 : bool aBypassClassifier)
11479 : {
11480 : nsresult rv;
11481 : // Mark the channel as being a document URI and allow content sniffing...
11482 6 : nsLoadFlags loadFlags = 0;
11483 6 : (void)aChannel->GetLoadFlags(&loadFlags);
11484 6 : loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
11485 6 : nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
11486 :
11487 : // Load attributes depend on load type...
11488 6 : switch (mLoadType) {
11489 : case LOAD_HISTORY: {
11490 : // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
11491 : // push/replaceState (bug 669671).
11492 0 : bool uriModified = false;
11493 0 : if (mLSHE) {
11494 0 : mLSHE->GetURIWasModified(&uriModified);
11495 : }
11496 :
11497 0 : if (!uriModified) {
11498 0 : loadFlags |= nsIRequest::VALIDATE_NEVER;
11499 : }
11500 0 : break;
11501 : }
11502 :
11503 : case LOAD_RELOAD_CHARSET_CHANGE: {
11504 : // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we only want
11505 : // to force cache load for this channel, not the whole loadGroup.
11506 0 : nsCOMPtr<nsICacheInfoChannel> cachingChannel = do_QueryInterface(aChannel);
11507 0 : if (cachingChannel) {
11508 0 : cachingChannel->SetAllowStaleCacheContent(true);
11509 : }
11510 0 : break;
11511 : }
11512 :
11513 : case LOAD_RELOAD_NORMAL:
11514 : case LOAD_REFRESH:
11515 0 : loadFlags |= nsIRequest::VALIDATE_ALWAYS;
11516 0 : break;
11517 :
11518 : case LOAD_NORMAL_BYPASS_CACHE:
11519 : case LOAD_NORMAL_BYPASS_PROXY:
11520 : case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
11521 : case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
11522 : case LOAD_RELOAD_BYPASS_CACHE:
11523 : case LOAD_RELOAD_BYPASS_PROXY:
11524 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
11525 : case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
11526 : case LOAD_REPLACE_BYPASS_CACHE:
11527 0 : loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
11528 0 : nsIRequest::LOAD_FRESH_CONNECTION;
11529 0 : break;
11530 :
11531 : case LOAD_NORMAL:
11532 : case LOAD_LINK:
11533 : // Set cache checking flags
11534 6 : switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
11535 : case 0:
11536 0 : loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
11537 0 : break;
11538 : case 1:
11539 0 : loadFlags |= nsIRequest::VALIDATE_ALWAYS;
11540 0 : break;
11541 : case 2:
11542 0 : loadFlags |= nsIRequest::VALIDATE_NEVER;
11543 0 : break;
11544 : }
11545 6 : break;
11546 : }
11547 :
11548 6 : if (!aBypassClassifier) {
11549 6 : loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
11550 : }
11551 :
11552 : // If the user pressed shift-reload, then do not allow ServiceWorker
11553 : // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
11554 6 : if (IsForceReloadType(mLoadType)) {
11555 0 : loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
11556 : }
11557 :
11558 6 : (void)aChannel->SetLoadFlags(loadFlags);
11559 :
11560 6 : uint32_t openFlags = 0;
11561 6 : if (mLoadType == LOAD_LINK) {
11562 0 : openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
11563 : }
11564 6 : if (!mAllowContentRetargeting) {
11565 0 : openFlags |= nsIURILoader::DONT_RETARGET;
11566 : }
11567 6 : rv = aURILoader->OpenURI(aChannel, openFlags, this);
11568 6 : NS_ENSURE_SUCCESS(rv, rv);
11569 :
11570 6 : return NS_OK;
11571 : }
11572 :
11573 : nsresult
11574 0 : nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
11575 : nsACString& aNewHash, uint32_t aLoadType)
11576 : {
11577 0 : if (!mCurrentURI) {
11578 0 : return NS_OK;
11579 : }
11580 :
11581 0 : nsCOMPtr<nsIPresShell> shell = GetPresShell();
11582 0 : if (!shell) {
11583 : // If we failed to get the shell, or if there is no shell,
11584 : // nothing left to do here.
11585 0 : return NS_OK;
11586 : }
11587 :
11588 0 : nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
11589 0 : if (rootScroll) {
11590 0 : rootScroll->ClearDidHistoryRestore();
11591 : }
11592 :
11593 : // If we have no new anchor, we do not want to scroll, unless there is a
11594 : // current anchor and we are doing a history load. So return if we have no
11595 : // new anchor, and there is no current anchor or the load is not a history
11596 : // load.
11597 0 : if ((!aCurHasRef || aLoadType != LOAD_HISTORY) && !aNewHasRef) {
11598 0 : return NS_OK;
11599 : }
11600 :
11601 : // Both the new and current URIs refer to the same page. We can now
11602 : // browse to the hash stored in the new URI.
11603 :
11604 0 : if (!aNewHash.IsEmpty()) {
11605 : // anchor is there, but if it's a load from history,
11606 : // we don't have any anchor jumping to do
11607 0 : bool scroll = aLoadType != LOAD_HISTORY &&
11608 0 : aLoadType != LOAD_RELOAD_NORMAL;
11609 :
11610 0 : char* str = ToNewCString(aNewHash);
11611 0 : if (!str) {
11612 0 : return NS_ERROR_OUT_OF_MEMORY;
11613 : }
11614 :
11615 : // nsUnescape modifies the string that is passed into it.
11616 0 : nsUnescape(str);
11617 :
11618 : // We assume that the bytes are in UTF-8, as it says in the
11619 : // spec:
11620 : // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
11621 :
11622 : // We try the UTF-8 string first, and then try the document's
11623 : // charset (see below). If the string is not UTF-8,
11624 : // conversion will fail and give us an empty Unicode string.
11625 : // In that case, we should just fall through to using the
11626 : // page's charset.
11627 0 : nsresult rv = NS_ERROR_FAILURE;
11628 0 : NS_ConvertUTF8toUTF16 uStr(str);
11629 0 : if (!uStr.IsEmpty()) {
11630 0 : rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll,
11631 0 : nsIPresShell::SCROLL_SMOOTH_AUTO);
11632 : }
11633 0 : free(str);
11634 :
11635 : // Above will fail if the anchor name is not UTF-8. Need to
11636 : // convert from document charset to unicode.
11637 0 : if (NS_FAILED(rv)) {
11638 : // Get a document charset
11639 0 : NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
11640 0 : nsIDocument* doc = mContentViewer->GetDocument();
11641 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
11642 0 : nsAutoCString charset;
11643 0 : doc->GetDocumentCharacterSet()->Name(charset);
11644 :
11645 : nsCOMPtr<nsITextToSubURI> textToSubURI =
11646 0 : do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
11647 0 : NS_ENSURE_SUCCESS(rv, rv);
11648 :
11649 : // Unescape and convert to unicode
11650 0 : nsAutoString uStr;
11651 :
11652 0 : rv = textToSubURI->UnEscapeAndConvert(charset, aNewHash, uStr);
11653 0 : NS_ENSURE_SUCCESS(rv, rv);
11654 :
11655 : // Ignore return value of GoToAnchor, since it will return an error
11656 : // if there is no such anchor in the document, which is actually a
11657 : // success condition for us (we want to update the session history
11658 : // with the new URI no matter whether we actually scrolled
11659 : // somewhere).
11660 : //
11661 : // When aNewHash contains "%00", unescaped string may be empty.
11662 : // And GoToAnchor asserts if we ask it to scroll to an empty ref.
11663 0 : shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty(),
11664 0 : nsIPresShell::SCROLL_SMOOTH_AUTO);
11665 : }
11666 : } else {
11667 : // Tell the shell it's at an anchor, without scrolling.
11668 0 : shell->GoToAnchor(EmptyString(), false);
11669 :
11670 : // An empty anchor was found, but if it's a load from history,
11671 : // we don't have to jump to the top of the page. Scrollbar
11672 : // position will be restored by the caller, based on positions
11673 : // stored in session history.
11674 0 : if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) {
11675 0 : return NS_OK;
11676 : }
11677 : // An empty anchor. Scroll to the top of the page. Ignore the
11678 : // return value; failure to scroll here (e.g. if there is no
11679 : // root scrollframe) is not grounds for canceling the load!
11680 0 : SetCurScrollPosEx(0, 0);
11681 : }
11682 :
11683 0 : return NS_OK;
11684 : }
11685 :
11686 : void
11687 4 : nsDocShell::SetupReferrerFromChannel(nsIChannel* aChannel)
11688 : {
11689 8 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11690 4 : if (httpChannel) {
11691 2 : nsCOMPtr<nsIURI> referrer;
11692 1 : nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
11693 1 : if (NS_SUCCEEDED(rv)) {
11694 1 : SetReferrerURI(referrer);
11695 : }
11696 : uint32_t referrerPolicy;
11697 1 : rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
11698 1 : if (NS_SUCCEEDED(rv)) {
11699 1 : SetReferrerPolicy(referrerPolicy);
11700 : }
11701 : }
11702 4 : }
11703 :
11704 : bool
11705 4 : nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
11706 : nsIPrincipal* aTriggeringPrincipal,
11707 : nsIPrincipal* aPrincipalToInherit,
11708 : uint32_t aLoadType, bool aFireOnLocationChange,
11709 : bool aAddToGlobalHistory, bool aCloneSHChildren)
11710 : {
11711 4 : NS_PRECONDITION(aURI, "uri is null");
11712 4 : NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
11713 :
11714 4 : MOZ_ASSERT(!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal));
11715 :
11716 : #if defined(DEBUG)
11717 4 : if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
11718 0 : nsAutoCString chanName;
11719 0 : if (aChannel) {
11720 0 : aChannel->GetName(chanName);
11721 : } else {
11722 0 : chanName.AssignLiteral("<no channel>");
11723 : }
11724 :
11725 0 : MOZ_LOG(gDocShellLog, LogLevel::Debug,
11726 : ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n",
11727 : this, aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType));
11728 : }
11729 : #endif
11730 :
11731 4 : bool equalUri = false;
11732 :
11733 : // Get the post data and the HTTP response code from the channel.
11734 4 : uint32_t responseStatus = 0;
11735 8 : nsCOMPtr<nsIInputStream> inputStream;
11736 4 : if (aChannel) {
11737 8 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
11738 :
11739 : // Check if the HTTPChannel is hiding under a multiPartChannel
11740 4 : if (!httpChannel) {
11741 3 : GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
11742 : }
11743 :
11744 4 : if (httpChannel) {
11745 2 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
11746 1 : if (uploadChannel) {
11747 1 : uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
11748 : }
11749 :
11750 : // If the response status indicates an error, unlink this session
11751 : // history entry from any entries sharing its document.
11752 1 : nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
11753 1 : if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
11754 0 : mLSHE->AbandonBFCacheEntry();
11755 : }
11756 : }
11757 : }
11758 :
11759 : // Determine if this type of load should update history.
11760 8 : bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY ||
11761 : aLoadType == LOAD_ERROR_PAGE ||
11762 8 : aLoadType & LOAD_CMD_HISTORY);
11763 :
11764 : // We don't update session history on reload unless we're loading
11765 : // an iframe in shift-reload case.
11766 12 : bool updateSHistory = updateGHistory &&
11767 4 : (!(aLoadType & LOAD_CMD_RELOAD) ||
11768 4 : (IsForceReloadType(aLoadType) && IsFrame()));
11769 :
11770 : // Create SH Entry (mLSHE) only if there is a SessionHistory object in the
11771 : // current frame or in the root docshell.
11772 8 : nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
11773 4 : if (!rootSH) {
11774 : // Get the handle to SH from the root docshell
11775 3 : GetRootSessionHistory(getter_AddRefs(rootSH));
11776 3 : if (!rootSH) {
11777 3 : updateSHistory = false;
11778 3 : updateGHistory = false; // XXX Why global history too?
11779 : }
11780 : }
11781 :
11782 : // Check if the url to be loaded is the same as the one already loaded.
11783 4 : if (mCurrentURI) {
11784 3 : aURI->Equals(mCurrentURI, &equalUri);
11785 : }
11786 :
11787 : #ifdef DEBUG
11788 4 : bool shAvailable = (rootSH != nullptr);
11789 :
11790 : // XXX This log message is almost useless because |updateSHistory|
11791 : // and |updateGHistory| are not correct at this point.
11792 :
11793 4 : MOZ_LOG(gDocShellLog, LogLevel::Debug,
11794 : (" shAvailable=%i updateSHistory=%i updateGHistory=%i"
11795 : " equalURI=%i\n",
11796 : shAvailable, updateSHistory, updateGHistory, equalUri));
11797 :
11798 4 : if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
11799 : // XXX mCurrentURI can be changed from any caller regardless what actual
11800 : // loaded document is, so testing mCurrentURI isn't really a reliable way.
11801 : // Session restore is one example which changes current URI in order to
11802 : // show address before loading. See bug 1301399.
11803 1 : NS_ASSERTION(NS_IsAboutBlank(mCurrentURI),
11804 : "no SHEntry for a non-transient viewer?");
11805 : }
11806 : #endif
11807 :
11808 : /* If the url to be loaded is the same as the one already there,
11809 : * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
11810 : * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
11811 : * AddToSessionHistory() won't mess with the current SHEntry and
11812 : * if this page has any frame children, it also will be handled
11813 : * properly. see bug 83684
11814 : *
11815 : * NB: If mOSHE is null but we have a current URI, then it means
11816 : * that we must be at the transient about:blank content viewer
11817 : * (asserted above) and we should let the normal load continue,
11818 : * since there's nothing to replace.
11819 : *
11820 : * XXX Hopefully changing the loadType at this time will not hurt
11821 : * anywhere. The other way to take care of sequentially repeating
11822 : * frameset pages is to add new methods to nsIDocShellTreeItem.
11823 : * Hopefully I don't have to do that.
11824 : */
11825 4 : if (equalUri &&
11826 0 : mOSHE &&
11827 0 : (mLoadType == LOAD_NORMAL ||
11828 0 : mLoadType == LOAD_LINK ||
11829 4 : mLoadType == LOAD_STOP_CONTENT) &&
11830 0 : !inputStream) {
11831 0 : mLoadType = LOAD_NORMAL_REPLACE;
11832 : }
11833 :
11834 : // If this is a refresh to the currently loaded url, we don't
11835 : // have to update session or global history.
11836 4 : if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
11837 0 : SetHistoryEntry(&mLSHE, mOSHE);
11838 : }
11839 :
11840 : /* If the user pressed shift-reload, cache will create a new cache key
11841 : * for the page. Save the new cacheKey in Session History.
11842 : * see bug 90098
11843 : */
11844 4 : if (aChannel && IsForceReloadType(aLoadType)) {
11845 0 : MOZ_ASSERT(!updateSHistory || IsFrame(),
11846 : "We shouldn't be updating session history for forced"
11847 : " reloads unless we're in a newly created iframe!");
11848 :
11849 0 : nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aChannel));
11850 0 : nsCOMPtr<nsISupports> cacheKey;
11851 : // Get the Cache Key and store it in SH.
11852 0 : if (cacheChannel) {
11853 0 : cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
11854 : }
11855 : // If we already have a loading history entry, store the new cache key
11856 : // in it. Otherwise, since we're doing a reload and won't be updating
11857 : // our history entry, store the cache key in our current history entry.
11858 0 : if (mLSHE) {
11859 0 : mLSHE->SetCacheKey(cacheKey);
11860 0 : } else if (mOSHE) {
11861 0 : mOSHE->SetCacheKey(cacheKey);
11862 : }
11863 : }
11864 :
11865 : // Clear subframe history on refresh or reload.
11866 : // XXX: history.go(0) won't go this path as aLoadType is LOAD_HISTORY in this
11867 : // case. One should re-validate after bug 1331865 fixed.
11868 4 : if (aLoadType == LOAD_REFRESH || (aLoadType & LOAD_CMD_RELOAD)) {
11869 0 : ClearFrameHistory(mLSHE);
11870 0 : ClearFrameHistory(mOSHE);
11871 : }
11872 :
11873 4 : if (updateSHistory) {
11874 : // Update session history if necessary...
11875 1 : if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
11876 : /* This is a fresh page getting loaded for the first time
11877 : *.Create a Entry for it and add it to SH, if this is the
11878 : * rootDocShell
11879 : */
11880 1 : (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal,
11881 : aPrincipalToInherit, aCloneSHChildren,
11882 2 : getter_AddRefs(mLSHE));
11883 : }
11884 3 : } else if (mSessionHistory && mLSHE && mURIResultedInDocument) {
11885 : // Even if we don't add anything to SHistory, ensure the current index
11886 : // points to the same SHEntry as our mLSHE.
11887 0 : int32_t index = 0;
11888 0 : mSessionHistory->GetRequestedIndex(&index);
11889 0 : if (index == -1) {
11890 0 : mSessionHistory->GetIndex(&index);
11891 : }
11892 0 : nsCOMPtr<nsISHEntry> currentSH;
11893 0 : mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(currentSH));
11894 0 : if (currentSH != mLSHE) {
11895 : nsCOMPtr<nsISHistoryInternal> shPrivate =
11896 0 : do_QueryInterface(mSessionHistory);
11897 0 : shPrivate->ReplaceEntry(index, mLSHE);
11898 : }
11899 : }
11900 :
11901 : // If this is a POST request, we do not want to include this in global
11902 : // history.
11903 4 : if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) {
11904 2 : nsCOMPtr<nsIURI> previousURI;
11905 1 : uint32_t previousFlags = 0;
11906 :
11907 1 : if (aLoadType & LOAD_CMD_RELOAD) {
11908 : // On a reload request, we don't set redirecting flags.
11909 0 : previousURI = aURI;
11910 : } else {
11911 1 : ExtractLastVisit(aChannel, getter_AddRefs(previousURI), &previousFlags);
11912 : }
11913 :
11914 : // Note: We don't use |referrer| when our global history is
11915 : // based on IHistory.
11916 2 : nsCOMPtr<nsIURI> referrer;
11917 : // Treat referrer as null if there is an error getting it.
11918 1 : (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
11919 :
11920 1 : AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
11921 : }
11922 :
11923 : // If this was a history load or a refresh, or it was a history load but
11924 : // later changed to LOAD_NORMAL_REPLACE due to redirection, update the index
11925 : // in session history.
11926 5 : if (rootSH &&
11927 2 : ((mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD)) ||
11928 5 : mLoadType == LOAD_NORMAL_REPLACE)) {
11929 0 : nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
11930 0 : if (shInternal) {
11931 0 : rootSH->GetIndex(&mPreviousTransIndex);
11932 0 : shInternal->UpdateIndex();
11933 0 : rootSH->GetIndex(&mLoadedTransIndex);
11934 : #ifdef DEBUG_PAGE_CACHE
11935 : printf("Previous index: %d, Loaded index: %d\n\n",
11936 : mPreviousTransIndex, mLoadedTransIndex);
11937 : #endif
11938 : }
11939 : }
11940 :
11941 : // aCloneSHChildren exactly means "we are not loading a new document".
11942 : uint32_t locationFlags =
11943 4 : aCloneSHChildren ? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
11944 :
11945 4 : bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
11946 : aFireOnLocationChange,
11947 4 : locationFlags);
11948 : // Make sure to store the referrer from the channel, if any
11949 4 : SetupReferrerFromChannel(aChannel);
11950 8 : return onLocationChangeNeeded;
11951 : }
11952 :
11953 : bool
11954 4 : nsDocShell::OnLoadingSite(nsIChannel* aChannel, bool aFireOnLocationChange,
11955 : bool aAddToGlobalHistory)
11956 : {
11957 8 : nsCOMPtr<nsIURI> uri;
11958 : // If this a redirect, use the final url (uri)
11959 : // else use the original url
11960 : //
11961 : // Note that this should match what documents do (see nsDocument::Reset).
11962 4 : NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
11963 4 : NS_ENSURE_TRUE(uri, false);
11964 :
11965 : // Pass false for aCloneSHChildren, since we're loading a new page here.
11966 4 : return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType, aFireOnLocationChange,
11967 4 : aAddToGlobalHistory, false);
11968 : }
11969 :
11970 : void
11971 1 : nsDocShell::SetReferrerURI(nsIURI* aURI)
11972 : {
11973 1 : mReferrerURI = aURI; // This assigment addrefs
11974 1 : }
11975 :
11976 : void
11977 1 : nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy)
11978 : {
11979 1 : mReferrerPolicy = aReferrerPolicy;
11980 1 : }
11981 :
11982 : //*****************************************************************************
11983 : // nsDocShell: Session History
11984 : //*****************************************************************************
11985 :
11986 : NS_IMETHODIMP
11987 0 : nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
11988 : const nsAString& aURL, bool aReplace, JSContext* aCx)
11989 : {
11990 : // Implements History.pushState and History.replaceState
11991 :
11992 : // Here's what we do, roughly in the order specified by HTML5:
11993 : // 1. Serialize aData using structured clone.
11994 : // 2. If the third argument is present,
11995 : // a. Resolve the url, relative to the first script's base URL
11996 : // b. If (a) fails, raise a SECURITY_ERR
11997 : // c. Compare the resulting absolute URL to the document's address. If
11998 : // any part of the URLs difer other than the <path>, <query>, and
11999 : // <fragment> components, raise a SECURITY_ERR and abort.
12000 : // 3. If !aReplace:
12001 : // Remove from the session history all entries after the current entry,
12002 : // as we would after a regular navigation, and save the current
12003 : // entry's scroll position (bug 590573).
12004 : // 4. As apropriate, either add a state object entry to the session history
12005 : // after the current entry with the following properties, or modify the
12006 : // current session history entry to set
12007 : // a. cloned data as the state object,
12008 : // b. if the third argument was present, the absolute URL found in
12009 : // step 2
12010 : // Also clear the new history entry's POST data (see bug 580069).
12011 : // 5. If aReplace is false (i.e. we're doing a pushState instead of a
12012 : // replaceState), notify bfcache that we've navigated to a new page.
12013 : // 6. If the third argument is present, set the document's current address
12014 : // to the absolute URL found in step 2.
12015 : //
12016 : // It's important that this function not run arbitrary scripts after step 1
12017 : // and before completing step 5. For example, if a script called
12018 : // history.back() before we completed step 5, bfcache might destroy an
12019 : // active content viewer. Since EvictOutOfRangeContentViewers at the end of
12020 : // step 5 might run script, we can't just put a script blocker around the
12021 : // critical section.
12022 : //
12023 : // Note that we completely ignore the aTitle parameter.
12024 :
12025 : nsresult rv;
12026 :
12027 : // Don't clobber the load type of an existing network load.
12028 0 : AutoRestore<uint32_t> loadTypeResetter(mLoadType);
12029 :
12030 : // pushState effectively becomes replaceState when we've started a network
12031 : // load but haven't adopted its document yet. This mirrors what we do with
12032 : // changes to the hash at this stage of the game.
12033 0 : if (JustStartedNetworkLoad()) {
12034 0 : aReplace = true;
12035 : }
12036 :
12037 0 : nsCOMPtr<nsIDocument> document = GetDocument();
12038 0 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
12039 :
12040 : // Step 1: Serialize aData using structured clone.
12041 0 : nsCOMPtr<nsIStructuredCloneContainer> scContainer;
12042 :
12043 : // scContainer->Init might cause arbitrary JS to run, and this code might
12044 : // navigate the page we're on, potentially to a different origin! (bug
12045 : // 634834) To protect against this, we abort if our principal changes due
12046 : // to the InitFromJSVal() call.
12047 : {
12048 0 : nsCOMPtr<nsIDocument> origDocument = GetDocument();
12049 0 : if (!origDocument) {
12050 0 : return NS_ERROR_DOM_SECURITY_ERR;
12051 : }
12052 0 : nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
12053 :
12054 0 : scContainer = new nsStructuredCloneContainer();
12055 0 : rv = scContainer->InitFromJSVal(aData, aCx);
12056 0 : NS_ENSURE_SUCCESS(rv, rv);
12057 :
12058 0 : nsCOMPtr<nsIDocument> newDocument = GetDocument();
12059 0 : if (!newDocument) {
12060 0 : return NS_ERROR_DOM_SECURITY_ERR;
12061 : }
12062 0 : nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
12063 :
12064 0 : bool principalsEqual = false;
12065 0 : origPrincipal->Equals(newPrincipal, &principalsEqual);
12066 0 : NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
12067 : }
12068 :
12069 : // Check that the state object isn't too long.
12070 : // Default max length: 640k bytes.
12071 : int32_t maxStateObjSize =
12072 0 : Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
12073 0 : if (maxStateObjSize < 0) {
12074 0 : maxStateObjSize = 0;
12075 : }
12076 :
12077 : uint64_t scSize;
12078 0 : rv = scContainer->GetSerializedNBytes(&scSize);
12079 0 : NS_ENSURE_SUCCESS(rv, rv);
12080 :
12081 0 : NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, NS_ERROR_ILLEGAL_VALUE);
12082 :
12083 : // Step 2: Resolve aURL
12084 0 : bool equalURIs = true;
12085 0 : nsCOMPtr<nsIURI> currentURI;
12086 0 : if (sURIFixup && mCurrentURI) {
12087 0 : rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(currentURI));
12088 0 : NS_ENSURE_SUCCESS(rv, rv);
12089 : } else {
12090 0 : currentURI = mCurrentURI;
12091 : }
12092 0 : nsCOMPtr<nsIURI> oldURI = currentURI;
12093 0 : nsCOMPtr<nsIURI> newURI;
12094 0 : if (aURL.Length() == 0) {
12095 0 : newURI = currentURI;
12096 : } else {
12097 : // 2a: Resolve aURL relative to mURI
12098 :
12099 0 : nsIURI* docBaseURI = document->GetDocBaseURI();
12100 0 : if (!docBaseURI) {
12101 0 : return NS_ERROR_FAILURE;
12102 : }
12103 :
12104 0 : nsAutoCString spec;
12105 0 : docBaseURI->GetSpec(spec);
12106 :
12107 0 : nsAutoCString charset;
12108 0 : rv = docBaseURI->GetOriginCharset(charset);
12109 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
12110 :
12111 0 : rv = NS_NewURI(getter_AddRefs(newURI), aURL, charset.get(), docBaseURI);
12112 :
12113 : // 2b: If 2a fails, raise a SECURITY_ERR
12114 0 : if (NS_FAILED(rv)) {
12115 0 : return NS_ERROR_DOM_SECURITY_ERR;
12116 : }
12117 :
12118 : // 2c: Same-origin check.
12119 0 : if (!nsContentUtils::URIIsLocalFile(newURI)) {
12120 : // In addition to checking that the security manager says that
12121 : // the new URI has the same origin as our current URI, we also
12122 : // check that the two URIs have the same userpass. (The
12123 : // security manager says that |http://foo.com| and
12124 : // |http://me@foo.com| have the same origin.) currentURI
12125 : // won't contain the password part of the userpass, so this
12126 : // means that it's never valid to specify a password in a
12127 : // pushState or replaceState URI.
12128 :
12129 : nsCOMPtr<nsIScriptSecurityManager> secMan =
12130 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
12131 0 : NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
12132 :
12133 : // It's very important that we check that newURI is of the same
12134 : // origin as currentURI, not docBaseURI, because a page can
12135 : // set docBaseURI arbitrarily to any domain.
12136 0 : nsAutoCString currentUserPass, newUserPass;
12137 0 : NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
12138 : NS_ERROR_FAILURE);
12139 0 : NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), NS_ERROR_FAILURE);
12140 0 : if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, newURI, true)) ||
12141 0 : !currentUserPass.Equals(newUserPass)) {
12142 0 : return NS_ERROR_DOM_SECURITY_ERR;
12143 : }
12144 : } else {
12145 : // It's a file:// URI
12146 : nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
12147 0 : do_QueryInterface(document);
12148 :
12149 0 : if (!docScriptObj) {
12150 0 : return NS_ERROR_DOM_SECURITY_ERR;
12151 : }
12152 :
12153 0 : nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
12154 :
12155 0 : if (!principal ||
12156 0 : NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
12157 0 : return NS_ERROR_DOM_SECURITY_ERR;
12158 : }
12159 : }
12160 :
12161 0 : if (currentURI) {
12162 0 : currentURI->Equals(newURI, &equalURIs);
12163 : } else {
12164 0 : equalURIs = false;
12165 : }
12166 :
12167 : } // end of same-origin check
12168 :
12169 : // Step 3: Create a new entry in the session history. This will erase
12170 : // all SHEntries after the new entry and make this entry the current
12171 : // one. This operation may modify mOSHE, which we need later, so we
12172 : // keep a reference here.
12173 0 : NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
12174 0 : nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
12175 :
12176 0 : mLoadType = LOAD_PUSHSTATE;
12177 :
12178 0 : nsCOMPtr<nsISHEntry> newSHEntry;
12179 0 : if (!aReplace) {
12180 : // Save the current scroll position (bug 590573).
12181 0 : nscoord cx = 0, cy = 0;
12182 0 : GetCurScrollPos(ScrollOrientation_X, &cx);
12183 0 : GetCurScrollPos(ScrollOrientation_Y, &cy);
12184 0 : mOSHE->SetScrollPosition(cx, cy);
12185 :
12186 0 : bool scrollRestorationIsManual = false;
12187 0 : mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
12188 :
12189 : // Since we're not changing which page we have loaded, pass
12190 : // true for aCloneChildren.
12191 0 : rv = AddToSessionHistory(newURI, nullptr,
12192 0 : document->NodePrincipal(), // triggeringPrincipal
12193 : nullptr, true,
12194 0 : getter_AddRefs(newSHEntry));
12195 0 : NS_ENSURE_SUCCESS(rv, rv);
12196 :
12197 0 : NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
12198 :
12199 : // Session history entries created by pushState inherit scroll restoration
12200 : // mode from the current entry.
12201 0 : newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
12202 :
12203 : // Link the new SHEntry to the old SHEntry's BFCache entry, since the
12204 : // two entries correspond to the same document.
12205 0 : NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE);
12206 :
12207 : // Set the new SHEntry's title (bug 655273).
12208 0 : nsString title;
12209 0 : mOSHE->GetTitle(getter_Copies(title));
12210 0 : newSHEntry->SetTitle(title);
12211 :
12212 : // AddToSessionHistory may not modify mOSHE. In case it doesn't,
12213 : // we'll just set mOSHE here.
12214 0 : mOSHE = newSHEntry;
12215 :
12216 : } else {
12217 0 : newSHEntry = mOSHE;
12218 0 : newSHEntry->SetURI(newURI);
12219 0 : newSHEntry->SetOriginalURI(newURI);
12220 0 : newSHEntry->SetLoadReplace(false);
12221 : }
12222 :
12223 : // Step 4: Modify new/original session history entry and clear its POST
12224 : // data, if there is any.
12225 0 : newSHEntry->SetStateData(scContainer);
12226 0 : newSHEntry->SetPostData(nullptr);
12227 :
12228 : // If this push/replaceState changed the document's current URI and the new
12229 : // URI differs from the old URI in more than the hash, or if the old
12230 : // SHEntry's URI was modified in this way by a push/replaceState call
12231 : // set URIWasModified to true for the current SHEntry (bug 669671).
12232 0 : bool sameExceptHashes = true, oldURIWasModified = false;
12233 0 : newURI->EqualsExceptRef(currentURI, &sameExceptHashes);
12234 0 : oldOSHE->GetURIWasModified(&oldURIWasModified);
12235 0 : newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
12236 :
12237 : // Step 5: If aReplace is false, indicating that we're doing a pushState
12238 : // rather than a replaceState, notify bfcache that we've added a page to
12239 : // the history so it can evict content viewers if appropriate. Otherwise
12240 : // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
12241 : // was replaced.
12242 0 : nsCOMPtr<nsISHistory> rootSH;
12243 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
12244 0 : NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
12245 :
12246 0 : nsCOMPtr<nsISHistoryInternal> internalSH = do_QueryInterface(rootSH);
12247 0 : NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
12248 :
12249 0 : if (!aReplace) {
12250 0 : int32_t curIndex = -1;
12251 0 : rv = rootSH->GetIndex(&curIndex);
12252 0 : if (NS_SUCCEEDED(rv) && curIndex > -1) {
12253 0 : internalSH->EvictOutOfRangeContentViewers(curIndex);
12254 : }
12255 : } else {
12256 0 : nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry);
12257 :
12258 0 : int32_t index = -1;
12259 0 : rv = rootSH->GetIndexOfEntry(rootSHEntry, &index);
12260 0 : if (NS_SUCCEEDED(rv) && index > -1) {
12261 0 : internalSH->ReplaceEntry(index, rootSHEntry);
12262 : }
12263 : }
12264 :
12265 : // Step 6: If the document's URI changed, update document's URI and update
12266 : // global history.
12267 : //
12268 : // We need to call FireOnLocationChange so that the browser's address bar
12269 : // gets updated and the back button is enabled, but we only need to
12270 : // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
12271 : // since SetCurrentURI will call FireOnLocationChange for us.
12272 : //
12273 : // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
12274 : // nullptr for aRequest param to FireOnLocationChange(...). Such an update
12275 : // notification is allowed only when we know docshell is not loading a new
12276 : // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
12277 : // FireOnLocationChange(...) breaks security UI.
12278 0 : if (!equalURIs) {
12279 0 : document->SetDocumentURI(newURI);
12280 : // We can't trust SetCurrentURI to do always fire locationchange events
12281 : // when we expect it to, so we hack around that by doing it ourselves...
12282 0 : SetCurrentURI(newURI, nullptr, false, LOCATION_CHANGE_SAME_DOCUMENT);
12283 0 : if (mLoadType != LOAD_ERROR_PAGE) {
12284 0 : FireDummyOnLocationChange();
12285 : }
12286 :
12287 0 : AddURIVisit(newURI, oldURI, oldURI, 0);
12288 :
12289 : // AddURIVisit doesn't set the title for the new URI in global history,
12290 : // so do that here.
12291 0 : UpdateGlobalHistoryTitle(newURI);
12292 :
12293 : // Inform the favicon service that our old favicon applies to this new
12294 : // URI.
12295 0 : CopyFavicon(oldURI, newURI, document->NodePrincipal(), UsePrivateBrowsing());
12296 : } else {
12297 0 : FireDummyOnLocationChange();
12298 : }
12299 0 : document->SetStateObject(scContainer);
12300 :
12301 0 : return NS_OK;
12302 : }
12303 :
12304 : NS_IMETHODIMP
12305 0 : nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual)
12306 : {
12307 0 : *aIsManual = false;
12308 0 : if (mOSHE) {
12309 0 : mOSHE->GetScrollRestorationIsManual(aIsManual);
12310 : }
12311 :
12312 0 : return NS_OK;
12313 : }
12314 :
12315 : NS_IMETHODIMP
12316 0 : nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual)
12317 : {
12318 0 : if (mOSHE) {
12319 0 : mOSHE->SetScrollRestorationIsManual(aIsManual);
12320 : }
12321 :
12322 0 : return NS_OK;
12323 : }
12324 :
12325 : bool
12326 1 : nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI)
12327 : {
12328 : // I believe none of the about: urls should go in the history. But then
12329 : // that could just be me... If the intent is only deny about:blank then we
12330 : // should just do a spec compare, rather than two gets of the scheme and
12331 : // then the path. -Gagan
12332 : nsresult rv;
12333 2 : nsAutoCString buf;
12334 :
12335 1 : rv = aURI->GetScheme(buf);
12336 1 : if (NS_FAILED(rv)) {
12337 0 : return false;
12338 : }
12339 :
12340 1 : if (buf.EqualsLiteral("about")) {
12341 0 : rv = aURI->GetPath(buf);
12342 0 : if (NS_FAILED(rv)) {
12343 0 : return false;
12344 : }
12345 :
12346 0 : if (buf.EqualsLiteral("blank") || buf.EqualsLiteral("newtab")) {
12347 0 : return false;
12348 : }
12349 : }
12350 :
12351 1 : return true;
12352 : }
12353 :
12354 : nsresult
12355 1 : nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
12356 : nsIPrincipal* aTriggeringPrincipal,
12357 : nsIPrincipal* aPrincipalToInherit,
12358 : bool aCloneChildren,
12359 : nsISHEntry** aNewEntry)
12360 : {
12361 1 : NS_PRECONDITION(aURI, "uri is null");
12362 1 : NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
12363 :
12364 : #if defined(DEBUG)
12365 1 : if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
12366 0 : nsAutoCString chanName;
12367 0 : if (aChannel) {
12368 0 : aChannel->GetName(chanName);
12369 : } else {
12370 0 : chanName.AssignLiteral("<no channel>");
12371 : }
12372 :
12373 0 : MOZ_LOG(gDocShellLog, LogLevel::Debug,
12374 : ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
12375 : this, aURI->GetSpecOrDefault().get(), chanName.get()));
12376 : }
12377 : #endif
12378 :
12379 1 : nsresult rv = NS_OK;
12380 2 : nsCOMPtr<nsISHEntry> entry;
12381 : bool shouldPersist;
12382 :
12383 1 : shouldPersist = ShouldAddToSessionHistory(aURI);
12384 :
12385 : // Get a handle to the root docshell
12386 2 : nsCOMPtr<nsIDocShellTreeItem> root;
12387 1 : GetSameTypeRootTreeItem(getter_AddRefs(root));
12388 : /*
12389 : * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
12390 : * the existing SH entry in the page and replace the url and
12391 : * other vitalities.
12392 : */
12393 1 : if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
12394 0 : root != static_cast<nsIDocShellTreeItem*>(this)) {
12395 : // This is a subframe
12396 0 : entry = mOSHE;
12397 0 : nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
12398 0 : if (shContainer) {
12399 0 : int32_t childCount = 0;
12400 0 : shContainer->GetChildCount(&childCount);
12401 : // Remove all children of this entry
12402 0 : for (int32_t i = childCount - 1; i >= 0; i--) {
12403 0 : nsCOMPtr<nsISHEntry> child;
12404 0 : shContainer->GetChildAt(i, getter_AddRefs(child));
12405 0 : shContainer->RemoveChild(child);
12406 : }
12407 0 : entry->AbandonBFCacheEntry();
12408 : }
12409 : }
12410 :
12411 : // Create a new entry if necessary.
12412 1 : if (!entry) {
12413 1 : entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
12414 :
12415 1 : if (!entry) {
12416 0 : return NS_ERROR_OUT_OF_MEMORY;
12417 : }
12418 : }
12419 :
12420 : // Get the post data & referrer
12421 2 : nsCOMPtr<nsIInputStream> inputStream;
12422 2 : nsCOMPtr<nsIURI> originalURI;
12423 2 : nsCOMPtr<nsIURI> resultPrincipalURI;
12424 1 : bool loadReplace = false;
12425 2 : nsCOMPtr<nsIURI> referrerURI;
12426 1 : uint32_t referrerPolicy = mozilla::net::RP_Unset;
12427 2 : nsCOMPtr<nsISupports> cacheKey;
12428 2 : nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
12429 2 : nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
12430 1 : bool expired = false;
12431 1 : bool discardLayoutState = false;
12432 2 : nsCOMPtr<nsICacheInfoChannel> cacheChannel;
12433 1 : if (aChannel) {
12434 1 : cacheChannel = do_QueryInterface(aChannel);
12435 :
12436 : /* If there is a caching channel, get the Cache Key and store it
12437 : * in SH.
12438 : */
12439 1 : if (cacheChannel) {
12440 1 : cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
12441 : }
12442 2 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
12443 :
12444 : // Check if the httpChannel is hiding under a multipartChannel
12445 1 : if (!httpChannel) {
12446 0 : GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
12447 : }
12448 1 : if (httpChannel) {
12449 2 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
12450 1 : if (uploadChannel) {
12451 1 : uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
12452 : }
12453 1 : httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
12454 : uint32_t loadFlags;
12455 1 : aChannel->GetLoadFlags(&loadFlags);
12456 1 : loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
12457 1 : rv = httpChannel->GetReferrer(getter_AddRefs(referrerURI));
12458 1 : MOZ_ASSERT(NS_SUCCEEDED(rv));
12459 1 : rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
12460 1 : MOZ_ASSERT(NS_SUCCEEDED(rv));
12461 :
12462 1 : discardLayoutState = ShouldDiscardLayoutState(httpChannel);
12463 : }
12464 :
12465 2 : nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
12466 1 : if (loadInfo) {
12467 1 : if (!triggeringPrincipal) {
12468 1 : triggeringPrincipal = loadInfo->TriggeringPrincipal();
12469 : }
12470 :
12471 1 : loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
12472 :
12473 : // For now keep storing just the principal in the SHEntry.
12474 1 : if (!principalToInherit) {
12475 1 : if (loadInfo->GetLoadingSandboxed()) {
12476 0 : if (loadInfo->LoadingPrincipal()) {
12477 0 : principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
12478 0 : loadInfo->LoadingPrincipal());
12479 : } else {
12480 : // get the OriginAttributes
12481 0 : OriginAttributes attrs;
12482 0 : loadInfo->GetOriginAttributes(&attrs);
12483 0 : principalToInherit = NullPrincipal::Create(attrs);
12484 : }
12485 : } else {
12486 1 : principalToInherit = loadInfo->PrincipalToInherit();
12487 : }
12488 : }
12489 : }
12490 : }
12491 :
12492 : // Title is set in nsDocShell::SetTitle()
12493 3 : entry->Create(aURI, // uri
12494 1 : EmptyString(), // Title
12495 : inputStream, // Post data stream
12496 : nullptr, // LayoutHistory state
12497 : cacheKey, // CacheKey
12498 : mContentTypeHint, // Content-type
12499 : triggeringPrincipal, // Channel or provided principal
12500 : principalToInherit,
12501 : mHistoryID,
12502 2 : mDynamicallyCreated);
12503 :
12504 1 : entry->SetOriginalURI(originalURI);
12505 1 : entry->SetResultPrincipalURI(resultPrincipalURI);
12506 1 : entry->SetLoadReplace(loadReplace);
12507 1 : entry->SetReferrerURI(referrerURI);
12508 1 : entry->SetReferrerPolicy(referrerPolicy);
12509 2 : nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
12510 1 : if (inStrmChan) {
12511 : bool isSrcdocChannel;
12512 0 : inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
12513 0 : if (isSrcdocChannel) {
12514 0 : nsAutoString srcdoc;
12515 0 : inStrmChan->GetSrcdocData(srcdoc);
12516 0 : entry->SetSrcdocData(srcdoc);
12517 0 : nsCOMPtr<nsIURI> baseURI;
12518 0 : inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
12519 0 : entry->SetBaseURI(baseURI);
12520 : }
12521 : }
12522 : /* If cache got a 'no-store', ask SH not to store
12523 : * HistoryLayoutState. By default, SH will set this
12524 : * flag to true and save HistoryLayoutState.
12525 : */
12526 1 : if (discardLayoutState) {
12527 0 : entry->SetSaveLayoutStateFlag(false);
12528 : }
12529 1 : if (cacheChannel) {
12530 : // Check if the page has expired from cache
12531 1 : uint32_t expTime = 0;
12532 1 : cacheChannel->GetCacheTokenExpirationTime(&expTime);
12533 1 : uint32_t now = PRTimeToSeconds(PR_Now());
12534 1 : if (expTime <= now) {
12535 0 : expired = true;
12536 : }
12537 : }
12538 1 : if (expired) {
12539 0 : entry->SetExpirationStatus(true);
12540 : }
12541 :
12542 1 : if (root == static_cast<nsIDocShellTreeItem*>(this) && mSessionHistory) {
12543 : // If we need to clone our children onto the new session
12544 : // history entry, do so now.
12545 1 : if (aCloneChildren && mOSHE) {
12546 : uint32_t cloneID;
12547 0 : mOSHE->GetID(&cloneID);
12548 0 : nsCOMPtr<nsISHEntry> newEntry;
12549 0 : CloneAndReplace(mOSHE, this, cloneID, entry, true,
12550 0 : getter_AddRefs(newEntry));
12551 0 : NS_ASSERTION(entry == newEntry,
12552 : "The new session history should be in the new entry");
12553 : }
12554 :
12555 : // This is the root docshell
12556 1 : bool addToSHistory = !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY);
12557 1 : if (!addToSHistory) {
12558 : // Replace current entry in session history; If the requested index is
12559 : // valid, it indicates the loading was triggered by a history load, and
12560 : // we should replace the entry at requested index instead.
12561 0 : int32_t index = 0;
12562 0 : mSessionHistory->GetRequestedIndex(&index);
12563 0 : if (index == -1) {
12564 0 : mSessionHistory->GetIndex(&index);
12565 : }
12566 : nsCOMPtr<nsISHistoryInternal> shPrivate =
12567 0 : do_QueryInterface(mSessionHistory);
12568 : // Replace the current entry with the new entry
12569 0 : if (index >= 0) {
12570 0 : if (shPrivate) {
12571 0 : rv = shPrivate->ReplaceEntry(index, entry);
12572 : }
12573 : } else {
12574 : // If we're trying to replace an inexistant shistory entry, append.
12575 0 : addToSHistory = true;
12576 : }
12577 : }
12578 :
12579 1 : if (addToSHistory) {
12580 : // Add to session history
12581 : nsCOMPtr<nsISHistoryInternal> shPrivate =
12582 2 : do_QueryInterface(mSessionHistory);
12583 1 : NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
12584 1 : mSessionHistory->GetIndex(&mPreviousTransIndex);
12585 1 : rv = shPrivate->AddEntry(entry, shouldPersist);
12586 1 : mSessionHistory->GetIndex(&mLoadedTransIndex);
12587 : #ifdef DEBUG_PAGE_CACHE
12588 : printf("Previous index: %d, Loaded index: %d\n\n",
12589 : mPreviousTransIndex, mLoadedTransIndex);
12590 : #endif
12591 : }
12592 : } else {
12593 : // This is a subframe.
12594 0 : if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
12595 0 : rv = AddChildSHEntryToParent(entry, mChildOffset, aCloneChildren);
12596 : }
12597 : }
12598 :
12599 : // Return the new SH entry...
12600 1 : if (aNewEntry) {
12601 1 : *aNewEntry = nullptr;
12602 1 : if (NS_SUCCEEDED(rv)) {
12603 1 : entry.forget(aNewEntry);
12604 : }
12605 : }
12606 :
12607 1 : return rv;
12608 : }
12609 :
12610 : nsresult
12611 0 : nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
12612 : {
12613 0 : if (!IsNavigationAllowed()) {
12614 0 : return NS_OK;
12615 : }
12616 :
12617 0 : nsCOMPtr<nsIURI> uri;
12618 0 : nsCOMPtr<nsIURI> originalURI;
12619 0 : nsCOMPtr<nsIURI> resultPrincipalURI;
12620 0 : bool loadReplace = false;
12621 0 : nsCOMPtr<nsIInputStream> postData;
12622 0 : nsCOMPtr<nsIURI> referrerURI;
12623 : uint32_t referrerPolicy;
12624 0 : nsAutoCString contentType;
12625 0 : nsCOMPtr<nsIPrincipal> triggeringPrincipal;
12626 0 : nsCOMPtr<nsIPrincipal> principalToInherit;
12627 :
12628 0 : NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
12629 :
12630 0 : NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
12631 0 : NS_ENSURE_SUCCESS(aEntry->GetOriginalURI(getter_AddRefs(originalURI)),
12632 : NS_ERROR_FAILURE);
12633 0 : NS_ENSURE_SUCCESS(aEntry->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)),
12634 : NS_ERROR_FAILURE);
12635 0 : NS_ENSURE_SUCCESS(aEntry->GetLoadReplace(&loadReplace),
12636 : NS_ERROR_FAILURE);
12637 0 : NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
12638 : NS_ERROR_FAILURE);
12639 0 : NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
12640 : NS_ERROR_FAILURE);
12641 0 : NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
12642 : NS_ERROR_FAILURE);
12643 0 : NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
12644 0 : NS_ENSURE_SUCCESS(aEntry->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal)),
12645 : NS_ERROR_FAILURE);
12646 0 : NS_ENSURE_SUCCESS(aEntry->GetPrincipalToInherit(getter_AddRefs(principalToInherit)),
12647 : NS_ERROR_FAILURE);
12648 :
12649 : // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
12650 : // that's the only thing holding a ref to aEntry that will cause aEntry to
12651 : // die while we're loading it. So hold a strong ref to aEntry here, just
12652 : // in case.
12653 0 : nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
12654 : bool isJS;
12655 0 : nsresult rv = uri->SchemeIs("javascript", &isJS);
12656 0 : if (NS_FAILED(rv) || isJS) {
12657 : // We're loading a URL that will execute script from inside asyncOpen.
12658 : // Replace the current document with about:blank now to prevent
12659 : // anything from the current document from leaking into any JavaScript
12660 : // code in the URL.
12661 : // Don't cache the presentation if we're going to just reload the
12662 : // current entry. Caching would lead to trying to save the different
12663 : // content viewers in the same nsISHEntry object.
12664 0 : rv = CreateAboutBlankContentViewer(principalToInherit, nullptr,
12665 0 : aEntry != mOSHE);
12666 :
12667 0 : if (NS_FAILED(rv)) {
12668 : // The creation of the intermittent about:blank content
12669 : // viewer failed for some reason (potentially because the
12670 : // user prevented it). Interrupt the history load.
12671 0 : return NS_OK;
12672 : }
12673 :
12674 0 : if (!triggeringPrincipal) {
12675 : // Ensure that we have a triggeringPrincipal. Otherwise javascript:
12676 : // URIs will pick it up from the about:blank page we just loaded,
12677 : // and we don't really want even that in this case.
12678 0 : triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this);
12679 : }
12680 : }
12681 :
12682 : /* If there is a valid postdata *and* the user pressed
12683 : * reload or shift-reload, take user's permission before we
12684 : * repost the data to the server.
12685 : */
12686 0 : if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
12687 : bool repost;
12688 0 : rv = ConfirmRepost(&repost);
12689 0 : if (NS_FAILED(rv)) {
12690 0 : return rv;
12691 : }
12692 :
12693 : // If the user pressed cancel in the dialog, return. We're done here.
12694 0 : if (!repost) {
12695 0 : return NS_BINDING_ABORTED;
12696 : }
12697 : }
12698 :
12699 : // Do not inherit principal from document (security-critical!);
12700 0 : uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
12701 :
12702 0 : nsAutoString srcdoc;
12703 : bool isSrcdoc;
12704 0 : nsCOMPtr<nsIURI> baseURI;
12705 0 : aEntry->GetIsSrcdocEntry(&isSrcdoc);
12706 0 : if (isSrcdoc) {
12707 0 : aEntry->GetSrcdocData(srcdoc);
12708 0 : aEntry->GetBaseURI(getter_AddRefs(baseURI));
12709 0 : flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
12710 : } else {
12711 0 : srcdoc = NullString();
12712 : }
12713 :
12714 0 : if (!triggeringPrincipal) {
12715 0 : triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
12716 : }
12717 :
12718 : // Passing nullptr as aSourceDocShell gives the same behaviour as before
12719 : // aSourceDocShell was introduced. According to spec we should be passing
12720 : // the source browsing context that was used when the history entry was
12721 : // first created. bug 947716 has been created to address this issue.
12722 0 : Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
12723 0 : emplacedResultPrincipalURI.emplace(Move(resultPrincipalURI));
12724 0 : rv = InternalLoad(uri,
12725 : originalURI,
12726 : emplacedResultPrincipalURI,
12727 : loadReplace,
12728 : referrerURI,
12729 : referrerPolicy,
12730 : triggeringPrincipal,
12731 : principalToInherit,
12732 : flags,
12733 0 : EmptyString(), // No window target
12734 : contentType.get(), // Type hint
12735 0 : NullString(), // No forced file download
12736 : postData, // Post data stream
12737 : nullptr, // No headers stream
12738 : aLoadType, // Load type
12739 : aEntry, // SHEntry
12740 : true,
12741 : srcdoc,
12742 : nullptr, // Source docshell, see comment above
12743 : baseURI,
12744 : false,
12745 : nullptr, // No nsIDocShell
12746 0 : nullptr); // No nsIRequest
12747 0 : return rv;
12748 : }
12749 :
12750 : NS_IMETHODIMP
12751 0 : nsDocShell::GetShouldSaveLayoutState(bool* aShould)
12752 : {
12753 0 : *aShould = false;
12754 0 : if (mOSHE) {
12755 : // Don't capture historystate and save it in history
12756 : // if the page asked not to do so.
12757 0 : mOSHE->GetSaveLayoutStateFlag(aShould);
12758 : }
12759 :
12760 0 : return NS_OK;
12761 : }
12762 :
12763 : nsresult
12764 9 : nsDocShell::PersistLayoutHistoryState()
12765 : {
12766 9 : nsresult rv = NS_OK;
12767 :
12768 9 : if (mOSHE) {
12769 0 : bool scrollRestorationIsManual = false;
12770 0 : mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
12771 :
12772 0 : nsCOMPtr<nsIPresShell> shell = GetPresShell();
12773 0 : nsCOMPtr<nsILayoutHistoryState> layoutState;
12774 0 : if (shell) {
12775 0 : rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
12776 0 : } else if (scrollRestorationIsManual) {
12777 : // Even if we don't have layout anymore, we may want to reset the current
12778 : // scroll state in layout history.
12779 0 : GetLayoutHistoryState(getter_AddRefs(layoutState));
12780 : }
12781 :
12782 0 : if (scrollRestorationIsManual && layoutState) {
12783 0 : layoutState->ResetScrollState();
12784 : }
12785 : }
12786 :
12787 9 : return rv;
12788 : }
12789 :
12790 : /* static */ nsresult
12791 0 : nsDocShell::WalkHistoryEntries(nsISHEntry* aRootEntry,
12792 : nsDocShell* aRootShell,
12793 : WalkHistoryEntriesFunc aCallback,
12794 : void* aData)
12795 : {
12796 0 : NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
12797 :
12798 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
12799 0 : if (!container) {
12800 0 : return NS_ERROR_FAILURE;
12801 : }
12802 :
12803 : int32_t childCount;
12804 0 : container->GetChildCount(&childCount);
12805 0 : for (int32_t i = 0; i < childCount; i++) {
12806 0 : nsCOMPtr<nsISHEntry> childEntry;
12807 0 : container->GetChildAt(i, getter_AddRefs(childEntry));
12808 0 : if (!childEntry) {
12809 : // childEntry can be null for valid reasons, for example if the
12810 : // docshell at index i never loaded anything useful.
12811 : // Remember to clone also nulls in the child array (bug 464064).
12812 0 : aCallback(nullptr, nullptr, i, aData);
12813 0 : continue;
12814 : }
12815 :
12816 0 : nsDocShell* childShell = nullptr;
12817 0 : if (aRootShell) {
12818 : // Walk the children of aRootShell and see if one of them
12819 : // has srcChild as a SHEntry.
12820 : nsTObserverArray<nsDocLoader*>::ForwardIterator iter(
12821 0 : aRootShell->mChildList);
12822 0 : while (iter.HasMore()) {
12823 0 : nsDocShell* child = static_cast<nsDocShell*>(iter.GetNext());
12824 :
12825 0 : if (child->HasHistoryEntry(childEntry)) {
12826 0 : childShell = child;
12827 0 : break;
12828 : }
12829 : }
12830 : }
12831 0 : nsresult rv = aCallback(childEntry, childShell, i, aData);
12832 0 : NS_ENSURE_SUCCESS(rv, rv);
12833 : }
12834 :
12835 0 : return NS_OK;
12836 : }
12837 :
12838 : // callback data for WalkHistoryEntries
12839 0 : struct MOZ_STACK_CLASS CloneAndReplaceData
12840 : {
12841 0 : CloneAndReplaceData(uint32_t aCloneID, nsISHEntry* aReplaceEntry,
12842 : bool aCloneChildren, nsISHEntry* aDestTreeParent)
12843 0 : : cloneID(aCloneID)
12844 : , cloneChildren(aCloneChildren)
12845 : , replaceEntry(aReplaceEntry)
12846 0 : , destTreeParent(aDestTreeParent)
12847 : {
12848 0 : }
12849 :
12850 : uint32_t cloneID;
12851 : bool cloneChildren;
12852 : nsISHEntry* replaceEntry;
12853 : nsISHEntry* destTreeParent;
12854 : nsCOMPtr<nsISHEntry> resultEntry;
12855 : };
12856 :
12857 : /* static */ nsresult
12858 0 : nsDocShell::CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell,
12859 : int32_t aEntryIndex, void* aData)
12860 : {
12861 0 : nsCOMPtr<nsISHEntry> dest;
12862 :
12863 0 : CloneAndReplaceData* data = static_cast<CloneAndReplaceData*>(aData);
12864 0 : uint32_t cloneID = data->cloneID;
12865 0 : nsISHEntry* replaceEntry = data->replaceEntry;
12866 :
12867 0 : nsCOMPtr<nsISHContainer> container = do_QueryInterface(data->destTreeParent);
12868 0 : if (!aEntry) {
12869 0 : if (container) {
12870 0 : container->AddChild(nullptr, aEntryIndex);
12871 : }
12872 0 : return NS_OK;
12873 : }
12874 :
12875 : uint32_t srcID;
12876 0 : aEntry->GetID(&srcID);
12877 :
12878 0 : nsresult rv = NS_OK;
12879 0 : if (srcID == cloneID) {
12880 : // Replace the entry
12881 0 : dest = replaceEntry;
12882 : } else {
12883 : // Clone the SHEntry...
12884 0 : rv = aEntry->Clone(getter_AddRefs(dest));
12885 0 : NS_ENSURE_SUCCESS(rv, rv);
12886 : }
12887 0 : dest->SetIsSubFrame(true);
12888 :
12889 0 : if (srcID != cloneID || data->cloneChildren) {
12890 : // Walk the children
12891 : CloneAndReplaceData childData(cloneID, replaceEntry,
12892 0 : data->cloneChildren, dest);
12893 : rv = WalkHistoryEntries(aEntry, aShell,
12894 0 : CloneAndReplaceChild, &childData);
12895 0 : NS_ENSURE_SUCCESS(rv, rv);
12896 : }
12897 :
12898 0 : if (srcID != cloneID && aShell) {
12899 0 : aShell->SwapHistoryEntries(aEntry, dest);
12900 : }
12901 :
12902 0 : if (container) {
12903 0 : container->AddChild(dest, aEntryIndex);
12904 : }
12905 :
12906 0 : data->resultEntry = dest;
12907 0 : return rv;
12908 : }
12909 :
12910 : /* static */ nsresult
12911 0 : nsDocShell::CloneAndReplace(nsISHEntry* aSrcEntry,
12912 : nsDocShell* aSrcShell,
12913 : uint32_t aCloneID,
12914 : nsISHEntry* aReplaceEntry,
12915 : bool aCloneChildren,
12916 : nsISHEntry** aResultEntry)
12917 : {
12918 0 : NS_ENSURE_ARG_POINTER(aResultEntry);
12919 0 : NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
12920 :
12921 0 : CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr);
12922 0 : nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
12923 :
12924 0 : data.resultEntry.swap(*aResultEntry);
12925 0 : return rv;
12926 : }
12927 :
12928 : void
12929 0 : nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry)
12930 : {
12931 0 : if (aOldEntry == mOSHE) {
12932 0 : mOSHE = aNewEntry;
12933 : }
12934 :
12935 0 : if (aOldEntry == mLSHE) {
12936 0 : mLSHE = aNewEntry;
12937 : }
12938 0 : }
12939 :
12940 : struct SwapEntriesData
12941 : {
12942 : nsDocShell* ignoreShell; // constant; the shell to ignore
12943 : nsISHEntry* destTreeRoot; // constant; the root of the dest tree
12944 : nsISHEntry* destTreeParent; // constant; the node under destTreeRoot
12945 : // whose children will correspond to aEntry
12946 : };
12947 :
12948 : nsresult
12949 0 : nsDocShell::SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell,
12950 : int32_t aEntryIndex, void* aData)
12951 : {
12952 0 : SwapEntriesData* data = static_cast<SwapEntriesData*>(aData);
12953 0 : nsDocShell* ignoreShell = data->ignoreShell;
12954 :
12955 0 : if (!aShell || aShell == ignoreShell) {
12956 0 : return NS_OK;
12957 : }
12958 :
12959 0 : nsISHEntry* destTreeRoot = data->destTreeRoot;
12960 :
12961 0 : nsCOMPtr<nsISHEntry> destEntry;
12962 0 : nsCOMPtr<nsISHContainer> container = do_QueryInterface(data->destTreeParent);
12963 :
12964 0 : if (container) {
12965 : // aEntry is a clone of some child of destTreeParent, but since the
12966 : // trees aren't necessarily in sync, we'll have to locate it.
12967 : // Note that we could set aShell's entry to null if we don't find a
12968 : // corresponding entry under destTreeParent.
12969 :
12970 : uint32_t targetID, id;
12971 0 : aEntry->GetID(&targetID);
12972 :
12973 : // First look at the given index, since this is the common case.
12974 0 : nsCOMPtr<nsISHEntry> entry;
12975 0 : container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
12976 0 : if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
12977 0 : destEntry.swap(entry);
12978 : } else {
12979 : int32_t childCount;
12980 0 : container->GetChildCount(&childCount);
12981 0 : for (int32_t i = 0; i < childCount; ++i) {
12982 0 : container->GetChildAt(i, getter_AddRefs(entry));
12983 0 : if (!entry) {
12984 0 : continue;
12985 : }
12986 :
12987 0 : entry->GetID(&id);
12988 0 : if (id == targetID) {
12989 0 : destEntry.swap(entry);
12990 0 : break;
12991 : }
12992 : }
12993 : }
12994 : } else {
12995 0 : destEntry = destTreeRoot;
12996 : }
12997 :
12998 0 : aShell->SwapHistoryEntries(aEntry, destEntry);
12999 :
13000 : // Now handle the children of aEntry.
13001 0 : SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
13002 0 : return WalkHistoryEntries(aEntry, aShell, SetChildHistoryEntry, &childData);
13003 : }
13004 :
13005 : static nsISHEntry*
13006 13 : GetRootSHEntry(nsISHEntry* aEntry)
13007 : {
13008 26 : nsCOMPtr<nsISHEntry> rootEntry = aEntry;
13009 13 : nsISHEntry* result = nullptr;
13010 15 : while (rootEntry) {
13011 1 : result = rootEntry;
13012 1 : result->GetParent(getter_AddRefs(rootEntry));
13013 : }
13014 :
13015 26 : return result;
13016 : }
13017 :
13018 : void
13019 12 : nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr, nsISHEntry* aEntry)
13020 : {
13021 : // We need to sync up the docshell and session history trees for
13022 : // subframe navigation. If the load was in a subframe, we forward up to
13023 : // the root docshell, which will then recursively sync up all docshells
13024 : // to their corresponding entries in the new session history tree.
13025 : // If we don't do this, then we can cache a content viewer on the wrong
13026 : // cloned entry, and subsequently restore it at the wrong time.
13027 :
13028 12 : nsISHEntry* newRootEntry = GetRootSHEntry(aEntry);
13029 12 : if (newRootEntry) {
13030 : // newRootEntry is now the new root entry.
13031 : // Find the old root entry as well.
13032 :
13033 : // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
13034 : // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
13035 2 : nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
13036 1 : if (oldRootEntry) {
13037 0 : nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
13038 0 : GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
13039 0 : nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
13040 0 : if (rootShell) { // if we're the root just set it, nothing to swap
13041 0 : SwapEntriesData data = { this, newRootEntry };
13042 0 : nsIDocShell* rootIDocShell = static_cast<nsIDocShell*>(rootShell);
13043 0 : nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell);
13044 :
13045 : #ifdef DEBUG
13046 : nsresult rv =
13047 : #endif
13048 0 : SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data);
13049 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
13050 : }
13051 : }
13052 : }
13053 :
13054 12 : *aPtr = aEntry;
13055 12 : }
13056 :
13057 : nsresult
13058 9 : nsDocShell::GetRootSessionHistory(nsISHistory** aReturn)
13059 : {
13060 : nsresult rv;
13061 :
13062 18 : nsCOMPtr<nsIDocShellTreeItem> root;
13063 : // Get the root docshell
13064 9 : rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
13065 : // QI to nsIWebNavigation
13066 18 : nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
13067 9 : if (rootAsWebnav) {
13068 : // Get the handle to SH from the root docshell
13069 9 : rv = rootAsWebnav->GetSessionHistory(aReturn);
13070 : }
13071 18 : return rv;
13072 : }
13073 :
13074 : nsresult
13075 10 : nsDocShell::GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn)
13076 : {
13077 10 : NS_ENSURE_ARG_POINTER(aReturn);
13078 10 : if (!aChannel) {
13079 0 : return NS_ERROR_FAILURE;
13080 : }
13081 :
13082 20 : nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
13083 10 : if (multiPartChannel) {
13084 0 : nsCOMPtr<nsIChannel> baseChannel;
13085 0 : multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
13086 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
13087 0 : *aReturn = httpChannel;
13088 0 : NS_IF_ADDREF(*aReturn);
13089 : }
13090 10 : return NS_OK;
13091 : }
13092 :
13093 : bool
13094 2 : nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel)
13095 : {
13096 : // By default layout State will be saved.
13097 2 : if (!aChannel) {
13098 0 : return false;
13099 : }
13100 :
13101 : // figure out if SH should be saving layout state
13102 2 : bool noStore = false;
13103 2 : Unused << aChannel->IsNoStoreResponse(&noStore);
13104 2 : return noStore;
13105 : }
13106 :
13107 : NS_IMETHODIMP
13108 0 : nsDocShell::GetEditor(nsIEditor** aEditor)
13109 : {
13110 0 : NS_ENSURE_ARG_POINTER(aEditor);
13111 :
13112 0 : if (!mEditorData) {
13113 0 : *aEditor = nullptr;
13114 0 : return NS_OK;
13115 : }
13116 :
13117 0 : return mEditorData->GetEditor(aEditor);
13118 : }
13119 :
13120 : NS_IMETHODIMP
13121 0 : nsDocShell::SetEditor(nsIEditor* aEditor)
13122 : {
13123 0 : nsresult rv = EnsureEditorData();
13124 0 : if (NS_FAILED(rv)) {
13125 0 : return rv;
13126 : }
13127 :
13128 0 : return mEditorData->SetEditor(aEditor);
13129 : }
13130 :
13131 : NS_IMETHODIMP
13132 6 : nsDocShell::GetEditable(bool* aEditable)
13133 : {
13134 6 : NS_ENSURE_ARG_POINTER(aEditable);
13135 6 : *aEditable = mEditorData && mEditorData->GetEditable();
13136 6 : return NS_OK;
13137 : }
13138 :
13139 : NS_IMETHODIMP
13140 0 : nsDocShell::GetHasEditingSession(bool* aHasEditingSession)
13141 : {
13142 0 : NS_ENSURE_ARG_POINTER(aHasEditingSession);
13143 :
13144 0 : if (mEditorData) {
13145 0 : nsCOMPtr<nsIEditingSession> editingSession;
13146 0 : mEditorData->GetEditingSession(getter_AddRefs(editingSession));
13147 0 : *aHasEditingSession = (editingSession.get() != nullptr);
13148 : } else {
13149 0 : *aHasEditingSession = false;
13150 : }
13151 :
13152 0 : return NS_OK;
13153 : }
13154 :
13155 : NS_IMETHODIMP
13156 0 : nsDocShell::MakeEditable(bool aInWaitForUriLoad)
13157 : {
13158 0 : nsresult rv = EnsureEditorData();
13159 0 : if (NS_FAILED(rv)) {
13160 0 : return rv;
13161 : }
13162 :
13163 0 : return mEditorData->MakeEditable(aInWaitForUriLoad);
13164 : }
13165 :
13166 : bool
13167 1 : nsDocShell::ChannelIsPost(nsIChannel* aChannel)
13168 : {
13169 2 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
13170 1 : if (!httpChannel) {
13171 0 : return false;
13172 : }
13173 :
13174 2 : nsAutoCString method;
13175 1 : Unused << httpChannel->GetRequestMethod(method);
13176 1 : return method.EqualsLiteral("POST");
13177 : }
13178 :
13179 : void
13180 1 : nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
13181 : nsIURI** aURI,
13182 : uint32_t* aChannelRedirectFlags)
13183 : {
13184 2 : nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
13185 1 : if (!props) {
13186 0 : return;
13187 : }
13188 :
13189 2 : nsresult rv = props->GetPropertyAsInterface(
13190 2 : NS_LITERAL_STRING("docshell.previousURI"),
13191 : NS_GET_IID(nsIURI),
13192 3 : reinterpret_cast<void**>(aURI));
13193 :
13194 1 : if (NS_FAILED(rv)) {
13195 : // There is no last visit for this channel, so this must be the first
13196 : // link. Link the visit to the referrer of this request, if any.
13197 : // Treat referrer as null if there is an error getting it.
13198 1 : (void)NS_GetReferrerFromChannel(aChannel, aURI);
13199 : } else {
13200 0 : rv = props->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
13201 0 : aChannelRedirectFlags);
13202 :
13203 0 : NS_WARNING_ASSERTION(
13204 : NS_SUCCEEDED(rv),
13205 : "Could not fetch previous flags, URI will be treated like referrer");
13206 : }
13207 : }
13208 :
13209 : void
13210 0 : nsDocShell::SaveLastVisit(nsIChannel* aChannel,
13211 : nsIURI* aURI,
13212 : uint32_t aChannelRedirectFlags)
13213 : {
13214 0 : nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
13215 0 : if (!props || !aURI) {
13216 0 : return;
13217 : }
13218 :
13219 0 : props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
13220 0 : aURI);
13221 0 : props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
13222 0 : aChannelRedirectFlags);
13223 : }
13224 :
13225 : void
13226 1 : nsDocShell::AddURIVisit(nsIURI* aURI,
13227 : nsIURI* aReferrerURI,
13228 : nsIURI* aPreviousURI,
13229 : uint32_t aChannelRedirectFlags,
13230 : uint32_t aResponseStatus)
13231 : {
13232 1 : MOZ_ASSERT(aURI, "Visited URI is null!");
13233 1 : MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE &&
13234 : mLoadType != LOAD_BYPASS_HISTORY,
13235 : "Do not add error or bypass pages to global history");
13236 :
13237 : // Only content-type docshells save URI visits. Also don't do
13238 : // anything here if we're not supposed to use global history.
13239 1 : if (mItemType != typeContent || !mUseGlobalHistory || UsePrivateBrowsing()) {
13240 0 : return;
13241 : }
13242 :
13243 2 : nsCOMPtr<IHistory> history = services::GetHistoryService();
13244 :
13245 1 : if (mPrerenderGlobalHistory || history) {
13246 1 : uint32_t visitURIFlags = 0;
13247 :
13248 1 : if (!IsFrame()) {
13249 1 : visitURIFlags |= IHistory::TOP_LEVEL;
13250 : }
13251 :
13252 1 : if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
13253 0 : visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
13254 1 : } else if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) {
13255 0 : visitURIFlags |= IHistory::REDIRECT_PERMANENT;
13256 : } else {
13257 1 : MOZ_ASSERT(!aChannelRedirectFlags,
13258 : "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set "
13259 : "if any flags in aChannelRedirectFlags is set.");
13260 : }
13261 :
13262 1 : if (aResponseStatus >= 300 && aResponseStatus < 400) {
13263 0 : visitURIFlags |= IHistory::REDIRECT_SOURCE;
13264 : }
13265 : // Errors 400-501 and 505 are considered unrecoverable, in the sense a
13266 : // simple retry attempt by the user is unlikely to solve them.
13267 : // 408 is special cased, since may actually indicate a temporary
13268 : // connection problem.
13269 1 : else if (aResponseStatus != 408 &&
13270 0 : ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
13271 : aResponseStatus == 505)) {
13272 0 : visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
13273 : }
13274 :
13275 1 : if (mPrerenderGlobalHistory) {
13276 0 : mPrerenderGlobalHistory->VisitURI(aURI,
13277 : aPreviousURI,
13278 : aReferrerURI,
13279 0 : visitURIFlags);
13280 : } else {
13281 1 : (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
13282 : }
13283 0 : } else if (mGlobalHistory) {
13284 : // Falls back to sync global history interface.
13285 0 : (void)mGlobalHistory->AddURI(aURI,
13286 : !!aChannelRedirectFlags,
13287 0 : !IsFrame(),
13288 0 : aReferrerURI);
13289 : }
13290 : }
13291 :
13292 : //*****************************************************************************
13293 : // nsDocShell: Helper Routines
13294 : //*****************************************************************************
13295 :
13296 : NS_IMETHODIMP
13297 0 : nsDocShell::SetLoadType(uint32_t aLoadType)
13298 : {
13299 0 : mLoadType = aLoadType;
13300 0 : return NS_OK;
13301 : }
13302 :
13303 : NS_IMETHODIMP
13304 14 : nsDocShell::GetLoadType(uint32_t* aLoadType)
13305 : {
13306 14 : *aLoadType = mLoadType;
13307 14 : return NS_OK;
13308 : }
13309 :
13310 : nsresult
13311 0 : nsDocShell::ConfirmRepost(bool* aRepost)
13312 : {
13313 0 : nsCOMPtr<nsIPrompt> prompter;
13314 0 : CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
13315 0 : if (!prompter) {
13316 0 : return NS_ERROR_NOT_AVAILABLE;
13317 : }
13318 :
13319 : nsCOMPtr<nsIStringBundleService> stringBundleService =
13320 0 : mozilla::services::GetStringBundleService();
13321 0 : if (!stringBundleService) {
13322 0 : return NS_ERROR_FAILURE;
13323 : }
13324 :
13325 0 : nsCOMPtr<nsIStringBundle> appBundle;
13326 0 : nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
13327 0 : getter_AddRefs(appBundle));
13328 0 : NS_ENSURE_SUCCESS(rv, rv);
13329 :
13330 0 : nsCOMPtr<nsIStringBundle> brandBundle;
13331 0 : rv = stringBundleService->CreateBundle(kBrandBundleURL,
13332 0 : getter_AddRefs(brandBundle));
13333 0 : NS_ENSURE_SUCCESS(rv, rv);
13334 :
13335 0 : NS_ASSERTION(prompter && brandBundle && appBundle,
13336 : "Unable to set up repost prompter.");
13337 :
13338 0 : nsXPIDLString brandName;
13339 0 : rv = brandBundle->GetStringFromName(u"brandShortName",
13340 0 : getter_Copies(brandName));
13341 :
13342 0 : nsXPIDLString msgString, button0Title;
13343 0 : if (NS_FAILED(rv)) { // No brand, use the generic version.
13344 0 : rv = appBundle->GetStringFromName(u"confirmRepostPrompt",
13345 0 : getter_Copies(msgString));
13346 : } else {
13347 : // Brand available - if the app has an override file with formatting, the
13348 : // app name will be included. Without an override, the prompt will look
13349 : // like the generic version.
13350 0 : const char16_t* formatStrings[] = { brandName.get() };
13351 0 : rv = appBundle->FormatStringFromName(u"confirmRepostPrompt",
13352 : formatStrings,
13353 0 : ArrayLength(formatStrings),
13354 0 : getter_Copies(msgString));
13355 : }
13356 0 : if (NS_FAILED(rv)) {
13357 0 : return rv;
13358 : }
13359 :
13360 0 : rv = appBundle->GetStringFromName(u"resendButton.label",
13361 0 : getter_Copies(button0Title));
13362 0 : if (NS_FAILED(rv)) {
13363 0 : return rv;
13364 : }
13365 :
13366 : int32_t buttonPressed;
13367 : // The actual value here is irrelevant, but we can't pass an invalid
13368 : // bool through XPConnect.
13369 0 : bool checkState = false;
13370 0 : rv = prompter->ConfirmEx(
13371 : nullptr, msgString.get(),
13372 : (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
13373 : (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
13374 0 : button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed);
13375 0 : if (NS_FAILED(rv)) {
13376 0 : return rv;
13377 : }
13378 :
13379 0 : *aRepost = (buttonPressed == 0);
13380 0 : return NS_OK;
13381 : }
13382 :
13383 : NS_IMETHODIMP
13384 0 : nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt,
13385 : nsIStringBundle** aStringBundle)
13386 : {
13387 0 : NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt),
13388 : NS_ERROR_FAILURE);
13389 :
13390 : nsCOMPtr<nsIStringBundleService> stringBundleService =
13391 0 : mozilla::services::GetStringBundleService();
13392 0 : NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
13393 :
13394 0 : NS_ENSURE_SUCCESS(
13395 : stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle),
13396 : NS_ERROR_FAILURE);
13397 :
13398 0 : return NS_OK;
13399 : }
13400 :
13401 : NS_IMETHODIMP
13402 0 : nsDocShell::GetChildOffset(nsIDOMNode* aChild, nsIDOMNode* aParent,
13403 : int32_t* aOffset)
13404 : {
13405 0 : NS_ENSURE_ARG_POINTER(aChild || aParent);
13406 :
13407 0 : nsCOMPtr<nsIDOMNodeList> childNodes;
13408 0 : NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
13409 : NS_ERROR_FAILURE);
13410 0 : NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
13411 :
13412 0 : int32_t i = 0;
13413 :
13414 0 : for (; true; i++) {
13415 0 : nsCOMPtr<nsIDOMNode> childNode;
13416 0 : NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
13417 : NS_ERROR_FAILURE);
13418 0 : NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
13419 :
13420 0 : if (childNode.get() == aChild) {
13421 0 : *aOffset = i;
13422 0 : return NS_OK;
13423 : }
13424 0 : }
13425 :
13426 : return NS_ERROR_FAILURE;
13427 : }
13428 :
13429 : nsIScrollableFrame*
13430 0 : nsDocShell::GetRootScrollFrame()
13431 : {
13432 0 : nsCOMPtr<nsIPresShell> shell = GetPresShell();
13433 0 : NS_ENSURE_TRUE(shell, nullptr);
13434 :
13435 0 : return shell->GetRootScrollFrameAsScrollableExternal();
13436 : }
13437 :
13438 : NS_IMETHODIMP
13439 325 : nsDocShell::EnsureScriptEnvironment()
13440 : {
13441 325 : if (mScriptGlobal) {
13442 319 : return NS_OK;
13443 : }
13444 :
13445 6 : if (mIsBeingDestroyed) {
13446 1 : return NS_ERROR_NOT_AVAILABLE;
13447 : }
13448 :
13449 : #ifdef DEBUG
13450 5 : NS_ASSERTION(!mInEnsureScriptEnv,
13451 : "Infinite loop! Calling EnsureScriptEnvironment() from "
13452 : "within EnsureScriptEnvironment()!");
13453 :
13454 : // Yeah, this isn't re-entrant safe, but that's ok since if we
13455 : // re-enter this method, we'll infinitely loop...
13456 10 : AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
13457 5 : mInEnsureScriptEnv = true;
13458 : #endif
13459 :
13460 10 : nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
13461 5 : NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
13462 :
13463 : uint32_t chromeFlags;
13464 5 : browserChrome->GetChromeFlags(&chromeFlags);
13465 :
13466 : bool isModalContentWindow =
13467 7 : (mItemType == typeContent) &&
13468 7 : (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW);
13469 : // There can be various other content docshells associated with the
13470 : // top-level window, like sidebars. Make sure that we only create an
13471 : // nsGlobalModalWindow for the primary content shell.
13472 5 : if (isModalContentWindow) {
13473 0 : nsCOMPtr<nsIDocShellTreeItem> primaryItem;
13474 : nsresult rv =
13475 0 : mTreeOwner->GetPrimaryContentShell(getter_AddRefs(primaryItem));
13476 0 : NS_ENSURE_SUCCESS(rv, rv);
13477 0 : isModalContentWindow = (primaryItem == this);
13478 : }
13479 :
13480 : // If our window is modal and we're not opened as chrome, make
13481 : // this window a modal content window.
13482 : mScriptGlobal =
13483 5 : NS_NewScriptGlobalObject(mItemType == typeChrome, isModalContentWindow);
13484 5 : MOZ_ASSERT(mScriptGlobal);
13485 :
13486 5 : mScriptGlobal->SetDocShell(this);
13487 :
13488 : // Ensure the script object is set up to run script.
13489 5 : return mScriptGlobal->EnsureScriptEnvironment();
13490 : }
13491 :
13492 : NS_IMETHODIMP
13493 0 : nsDocShell::EnsureEditorData()
13494 : {
13495 0 : bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
13496 0 : if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
13497 : // We shouldn't recreate the editor data if it already exists, or
13498 : // we're shutting down, or we already have a detached editor data
13499 : // stored in the session history. We should only have one editordata
13500 : // per docshell.
13501 0 : mEditorData = new nsDocShellEditorData(this);
13502 : }
13503 :
13504 0 : return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
13505 : }
13506 :
13507 : nsresult
13508 0 : nsDocShell::EnsureTransferableHookData()
13509 : {
13510 0 : if (!mTransferableHookData) {
13511 0 : mTransferableHookData = new nsTransferableHookData();
13512 : }
13513 :
13514 0 : return NS_OK;
13515 : }
13516 :
13517 : NS_IMETHODIMP
13518 0 : nsDocShell::EnsureFind()
13519 : {
13520 : nsresult rv;
13521 0 : if (!mFind) {
13522 0 : mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
13523 0 : if (NS_FAILED(rv)) {
13524 0 : return rv;
13525 : }
13526 : }
13527 :
13528 : // we promise that the nsIWebBrowserFind that we return has been set
13529 : // up to point to the focused, or content window, so we have to
13530 : // set that up each time.
13531 :
13532 0 : nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
13533 0 : NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
13534 :
13535 : // default to our window
13536 0 : nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_QueryInterface(scriptGO);
13537 0 : nsCOMPtr<nsPIDOMWindowOuter> windowToSearch;
13538 0 : nsFocusManager::GetFocusedDescendant(ourWindow, true,
13539 0 : getter_AddRefs(windowToSearch));
13540 :
13541 0 : nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
13542 0 : if (!findInFrames) {
13543 0 : return NS_ERROR_NO_INTERFACE;
13544 : }
13545 :
13546 0 : rv = findInFrames->SetRootSearchFrame(ourWindow);
13547 0 : if (NS_FAILED(rv)) {
13548 0 : return rv;
13549 : }
13550 0 : rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
13551 0 : if (NS_FAILED(rv)) {
13552 0 : return rv;
13553 : }
13554 :
13555 0 : return NS_OK;
13556 : }
13557 :
13558 : bool
13559 53 : nsDocShell::IsFrame()
13560 : {
13561 106 : nsCOMPtr<nsIDocShellTreeItem> parent;
13562 53 : GetSameTypeParent(getter_AddRefs(parent));
13563 106 : return !!parent;
13564 : }
13565 :
13566 : NS_IMETHODIMP
13567 2 : nsDocShell::IsBeingDestroyed(bool* aDoomed)
13568 : {
13569 2 : NS_ENSURE_ARG(aDoomed);
13570 2 : *aDoomed = mIsBeingDestroyed;
13571 2 : return NS_OK;
13572 : }
13573 :
13574 : NS_IMETHODIMP
13575 5 : nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult)
13576 : {
13577 5 : NS_ENSURE_ARG(aResult);
13578 5 : *aResult = mIsExecutingOnLoadHandler;
13579 5 : return NS_OK;
13580 : }
13581 :
13582 : NS_IMETHODIMP
13583 22 : nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState** aLayoutHistoryState)
13584 : {
13585 22 : if (mOSHE) {
13586 4 : mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
13587 : }
13588 22 : return NS_OK;
13589 : }
13590 :
13591 : NS_IMETHODIMP
13592 4 : nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState* aLayoutHistoryState)
13593 : {
13594 4 : if (mOSHE) {
13595 1 : mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
13596 : }
13597 4 : return NS_OK;
13598 : }
13599 :
13600 0 : nsRefreshTimer::nsRefreshTimer()
13601 0 : : mDelay(0), mRepeat(false), mMetaRefresh(false)
13602 : {
13603 0 : }
13604 :
13605 0 : nsRefreshTimer::~nsRefreshTimer()
13606 : {
13607 0 : }
13608 :
13609 0 : NS_IMPL_ADDREF(nsRefreshTimer)
13610 0 : NS_IMPL_RELEASE(nsRefreshTimer)
13611 :
13612 0 : NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
13613 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
13614 0 : NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
13615 0 : NS_INTERFACE_MAP_END_THREADSAFE
13616 :
13617 : NS_IMETHODIMP
13618 0 : nsRefreshTimer::Notify(nsITimer* aTimer)
13619 : {
13620 0 : NS_ASSERTION(mDocShell, "DocShell is somehow null");
13621 :
13622 0 : if (mDocShell && aTimer) {
13623 : // Get the delay count to determine load type
13624 0 : uint32_t delay = 0;
13625 0 : aTimer->GetDelay(&delay);
13626 0 : mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer);
13627 : }
13628 0 : return NS_OK;
13629 : }
13630 :
13631 5 : nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(
13632 5 : nsIInterfaceRequestor* aRequestor)
13633 : {
13634 5 : if (aRequestor) {
13635 5 : mWeakPtr = do_GetWeakReference(aRequestor);
13636 : }
13637 5 : }
13638 :
13639 0 : nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
13640 : {
13641 0 : mWeakPtr = nullptr;
13642 0 : }
13643 :
13644 3196 : NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)
13645 :
13646 : NS_IMETHODIMP
13647 612 : nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID& aIID,
13648 : void** aSink)
13649 : {
13650 612 : NS_ENSURE_ARG_POINTER(aSink);
13651 1224 : nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
13652 612 : if (ifReq) {
13653 612 : return ifReq->GetInterface(aIID, aSink);
13654 : }
13655 0 : *aSink = nullptr;
13656 0 : return NS_NOINTERFACE;
13657 : }
13658 :
13659 : nsresult
13660 0 : nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer)
13661 : {
13662 0 : if (!aContentViewer) {
13663 0 : return NS_ERROR_FAILURE;
13664 : }
13665 :
13666 0 : nsCOMPtr<nsIURI> baseURI;
13667 0 : nsresult rv = NS_ERROR_NOT_AVAILABLE;
13668 :
13669 0 : if (sURIFixup) {
13670 0 : rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(baseURI));
13671 : }
13672 :
13673 : // Get the current document and set the base uri
13674 0 : if (baseURI) {
13675 0 : nsIDocument* document = aContentViewer->GetDocument();
13676 0 : if (document) {
13677 0 : document->SetBaseURI(baseURI);
13678 : }
13679 : }
13680 0 : return rv;
13681 : }
13682 :
13683 : //*****************************************************************************
13684 : // nsDocShell::nsIAuthPromptProvider
13685 : //*****************************************************************************
13686 :
13687 : NS_IMETHODIMP
13688 0 : nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& aIID,
13689 : void** aResult)
13690 : {
13691 : // a priority prompt request will override a false mAllowAuth setting
13692 0 : bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
13693 :
13694 0 : if (!mAllowAuth && !priorityPrompt) {
13695 0 : return NS_ERROR_NOT_AVAILABLE;
13696 : }
13697 :
13698 : // we're either allowing auth, or it's a proxy request
13699 : nsresult rv;
13700 : nsCOMPtr<nsIPromptFactory> wwatch =
13701 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
13702 0 : NS_ENSURE_SUCCESS(rv, rv);
13703 :
13704 0 : rv = EnsureScriptEnvironment();
13705 0 : NS_ENSURE_SUCCESS(rv, rv);
13706 :
13707 : // Get the an auth prompter for our window so that the parenting
13708 : // of the dialogs works as it should when using tabs.
13709 :
13710 0 : return wwatch->GetPrompt(mScriptGlobal->AsOuter(), aIID,
13711 0 : reinterpret_cast<void**>(aResult));
13712 : }
13713 :
13714 : //*****************************************************************************
13715 : // nsDocShell::nsILoadContext
13716 : //*****************************************************************************
13717 :
13718 : NS_IMETHODIMP
13719 9 : nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy** aWindow)
13720 : {
13721 9 : CallGetInterface(this, aWindow);
13722 9 : return NS_OK;
13723 : }
13724 :
13725 : NS_IMETHODIMP
13726 0 : nsDocShell::GetTopWindow(mozIDOMWindowProxy** aWindow)
13727 : {
13728 0 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
13729 0 : if (win) {
13730 0 : win = win->GetTop();
13731 : }
13732 0 : win.forget(aWindow);
13733 0 : return NS_OK;
13734 : }
13735 :
13736 : NS_IMETHODIMP
13737 17 : nsDocShell::GetTopFrameElement(nsIDOMElement** aElement)
13738 : {
13739 17 : *aElement = nullptr;
13740 34 : nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
13741 17 : if (!win) {
13742 0 : return NS_OK;
13743 : }
13744 :
13745 34 : nsCOMPtr<nsPIDOMWindowOuter> top = win->GetScriptableTop();
13746 17 : NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
13747 :
13748 : // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is
13749 : // inside <iframe mozbrowser>, we want to return the iframe, not null.
13750 : // And we want to cross the content/chrome boundary.
13751 : nsCOMPtr<nsIDOMElement> elt =
13752 34 : do_QueryInterface(top->GetFrameElementInternal());
13753 17 : elt.forget(aElement);
13754 17 : return NS_OK;
13755 : }
13756 :
13757 : NS_IMETHODIMP
13758 0 : nsDocShell::GetNestedFrameId(uint64_t* aId)
13759 : {
13760 0 : *aId = 0;
13761 0 : return NS_OK;
13762 : }
13763 :
13764 : NS_IMETHODIMP
13765 7 : nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection)
13766 : {
13767 7 : *aUseTrackingProtection = false;
13768 :
13769 : static bool sTPEnabled = false;
13770 : static bool sTPInPBEnabled = false;
13771 : static bool sPrefsInit = false;
13772 :
13773 7 : if (!sPrefsInit) {
13774 2 : sPrefsInit = true;
13775 : Preferences::AddBoolVarCache(&sTPEnabled,
13776 2 : "privacy.trackingprotection.enabled", false);
13777 : Preferences::AddBoolVarCache(&sTPInPBEnabled,
13778 2 : "privacy.trackingprotection.pbmode.enabled", false);
13779 : }
13780 :
13781 14 : if (mUseTrackingProtection || sTPEnabled ||
13782 7 : (UsePrivateBrowsing() && sTPInPBEnabled)) {
13783 0 : *aUseTrackingProtection = true;
13784 0 : return NS_OK;
13785 : }
13786 :
13787 14 : RefPtr<nsDocShell> parent = GetParentDocshell();
13788 7 : if (parent) {
13789 0 : return parent->GetUseTrackingProtection(aUseTrackingProtection);
13790 : }
13791 :
13792 7 : return NS_OK;
13793 : }
13794 :
13795 : NS_IMETHODIMP
13796 0 : nsDocShell::SetUseTrackingProtection(bool aUseTrackingProtection)
13797 : {
13798 0 : mUseTrackingProtection = aUseTrackingProtection;
13799 0 : return NS_OK;
13800 : }
13801 :
13802 : NS_IMETHODIMP
13803 3 : nsDocShell::GetIsContent(bool* aIsContent)
13804 : {
13805 3 : *aIsContent = (mItemType == typeContent);
13806 3 : return NS_OK;
13807 : }
13808 :
13809 : bool
13810 0 : nsDocShell::IsOKToLoadURI(nsIURI* aURI)
13811 : {
13812 0 : NS_PRECONDITION(aURI, "Must have a URI!");
13813 :
13814 0 : if (!mFiredUnloadEvent) {
13815 0 : return true;
13816 : }
13817 :
13818 0 : if (!mLoadingURI) {
13819 0 : return false;
13820 : }
13821 :
13822 : nsCOMPtr<nsIScriptSecurityManager> secMan =
13823 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
13824 0 : return secMan &&
13825 0 : NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
13826 : }
13827 :
13828 : //
13829 : // Routines for selection and clipboard
13830 : //
13831 : nsresult
13832 0 : nsDocShell::GetControllerForCommand(const char* aCommand,
13833 : nsIController** aResult)
13834 : {
13835 0 : NS_ENSURE_ARG_POINTER(aResult);
13836 0 : *aResult = nullptr;
13837 :
13838 0 : NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
13839 :
13840 0 : nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
13841 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
13842 :
13843 0 : return root->GetControllerForCommand(aCommand, aResult);
13844 : }
13845 :
13846 : NS_IMETHODIMP
13847 0 : nsDocShell::IsCommandEnabled(const char* aCommand, bool* aResult)
13848 : {
13849 0 : NS_ENSURE_ARG_POINTER(aResult);
13850 0 : *aResult = false;
13851 :
13852 0 : nsresult rv = NS_ERROR_FAILURE;
13853 :
13854 0 : nsCOMPtr<nsIController> controller;
13855 0 : rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
13856 0 : if (controller) {
13857 0 : rv = controller->IsCommandEnabled(aCommand, aResult);
13858 : }
13859 :
13860 0 : return rv;
13861 : }
13862 :
13863 : NS_IMETHODIMP
13864 0 : nsDocShell::DoCommand(const char* aCommand)
13865 : {
13866 0 : nsresult rv = NS_ERROR_FAILURE;
13867 :
13868 0 : nsCOMPtr<nsIController> controller;
13869 0 : rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
13870 0 : if (controller) {
13871 0 : rv = controller->DoCommand(aCommand);
13872 : }
13873 :
13874 0 : return rv;
13875 : }
13876 :
13877 : NS_IMETHODIMP
13878 0 : nsDocShell::DoCommandWithParams(const char* aCommand, nsICommandParams* aParams)
13879 : {
13880 0 : nsCOMPtr<nsIController> controller;
13881 0 : nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
13882 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
13883 0 : return rv;
13884 : }
13885 :
13886 : nsCOMPtr<nsICommandController> commandController =
13887 0 : do_QueryInterface(controller, &rv);
13888 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
13889 0 : return rv;
13890 : }
13891 :
13892 0 : return commandController->DoCommandWithParams(aCommand, aParams);
13893 : }
13894 :
13895 : nsresult
13896 0 : nsDocShell::EnsureCommandHandler()
13897 : {
13898 0 : if (!mCommandManager) {
13899 : nsCOMPtr<nsPICommandUpdater> commandUpdater =
13900 0 : do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
13901 0 : if (!commandUpdater) {
13902 0 : return NS_ERROR_OUT_OF_MEMORY;
13903 : }
13904 :
13905 0 : nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow();
13906 0 : nsresult rv = commandUpdater->Init(domWindow);
13907 0 : if (NS_SUCCEEDED(rv)) {
13908 0 : mCommandManager = do_QueryInterface(commandUpdater);
13909 : }
13910 : }
13911 :
13912 0 : return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
13913 : }
13914 :
13915 : NS_IMETHODIMP
13916 0 : nsDocShell::CanCutSelection(bool* aResult)
13917 : {
13918 0 : return IsCommandEnabled("cmd_cut", aResult);
13919 : }
13920 :
13921 : NS_IMETHODIMP
13922 0 : nsDocShell::CanCopySelection(bool* aResult)
13923 : {
13924 0 : return IsCommandEnabled("cmd_copy", aResult);
13925 : }
13926 :
13927 : NS_IMETHODIMP
13928 0 : nsDocShell::CanCopyLinkLocation(bool* aResult)
13929 : {
13930 0 : return IsCommandEnabled("cmd_copyLink", aResult);
13931 : }
13932 :
13933 : NS_IMETHODIMP
13934 0 : nsDocShell::CanCopyImageLocation(bool* aResult)
13935 : {
13936 0 : return IsCommandEnabled("cmd_copyImageLocation", aResult);
13937 : }
13938 :
13939 : NS_IMETHODIMP
13940 0 : nsDocShell::CanCopyImageContents(bool* aResult)
13941 : {
13942 0 : return IsCommandEnabled("cmd_copyImageContents", aResult);
13943 : }
13944 :
13945 : NS_IMETHODIMP
13946 0 : nsDocShell::CanPaste(bool* aResult)
13947 : {
13948 0 : return IsCommandEnabled("cmd_paste", aResult);
13949 : }
13950 :
13951 : NS_IMETHODIMP
13952 0 : nsDocShell::CutSelection(void)
13953 : {
13954 0 : return DoCommand("cmd_cut");
13955 : }
13956 :
13957 : NS_IMETHODIMP
13958 0 : nsDocShell::CopySelection(void)
13959 : {
13960 0 : return DoCommand("cmd_copy");
13961 : }
13962 :
13963 : NS_IMETHODIMP
13964 0 : nsDocShell::CopyLinkLocation(void)
13965 : {
13966 0 : return DoCommand("cmd_copyLink");
13967 : }
13968 :
13969 : NS_IMETHODIMP
13970 0 : nsDocShell::CopyImageLocation(void)
13971 : {
13972 0 : return DoCommand("cmd_copyImageLocation");
13973 : }
13974 :
13975 : NS_IMETHODIMP
13976 0 : nsDocShell::CopyImageContents(void)
13977 : {
13978 0 : return DoCommand("cmd_copyImageContents");
13979 : }
13980 :
13981 : NS_IMETHODIMP
13982 0 : nsDocShell::Paste(void)
13983 : {
13984 0 : return DoCommand("cmd_paste");
13985 : }
13986 :
13987 : NS_IMETHODIMP
13988 0 : nsDocShell::SelectAll(void)
13989 : {
13990 0 : return DoCommand("cmd_selectAll");
13991 : }
13992 :
13993 : //
13994 : // SelectNone
13995 : //
13996 : // Collapses the current selection, insertion point ends up at beginning
13997 : // of previous selection.
13998 : //
13999 : NS_IMETHODIMP
14000 0 : nsDocShell::SelectNone(void)
14001 : {
14002 0 : return DoCommand("cmd_selectNone");
14003 : }
14004 :
14005 : // link handling
14006 :
14007 0 : class OnLinkClickEvent : public Runnable
14008 : {
14009 : public:
14010 : OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
14011 : nsIURI* aURI,
14012 : const char16_t* aTargetSpec,
14013 : const nsAString& aFileName,
14014 : nsIInputStream* aPostDataStream,
14015 : nsIInputStream* aHeadersDataStream,
14016 : bool aNoOpenerImplied,
14017 : bool aIsTrusted,
14018 : nsIPrincipal* aTriggeringPrincipal);
14019 :
14020 0 : NS_IMETHOD Run() override
14021 : {
14022 0 : nsAutoPopupStatePusher popupStatePusher(mPopupState);
14023 :
14024 : // We need to set up an AutoJSAPI here for the following reason: When we do
14025 : // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
14026 : // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
14027 : // So we need to fake things so that we don't look like native code as far
14028 : // as LegacyIsCallerNativeCode() is concerned.
14029 0 : AutoJSAPI jsapi;
14030 0 : if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
14031 0 : mHandler->OnLinkClickSync(mContent, mURI,
14032 : mTargetSpec.get(), mFileName,
14033 : mPostDataStream, mHeadersDataStream,
14034 0 : mNoOpenerImplied,
14035 0 : nullptr, nullptr, mTriggeringPrincipal);
14036 : }
14037 0 : return NS_OK;
14038 : }
14039 :
14040 : private:
14041 : RefPtr<nsDocShell> mHandler;
14042 : nsCOMPtr<nsIURI> mURI;
14043 : nsString mTargetSpec;
14044 : nsString mFileName;
14045 : nsCOMPtr<nsIInputStream> mPostDataStream;
14046 : nsCOMPtr<nsIInputStream> mHeadersDataStream;
14047 : nsCOMPtr<nsIContent> mContent;
14048 : PopupControlState mPopupState;
14049 : bool mNoOpenerImplied;
14050 : bool mIsTrusted;
14051 : nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
14052 : };
14053 :
14054 0 : OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
14055 : nsIContent* aContent,
14056 : nsIURI* aURI,
14057 : const char16_t* aTargetSpec,
14058 : const nsAString& aFileName,
14059 : nsIInputStream* aPostDataStream,
14060 : nsIInputStream* aHeadersDataStream,
14061 : bool aNoOpenerImplied,
14062 : bool aIsTrusted,
14063 0 : nsIPrincipal* aTriggeringPrincipal)
14064 : : mozilla::Runnable("OnLinkClickEvent")
14065 : , mHandler(aHandler)
14066 : , mURI(aURI)
14067 : , mTargetSpec(aTargetSpec)
14068 : , mFileName(aFileName)
14069 : , mPostDataStream(aPostDataStream)
14070 : , mHeadersDataStream(aHeadersDataStream)
14071 : , mContent(aContent)
14072 0 : , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
14073 : , mNoOpenerImplied(aNoOpenerImplied)
14074 : , mIsTrusted(aIsTrusted)
14075 0 : , mTriggeringPrincipal(aTriggeringPrincipal)
14076 : {
14077 0 : }
14078 :
14079 : NS_IMETHODIMP
14080 0 : nsDocShell::OnLinkClick(nsIContent* aContent,
14081 : nsIURI* aURI,
14082 : const char16_t* aTargetSpec,
14083 : const nsAString& aFileName,
14084 : nsIInputStream* aPostDataStream,
14085 : nsIInputStream* aHeadersDataStream,
14086 : bool aIsTrusted,
14087 : nsIPrincipal* aTriggeringPrincipal)
14088 : {
14089 0 : NS_ASSERTION(NS_IsMainThread(), "wrong thread");
14090 :
14091 0 : if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
14092 0 : return NS_OK;
14093 : }
14094 :
14095 : // On history navigation through Back/Forward buttons, don't execute
14096 : // automatic JavaScript redirection such as |anchorElement.click()| or
14097 : // |formElement.submit()|.
14098 : //
14099 : // XXX |formElement.submit()| bypasses this checkpoint because it calls
14100 : // nsDocShell::OnLinkClickSync(...) instead.
14101 0 : if (ShouldBlockLoadingForBackButton()) {
14102 0 : return NS_OK;
14103 : }
14104 :
14105 0 : if (aContent->IsEditable()) {
14106 0 : return NS_OK;
14107 : }
14108 :
14109 0 : nsresult rv = NS_ERROR_FAILURE;
14110 0 : nsAutoString target;
14111 :
14112 0 : nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
14113 0 : bool noOpenerImplied = false;
14114 0 : if (browserChrome3) {
14115 0 : nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
14116 0 : nsAutoString oldTarget(aTargetSpec);
14117 0 : rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
14118 0 : linkNode, mIsAppTab, target);
14119 0 : if (!oldTarget.Equals(target)) {
14120 0 : noOpenerImplied = true;
14121 : }
14122 : }
14123 :
14124 0 : if (NS_FAILED(rv)) {
14125 0 : target = aTargetSpec;
14126 : }
14127 :
14128 : nsCOMPtr<nsIRunnable> ev =
14129 0 : new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
14130 : aPostDataStream, aHeadersDataStream, noOpenerImplied,
14131 0 : aIsTrusted, aTriggeringPrincipal);
14132 : return DispatchToTabGroup("nsDocShell::OnLinkClickEvent",
14133 0 : TaskCategory::UI, ev.forget());
14134 : }
14135 :
14136 : NS_IMETHODIMP
14137 0 : nsDocShell::OnLinkClickSync(nsIContent* aContent,
14138 : nsIURI* aURI,
14139 : const char16_t* aTargetSpec,
14140 : const nsAString& aFileName,
14141 : nsIInputStream* aPostDataStream,
14142 : nsIInputStream* aHeadersDataStream,
14143 : bool aNoOpenerImplied,
14144 : nsIDocShell** aDocShell,
14145 : nsIRequest** aRequest,
14146 : nsIPrincipal* aTriggeringPrincipal)
14147 : {
14148 : // Initialize the DocShell / Request
14149 0 : if (aDocShell) {
14150 0 : *aDocShell = nullptr;
14151 : }
14152 0 : if (aRequest) {
14153 0 : *aRequest = nullptr;
14154 : }
14155 :
14156 0 : if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
14157 0 : return NS_OK;
14158 : }
14159 :
14160 : // XXX When the linking node was HTMLFormElement, it is synchronous event.
14161 : // That is, the caller of this method is not |OnLinkClickEvent::Run()|
14162 : // but |HTMLFormElement::SubmitSubmission(...)|.
14163 0 : if (aContent->IsHTMLElement(nsGkAtoms::form) &&
14164 0 : ShouldBlockLoadingForBackButton()) {
14165 0 : return NS_OK;
14166 : }
14167 :
14168 0 : if (aContent->IsEditable()) {
14169 0 : return NS_OK;
14170 : }
14171 :
14172 : {
14173 : // defer to an external protocol handler if necessary...
14174 : nsCOMPtr<nsIExternalProtocolService> extProtService =
14175 0 : do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
14176 0 : if (extProtService) {
14177 0 : nsAutoCString scheme;
14178 0 : aURI->GetScheme(scheme);
14179 0 : if (!scheme.IsEmpty()) {
14180 : // if the URL scheme does not correspond to an exposed protocol, then we
14181 : // need to hand this link click over to the external protocol handler.
14182 : bool isExposed;
14183 : nsresult rv =
14184 0 : extProtService->IsExposedProtocol(scheme.get(), &isExposed);
14185 0 : if (NS_SUCCEEDED(rv) && !isExposed) {
14186 0 : return extProtService->LoadURI(aURI, this);
14187 : }
14188 : }
14189 : }
14190 : }
14191 :
14192 0 : uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
14193 0 : if (IsElementAnchor(aContent)) {
14194 0 : MOZ_ASSERT(aContent->IsHTMLElement());
14195 0 : nsAutoString referrer;
14196 0 : aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
14197 0 : nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer);
14198 0 : while (tok.hasMoreTokens()) {
14199 0 : const nsAString& token = tok.nextToken();
14200 0 : if (token.LowerCaseEqualsLiteral("noreferrer")) {
14201 0 : flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
14202 : INTERNAL_LOAD_FLAGS_NO_OPENER;
14203 : // We now have all the flags we could possibly have, so just stop.
14204 0 : break;
14205 : }
14206 0 : if (token.LowerCaseEqualsLiteral("noopener")) {
14207 0 : flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
14208 : }
14209 : }
14210 0 : if (aNoOpenerImplied) {
14211 0 : flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
14212 : }
14213 : }
14214 :
14215 : // Get the owner document of the link that was clicked, this will be
14216 : // the document that the link is in, or the last document that the
14217 : // link was in. From that document, we'll get the URI to use as the
14218 : // referer, since the current URI in this docshell may be a
14219 : // new document that we're in the process of loading.
14220 0 : nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
14221 0 : NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
14222 :
14223 : // Now check that the refererDoc's inner window is the current inner
14224 : // window for mScriptGlobal. If it's not, then we don't want to
14225 : // follow this link.
14226 0 : nsPIDOMWindowInner* refererInner = refererDoc->GetInnerWindow();
14227 0 : NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
14228 0 : if (!mScriptGlobal ||
14229 0 : mScriptGlobal->AsOuter()->GetCurrentInnerWindow() != refererInner) {
14230 : // We're no longer the current inner window
14231 0 : return NS_OK;
14232 : }
14233 :
14234 0 : nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
14235 0 : uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
14236 :
14237 : // get referrer attribute from clicked link and parse it
14238 : // if per element referrer is enabled, the element referrer overrules
14239 : // the document wide referrer
14240 0 : if (IsElementAnchor(aContent)) {
14241 0 : net::ReferrerPolicy refPolEnum = aContent->AsElement()->GetReferrerPolicyAsEnum();
14242 0 : if (refPolEnum != net::RP_Unset) {
14243 0 : refererPolicy = refPolEnum;
14244 : }
14245 : }
14246 :
14247 : // referer could be null here in some odd cases, but that's ok,
14248 : // we'll just load the link w/o sending a referer in those cases.
14249 :
14250 0 : nsAutoString target(aTargetSpec);
14251 :
14252 : // If this is an anchor element, grab its type property to use as a hint
14253 0 : nsAutoString typeHint;
14254 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent));
14255 0 : if (anchor) {
14256 0 : anchor->GetType(typeHint);
14257 0 : NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
14258 0 : nsAutoCString type, dummy;
14259 0 : NS_ParseRequestContentType(utf8Hint, type, dummy);
14260 0 : CopyUTF8toUTF16(type, typeHint);
14261 : }
14262 :
14263 : // Clone the URI now, in case a content policy or something messes
14264 : // with it under InternalLoad; we do _not_ want to change the URI
14265 : // our caller passed in.
14266 0 : nsCOMPtr<nsIURI> clonedURI;
14267 0 : aURI->Clone(getter_AddRefs(clonedURI));
14268 0 : if (!clonedURI) {
14269 0 : return NS_ERROR_OUT_OF_MEMORY;
14270 : }
14271 :
14272 : // if the triggeringPrincipal is not passed explicitly, then we
14273 : // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
14274 : nsCOMPtr<nsIPrincipal> triggeringPrincipal =
14275 : aTriggeringPrincipal ? aTriggeringPrincipal
14276 0 : : aContent->NodePrincipal();
14277 :
14278 0 : nsresult rv = InternalLoad(clonedURI, // New URI
14279 : nullptr, // Original URI
14280 0 : Nothing(), // Let the protocol handler assign it
14281 : false, // LoadReplace
14282 : referer, // Referer URI
14283 : refererPolicy, // Referer policy
14284 : triggeringPrincipal,
14285 : aContent->NodePrincipal(),
14286 : flags,
14287 : target, // Window target
14288 0 : NS_LossyConvertUTF16toASCII(typeHint).get(),
14289 : aFileName, // Download as file
14290 : aPostDataStream, // Post data stream
14291 : aHeadersDataStream, // Headers stream
14292 : LOAD_LINK, // Load type
14293 : nullptr, // No SHEntry
14294 : true, // first party site
14295 0 : NullString(), // No srcdoc
14296 : this, // We are the source
14297 : nullptr, // baseURI not needed
14298 : true, // Check for prerendered doc
14299 : aDocShell, // DocShell out-param
14300 0 : aRequest); // Request out-param
14301 0 : if (NS_SUCCEEDED(rv)) {
14302 0 : DispatchPings(this, aContent, aURI, referer, refererPolicy);
14303 : }
14304 0 : return rv;
14305 : }
14306 :
14307 : NS_IMETHODIMP
14308 0 : nsDocShell::OnOverLink(nsIContent* aContent,
14309 : nsIURI* aURI,
14310 : const char16_t* aTargetSpec)
14311 : {
14312 0 : if (aContent->IsEditable()) {
14313 0 : return NS_OK;
14314 : }
14315 :
14316 0 : nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
14317 0 : nsresult rv = NS_ERROR_FAILURE;
14318 :
14319 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome;
14320 0 : if (!browserChrome2) {
14321 0 : browserChrome = do_GetInterface(mTreeOwner);
14322 0 : if (!browserChrome) {
14323 0 : return rv;
14324 : }
14325 : }
14326 :
14327 0 : nsAutoCString spec;
14328 0 : rv = aURI->GetSpec(spec);
14329 0 : NS_ENSURE_SUCCESS(rv, rv);
14330 :
14331 0 : NS_ConvertUTF8toUTF16 uStr(spec);
14332 :
14333 0 : mozilla::net::PredictorPredict(aURI, mCurrentURI,
14334 : nsINetworkPredictor::PREDICT_LINK,
14335 0 : aContent->NodePrincipal()->OriginAttributesRef(),
14336 0 : nullptr);
14337 :
14338 0 : if (browserChrome2) {
14339 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
14340 0 : rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
14341 0 : uStr, element);
14342 : } else {
14343 0 : rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
14344 : }
14345 0 : return rv;
14346 : }
14347 :
14348 : NS_IMETHODIMP
14349 0 : nsDocShell::OnLeaveLink()
14350 : {
14351 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
14352 0 : nsresult rv = NS_ERROR_FAILURE;
14353 :
14354 0 : if (browserChrome) {
14355 0 : rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
14356 0 : EmptyString().get());
14357 : }
14358 0 : return rv;
14359 : }
14360 :
14361 : bool
14362 6 : nsDocShell::ShouldBlockLoadingForBackButton()
14363 : {
14364 12 : if (!(mLoadType & LOAD_CMD_HISTORY) ||
14365 6 : EventStateManager::IsHandlingUserInput() ||
14366 0 : !Preferences::GetBool("accessibility.blockjsredirection")) {
14367 6 : return false;
14368 : }
14369 :
14370 0 : bool canGoForward = false;
14371 0 : GetCanGoForward(&canGoForward);
14372 0 : return canGoForward;
14373 : }
14374 :
14375 : bool
14376 0 : nsDocShell::PluginsAllowedInCurrentDoc()
14377 : {
14378 :
14379 0 : if (!mContentViewer) {
14380 0 : return false;
14381 : }
14382 :
14383 0 : nsIDocument* doc = mContentViewer->GetDocument();
14384 0 : if (!doc) {
14385 0 : return false;
14386 : }
14387 :
14388 0 : return doc->GetAllowPlugins();
14389 : }
14390 :
14391 : //----------------------------------------------------------------------
14392 : // Web Shell Services API
14393 :
14394 : // This functions is only called when a new charset is detected in loading a
14395 : // document. Its name should be changed to "CharsetReloadDocument"
14396 : NS_IMETHODIMP
14397 0 : nsDocShell::ReloadDocument(const char* aCharset, int32_t aSource)
14398 : {
14399 : // XXX hack. keep the aCharset and aSource wait to pick it up
14400 0 : nsCOMPtr<nsIContentViewer> cv;
14401 0 : NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
14402 0 : if (cv) {
14403 : int32_t hint;
14404 0 : cv->GetHintCharacterSetSource(&hint);
14405 0 : if (aSource > hint) {
14406 0 : nsCString charset(aCharset);
14407 0 : cv->SetHintCharacterSet(charset);
14408 0 : cv->SetHintCharacterSetSource(aSource);
14409 0 : if (eCharsetReloadRequested != mCharsetReloadState) {
14410 0 : mCharsetReloadState = eCharsetReloadRequested;
14411 0 : return Reload(LOAD_FLAGS_CHARSET_CHANGE);
14412 : }
14413 : }
14414 : }
14415 : // return failure if this request is not accepted due to mCharsetReloadState
14416 0 : return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
14417 : }
14418 :
14419 : NS_IMETHODIMP
14420 0 : nsDocShell::StopDocumentLoad(void)
14421 : {
14422 0 : if (eCharsetReloadRequested != mCharsetReloadState) {
14423 0 : Stop(nsIWebNavigation::STOP_ALL);
14424 0 : return NS_OK;
14425 : }
14426 : // return failer if this request is not accepted due to mCharsetReloadState
14427 0 : return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
14428 : }
14429 :
14430 : NS_IMETHODIMP
14431 0 : nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
14432 : {
14433 0 : *aPrintPreview = nullptr;
14434 : #if NS_PRINT_PREVIEW
14435 0 : nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
14436 0 : if (!print || !print->IsInitializedForPrintPreview()) {
14437 : // XXX: Creating a brand new content viewer to host preview every
14438 : // time we enter here seems overwork. We could skip ahead to where
14439 : // we QI the mContentViewer if the current URI is either about:blank
14440 : // or about:printpreview.
14441 0 : Stop(nsIWebNavigation::STOP_ALL);
14442 0 : nsCOMPtr<nsIPrincipal> principal = NullPrincipal::CreateWithInheritedAttributes(this);
14443 0 : nsCOMPtr<nsIURI> uri;
14444 0 : NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview"));
14445 0 : nsresult rv = CreateAboutBlankContentViewer(principal, uri);
14446 0 : NS_ENSURE_SUCCESS(rv, rv);
14447 : // Here we manually set current URI since we have just created a
14448 : // brand new content viewer (about:blank) to host preview.
14449 0 : SetCurrentURI(uri, nullptr, true, 0);
14450 0 : print = do_QueryInterface(mContentViewer);
14451 0 : NS_ENSURE_STATE(print);
14452 0 : print->InitializeForPrintPreview();
14453 : }
14454 0 : nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
14455 0 : result.forget(aPrintPreview);
14456 0 : return NS_OK;
14457 : #else
14458 : return NS_ERROR_NOT_IMPLEMENTED;
14459 : #endif
14460 : }
14461 :
14462 : #ifdef DEBUG
14463 : unsigned long nsDocShell::gNumberOfDocShells = 0;
14464 : #endif
14465 :
14466 : NS_IMETHODIMP
14467 7 : nsDocShell::GetCanExecuteScripts(bool* aResult)
14468 : {
14469 7 : *aResult = mCanExecuteScripts;
14470 7 : return NS_OK;
14471 : }
14472 :
14473 : /* [infallible] */ NS_IMETHODIMP
14474 1 : nsDocShell::SetFrameType(uint32_t aFrameType)
14475 : {
14476 1 : mFrameType = aFrameType;
14477 1 : return NS_OK;
14478 : }
14479 :
14480 : /* [infallible] */ NS_IMETHODIMP
14481 0 : nsDocShell::GetFrameType(uint32_t* aFrameType)
14482 : {
14483 0 : *aFrameType = mFrameType;
14484 0 : return NS_OK;
14485 : }
14486 :
14487 : /* [infallible] */ NS_IMETHODIMP
14488 347 : nsDocShell::GetIsMozBrowser(bool* aIsMozBrowser)
14489 : {
14490 347 : *aIsMozBrowser = (mFrameType == FRAME_TYPE_BROWSER);
14491 347 : return NS_OK;
14492 : }
14493 :
14494 : uint32_t
14495 4 : nsDocShell::GetInheritedFrameType()
14496 : {
14497 4 : if (mFrameType != FRAME_TYPE_REGULAR) {
14498 0 : return mFrameType;
14499 : }
14500 :
14501 8 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
14502 4 : GetSameTypeParent(getter_AddRefs(parentAsItem));
14503 :
14504 8 : nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
14505 4 : if (!parent) {
14506 3 : return FRAME_TYPE_REGULAR;
14507 : }
14508 :
14509 1 : return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
14510 : }
14511 :
14512 : /* [infallible] */ NS_IMETHODIMP
14513 0 : nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement)
14514 : {
14515 0 : bool result = mFrameType == FRAME_TYPE_BROWSER &&
14516 0 : mOriginAttributes.mInIsolatedMozBrowser;
14517 0 : *aIsIsolatedMozBrowserElement = result;
14518 0 : return NS_OK;
14519 : }
14520 :
14521 : /* [infallible] */ NS_IMETHODIMP
14522 3 : nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
14523 : {
14524 3 : MOZ_ASSERT(!mOriginAttributes.mInIsolatedMozBrowser ||
14525 : (GetInheritedFrameType() == FRAME_TYPE_BROWSER),
14526 : "Isolated mozbrowser should only be true inside browser frames");
14527 3 : bool result = (GetInheritedFrameType() == FRAME_TYPE_BROWSER) &&
14528 3 : mOriginAttributes.mInIsolatedMozBrowser;
14529 3 : *aIsInIsolatedMozBrowserElement = result;
14530 3 : return NS_OK;
14531 : }
14532 :
14533 : /* [infallible] */ NS_IMETHODIMP
14534 0 : nsDocShell::GetIsInMozBrowser(bool* aIsInMozBrowser)
14535 : {
14536 0 : *aIsInMozBrowser = (GetInheritedFrameType() == FRAME_TYPE_BROWSER);
14537 0 : return NS_OK;
14538 : }
14539 :
14540 : /* [infallible] */ NS_IMETHODIMP
14541 0 : nsDocShell::GetIsTopLevelContentDocShell(bool* aIsTopLevelContentDocShell)
14542 : {
14543 0 : *aIsTopLevelContentDocShell = false;
14544 :
14545 0 : if (mItemType == typeContent) {
14546 0 : nsCOMPtr<nsIDocShellTreeItem> root;
14547 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
14548 0 : *aIsTopLevelContentDocShell = root.get() == static_cast<nsIDocShellTreeItem*>(this);
14549 : }
14550 :
14551 0 : return NS_OK;
14552 : }
14553 :
14554 : // Implements nsILoadContext.originAttributes
14555 : NS_IMETHODIMP
14556 3 : nsDocShell::GetScriptableOriginAttributes(JS::MutableHandle<JS::Value> aVal)
14557 : {
14558 3 : JSContext* cx = nsContentUtils::GetCurrentJSContext();
14559 3 : MOZ_ASSERT(cx);
14560 :
14561 3 : return GetOriginAttributes(cx, aVal);
14562 : }
14563 :
14564 : // Implements nsIDocShell.GetOriginAttributes()
14565 : NS_IMETHODIMP
14566 3 : nsDocShell::GetOriginAttributes(JSContext* aCx,
14567 : JS::MutableHandle<JS::Value> aVal)
14568 : {
14569 3 : bool ok = ToJSValue(aCx, mOriginAttributes, aVal);
14570 3 : NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
14571 3 : return NS_OK;
14572 : }
14573 :
14574 : bool
14575 3 : nsDocShell::CanSetOriginAttributes()
14576 : {
14577 3 : MOZ_ASSERT(mChildList.IsEmpty());
14578 3 : if (!mChildList.IsEmpty()) {
14579 0 : return false;
14580 : }
14581 :
14582 : // TODO: Bug 1273058 - mContentViewer should be null when setting origin
14583 : // attributes.
14584 3 : if (mContentViewer) {
14585 0 : nsIDocument* doc = mContentViewer->GetDocument();
14586 0 : if (doc) {
14587 0 : nsIURI* uri = doc->GetDocumentURI();
14588 0 : if (!uri) {
14589 0 : return false;
14590 : }
14591 0 : nsCString uriSpec = uri->GetSpecOrDefault();
14592 0 : MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank"));
14593 0 : if (!uriSpec.EqualsLiteral("about:blank")) {
14594 0 : return false;
14595 : }
14596 : }
14597 : }
14598 :
14599 3 : return true;
14600 : }
14601 :
14602 : nsresult
14603 3 : nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs)
14604 : {
14605 3 : if (!CanSetOriginAttributes()) {
14606 0 : return NS_ERROR_FAILURE;
14607 : }
14608 :
14609 3 : AssertOriginAttributesMatchPrivateBrowsing();
14610 3 : mOriginAttributes = aAttrs;
14611 :
14612 3 : bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
14613 : // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
14614 3 : if (mItemType == typeChrome && isPrivate) {
14615 0 : mOriginAttributes.mPrivateBrowsingId = 0;
14616 : }
14617 :
14618 3 : SetPrivateBrowsing(isPrivate);
14619 3 : AssertOriginAttributesMatchPrivateBrowsing();
14620 :
14621 3 : return NS_OK;
14622 : }
14623 :
14624 : NS_IMETHODIMP
14625 0 : nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes)
14626 : {
14627 0 : if (!aOriginAttributes.isObject()) {
14628 0 : return NS_ERROR_INVALID_ARG;
14629 : }
14630 :
14631 0 : AutoJSAPI jsapi;
14632 0 : if (!jsapi.Init(&aOriginAttributes.toObject())) {
14633 0 : return NS_ERROR_UNEXPECTED;
14634 : }
14635 :
14636 0 : JSContext* cx = jsapi.cx();
14637 0 : if (NS_WARN_IF(!cx)) {
14638 0 : return NS_ERROR_FAILURE;
14639 : }
14640 :
14641 0 : OriginAttributes attrs;
14642 0 : if (!aOriginAttributes.isObject() || !attrs.Init(cx, aOriginAttributes)) {
14643 0 : return NS_ERROR_INVALID_ARG;
14644 : }
14645 :
14646 0 : return SetOriginAttributes(attrs);
14647 : }
14648 :
14649 : NS_IMETHODIMP
14650 0 : nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
14651 : JSContext* aCx)
14652 : {
14653 0 : OriginAttributes attrs;
14654 0 : if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
14655 0 : return NS_ERROR_INVALID_ARG;
14656 : }
14657 :
14658 0 : return SetOriginAttributes(attrs);
14659 : }
14660 :
14661 : NS_IMETHODIMP
14662 0 : nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
14663 : {
14664 0 : if (nsIPresShell* presShell = GetPresShell()) {
14665 0 : *aOut = presShell->AsyncPanZoomEnabled();
14666 0 : return NS_OK;
14667 : }
14668 :
14669 : // If we don't have a presShell, fall back to the default platform value of
14670 : // whether or not APZ is enabled.
14671 0 : *aOut = gfxPlatform::AsyncPanZoomEnabled();
14672 0 : return NS_OK;
14673 : }
14674 :
14675 : bool
14676 6 : nsDocShell::HasUnloadedParent()
14677 : {
14678 12 : RefPtr<nsDocShell> parent = GetParentDocshell();
14679 10 : while (parent) {
14680 2 : bool inUnload = false;
14681 2 : parent->GetIsInUnload(&inUnload);
14682 2 : if (inUnload) {
14683 0 : return true;
14684 : }
14685 2 : parent = parent->GetParentDocshell();
14686 : }
14687 6 : return false;
14688 : }
14689 :
14690 : void
14691 3 : nsDocShell::UpdateGlobalHistoryTitle(nsIURI* aURI)
14692 : {
14693 3 : if (mUseGlobalHistory && !UsePrivateBrowsing()) {
14694 2 : nsCOMPtr<IHistory> history = services::GetHistoryService();
14695 1 : if (mPrerenderGlobalHistory) {
14696 0 : mPrerenderGlobalHistory->SetURITitle(aURI, mTitle);
14697 1 : } else if (history) {
14698 1 : history->SetURITitle(aURI, mTitle);
14699 0 : } else if (mGlobalHistory) {
14700 0 : mGlobalHistory->SetPageTitle(aURI, nsString(mTitle));
14701 : }
14702 : }
14703 3 : }
14704 :
14705 : bool
14706 7 : nsDocShell::IsInvisible()
14707 : {
14708 7 : return mInvisible;
14709 : }
14710 :
14711 : void
14712 0 : nsDocShell::SetInvisible(bool aInvisible)
14713 : {
14714 0 : mInvisible = aInvisible;
14715 0 : }
14716 :
14717 : void
14718 2 : nsDocShell::SetOpener(nsITabParent* aOpener)
14719 : {
14720 2 : mOpener = do_GetWeakReference(aOpener);
14721 2 : }
14722 :
14723 : nsITabParent*
14724 1 : nsDocShell::GetOpener()
14725 : {
14726 2 : nsCOMPtr<nsITabParent> opener(do_QueryReferent(mOpener));
14727 2 : return opener;
14728 : }
14729 :
14730 : // The caller owns |aAsyncCause| here.
14731 : void
14732 0 : nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
14733 : const char16_t* aFunctionName,
14734 : const char16_t* aFilename,
14735 : const uint32_t aLineNumber,
14736 : JS::Handle<JS::Value> aAsyncStack,
14737 : const char* aAsyncCause)
14738 : {
14739 : // If first start, mark interval start.
14740 0 : if (mJSRunToCompletionDepth == 0) {
14741 0 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
14742 0 : if (timelines && timelines->HasConsumer(this)) {
14743 0 : timelines->AddMarkerForDocShell(this, Move(
14744 0 : mozilla::MakeUnique<JavascriptTimelineMarker>(
14745 : aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START,
14746 0 : aAsyncStack, aAsyncCause)));
14747 : }
14748 : }
14749 :
14750 0 : mJSRunToCompletionDepth++;
14751 0 : }
14752 :
14753 : void
14754 0 : nsDocShell::NotifyJSRunToCompletionStop()
14755 : {
14756 0 : mJSRunToCompletionDepth--;
14757 :
14758 : // If last stop, mark interval end.
14759 0 : if (mJSRunToCompletionDepth == 0) {
14760 0 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
14761 0 : if (timelines && timelines->HasConsumer(this)) {
14762 0 : timelines->AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
14763 : }
14764 : }
14765 0 : }
14766 :
14767 : void
14768 3 : nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
14769 : const nsString& aKeyword)
14770 : {
14771 3 : if (aProvider.IsEmpty()) {
14772 6 : return;
14773 : }
14774 :
14775 0 : if (XRE_IsContentProcess()) {
14776 0 : dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
14777 0 : if (contentChild) {
14778 0 : contentChild->SendNotifyKeywordSearchLoading(aProvider, aKeyword);
14779 : }
14780 0 : return;
14781 : }
14782 :
14783 : #ifdef MOZ_TOOLKIT_SEARCH
14784 : nsCOMPtr<nsIBrowserSearchService> searchSvc =
14785 0 : do_GetService("@mozilla.org/browser/search-service;1");
14786 0 : if (searchSvc) {
14787 0 : nsCOMPtr<nsISearchEngine> searchEngine;
14788 0 : searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine));
14789 0 : if (searchEngine) {
14790 0 : nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
14791 0 : if (obsSvc) {
14792 : // Note that "keyword-search" refers to a search via the url
14793 : // bar, not a bookmarks keyword search.
14794 0 : obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get());
14795 : }
14796 : }
14797 : }
14798 : #endif
14799 : }
14800 :
14801 : NS_IMETHODIMP
14802 4 : nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceRequest,
14803 : bool* aShouldIntercept)
14804 : {
14805 4 : *aShouldIntercept = false;
14806 : // No in private browsing
14807 4 : if (UsePrivateBrowsing()) {
14808 0 : return NS_OK;
14809 : }
14810 :
14811 4 : if (mSandboxFlags) {
14812 : // If we're sandboxed, don't intercept.
14813 0 : return NS_OK;
14814 : }
14815 :
14816 8 : RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
14817 4 : if (!swm) {
14818 0 : return NS_OK;
14819 : }
14820 :
14821 : nsresult result;
14822 : nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
14823 8 : do_GetService(THIRDPARTYUTIL_CONTRACTID, &result);
14824 4 : NS_ENSURE_SUCCESS(result, result);
14825 :
14826 8 : if (mCurrentURI &&
14827 8 : nsContentUtils::CookiesBehavior() == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
14828 0 : nsAutoCString uriSpec;
14829 0 : if (!(mCurrentURI->GetSpecOrDefault().EqualsLiteral("about:blank"))) {
14830 : // Reject the interception of third-party iframes if the cookie behaviour
14831 : // is set to reject all third-party cookies (1). In case that this pref
14832 : // is not set or can't be read, we default to allow all cookies (0) as
14833 : // this is the default value in all.js.
14834 0 : bool isThirdPartyURI = true;
14835 0 : result = thirdPartyUtil->IsThirdPartyURI(mCurrentURI, aURI,
14836 0 : &isThirdPartyURI);
14837 0 : if (NS_FAILED(result)) {
14838 0 : return result;
14839 : }
14840 :
14841 0 : if (isThirdPartyURI) {
14842 0 : return NS_OK;
14843 : }
14844 : }
14845 : }
14846 :
14847 4 : if (aIsNonSubresourceRequest) {
14848 : nsCOMPtr<nsIPrincipal> principal =
14849 2 : BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
14850 1 : *aShouldIntercept = swm->IsAvailable(principal, aURI);
14851 1 : return NS_OK;
14852 : }
14853 :
14854 6 : nsCOMPtr<nsIDocument> doc = GetDocument();
14855 3 : if (!doc) {
14856 0 : return NS_ERROR_NOT_AVAILABLE;
14857 : }
14858 :
14859 6 : ErrorResult rv;
14860 3 : *aShouldIntercept = swm->IsControlled(doc, rv);
14861 3 : if (NS_WARN_IF(rv.Failed())) {
14862 0 : return rv.StealNSResult();
14863 : }
14864 :
14865 3 : return NS_OK;
14866 : }
14867 :
14868 : NS_IMETHODIMP
14869 0 : nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
14870 : {
14871 0 : RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
14872 0 : if (!swm) {
14873 0 : aChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
14874 0 : return NS_OK;
14875 : }
14876 :
14877 0 : nsCOMPtr<nsIChannel> channel;
14878 0 : nsresult rv = aChannel->GetChannel(getter_AddRefs(channel));
14879 0 : NS_ENSURE_SUCCESS(rv, rv);
14880 :
14881 0 : nsCOMPtr<nsIDocument> doc;
14882 :
14883 0 : bool isSubresourceLoad = !nsContentUtils::IsNonSubresourceRequest(channel);
14884 0 : if (isSubresourceLoad) {
14885 0 : doc = GetDocument();
14886 0 : if (!doc) {
14887 0 : return NS_ERROR_NOT_AVAILABLE;
14888 : }
14889 : } else {
14890 : // For top-level navigations, save a document ID which will be passed to
14891 : // the FetchEvent as the clientId later on.
14892 0 : rv = nsIDocument::GenerateDocumentId(mInterceptedDocumentId);
14893 0 : NS_ENSURE_SUCCESS(rv, rv);
14894 : }
14895 :
14896 0 : bool isReload = mLoadType & LOAD_CMD_RELOAD;
14897 :
14898 0 : ErrorResult error;
14899 0 : swm->DispatchFetchEvent(mOriginAttributes, doc, mInterceptedDocumentId,
14900 0 : aChannel, isReload, isSubresourceLoad, error);
14901 0 : if (NS_WARN_IF(error.Failed())) {
14902 0 : return error.StealNSResult();
14903 : }
14904 :
14905 0 : return NS_OK;
14906 : }
14907 :
14908 : bool
14909 0 : nsDocShell::InFrameSwap()
14910 : {
14911 0 : RefPtr<nsDocShell> shell = this;
14912 0 : do {
14913 0 : if (shell->mInFrameSwap) {
14914 0 : return true;
14915 : }
14916 0 : shell = shell->GetParentDocshell();
14917 : } while (shell);
14918 0 : return false;
14919 : }
14920 :
14921 : NS_IMETHODIMP
14922 0 : nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError)
14923 : {
14924 0 : if (mContentViewer) {
14925 0 : nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
14926 0 : if (doc) {
14927 0 : doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
14928 : }
14929 : }
14930 0 : return NS_OK;
14931 : }
14932 :
14933 : NS_IMETHODIMP
14934 0 : nsDocShell::GetEditingSession(nsIEditingSession** aEditSession)
14935 : {
14936 0 : if (!NS_SUCCEEDED(EnsureEditorData())) {
14937 0 : return NS_ERROR_FAILURE;
14938 : }
14939 :
14940 0 : mEditorData->GetEditingSession(aEditSession);
14941 0 : return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
14942 : }
14943 :
14944 : NS_IMETHODIMP
14945 0 : nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild)
14946 : {
14947 0 : *aTabChild = GetTabChild().take();
14948 0 : return *aTabChild ? NS_OK : NS_ERROR_FAILURE;
14949 : }
14950 :
14951 : already_AddRefed<nsITabChild>
14952 29 : nsDocShell::GetTabChild()
14953 : {
14954 58 : nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner);
14955 58 : nsCOMPtr<nsITabChild> tc = do_GetInterface(owner);
14956 58 : return tc.forget();
14957 : }
14958 :
14959 : nsICommandManager*
14960 0 : nsDocShell::GetCommandManager()
14961 : {
14962 0 : NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr);
14963 0 : return mCommandManager;
14964 : }
14965 :
14966 : NS_IMETHODIMP
14967 0 : nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult)
14968 : {
14969 0 : MOZ_ASSERT(aResult);
14970 :
14971 0 : nsPIDOMWindowOuter* outer = GetWindow();
14972 0 : MOZ_ASSERT(outer);
14973 :
14974 : // If we are not toplevel then we are not the only toplevel window in the tab
14975 : // group.
14976 0 : if (outer->GetScriptableParentOrNull()) {
14977 0 : *aResult = false;
14978 0 : return NS_OK;
14979 : }
14980 :
14981 : // If we have any other toplevel windows in our tab group, then we are not the
14982 : // only toplevel window in the tab group.
14983 : nsTArray<nsPIDOMWindowOuter*> toplevelWindows =
14984 0 : outer->TabGroup()->GetTopLevelWindows();
14985 0 : if (toplevelWindows.Length() > 1) {
14986 0 : *aResult = false;
14987 0 : return NS_OK;
14988 : }
14989 0 : MOZ_ASSERT(toplevelWindows.Length() == 1);
14990 0 : MOZ_ASSERT(toplevelWindows[0] == outer);
14991 :
14992 0 : *aResult = true;
14993 0 : return NS_OK;
14994 : }
14995 :
14996 : NS_IMETHODIMP
14997 0 : nsDocShell::GetAwaitingLargeAlloc(bool* aResult)
14998 : {
14999 0 : MOZ_ASSERT(aResult);
15000 0 : nsCOMPtr<nsITabChild> tabChild = GetTabChild();
15001 0 : if (!tabChild) {
15002 0 : *aResult = false;
15003 0 : return NS_OK;
15004 : }
15005 0 : *aResult = static_cast<TabChild*>(tabChild.get())->IsAwaitingLargeAlloc();
15006 0 : return NS_OK;
15007 : }
15008 :
15009 : NS_IMETHODIMP_(void)
15010 11 : nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs)
15011 : {
15012 11 : aAttrs = mOriginAttributes;
15013 11 : }
|