docshell/base/nsDocShell.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set ts=4 sw=4 tw=80 et: */
     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/. */
     7 #include "nsDocShell.h"
     9 #include <algorithm>
    11 #include "mozilla/ArrayUtils.h"
    12 #include "mozilla/Attributes.h"
    13 #include "mozilla/AutoRestore.h"
    14 #include "mozilla/Casting.h"
    15 #include "mozilla/dom/ContentChild.h"
    16 #include "mozilla/dom/Element.h"
    17 #include "mozilla/dom/TabChild.h"
    18 #include "mozilla/EventStateManager.h"
    19 #include "mozilla/Preferences.h"
    20 #include "mozilla/Services.h"
    21 #include "mozilla/StartupTimeline.h"
    22 #include "mozilla/Telemetry.h"
    23 #include "mozilla/unused.h"
    24 #include "mozilla/VisualEventTracer.h"
    26 #ifdef MOZ_LOGGING
    27 // so we can get logging even in release builds (but only for some things)
    28 #define FORCE_PR_LOG 1
    29 #endif
    31 #include "nsIContent.h"
    32 #include "nsIDocument.h"
    33 #include "nsIDOMDocument.h"
    34 #include "nsIDOMElement.h"
    35 #include "nsIDOMStorage.h"
    36 #include "nsPIDOMStorage.h"
    37 #include "nsIContentViewer.h"
    38 #include "nsIDocumentLoaderFactory.h"
    39 #include "nsCURILoader.h"
    40 #include "nsDocShellCID.h"
    41 #include "nsDOMCID.h"
    42 #include "nsNetUtil.h"
    43 #include "nsRect.h"
    44 #include "prenv.h"
    45 #include "nsIMarkupDocumentViewer.h"
    46 #include "nsIDOMWindow.h"
    47 #include "nsIWebBrowserChrome.h"
    48 #include "nsPoint.h"
    49 #include "nsIObserverService.h"
    50 #include "nsIPrompt.h"
    51 #include "nsIAuthPrompt.h"
    52 #include "nsIAuthPrompt2.h"
    53 #include "nsIChannelEventSink.h"
    54 #include "nsIAsyncVerifyRedirectCallback.h"
    55 #include "nsIScriptSecurityManager.h"
    56 #include "nsIScriptObjectPrincipal.h"
    57 #include "nsIScrollableFrame.h"
    58 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
    59 #include "nsISeekableStream.h"
    60 #include "nsAutoPtr.h"
    61 #include "nsIWritablePropertyBag2.h"
    62 #include "nsIAppShell.h"
    63 #include "nsWidgetsCID.h"
    64 #include "nsIInterfaceRequestorUtils.h"
    65 #include "nsView.h"
    66 #include "nsViewManager.h"
    67 #include "nsIScriptChannel.h"
    68 #include "nsITimedChannel.h"
    69 #include "nsIPrivacyTransitionObserver.h"
    70 #include "nsIReflowObserver.h"
    71 #include "nsIScrollObserver.h"
    72 #include "nsIDocShellTreeItem.h"
    73 #include "nsIChannel.h"
    74 #include "IHistory.h"
    75 #include "nsViewSourceHandler.h"
    77 // we want to explore making the document own the load group
    78 // so we can associate the document URI with the load group.
    79 // until this point, we have an evil hack:
    80 #include "nsIHttpChannelInternal.h"  
    81 #include "nsPILoadGroupInternal.h"
    83 // Local Includes
    84 #include "nsDocShellLoadInfo.h"
    85 #include "nsCDefaultURIFixup.h"
    86 #include "nsDocShellEnumerator.h"
    87 #include "nsSHistory.h"
    88 #include "nsDocShellEditorData.h"
    90 // Helper Classes
    91 #include "nsError.h"
    92 #include "nsEscape.h"
    94 // Interfaces Needed
    95 #include "nsIUploadChannel.h"
    96 #include "nsIUploadChannel2.h"
    97 #include "nsIWebProgress.h"
    98 #include "nsILayoutHistoryState.h"
    99 #include "nsITimer.h"
   100 #include "nsISHistoryInternal.h"
   101 #include "nsIPrincipal.h"
   102 #include "nsISHEntry.h"
   103 #include "nsIWindowWatcher.h"
   104 #include "nsIPromptFactory.h"
   105 #include "nsITransportSecurityInfo.h"
   106 #include "nsINSSErrorsService.h"
   107 #include "nsIApplicationCacheChannel.h"
   108 #include "nsIApplicationCacheContainer.h"
   109 #include "nsStreamUtils.h"
   110 #include "nsIController.h"
   111 #include "nsPICommandUpdater.h"
   112 #include "nsIDOMHTMLAnchorElement.h"
   113 #include "nsIWebBrowserChrome3.h"
   114 #include "nsITabChild.h"
   115 #include "nsISiteSecurityService.h"
   116 #include "nsStructuredCloneContainer.h"
   117 #include "nsIStructuredCloneContainer.h"
   118 #ifdef MOZ_PLACES
   119 #include "nsIFaviconService.h"
   120 #include "mozIAsyncFavicons.h"
   121 #endif
   122 #include "nsINetworkSeer.h"
   124 // Editor-related
   125 #include "nsIEditingSession.h"
   127 #include "nsPIDOMWindow.h"
   128 #include "nsGlobalWindow.h"
   129 #include "nsPIWindowRoot.h"
   130 #include "nsICachingChannel.h"
   131 #include "nsIMultiPartChannel.h"
   132 #include "nsIWyciwygChannel.h"
   134 // For reporting errors with the console service.
   135 // These can go away if error reporting is propagated up past nsDocShell.
   136 #include "nsIScriptError.h"
   138 // used to dispatch urls to default protocol handlers
   139 #include "nsCExternalHandlerService.h"
   140 #include "nsIExternalProtocolService.h"
   142 #include "nsFocusManager.h"
   144 #include "nsITextToSubURI.h"
   146 #include "nsIJARChannel.h"
   148 #include "prlog.h"
   150 #include "nsISelectionDisplay.h"
   152 #include "nsIGlobalHistory2.h"
   154 #include "nsIFrame.h"
   155 #include "nsSubDocumentFrame.h"
   157 // for embedding
   158 #include "nsIWebBrowserChromeFocus.h"
   160 #if NS_PRINT_PREVIEW
   161 #include "nsIDocumentViewerPrint.h"
   162 #include "nsIWebBrowserPrint.h"
   163 #endif
   165 #include "nsContentUtils.h"
   166 #include "nsCxPusher.h"
   167 #include "nsIChannelPolicy.h"
   168 #include "nsIContentSecurityPolicy.h"
   169 #include "nsSandboxFlags.h"
   170 #include "mozIThirdPartyUtil.h"
   171 #include "nsXULAppAPI.h"
   172 #include "nsDOMNavigationTiming.h"
   173 #include "nsISecurityUITelemetry.h"
   174 #include "nsIAppsService.h"
   175 #include "nsDSURIContentListener.h"
   176 #include "nsDocShellLoadTypes.h"
   177 #include "nsDocShellTransferableHooks.h"
   178 #include "nsICommandManager.h"
   179 #include "nsIDOMNode.h"
   180 #include "nsIDocShellTreeOwner.h"
   181 #include "nsIHttpChannel.h"
   182 #include "nsISHContainer.h"
   183 #include "nsISHistory.h"
   184 #include "nsISecureBrowserUI.h"
   185 #include "nsIStringBundle.h"
   186 #include "nsISupportsArray.h"
   187 #include "nsIURIFixup.h"
   188 #include "nsIURILoader.h"
   189 #include "nsIWebBrowserFind.h"
   190 #include "nsIWidget.h"
   191 #include "mozilla/dom/EncodingUtils.h"
   193 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
   195 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
   196 //#define DEBUG_DOCSHELL_FOCUS
   197 #define DEBUG_PAGE_CACHE
   198 #endif
   200 #ifdef XP_WIN
   201 #include <process.h>
   202 #define getpid _getpid
   203 #else
   204 #include <unistd.h> // for getpid()
   205 #endif
   207 using namespace mozilla;
   208 using namespace mozilla::dom;
   210 // True means sUseErrorPages has been added to preferences var cache.
   211 static bool gAddedPreferencesVarCache = false;
   213 bool nsDocShell::sUseErrorPages = false;
   215 // Number of documents currently loading
   216 static int32_t gNumberOfDocumentsLoading = 0;
   218 // Global count of existing docshells.
   219 static int32_t gDocShellCount = 0;
   221 // Global count of docshells with the private attribute set
   222 static uint32_t gNumberOfPrivateDocShells = 0;
   224 // Global reference to the URI fixup service.
   225 nsIURIFixup *nsDocShell::sURIFixup = 0;
   227 // True means we validate window targets to prevent frameset
   228 // spoofing. Initialize this to a non-bolean value so we know to check
   229 // the pref on the creation of the first docshell.
   230 static uint32_t gValidateOrigin = 0xffffffff;
   232 // Hint for native dispatch of events on how long to delay after 
   233 // all documents have loaded in milliseconds before favoring normal
   234 // native event dispatch priorites over performance
   235 // Can be overridden with docshell.event_starvation_delay_hint pref.
   236 #define NS_EVENT_STARVATION_DELAY_HINT 2000
   238 #ifdef PR_LOGGING
   239 #ifdef DEBUG
   240 static PRLogModuleInfo* gDocShellLog;
   241 #endif
   242 static PRLogModuleInfo* gDocShellLeakLog;
   243 #endif
   245 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
   246 const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
   248 static void
   249 FavorPerformanceHint(bool perfOverStarvation)
   250 {
   251     nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
   252     if (appShell) {
   253         appShell->FavorPerformanceHint(perfOverStarvation,
   254                                        Preferences::GetUint("docshell.event_starvation_delay_hint",
   255                                                             NS_EVENT_STARVATION_DELAY_HINT));
   256     }
   257 }
   259 //*****************************************************************************
   260 // <a ping> support
   261 //*****************************************************************************
   263 #define PREF_PINGS_ENABLED           "browser.send_pings"
   264 #define PREF_PINGS_MAX_PER_LINK      "browser.send_pings.max_per_link"
   265 #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
   267 // Check prefs to see if pings are enabled and if so what restrictions might
   268 // be applied.
   269 //
   270 // @param maxPerLink
   271 //   This parameter returns the number of pings that are allowed per link click
   272 //
   273 // @param requireSameHost
   274 //   This parameter returns true if pings are restricted to the same host as
   275 //   the document in which the click occurs.  If the same host restriction is
   276 //   imposed, then we still allow for pings to cross over to different
   277 //   protocols and ports for flexibility and because it is not possible to send
   278 //   a ping via FTP.
   279 //
   280 // @returns
   281 //   true if pings are enabled and false otherwise.
   282 //
   283 static bool
   284 PingsEnabled(int32_t *maxPerLink, bool *requireSameHost)
   285 {
   286   bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false);
   288   *maxPerLink = 1;
   289   *requireSameHost = true;
   291   if (allow) {
   292     Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, maxPerLink);
   293     Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost);
   294   }
   296   return allow;
   297 }
   299 static bool
   300 CheckPingURI(nsIURI* uri, nsIContent* content)
   301 {
   302   if (!uri)
   303     return false;
   305   // Check with nsIScriptSecurityManager
   306   nsCOMPtr<nsIScriptSecurityManager> ssmgr =
   307     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   308   NS_ENSURE_TRUE(ssmgr, false);
   310   nsresult rv =
   311     ssmgr->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri,
   312                                      nsIScriptSecurityManager::STANDARD);
   313   if (NS_FAILED(rv)) {
   314     return false;
   315   }
   317   // Ignore non-HTTP(S)
   318   bool match;
   319   if ((NS_FAILED(uri->SchemeIs("http", &match)) || !match) &&
   320       (NS_FAILED(uri->SchemeIs("https", &match)) || !match)) {
   321     return false;
   322   }
   324   // Check with contentpolicy
   325   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
   326   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING,
   327                                  uri,
   328                                  content->NodePrincipal(),
   329                                  content,
   330                                  EmptyCString(), // mime hint
   331                                  nullptr, //extra
   332                                  &shouldLoad);
   333   return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
   334 }
   336 typedef void (* ForEachPingCallback)(void *closure, nsIContent *content,
   337                                      nsIURI *uri, nsIIOService *ios);
   339 static void
   340 ForEachPing(nsIContent *content, ForEachPingCallback callback, void *closure)
   341 {
   342   // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
   343   //       since we'd still need to parse the resulting string.  Instead, we
   344   //       just parse the raw attribute.  It might be nice if the content node
   345   //       implemented an interface that exposed an enumeration of nsIURIs.
   347   // Make sure we are dealing with either an <A> or <AREA> element in the HTML
   348   // or XHTML namespace.
   349   if (!content->IsHTML())
   350     return;
   351   nsIAtom *nameAtom = content->Tag();
   352   if (nameAtom != nsGkAtoms::a && nameAtom != nsGkAtoms::area)
   353     return;
   355   nsCOMPtr<nsIAtom> pingAtom = do_GetAtom("ping");
   356   if (!pingAtom)
   357     return;
   359   nsAutoString value;
   360   content->GetAttr(kNameSpaceID_None, pingAtom, value);
   361   if (value.IsEmpty())
   362     return;
   364   nsCOMPtr<nsIIOService> ios = do_GetIOService();
   365   if (!ios)
   366     return;
   368   nsIDocument *doc = content->OwnerDoc();
   370   // value contains relative URIs split on spaces (U+0020)
   371   const char16_t *start = value.BeginReading();
   372   const char16_t *end   = value.EndReading();
   373   const char16_t *iter  = start;
   374   for (;;) {
   375     if (iter < end && *iter != ' ') {
   376       ++iter;
   377     } else {  // iter is pointing at either end or a space
   378       while (*start == ' ' && start < iter)
   379         ++start;
   380       if (iter != start) {
   381         nsCOMPtr<nsIURI> uri, baseURI = content->GetBaseURI();
   382         ios->NewURI(NS_ConvertUTF16toUTF8(Substring(start, iter)),
   383                     doc->GetDocumentCharacterSet().get(),
   384                     baseURI, getter_AddRefs(uri));
   385         if (CheckPingURI(uri, content)) {
   386           callback(closure, content, uri, ios);
   387         }
   388       }
   389       start = iter = iter + 1;
   390       if (iter >= end)
   391         break;
   392     }
   393   }
   394 }
   396 //----------------------------------------------------------------------
   398 // We wait this many milliseconds before killing the ping channel...
   399 #define PING_TIMEOUT 10000
   401 static void
   402 OnPingTimeout(nsITimer *timer, void *closure)
   403 {
   404   nsILoadGroup *loadGroup = static_cast<nsILoadGroup *>(closure);
   405   if (loadGroup)
   406     loadGroup->Cancel(NS_ERROR_ABORT);
   407 }
   409 // Check to see if two URIs have the same host or not
   410 static bool
   411 IsSameHost(nsIURI *uri1, nsIURI *uri2)
   412 {
   413   nsAutoCString host1, host2;
   414   uri1->GetAsciiHost(host1);
   415   uri2->GetAsciiHost(host2);
   416   return host1.Equals(host2);
   417 }
   419 class nsPingListener MOZ_FINAL : public nsIStreamListener
   420                                , public nsIInterfaceRequestor
   421                                , public nsIChannelEventSink
   422 {
   423 public:
   424   NS_DECL_ISUPPORTS
   425   NS_DECL_NSIREQUESTOBSERVER
   426   NS_DECL_NSISTREAMLISTENER
   427   NS_DECL_NSIINTERFACEREQUESTOR
   428   NS_DECL_NSICHANNELEVENTSINK
   430   nsPingListener(bool requireSameHost, nsIContent* content, nsILoadGroup* loadGroup)
   431     : mRequireSameHost(requireSameHost),
   432       mContent(content),
   433       mLoadGroup(loadGroup)
   434   {}
   436   ~nsPingListener();
   438   nsresult StartTimeout();
   440 private:
   441   bool mRequireSameHost;
   442   nsCOMPtr<nsIContent> mContent;
   443   nsCOMPtr<nsILoadGroup> mLoadGroup;
   444   nsCOMPtr<nsITimer> mTimer;
   445 };
   447 NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver,
   448                   nsIInterfaceRequestor, nsIChannelEventSink)
   450 nsPingListener::~nsPingListener()
   451 {
   452   if (mTimer) {
   453     mTimer->Cancel();
   454     mTimer = nullptr;
   455   }
   456 }
   458 nsresult
   459 nsPingListener::StartTimeout()
   460 {
   461   nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
   463   if (timer) {
   464     nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, mLoadGroup,
   465                                               PING_TIMEOUT,
   466                                               nsITimer::TYPE_ONE_SHOT);
   467     if (NS_SUCCEEDED(rv)) {
   468       mTimer = timer;
   469       return NS_OK;
   470     }
   471   }
   473   return NS_ERROR_OUT_OF_MEMORY;
   474 }
   476 NS_IMETHODIMP
   477 nsPingListener::OnStartRequest(nsIRequest *request, nsISupports *context)
   478 {
   479   return NS_OK;
   480 }
   482 NS_IMETHODIMP
   483 nsPingListener::OnDataAvailable(nsIRequest *request, nsISupports *context,
   484                                 nsIInputStream *stream, uint64_t offset,
   485                                 uint32_t count)
   486 {
   487   uint32_t result;
   488   return stream->ReadSegments(NS_DiscardSegment, nullptr, count, &result);
   489 }
   491 NS_IMETHODIMP
   492 nsPingListener::OnStopRequest(nsIRequest *request, nsISupports *context,
   493                               nsresult status)
   494 {
   495   mLoadGroup = nullptr;
   497   if (mTimer) {
   498     mTimer->Cancel();
   499     mTimer = nullptr;
   500   }
   502   return NS_OK;
   503 }
   505 NS_IMETHODIMP
   506 nsPingListener::GetInterface(const nsIID &iid, void **result)
   507 {
   508   if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
   509     NS_ADDREF_THIS();
   510     *result = (nsIChannelEventSink *) this;
   511     return NS_OK;
   512   }
   514   return NS_ERROR_NO_INTERFACE;
   515 }
   517 NS_IMETHODIMP
   518 nsPingListener::AsyncOnChannelRedirect(nsIChannel *oldChan, nsIChannel *newChan,
   519                                        uint32_t flags,
   520                                        nsIAsyncVerifyRedirectCallback *callback)
   521 {
   522   nsCOMPtr<nsIURI> newURI;
   523   newChan->GetURI(getter_AddRefs(newURI));
   525   if (!CheckPingURI(newURI, mContent))
   526     return NS_ERROR_ABORT;
   528   if (!mRequireSameHost) {
   529     callback->OnRedirectVerifyCallback(NS_OK);
   530     return NS_OK;
   531   }
   533   // XXXbz should this be using something more like the nsContentUtils
   534   // same-origin checker?
   535   nsCOMPtr<nsIURI> oldURI;
   536   oldChan->GetURI(getter_AddRefs(oldURI));
   537   NS_ENSURE_STATE(oldURI && newURI);
   539   if (!IsSameHost(oldURI, newURI))
   540     return NS_ERROR_ABORT;
   542   callback->OnRedirectVerifyCallback(NS_OK);
   543   return NS_OK;
   544 }
   546 struct SendPingInfo {
   547   int32_t numPings;
   548   int32_t maxPings;
   549   bool    requireSameHost;
   550   nsIURI *target;
   551   nsIURI *referrer;
   552 };
   554 static void
   555 SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
   556 {
   557   SendPingInfo *info = static_cast<SendPingInfo *>(closure);
   558   if (info->numPings >= info->maxPings)
   559     return;
   561   if (info->requireSameHost) {
   562     // Make sure the referrer and the given uri share the same origin.  We
   563     // only require the same hostname.  The scheme and port may differ.
   564     if (!IsSameHost(uri, info->referrer))
   565       return;
   566   }
   568   nsIDocument *doc = content->OwnerDoc();
   570   nsCOMPtr<nsIChannel> chan;
   571   ios->NewChannelFromURI(uri, getter_AddRefs(chan));
   572   if (!chan)
   573     return;
   575   // Don't bother caching the result of this URI load.
   576   chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING);
   578   nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
   579   if (!httpChan)
   580     return;
   582   // This is needed in order for 3rd-party cookie blocking to work.
   583   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
   584   if (httpInternal)
   585     httpInternal->SetDocumentURI(doc->GetDocumentURI());
   588   httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
   590   // Remove extraneous request headers (to reduce request size)
   591   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
   592                              EmptyCString(), false);
   593   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
   594                              EmptyCString(), false);
   595   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
   596                              EmptyCString(), false);
   598   // Always send a Ping-To header.
   599   nsAutoCString pingTo;
   600   if (NS_SUCCEEDED(info->target->GetSpec(pingTo)))
   601     httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
   603   nsCOMPtr<nsIScriptSecurityManager> sm =
   604     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   606   if (sm && info->referrer) {
   607     bool referrerIsSecure;
   608     uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
   609     nsresult rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
   611     // Default to sending less data if NS_URIChainHasFlags() fails.
   612     referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
   614     bool sameOrigin =
   615       NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, uri, false));
   617     // If both the address of the document containing the hyperlink being
   618     // audited and "ping URL" have the same origin or the document containing
   619     // the hyperlink being audited was not retrieved over an encrypted
   620     // connection, send a Ping-From header.
   621     if (sameOrigin || !referrerIsSecure) {
   622       nsAutoCString pingFrom;
   623       if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom)))
   624         httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom, false);
   625     }
   627     // If the document containing the hyperlink being audited was not retrieved
   628     // over an encrypted connection and its address does not have the same
   629     // origin as "ping URL", send a referrer.
   630     if (!sameOrigin && !referrerIsSecure)
   631       httpChan->SetReferrer(info->referrer);
   632   }
   634   nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan);
   635   if (!uploadChan)
   636     return;
   638   NS_NAMED_LITERAL_CSTRING(uploadData, "PING");
   640   nsCOMPtr<nsIInputStream> uploadStream;
   641   NS_NewPostDataStream(getter_AddRefs(uploadStream), false, uploadData);
   642   if (!uploadStream)
   643     return;
   645   uploadChan->ExplicitSetUploadStream(uploadStream,
   646     NS_LITERAL_CSTRING("text/ping"), uploadData.Length(),
   647     NS_LITERAL_CSTRING("POST"), false);
   649   // The channel needs to have a loadgroup associated with it, so that we can
   650   // cancel the channel and any redirected channels it may create.
   651   nsCOMPtr<nsILoadGroup> loadGroup =
   652       do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   653   if (!loadGroup)
   654     return;
   655   chan->SetLoadGroup(loadGroup);
   657   // Construct a listener that merely discards any response.  If successful at
   658   // opening the channel, then it is not necessary to hold a reference to the
   659   // channel.  The networking subsystem will take care of that for us.
   660   nsPingListener *pingListener =
   661       new nsPingListener(info->requireSameHost, content, loadGroup);
   662   if (!pingListener)
   663     return;
   665   nsCOMPtr<nsIStreamListener> listener(pingListener);
   667   // Observe redirects as well:
   668   nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(listener);
   669   NS_ASSERTION(callbacks, "oops");
   670   loadGroup->SetNotificationCallbacks(callbacks);
   672   chan->AsyncOpen(listener, nullptr);
   674   // Even if AsyncOpen failed, we still count this as a successful ping.  It's
   675   // possible that AsyncOpen may have failed after triggering some background
   676   // process that may have written something to the network.
   677   info->numPings++;
   679   // Prevent ping requests from stalling and never being garbage collected...
   680   if (NS_FAILED(pingListener->StartTimeout())) {
   681     // If we failed to setup the timer, then we should just cancel the channel
   682     // because we won't be able to ensure that it goes away in a timely manner.
   683     chan->Cancel(NS_ERROR_ABORT);
   684   }
   685 }
   687 // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
   688 static void
   689 DispatchPings(nsIContent *content, nsIURI *target, nsIURI *referrer)
   690 {
   691   SendPingInfo info;
   693   if (!PingsEnabled(&info.maxPings, &info.requireSameHost))
   694     return;
   695   if (info.maxPings == 0)
   696     return;
   698   info.numPings = 0;
   699   info.target = target;
   700   info.referrer = referrer;
   702   ForEachPing(content, SendPing, &info);
   703 }
   705 static nsDOMPerformanceNavigationType
   706 ConvertLoadTypeToNavigationType(uint32_t aLoadType)
   707 {
   708   // Not initialized, assume it's normal load.
   709   if (aLoadType == 0) {
   710     aLoadType = LOAD_NORMAL;
   711   }
   713   nsDOMPerformanceNavigationType result = dom::PerformanceNavigation::TYPE_RESERVED;
   714   switch (aLoadType) {
   715     case LOAD_NORMAL:
   716     case LOAD_NORMAL_EXTERNAL:
   717     case LOAD_NORMAL_BYPASS_CACHE:
   718     case LOAD_NORMAL_BYPASS_PROXY:
   719     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
   720     case LOAD_NORMAL_REPLACE:
   721     case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
   722     case LOAD_LINK:
   723     case LOAD_STOP_CONTENT:
   724     case LOAD_REPLACE_BYPASS_CACHE:
   725         result = dom::PerformanceNavigation::TYPE_NAVIGATE;
   726         break;
   727     case LOAD_HISTORY:
   728         result = dom::PerformanceNavigation::TYPE_BACK_FORWARD;
   729         break;
   730     case LOAD_RELOAD_NORMAL:
   731     case LOAD_RELOAD_CHARSET_CHANGE:
   732     case LOAD_RELOAD_BYPASS_CACHE:
   733     case LOAD_RELOAD_BYPASS_PROXY:
   734     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
   735     case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
   736         result = dom::PerformanceNavigation::TYPE_RELOAD;
   737         break;
   738     case LOAD_STOP_CONTENT_AND_REPLACE:
   739     case LOAD_REFRESH:
   740     case LOAD_BYPASS_HISTORY:
   741     case LOAD_ERROR_PAGE:
   742     case LOAD_PUSHSTATE:
   743         result = dom::PerformanceNavigation::TYPE_RESERVED;
   744         break;
   745     default:
   746         // NS_NOTREACHED("Unexpected load type value");
   747         result = dom::PerformanceNavigation::TYPE_RESERVED;
   748         break;
   749   }
   751   return result;
   752 }
   754 static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
   756 static void
   757 IncreasePrivateDocShellCount()
   758 {
   759     gNumberOfPrivateDocShells++;
   760     if (gNumberOfPrivateDocShells > 1 ||
   761         XRE_GetProcessType() != GeckoProcessType_Content) {
   762         return;
   763     }
   765     mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
   766     cc->SendPrivateDocShellsExist(true);
   767 }
   769 static void
   770 DecreasePrivateDocShellCount()
   771 {
   772     MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
   773     gNumberOfPrivateDocShells--;
   774     if (!gNumberOfPrivateDocShells)
   775     {
   776         if (XRE_GetProcessType() == GeckoProcessType_Content) {
   777             mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
   778             cc->SendPrivateDocShellsExist(false);
   779             return;
   780         }
   782         nsCOMPtr<nsIObserverService> obsvc = mozilla::services::GetObserverService();
   783         if (obsvc) {
   784             obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
   785         }
   786     }
   787 }
   789 //*****************************************************************************
   790 //***    nsDocShell: Object Management
   791 //*****************************************************************************
   793 static uint64_t gDocshellIDCounter = 0;
   795 // Note: operator new zeros our memory
   796 nsDocShell::nsDocShell():
   797     nsDocLoader(),
   798     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
   799     mTreeOwner(nullptr),
   800     mChromeEventHandler(nullptr),
   801     mCharsetReloadState(eCharsetReloadInit),
   802     mChildOffset(0),
   803     mBusyFlags(BUSY_FLAGS_NONE),
   804     mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
   805     mLoadType(0),
   806     mMarginWidth(-1),
   807     mMarginHeight(-1),
   808     mItemType(typeContent),
   809     mPreviousTransIndex(-1),
   810     mLoadedTransIndex(-1),
   811     mSandboxFlags(0),
   812     mFullscreenAllowed(CHECK_ATTRIBUTES),
   813     mCreated(false),
   814     mAllowSubframes(true),
   815     mAllowPlugins(true),
   816     mAllowJavascript(true),
   817     mAllowMetaRedirects(true),
   818     mAllowImages(true),
   819     mAllowMedia(true),
   820     mAllowDNSPrefetch(true),
   821     mAllowWindowControl(true),
   822     mAllowContentRetargeting(true),
   823     mCreatingDocument(false),
   824     mUseErrorPages(false),
   825     mObserveErrorPages(true),
   826     mAllowAuth(true),
   827     mAllowKeywordFixup(false),
   828     mIsOffScreenBrowser(false),
   829     mIsActive(true),
   830     mIsAppTab(false),
   831     mUseGlobalHistory(false),
   832     mInPrivateBrowsing(false),
   833     mUseRemoteTabs(false),
   834     mDeviceSizeIsPageSize(false),
   835     mCanExecuteScripts(false),
   836     mFiredUnloadEvent(false),
   837     mEODForCurrentDocument(false),
   838     mURIResultedInDocument(false),
   839     mIsBeingDestroyed(false),
   840     mIsExecutingOnLoadHandler(false),
   841     mIsPrintingOrPP(false),
   842     mSavingOldViewer(false),
   843 #ifdef DEBUG
   844     mInEnsureScriptEnv(false),
   845 #endif
   846     mAffectPrivateSessionLifetime(true),
   847     mInvisible(false),
   848     mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
   849     mFrameType(eFrameTypeRegular),
   850     mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID),
   851     mParentCharsetSource(0)
   852 {
   853     mHistoryID = ++gDocshellIDCounter;
   854     if (gDocShellCount++ == 0) {
   855         NS_ASSERTION(sURIFixup == nullptr,
   856                      "Huh, sURIFixup not null in first nsDocShell ctor!");
   858         CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
   859     }
   861 #ifdef PR_LOGGING
   862 #ifdef DEBUG
   863     if (! gDocShellLog)
   864         gDocShellLog = PR_NewLogModule("nsDocShell");
   865 #endif
   866     if (nullptr == gDocShellLeakLog)
   867         gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
   868     if (gDocShellLeakLog)
   869         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this));
   870 #endif
   872 #ifdef DEBUG
   873   // We're counting the number of |nsDocShells| to help find leaks
   874   ++gNumberOfDocShells;
   875   if (!PR_GetEnv("MOZ_QUIET")) {
   876       printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
   877                     (void*) this,
   878                     gNumberOfDocShells,
   879                     getpid(),
   880                     SafeCast<unsigned long long>(mHistoryID));
   881   }
   882 #endif
   883 }
   885 nsDocShell::~nsDocShell()
   886 {
   887     Destroy();
   889     nsCOMPtr<nsISHistoryInternal>
   890         shPrivate(do_QueryInterface(mSessionHistory));
   891     if (shPrivate) {
   892         shPrivate->SetRootDocShell(nullptr);
   893     }
   895     if (--gDocShellCount == 0) {
   896         NS_IF_RELEASE(sURIFixup);
   897     }
   899 #ifdef PR_LOGGING
   900     if (gDocShellLeakLog)
   901         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this));
   902 #endif
   904 #ifdef DEBUG
   905     // We're counting the number of |nsDocShells| to help find leaks
   906     --gNumberOfDocShells;
   907     if (!PR_GetEnv("MOZ_QUIET")) {
   908         printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
   909                       (void*) this,
   910                       gNumberOfDocShells,
   911                       getpid(),
   912                       SafeCast<unsigned long long>(mHistoryID));
   913     }
   914 #endif
   915 }
   917 nsresult
   918 nsDocShell::Init()
   919 {
   920     nsresult rv = nsDocLoader::Init();
   921     NS_ENSURE_SUCCESS(rv, rv);
   923     NS_ASSERTION(mLoadGroup, "Something went wrong!");
   925     mContentListener = new nsDSURIContentListener(this);
   926     NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
   928     rv = mContentListener->Init();
   929     NS_ENSURE_SUCCESS(rv, rv);
   931     // We want to hold a strong ref to the loadgroup, so it better hold a weak
   932     // ref to us...  use an InterfaceRequestorProxy to do this.
   933     nsCOMPtr<nsIInterfaceRequestor> proxy =
   934         new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>
   935                                                (this));
   936     NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
   937     mLoadGroup->SetNotificationCallbacks(proxy);
   939     rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
   940     NS_ENSURE_SUCCESS(rv, rv);
   942     // Add as |this| a progress listener to itself.  A little weird, but
   943     // simpler than reproducing all the listener-notification logic in
   944     // overrides of the various methods via which nsDocLoader can be
   945     // notified.   Note that this holds an nsWeakPtr to ourselves, so it's ok.
   946     return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
   947                                      nsIWebProgress::NOTIFY_STATE_NETWORK);
   949 }
   951 void
   952 nsDocShell::DestroyChildren()
   953 {
   954     nsCOMPtr<nsIDocShellTreeItem> shell;
   955     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
   956     while (iter.HasMore()) {
   957         shell = do_QueryObject(iter.GetNext());
   958         NS_ASSERTION(shell, "docshell has null child");
   960         if (shell) {
   961             shell->SetTreeOwner(nullptr);
   962         }
   963     }
   965     nsDocLoader::DestroyChildren();
   966 }
   968 //*****************************************************************************
   969 // nsDocShell::nsISupports
   970 //*****************************************************************************   
   972 NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
   973 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
   975 NS_INTERFACE_MAP_BEGIN(nsDocShell)
   976     NS_INTERFACE_MAP_ENTRY(nsIDocShell)
   977     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
   978     NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
   979     NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
   980     NS_INTERFACE_MAP_ENTRY(nsIScrollable)
   981     NS_INTERFACE_MAP_ENTRY(nsITextScroll)
   982     NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
   983     NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
   984     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
   985     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   986     NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
   987     NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
   988     NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
   989     NS_INTERFACE_MAP_ENTRY(nsILoadContext)
   990     NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
   991     NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
   992     NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
   993     NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
   994 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
   996 ///*****************************************************************************
   997 // nsDocShell::nsIInterfaceRequestor
   998 //*****************************************************************************   
   999 NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
  1001     NS_PRECONDITION(aSink, "null out param");
  1003     *aSink = nullptr;
  1005     if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
  1006         NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
  1007         *aSink = mCommandManager;
  1009     else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
  1010         *aSink = mContentListener;
  1012     else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
  1013               aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||
  1014               aIID.Equals(NS_GET_IID(nsIDOMWindow)) ||
  1015               aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) &&
  1016              NS_SUCCEEDED(EnsureScriptEnvironment())) {
  1017         return mScriptGlobal->QueryInterface(aIID, aSink);
  1019     else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
  1020              NS_SUCCEEDED(EnsureContentViewer())) {
  1021         mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
  1022         return *aSink ? NS_OK : NS_NOINTERFACE;
  1024     else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
  1025              NS_SUCCEEDED(EnsureContentViewer())) {
  1026         nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
  1027         doc.forget(aSink);
  1028         return *aSink ? NS_OK : NS_NOINTERFACE;
  1030     else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
  1031         *aSink = nullptr;
  1033         // Return application cache associated with this docshell, if any
  1035         nsCOMPtr<nsIContentViewer> contentViewer;
  1036         GetContentViewer(getter_AddRefs(contentViewer));
  1037         if (!contentViewer)
  1038             return NS_ERROR_NO_INTERFACE;
  1040         nsCOMPtr<nsIDOMDocument> domDoc;
  1041         contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
  1042         NS_ASSERTION(domDoc, "Should have a document.");
  1043         if (!domDoc)
  1044             return NS_ERROR_NO_INTERFACE;
  1046 #if defined(PR_LOGGING) && defined(DEBUG)
  1047         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
  1048                ("nsDocShell[%p]: returning app cache container %p",
  1049                 this, domDoc.get()));
  1050 #endif
  1051         return domDoc->QueryInterface(aIID, aSink);
  1053     else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
  1054              NS_SUCCEEDED(EnsureScriptEnvironment())) {
  1055         nsresult rv;
  1056         nsCOMPtr<nsIWindowWatcher> wwatch =
  1057             do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
  1058         NS_ENSURE_SUCCESS(rv, rv);
  1060         // Get the an auth prompter for our window so that the parenting
  1061         // of the dialogs works as it should when using tabs.
  1062         nsIPrompt *prompt;
  1063         rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt);
  1064         NS_ENSURE_SUCCESS(rv, rv);
  1066         *aSink = prompt;
  1067         return NS_OK;
  1069     else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
  1070              aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
  1071         return NS_SUCCEEDED(
  1072                 GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
  1073                 NS_OK : NS_NOINTERFACE;
  1075     else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
  1076         nsCOMPtr<nsISHistory> shistory;
  1077         nsresult
  1078             rv =
  1079             GetSessionHistory(getter_AddRefs(shistory));
  1080         if (NS_SUCCEEDED(rv) && shistory) {
  1081             *aSink = shistory;
  1082             NS_ADDREF((nsISupports *) * aSink);
  1083             return NS_OK;
  1085         return NS_NOINTERFACE;
  1087     else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
  1088         nsresult rv = EnsureFind();
  1089         if (NS_FAILED(rv)) return rv;
  1091         *aSink = mFind;
  1092         NS_ADDREF((nsISupports*)*aSink);
  1093         return NS_OK;
  1095     else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) {
  1096       nsCOMPtr<nsIEditingSession> editingSession;
  1097       mEditorData->GetEditingSession(getter_AddRefs(editingSession));
  1098       if (editingSession)
  1100         *aSink = editingSession;
  1101         NS_ADDREF((nsISupports *)*aSink);
  1102         return NS_OK;
  1105       return NS_NOINTERFACE;   
  1107     else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) 
  1108             && NS_SUCCEEDED(EnsureTransferableHookData())) {
  1109         *aSink = mTransferableHookData;
  1110         NS_ADDREF((nsISupports *)*aSink);
  1111         return NS_OK;
  1113     else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
  1114       nsIPresShell* shell = GetPresShell();
  1115       if (shell)
  1116         return shell->QueryInterface(aIID,aSink);    
  1118     else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
  1119       nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  1120       nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
  1121       if (NS_SUCCEEDED(rv) && treeOwner)
  1122         return treeOwner->QueryInterface(aIID, aSink);
  1124     else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
  1125       nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  1126       nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
  1127       if (NS_SUCCEEDED(rv) && treeOwner) {
  1128         nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(treeOwner);
  1129         if (ir)
  1130           return ir->GetInterface(aIID, aSink);
  1133     else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
  1134       nsCOMPtr<nsITabChild> tabChild =
  1135         do_GetInterface(static_cast<nsIDocShell*>(this));
  1136       nsCOMPtr<nsIContentFrameMessageManager> mm;
  1137       if (tabChild) {
  1138         tabChild->
  1139           GetMessageManager(getter_AddRefs(mm));
  1140       } else {
  1141         nsCOMPtr<nsPIDOMWindow> win =
  1142           do_GetInterface(static_cast<nsIDocShell*>(this));
  1143         if (win) {
  1144           mm = do_QueryInterface(win->GetParentTarget());
  1147       *aSink = mm.get();
  1149     else {
  1150       return nsDocLoader::GetInterface(aIID, aSink);
  1153     NS_IF_ADDREF(((nsISupports *) * aSink));
  1154     return *aSink ? NS_OK : NS_NOINTERFACE;
  1157 uint32_t
  1158 nsDocShell::
  1159 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType)
  1161     uint32_t loadType = LOAD_NORMAL;
  1163     switch (aDocShellLoadType) {
  1164     case nsIDocShellLoadInfo::loadNormal:
  1165         loadType = LOAD_NORMAL;
  1166         break;
  1167     case nsIDocShellLoadInfo::loadNormalReplace:
  1168         loadType = LOAD_NORMAL_REPLACE;
  1169         break;
  1170     case nsIDocShellLoadInfo::loadNormalExternal:
  1171         loadType = LOAD_NORMAL_EXTERNAL;
  1172         break;
  1173     case nsIDocShellLoadInfo::loadHistory:
  1174         loadType = LOAD_HISTORY;
  1175         break;
  1176     case nsIDocShellLoadInfo::loadNormalBypassCache:
  1177         loadType = LOAD_NORMAL_BYPASS_CACHE;
  1178         break;
  1179     case nsIDocShellLoadInfo::loadNormalBypassProxy:
  1180         loadType = LOAD_NORMAL_BYPASS_PROXY;
  1181         break;
  1182     case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
  1183         loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
  1184         break;
  1185     case nsIDocShellLoadInfo::loadNormalAllowMixedContent:
  1186         loadType = LOAD_NORMAL_ALLOW_MIXED_CONTENT;
  1187         break;
  1188     case nsIDocShellLoadInfo::loadReloadNormal:
  1189         loadType = LOAD_RELOAD_NORMAL;
  1190         break;
  1191     case nsIDocShellLoadInfo::loadReloadCharsetChange:
  1192         loadType = LOAD_RELOAD_CHARSET_CHANGE;
  1193         break;
  1194     case nsIDocShellLoadInfo::loadReloadBypassCache:
  1195         loadType = LOAD_RELOAD_BYPASS_CACHE;
  1196         break;
  1197     case nsIDocShellLoadInfo::loadReloadBypassProxy:
  1198         loadType = LOAD_RELOAD_BYPASS_PROXY;
  1199         break;
  1200     case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
  1201         loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
  1202         break;
  1203     case nsIDocShellLoadInfo::loadLink:
  1204         loadType = LOAD_LINK;
  1205         break;
  1206     case nsIDocShellLoadInfo::loadRefresh:
  1207         loadType = LOAD_REFRESH;
  1208         break;
  1209     case nsIDocShellLoadInfo::loadBypassHistory:
  1210         loadType = LOAD_BYPASS_HISTORY;
  1211         break;
  1212     case nsIDocShellLoadInfo::loadStopContent:
  1213         loadType = LOAD_STOP_CONTENT;
  1214         break;
  1215     case nsIDocShellLoadInfo::loadStopContentAndReplace:
  1216         loadType = LOAD_STOP_CONTENT_AND_REPLACE;
  1217         break;
  1218     case nsIDocShellLoadInfo::loadPushState:
  1219         loadType = LOAD_PUSHSTATE;
  1220         break;
  1221     case nsIDocShellLoadInfo::loadReplaceBypassCache:
  1222         loadType = LOAD_REPLACE_BYPASS_CACHE;
  1223         break;
  1224     case nsIDocShellLoadInfo::loadReloadMixedContent:
  1225         loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
  1226         break;
  1227     default:
  1228         NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
  1231     return loadType;
  1235 nsDocShellInfoLoadType
  1236 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType)
  1238     nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
  1239     switch (aLoadType) {
  1240     case LOAD_NORMAL:
  1241         docShellLoadType = nsIDocShellLoadInfo::loadNormal;
  1242         break;
  1243     case LOAD_NORMAL_REPLACE:
  1244         docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
  1245         break;
  1246     case LOAD_NORMAL_EXTERNAL:
  1247         docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
  1248         break;
  1249     case LOAD_NORMAL_BYPASS_CACHE:
  1250         docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
  1251         break;
  1252     case LOAD_NORMAL_BYPASS_PROXY:
  1253         docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
  1254         break;
  1255     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
  1256         docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
  1257         break;
  1258     case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
  1259         docShellLoadType = nsIDocShellLoadInfo::loadNormalAllowMixedContent;
  1260         break;
  1261     case LOAD_HISTORY:
  1262         docShellLoadType = nsIDocShellLoadInfo::loadHistory;
  1263         break;
  1264     case LOAD_RELOAD_NORMAL:
  1265         docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
  1266         break;
  1267     case LOAD_RELOAD_CHARSET_CHANGE:
  1268         docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
  1269         break;
  1270     case LOAD_RELOAD_BYPASS_CACHE:
  1271         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
  1272         break;
  1273     case LOAD_RELOAD_BYPASS_PROXY:
  1274         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
  1275         break;
  1276     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
  1277         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
  1278         break;
  1279     case LOAD_LINK:
  1280         docShellLoadType = nsIDocShellLoadInfo::loadLink;
  1281         break;
  1282     case LOAD_REFRESH:
  1283         docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
  1284         break;
  1285     case LOAD_BYPASS_HISTORY:
  1286     case LOAD_ERROR_PAGE:
  1287         docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
  1288         break;
  1289     case LOAD_STOP_CONTENT:
  1290         docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
  1291         break;
  1292     case LOAD_STOP_CONTENT_AND_REPLACE:
  1293         docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
  1294         break;
  1295     case LOAD_PUSHSTATE:
  1296         docShellLoadType = nsIDocShellLoadInfo::loadPushState;
  1297         break;
  1298     case LOAD_REPLACE_BYPASS_CACHE:
  1299         docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
  1300         break;
  1301     case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
  1302         docShellLoadType = nsIDocShellLoadInfo::loadReloadMixedContent;
  1303         break;
  1304     default:
  1305         NS_NOTREACHED("Unexpected load type value");
  1308     return docShellLoadType;
  1311 //*****************************************************************************
  1312 // nsDocShell::nsIDocShell
  1313 //*****************************************************************************   
  1314 NS_IMETHODIMP
  1315 nsDocShell::LoadURI(nsIURI * aURI,
  1316                     nsIDocShellLoadInfo * aLoadInfo,
  1317                     uint32_t aLoadFlags,
  1318                     bool aFirstParty)
  1320     NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
  1321                     "Unexpected flags");
  1322     NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
  1324     // Note: we allow loads to get through here even if mFiredUnloadEvent is
  1325     // true; that case will get handled in LoadInternal or LoadHistoryEntry.
  1326     if (IsPrintingOrPP()) {
  1327       return NS_OK; // JS may not handle returning of an error code
  1329     nsCOMPtr<nsIURI> referrer;
  1330     nsCOMPtr<nsIInputStream> postStream;
  1331     nsCOMPtr<nsIInputStream> headersStream;
  1332     nsCOMPtr<nsISupports> owner;
  1333     bool inheritOwner = false;
  1334     bool ownerIsExplicit = false;
  1335     bool sendReferrer = true;
  1336     bool isSrcdoc = false;
  1337     nsCOMPtr<nsISHEntry> shEntry;
  1338     nsXPIDLString target;
  1339     nsAutoString srcdoc;
  1340     nsCOMPtr<nsIDocShell> sourceDocShell;
  1341     nsCOMPtr<nsIURI> baseURI;
  1343     uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);    
  1345     NS_ENSURE_ARG(aURI);
  1347     if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
  1348         mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
  1349         StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
  1352     // Extract the info from the DocShellLoadInfo struct...
  1353     if (aLoadInfo) {
  1354         aLoadInfo->GetReferrer(getter_AddRefs(referrer));
  1356         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
  1357         aLoadInfo->GetLoadType(&lt);
  1358         // Get the appropriate loadType from nsIDocShellLoadInfo type
  1359         loadType = ConvertDocShellLoadInfoToLoadType(lt);
  1361         aLoadInfo->GetOwner(getter_AddRefs(owner));
  1362         aLoadInfo->GetInheritOwner(&inheritOwner);
  1363         aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
  1364         aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
  1365         aLoadInfo->GetTarget(getter_Copies(target));
  1366         aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
  1367         aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
  1368         aLoadInfo->GetSendReferrer(&sendReferrer);
  1369         aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
  1370         aLoadInfo->GetSrcdocData(srcdoc);
  1371         aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
  1372         aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
  1375 #if defined(PR_LOGGING) && defined(DEBUG)
  1376     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
  1377         nsAutoCString uristr;
  1378         aURI->GetAsciiSpec(uristr);
  1379         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
  1380                ("nsDocShell[%p]: loading %s with flags 0x%08x",
  1381                 this, uristr.get(), aLoadFlags));
  1383 #endif
  1385     if (!shEntry &&
  1386         !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
  1387         // First verify if this is a subframe.
  1388         nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
  1389         GetSameTypeParent(getter_AddRefs(parentAsItem));
  1390         nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
  1391         uint32_t parentLoadType;
  1393         if (parentDS && parentDS != static_cast<nsIDocShell *>(this)) {
  1394             /* OK. It is a subframe. Checkout the 
  1395              * parent's loadtype. If the parent was loaded thro' a history
  1396              * mechanism, then get the SH entry for the child from the parent.
  1397              * This is done to restore frameset navigation while going back/forward.
  1398              * If the parent was loaded through any other loadType, set the
  1399              * child's loadType too accordingly, so that session history does not
  1400              * get confused. 
  1401              */
  1403             // Get the parent's load type
  1404             parentDS->GetLoadType(&parentLoadType);            
  1406             // Get the ShEntry for the child from the parent
  1407             nsCOMPtr<nsISHEntry> currentSH;
  1408             bool oshe = false;
  1409             parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
  1410             bool dynamicallyAddedChild = mDynamicallyCreated;
  1411             if (!dynamicallyAddedChild && !oshe && currentSH) {
  1412                 currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
  1414             if (!dynamicallyAddedChild) {
  1415                 // Only use the old SHEntry, if we're sure enough that
  1416                 // it wasn't originally for some other frame.
  1417                 parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
  1420             // Make some decisions on the child frame's loadType based on the 
  1421             // parent's loadType. 
  1422             if (mCurrentURI == nullptr) {
  1423                 // This is a newly created frame. Check for exception cases first. 
  1424                 // By default the subframe will inherit the parent's loadType.
  1425                 if (shEntry && (parentLoadType == LOAD_NORMAL ||
  1426                             parentLoadType == LOAD_LINK   ||
  1427                             parentLoadType == LOAD_NORMAL_EXTERNAL)) {
  1428                     // The parent was loaded normally. In this case, this *brand new* child really shouldn't
  1429                     // have a SHEntry. If it does, it could be because the parent is replacing an
  1430                     // existing frame with a new frame, in the onLoadHandler. We don't want this
  1431                     // url to get into session history. Clear off shEntry, and set load type to
  1432                     // LOAD_BYPASS_HISTORY. 
  1433                     bool inOnLoadHandler=false;
  1434                     parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
  1435                     if (inOnLoadHandler) {
  1436                         loadType = LOAD_NORMAL_REPLACE;
  1437                         shEntry = nullptr;
  1439                 }   else if (parentLoadType == LOAD_REFRESH) {
  1440                     // Clear shEntry. For refresh loads, we have to load
  1441                     // what comes thro' the pipe, not what's in history.
  1442                     shEntry = nullptr;
  1443                 } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
  1444                         (shEntry && 
  1445                          ((parentLoadType & LOAD_CMD_HISTORY) || 
  1446                           (parentLoadType == LOAD_RELOAD_NORMAL) || 
  1447                           (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
  1448                     // If the parent url, bypassed history or was loaded from
  1449                     // history, pass on the parent's loadType to the new child 
  1450                     // frame too, so that the child frame will also
  1451                     // avoid getting into history. 
  1452                     loadType = parentLoadType;
  1453                 } else if (parentLoadType == LOAD_ERROR_PAGE) {
  1454                     // If the parent document is an error page, we don't
  1455                     // want to update global/session history. However,
  1456                     // this child frame is not an error page.
  1457                     loadType = LOAD_BYPASS_HISTORY;
  1458                 } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
  1459                            (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
  1460                            (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
  1461                     // the new frame should inherit the parent's load type so that it also
  1462                     // bypasses the cache and/or proxy
  1463                     loadType = parentLoadType;
  1465             } else {
  1466                 // This is a pre-existing subframe. If the load was not originally initiated
  1467                 // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
  1468                 // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading 
  1469                 // a new page in this child. Check parent's and self's busy flag  and if it is set,
  1470                 // we don't want this onLoadHandler load to get in to session history.
  1471                 uint32_t parentBusy = BUSY_FLAGS_NONE;
  1472                 uint32_t selfBusy = BUSY_FLAGS_NONE;
  1473                 parentDS->GetBusyFlags(&parentBusy);                    
  1474                 GetBusyFlags(&selfBusy);
  1475                 if (parentBusy & BUSY_FLAGS_BUSY ||
  1476                         selfBusy & BUSY_FLAGS_BUSY) {
  1477                     loadType = LOAD_NORMAL_REPLACE;
  1478                     shEntry = nullptr; 
  1481         } //parentDS
  1482         else {  
  1483             // This is the root docshell. If we got here while  
  1484             // executing an onLoad Handler,this load will not go 
  1485             // into session history.
  1486             bool inOnLoadHandler=false;
  1487             GetIsExecutingOnLoadHandler(&inOnLoadHandler);
  1488             if (inOnLoadHandler) {
  1489                 loadType = LOAD_NORMAL_REPLACE;
  1492     } // !shEntry
  1494     if (shEntry) {
  1495 #ifdef DEBUG
  1496         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
  1497               ("nsDocShell[%p]: loading from session history", this));
  1498 #endif
  1500         return LoadHistoryEntry(shEntry, loadType);
  1503     // On history navigation via Back/Forward buttons, don't execute
  1504     // automatic JavaScript redirection such as |location.href = ...| or
  1505     // |window.open()|
  1506     //
  1507     // LOAD_NORMAL:        window.open(...) etc.
  1508     // LOAD_STOP_CONTENT:  location.href = ..., location.assign(...)
  1509     if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
  1510         ShouldBlockLoadingForBackButton()) {
  1511         return NS_OK;
  1514     // Perform the load...
  1516     // We need an owner (a referring principal).
  1517     //
  1518     // If ownerIsExplicit is not set there are 4 possibilities:
  1519     // (1) If the system principal or an expanded principal was passed
  1520     //     in and we're a typeContent docshell, inherit the principal
  1521     //     from the current document instead.
  1522     // (2) In all other cases when the principal passed in is not null,
  1523     //     use that principal.
  1524     // (3) If the caller has allowed inheriting from the current document,
  1525     //     or if we're being called from system code (eg chrome JS or pure
  1526     //     C++) then inheritOwner should be true and InternalLoad will get
  1527     //     an owner from the current document. If none of these things are
  1528     //     true, then
  1529     // (4) we pass a null owner into the channel, and an owner will be
  1530     //     created later from the channel's internal data.
  1531     //
  1532     // If ownerIsExplicit *is* set, there are 4 possibilities
  1533     // (1) If the system principal or an expanded principal was passed in
  1534     //     and we're a typeContent docshell, return an error.
  1535     // (2) In all other cases when the principal passed in is not null,
  1536     //     use that principal.
  1537     // (3) If the caller has allowed inheriting from the current document,
  1538     //     then inheritOwner should be true and InternalLoad will get an owner
  1539     //     from the current document. If none of these things are true, then
  1540     // (4) we pass a null owner into the channel, and an owner will be
  1541     //     created later from the channel's internal data.
  1542     //
  1543     // NOTE: This all only works because the only thing the owner is used  
  1544     //       for in InternalLoad is data:, javascript:, and about:blank
  1545     //       URIs.  For other URIs this would all be dead wrong!
  1547     if (owner && mItemType != typeChrome) {
  1548         nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
  1549         if (nsContentUtils::IsSystemOrExpandedPrincipal(ownerPrincipal)) {
  1550             if (ownerIsExplicit) {
  1551                 return NS_ERROR_DOM_SECURITY_ERR;
  1553             owner = nullptr;
  1554             inheritOwner = true;
  1557     if (!owner && !inheritOwner && !ownerIsExplicit) {
  1558         // See if there's system or chrome JS code running
  1559         inheritOwner = nsContentUtils::IsSystemPrincipal(
  1560           nsContentUtils::GetSubjectPrincipal());
  1563     if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
  1564         inheritOwner = false;
  1565         owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
  1568     uint32_t flags = 0;
  1570     if (inheritOwner)
  1571         flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
  1573     if (!sendReferrer)
  1574         flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
  1576     if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
  1577         flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
  1579     if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS)
  1580         flags |= INTERNAL_LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
  1582     if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
  1583         flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
  1585     if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
  1586         flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
  1588     if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES)
  1589         flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
  1591     if (isSrcdoc)
  1592         flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
  1594     return InternalLoad(aURI,
  1595                         referrer,
  1596                         owner,
  1597                         flags,
  1598                         target.get(),
  1599                         nullptr,         // No type hint
  1600                         NullString(),    // No forced download
  1601                         postStream,
  1602                         headersStream,
  1603                         loadType,
  1604                         nullptr,         // No SHEntry
  1605                         aFirstParty,
  1606                         srcdoc,
  1607                         sourceDocShell,
  1608                         baseURI,
  1609                         nullptr,         // No nsIDocShell
  1610                         nullptr);        // No nsIRequest
  1613 NS_IMETHODIMP
  1614 nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
  1615                        const nsACString &aContentType,
  1616                        const nsACString &aContentCharset,
  1617                        nsIDocShellLoadInfo * aLoadInfo)
  1619     NS_ENSURE_ARG(aStream);
  1621     mAllowKeywordFixup = false;
  1623     // if the caller doesn't pass in a URI we need to create a dummy URI. necko
  1624     // currently requires a URI in various places during the load. Some consumers
  1625     // do as well.
  1626     nsCOMPtr<nsIURI> uri = aURI;
  1627     if (!uri) {
  1628         // HACK ALERT
  1629         nsresult rv = NS_OK;
  1630         uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
  1631         if (NS_FAILED(rv))
  1632             return rv;
  1633         // Make sure that the URI spec "looks" like a protocol and path...
  1634         // For now, just use a bogus protocol called "internal"
  1635         rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
  1636         if (NS_FAILED(rv))
  1637             return rv;
  1640     uint32_t loadType = LOAD_NORMAL;
  1641     if (aLoadInfo) {
  1642         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
  1643         (void) aLoadInfo->GetLoadType(&lt);
  1644         // Get the appropriate LoadType from nsIDocShellLoadInfo type
  1645         loadType = ConvertDocShellLoadInfoToLoadType(lt);
  1648     NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
  1650     mLoadType = loadType;
  1652     // build up a channel for this stream.
  1653     nsCOMPtr<nsIChannel> channel;
  1654     NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
  1655                       (getter_AddRefs(channel), uri, aStream,
  1656                        aContentType, aContentCharset),
  1657                       NS_ERROR_FAILURE);
  1659     nsCOMPtr<nsIURILoader>
  1660         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
  1661     NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
  1663     NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
  1664                       NS_ERROR_FAILURE);
  1665     return NS_OK;
  1668 NS_IMETHODIMP
  1669 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo)
  1671     nsDocShellLoadInfo *loadInfo = new nsDocShellLoadInfo();
  1672     NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
  1673     nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
  1675     *aLoadInfo = localRef;
  1676     NS_ADDREF(*aLoadInfo);
  1677     return NS_OK;
  1681 /*
  1682  * Reset state to a new content model within the current document and the document
  1683  * viewer.  Called by the document before initiating an out of band document.write().
  1684  */
  1685 NS_IMETHODIMP
  1686 nsDocShell::PrepareForNewContentModel()
  1688   mEODForCurrentDocument = false;
  1689   return NS_OK;
  1693 NS_IMETHODIMP
  1694 nsDocShell::FirePageHideNotification(bool aIsUnload)
  1696     if (mContentViewer && !mFiredUnloadEvent) {
  1697         // Keep an explicit reference since calling PageHide could release
  1698         // mContentViewer
  1699         nsCOMPtr<nsIContentViewer> kungFuDeathGrip(mContentViewer);
  1700         mFiredUnloadEvent = true;
  1702         if (mTiming) {
  1703             mTiming->NotifyUnloadEventStart();
  1706         mContentViewer->PageHide(aIsUnload);
  1708         if (mTiming) {
  1709             mTiming->NotifyUnloadEventEnd();
  1712         nsAutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
  1713         uint32_t n = mChildList.Length();
  1714         kids.SetCapacity(n);
  1715         for (uint32_t i = 0; i < n; i++) {
  1716             kids.AppendElement(do_QueryInterface(ChildAt(i)));
  1719         n = kids.Length();
  1720         for (uint32_t i = 0; i < n; ++i) {
  1721             if (kids[i]) {
  1722                 kids[i]->FirePageHideNotification(aIsUnload);
  1725         // Now make sure our editor, if any, is detached before we go
  1726         // any farther.
  1727         DetachEditorFromWindow();
  1730     return NS_OK;
  1733 void
  1734 nsDocShell::MaybeInitTiming()
  1736     if (mTiming) {
  1737         return;
  1740     mTiming = new nsDOMNavigationTiming();
  1741     mTiming->NotifyNavigationStart();
  1745 //
  1746 // Bug 13871: Prevent frameset spoofing
  1747 //
  1748 // This routine answers: 'Is origin's document from same domain as
  1749 // target's document?'
  1750 //
  1751 // file: uris are considered the same domain for the purpose of
  1752 // frame navigation regardless of script accessibility (bug 420425)
  1753 //
  1754 /* static */
  1755 bool
  1756 nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
  1757                            nsIDocShellTreeItem* aTargetTreeItem)
  1759     // We want to bypass this check for chrome callers, but only if there's
  1760     // JS on the stack. System callers still need to do it.
  1761     if (nsContentUtils::GetCurrentJSContext() && nsContentUtils::IsCallerChrome()) {
  1762         return true;
  1765     // Get origin document principal
  1766     nsCOMPtr<nsIDocument> originDocument(do_GetInterface(aOriginTreeItem));
  1767     NS_ENSURE_TRUE(originDocument, false);
  1769     // Get target principal
  1770     nsCOMPtr<nsIDocument> targetDocument(do_GetInterface(aTargetTreeItem));
  1771     NS_ENSURE_TRUE(targetDocument, false);
  1773     bool equal;
  1774     nsresult rv = originDocument->NodePrincipal()->Equals(targetDocument->NodePrincipal(),
  1775                                                           &equal);
  1776     if (NS_SUCCEEDED(rv) && equal) {
  1777         return true;
  1780     // Not strictly equal, special case if both are file: uris
  1781     bool originIsFile = false;
  1782     bool targetIsFile = false;
  1783     nsCOMPtr<nsIURI> originURI;
  1784     nsCOMPtr<nsIURI> targetURI;
  1785     nsCOMPtr<nsIURI> innerOriginURI;
  1786     nsCOMPtr<nsIURI> innerTargetURI;
  1788     rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
  1789     if (NS_SUCCEEDED(rv) && originURI)
  1790         innerOriginURI = NS_GetInnermostURI(originURI);
  1792     rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
  1793     if (NS_SUCCEEDED(rv) && targetURI)
  1794         innerTargetURI = NS_GetInnermostURI(targetURI);
  1796     return innerOriginURI && innerTargetURI &&
  1797         NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
  1798         NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
  1799         originIsFile && targetIsFile;
  1802 NS_IMETHODIMP
  1803 nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
  1805     NS_ENSURE_ARG_POINTER(aPresContext);
  1806     *aPresContext = nullptr;
  1808     nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
  1809     while (viewer) {
  1810         nsCOMPtr<nsIContentViewer> prevViewer;
  1811         viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
  1812         if (!prevViewer) {
  1813             return viewer->GetPresContext(aPresContext);
  1815         viewer = prevViewer;
  1818     return NS_OK;
  1821 NS_IMETHODIMP
  1822 nsDocShell::GetPresContext(nsPresContext ** aPresContext)
  1824     NS_ENSURE_ARG_POINTER(aPresContext);
  1825     *aPresContext = nullptr;
  1827     if (!mContentViewer)
  1828       return NS_OK;
  1830     return mContentViewer->GetPresContext(aPresContext);
  1833 NS_IMETHODIMP_(nsIPresShell*)
  1834 nsDocShell::GetPresShell()
  1836     nsRefPtr<nsPresContext> presContext;
  1837     (void) GetPresContext(getter_AddRefs(presContext));
  1838     return presContext ? presContext->GetPresShell() : nullptr;
  1841 NS_IMETHODIMP
  1842 nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
  1844     nsresult rv = NS_OK;
  1846     NS_ENSURE_ARG_POINTER(aPresShell);
  1847     *aPresShell = nullptr;
  1849     nsRefPtr<nsPresContext> presContext;
  1850     (void) GetEldestPresContext(getter_AddRefs(presContext));
  1852     if (presContext) {
  1853         NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
  1856     return rv;
  1859 NS_IMETHODIMP
  1860 nsDocShell::GetContentViewer(nsIContentViewer ** aContentViewer)
  1862     NS_ENSURE_ARG_POINTER(aContentViewer);
  1864     *aContentViewer = mContentViewer;
  1865     NS_IF_ADDREF(*aContentViewer);
  1866     return NS_OK;
  1869 NS_IMETHODIMP
  1870 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
  1872     // Weak reference. Don't addref.
  1873     nsCOMPtr<EventTarget> handler = do_QueryInterface(aChromeEventHandler);
  1874     mChromeEventHandler = handler.get();
  1876     if (mScriptGlobal) {
  1877         mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
  1880     return NS_OK;
  1883 NS_IMETHODIMP
  1884 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
  1886     NS_ENSURE_ARG_POINTER(aChromeEventHandler);
  1887     nsCOMPtr<EventTarget> handler = mChromeEventHandler;
  1888     handler.forget(aChromeEventHandler);
  1889     return NS_OK;
  1892 /* void setCurrentURI (in nsIURI uri); */
  1893 NS_IMETHODIMP
  1894 nsDocShell::SetCurrentURI(nsIURI *aURI)
  1896     // Note that securityUI will set STATE_IS_INSECURE, even if
  1897     // the scheme of |aURI| is "https".
  1898     SetCurrentURI(aURI, nullptr, true, 0);
  1899     return NS_OK;
  1902 bool
  1903 nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
  1904                           bool aFireOnLocationChange, uint32_t aLocationFlags)
  1906 #ifdef PR_LOGGING
  1907     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
  1908         nsAutoCString spec;
  1909         if (aURI)
  1910             aURI->GetSpec(spec);
  1911         PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
  1913 #endif
  1915     // We don't want to send a location change when we're displaying an error
  1916     // page, and we don't want to change our idea of "current URI" either
  1917     if (mLoadType == LOAD_ERROR_PAGE) {
  1918         return false;
  1921     mCurrentURI = NS_TryToMakeImmutable(aURI);
  1923     bool isRoot = false;   // Is this the root docshell
  1924     bool isSubFrame = false;  // Is this a subframe navigation?
  1926     nsCOMPtr<nsIDocShellTreeItem> root;
  1928     GetSameTypeRootTreeItem(getter_AddRefs(root));
  1929     if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) 
  1931         // This is the root docshell
  1932         isRoot = true;
  1934     if (mLSHE) {
  1935         mLSHE->GetIsSubFrame(&isSubFrame);
  1938     if (!isSubFrame && !isRoot) {
  1939       /* 
  1940        * We don't want to send OnLocationChange notifications when
  1941        * a subframe is being loaded for the first time, while
  1942        * visiting a frameset page
  1943        */
  1944       return false; 
  1947     if (aFireOnLocationChange) {
  1948         FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
  1950     return !aFireOnLocationChange;
  1953 NS_IMETHODIMP
  1954 nsDocShell::GetCharset(nsACString& aCharset)
  1956     aCharset.Truncate();
  1958     nsIPresShell* presShell = GetPresShell();
  1959     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
  1960     nsIDocument *doc = presShell->GetDocument();
  1961     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
  1962     aCharset = doc->GetDocumentCharacterSet();
  1963     return NS_OK;
  1966 NS_IMETHODIMP
  1967 nsDocShell::GatherCharsetMenuTelemetry()
  1969   nsCOMPtr<nsIContentViewer> viewer;
  1970   GetContentViewer(getter_AddRefs(viewer));
  1971   if (!viewer) {
  1972     return NS_OK;
  1975   nsIDocument* doc = viewer->GetDocument();
  1976   if (!doc || doc->WillIgnoreCharsetOverride()) {
  1977     return NS_OK;
  1980   Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true);
  1982   bool isFileURL = false;
  1983   nsIURI* url = doc->GetOriginalURI();
  1984   if (url) {
  1985     url->SchemeIs("file", &isFileURL);
  1988   int32_t charsetSource = doc->GetDocumentCharacterSetSource();
  1989   switch (charsetSource) {
  1990     case kCharsetFromTopLevelDomain:
  1991       // Unlabeled doc on a domain that we map to a fallback encoding
  1992       Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7);
  1993       break;
  1994     case kCharsetFromFallback:
  1995     case kCharsetFromDocTypeDefault:
  1996     case kCharsetFromCache:
  1997     case kCharsetFromParentFrame:
  1998     case kCharsetFromHintPrevDoc:
  1999       // Changing charset on an unlabeled doc.
  2000       if (isFileURL) {
  2001         Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
  2002       } else {
  2003         Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1);
  2005       break;
  2006     case kCharsetFromAutoDetection:
  2007       // Changing charset on unlabeled doc where chardet fired
  2008       if (isFileURL) {
  2009         Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2);
  2010       } else {
  2011         Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3);
  2013       break;
  2014     case kCharsetFromMetaPrescan:
  2015     case kCharsetFromMetaTag:
  2016     case kCharsetFromChannel:
  2017       // Changing charset on a doc that had a charset label.
  2018       Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4);
  2019       break;
  2020     case kCharsetFromParentForced:
  2021     case kCharsetFromUserForced:
  2022       // Changing charset on a document that already had an override.
  2023       Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5);
  2024       break;
  2025     case kCharsetFromIrreversibleAutoDetection:
  2026     case kCharsetFromOtherComponent:
  2027     case kCharsetFromByteOrderMark:
  2028     case kCharsetUninitialized:
  2029     default:
  2030       // Bug. This isn't supposed to happen.
  2031       Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6);
  2032       break;
  2034   return NS_OK;
  2037 NS_IMETHODIMP
  2038 nsDocShell::SetCharset(const nsACString& aCharset)
  2040     // set the charset override
  2041     return SetForcedCharset(aCharset);
  2044 NS_IMETHODIMP nsDocShell::SetForcedCharset(const nsACString& aCharset)
  2046   if (aCharset.IsEmpty()) {
  2047     mForcedCharset.Truncate();
  2048     return NS_OK;
  2050   nsAutoCString encoding;
  2051   if (!EncodingUtils::FindEncodingForLabel(aCharset, encoding)) {
  2052     // Reject unknown labels
  2053     return NS_ERROR_INVALID_ARG;
  2055   if (!EncodingUtils::IsAsciiCompatible(encoding)) {
  2056     // Reject XSS hazards
  2057     return NS_ERROR_INVALID_ARG;
  2059   mForcedCharset = encoding;
  2060   return NS_OK;
  2063 NS_IMETHODIMP nsDocShell::GetForcedCharset(nsACString& aResult)
  2065   aResult = mForcedCharset;
  2066   return NS_OK;
  2069 void
  2070 nsDocShell::SetParentCharset(const nsACString& aCharset,
  2071                              int32_t aCharsetSource,
  2072                              nsIPrincipal* aPrincipal)
  2074   mParentCharset = aCharset;
  2075   mParentCharsetSource = aCharsetSource;
  2076   mParentCharsetPrincipal = aPrincipal;
  2079 void
  2080 nsDocShell::GetParentCharset(nsACString& aCharset,
  2081                              int32_t* aCharsetSource,
  2082                              nsIPrincipal** aPrincipal)
  2084   aCharset = mParentCharset;
  2085   *aCharsetSource = mParentCharsetSource;
  2086   NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
  2089 NS_IMETHODIMP
  2090 nsDocShell::GetChannelIsUnsafe(bool *aUnsafe)
  2092     *aUnsafe = false;
  2094     nsIChannel* channel = GetCurrentDocChannel();
  2095     if (!channel) {
  2096         return NS_OK;
  2099     nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
  2100     if (!jarChannel) {
  2101         return NS_OK;
  2104     return jarChannel->GetIsUnsafe(aUnsafe);
  2107 NS_IMETHODIMP
  2108 nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded)
  2110     nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  2111     *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
  2112     return NS_OK;
  2115 NS_IMETHODIMP
  2116 nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked)
  2118     nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  2119     *aHasMixedActiveContentBlocked = doc && doc->GetHasMixedActiveContentBlocked();
  2120     return NS_OK;
  2123 NS_IMETHODIMP
  2124 nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded)
  2126     nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  2127     *aHasMixedDisplayContentLoaded = doc && doc->GetHasMixedDisplayContentLoaded();
  2128     return NS_OK;
  2131 NS_IMETHODIMP
  2132 nsDocShell::GetHasMixedDisplayContentBlocked(bool* aHasMixedDisplayContentBlocked)
  2134     nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  2135     *aHasMixedDisplayContentBlocked = doc && doc->GetHasMixedDisplayContentBlocked();
  2136     return NS_OK;
  2139 NS_IMETHODIMP
  2140 nsDocShell::GetAllowPlugins(bool * aAllowPlugins)
  2142     NS_ENSURE_ARG_POINTER(aAllowPlugins);
  2144     *aAllowPlugins = mAllowPlugins;
  2145     if (!mAllowPlugins) {
  2146         return NS_OK;
  2149     bool unsafe;
  2150     *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
  2151     return NS_OK;
  2154 NS_IMETHODIMP
  2155 nsDocShell::SetAllowPlugins(bool aAllowPlugins)
  2157     mAllowPlugins = aAllowPlugins;
  2158     //XXX should enable or disable a plugin host
  2159     return NS_OK;
  2162 NS_IMETHODIMP
  2163 nsDocShell::GetAllowJavascript(bool * aAllowJavascript)
  2165     NS_ENSURE_ARG_POINTER(aAllowJavascript);
  2167     *aAllowJavascript = mAllowJavascript;
  2168     return NS_OK;
  2171 NS_IMETHODIMP
  2172 nsDocShell::SetAllowJavascript(bool aAllowJavascript)
  2174     mAllowJavascript = aAllowJavascript;
  2175     RecomputeCanExecuteScripts();
  2176     return NS_OK;
  2179 NS_IMETHODIMP
  2180 nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
  2182     NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
  2184     *aUsePrivateBrowsing = mInPrivateBrowsing;
  2185     return NS_OK;
  2188 NS_IMETHODIMP
  2189 nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
  2191     nsContentUtils::ReportToConsoleNonLocalized(
  2192         NS_LITERAL_STRING("Only internal code is allowed to set the usePrivateBrowsing attribute"),
  2193         nsIScriptError::warningFlag,
  2194         NS_LITERAL_CSTRING("Internal API Used"),
  2195         mContentViewer ? mContentViewer->GetDocument() : nullptr);
  2197     return SetPrivateBrowsing(aUsePrivateBrowsing);
  2200 NS_IMETHODIMP
  2201 nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
  2203     bool changed = aUsePrivateBrowsing != mInPrivateBrowsing;
  2204     if (changed) {
  2205         mInPrivateBrowsing = aUsePrivateBrowsing;
  2206         if (mAffectPrivateSessionLifetime) {
  2207             if (aUsePrivateBrowsing) {
  2208                 IncreasePrivateDocShellCount();
  2209             } else {
  2210                 DecreasePrivateDocShellCount();
  2215     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  2216     while (iter.HasMore()) {
  2217         nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext());
  2218         if (shell) {
  2219             shell->SetPrivateBrowsing(aUsePrivateBrowsing);
  2223     if (changed) {
  2224         nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
  2225         while (iter.HasMore()) {
  2226             nsWeakPtr ref = iter.GetNext();
  2227             nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
  2228             if (!obs) {
  2229                 mPrivacyObservers.RemoveElement(ref);
  2230             } else {
  2231                 obs->PrivateModeChanged(aUsePrivateBrowsing);
  2235     return NS_OK;
  2238 NS_IMETHODIMP
  2239 nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
  2241     NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
  2243     *aUseRemoteTabs = mUseRemoteTabs;
  2244     return NS_OK;
  2247 NS_IMETHODIMP
  2248 nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
  2250 #ifdef MOZ_CRASHREPORTER
  2251     if (aUseRemoteTabs) {
  2252         CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
  2253                                            NS_LITERAL_CSTRING("1"));
  2255 #endif
  2257     mUseRemoteTabs = aUseRemoteTabs;
  2258     return NS_OK;
  2261 NS_IMETHODIMP
  2262 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
  2264     bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
  2265     if (change && mInPrivateBrowsing) {
  2266         if (aAffectLifetime) {
  2267             IncreasePrivateDocShellCount();
  2268         } else {
  2269             DecreasePrivateDocShellCount();
  2272     mAffectPrivateSessionLifetime = aAffectLifetime;
  2274     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  2275     while (iter.HasMore()) {
  2276         nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
  2277         if (shell) {
  2278             shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
  2281     return NS_OK;
  2284 NS_IMETHODIMP
  2285 nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime)
  2287     *aAffectLifetime = mAffectPrivateSessionLifetime;
  2288     return NS_OK;
  2291 NS_IMETHODIMP
  2292 nsDocShell::AddWeakPrivacyTransitionObserver(nsIPrivacyTransitionObserver* aObserver)
  2294     nsWeakPtr weakObs = do_GetWeakReference(aObserver);
  2295     if (!weakObs) {
  2296         return NS_ERROR_NOT_AVAILABLE;
  2298     return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
  2301 NS_IMETHODIMP
  2302 nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver)
  2304     nsWeakPtr weakObs = do_GetWeakReference(aObserver);
  2305     if (!weakObs) {
  2306         return NS_ERROR_FAILURE;
  2308     return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
  2311 NS_IMETHODIMP
  2312 nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver)
  2314     nsWeakPtr obs = do_GetWeakReference(aObserver);
  2315     return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
  2318 NS_IMETHODIMP
  2319 nsDocShell::NotifyReflowObservers(bool aInterruptible,
  2320                                   DOMHighResTimeStamp aStart,
  2321                                   DOMHighResTimeStamp aEnd)
  2323     nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
  2324     while (iter.HasMore()) {
  2325         nsWeakPtr ref = iter.GetNext();
  2326         nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
  2327         if (!obs) {
  2328             mReflowObservers.RemoveElement(ref);
  2329         } else if (aInterruptible) {
  2330             obs->ReflowInterruptible(aStart, aEnd);
  2331         } else {
  2332             obs->Reflow(aStart, aEnd);
  2335     return NS_OK;
  2338 NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(bool * aReturn)
  2340     NS_ENSURE_ARG_POINTER(aReturn);
  2342     *aReturn = mAllowMetaRedirects;
  2343     if (!mAllowMetaRedirects) {
  2344         return NS_OK;
  2347     bool unsafe;
  2348     *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
  2349     return NS_OK;
  2352 NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(bool aValue)
  2354     mAllowMetaRedirects = aValue;
  2355     return NS_OK;
  2358 NS_IMETHODIMP nsDocShell::GetAllowSubframes(bool * aAllowSubframes)
  2360     NS_ENSURE_ARG_POINTER(aAllowSubframes);
  2362     *aAllowSubframes = mAllowSubframes;
  2363     return NS_OK;
  2366 NS_IMETHODIMP nsDocShell::SetAllowSubframes(bool aAllowSubframes)
  2368     mAllowSubframes = aAllowSubframes;
  2369     return NS_OK;
  2372 NS_IMETHODIMP nsDocShell::GetAllowImages(bool * aAllowImages)
  2374     NS_ENSURE_ARG_POINTER(aAllowImages);
  2376     *aAllowImages = mAllowImages;
  2377     return NS_OK;
  2380 NS_IMETHODIMP nsDocShell::SetAllowImages(bool aAllowImages)
  2382     mAllowImages = aAllowImages;
  2383     return NS_OK;
  2386 NS_IMETHODIMP nsDocShell::GetAllowMedia(bool * aAllowMedia)
  2388     *aAllowMedia = mAllowMedia;
  2389     return NS_OK;
  2392 NS_IMETHODIMP nsDocShell::SetAllowMedia(bool aAllowMedia)
  2394     mAllowMedia = aAllowMedia;
  2396     // Mute or unmute audio contexts attached to the inner window.
  2397     if (mScriptGlobal) {
  2398         nsPIDOMWindow* innerWin = mScriptGlobal->GetCurrentInnerWindow();
  2399         if (innerWin) {
  2400             if (aAllowMedia) {
  2401                 innerWin->UnmuteAudioContexts();
  2402             } else {
  2403                 innerWin->MuteAudioContexts();
  2408     return NS_OK;
  2411 NS_IMETHODIMP nsDocShell::GetAllowDNSPrefetch(bool * aAllowDNSPrefetch)
  2413     *aAllowDNSPrefetch = mAllowDNSPrefetch;
  2414     return NS_OK;
  2417 NS_IMETHODIMP nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
  2419     mAllowDNSPrefetch = aAllowDNSPrefetch;
  2420     return NS_OK;
  2423 NS_IMETHODIMP nsDocShell::GetAllowWindowControl(bool * aAllowWindowControl)
  2425     *aAllowWindowControl = mAllowWindowControl;
  2426     return NS_OK;
  2429 NS_IMETHODIMP nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
  2431     mAllowWindowControl = aAllowWindowControl;
  2432     return NS_OK;
  2435 NS_IMETHODIMP
  2436 nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting)
  2438     *aAllowContentRetargeting = mAllowContentRetargeting;
  2439     return NS_OK;
  2442 NS_IMETHODIMP
  2443 nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting)
  2445     mAllowContentRetargeting = aAllowContentRetargeting;
  2446     return NS_OK;
  2449 NS_IMETHODIMP
  2450 nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
  2452     NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
  2454     // Browsers and apps have their mFullscreenAllowed retrieved from their
  2455     // corresponding iframe in their parent upon creation.
  2456     if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
  2457         *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
  2458         return NS_OK;
  2461     // Assume false until we determine otherwise...
  2462     *aFullscreenAllowed = false;
  2464     // For non-browsers/apps, check that the enclosing iframe element
  2465     // has the allowfullscreen attribute set to true. If any ancestor
  2466     // iframe does not have mozallowfullscreen=true, then fullscreen is
  2467     // prohibited.
  2468     nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(GetAsSupports(this));
  2469     if (!win) {
  2470         return NS_OK;
  2472     nsCOMPtr<nsIContent> frameElement = do_QueryInterface(win->GetFrameElementInternal());
  2473     if (frameElement &&
  2474         frameElement->IsHTML(nsGkAtoms::iframe) &&
  2475         !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) &&
  2476         !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) {
  2477         return NS_OK;
  2480     // If we have no parent then we're the root docshell; no ancestor of the
  2481     // original docshell doesn't have a allowfullscreen attribute, so
  2482     // report fullscreen as allowed.
  2483     nsCOMPtr<nsIDocShellTreeItem> dsti = do_GetInterface(GetAsSupports(this));
  2484     NS_ENSURE_TRUE(dsti, NS_OK);
  2486     nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
  2487     dsti->GetParent(getter_AddRefs(parentTreeItem));
  2488     if (!parentTreeItem) {
  2489         *aFullscreenAllowed = true;
  2490         return NS_OK;
  2492     // Otherwise, we have a parent, continue the checking for
  2493     // mozFullscreenAllowed in the parent docshell's ancestors.
  2494     nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem);
  2495     NS_ENSURE_TRUE(parent, NS_OK);
  2497     return parent->GetFullscreenAllowed(aFullscreenAllowed);
  2500 NS_IMETHODIMP
  2501 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
  2503     if (!nsIDocShell::GetIsBrowserOrApp()) {
  2504         // Only allow setting of fullscreenAllowed on content/process boundaries.
  2505         // At non-boundaries the fullscreenAllowed attribute is calculated based on
  2506         // whether all enclosing frames have the "mozFullscreenAllowed" attribute
  2507         // set to "true". fullscreenAllowed is set at the process boundaries to
  2508         // propagate the value of the parent's "mozFullscreenAllowed" attribute
  2509         // across process boundaries.
  2510         return NS_ERROR_UNEXPECTED;
  2512     mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS);
  2513     return NS_OK;
  2516 NS_IMETHODIMP
  2517 nsDocShell::GetMayEnableCharacterEncodingMenu(bool* aMayEnableCharacterEncodingMenu)
  2519   *aMayEnableCharacterEncodingMenu = false;
  2520   if (!mContentViewer) {
  2521     return NS_OK;
  2523   nsIDocument* doc = mContentViewer->GetDocument();
  2524   if (!doc) {
  2525     return NS_OK;
  2527   if (doc->WillIgnoreCharsetOverride()) {
  2528     return NS_OK;
  2531   *aMayEnableCharacterEncodingMenu = true;
  2532   return NS_OK;
  2535 NS_IMETHODIMP
  2536 nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection, nsISimpleEnumerator **outEnum)
  2538     NS_ENSURE_ARG_POINTER(outEnum);
  2539     *outEnum = nullptr;
  2541     nsRefPtr<nsDocShellEnumerator> docShellEnum;
  2542     if (aDirection == ENUMERATE_FORWARDS)
  2543         docShellEnum = new nsDocShellForwardsEnumerator;
  2544     else
  2545         docShellEnum = new nsDocShellBackwardsEnumerator;
  2547     if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY;
  2549     nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
  2550     if (NS_FAILED(rv)) return rv;
  2552     rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this);
  2553     if (NS_FAILED(rv)) return rv;
  2555     rv = docShellEnum->First();
  2556     if (NS_FAILED(rv)) return rv;
  2558     rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum);
  2560     return rv;
  2563 NS_IMETHODIMP
  2564 nsDocShell::GetAppType(uint32_t * aAppType)
  2566     *aAppType = mAppType;
  2567     return NS_OK;
  2570 NS_IMETHODIMP
  2571 nsDocShell::SetAppType(uint32_t aAppType)
  2573     mAppType = aAppType;
  2574     return NS_OK;
  2578 NS_IMETHODIMP
  2579 nsDocShell::GetAllowAuth(bool * aAllowAuth)
  2581     *aAllowAuth = mAllowAuth;
  2582     return NS_OK;
  2585 NS_IMETHODIMP
  2586 nsDocShell::SetAllowAuth(bool aAllowAuth)
  2588     mAllowAuth = aAllowAuth;
  2589     return NS_OK;
  2592 NS_IMETHODIMP
  2593 nsDocShell::GetZoom(float *zoom)
  2595     NS_ENSURE_ARG_POINTER(zoom);
  2596     *zoom = 1.0f;
  2597     return NS_OK;
  2600 NS_IMETHODIMP
  2601 nsDocShell::SetZoom(float zoom)
  2603     return NS_ERROR_NOT_IMPLEMENTED;
  2606 NS_IMETHODIMP
  2607 nsDocShell::GetMarginWidth(int32_t * aWidth)
  2609     NS_ENSURE_ARG_POINTER(aWidth);
  2611     *aWidth = mMarginWidth;
  2612     return NS_OK;
  2615 NS_IMETHODIMP
  2616 nsDocShell::SetMarginWidth(int32_t aWidth)
  2618     mMarginWidth = aWidth;
  2619     return NS_OK;
  2622 NS_IMETHODIMP
  2623 nsDocShell::GetMarginHeight(int32_t * aHeight)
  2625     NS_ENSURE_ARG_POINTER(aHeight);
  2627     *aHeight = mMarginHeight;
  2628     return NS_OK;
  2631 NS_IMETHODIMP
  2632 nsDocShell::SetMarginHeight(int32_t aHeight)
  2634     mMarginHeight = aHeight;
  2635     return NS_OK;
  2638 NS_IMETHODIMP
  2639 nsDocShell::GetBusyFlags(uint32_t * aBusyFlags)
  2641     NS_ENSURE_ARG_POINTER(aBusyFlags);
  2643     *aBusyFlags = mBusyFlags;
  2644     return NS_OK;
  2647 NS_IMETHODIMP
  2648 nsDocShell::TabToTreeOwner(bool aForward, bool* aTookFocus)
  2650     NS_ENSURE_ARG_POINTER(aTookFocus);
  2652     nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
  2653     if (chromeFocus) {
  2654         if (aForward)
  2655             *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement());
  2656         else
  2657             *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement());
  2658     } else
  2659         *aTookFocus = false;
  2661     return NS_OK;
  2664 NS_IMETHODIMP
  2665 nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI)
  2667     NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
  2668     return NS_OK;
  2671 NS_IMETHODIMP
  2672 nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI)
  2674     mSecurityUI = aSecurityUI;
  2675     mSecurityUI->SetDocShell(this);
  2676     return NS_OK;
  2679 NS_IMETHODIMP
  2680 nsDocShell::GetUseErrorPages(bool *aUseErrorPages)
  2682     *aUseErrorPages = UseErrorPages();
  2683     return NS_OK;
  2686 NS_IMETHODIMP
  2687 nsDocShell::SetUseErrorPages(bool aUseErrorPages)
  2689     // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
  2690     if (mObserveErrorPages) {
  2691         mObserveErrorPages = false;
  2693     mUseErrorPages = aUseErrorPages;
  2694     return NS_OK;
  2697 NS_IMETHODIMP
  2698 nsDocShell::GetPreviousTransIndex(int32_t *aPreviousTransIndex)
  2700     *aPreviousTransIndex = mPreviousTransIndex;
  2701     return NS_OK;
  2704 NS_IMETHODIMP
  2705 nsDocShell::GetLoadedTransIndex(int32_t *aLoadedTransIndex)
  2707     *aLoadedTransIndex = mLoadedTransIndex;
  2708     return NS_OK;
  2711 NS_IMETHODIMP
  2712 nsDocShell::HistoryPurged(int32_t aNumEntries)
  2714     // These indices are used for fastback cache eviction, to determine
  2715     // which session history entries are candidates for content viewer
  2716     // eviction.  We need to adjust by the number of entries that we
  2717     // just purged from history, so that we look at the right session history
  2718     // entries during eviction.
  2719     mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries);
  2720     mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries);
  2722     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  2723     while (iter.HasMore()) {
  2724         nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
  2725         if (shell) {
  2726             shell->HistoryPurged(aNumEntries);
  2730     return NS_OK;
  2733 nsresult
  2734 nsDocShell::HistoryTransactionRemoved(int32_t aIndex)
  2736     // These indices are used for fastback cache eviction, to determine
  2737     // which session history entries are candidates for content viewer
  2738     // eviction.  We need to adjust by the number of entries that we
  2739     // just purged from history, so that we look at the right session history
  2740     // entries during eviction.
  2741     if (aIndex == mPreviousTransIndex) {
  2742         mPreviousTransIndex = -1;
  2743     } else if (aIndex < mPreviousTransIndex) {
  2744         --mPreviousTransIndex;
  2746     if (mLoadedTransIndex == aIndex) {
  2747         mLoadedTransIndex = 0;
  2748     } else if (aIndex < mLoadedTransIndex) {
  2749         --mLoadedTransIndex;
  2752     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  2753     while (iter.HasMore()) {
  2754         nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
  2755         if (shell) {
  2756             static_cast<nsDocShell*>(shell.get())->
  2757                 HistoryTransactionRemoved(aIndex);
  2761     return NS_OK;
  2764 nsIDOMStorageManager*
  2765 nsDocShell::TopSessionStorageManager()
  2767     nsresult rv;
  2769     nsCOMPtr<nsIDocShellTreeItem> topItem;
  2770     rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
  2771     if (NS_FAILED(rv)) {
  2772         return nullptr;
  2775     if (!topItem) {
  2776         return nullptr;
  2779     nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
  2780     if (topDocShell != this) {
  2781         return topDocShell->TopSessionStorageManager();
  2784     if (!mSessionStorageManager) {
  2785         mSessionStorageManager =
  2786             do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1");
  2789     return mSessionStorageManager;
  2792 NS_IMETHODIMP
  2793 nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
  2794                                           const nsAString& aDocumentURI,
  2795                                           bool aCreate,
  2796                                           nsIDOMStorage** aStorage)
  2798     nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager();
  2799     if (!manager) {
  2800         return NS_ERROR_UNEXPECTED;
  2803     nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
  2804                             do_GetService(THIRDPARTYUTIL_CONTRACTID);
  2805     if (!thirdPartyUtil)
  2806       return NS_ERROR_FAILURE;
  2808     nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  2809     nsCOMPtr<nsIURI> firstPartyIsolationURI;
  2810     nsresult rv = thirdPartyUtil->GetFirstPartyIsolationURI(nullptr, doc,
  2811                                            getter_AddRefs(firstPartyIsolationURI));
  2812     NS_ENSURE_SUCCESS(rv, rv);
  2814     if (aCreate) {
  2815         return manager->CreateStorageForFirstParty(firstPartyIsolationURI,
  2816                                       aPrincipal, aDocumentURI,
  2817                                       mInPrivateBrowsing, aStorage);
  2820     return manager->GetStorageForFirstParty(firstPartyIsolationURI, aPrincipal,
  2821                                             mInPrivateBrowsing, aStorage);
  2824 // Bacause it is not called from anywhere, nsDocShell::AddSessionStorage()
  2825 // does not need to be modified to isolate DOM Storage to the first party URI.
  2826 nsresult
  2827 nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
  2828                               nsIDOMStorage* aStorage)
  2830     nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(aStorage);
  2831     nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
  2832     if (storagePrincipal != aPrincipal) {
  2833         NS_ERROR("Wanting to add a sessionStorage for different principal");
  2834         return NS_ERROR_DOM_SECURITY_ERR;
  2837     nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager();
  2838     if (!manager) {
  2839         return NS_ERROR_UNEXPECTED;
  2842     return manager->CloneStorage(aStorage);
  2845 NS_IMETHODIMP
  2846 nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
  2848     NS_IF_ADDREF(*aResult = GetCurrentDocChannel()); 
  2849     return NS_OK;
  2852 nsIChannel*
  2853 nsDocShell::GetCurrentDocChannel()
  2855     if (mContentViewer) {
  2856         nsIDocument* doc = mContentViewer->GetDocument();
  2857         if (doc) {
  2858             return doc->GetChannel();
  2861     return nullptr;
  2864 NS_IMETHODIMP
  2865 nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver)
  2867     nsWeakPtr weakObs = do_GetWeakReference(aObserver);
  2868     if (!weakObs) {
  2869         return NS_ERROR_FAILURE;
  2871     return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
  2874 NS_IMETHODIMP
  2875 nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
  2877     nsWeakPtr obs = do_GetWeakReference(aObserver);
  2878     return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
  2881 NS_IMETHODIMP
  2882 nsDocShell::NotifyScrollObservers()
  2884     nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
  2885     while (iter.HasMore()) {
  2886         nsWeakPtr ref = iter.GetNext();
  2887         nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
  2888         if (obs) {
  2889             obs->ScrollPositionChanged();
  2890         } else {
  2891             mScrollObservers.RemoveElement(ref);
  2894     return NS_OK;
  2897 //*****************************************************************************
  2898 // nsDocShell::nsIDocShellTreeItem
  2899 //*****************************************************************************   
  2901 NS_IMETHODIMP
  2902 nsDocShell::GetName(nsAString& aName)
  2904     aName = mName;
  2905     return NS_OK;
  2908 NS_IMETHODIMP
  2909 nsDocShell::SetName(const nsAString& aName)
  2911     mName = aName;
  2912     return NS_OK;
  2915 NS_IMETHODIMP
  2916 nsDocShell::NameEquals(const char16_t *aName, bool *_retval)
  2918     NS_ENSURE_ARG_POINTER(aName);
  2919     NS_ENSURE_ARG_POINTER(_retval);
  2920     *_retval = mName.Equals(aName);
  2921     return NS_OK;
  2924 /* virtual */ int32_t
  2925 nsDocShell::ItemType()
  2927    return mItemType;
  2930 NS_IMETHODIMP
  2931 nsDocShell::GetItemType(int32_t * aItemType)
  2933     NS_ENSURE_ARG_POINTER(aItemType);
  2935     *aItemType = ItemType();
  2936     return NS_OK;
  2939 NS_IMETHODIMP
  2940 nsDocShell::SetItemType(int32_t aItemType)
  2942     NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
  2944     // Only allow setting the type on root docshells.  Those would be the ones
  2945     // that have the docloader service as mParent or have no mParent at all.
  2946     nsCOMPtr<nsIDocumentLoader> docLoaderService =
  2947         do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
  2948     NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
  2950     NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
  2952     mItemType = aItemType;
  2954     // disable auth prompting for anything but content
  2955     mAllowAuth = mItemType == typeContent; 
  2957     nsRefPtr<nsPresContext> presContext = nullptr;
  2958     GetPresContext(getter_AddRefs(presContext));
  2959     if (presContext) {
  2960         presContext->UpdateIsChrome();
  2963     return NS_OK;
  2966 NS_IMETHODIMP
  2967 nsDocShell::GetParent(nsIDocShellTreeItem ** aParent)
  2969     if (!mParent) {
  2970         *aParent = nullptr;
  2971     } else {
  2972         CallQueryInterface(mParent, aParent);
  2974     // Note that in the case when the parent is not an nsIDocShellTreeItem we
  2975     // don't want to throw; we just want to return null.
  2976     return NS_OK;
  2979 already_AddRefed<nsDocShell>
  2980 nsDocShell::GetParentDocshell()
  2982     nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
  2983     return docshell.forget().downcast<nsDocShell>();
  2986 void
  2987 nsDocShell::RecomputeCanExecuteScripts()
  2989     bool old = mCanExecuteScripts;
  2990     nsRefPtr<nsDocShell> parent = GetParentDocshell();
  2992     // If we have no tree owner, that means that we've been detached from the
  2993     // docshell tree (this is distinct from having no parent dochshell, which
  2994     // is the case for root docshells). It would be nice to simply disallow
  2995     // script in detached docshells, but bug 986542 demonstrates that this
  2996     // behavior breaks at least one website.
  2997     //
  2998     // So instead, we use our previous value, unless mAllowJavascript has been
  2999     // explicitly set to false.
  3000     if (!mTreeOwner) {
  3001         mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
  3002     // If scripting has been explicitly disabled on our docshell, we're done.
  3003     } else if (!mAllowJavascript) {
  3004         mCanExecuteScripts = false;
  3005     // If we have a parent, inherit.
  3006     } else if (parent) {
  3007         mCanExecuteScripts = parent->mCanExecuteScripts;
  3008     // Otherwise, we're the root of the tree, and we haven't explicitly disabled
  3009     // script. Allow.
  3010     } else {
  3011         mCanExecuteScripts = true;
  3014     // Inform our active DOM window.
  3015     //
  3016     // This will pass the outer, which will be in the scope of the active inner.
  3017     if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
  3018         xpc::Scriptability& scriptability =
  3019           xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
  3020         scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
  3023     // If our value has changed, our children might be affected. Recompute their
  3024     // value as well.
  3025     if (old != mCanExecuteScripts) {
  3026         nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  3027         while (iter.HasMore()) {
  3028             static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
  3033 nsresult
  3034 nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
  3036     bool wasFrame = IsFrame();
  3038     nsDocLoader::SetDocLoaderParent(aParent);
  3040     nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
  3041     if (wasFrame != IsFrame() && priorityGroup) {
  3042         priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
  3045     // Curse ambiguous nsISupports inheritance!
  3046     nsISupports* parent = GetAsSupports(aParent);
  3048     // If parent is another docshell, we inherit all their flags for
  3049     // allowing plugins, scripting etc.
  3050     bool value;
  3051     nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
  3052     if (parentAsDocShell)
  3054         if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value)))
  3056             SetAllowPlugins(value);
  3058         if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value)))
  3060             SetAllowJavascript(value);
  3062         if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value)))
  3064             SetAllowMetaRedirects(value);
  3066         if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value)))
  3068             SetAllowSubframes(value);
  3070         if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value)))
  3072             SetAllowImages(value);
  3074         SetAllowMedia(parentAsDocShell->GetAllowMedia());
  3075         if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value)))
  3077             SetAllowWindowControl(value);
  3079         SetAllowContentRetargeting(
  3080             parentAsDocShell->GetAllowContentRetargeting());
  3081         if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value)))
  3083             SetIsActive(value);
  3085         if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
  3086             value = false;
  3088         SetAllowDNSPrefetch(value);
  3089         value = parentAsDocShell->GetAffectPrivateSessionLifetime();
  3090         SetAffectPrivateSessionLifetime(value);
  3091         uint32_t flags;
  3092         if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags)))
  3094             SetDefaultLoadFlags(flags);
  3099     nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
  3100     if (parentAsLoadContext &&
  3101         NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value)))
  3103         SetPrivateBrowsing(value);
  3106     nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
  3107     if (parentURIListener)
  3108         mContentListener->SetParentContentListener(parentURIListener);
  3110     // Our parent has changed. Recompute scriptability.
  3111     RecomputeCanExecuteScripts();
  3113     return NS_OK;
  3116 NS_IMETHODIMP
  3117 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
  3119     NS_ENSURE_ARG_POINTER(aParent);
  3120     *aParent = nullptr;
  3122     if (nsIDocShell::GetIsBrowserOrApp()) {
  3123         return NS_OK;
  3126     nsCOMPtr<nsIDocShellTreeItem> parent =
  3127         do_QueryInterface(GetAsSupports(mParent));
  3128     if (!parent)
  3129         return NS_OK;
  3131     if (parent->ItemType() == mItemType) {
  3132         parent.swap(*aParent);
  3134     return NS_OK;
  3137 NS_IMETHODIMP
  3138 nsDocShell::GetSameTypeParentIgnoreBrowserAndAppBoundaries(nsIDocShell** aParent)
  3140     NS_ENSURE_ARG_POINTER(aParent);
  3141     *aParent = nullptr;
  3143     nsCOMPtr<nsIDocShellTreeItem> parent =
  3144         do_QueryInterface(GetAsSupports(mParent));
  3145     if (!parent)
  3146         return NS_OK;
  3148     if (parent->ItemType() == mItemType) {
  3149         nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent);
  3150         parentDS.forget(aParent);
  3152     return NS_OK;
  3155 NS_IMETHODIMP
  3156 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
  3158     NS_ENSURE_ARG_POINTER(aRootTreeItem);
  3159     *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
  3161     nsCOMPtr<nsIDocShellTreeItem> parent;
  3162     NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
  3163     while (parent) {
  3164         *aRootTreeItem = parent;
  3165         NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)),
  3166                           NS_ERROR_FAILURE);
  3168     NS_ADDREF(*aRootTreeItem);
  3169     return NS_OK;
  3172 NS_IMETHODIMP
  3173 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
  3175     NS_ENSURE_ARG_POINTER(aRootTreeItem);
  3176     *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
  3178     nsCOMPtr<nsIDocShellTreeItem> parent;
  3179     NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
  3180                       NS_ERROR_FAILURE);
  3181     while (parent) {
  3182         *aRootTreeItem = parent;
  3183         NS_ENSURE_SUCCESS((*aRootTreeItem)->
  3184                           GetSameTypeParent(getter_AddRefs(parent)),
  3185                           NS_ERROR_FAILURE);
  3187     NS_ADDREF(*aRootTreeItem);
  3188     return NS_OK;
  3191 /* static */
  3192 bool
  3193 nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
  3194                           nsIDocShellTreeItem* aAccessingItem,
  3195                           bool aConsiderOpener)
  3197     NS_PRECONDITION(aTargetItem, "Must have target item!");
  3199     if (!gValidateOrigin || !aAccessingItem) {
  3200         // Good to go
  3201         return true;
  3204     // XXXbz should we care if aAccessingItem or the document therein is
  3205     // chrome?  Should those get extra privileges?
  3207     // For historical context, see:
  3208     // 
  3209     // Bug 13871:  Prevent frameset spoofing
  3210     // Bug 103638: Targets with same name in different windows open in wrong
  3211     //             window with javascript
  3212     // Bug 408052: Adopt "ancestor" frame navigation policy
  3214     // Now do a security check.
  3215     //
  3216     // Disallow navigation if the two frames are not part of the same app, or if
  3217     // they have different is-in-browser-element states.
  3218     //
  3219     // Allow navigation if
  3220     //  1) aAccessingItem can script aTargetItem or one of its ancestors in
  3221     //     the frame hierarchy or
  3222     //  2) aTargetItem is a top-level frame and aAccessingItem is its descendant
  3223     //  3) aTargetItem is a top-level frame and aAccessingItem can target
  3224     //     its opener per rule (1) or (2).
  3226     if (aTargetItem == aAccessingItem) {
  3227         // A frame is allowed to navigate itself.
  3228         return true;
  3231     nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
  3232     nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
  3233     if (!!targetDS != !!accessingDS) {
  3234         // We must be able to convert both or neither to nsIDocShell.
  3235         return false;
  3238     if (targetDS && accessingDS &&
  3239         (targetDS->GetIsInBrowserElement() !=
  3240            accessingDS->GetIsInBrowserElement() ||
  3241          targetDS->GetAppId() != accessingDS->GetAppId())) {
  3242         return false;
  3245     nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
  3246     aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
  3248     if (aTargetItem == accessingRoot) {
  3249         // A frame can navigate its root.
  3250         return true;
  3253     // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
  3254     nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
  3255     do {
  3256         if (ValidateOrigin(aAccessingItem, target)) {
  3257             return true;
  3260         nsCOMPtr<nsIDocShellTreeItem> parent;
  3261         target->GetSameTypeParent(getter_AddRefs(parent));
  3262         parent.swap(target);
  3263     } while (target);
  3265     nsCOMPtr<nsIDocShellTreeItem> targetRoot;
  3266     aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
  3268     if (aTargetItem != targetRoot) {
  3269         // target is a subframe, not in accessor's frame hierarchy, and all its
  3270         // ancestors have origins different from that of the accessor. Don't
  3271         // allow access.
  3272         return false;
  3275     if (!aConsiderOpener) {
  3276         // All done here
  3277         return false;
  3280     nsCOMPtr<nsIDOMWindow> targetWindow = do_GetInterface(aTargetItem);
  3281     if (!targetWindow) {
  3282         NS_ERROR("This should not happen, really");
  3283         return false;
  3286     nsCOMPtr<nsIDOMWindow> targetOpener;
  3287     targetWindow->GetOpener(getter_AddRefs(targetOpener));
  3288     nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
  3289     nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
  3291     if (!openerItem) {
  3292         return false;
  3295     return CanAccessItem(openerItem, aAccessingItem, false);    
  3298 static bool
  3299 ItemIsActive(nsIDocShellTreeItem *aItem)
  3301     nsCOMPtr<nsIDOMWindow> window(do_GetInterface(aItem));
  3303     if (window) {
  3304         bool isClosed;
  3306         if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) {
  3307             return true;
  3311     return false;
  3314 NS_IMETHODIMP
  3315 nsDocShell::FindItemWithName(const char16_t * aName,
  3316                              nsISupports * aRequestor,
  3317                              nsIDocShellTreeItem * aOriginalRequestor,
  3318                              nsIDocShellTreeItem ** _retval)
  3320     NS_ENSURE_ARG(aName);
  3321     NS_ENSURE_ARG_POINTER(_retval);
  3323     // If we don't find one, we return NS_OK and a null result
  3324     *_retval = nullptr;
  3326     if (!*aName)
  3327         return NS_OK;
  3329     if (aRequestor) {
  3330         // If aRequestor is not null we don't need to check special names, so
  3331         // just hand straight off to the search by actual name function.
  3332         return DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
  3333                                   _retval);
  3334     } else {
  3336         // This is the entry point into the target-finding algorithm.  Check
  3337         // for special names.  This should only be done once, hence the check
  3338         // for a null aRequestor.
  3340         nsCOMPtr<nsIDocShellTreeItem> foundItem;
  3341         nsDependentString name(aName);
  3342         if (name.LowerCaseEqualsLiteral("_self")) {
  3343             foundItem = this;
  3345         else if (name.LowerCaseEqualsLiteral("_blank"))
  3347             // Just return null.  Caller must handle creating a new window with
  3348             // a blank name himself.
  3349             return NS_OK;
  3351         else if (name.LowerCaseEqualsLiteral("_parent"))
  3353             GetSameTypeParent(getter_AddRefs(foundItem));
  3354             if(!foundItem)
  3355                 foundItem = this;
  3357         else if (name.LowerCaseEqualsLiteral("_top"))
  3359             GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
  3360             NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
  3362         // _main is an IE target which should be case-insensitive but isn't
  3363         // see bug 217886 for details
  3364         else if (name.LowerCaseEqualsLiteral("_content") ||
  3365                  name.EqualsLiteral("_main"))
  3367             // Must pass our same type root as requestor to the
  3368             // treeowner to make sure things work right.
  3369             nsCOMPtr<nsIDocShellTreeItem> root;
  3370             GetSameTypeRootTreeItem(getter_AddRefs(root));
  3371             if (mTreeOwner) {
  3372                 NS_ASSERTION(root, "Must have this; worst case it's us!");
  3373                 mTreeOwner->FindItemWithName(aName, root, aOriginalRequestor,
  3374                                              getter_AddRefs(foundItem));
  3376 #ifdef DEBUG
  3377             else {
  3378                 NS_ERROR("Someone isn't setting up the tree owner.  "
  3379                          "You might like to try that.  "
  3380                          "Things will.....you know, work.");
  3381                 // Note: _content should always exist.  If we don't have one
  3382                 // hanging off the treeowner, just create a named window....
  3383                 // so don't return here, in case we did that and can now find
  3384                 // it.                
  3385                 // XXXbz should we be using |root| instead of creating
  3386                 // a new window?
  3388 #endif
  3389         } else {
  3390             // Do the search for item by an actual name.
  3391             DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
  3392                                getter_AddRefs(foundItem));
  3395         if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
  3396             foundItem = nullptr;
  3399         // DoFindItemWithName only returns active items and we don't check if
  3400         // the item is active for the special cases.
  3401         if (foundItem) {
  3402             foundItem.swap(*_retval);
  3404         return NS_OK;
  3408 nsresult
  3409 nsDocShell::DoFindItemWithName(const char16_t* aName,
  3410                                nsISupports* aRequestor,
  3411                                nsIDocShellTreeItem* aOriginalRequestor,
  3412                                nsIDocShellTreeItem** _retval)
  3414     // First we check our name.
  3415     if (mName.Equals(aName) && ItemIsActive(this) &&
  3416         CanAccessItem(this, aOriginalRequestor)) {
  3417         NS_ADDREF(*_retval = this);
  3418         return NS_OK;
  3421     // This QI may fail, but the places where we want to compare, comparing
  3422     // against nullptr serves the same purpose.
  3423     nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
  3425     // Second we check our children making sure not to ask a child if
  3426     // it is the aRequestor.
  3427 #ifdef DEBUG
  3428     nsresult rv =
  3429 #endif
  3430     FindChildWithName(aName, true, true, reqAsTreeItem,
  3431                       aOriginalRequestor, _retval);
  3432     NS_ASSERTION(NS_SUCCEEDED(rv),
  3433                  "FindChildWithName should not be failing here.");
  3434     if (*_retval)
  3435         return NS_OK;
  3437     // Third if we have a parent and it isn't the requestor then we
  3438     // should ask it to do the search.  If it is the requestor we
  3439     // should just stop here and let the parent do the rest.  If we
  3440     // don't have a parent, then we should ask the
  3441     // docShellTreeOwner to do the search.
  3442     nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
  3443         do_QueryInterface(GetAsSupports(mParent));
  3444     if (parentAsTreeItem) {
  3445         if (parentAsTreeItem == reqAsTreeItem)
  3446             return NS_OK;
  3448         if (parentAsTreeItem->ItemType() == mItemType) {
  3449             return parentAsTreeItem->
  3450                 FindItemWithName(aName,
  3451                                  static_cast<nsIDocShellTreeItem*>
  3452                                             (this),
  3453                                  aOriginalRequestor,
  3454                                  _retval);
  3458     // If the parent is null or not of the same type fall through and ask tree
  3459     // owner.
  3461     // This may fail, but comparing against null serves the same purpose
  3462     nsCOMPtr<nsIDocShellTreeOwner>
  3463         reqAsTreeOwner(do_QueryInterface(aRequestor));
  3465     if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
  3466         return mTreeOwner->
  3467             FindItemWithName(aName, this, aOriginalRequestor, _retval);
  3470     return NS_OK;
  3473 bool
  3474 nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell)
  3476     // If no target then not sandboxed.
  3477     if (!aTargetDocShell) {
  3478         return false;
  3481     // We cannot be sandboxed from ourselves.
  3482     if (aTargetDocShell == this) {
  3483         return false;
  3486     // Default the sandbox flags to our flags, so that if we can't retrieve the
  3487     // active document, we will still enforce our own.
  3488     uint32_t sandboxFlags = mSandboxFlags;
  3489     if (mContentViewer) {
  3490         nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
  3491         if (doc) {
  3492             sandboxFlags = doc->GetSandboxFlags();
  3496     // If no flags, we are not sandboxed at all.
  3497     if (!sandboxFlags) {
  3498         return false;
  3501     // If aTargetDocShell has an ancestor, it is not top level.
  3502     nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
  3503     aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
  3504     if (ancestorOfTarget) {
  3505         do {
  3506             // We are not sandboxed if we are an ancestor of target.
  3507             if (ancestorOfTarget == this) {
  3508                 return false;
  3510             nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
  3511             ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
  3512             tempTreeItem.swap(ancestorOfTarget);
  3513         } while (ancestorOfTarget);
  3515         // Otherwise, we are sandboxed from aTargetDocShell.
  3516         return true;
  3519     // aTargetDocShell is top level, are we the "one permitted sandboxed
  3520     // navigator", i.e. did we open aTargetDocShell?
  3521     nsCOMPtr<nsIDocShell> permittedNavigator;
  3522     aTargetDocShell->
  3523         GetOnePermittedSandboxedNavigator(getter_AddRefs(permittedNavigator));
  3524     if (permittedNavigator == this) {
  3525         return false;
  3528     // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
  3529     // from our top.
  3530     if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
  3531         nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
  3532         GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
  3533         if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) {
  3534             return false;
  3538     // Otherwise, we are sandboxed from aTargetDocShell.
  3539     return true;
  3542 NS_IMETHODIMP
  3543 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)
  3545     NS_ENSURE_ARG_POINTER(aTreeOwner);
  3547     *aTreeOwner = mTreeOwner;
  3548     NS_IF_ADDREF(*aTreeOwner);
  3549     return NS_OK;
  3552 #ifdef DEBUG_DOCSHELL_FOCUS
  3553 static void 
  3554 PrintDocTree(nsIDocShellTreeItem * aParentNode, int aLevel)
  3556   for (int32_t i=0;i<aLevel;i++) printf("  ");
  3558   int32_t childWebshellCount;
  3559   aParentNode->GetChildCount(&childWebshellCount);
  3560   nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
  3561   int32_t type = aParentNode->ItemType();
  3562   nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
  3563   nsRefPtr<nsPresContext> presContext;
  3564   parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
  3565   nsIDocument *doc = presShell->GetDocument();
  3567   nsCOMPtr<nsIDOMWindow> domwin(doc->GetWindow());
  3569   nsCOMPtr<nsIWidget> widget;
  3570   nsViewManager* vm = presShell->GetViewManager();
  3571   if (vm) {
  3572     vm->GetWidget(getter_AddRefs(widget));
  3574   dom::Element* rootElement = doc->GetRootElement();
  3576   printf("DS %p  Ty %s  Doc %p DW %p EM %p CN %p\n",  
  3577     (void*)parentAsDocShell.get(), 
  3578     type==nsIDocShellTreeItem::typeChrome?"Chr":"Con", 
  3579      (void*)doc, (void*)domwin.get(),
  3580      (void*)presContext->EventStateManager(), (void*)rootElement);
  3582   if (childWebshellCount > 0) {
  3583     for (int32_t i=0;i<childWebshellCount;i++) {
  3584       nsCOMPtr<nsIDocShellTreeItem> child;
  3585       aParentNode->GetChildAt(i, getter_AddRefs(child));
  3586       PrintDocTree(child, aLevel+1);
  3591 static void 
  3592 PrintDocTree(nsIDocShellTreeItem * aParentNode)
  3594   NS_ASSERTION(aParentNode, "Pointer is null!");
  3596   nsCOMPtr<nsIDocShellTreeItem> parentItem;
  3597   aParentNode->GetParent(getter_AddRefs(parentItem));
  3598   while (parentItem) {
  3599     nsCOMPtr<nsIDocShellTreeItem>tmp;
  3600     parentItem->GetParent(getter_AddRefs(tmp));
  3601     if (!tmp) {
  3602       break;
  3604     parentItem = tmp;
  3607   if (!parentItem) {
  3608     parentItem = aParentNode;
  3611   PrintDocTree(parentItem, 0);
  3613 #endif
  3615 NS_IMETHODIMP
  3616 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
  3618 #ifdef DEBUG_DOCSHELL_FOCUS
  3619     nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
  3620     if (item) {
  3621       PrintDocTree(item);
  3623 #endif
  3625     // Don't automatically set the progress based on the tree owner for frames
  3626     if (!IsFrame()) {
  3627         nsCOMPtr<nsIWebProgress> webProgress =
  3628             do_QueryInterface(GetAsSupports(this));
  3630         if (webProgress) {
  3631             nsCOMPtr<nsIWebProgressListener>
  3632                 oldListener(do_QueryInterface(mTreeOwner));
  3633             nsCOMPtr<nsIWebProgressListener>
  3634                 newListener(do_QueryInterface(aTreeOwner));
  3636             if (oldListener) {
  3637                 webProgress->RemoveProgressListener(oldListener);
  3640             if (newListener) {
  3641                 webProgress->AddProgressListener(newListener,
  3642                                                  nsIWebProgress::NOTIFY_ALL);
  3647     mTreeOwner = aTreeOwner;    // Weak reference per API
  3649     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  3650     while (iter.HasMore()) {
  3651         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
  3652         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
  3654         if (child->ItemType() == mItemType)
  3655             child->SetTreeOwner(aTreeOwner);
  3658     // Our tree owner has changed. Recompute scriptability.
  3659     //
  3660     // Note that this is near-redundant with the recomputation in
  3661     // SetDocLoaderParent(), but not so for the root DocShell, where the call to
  3662     // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
  3663     // and we never set another parent. Given that this is neither expensive nor
  3664     // performance-critical, let's be safe and unconditionally recompute this
  3665     // state whenever dependent state changes.
  3666     RecomputeCanExecuteScripts();
  3668     return NS_OK;
  3671 NS_IMETHODIMP
  3672 nsDocShell::SetChildOffset(uint32_t aChildOffset)
  3674     mChildOffset = aChildOffset;
  3675     return NS_OK;
  3678 NS_IMETHODIMP
  3679 nsDocShell::GetHistoryID(uint64_t* aID)
  3681   *aID = mHistoryID;
  3682   return NS_OK;
  3685 NS_IMETHODIMP
  3686 nsDocShell::GetIsInUnload(bool* aIsInUnload)
  3688     *aIsInUnload = mFiredUnloadEvent;
  3689     return NS_OK;
  3692 NS_IMETHODIMP
  3693 nsDocShell::GetChildCount(int32_t * aChildCount)
  3695     NS_ENSURE_ARG_POINTER(aChildCount);
  3696     *aChildCount = mChildList.Length();
  3697     return NS_OK;
  3702 NS_IMETHODIMP
  3703 nsDocShell::AddChild(nsIDocShellTreeItem * aChild)
  3705     NS_ENSURE_ARG_POINTER(aChild);
  3707     nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
  3708     NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
  3710     // Make sure we're not creating a loop in the docshell tree
  3711     nsDocLoader* ancestor = this;
  3712     do {
  3713         if (childAsDocLoader == ancestor) {
  3714             return NS_ERROR_ILLEGAL_VALUE;
  3716         ancestor = ancestor->GetParent();
  3717     } while (ancestor);
  3719     // Make sure to remove the child from its current parent.
  3720     nsDocLoader* childsParent = childAsDocLoader->GetParent();
  3721     if (childsParent) {
  3722         childsParent->RemoveChildLoader(childAsDocLoader);
  3725     // Make sure to clear the treeowner in case this child is a different type
  3726     // from us.
  3727     aChild->SetTreeOwner(nullptr);
  3729     nsresult res = AddChildLoader(childAsDocLoader);
  3730     NS_ENSURE_SUCCESS(res, res);
  3731     NS_ASSERTION(!mChildList.IsEmpty(),
  3732                  "child list must not be empty after a successful add");
  3734     nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
  3735     bool dynamic = false;
  3736     childDocShell->GetCreatedDynamically(&dynamic);
  3737     if (!dynamic) {
  3738         nsCOMPtr<nsISHEntry> currentSH;
  3739         bool oshe = false;
  3740         GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
  3741         if (currentSH) {
  3742             currentSH->HasDynamicallyAddedChild(&dynamic);
  3745     childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
  3747     /* Set the child's global history if the parent has one */
  3748     if (mUseGlobalHistory) {
  3749             childDocShell->SetUseGlobalHistory(true);
  3752     if (aChild->ItemType() != mItemType) {
  3753         return NS_OK;
  3756     aChild->SetTreeOwner(mTreeOwner);
  3758     nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
  3759     if (!childAsDocShell)
  3760         return NS_OK;
  3762     // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
  3764     // Now take this document's charset and set the child's parentCharset field
  3765     // to it. We'll later use that field, in the loading process, for the
  3766     // charset choosing algorithm.
  3767     // If we fail, at any point, we just return NS_OK.
  3768     // This code has some performance impact. But this will be reduced when 
  3769     // the current charset will finally be stored as an Atom, avoiding the
  3770     // alias resolution extra look-up.
  3772     // we are NOT going to propagate the charset is this Chrome's docshell
  3773     if (mItemType == nsIDocShellTreeItem::typeChrome)
  3774         return NS_OK;
  3776     // get the parent's current charset
  3777     if (!mContentViewer)
  3778         return NS_OK;
  3779     nsIDocument* doc = mContentViewer->GetDocument();
  3780     if (!doc)
  3781         return NS_OK;
  3783     bool isWyciwyg = false;
  3785     if (mCurrentURI) {
  3786         // Check if the url is wyciwyg
  3787         mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);      
  3790     if (!isWyciwyg) {
  3791         // If this docshell is loaded from a wyciwyg: URI, don't
  3792         // advertise our charset since it does not in any way reflect
  3793         // the actual source charset, which is what we're trying to
  3794         // expose here.
  3796         const nsACString &parentCS = doc->GetDocumentCharacterSet();
  3797         int32_t charsetSource = doc->GetDocumentCharacterSetSource();
  3798         // set the child's parentCharset
  3799         childAsDocShell->SetParentCharset(parentCS,
  3800                                           charsetSource,
  3801                                           doc->NodePrincipal());
  3804     // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
  3806     return NS_OK;
  3809 NS_IMETHODIMP
  3810 nsDocShell::RemoveChild(nsIDocShellTreeItem * aChild)
  3812     NS_ENSURE_ARG_POINTER(aChild);
  3814     nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
  3815     NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
  3817     nsresult rv = RemoveChildLoader(childAsDocLoader);
  3818     NS_ENSURE_SUCCESS(rv, rv);
  3820     aChild->SetTreeOwner(nullptr);
  3822     return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
  3825 NS_IMETHODIMP
  3826 nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem ** aChild)
  3828     NS_ENSURE_ARG_POINTER(aChild);
  3830 #ifdef DEBUG
  3831     if (aIndex < 0) {
  3832       NS_WARNING("Negative index passed to GetChildAt");
  3833     } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
  3834       NS_WARNING("Too large an index passed to GetChildAt");
  3836 #endif
  3838     nsIDocumentLoader* child = ChildAt(aIndex);
  3839     NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
  3841     return CallQueryInterface(child, aChild);
  3844 NS_IMETHODIMP
  3845 nsDocShell::FindChildWithName(const char16_t * aName,
  3846                               bool aRecurse, bool aSameType,
  3847                               nsIDocShellTreeItem * aRequestor,
  3848                               nsIDocShellTreeItem * aOriginalRequestor,
  3849                               nsIDocShellTreeItem ** _retval)
  3851     NS_ENSURE_ARG(aName);
  3852     NS_ENSURE_ARG_POINTER(_retval);
  3854     *_retval = nullptr;          // if we don't find one, we return NS_OK and a null result 
  3856     if (!*aName)
  3857         return NS_OK;
  3859     nsXPIDLString childName;
  3860     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  3861     while (iter.HasMore()) {
  3862         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
  3863         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
  3864         int32_t childType = child->ItemType();
  3866         if (aSameType && (childType != mItemType))
  3867             continue;
  3869         bool childNameEquals = false;
  3870         child->NameEquals(aName, &childNameEquals);
  3871         if (childNameEquals && ItemIsActive(child) &&
  3872             CanAccessItem(child, aOriginalRequestor)) {
  3873             child.swap(*_retval);
  3874             break;
  3877         if (childType != mItemType)     //Only ask it to check children if it is same type
  3878             continue;
  3880         if (aRecurse && (aRequestor != child))  // Only ask the child if it isn't the requestor
  3882             // See if child contains the shell with the given name
  3883 #ifdef DEBUG
  3884             nsresult rv =
  3885 #endif
  3886             child->FindChildWithName(aName, true,
  3887                                      aSameType,
  3888                                      static_cast<nsIDocShellTreeItem*>
  3889                                                 (this),
  3890                                      aOriginalRequestor,
  3891                                      _retval);
  3892             NS_ASSERTION(NS_SUCCEEDED(rv),
  3893                          "FindChildWithName should not fail here");
  3894             if (*_retval)           // found it
  3895                 return NS_OK;
  3898     return NS_OK;
  3901 NS_IMETHODIMP
  3902 nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry ** aResult)
  3904     nsresult rv = NS_OK;
  3906     NS_ENSURE_ARG_POINTER(aResult);
  3907     *aResult = nullptr;
  3910     // A nsISHEntry for a child is *only* available when the parent is in
  3911     // the progress of loading a document too...
  3913     if (mLSHE) {
  3914         /* Before looking for the subframe's url, check
  3915          * the expiration status of the parent. If the parent
  3916          * has expired from cache, then subframes will not be 
  3917          * loaded from history in certain situations.  
  3918          */
  3919         bool parentExpired=false;
  3920         mLSHE->GetExpirationStatus(&parentExpired);
  3922         /* Get the parent's Load Type so that it can be set on the child too.
  3923          * By default give a loadHistory value
  3924          */
  3925         uint32_t loadType = nsIDocShellLoadInfo::loadHistory;
  3926         mLSHE->GetLoadType(&loadType);  
  3927         // If the user did a shift-reload on this frameset page, 
  3928         // we don't want to load the subframes from history.
  3929         if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
  3930             loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
  3931             loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
  3932             loadType == nsIDocShellLoadInfo::loadRefresh)
  3933             return rv;
  3935         /* If the user pressed reload and the parent frame has expired
  3936          *  from cache, we do not want to load the child frame from history.
  3937          */
  3938         if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
  3939             // The parent has expired. Return null.
  3940             *aResult = nullptr;
  3941             return rv;
  3944         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
  3945         if (container) {
  3946             // Get the child subframe from session history.
  3947             rv = container->GetChildAt(aChildOffset, aResult);            
  3948             if (*aResult) 
  3949                 (*aResult)->SetLoadType(loadType);            
  3952     return rv;
  3955 NS_IMETHODIMP
  3956 nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
  3957                             int32_t aChildOffset, uint32_t loadType,
  3958                             bool aCloneChildren)
  3960     nsresult rv;
  3962     if (mLSHE && loadType != LOAD_PUSHSTATE) {
  3963         /* You get here if you are currently building a 
  3964          * hierarchy ie.,you just visited a frameset page
  3965          */
  3966         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
  3967         if (container) {
  3968             rv = container->AddChild(aNewEntry, aChildOffset);
  3971     else if (!aCloneRef) {
  3972         /* This is an initial load in some subframe.  Just append it if we can */
  3973         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
  3974         if (container) {
  3975             rv = container->AddChild(aNewEntry, aChildOffset);
  3978     else if (mSessionHistory) {
  3979         /* You are currently in the rootDocShell.
  3980          * You will get here when a subframe has a new url
  3981          * to load and you have walked up the tree all the 
  3982          * way to the top to clone the current SHEntry hierarchy
  3983          * and replace the subframe where a new url was loaded with
  3984          * a new entry.
  3985          */
  3986         int32_t index = -1;
  3987         nsCOMPtr<nsISHEntry> currentHE;
  3988         mSessionHistory->GetIndex(&index);
  3989         if (index < 0)
  3990             return NS_ERROR_FAILURE;
  3992         rv = mSessionHistory->GetEntryAtIndex(index, false,
  3993                                               getter_AddRefs(currentHE));
  3994         NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
  3996         nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
  3997         if (currentEntry) {
  3998             uint32_t cloneID = 0;
  3999             nsCOMPtr<nsISHEntry> nextEntry;
  4000             aCloneRef->GetID(&cloneID);
  4001             rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
  4002                                  aCloneChildren, getter_AddRefs(nextEntry));
  4004             if (NS_SUCCEEDED(rv)) {
  4005                 nsCOMPtr<nsISHistoryInternal>
  4006                     shPrivate(do_QueryInterface(mSessionHistory));
  4007                 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
  4008                 rv = shPrivate->AddEntry(nextEntry, true);
  4012     else {
  4013         /* Just pass this along */
  4014         nsCOMPtr<nsIDocShell> parent =
  4015             do_QueryInterface(GetAsSupports(mParent), &rv);
  4016         if (parent) {
  4017             rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
  4018                                          loadType, aCloneChildren);
  4021     return rv;
  4024 nsresult
  4025 nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, int32_t aChildOffset,
  4026                               bool aCloneChildren)
  4028     /* You will get here when you are in a subframe and
  4029      * a new url has been loaded on you. 
  4030      * The mOSHE in this subframe will be the previous url's
  4031      * mOSHE. This mOSHE will be used as the identification
  4032      * for this subframe in the  CloneAndReplace function.
  4033      */
  4035     // In this case, we will end up calling AddEntry, which increases the
  4036     // current index by 1
  4037     nsCOMPtr<nsISHistory> rootSH;
  4038     GetRootSessionHistory(getter_AddRefs(rootSH));
  4039     if (rootSH) {
  4040         rootSH->GetIndex(&mPreviousTransIndex);
  4043     nsresult rv;
  4044     nsCOMPtr<nsIDocShell> parent =
  4045         do_QueryInterface(GetAsSupports(mParent), &rv);
  4046     if (parent) {
  4047         rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
  4048                                      aCloneChildren);
  4052     if (rootSH) {
  4053         rootSH->GetIndex(&mLoadedTransIndex);
  4054 #ifdef DEBUG_PAGE_CACHE
  4055         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
  4056                mLoadedTransIndex);
  4057 #endif
  4060     return rv;
  4063 NS_IMETHODIMP
  4064 nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
  4066     nsresult rv;
  4068     mUseGlobalHistory = aUseGlobalHistory;
  4070     if (!aUseGlobalHistory) {
  4071         mGlobalHistory = nullptr;
  4072         return NS_OK;
  4075     // No need to initialize mGlobalHistory if IHistory is available.
  4076     nsCOMPtr<IHistory> history = services::GetHistoryService();
  4077     if (history) {
  4078         return NS_OK;
  4081     if (mGlobalHistory) {
  4082         return NS_OK;
  4085     mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
  4086     return rv;
  4089 NS_IMETHODIMP
  4090 nsDocShell::GetUseGlobalHistory(bool *aUseGlobalHistory)
  4092     *aUseGlobalHistory = mUseGlobalHistory;
  4093     return NS_OK;
  4096 NS_IMETHODIMP
  4097 nsDocShell::RemoveFromSessionHistory()
  4099     nsCOMPtr<nsISHistoryInternal> internalHistory;
  4100     nsCOMPtr<nsISHistory> sessionHistory;
  4101     nsCOMPtr<nsIDocShellTreeItem> root;
  4102     GetSameTypeRootTreeItem(getter_AddRefs(root));
  4103     if (root) {
  4104         nsCOMPtr<nsIWebNavigation> rootAsWebnav =
  4105             do_QueryInterface(root);
  4106         if (rootAsWebnav) {
  4107             rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
  4108             internalHistory = do_QueryInterface(sessionHistory);
  4111     if (!internalHistory) {
  4112         return NS_OK;
  4115     int32_t index = 0;
  4116     sessionHistory->GetIndex(&index);
  4117     nsAutoTArray<uint64_t, 16> ids;
  4118     ids.AppendElement(mHistoryID);
  4119     internalHistory->RemoveEntries(ids, index);
  4120     return NS_OK;
  4123 NS_IMETHODIMP
  4124 nsDocShell::SetCreatedDynamically(bool aDynamic)
  4126     mDynamicallyCreated = aDynamic;
  4127     return NS_OK;
  4130 NS_IMETHODIMP
  4131 nsDocShell::GetCreatedDynamically(bool* aDynamic)
  4133     *aDynamic = mDynamicallyCreated;
  4134     return NS_OK;
  4137 NS_IMETHODIMP
  4138 nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
  4140     *aOSHE = false;
  4141     *aEntry = nullptr;
  4142     if (mLSHE) {
  4143         NS_ADDREF(*aEntry = mLSHE);
  4144     } else if (mOSHE) {
  4145         NS_ADDREF(*aEntry = mOSHE);
  4146         *aOSHE = true;
  4148     return NS_OK;
  4151 nsIScriptGlobalObject*
  4152 nsDocShell::GetScriptGlobalObject()
  4154     NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
  4155     return mScriptGlobal;
  4158 NS_IMETHODIMP
  4159 nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
  4161     if (mDeviceSizeIsPageSize != aValue) {
  4162       mDeviceSizeIsPageSize = aValue;
  4163       nsRefPtr<nsPresContext> presContext;
  4164       GetPresContext(getter_AddRefs(presContext));
  4165       if (presContext) {
  4166           presContext->MediaFeatureValuesChanged(presContext->eAlwaysRebuildStyle);
  4169     return NS_OK;
  4172 NS_IMETHODIMP
  4173 nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
  4175     *aValue = mDeviceSizeIsPageSize;
  4176     return NS_OK;
  4179 void
  4180 nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
  4182   nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
  4183   nsCOMPtr<nsISHistory> rootSH;
  4184   GetRootSessionHistory(getter_AddRefs(rootSH));
  4185   nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
  4186   if (!history || !shcontainer) {
  4187     return;
  4190   int32_t count = 0;
  4191   shcontainer->GetChildCount(&count);
  4192   nsAutoTArray<uint64_t, 16> ids;
  4193   for (int32_t i = 0; i < count; ++i) {
  4194     nsCOMPtr<nsISHEntry> child;
  4195     shcontainer->GetChildAt(i, getter_AddRefs(child));
  4196     if (child) {
  4197       uint64_t id = 0;
  4198       child->GetDocshellID(&id);
  4199       ids.AppendElement(id);
  4202   int32_t index = 0;
  4203   rootSH->GetIndex(&index);
  4204   history->RemoveEntries(ids, index);
  4207 //-------------------------------------
  4208 //-- Helper Method for Print discovery
  4209 //-------------------------------------
  4210 bool 
  4211 nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
  4213   if (mIsPrintingOrPP && aDisplayErrorDialog) {
  4214     DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
  4217   return mIsPrintingOrPP;
  4220 bool
  4221 nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog)
  4223   bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
  4224   if (!isAllowed) {
  4225     return false;
  4227   if (!mContentViewer) {
  4228     return true;
  4230   bool firingBeforeUnload;
  4231   mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
  4232   return !firingBeforeUnload;
  4235 //*****************************************************************************
  4236 // nsDocShell::nsIWebNavigation
  4237 //*****************************************************************************   
  4239 NS_IMETHODIMP
  4240 nsDocShell::GetCanGoBack(bool * aCanGoBack)
  4242     if (!IsNavigationAllowed(false)) {
  4243       *aCanGoBack = false;
  4244       return NS_OK; // JS may not handle returning of an error code
  4246     nsresult rv;
  4247     nsCOMPtr<nsISHistory> rootSH;
  4248     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
  4249     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
  4250     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
  4251     rv = webnav->GetCanGoBack(aCanGoBack);   
  4252     return rv;
  4256 NS_IMETHODIMP
  4257 nsDocShell::GetCanGoForward(bool * aCanGoForward)
  4259     if (!IsNavigationAllowed(false)) {
  4260       *aCanGoForward = false;
  4261       return NS_OK; // JS may not handle returning of an error code
  4263     nsresult rv;
  4264     nsCOMPtr<nsISHistory> rootSH;
  4265     rv = GetRootSessionHistory(getter_AddRefs(rootSH)); 
  4266     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
  4267     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
  4268     rv = webnav->GetCanGoForward(aCanGoForward);
  4269     return rv;
  4273 NS_IMETHODIMP
  4274 nsDocShell::GoBack()
  4276     if (!IsNavigationAllowed()) {
  4277       return NS_OK; // JS may not handle returning of an error code
  4279     nsresult rv;
  4280     nsCOMPtr<nsISHistory> rootSH;
  4281     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
  4282     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
  4283     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
  4284     rv = webnav->GoBack();
  4285     return rv;
  4289 NS_IMETHODIMP
  4290 nsDocShell::GoForward()
  4292     if (!IsNavigationAllowed()) {
  4293       return NS_OK; // JS may not handle returning of an error code
  4295     nsresult rv;
  4296     nsCOMPtr<nsISHistory> rootSH;
  4297     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
  4298     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
  4299     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
  4300     rv = webnav->GoForward();
  4301     return rv;
  4305 NS_IMETHODIMP nsDocShell::GotoIndex(int32_t aIndex)
  4307     if (!IsNavigationAllowed()) {
  4308       return NS_OK; // JS may not handle returning of an error code
  4310     nsresult rv;
  4311     nsCOMPtr<nsISHistory> rootSH;
  4312     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
  4313     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
  4314     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
  4315     rv = webnav->GotoIndex(aIndex);
  4316     return rv;
  4320 NS_IMETHODIMP
  4321 nsDocShell::LoadURI(const char16_t * aURI,
  4322                     uint32_t aLoadFlags,
  4323                     nsIURI * aReferringURI,
  4324                     nsIInputStream * aPostStream,
  4325                     nsIInputStream * aHeaderStream)
  4327     return LoadURIWithBase(aURI, aLoadFlags, aReferringURI, aPostStream,
  4328                            aHeaderStream, nullptr);
  4331 NS_IMETHODIMP
  4332 nsDocShell::LoadURIWithBase(const char16_t * aURI,
  4333                             uint32_t aLoadFlags,
  4334                             nsIURI * aReferringURI,
  4335                             nsIInputStream * aPostStream,
  4336                             nsIInputStream * aHeaderStream,
  4337                             nsIURI * aBaseURI)
  4339     NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
  4341     if (!IsNavigationAllowed()) {
  4342       return NS_OK; // JS may not handle returning of an error code
  4344     nsCOMPtr<nsIURI> uri;
  4345     nsCOMPtr<nsIInputStream> postStream(aPostStream);
  4346     nsresult rv = NS_OK;
  4348     // Create a URI from our string; if that succeeds, we want to
  4349     // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
  4350     // flag.
  4352     NS_ConvertUTF16toUTF8 uriString(aURI);
  4353     // Cleanup the empty spaces that might be on each end.
  4354     uriString.Trim(" ");
  4355     // Eliminate embedded newlines, which single-line text fields now allow:
  4356     uriString.StripChars("\r\n");
  4357     NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
  4359     rv = NS_NewURI(getter_AddRefs(uri), uriString);
  4360     if (uri) {
  4361         aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
  4364     if (sURIFixup) {
  4365         // Call the fixup object.  This will clobber the rv from NS_NewURI
  4366         // above, but that's fine with us.  Note that we need to do this even
  4367         // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
  4368         // (things like view-source:mozilla.org for example).
  4369         uint32_t fixupFlags = 0;
  4370         if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
  4371           fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
  4373         if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
  4374           fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
  4376         nsCOMPtr<nsIInputStream> fixupStream;
  4377         rv = sURIFixup->CreateFixupURI(uriString, fixupFlags,
  4378                                        getter_AddRefs(fixupStream),
  4379                                        getter_AddRefs(uri));
  4380         if (fixupStream) {
  4381             // CreateFixupURI only returns a post data stream if it succeeded
  4382             // and changed the URI, in which case we should override the
  4383             // passed-in post data.
  4384             postStream = fixupStream;
  4387     // else no fixup service so just use the URI we created and see
  4388     // what happens
  4390     if (NS_ERROR_MALFORMED_URI == rv) {
  4391         DisplayLoadError(rv, uri, aURI, nullptr);
  4394     if (NS_FAILED(rv) || !uri)
  4395         return NS_ERROR_FAILURE;
  4397     PopupControlState popupState;
  4398     if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
  4399         popupState = openAllowed;
  4400         aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
  4401     } else {
  4402         popupState = openOverridden;
  4404     nsAutoPopupStatePusher statePusher(popupState);
  4406     // Don't pass certain flags that aren't needed and end up confusing
  4407     // ConvertLoadTypeToDocShellLoadInfo.  We do need to ensure that they are
  4408     // passed to LoadURI though, since it uses them.
  4409     uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
  4410     aLoadFlags &= ~EXTRA_LOAD_FLAGS;
  4412     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
  4413     rv = CreateLoadInfo(getter_AddRefs(loadInfo));
  4414     if (NS_FAILED(rv)) return rv;
  4416     /*
  4417      * If the user "Disables Protection on This Page", we have to make sure to
  4418      * remember the users decision when opening links in child tabs [Bug 906190]
  4419      */
  4420     uint32_t loadType;
  4421     if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
  4422       loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
  4423     } else {
  4424       loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
  4427     loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
  4428     loadInfo->SetPostDataStream(postStream);
  4429     loadInfo->SetReferrer(aReferringURI);
  4430     loadInfo->SetHeadersStream(aHeaderStream);
  4431     loadInfo->SetBaseURI(aBaseURI);
  4433     rv = LoadURI(uri, loadInfo, extraFlags, true);
  4435     // Save URI string in case it's needed later when
  4436     // sending to search engine service in EndPageLoad()
  4437     mOriginalUriString = uriString; 
  4439     return rv;
  4442 NS_IMETHODIMP
  4443 nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
  4444                              const char16_t *aURL,
  4445                              nsIChannel* aFailedChannel)
  4447     // Get prompt and string bundle servcies
  4448     nsCOMPtr<nsIPrompt> prompter;
  4449     nsCOMPtr<nsIStringBundle> stringBundle;
  4450     GetPromptAndStringBundle(getter_AddRefs(prompter),
  4451                              getter_AddRefs(stringBundle));
  4453     NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
  4454     NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
  4456     nsAutoString error;
  4457     const uint32_t kMaxFormatStrArgs = 3;
  4458     nsAutoString formatStrs[kMaxFormatStrArgs];
  4459     uint32_t formatStrCount = 0;
  4460     bool addHostPort = false;
  4461     nsresult rv = NS_OK;
  4462     nsAutoString messageStr;
  4463     nsAutoCString cssClass;
  4464     nsAutoCString errorPage;
  4466     errorPage.AssignLiteral("neterror");
  4468     // Turn the error code into a human readable error message.
  4469     if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
  4470         NS_ENSURE_ARG_POINTER(aURI);
  4472         // Extract the schemes into a comma delimited list.
  4473         nsAutoCString scheme;
  4474         aURI->GetScheme(scheme);
  4475         CopyASCIItoUTF16(scheme, formatStrs[0]);
  4476         nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
  4477         while (nestedURI) {
  4478             nsCOMPtr<nsIURI> tempURI;
  4479             nsresult rv2;
  4480             rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
  4481             if (NS_SUCCEEDED(rv2) && tempURI) {
  4482                 tempURI->GetScheme(scheme);
  4483                 formatStrs[0].Append(NS_LITERAL_STRING(", "));
  4484                 AppendASCIItoUTF16(scheme, formatStrs[0]);
  4486             nestedURI = do_QueryInterface(tempURI);
  4488         formatStrCount = 1;
  4489         error.AssignLiteral("unknownProtocolFound");
  4491     else if (NS_ERROR_FILE_NOT_FOUND == aError) {
  4492         NS_ENSURE_ARG_POINTER(aURI);
  4493         error.AssignLiteral("fileNotFound");
  4495     else if (NS_ERROR_UNKNOWN_HOST == aError) {
  4496         NS_ENSURE_ARG_POINTER(aURI);
  4497         // Get the host
  4498         nsAutoCString host;
  4499         nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
  4500         innermostURI->GetHost(host);
  4501         CopyUTF8toUTF16(host, formatStrs[0]);
  4502         formatStrCount = 1;
  4503         error.AssignLiteral("dnsNotFound");
  4505     else if(NS_ERROR_CONNECTION_REFUSED == aError) {
  4506         NS_ENSURE_ARG_POINTER(aURI);
  4507         addHostPort = true;
  4508         error.AssignLiteral("connectionFailure");
  4510     else if(NS_ERROR_NET_INTERRUPT == aError) {
  4511         NS_ENSURE_ARG_POINTER(aURI);
  4512         addHostPort = true;
  4513         error.AssignLiteral("netInterrupt");
  4515     else if (NS_ERROR_NET_TIMEOUT == aError) {
  4516         NS_ENSURE_ARG_POINTER(aURI);
  4517         // Get the host
  4518         nsAutoCString host;
  4519         aURI->GetHost(host);
  4520         CopyUTF8toUTF16(host, formatStrs[0]);
  4521         formatStrCount = 1;
  4522         error.AssignLiteral("netTimeout");
  4524     else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError) {
  4525         // CSP error
  4526         cssClass.AssignLiteral("neterror");
  4527         error.AssignLiteral("cspFrameAncestorBlocked");
  4529     else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
  4530         nsCOMPtr<nsINSSErrorsService> nsserr =
  4531             do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
  4533         uint32_t errorClass;
  4534         if (!nsserr ||
  4535             NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
  4536           errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
  4539         nsCOMPtr<nsISupports> securityInfo;
  4540         nsCOMPtr<nsITransportSecurityInfo> tsi;
  4541         if (aFailedChannel)
  4542             aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
  4543         tsi = do_QueryInterface(securityInfo);
  4544         if (tsi) {
  4545             // Usually we should have aFailedChannel and get a detailed message
  4546             tsi->GetErrorMessage(getter_Copies(messageStr));
  4548         else {
  4549             // No channel, let's obtain the generic error message
  4550             if (nsserr) {
  4551                 nsserr->GetErrorMessage(aError, messageStr);
  4554         if (!messageStr.IsEmpty()) {
  4555             if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
  4556                 error.AssignLiteral("nssBadCert");
  4558                 // if this is a Strict-Transport-Security host and the cert
  4559                 // is bad, don't allow overrides (STS Spec section 7.3).
  4560                 nsCOMPtr<nsISiteSecurityService> sss =
  4561                           do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
  4562                 NS_ENSURE_SUCCESS(rv, rv);
  4563                 uint32_t flags =
  4564                   mInPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
  4566                 bool isStsHost = false;
  4567                 rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
  4568                                       aURI, flags, &isStsHost);
  4569                 NS_ENSURE_SUCCESS(rv, rv);
  4571                 uint32_t bucketId;
  4572                 if (isStsHost) {
  4573                   cssClass.AssignLiteral("badStsCert");
  4574                   //measuring STS separately allows us to measure click through
  4575                   //rates easily
  4576                   bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
  4577                 } else {
  4578                   bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
  4582                 if (Preferences::GetBool(
  4583                         "browser.xul.error_pages.expert_bad_cert", false)) {
  4584                     cssClass.AssignLiteral("expertBadCert");
  4587                 // See if an alternate cert error page is registered
  4588                 nsAdoptingCString alternateErrorPage =
  4589                     Preferences::GetCString(
  4590                         "security.alternate_certificate_error_page");
  4591                 if (alternateErrorPage)
  4592                     errorPage.Assign(alternateErrorPage);
  4594                 if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) 
  4595                     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
  4597             } else {
  4598                 error.AssignLiteral("nssFailure2");
  4601     } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError) {
  4602         nsAutoCString host;
  4603         aURI->GetHost(host);
  4604         CopyUTF8toUTF16(host, formatStrs[0]);
  4605         formatStrCount = 1;
  4607         // Malware and phishing detectors may want to use an alternate error
  4608         // page, but if the pref's not set, we'll fall back on the standard page
  4609         nsAdoptingCString alternateErrorPage =
  4610             Preferences::GetCString("urlclassifier.alternate_error_page");
  4611         if (alternateErrorPage)
  4612             errorPage.Assign(alternateErrorPage);
  4614         uint32_t bucketId;
  4615         if (NS_ERROR_PHISHING_URI == aError) {
  4616             error.AssignLiteral("phishingBlocked");
  4617             bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME :
  4618                                    nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP ;
  4619         } else {
  4620             error.AssignLiteral("malwareBlocked");
  4621             bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME :
  4622                                    nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP ;
  4625         if (errorPage.EqualsIgnoreCase("blocked"))
  4626             mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI,
  4627                                            bucketId);
  4629         cssClass.AssignLiteral("blacklist");
  4630     } else if (NS_ERROR_CONTENT_CRASHED == aError) {
  4631       errorPage.AssignLiteral("tabcrashed");
  4632       error.AssignLiteral("tabcrashed");
  4634       nsCOMPtr<EventTarget> handler = mChromeEventHandler;
  4635       if (handler) {
  4636         nsCOMPtr<Element> element = do_QueryInterface(handler);
  4637         element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
  4640       // DisplayLoadError requires a non-empty messageStr to proceed and call LoadErrorPage.
  4641       // If the page doesn't have a title, we will use a blank space which will be trimmed
  4642       // and thus treated as empty by the front-end.
  4643       if (messageStr.IsEmpty()) {
  4644         messageStr.Assign(NS_LITERAL_STRING(" "));
  4647     else {
  4648         // Errors requiring simple formatting
  4649         switch (aError) {
  4650         case NS_ERROR_MALFORMED_URI:
  4651             // URI is malformed
  4652             error.AssignLiteral("malformedURI");
  4653             break;
  4654         case NS_ERROR_REDIRECT_LOOP:
  4655             // Doc failed to load because the server generated too many redirects
  4656             error.AssignLiteral("redirectLoop");
  4657             break;
  4658         case NS_ERROR_UNKNOWN_SOCKET_TYPE:
  4659             // Doc failed to load because PSM is not installed
  4660             error.AssignLiteral("unknownSocketType");
  4661             break;
  4662         case NS_ERROR_NET_RESET:
  4663             // Doc failed to load because the server kept reseting the connection
  4664             // before we could read any data from it
  4665             error.AssignLiteral("netReset");
  4666             break;
  4667         case NS_ERROR_DOCUMENT_NOT_CACHED:
  4668             // Doc failed to load because the cache does not contain a copy of
  4669             // the document.
  4670             error.AssignLiteral("notCached");
  4671             break;
  4672         case NS_ERROR_OFFLINE:
  4673             // Doc failed to load because we are offline.
  4674             error.AssignLiteral("netOffline");
  4675             break;
  4676         case NS_ERROR_DOCUMENT_IS_PRINTMODE:
  4677             // Doc navigation attempted while Printing or Print Preview
  4678             error.AssignLiteral("isprinting");
  4679             break;
  4680         case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
  4681             // Port blocked for security reasons
  4682             addHostPort = true;
  4683             error.AssignLiteral("deniedPortAccess");
  4684             break;
  4685         case NS_ERROR_UNKNOWN_PROXY_HOST:
  4686             // Proxy hostname could not be resolved.
  4687             error.AssignLiteral("proxyResolveFailure");
  4688             break;
  4689         case NS_ERROR_PROXY_CONNECTION_REFUSED:
  4690             // Proxy connection was refused.
  4691             error.AssignLiteral("proxyConnectFailure");
  4692             break;
  4693         case NS_ERROR_INVALID_CONTENT_ENCODING:
  4694             // Bad Content Encoding.
  4695             error.AssignLiteral("contentEncodingError");
  4696             break;
  4697         case NS_ERROR_REMOTE_XUL:
  4699             error.AssignLiteral("remoteXUL");
  4700             break;
  4702         case NS_ERROR_UNSAFE_CONTENT_TYPE:
  4703             // Channel refused to load from an unrecognized content type.
  4704             error.AssignLiteral("unsafeContentType");
  4705             break;
  4706         case NS_ERROR_CORRUPTED_CONTENT:
  4707             // Broken Content Detected. e.g. Content-MD5 check failure.
  4708             error.AssignLiteral("corruptedContentError");
  4709             break;
  4710         default:
  4711             break;
  4715     // Test if the error should be displayed
  4716     if (error.IsEmpty()) {
  4717         return NS_OK;
  4720     // Test if the error needs to be formatted
  4721     if (!messageStr.IsEmpty()) {
  4722         // already obtained message
  4724     else {
  4725         if (addHostPort) {
  4726             // Build up the host:port string.
  4727             nsAutoCString hostport;
  4728             if (aURI) {
  4729                 aURI->GetHostPort(hostport);
  4730             } else {
  4731                 hostport.AssignLiteral("?");
  4733             CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
  4736         nsAutoCString spec;
  4737         rv = NS_ERROR_NOT_AVAILABLE;
  4738         if (aURI) {
  4739             // displaying "file://" is aesthetically unpleasing and could even be
  4740             // confusing to the user
  4741             bool isFileURI = false;
  4742             rv = aURI->SchemeIs("file", &isFileURI);
  4743             if (NS_SUCCEEDED(rv) && isFileURI)
  4744                 aURI->GetPath(spec);
  4745             else
  4746                 aURI->GetSpec(spec);
  4748             nsAutoCString charset;
  4749             // unescape and convert from origin charset
  4750             aURI->GetOriginCharset(charset);
  4751             nsCOMPtr<nsITextToSubURI> textToSubURI(
  4752                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
  4753             if (NS_SUCCEEDED(rv)) {
  4754                 rv = textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[formatStrCount]);
  4756         } else {
  4757             spec.AssignLiteral("?");
  4759         if (NS_FAILED(rv))
  4760             CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
  4761         rv = NS_OK;
  4762         ++formatStrCount;
  4764         const char16_t *strs[kMaxFormatStrArgs];
  4765         for (uint32_t i = 0; i < formatStrCount; i++) {
  4766             strs[i] = formatStrs[i].get();
  4768         nsXPIDLString str;
  4769         rv = stringBundle->FormatStringFromName(
  4770             error.get(),
  4771             strs, formatStrCount, getter_Copies(str));
  4772         NS_ENSURE_SUCCESS(rv, rv);
  4773         messageStr.Assign(str.get());
  4776     // Display the error as a page or an alert prompt
  4777     NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
  4779     if (UseErrorPages()) {
  4780         // Display an error page
  4781         LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
  4782                       messageStr.get(), cssClass.get(), aFailedChannel);
  4784     else
  4786         // The prompter reqires that our private window has a document (or it
  4787         // asserts). Satisfy that assertion now since GetDoc will force
  4788         // creation of one if it hasn't already been created.
  4789         if (mScriptGlobal) {
  4790             unused << mScriptGlobal->GetDoc();
  4793         // Display a message box
  4794         prompter->Alert(nullptr, messageStr.get());
  4797     return NS_OK;
  4801 NS_IMETHODIMP
  4802 nsDocShell::LoadErrorPage(nsIURI *aURI, const char16_t *aURL,
  4803                           const char *aErrorPage,
  4804                           const char16_t *aErrorType,
  4805                           const char16_t *aDescription,
  4806                           const char *aCSSClass,
  4807                           nsIChannel* aFailedChannel)
  4809 #if defined(PR_LOGGING) && defined(DEBUG)
  4810     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
  4811         nsAutoCString spec;
  4812         aURI->GetSpec(spec);
  4814         nsAutoCString chanName;
  4815         if (aFailedChannel)
  4816             aFailedChannel->GetName(chanName);
  4817         else
  4818             chanName.AssignLiteral("<no channel>");
  4820         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
  4821                ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
  4822                 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
  4824 #endif
  4825     mFailedChannel = aFailedChannel;
  4826     mFailedURI = aURI;
  4827     mFailedLoadType = mLoadType;
  4829     if (mLSHE) {
  4830         // Abandon mLSHE's BFCache entry and create a new one.  This way, if
  4831         // we go back or forward to another SHEntry with the same doc
  4832         // identifier, the error page won't persist.
  4833         mLSHE->AbandonBFCacheEntry();
  4836     nsAutoCString url;
  4837     nsAutoCString charset;
  4838     if (aURI)
  4840         nsresult rv = aURI->GetSpec(url);
  4841         NS_ENSURE_SUCCESS(rv, rv);
  4842         rv = aURI->GetOriginCharset(charset);
  4843         NS_ENSURE_SUCCESS(rv, rv);
  4845     else if (aURL)
  4847         CopyUTF16toUTF8(aURL, url);
  4849     else
  4851         return NS_ERROR_INVALID_POINTER;
  4854     // Create a URL to pass all the error information through to the page.
  4856 #undef SAFE_ESCAPE
  4857 #define SAFE_ESCAPE(cstring, escArg1, escArg2)  \
  4858     {                                           \
  4859         char* s = nsEscape(escArg1, escArg2);   \
  4860         if (!s)                                 \
  4861             return NS_ERROR_OUT_OF_MEMORY;      \
  4862         cstring.Adopt(s);                       \
  4864     nsCString escapedUrl, escapedCharset, escapedError, escapedDescription,
  4865               escapedCSSClass;
  4866     SAFE_ESCAPE(escapedUrl, url.get(), url_Path);
  4867     SAFE_ESCAPE(escapedCharset, charset.get(), url_Path);
  4868     SAFE_ESCAPE(escapedError,
  4869                 NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
  4870     SAFE_ESCAPE(escapedDescription,
  4871                 NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
  4872     if (aCSSClass) {
  4873         SAFE_ESCAPE(escapedCSSClass, aCSSClass, url_Path);
  4875     nsCString errorPageUrl("about:");
  4876     errorPageUrl.AppendASCII(aErrorPage);
  4877     errorPageUrl.AppendLiteral("?e=");
  4879     errorPageUrl.AppendASCII(escapedError.get());
  4880     errorPageUrl.AppendLiteral("&u=");
  4881     errorPageUrl.AppendASCII(escapedUrl.get());
  4882     if (!escapedCSSClass.IsEmpty()) {
  4883         errorPageUrl.AppendLiteral("&s=");
  4884         errorPageUrl.AppendASCII(escapedCSSClass.get());
  4886     errorPageUrl.AppendLiteral("&c=");
  4887     errorPageUrl.AppendASCII(escapedCharset.get());
  4889     nsAutoCString frameType(FrameTypeToString(mFrameType));
  4890     errorPageUrl.AppendLiteral("&f=");
  4891     errorPageUrl.AppendASCII(frameType.get());
  4893     // Append the manifest URL if the error comes from an app.
  4894     nsString manifestURL;
  4895     nsresult rv = GetAppManifestURL(manifestURL);
  4896     if (manifestURL.Length() > 0) {
  4897       nsCString manifestParam;
  4898       SAFE_ESCAPE(manifestParam,
  4899                   NS_ConvertUTF16toUTF8(manifestURL).get(),
  4900                   url_Path);
  4901       errorPageUrl.AppendLiteral("&m=");
  4902       errorPageUrl.AppendASCII(manifestParam.get());
  4905     // netError.xhtml's getDescription only handles the "d" parameter at the
  4906     // end of the URL, so append it last.
  4907     errorPageUrl.AppendLiteral("&d=");
  4908     errorPageUrl.AppendASCII(escapedDescription.get());
  4910     nsCOMPtr<nsIURI> errorPageURI;
  4911     rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
  4912     NS_ENSURE_SUCCESS(rv, rv);
  4914     return InternalLoad(errorPageURI, nullptr, nullptr,
  4915                         INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr, nullptr,
  4916                         NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
  4917                         nullptr, true, NullString(), this, nullptr, nullptr,
  4918                         nullptr);
  4922 NS_IMETHODIMP
  4923 nsDocShell::Reload(uint32_t aReloadFlags)
  4925     if (!IsNavigationAllowed()) {
  4926       return NS_OK; // JS may not handle returning of an error code
  4928     nsresult rv;
  4929     NS_ASSERTION(((aReloadFlags & 0xf) == 0),
  4930                  "Reload command not updated to use load flags!");
  4931     NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
  4932                  "Don't pass these flags to Reload");
  4934     uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
  4935     NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
  4937     // Send notifications to the HistoryListener if any, about the impending reload
  4938     nsCOMPtr<nsISHistory> rootSH;
  4939     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
  4940     nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
  4941     bool canReload = true;
  4942     if (rootSH) {
  4943       shistInt->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
  4946     if (!canReload)
  4947       return NS_OK;
  4949     /* If you change this part of code, make sure bug 45297 does not re-occur */
  4950     if (mOSHE) {
  4951         rv = LoadHistoryEntry(mOSHE, loadType);
  4953     else if (mLSHE) { // In case a reload happened before the current load is done
  4954         rv = LoadHistoryEntry(mLSHE, loadType);
  4956     else {
  4957         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  4959         // Do not inherit owner from document
  4960         uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
  4961         nsAutoString srcdoc;
  4962         nsIPrincipal* principal = nullptr;
  4963         nsAutoString contentTypeHint;
  4964         nsCOMPtr<nsIURI> baseURI;
  4965         if (doc) {
  4966             principal = doc->NodePrincipal();
  4967             doc->GetContentType(contentTypeHint);
  4969             if (doc->IsSrcdocDocument()) {
  4970                 doc->GetSrcdocData(srcdoc);
  4971                 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
  4972                 baseURI = doc->GetBaseURI();
  4975         rv = InternalLoad(mCurrentURI,
  4976                           mReferrerURI,
  4977                           principal,
  4978                           flags,
  4979                           nullptr,         // No window target
  4980                           NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
  4981                           NullString(),    // No forced download
  4982                           nullptr,         // No post data
  4983                           nullptr,         // No headers data
  4984                           loadType,        // Load type
  4985                           nullptr,         // No SHEntry
  4986                           true,
  4987                           srcdoc,          // srcdoc argument for iframe
  4988                           this,            // For reloads we are the source
  4989                           baseURI,
  4990                           nullptr,         // No nsIDocShell
  4991                           nullptr);        // No nsIRequest
  4994     return rv;
  4997 NS_IMETHODIMP
  4998 nsDocShell::Stop(uint32_t aStopFlags)
  5000     // Revoke any pending event related to content viewer restoration
  5001     mRestorePresentationEvent.Revoke();
  5003     if (mLoadType == LOAD_ERROR_PAGE) {
  5004         if (mLSHE) {
  5005             // Since error page loads never unset mLSHE, do so now
  5006             SetHistoryEntry(&mOSHE, mLSHE);
  5007             SetHistoryEntry(&mLSHE, nullptr);
  5010         mFailedChannel = nullptr;
  5011         mFailedURI = nullptr;
  5014     if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
  5015         // Stop the document loading
  5016         if (mContentViewer) {
  5017             nsCOMPtr<nsIContentViewer> cv = mContentViewer;
  5018             cv->Stop();
  5022     if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
  5023         // Suspend any timers that were set for this loader.  We'll clear
  5024         // them out for good in CreateContentViewer.
  5025         if (mRefreshURIList) {
  5026             SuspendRefreshURIs();
  5027             mSavedRefreshURIList.swap(mRefreshURIList);
  5028             mRefreshURIList = nullptr;
  5031         // XXXbz We could also pass |this| to nsIURILoader::Stop.  That will
  5032         // just call Stop() on us as an nsIDocumentLoader... We need fewer
  5033         // redundant apis!
  5034         Stop();
  5037     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  5038     while (iter.HasMore()) {
  5039         nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext()));
  5040         if (shellAsNav)
  5041             shellAsNav->Stop(aStopFlags);
  5044     return NS_OK;
  5047 NS_IMETHODIMP
  5048 nsDocShell::GetDocument(nsIDOMDocument ** aDocument)
  5050     NS_ENSURE_ARG_POINTER(aDocument);
  5051     NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
  5053     return mContentViewer->GetDOMDocument(aDocument);
  5056 NS_IMETHODIMP
  5057 nsDocShell::GetCurrentURI(nsIURI ** aURI)
  5059     NS_ENSURE_ARG_POINTER(aURI);
  5061     if (mCurrentURI) {
  5062         return NS_EnsureSafeToReturn(mCurrentURI, aURI);
  5065     *aURI = nullptr;
  5066     return NS_OK;
  5069 NS_IMETHODIMP
  5070 nsDocShell::GetReferringURI(nsIURI ** aURI)
  5072     NS_ENSURE_ARG_POINTER(aURI);
  5074     *aURI = mReferrerURI;
  5075     NS_IF_ADDREF(*aURI);
  5077     return NS_OK;
  5080 NS_IMETHODIMP
  5081 nsDocShell::SetSessionHistory(nsISHistory * aSessionHistory)
  5084     NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
  5085     // make sure that we are the root docshell and
  5086     // set a handle to root docshell in SH.
  5088     nsCOMPtr<nsIDocShellTreeItem> root;
  5089     /* Get the root docshell. If *this* is the root docshell
  5090      * then save a handle to *this* in SH. SH needs it to do
  5091      * traversions thro' its entries
  5092      */
  5093     GetSameTypeRootTreeItem(getter_AddRefs(root));
  5094     NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  5095     if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) {
  5096         mSessionHistory = aSessionHistory;
  5097         nsCOMPtr<nsISHistoryInternal>
  5098             shPrivate(do_QueryInterface(mSessionHistory));
  5099         NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
  5100         shPrivate->SetRootDocShell(this);
  5101         return NS_OK;
  5103     return NS_ERROR_FAILURE;
  5108 NS_IMETHODIMP
  5109 nsDocShell::GetSessionHistory(nsISHistory ** aSessionHistory)
  5111     NS_ENSURE_ARG_POINTER(aSessionHistory);
  5112     *aSessionHistory = mSessionHistory;
  5113     NS_IF_ADDREF(*aSessionHistory);
  5114     return NS_OK;
  5117 //*****************************************************************************
  5118 // nsDocShell::nsIWebPageDescriptor
  5119 //*****************************************************************************
  5120 NS_IMETHODIMP
  5121 nsDocShell::LoadPage(nsISupports *aPageDescriptor, uint32_t aDisplayType)
  5123     nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
  5125     // Currently, the opaque 'page descriptor' is an nsISHEntry...
  5126     if (!shEntryIn) {
  5127         return NS_ERROR_INVALID_POINTER;
  5130     // Now clone shEntryIn, since we might end up modifying it later on, and we
  5131     // want a page descriptor to be reusable.
  5132     nsCOMPtr<nsISHEntry> shEntry;
  5133     nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
  5134     NS_ENSURE_SUCCESS(rv, rv);
  5136     // Give our cloned shEntry a new bfcache entry so this load is independent
  5137     // of all other loads.  (This is important, in particular, for bugs 582795
  5138     // and 585298.)
  5139     rv = shEntry->AbandonBFCacheEntry();
  5140     NS_ENSURE_SUCCESS(rv, rv);
  5142     //
  5143     // load the page as view-source
  5144     //
  5145     if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
  5146         nsCOMPtr<nsIURI> oldUri, newUri;
  5147         nsCString spec, newSpec;
  5149         // Create a new view-source URI and replace the original.
  5150         rv = shEntry->GetURI(getter_AddRefs(oldUri));
  5151         if (NS_FAILED(rv))
  5152               return rv;
  5154         oldUri->GetSpec(spec);
  5155         newSpec.AppendLiteral("view-source:");
  5156         newSpec.Append(spec);
  5158         rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
  5159         if (NS_FAILED(rv)) {
  5160             return rv;
  5162         shEntry->SetURI(newUri);
  5165     rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
  5166     return rv;
  5169 NS_IMETHODIMP
  5170 nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor)
  5172     NS_PRECONDITION(aPageDescriptor, "Null out param?");
  5174     *aPageDescriptor = nullptr;
  5176     nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
  5177     if (src) {
  5178         nsCOMPtr<nsISHEntry> dest;
  5180         nsresult rv = src->Clone(getter_AddRefs(dest));
  5181         if (NS_FAILED(rv)) {
  5182             return rv;
  5185         // null out inappropriate cloned attributes...
  5186         dest->SetParent(nullptr);
  5187         dest->SetIsSubFrame(false);
  5189         return CallQueryInterface(dest, aPageDescriptor);
  5192     return NS_ERROR_NOT_AVAILABLE;
  5196 //*****************************************************************************
  5197 // nsDocShell::nsIBaseWindow
  5198 //*****************************************************************************   
  5200 NS_IMETHODIMP
  5201 nsDocShell::InitWindow(nativeWindow parentNativeWindow,
  5202                        nsIWidget * parentWidget, int32_t x, int32_t y,
  5203                        int32_t cx, int32_t cy)
  5205     SetParentWidget(parentWidget);
  5206     SetPositionAndSize(x, y, cx, cy, false);
  5208     return NS_OK;
  5211 NS_IMETHODIMP
  5212 nsDocShell::Create()
  5214     if (mCreated) {
  5215         // We've already been created
  5216         return NS_OK;
  5219     NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
  5220                  "Unexpected item type in docshell");
  5222     NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
  5223     mCreated = true;
  5225     mAllowSubframes =
  5226         Preferences::GetBool("browser.frames.enabled", mAllowSubframes);
  5228     if (gValidateOrigin == 0xffffffff) {
  5229         // Check pref to see if we should prevent frameset spoofing
  5230         gValidateOrigin =
  5231             Preferences::GetBool("browser.frame.validate_origin", true);
  5234     // Should we use XUL error pages instead of alerts if possible?
  5235     mUseErrorPages =
  5236         Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
  5238     if(!gAddedPreferencesVarCache) {
  5239         Preferences::AddBoolVarCache(&sUseErrorPages, 
  5240                                      "browser.xul.error_pages.enabled", 
  5241                                      mUseErrorPages);
  5242         gAddedPreferencesVarCache = true;
  5245     mDeviceSizeIsPageSize =
  5246         Preferences::GetBool("docshell.device_size_is_page_size",
  5247                              mDeviceSizeIsPageSize);
  5249     nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
  5250     if (serv) {
  5251         const char* msg = mItemType == typeContent ?
  5252             NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
  5253         serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
  5256     return NS_OK;
  5259 NS_IMETHODIMP
  5260 nsDocShell::Destroy()
  5262     NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
  5263                  "Unexpected item type in docshell");
  5265     if (!mIsBeingDestroyed) {
  5266         nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
  5267         if (serv) {
  5268             const char* msg = mItemType == typeContent ?
  5269                 NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
  5270             serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
  5274     mIsBeingDestroyed = true;
  5276     // Remove our pref observers
  5277     if (mObserveErrorPages) {
  5278         mObserveErrorPages = false;
  5281     // Make sure to blow away our mLoadingURI just in case.  No loads
  5282     // from inside this pagehide.
  5283     mLoadingURI = nullptr;
  5285     // Fire unload event before we blow anything away.
  5286     (void) FirePageHideNotification(true);
  5288     // Clear pointers to any detached nsEditorData that's lying
  5289     // around in shistory entries. Breaks cycle. See bug 430921.
  5290     if (mOSHE)
  5291       mOSHE->SetEditorData(nullptr);
  5292     if (mLSHE)
  5293       mLSHE->SetEditorData(nullptr);
  5295     // Note: mContentListener can be null if Init() failed and we're being
  5296     // called from the destructor.
  5297     if (mContentListener) {
  5298         mContentListener->DropDocShellreference();
  5299         mContentListener->SetParentContentListener(nullptr);
  5300         // Note that we do NOT set mContentListener to null here; that
  5301         // way if someone tries to do a load in us after this point
  5302         // the nsDSURIContentListener will block it.  All of which
  5303         // means that we should do this before calling Stop(), of
  5304         // course.
  5307     // Stop any URLs that are currently being loaded...
  5308     Stop(nsIWebNavigation::STOP_ALL);
  5310     mEditorData = nullptr;
  5312     mTransferableHookData = nullptr;
  5314     // Save the state of the current document, before destroying the window.
  5315     // This is needed to capture the state of a frameset when the new document
  5316     // causes the frameset to be destroyed...
  5317     PersistLayoutHistoryState();
  5319     // Remove this docshell from its parent's child list
  5320     nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
  5321         do_QueryInterface(GetAsSupports(mParent));
  5322     if (docShellParentAsItem)
  5323         docShellParentAsItem->RemoveChild(this);
  5325     if (mContentViewer) {
  5326         mContentViewer->Close(nullptr);
  5327         mContentViewer->Destroy();
  5328         mContentViewer = nullptr;
  5331     nsDocLoader::Destroy();
  5333     mParentWidget = nullptr;
  5334     mCurrentURI = nullptr;
  5336     if (mScriptGlobal) {
  5337         mScriptGlobal->DetachFromDocShell();
  5338         mScriptGlobal = nullptr;
  5341     if (mSessionHistory) {
  5342         // We want to destroy these content viewers now rather than
  5343         // letting their destruction wait for the session history
  5344         // entries to get garbage collected.  (Bug 488394)
  5345         nsCOMPtr<nsISHistoryInternal> shPrivate =
  5346             do_QueryInterface(mSessionHistory);
  5347         if (shPrivate) {
  5348             shPrivate->EvictAllContentViewers();
  5350         mSessionHistory = nullptr;
  5353     SetTreeOwner(nullptr);
  5355     mOnePermittedSandboxedNavigator = nullptr;
  5357     // required to break ref cycle
  5358     mSecurityUI = nullptr;
  5360     // Cancel any timers that were set for this docshell; this is needed
  5361     // to break the cycle between us and the timers.
  5362     CancelRefreshURITimers();
  5364     if (mInPrivateBrowsing) {
  5365         mInPrivateBrowsing = false;
  5366         if (mAffectPrivateSessionLifetime) {
  5367             DecreasePrivateDocShellCount();
  5371     return NS_OK;
  5374 NS_IMETHODIMP
  5375 nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
  5377     if (mParentWidget) {
  5378         *aScale = mParentWidget->GetDefaultScale().scale;
  5379         return NS_OK;
  5382     nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
  5383     if (ownerWindow) {
  5384         return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
  5387     *aScale = 1.0;
  5388     return NS_OK;
  5391 NS_IMETHODIMP
  5392 nsDocShell::SetPosition(int32_t x, int32_t y)
  5394     mBounds.x = x;
  5395     mBounds.y = y;
  5397     if (mContentViewer)
  5398         NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE);
  5400     return NS_OK;
  5403 NS_IMETHODIMP
  5404 nsDocShell::GetPosition(int32_t * aX, int32_t * aY)
  5406     int32_t dummyHolder;
  5407     return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder);
  5410 NS_IMETHODIMP
  5411 nsDocShell::SetSize(int32_t aCX, int32_t aCY, bool aRepaint)
  5413     int32_t x = 0, y = 0;
  5414     GetPosition(&x, &y);
  5415     return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
  5418 NS_IMETHODIMP
  5419 nsDocShell::GetSize(int32_t * aCX, int32_t * aCY)
  5421     int32_t dummyHolder;
  5422     return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY);
  5425 NS_IMETHODIMP
  5426 nsDocShell::SetPositionAndSize(int32_t x, int32_t y, int32_t cx,
  5427                                int32_t cy, bool fRepaint)
  5429     mBounds.x = x;
  5430     mBounds.y = y;
  5431     mBounds.width = cx;
  5432     mBounds.height = cy;
  5434     // Hold strong ref, since SetBounds can make us null out mContentViewer
  5435     nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
  5436     if (viewer) {
  5437         //XXX Border figured in here or is that handled elsewhere?
  5438         NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE);
  5441     return NS_OK;
  5444 NS_IMETHODIMP
  5445 nsDocShell::GetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx,
  5446                                int32_t * cy)
  5448     if (mParentWidget) {
  5449         // ensure size is up-to-date if window has changed resolution
  5450         nsIntRect r;
  5451         mParentWidget->GetClientBounds(r);
  5452         SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, false);
  5455     // We should really consider just getting this information from
  5456     // our window instead of duplicating the storage and code...
  5457     if (cx || cy) {
  5458         // Caller wants to know our size; make sure to give them up to
  5459         // date information.
  5460         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
  5461         if (doc) {
  5462             doc->FlushPendingNotifications(Flush_Layout);
  5466     DoGetPositionAndSize(x, y, cx, cy);
  5467     return NS_OK;
  5470 void
  5471 nsDocShell::DoGetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx,
  5472                                  int32_t * cy)
  5474     if (x)
  5475         *x = mBounds.x;
  5476     if (y)
  5477         *y = mBounds.y;
  5478     if (cx)
  5479         *cx = mBounds.width;
  5480     if (cy)
  5481         *cy = mBounds.height;
  5484 NS_IMETHODIMP
  5485 nsDocShell::Repaint(bool aForce)
  5487     nsCOMPtr<nsIPresShell> presShell =GetPresShell();
  5488     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
  5490     nsViewManager* viewManager = presShell->GetViewManager();
  5491     NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
  5493     viewManager->InvalidateAllViews();
  5494     return NS_OK;
  5497 NS_IMETHODIMP
  5498 nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
  5500     NS_ENSURE_ARG_POINTER(parentWidget);
  5502     *parentWidget = mParentWidget;
  5503     NS_IF_ADDREF(*parentWidget);
  5505     return NS_OK;
  5508 NS_IMETHODIMP
  5509 nsDocShell::SetParentWidget(nsIWidget * aParentWidget)
  5511     mParentWidget = aParentWidget;
  5513     return NS_OK;
  5516 NS_IMETHODIMP
  5517 nsDocShell::GetParentNativeWindow(nativeWindow * parentNativeWindow)
  5519     NS_ENSURE_ARG_POINTER(parentNativeWindow);
  5521     if (mParentWidget)
  5522         *parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
  5523     else
  5524         *parentNativeWindow = nullptr;
  5526     return NS_OK;
  5529 NS_IMETHODIMP
  5530 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
  5532     return NS_ERROR_NOT_IMPLEMENTED;
  5535 NS_IMETHODIMP
  5536 nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
  5538     // the nativeHandle should be accessed from nsIXULWindow
  5539     return NS_ERROR_NOT_IMPLEMENTED;
  5542 NS_IMETHODIMP
  5543 nsDocShell::GetVisibility(bool * aVisibility)
  5545     NS_ENSURE_ARG_POINTER(aVisibility);
  5547     *aVisibility = false;
  5549     if (!mContentViewer)
  5550         return NS_OK;
  5552     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
  5553     if (!presShell)
  5554         return NS_OK;
  5556     // get the view manager
  5557     nsViewManager* vm = presShell->GetViewManager();
  5558     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
  5560     // get the root view
  5561     nsView *view = vm->GetRootView(); // views are not ref counted
  5562     NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
  5564     // if our root view is hidden, we are not visible
  5565     if (view->GetVisibility() == nsViewVisibility_kHide)
  5566         return NS_OK;
  5568     // otherwise, we must walk up the document and view trees checking
  5569     // for a hidden view, unless we're an off screen browser, which 
  5570     // would make this test meaningless.
  5572     nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
  5573     nsCOMPtr<nsIDocShellTreeItem> parentItem;
  5574     treeItem->GetParent(getter_AddRefs(parentItem));
  5575     while (parentItem) {
  5576         nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem));
  5577         presShell = docShell->GetPresShell();
  5579         nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem);
  5580         nsCOMPtr<nsIPresShell> pPresShell = parentDS->GetPresShell();
  5582         // Null-check for crash in bug 267804
  5583         if (!pPresShell) {
  5584             NS_NOTREACHED("parent docshell has null pres shell");
  5585             return NS_OK;
  5588         nsIContent *shellContent =
  5589             pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument());
  5590         NS_ASSERTION(shellContent, "subshell not in the map");
  5592         nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nullptr;
  5593         bool isDocShellOffScreen = false;
  5594         docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
  5595         if (frame &&
  5596             !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
  5597             !isDocShellOffScreen) {
  5598             return NS_OK;
  5601         treeItem = parentItem;
  5602         treeItem->GetParent(getter_AddRefs(parentItem));
  5605     nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
  5606     if (!treeOwnerAsWin) {
  5607         *aVisibility = true;
  5608         return NS_OK;
  5611     // Check with the tree owner as well to give embedders a chance to
  5612     // expose visibility as well.
  5613     return treeOwnerAsWin->GetVisibility(aVisibility);
  5616 NS_IMETHODIMP
  5617 nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen) 
  5619     mIsOffScreenBrowser = aIsOffScreen;
  5620     return NS_OK;
  5623 NS_IMETHODIMP
  5624 nsDocShell::GetIsOffScreenBrowser(bool *aIsOffScreen) 
  5626     *aIsOffScreen = mIsOffScreenBrowser;
  5627     return NS_OK;
  5630 NS_IMETHODIMP
  5631 nsDocShell::SetIsActive(bool aIsActive)
  5633     // We disallow setting active on chrome docshells.
  5634     if (mItemType == nsIDocShellTreeItem::typeChrome)
  5635           return NS_ERROR_INVALID_ARG;
  5637     // Keep track ourselves.
  5638     mIsActive = aIsActive;
  5640     // Tell the PresShell about it.
  5641     nsCOMPtr<nsIPresShell> pshell = GetPresShell();
  5642     if (pshell)
  5643       pshell->SetIsActive(aIsActive);
  5645     // Tell the window about it
  5646     if (mScriptGlobal) {
  5647         mScriptGlobal->SetIsBackground(!aIsActive);
  5648         if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
  5649             doc->PostVisibilityUpdateEvent();
  5653     // Recursively tell all of our children, but don't tell <iframe mozbrowser>
  5654     // children; they handle their state separately.
  5655     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  5656     while (iter.HasMore()) {
  5657         nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
  5658         if (!docshell) {
  5659             continue;
  5662         if (!docshell->GetIsBrowserOrApp()) {
  5663             docshell->SetIsActive(aIsActive);
  5667     return NS_OK;
  5670 NS_IMETHODIMP
  5671 nsDocShell::GetIsActive(bool *aIsActive)
  5673     *aIsActive = mIsActive;
  5674     return NS_OK;
  5677 NS_IMETHODIMP
  5678 nsDocShell::SetIsAppTab(bool aIsAppTab)
  5680     mIsAppTab = aIsAppTab;
  5681     return NS_OK;
  5684 NS_IMETHODIMP
  5685 nsDocShell::GetIsAppTab(bool *aIsAppTab)
  5687     *aIsAppTab = mIsAppTab;
  5688     return NS_OK;
  5691 NS_IMETHODIMP
  5692 nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags)
  5694     mSandboxFlags = aSandboxFlags;
  5695     return NS_OK;
  5698 NS_IMETHODIMP
  5699 nsDocShell::GetSandboxFlags(uint32_t  *aSandboxFlags)
  5701     *aSandboxFlags = mSandboxFlags;
  5702     return NS_OK;
  5705 NS_IMETHODIMP
  5706 nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
  5708     if (mOnePermittedSandboxedNavigator) {
  5709         NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
  5710         return NS_OK;
  5713     mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
  5714     NS_ASSERTION(mOnePermittedSandboxedNavigator,
  5715              "One Permitted Sandboxed Navigator must support weak references.");
  5717     return NS_OK;
  5720 NS_IMETHODIMP
  5721 nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator)
  5723     NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
  5724     nsCOMPtr<nsIDocShell> permittedNavigator =
  5725         do_QueryReferent(mOnePermittedSandboxedNavigator);
  5726     NS_IF_ADDREF(*aSandboxedNavigator = permittedNavigator);
  5727     return NS_OK;
  5730 NS_IMETHODIMP
  5731 nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)
  5733     mDefaultLoadFlags = aDefaultLoadFlags;
  5735     // Tell the load group to set these flags all requests in the group
  5736     if (mLoadGroup) {
  5737         mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
  5738     } else {
  5739         NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to");
  5742     // Recursively tell all of our children.  We *do not* skip
  5743     // <iframe mozbrowser> children - if someone sticks custom flags in this
  5744     // docShell then they too get the same flags.
  5745     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  5746     while (iter.HasMore()) {
  5747         nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
  5748         if (!docshell) {
  5749             continue;
  5751         docshell->SetDefaultLoadFlags(aDefaultLoadFlags);
  5753     return NS_OK;
  5756 NS_IMETHODIMP
  5757 nsDocShell::GetDefaultLoadFlags(uint32_t *aDefaultLoadFlags)
  5759     *aDefaultLoadFlags = mDefaultLoadFlags;
  5760     return NS_OK;
  5764 NS_IMETHODIMP
  5765 nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
  5767 #ifdef DEBUG
  5768      // if the channel is non-null
  5769      if (aMixedContentChannel) {
  5770        // Get the root docshell.
  5771        nsCOMPtr<nsIDocShellTreeItem> root;
  5772        GetSameTypeRootTreeItem(getter_AddRefs(root));
  5773        NS_WARN_IF_FALSE(
  5774          root.get() == static_cast<nsIDocShellTreeItem *>(this), 
  5775          "Setting mMixedContentChannel on a docshell that is not the root docshell"
  5776        );
  5778 #endif
  5779      mMixedContentChannel = aMixedContentChannel;
  5780      return NS_OK;
  5783 NS_IMETHODIMP
  5784 nsDocShell::GetMixedContentChannel(nsIChannel **aMixedContentChannel)
  5786     NS_ENSURE_ARG_POINTER(aMixedContentChannel);
  5787     NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
  5788     return NS_OK;
  5791 NS_IMETHODIMP
  5792 nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection, bool* aAllowMixedContent, bool* aIsRootDocShell)
  5794   *aRootHasSecureConnection = true;
  5795   *aAllowMixedContent = false;
  5796   *aIsRootDocShell = false;
  5798   nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
  5799   GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
  5800   NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
  5801   *aIsRootDocShell = sameTypeRoot.get() == static_cast<nsIDocShellTreeItem *>(this);
  5803   // now get the document from sameTypeRoot
  5804   nsCOMPtr<nsIDocument> rootDoc = do_GetInterface(sameTypeRoot);
  5805   if (rootDoc) {
  5806     nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
  5808     // For things with system principal (e.g. scratchpad) there is no uri
  5809     // aRootHasSecureConnection should be false.
  5810     nsCOMPtr<nsIURI> rootUri;
  5811     if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
  5812         NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
  5813         NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) {
  5814       *aRootHasSecureConnection = false;
  5817     // Check the root doc's channel against the root docShell's mMixedContentChannel to see
  5818     // if they are the same.  If they are the same, the user has overriden
  5819     // the block.
  5820     nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot);
  5821     nsCOMPtr<nsIChannel> mixedChannel;
  5822     rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
  5823     *aAllowMixedContent = mixedChannel && (mixedChannel == rootDoc->GetChannel());
  5826   return NS_OK;
  5829 NS_IMETHODIMP
  5830 nsDocShell::SetVisibility(bool aVisibility)
  5832     // Show()/Hide() may change mContentViewer.
  5833     nsCOMPtr<nsIContentViewer> cv = mContentViewer;
  5834     if (!cv)
  5835         return NS_OK;
  5836     if (aVisibility) {
  5837         cv->Show();
  5839     else {
  5840         cv->Hide();
  5843     return NS_OK;
  5846 NS_IMETHODIMP
  5847 nsDocShell::GetEnabled(bool *aEnabled)
  5849   NS_ENSURE_ARG_POINTER(aEnabled);
  5850   *aEnabled = true;
  5851   return NS_ERROR_NOT_IMPLEMENTED;
  5854 NS_IMETHODIMP
  5855 nsDocShell::SetEnabled(bool aEnabled)
  5857   return NS_ERROR_NOT_IMPLEMENTED;
  5860 NS_IMETHODIMP
  5861 nsDocShell::SetFocus()
  5863   return NS_OK;
  5866 NS_IMETHODIMP
  5867 nsDocShell::GetMainWidget(nsIWidget ** aMainWidget)
  5869     // We don't create our own widget, so simply return the parent one. 
  5870     return GetParentWidget(aMainWidget);
  5873 NS_IMETHODIMP
  5874 nsDocShell::GetTitle(char16_t ** aTitle)
  5876     NS_ENSURE_ARG_POINTER(aTitle);
  5878     *aTitle = ToNewUnicode(mTitle);
  5879     return NS_OK;
  5882 NS_IMETHODIMP
  5883 nsDocShell::SetTitle(const char16_t * aTitle)
  5885     // Store local title
  5886     mTitle = aTitle;
  5888     nsCOMPtr<nsIDocShellTreeItem> parent;
  5889     GetSameTypeParent(getter_AddRefs(parent));
  5891     // When title is set on the top object it should then be passed to the 
  5892     // tree owner.
  5893     if (!parent) {
  5894         nsCOMPtr<nsIBaseWindow>
  5895             treeOwnerAsWin(do_QueryInterface(mTreeOwner));
  5896         if (treeOwnerAsWin)
  5897             treeOwnerAsWin->SetTitle(aTitle);
  5900     if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE && mUseGlobalHistory &&
  5901         !mInPrivateBrowsing) {
  5902         nsCOMPtr<IHistory> history = services::GetHistoryService();
  5903         if (history) {
  5904             history->SetURITitle(mCurrentURI, mTitle);
  5906         else if (mGlobalHistory) {
  5907             mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
  5911     // Update SessionHistory with the document's title.
  5912     if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
  5913         mLoadType != LOAD_ERROR_PAGE) {
  5915         mOSHE->SetTitle(mTitle);    
  5918     return NS_OK;
  5921 nsresult
  5922 nsDocShell::GetCurScrollPos(int32_t scrollOrientation, int32_t * curPos)
  5924     NS_ENSURE_ARG_POINTER(curPos);
  5926     nsIScrollableFrame* sf = GetRootScrollFrame();
  5927     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
  5929     nsPoint pt = sf->GetScrollPosition();
  5931     switch (scrollOrientation) {
  5932     case ScrollOrientation_X:
  5933         *curPos = pt.x;
  5934         return NS_OK;
  5936     case ScrollOrientation_Y:
  5937         *curPos = pt.y;
  5938         return NS_OK;
  5940     default:
  5941         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
  5945 nsresult
  5946 nsDocShell::SetCurScrollPosEx(int32_t curHorizontalPos, int32_t curVerticalPos)
  5948     nsIScrollableFrame* sf = GetRootScrollFrame();
  5949     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
  5951     sf->ScrollTo(nsPoint(curHorizontalPos, curVerticalPos),
  5952                  nsIScrollableFrame::INSTANT);
  5953     return NS_OK;
  5956 //*****************************************************************************
  5957 // nsDocShell::nsIScrollable
  5958 //*****************************************************************************   
  5960 NS_IMETHODIMP
  5961 nsDocShell::GetDefaultScrollbarPreferences(int32_t scrollOrientation,
  5962                                            int32_t * scrollbarPref)
  5964     NS_ENSURE_ARG_POINTER(scrollbarPref);
  5965     switch (scrollOrientation) {
  5966     case ScrollOrientation_X:
  5967         *scrollbarPref = mDefaultScrollbarPref.x;
  5968         return NS_OK;
  5970     case ScrollOrientation_Y:
  5971         *scrollbarPref = mDefaultScrollbarPref.y;
  5972         return NS_OK;
  5974     default:
  5975         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
  5977     return NS_ERROR_FAILURE;
  5980 NS_IMETHODIMP
  5981 nsDocShell::SetDefaultScrollbarPreferences(int32_t scrollOrientation,
  5982                                            int32_t scrollbarPref)
  5984     switch (scrollOrientation) {
  5985     case ScrollOrientation_X:
  5986         mDefaultScrollbarPref.x = scrollbarPref;
  5987         return NS_OK;
  5989     case ScrollOrientation_Y:
  5990         mDefaultScrollbarPref.y = scrollbarPref;
  5991         return NS_OK;
  5993     default:
  5994         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
  5996     return NS_ERROR_FAILURE;
  5999 NS_IMETHODIMP
  6000 nsDocShell::GetScrollbarVisibility(bool * verticalVisible,
  6001                                    bool * horizontalVisible)
  6003     nsIScrollableFrame* sf = GetRootScrollFrame();
  6004     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
  6006     uint32_t scrollbarVisibility = sf->GetScrollbarVisibility();
  6007     if (verticalVisible)
  6008         *verticalVisible = (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
  6009     if (horizontalVisible)
  6010         *horizontalVisible = (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
  6012     return NS_OK;
  6015 //*****************************************************************************
  6016 // nsDocShell::nsITextScroll
  6017 //*****************************************************************************   
  6019 NS_IMETHODIMP
  6020 nsDocShell::ScrollByLines(int32_t numLines)
  6022     nsIScrollableFrame* sf = GetRootScrollFrame();
  6023     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
  6025     sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
  6026                  nsIScrollableFrame::SMOOTH);
  6027     return NS_OK;
  6030 NS_IMETHODIMP
  6031 nsDocShell::ScrollByPages(int32_t numPages)
  6033     nsIScrollableFrame* sf = GetRootScrollFrame();
  6034     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
  6036     sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
  6037                  nsIScrollableFrame::SMOOTH);
  6038     return NS_OK;
  6041 //*****************************************************************************
  6042 // nsDocShell::nsIRefreshURI
  6043 //*****************************************************************************   
  6045 NS_IMETHODIMP
  6046 nsDocShell::RefreshURI(nsIURI * aURI, int32_t aDelay, bool aRepeat,
  6047                        bool aMetaRefresh)
  6049     NS_ENSURE_ARG(aURI);
  6051     /* Check if Meta refresh/redirects are permitted. Some
  6052      * embedded applications may not want to do this.
  6053      * Must do this before sending out NOTIFY_REFRESH events
  6054      * because listeners may have side effects (e.g. displaying a
  6055      * button to manually trigger the refresh later).
  6056      */
  6057     bool allowRedirects = true;
  6058     GetAllowMetaRedirects(&allowRedirects);
  6059     if (!allowRedirects)
  6060         return NS_OK;
  6062     // If any web progress listeners are listening for NOTIFY_REFRESH events,
  6063     // give them a chance to block this refresh.
  6064     bool sameURI;
  6065     nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
  6066     if (NS_FAILED(rv))
  6067         sameURI = false;
  6068     if (!RefreshAttempted(this, aURI, aDelay, sameURI))
  6069         return NS_OK;
  6071     nsRefreshTimer *refreshTimer = new nsRefreshTimer();
  6072     NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
  6073     uint32_t busyFlags = 0;
  6074     GetBusyFlags(&busyFlags);
  6076     nsCOMPtr<nsISupports> dataRef = refreshTimer;    // Get the ref count to 1
  6078     refreshTimer->mDocShell = this;
  6079     refreshTimer->mURI = aURI;
  6080     refreshTimer->mDelay = aDelay;
  6081     refreshTimer->mRepeat = aRepeat;
  6082     refreshTimer->mMetaRefresh = aMetaRefresh;
  6084     if (!mRefreshURIList) {
  6085         NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
  6086                           NS_ERROR_FAILURE);
  6089     if (busyFlags & BUSY_FLAGS_BUSY) {
  6090         // We are busy loading another page. Don't create the
  6091         // timer right now. Instead queue up the request and trigger the
  6092         // timer in EndPageLoad(). 
  6093         mRefreshURIList->AppendElement(refreshTimer);
  6095     else {
  6096         // There is no page loading going on right now.  Create the
  6097         // timer and fire it right away.
  6098         nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
  6099         NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
  6101         mRefreshURIList->AppendElement(timer);      // owning timer ref
  6102         timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
  6104     return NS_OK;
  6107 nsresult
  6108 nsDocShell::ForceRefreshURIFromTimer(nsIURI * aURI,
  6109                                      int32_t aDelay, 
  6110                                      bool aMetaRefresh,
  6111                                      nsITimer* aTimer)
  6113     NS_PRECONDITION(aTimer, "Must have a timer here");
  6115     // Remove aTimer from mRefreshURIList if needed
  6116     if (mRefreshURIList) {
  6117         uint32_t n = 0;
  6118         mRefreshURIList->Count(&n);
  6120         for (uint32_t i = 0;  i < n; ++i) {
  6121             nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
  6122             if (timer == aTimer) {
  6123                 mRefreshURIList->RemoveElementAt(i);
  6124                 break;
  6129     return ForceRefreshURI(aURI, aDelay, aMetaRefresh);
  6132 NS_IMETHODIMP
  6133 nsDocShell::ForceRefreshURI(nsIURI * aURI,
  6134                             int32_t aDelay, 
  6135                             bool aMetaRefresh)
  6137     NS_ENSURE_ARG(aURI);
  6139     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
  6140     CreateLoadInfo(getter_AddRefs(loadInfo));
  6141     NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
  6143     /* We do need to pass in a referrer, but we don't want it to
  6144      * be sent to the server.
  6145      */
  6146     loadInfo->SetSendReferrer(false);
  6148     /* for most refreshes the current URI is an appropriate
  6149      * internal referrer
  6150      */
  6151     loadInfo->SetReferrer(mCurrentURI);
  6153     /* Don't ever "guess" on which owner to use to avoid picking
  6154      * the current owner.
  6155      */
  6156     loadInfo->SetOwnerIsExplicit(true);
  6158     /* Check if this META refresh causes a redirection
  6159      * to another site. 
  6160      */
  6161     bool equalUri = false;
  6162     nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
  6163     if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
  6164         aDelay <= REFRESH_REDIRECT_TIMER) {
  6166         /* It is a META refresh based redirection within the threshold time
  6167          * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
  6168          * Pass a REPLACE flag to LoadURI().
  6169          */
  6170         loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
  6172         /* for redirects we mimic HTTP, which passes the
  6173          *  original referrer
  6174          */
  6175         nsCOMPtr<nsIURI> internalReferrer;
  6176         GetReferringURI(getter_AddRefs(internalReferrer));
  6177         if (internalReferrer) {
  6178             loadInfo->SetReferrer(internalReferrer);
  6181     else {
  6182         loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
  6185     /*
  6186      * LoadURI(...) will cancel all refresh timers... This causes the
  6187      * Timer and its refreshData instance to be released...
  6188      */
  6189     LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
  6191     return NS_OK;
  6194 nsresult
  6195 nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
  6196                                       nsIPrincipal* aPrincipal,
  6197                                       const nsACString & aHeader)
  6199     // Refresh headers are parsed with the following format in mind
  6200     // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
  6201     // By the time we are here, the following is true:
  6202     // header = "REFRESH"
  6203     // content = "5; URL=http://uri" // note the URL attribute is
  6204     // optional, if it is absent, the currently loaded url is used.
  6205     // Also note that the seconds and URL separator can be either
  6206     // a ';' or a ','. The ',' separator should be illegal but CNN
  6207     // is using it.
  6208     // 
  6209     // We need to handle the following strings, where
  6210     //  - X is a set of digits
  6211     //  - URI is either a relative or absolute URI
  6212     //
  6213     // Note that URI should start with "url=" but we allow omission
  6214     //
  6215     // "" || ";" || "," 
  6216     //  empty string. use the currently loaded URI
  6217     //  and refresh immediately.
  6218     // "X" || "X;" || "X,"
  6219     //  Refresh the currently loaded URI in X seconds.
  6220     // "X; URI" || "X, URI"
  6221     //  Refresh using URI as the destination in X seconds.
  6222     // "URI" || "; URI" || ", URI"
  6223     //  Refresh immediately using URI as the destination.
  6224     // 
  6225     // Currently, anything immediately following the URI, if
  6226     // separated by any char in the set "'\"\t\r\n " will be
  6227     // ignored. So "10; url=go.html ; foo=bar" will work,
  6228     // and so will "10; url='go.html'; foo=bar". However,
  6229     // "10; url=go.html; foo=bar" will result in the uri
  6230     // "go.html;" since ';' and ',' are valid uri characters.
  6231     // 
  6232     // Note that we need to remove any tokens wrapping the URI.
  6233     // These tokens currently include spaces, double and single
  6234     // quotes.
  6236     // when done, seconds is 0 or the given number of seconds
  6237     //            uriAttrib is empty or the URI specified
  6238     MOZ_ASSERT(aPrincipal);
  6240     nsAutoCString uriAttrib;
  6241     int32_t seconds = 0;
  6242     bool specifiesSeconds = false;
  6244     nsACString::const_iterator iter, tokenStart, doneIterating;
  6246     aHeader.BeginReading(iter);
  6247     aHeader.EndReading(doneIterating);
  6249     // skip leading whitespace
  6250     while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
  6251         ++iter;
  6253     tokenStart = iter;
  6255     // skip leading + and -
  6256     if (iter != doneIterating && (*iter == '-' || *iter == '+'))
  6257         ++iter;
  6259     // parse number
  6260     while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
  6261         seconds = seconds * 10 + (*iter - '0');
  6262         specifiesSeconds = true;
  6263         ++iter;
  6266     if (iter != doneIterating) {
  6267         // if we started with a '-', number is negative
  6268         if (*tokenStart == '-')
  6269             seconds = -seconds;
  6271         // skip to next ';' or ','
  6272         nsACString::const_iterator iterAfterDigit = iter;
  6273         while (iter != doneIterating && !(*iter == ';' || *iter == ','))
  6275             if (specifiesSeconds)
  6277                 // Non-whitespace characters here mean that the string is
  6278                 // malformed but tolerate sites that specify a decimal point,
  6279                 // even though meta refresh only works on whole seconds.
  6280                 if (iter == iterAfterDigit &&
  6281                     !nsCRT::IsAsciiSpace(*iter) && *iter != '.')
  6283                     // The characters between the seconds and the next
  6284                     // section are just garbage!
  6285                     //   e.g. content="2a0z+,URL=http://www.mozilla.org/"
  6286                     // Just ignore this redirect.
  6287                     return NS_ERROR_FAILURE;
  6289                 else if (nsCRT::IsAsciiSpace(*iter))
  6291                     // We've had at least one whitespace so tolerate the mistake
  6292                     // and drop through.
  6293                     // e.g. content="10 foo"
  6294                     ++iter;
  6295                     break;
  6298             ++iter;
  6301         // skip any remaining whitespace
  6302         while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
  6303             ++iter;
  6305         // skip ';' or ','
  6306         if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
  6307             ++iter;
  6310         // skip whitespace
  6311         while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
  6312             ++iter;
  6315     // possible start of URI
  6316     tokenStart = iter;
  6318     // skip "url = " to real start of URI
  6319     if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
  6320         ++iter;
  6321         if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
  6322             ++iter;
  6323             if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
  6324                 ++iter;
  6326                 // skip whitespace
  6327                 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
  6328                     ++iter;
  6330                 if (iter != doneIterating && *iter == '=') {
  6331                     ++iter;
  6333                     // skip whitespace
  6334                     while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
  6335                         ++iter;
  6337                     // found real start of URI
  6338                     tokenStart = iter;
  6344     // skip a leading '"' or '\''.
  6346     bool isQuotedURI = false;
  6347     if (tokenStart != doneIterating && (*tokenStart == '"' || *tokenStart == '\''))
  6349         isQuotedURI = true;
  6350         ++tokenStart;
  6353     // set iter to start of URI
  6354     iter = tokenStart;
  6356     // tokenStart here points to the beginning of URI
  6358     // grab the rest of the URI
  6359     while (iter != doneIterating)
  6361         if (isQuotedURI && (*iter == '"' || *iter == '\''))
  6362             break;
  6363         ++iter;
  6366     // move iter one back if the last character is a '"' or '\''
  6367     if (iter != tokenStart && isQuotedURI) {
  6368         --iter;
  6369         if (!(*iter == '"' || *iter == '\''))
  6370             ++iter;
  6373     // URI is whatever's contained from tokenStart to iter.
  6374     // note: if tokenStart == doneIterating, so is iter.
  6376     nsresult rv = NS_OK;
  6378     nsCOMPtr<nsIURI> uri;
  6379     bool specifiesURI = false;
  6380     if (tokenStart == iter) {
  6381         uri = aBaseURI;
  6383     else {
  6384         uriAttrib = Substring(tokenStart, iter);
  6385         // NS_NewURI takes care of any whitespace surrounding the URL
  6386         rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI);
  6387         specifiesURI = true;
  6390     // No URI or seconds were specified
  6391     if (!specifiesSeconds && !specifiesURI)
  6393         // Do nothing because the alternative is to spin around in a refresh
  6394         // loop forever!
  6395         return NS_ERROR_FAILURE;
  6398     if (NS_SUCCEEDED(rv)) {
  6399         nsCOMPtr<nsIScriptSecurityManager>
  6400             securityManager(do_GetService
  6401                             (NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
  6402         if (NS_SUCCEEDED(rv)) {
  6403             rv = securityManager->
  6404                 CheckLoadURIWithPrincipal(aPrincipal, uri,
  6405                                           nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
  6407             if (NS_SUCCEEDED(rv)) {
  6408                 bool isjs = true;
  6409                 rv = NS_URIChainHasFlags(uri,
  6410                   nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
  6411                 NS_ENSURE_SUCCESS(rv, rv);
  6413                 if (isjs) {
  6414                     return NS_ERROR_FAILURE;
  6418             if (NS_SUCCEEDED(rv)) {
  6419                 // Since we can't travel back in time yet, just pretend
  6420                 // negative numbers do nothing at all.
  6421                 if (seconds < 0)
  6422                     return NS_ERROR_FAILURE;
  6424                 rv = RefreshURI(uri, seconds * 1000, false, true);
  6428     return rv;
  6431 NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
  6433     nsresult rv;
  6434     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
  6435     if (NS_SUCCEEDED(rv)) {
  6436         nsAutoCString refreshHeader;
  6437         rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
  6438                                             refreshHeader);
  6440         if (!refreshHeader.IsEmpty()) {
  6441             nsCOMPtr<nsIScriptSecurityManager> secMan =
  6442                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  6443             NS_ENSURE_SUCCESS(rv, rv);
  6445             nsCOMPtr<nsIPrincipal> principal;
  6446             rv = secMan->GetChannelPrincipal(aChannel, getter_AddRefs(principal));
  6447             NS_ENSURE_SUCCESS(rv, rv);
  6449             SetupReferrerFromChannel(aChannel);
  6450             rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader);
  6451             if (NS_SUCCEEDED(rv)) {
  6452                 return NS_REFRESHURI_HEADER_FOUND;
  6456     return rv;
  6459 static void
  6460 DoCancelRefreshURITimers(nsISupportsArray* aTimerList)
  6462     if (!aTimerList)
  6463         return;
  6465     uint32_t n=0;
  6466     aTimerList->Count(&n);
  6468     while (n) {
  6469         nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
  6471         aTimerList->RemoveElementAt(n);    // bye bye owning timer ref
  6473         if (timer)
  6474             timer->Cancel();        
  6478 NS_IMETHODIMP
  6479 nsDocShell::CancelRefreshURITimers()
  6481     DoCancelRefreshURITimers(mRefreshURIList);
  6482     DoCancelRefreshURITimers(mSavedRefreshURIList);
  6483     mRefreshURIList = nullptr;
  6484     mSavedRefreshURIList = nullptr;
  6486     return NS_OK;
  6489 NS_IMETHODIMP
  6490 nsDocShell::GetRefreshPending(bool* _retval)
  6492     if (!mRefreshURIList) {
  6493         *_retval = false;
  6494         return NS_OK;
  6497     uint32_t count;
  6498     nsresult rv = mRefreshURIList->Count(&count);
  6499     if (NS_SUCCEEDED(rv))
  6500         *_retval = (count != 0);
  6501     return rv;
  6504 NS_IMETHODIMP
  6505 nsDocShell::SuspendRefreshURIs()
  6507     if (mRefreshURIList) {
  6508         uint32_t n = 0;
  6509         mRefreshURIList->Count(&n);
  6511         for (uint32_t i = 0;  i < n; ++i) {
  6512             nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
  6513             if (!timer)
  6514                 continue;  // this must be a nsRefreshURI already
  6516             // Replace this timer object with a nsRefreshTimer object.
  6517             nsCOMPtr<nsITimerCallback> callback;
  6518             timer->GetCallback(getter_AddRefs(callback));
  6520             timer->Cancel();
  6522             nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
  6523             NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects");
  6525             mRefreshURIList->ReplaceElementAt(rt, i);
  6529     // Suspend refresh URIs for our child shells as well.
  6530     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  6531     while (iter.HasMore()) {
  6532         nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
  6533         if (shell)
  6534             shell->SuspendRefreshURIs();
  6537     return NS_OK;
  6540 NS_IMETHODIMP
  6541 nsDocShell::ResumeRefreshURIs()
  6543     RefreshURIFromQueue();
  6545     // Resume refresh URIs for our child shells as well.
  6546     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  6547     while (iter.HasMore()) {
  6548         nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
  6549         if (shell)
  6550             shell->ResumeRefreshURIs();
  6553     return NS_OK;
  6556 nsresult
  6557 nsDocShell::RefreshURIFromQueue()
  6559     if (!mRefreshURIList)
  6560         return NS_OK;
  6561     uint32_t n = 0;
  6562     mRefreshURIList->Count(&n);
  6564     while (n) {
  6565         nsCOMPtr<nsISupports> element;
  6566         mRefreshURIList->GetElementAt(--n, getter_AddRefs(element));
  6567         nsCOMPtr<nsITimerCallback> refreshInfo(do_QueryInterface(element));
  6569         if (refreshInfo) {   
  6570             // This is the nsRefreshTimer object, waiting to be
  6571             // setup in a timer object and fired.                         
  6572             // Create the timer and  trigger it.
  6573             uint32_t delay = static_cast<nsRefreshTimer*>(static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
  6574             nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
  6575             if (timer) {    
  6576                 // Replace the nsRefreshTimer element in the queue with
  6577                 // its corresponding timer object, so that in case another
  6578                 // load comes through before the timer can go off, the timer will
  6579                 // get cancelled in CancelRefreshURITimer()
  6580                 mRefreshURIList->ReplaceElementAt(timer, n);
  6581                 timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
  6584     }  // while
  6586     return NS_OK;
  6589 //*****************************************************************************
  6590 // nsDocShell::nsIContentViewerContainer
  6591 //*****************************************************************************   
  6593 NS_IMETHODIMP
  6594 nsDocShell::Embed(nsIContentViewer * aContentViewer,
  6595                   const char *aCommand, nsISupports * aExtraInfo)
  6597     // Save the LayoutHistoryState of the previous document, before
  6598     // setting up new document
  6599     PersistLayoutHistoryState();
  6601     nsresult rv = SetupNewViewer(aContentViewer);
  6603     // If we are loading a wyciwyg url from history, change the base URI for 
  6604     // the document to the original http url that created the document.write().
  6605     // This makes sure that all relative urls in a document.written page loaded
  6606     // via history work properly.
  6607     if (mCurrentURI &&
  6608        (mLoadType & LOAD_CMD_HISTORY ||
  6609         mLoadType == LOAD_RELOAD_NORMAL ||
  6610         mLoadType == LOAD_RELOAD_CHARSET_CHANGE)){
  6611         bool isWyciwyg = false;
  6612         // Check if the url is wyciwyg
  6613         rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);      
  6614         if (isWyciwyg && NS_SUCCEEDED(rv))
  6615             SetBaseUrlForWyciwyg(aContentViewer);
  6617     // XXX What if SetupNewViewer fails?
  6618     if (mLSHE) {
  6619         // Restore the editing state, if it's stored in session history.
  6620         if (mLSHE->HasDetachedEditor()) {
  6621             ReattachEditorToWindow(mLSHE);
  6623         // Set history.state
  6624         SetDocCurrentStateObj(mLSHE);
  6626         SetHistoryEntry(&mOSHE, mLSHE);
  6629     bool updateHistory = true;
  6631     // Determine if this type of load should update history
  6632     switch (mLoadType) {
  6633     case LOAD_NORMAL_REPLACE:
  6634     case LOAD_STOP_CONTENT_AND_REPLACE:
  6635     case LOAD_RELOAD_BYPASS_CACHE:
  6636     case LOAD_RELOAD_BYPASS_PROXY:
  6637     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
  6638     case LOAD_REPLACE_BYPASS_CACHE:
  6639         updateHistory = false;
  6640         break;
  6641     default:
  6642         break;
  6645     if (!updateHistory)
  6646         SetLayoutHistoryState(nullptr);
  6648     return NS_OK;
  6651 /* void setIsPrinting (in boolean aIsPrinting); */
  6652 NS_IMETHODIMP 
  6653 nsDocShell::SetIsPrinting(bool aIsPrinting)
  6655     mIsPrintingOrPP = aIsPrinting;
  6656     return NS_OK;
  6659 //*****************************************************************************
  6660 // nsDocShell::nsIWebProgressListener
  6661 //*****************************************************************************   
  6663 NS_IMETHODIMP
  6664 nsDocShell::OnProgressChange(nsIWebProgress * aProgress,
  6665                              nsIRequest * aRequest,
  6666                              int32_t aCurSelfProgress,
  6667                              int32_t aMaxSelfProgress,
  6668                              int32_t aCurTotalProgress,
  6669                              int32_t aMaxTotalProgress)
  6671     return NS_OK;
  6674 NS_IMETHODIMP
  6675 nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
  6676                           uint32_t aStateFlags, nsresult aStatus)
  6678     if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
  6679         // Save timing statistics.
  6680         nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  6681         nsCOMPtr<nsIURI> uri;
  6682         channel->GetURI(getter_AddRefs(uri));
  6683         nsAutoCString aURI;
  6684         uri->GetAsciiSpec(aURI);
  6686         nsCOMPtr<nsIWyciwygChannel>  wcwgChannel(do_QueryInterface(aRequest));
  6687         nsCOMPtr<nsIWebProgress> webProgress =
  6688             do_QueryInterface(GetAsSupports(this));
  6690         // We don't update navigation timing for wyciwyg channels
  6691         if (this == aProgress && !wcwgChannel){
  6692             MaybeInitTiming();
  6693             mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType));
  6696         // Was the wyciwyg document loaded on this docshell?
  6697         if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
  6698             bool equalUri = true;
  6699             // Store the wyciwyg url in session history, only if it is
  6700             // being loaded fresh for the first time. We don't want 
  6701             // multiple entries for successive loads
  6702             if (mCurrentURI &&
  6703                 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
  6704                 !equalUri) {
  6706                 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
  6707                 GetSameTypeParent(getter_AddRefs(parentAsItem));
  6708                 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
  6709                 bool inOnLoadHandler = false;
  6710                 if (parentDS) {
  6711                   parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
  6713                 if (inOnLoadHandler) {
  6714                     // We're handling parent's load event listener, which causes
  6715                     // document.write in a subdocument.
  6716                     // Need to clear the session history for all child
  6717                     // docshells so that we can handle them like they would
  6718                     // all be added dynamically.
  6719                     nsCOMPtr<nsIDocShell> parent =
  6720                         do_QueryInterface(parentAsItem);
  6721                     if (parent) {
  6722                         bool oshe = false;
  6723                         nsCOMPtr<nsISHEntry> entry;
  6724                         parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
  6725                         static_cast<nsDocShell*>(parent.get())->
  6726                             ClearFrameHistory(entry);
  6730                 // This is a document.write(). Get the made-up url
  6731                 // from the channel and store it in session history.
  6732                 // Pass false for aCloneChildren, since we're creating
  6733                 // a new DOM here.
  6734                 AddToSessionHistory(uri, wcwgChannel, nullptr, false,
  6735                                     getter_AddRefs(mLSHE));
  6736                 SetCurrentURI(uri, aRequest, true, 0);
  6737                 // Save history state of the previous page
  6738                 PersistLayoutHistoryState();
  6739                 // We'll never get an Embed() for this load, so just go ahead
  6740                 // and SetHistoryEntry now.
  6741                 SetHistoryEntry(&mOSHE, mLSHE);
  6745         // Page has begun to load
  6746         mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
  6748         if ((aStateFlags & STATE_RESTORING) == 0) {
  6749             // Show the progress cursor if the pref is set
  6750             if (Preferences::GetBool("ui.use_activity_cursor", false)) {
  6751                 nsCOMPtr<nsIWidget> mainWidget;
  6752                 GetMainWidget(getter_AddRefs(mainWidget));
  6753                 if (mainWidget) {
  6754                     mainWidget->SetCursor(eCursor_spinning);
  6759     else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
  6760         // Page is loading
  6761         mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
  6763     else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
  6764         // Page has finished loading
  6765         mBusyFlags = BUSY_FLAGS_NONE;
  6767         // Hide the progress cursor if the pref is set
  6768         if (Preferences::GetBool("ui.use_activity_cursor", false)) {
  6769             nsCOMPtr<nsIWidget> mainWidget;
  6770             GetMainWidget(getter_AddRefs(mainWidget));
  6771             if (mainWidget) {
  6772                 mainWidget->SetCursor(eCursor_standard);
  6776     if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
  6777         nsCOMPtr<nsIWebProgress> webProgress =
  6778             do_QueryInterface(GetAsSupports(this));
  6779         // Is the document stop notification for this document?
  6780         if (aProgress == webProgress.get()) {
  6781             nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  6782             EndPageLoad(aProgress, channel, aStatus);
  6785     // note that redirect state changes will go through here as well, but it
  6786     // is better to handle those in OnRedirectStateChange where more
  6787     // information is available.
  6788     return NS_OK;
  6791 NS_IMETHODIMP
  6792 nsDocShell::OnLocationChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
  6793                              nsIURI * aURI, uint32_t aFlags)
  6795     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  6796     return NS_OK;
  6799 void
  6800 nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
  6801                                   nsIChannel* aNewChannel,
  6802                                   uint32_t aRedirectFlags,
  6803                                   uint32_t aStateFlags)
  6805     NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
  6806                  "Calling OnRedirectStateChange when there is no redirect");
  6807     if (!(aStateFlags & STATE_IS_DOCUMENT))
  6808         return; // not a toplevel document
  6810     nsCOMPtr<nsIURI> oldURI, newURI;
  6811     aOldChannel->GetURI(getter_AddRefs(oldURI));
  6812     aNewChannel->GetURI(getter_AddRefs(newURI));
  6813     if (!oldURI || !newURI) {
  6814         return;
  6817     // Check if we have a redirect registered for this url.
  6818     uint32_t appId;
  6819     nsresult rv = GetAppId(&appId);
  6820     if (NS_FAILED(rv)) {
  6821       return;
  6824     if (appId != nsIScriptSecurityManager::NO_APP_ID &&
  6825         appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
  6826       nsCOMPtr<nsIAppsService> appsService =
  6827         do_GetService(APPS_SERVICE_CONTRACTID);
  6828       NS_ASSERTION(appsService, "No AppsService available");
  6829       nsCOMPtr<nsIURI> redirect;
  6830       rv = appsService->GetRedirect(appId, newURI, getter_AddRefs(redirect));
  6831       if (NS_SUCCEEDED(rv) && redirect) {
  6832         aNewChannel->Cancel(NS_BINDING_ABORTED);
  6833         rv = LoadURI(redirect, nullptr, 0, false);
  6834         if (NS_SUCCEEDED(rv)) {
  6835           return;
  6840     // Below a URI visit is saved (see AddURIVisit method doc).
  6841     // The visit chain looks something like:
  6842     //   ...
  6843     //   Site N - 1
  6844     //                =>  Site N
  6845     //   (redirect to =>) Site N + 1 (we are here!)
  6847     // Get N - 1 and transition type
  6848     nsCOMPtr<nsIURI> previousURI;
  6849     uint32_t previousFlags = 0;
  6850     ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
  6852     if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
  6853         ChannelIsPost(aOldChannel)) {
  6854         // 1. Internal redirects are ignored because they are specific to the
  6855         //    channel implementation.
  6856         // 2. POSTs are not saved by global history.
  6857         //
  6858         // Regardless, we need to propagate the previous visit to the new
  6859         // channel.
  6860         SaveLastVisit(aNewChannel, previousURI, previousFlags);
  6862     else {
  6863         nsCOMPtr<nsIURI> referrer;
  6864         // Treat referrer as null if there is an error getting it.
  6865         (void)NS_GetReferrerFromChannel(aOldChannel,
  6866                                         getter_AddRefs(referrer));
  6868         // Get the HTTP response code, if available.
  6869         uint32_t responseStatus = 0;
  6870         nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
  6871         if (httpChannel) {
  6872             (void)httpChannel->GetResponseStatus(&responseStatus);
  6875         // Add visit N -1 => N
  6876         AddURIVisit(oldURI, referrer, previousURI, previousFlags,
  6877                     responseStatus);
  6879         // Since N + 1 could be the final destination, we will not save N => N + 1
  6880         // here.  OnNewURI will do that, so we will cache it.
  6881         SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
  6884     // check if the new load should go through the application cache.
  6885     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
  6886         do_QueryInterface(aNewChannel);
  6887     if (appCacheChannel) {
  6888         if (GeckoProcessType_Default != XRE_GetProcessType()) {
  6889             // Permission will be checked in the parent process.
  6890             appCacheChannel->SetChooseApplicationCache(true);
  6891         } else {
  6892             nsCOMPtr<nsIScriptSecurityManager> secMan =
  6893                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
  6895             if (secMan) {
  6896                 nsCOMPtr<nsIPrincipal> principal;
  6897                 secMan->GetDocShellCodebasePrincipal(newURI, this, getter_AddRefs(principal));
  6898                 appCacheChannel->SetChooseApplicationCache(NS_ShouldCheckAppCache(principal,
  6899                     mInPrivateBrowsing));
  6904     if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && 
  6905         mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
  6906         mLoadType = LOAD_NORMAL_REPLACE;
  6907         SetHistoryEntry(&mLSHE, nullptr);
  6911 NS_IMETHODIMP
  6912 nsDocShell::OnStatusChange(nsIWebProgress * aWebProgress,
  6913                            nsIRequest * aRequest,
  6914                            nsresult aStatus, const char16_t * aMessage)
  6916     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  6917     return NS_OK;
  6920 NS_IMETHODIMP
  6921 nsDocShell::OnSecurityChange(nsIWebProgress * aWebProgress,
  6922                              nsIRequest * aRequest, uint32_t state)
  6924     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
  6925     return NS_OK;
  6929 nsresult
  6930 nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
  6931                         nsIChannel * aChannel, nsresult aStatus)
  6933     if(!aChannel)
  6934         return NS_ERROR_NULL_POINTER;
  6936     MOZ_EVENT_TRACER_DONE(this, "docshell::pageload");
  6938     nsCOMPtr<nsIURI> url;
  6939     nsresult rv = aChannel->GetURI(getter_AddRefs(url));
  6940     if (NS_FAILED(rv)) return rv;
  6942     nsCOMPtr<nsITimedChannel> timingChannel =
  6943         do_QueryInterface(aChannel);
  6944     if (timingChannel) {
  6945         TimeStamp channelCreationTime;
  6946         rv = timingChannel->GetChannelCreation(&channelCreationTime);
  6947         if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
  6948             Telemetry::AccumulateTimeDelta(
  6949                 Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
  6950                 channelCreationTime);
  6951             nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup =
  6952                 do_QueryInterface(mLoadGroup);
  6953             if (internalLoadGroup)
  6954                 internalLoadGroup->OnEndPageLoad(aChannel);
  6958     // Timing is picked up by the window, we don't need it anymore
  6959     mTiming = nullptr;
  6961     // clean up reload state for meta charset
  6962     if (eCharsetReloadRequested == mCharsetReloadState)
  6963         mCharsetReloadState = eCharsetReloadStopOrigional;
  6964     else 
  6965         mCharsetReloadState = eCharsetReloadInit;
  6967     // Save a pointer to the currently-loading history entry.
  6968     // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
  6969     // entry further down in this method.
  6970     nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
  6972     //
  6973     // one of many safeguards that prevent death and destruction if
  6974     // someone is so very very rude as to bring this window down
  6975     // during this load handler.
  6976     //
  6977     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
  6979     // Notify the ContentViewer that the Document has finished loading.  This
  6980     // will cause any OnLoad(...) and PopState(...) handlers to fire.
  6981     if (!mEODForCurrentDocument && mContentViewer) {
  6982         mIsExecutingOnLoadHandler = true;
  6983         mContentViewer->LoadComplete(aStatus);
  6984         mIsExecutingOnLoadHandler = false;
  6986         mEODForCurrentDocument = true;
  6988         // If all documents have completed their loading
  6989         // favor native event dispatch priorities
  6990         // over performance
  6991         if (--gNumberOfDocumentsLoading == 0) {
  6992           // Hint to use normal native event dispatch priorities 
  6993           FavorPerformanceHint(false);
  6996     /* Check if the httpChannel has any cache-control related response headers,
  6997      * like no-store, no-cache. If so, update SHEntry so that 
  6998      * when a user goes back/forward to this page, we appropriately do 
  6999      * form value restoration or load from server.
  7000      */
  7001     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
  7002     if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel.    
  7003         GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
  7005     if (httpChannel) {
  7006         // figure out if SH should be saving layout state.
  7007         bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);       
  7008         if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
  7009             (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE))
  7010             mLSHE->SetSaveLayoutStateFlag(false);            
  7013     // Clear mLSHE after calling the onLoadHandlers. This way, if the
  7014     // onLoadHandler tries to load something different in
  7015     // itself or one of its children, we can deal with it appropriately.
  7016     if (mLSHE) {
  7017         mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
  7019         // Clear the mLSHE reference to indicate document loading is done one
  7020         // way or another.
  7021         SetHistoryEntry(&mLSHE, nullptr);
  7023     // if there's a refresh header in the channel, this method
  7024     // will set it up for us. 
  7025     RefreshURIFromQueue();
  7027     // Test whether this is the top frame or a subframe
  7028     bool isTopFrame = true;
  7029     nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
  7030     rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
  7031     if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
  7032         isTopFrame = false;
  7035     //
  7036     // If the page load failed, then deal with the error condition...
  7037     // Errors are handled as follows:
  7038     //   1. Check to see if it's a file not found error or bad content
  7039     //      encoding error.
  7040     //   2. Send the URI to a keyword server (if enabled)
  7041     //   3. If the error was DNS failure, then add www and .com to the URI
  7042     //      (if appropriate).
  7043     //   4. Throw an error dialog box...
  7044     //
  7045     if (url && NS_FAILED(aStatus)) {
  7046         if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
  7047             aStatus == NS_ERROR_CORRUPTED_CONTENT ||
  7048             aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
  7049             DisplayLoadError(aStatus, url, nullptr, aChannel);
  7050             return NS_OK;
  7053         if (sURIFixup) {
  7054             //
  7055             // Try and make an alternative URI from the old one
  7056             //
  7057             nsCOMPtr<nsIURI> newURI;
  7058             nsCOMPtr<nsIInputStream> newPostData;
  7060             nsAutoCString oldSpec;
  7061             url->GetSpec(oldSpec);
  7063             //
  7064             // First try keyword fixup
  7065             //
  7066             if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
  7067                 bool keywordsEnabled =
  7068                     Preferences::GetBool("keyword.enabled", false);
  7070                 nsAutoCString host;
  7071                 url->GetHost(host);
  7073                 nsAutoCString scheme;
  7074                 url->GetScheme(scheme);
  7076                 int32_t dotLoc = host.FindChar('.');
  7078                 // we should only perform a keyword search under the following
  7079                 // conditions:
  7080                 // (0) Pref keyword.enabled is true
  7081                 // (1) the url scheme is http (or https)
  7082                 // (2) the url does not have a protocol scheme
  7083                 // If we don't enforce such a policy, then we end up doing
  7084                 // keyword searchs on urls we don't intend like imap, file,
  7085                 // mailbox, etc. This could lead to a security problem where we
  7086                 // send data to the keyword server that we shouldn't be.
  7087                 // Someone needs to clean up keywords in general so we can
  7088                 // determine on a per url basis if we want keywords
  7089                 // enabled...this is just a bandaid...
  7090                 if (keywordsEnabled && !scheme.IsEmpty() &&
  7091                     (scheme.Find("http") != 0)) {
  7092                     keywordsEnabled = false;
  7095                 if (keywordsEnabled && (kNotFound == dotLoc)) {
  7096                     // only send non-qualified hosts to the keyword server
  7097                     if (!mOriginalUriString.IsEmpty()) {
  7098                         sURIFixup->KeywordToURI(mOriginalUriString,
  7099                                                 getter_AddRefs(newPostData),
  7100                                                 getter_AddRefs(newURI));
  7102                     else {
  7103                         //
  7104                         // If this string was passed through nsStandardURL by
  7105                         // chance, then it may have been converted from UTF-8 to
  7106                         // ACE, which would result in a completely bogus keyword
  7107                         // query.  Here we try to recover the original Unicode
  7108                         // value, but this is not 100% correct since the value may
  7109                         // have been normalized per the IDN normalization rules.
  7110                         //
  7111                         // Since we don't have access to the exact original string
  7112                         // that was entered by the user, this will just have to do.
  7113                         bool isACE;
  7114                         nsAutoCString utf8Host;
  7115                         nsCOMPtr<nsIIDNService> idnSrv =
  7116                             do_GetService(NS_IDNSERVICE_CONTRACTID);
  7117                         if (idnSrv &&
  7118                             NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
  7119                             NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
  7120                             sURIFixup->KeywordToURI(utf8Host,
  7121                                                     getter_AddRefs(newPostData),
  7122                                                     getter_AddRefs(newURI));
  7123                         } else {
  7124                             sURIFixup->KeywordToURI(host,
  7125                                                     getter_AddRefs(newPostData),
  7126                                                     getter_AddRefs(newURI));
  7129                 } // end keywordsEnabled
  7132             //
  7133             // Now try change the address, e.g. turn http://foo into
  7134             // http://www.foo.com
  7135             //
  7136             if (aStatus == NS_ERROR_UNKNOWN_HOST ||
  7137                 aStatus == NS_ERROR_NET_RESET) {
  7138                 bool doCreateAlternate = true;
  7140                 // Skip fixup for anything except a normal document load
  7141                 // operation on the topframe.
  7143                 if (mLoadType != LOAD_NORMAL || !isTopFrame) {
  7144                     doCreateAlternate = false;
  7146                 else {
  7147                     // Test if keyword lookup produced a new URI or not
  7148                     if (newURI) {
  7149                         bool sameURI = false;
  7150                         url->Equals(newURI, &sameURI);
  7151                         if (!sameURI) {
  7152                             // Keyword lookup made a new URI so no need to try
  7153                             // an alternate one.
  7154                             doCreateAlternate = false;
  7158                 if (doCreateAlternate) {
  7159                     newURI = nullptr;
  7160                     newPostData = nullptr;
  7161                     sURIFixup->CreateFixupURI(oldSpec,
  7162                       nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
  7163                                               getter_AddRefs(newPostData),
  7164                                               getter_AddRefs(newURI));
  7168             // Did we make a new URI that is different to the old one? If so
  7169             // load it.
  7170             //
  7171             if (newURI) {
  7172                 // Make sure the new URI is different from the old one,
  7173                 // otherwise there's little point trying to load it again.
  7174                 bool sameURI = false;
  7175                 url->Equals(newURI, &sameURI);
  7176                 if (!sameURI) {
  7177                     nsAutoCString newSpec;
  7178                     newURI->GetSpec(newSpec);
  7179                     NS_ConvertUTF8toUTF16 newSpecW(newSpec);
  7181                     return LoadURI(newSpecW.get(),  // URI string
  7182                                    LOAD_FLAGS_NONE, // Load flags
  7183                                    nullptr,          // Referring URI
  7184                                    newPostData,      // Post data stream
  7185                                    nullptr);         // Headers stream
  7190         // Well, fixup didn't work :-(
  7191         // It is time to throw an error dialog box, and be done with it...
  7193         // Errors to be shown only on top-level frames
  7194         if ((aStatus == NS_ERROR_UNKNOWN_HOST || 
  7195              aStatus == NS_ERROR_CONNECTION_REFUSED ||
  7196              aStatus == NS_ERROR_UNKNOWN_PROXY_HOST || 
  7197              aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
  7198             (isTopFrame || UseErrorPages())) {
  7199             DisplayLoadError(aStatus, url, nullptr, aChannel);
  7201         // Errors to be shown for any frame
  7202         else if (aStatus == NS_ERROR_NET_TIMEOUT ||
  7203                  aStatus == NS_ERROR_REDIRECT_LOOP ||
  7204                  aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
  7205                  aStatus == NS_ERROR_NET_INTERRUPT ||
  7206                  aStatus == NS_ERROR_NET_RESET ||
  7207                  aStatus == NS_ERROR_OFFLINE ||
  7208                  aStatus == NS_ERROR_MALWARE_URI ||
  7209                  aStatus == NS_ERROR_PHISHING_URI ||
  7210                  aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
  7211                  aStatus == NS_ERROR_REMOTE_XUL ||
  7212                  aStatus == NS_ERROR_OFFLINE ||
  7213                  NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
  7214             DisplayLoadError(aStatus, url, nullptr, aChannel);
  7216         else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
  7217             // Non-caching channels will simply return NS_ERROR_OFFLINE.
  7218             // Caching channels would have to look at their flags to work
  7219             // out which error to return. Or we can fix up the error here.
  7220             if (!(mLoadType & LOAD_CMD_HISTORY))
  7221                 aStatus = NS_ERROR_OFFLINE;
  7222             DisplayLoadError(aStatus, url, nullptr, aChannel);
  7224     } // if we have a host
  7225     else if (url && NS_SUCCEEDED(aStatus)) {
  7226         mozilla::net::SeerLearnRedirect(url, aChannel, this);
  7229     return NS_OK;
  7233 //*****************************************************************************
  7234 // nsDocShell: Content Viewer Management
  7235 //*****************************************************************************   
  7237 NS_IMETHODIMP
  7238 nsDocShell::EnsureContentViewer()
  7240     if (mContentViewer)
  7241         return NS_OK;
  7242     if (mIsBeingDestroyed)
  7243         return NS_ERROR_FAILURE;
  7245     nsCOMPtr<nsIURI> baseURI;
  7246     nsIPrincipal* principal = GetInheritedPrincipal(false);
  7247     nsCOMPtr<nsIDocShellTreeItem> parentItem;
  7248     GetSameTypeParent(getter_AddRefs(parentItem));
  7249     if (parentItem) {
  7250         nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
  7251         if (domWin) {
  7252             nsCOMPtr<nsIContent> parentContent =
  7253                 do_QueryInterface(domWin->GetFrameElementInternal());
  7254             if (parentContent) {
  7255                 baseURI = parentContent->GetBaseURI();
  7260     nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
  7262     if (NS_SUCCEEDED(rv)) {
  7263         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
  7264         NS_ASSERTION(doc,
  7265                      "Should have doc if CreateAboutBlankContentViewer "
  7266                      "succeeded!");
  7268         doc->SetIsInitialDocument(true);
  7271     return rv;
  7274 nsresult
  7275 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
  7276                                           nsIURI* aBaseURI,
  7277                                           bool aTryToSaveOldPresentation)
  7279   nsCOMPtr<nsIDocument> blankDoc;
  7280   nsCOMPtr<nsIContentViewer> viewer;
  7281   nsresult rv = NS_ERROR_FAILURE;
  7283   /* mCreatingDocument should never be true at this point. However, it's
  7284      a theoretical possibility. We want to know about it and make it stop,
  7285      and this sounds like a job for an assertion. */
  7286   NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted");
  7287   if (mCreatingDocument)
  7288     return NS_ERROR_FAILURE;
  7290   mCreatingDocument = true;
  7292   // mContentViewer->PermitUnload may release |this| docshell.
  7293   nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
  7295   // Make sure timing is created.  But first record whether we had it
  7296   // already, so we don't clobber the timing for an in-progress load.
  7297   bool hadTiming = mTiming;
  7298   MaybeInitTiming();
  7299   if (mContentViewer) {
  7300     // We've got a content viewer already. Make sure the user
  7301     // permits us to discard the current document and replace it
  7302     // with about:blank. And also ensure we fire the unload events
  7303     // in the current document.
  7305     // Unload gets fired first for
  7306     // document loaded from the session history.
  7307     mTiming->NotifyBeforeUnload();
  7309     bool okToUnload;
  7310     rv = mContentViewer->PermitUnload(false, &okToUnload);
  7312     if (NS_SUCCEEDED(rv) && !okToUnload) {
  7313       // The user chose not to unload the page, interrupt the load.
  7314       return NS_ERROR_FAILURE;
  7317     mSavingOldViewer = aTryToSaveOldPresentation && 
  7318                        CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
  7320     if (mTiming) {
  7321       mTiming->NotifyUnloadAccepted(mCurrentURI);
  7324     // Make sure to blow away our mLoadingURI just in case.  No loads
  7325     // from inside this pagehide.
  7326     mLoadingURI = nullptr;
  7328     // Stop any in-progress loading, so that we don't accidentally trigger any
  7329     // PageShow notifications from Embed() interrupting our loading below.
  7330     Stop();
  7332     // Notify the current document that it is about to be unloaded!!
  7333     //
  7334     // It is important to fire the unload() notification *before* any state
  7335     // is changed within the DocShell - otherwise, javascript will get the
  7336     // wrong information :-(
  7337     //
  7338     (void) FirePageHideNotification(!mSavingOldViewer);
  7341   // Now make sure we don't think we're in the middle of firing unload after
  7342   // this point.  This will make us fire unload when the about:blank document
  7343   // unloads... but that's ok, more or less.  Would be nice if it fired load
  7344   // too, of course.
  7345   mFiredUnloadEvent = false;
  7347   nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
  7348       nsContentUtils::FindInternalContentViewer("text/html");
  7350   if (docFactory) {
  7351     nsCOMPtr<nsIPrincipal> principal;
  7352     if (mSandboxFlags & SANDBOXED_ORIGIN) {
  7353       principal = do_CreateInstance("@mozilla.org/nullprincipal;1");
  7354     } else {
  7355       principal = aPrincipal;
  7357     // generate (about:blank) document to load
  7358     docFactory->CreateBlankDocument(mLoadGroup, principal,
  7359                                     getter_AddRefs(blankDoc));
  7360     if (blankDoc) {
  7361       // Hack: set the base URI manually, since this document never
  7362       // got Reset() with a channel.
  7363       blankDoc->SetBaseURI(aBaseURI);
  7365       blankDoc->SetContainer(this);
  7367       // Copy our sandbox flags to the document. These are immutable
  7368       // after being set here.
  7369       blankDoc->SetSandboxFlags(mSandboxFlags);
  7371       // create a content viewer for us and the new document
  7372       docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
  7373                     blankDoc, "view", getter_AddRefs(viewer));
  7375       // hook 'em up
  7376       if (viewer) {
  7377         viewer->SetContainer(this);
  7378         Embed(viewer, "", 0);
  7380         SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
  7381         rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
  7385   mCreatingDocument = false;
  7387   // The transient about:blank viewer doesn't have a session history entry.
  7388   SetHistoryEntry(&mOSHE, nullptr);
  7390   // Clear out our mTiming like we would in EndPageLoad, if we didn't
  7391   // have one before entering this function.
  7392   if (!hadTiming) {
  7393     mTiming = nullptr;
  7396   return rv;
  7399 NS_IMETHODIMP
  7400 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal)
  7402     return CreateAboutBlankContentViewer(aPrincipal, nullptr);
  7405 bool
  7406 nsDocShell::CanSavePresentation(uint32_t aLoadType,
  7407                                 nsIRequest *aNewRequest,
  7408                                 nsIDocument *aNewDocument)
  7410     if (!mOSHE)
  7411         return false; // no entry to save into
  7413     nsCOMPtr<nsIContentViewer> viewer;
  7414     mOSHE->GetContentViewer(getter_AddRefs(viewer));
  7415     if (viewer) {
  7416         NS_WARNING("mOSHE already has a content viewer!");
  7417         return false;
  7420     // Only save presentation for "normal" loads and link loads.  Anything else
  7421     // probably wants to refetch the page, so caching the old presentation
  7422     // would be incorrect.
  7423     if (aLoadType != LOAD_NORMAL &&
  7424         aLoadType != LOAD_HISTORY &&
  7425         aLoadType != LOAD_LINK &&
  7426         aLoadType != LOAD_STOP_CONTENT &&
  7427         aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
  7428         aLoadType != LOAD_ERROR_PAGE)
  7429         return false;
  7431     // If the session history entry has the saveLayoutState flag set to false,
  7432     // then we should not cache the presentation.
  7433     bool canSaveState;
  7434     mOSHE->GetSaveLayoutStateFlag(&canSaveState);
  7435     if (!canSaveState)
  7436         return false;
  7438     // If the document is not done loading, don't cache it.
  7439     if (!mScriptGlobal || mScriptGlobal->IsLoading())
  7440         return false;
  7442     if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument))
  7443         return false;
  7445     // Avoid doing the work of saving the presentation state in the case where
  7446     // the content viewer cache is disabled.
  7447     if (nsSHistory::GetMaxTotalViewers() == 0)
  7448         return false;
  7450     // Don't cache the content viewer if we're in a subframe and the subframe
  7451     // pref is disabled.
  7452     bool cacheFrames =
  7453         Preferences::GetBool("browser.sessionhistory.cache_subframes",
  7454                              false);
  7455     if (!cacheFrames) {
  7456         nsCOMPtr<nsIDocShellTreeItem> root;
  7457         GetSameTypeParent(getter_AddRefs(root));
  7458         if (root && root != this) {
  7459             return false;  // this is a subframe load
  7463     // If the document does not want its presentation cached, then don't.
  7464     nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
  7465     return doc && doc->CanSavePresentation(aNewRequest);
  7468 void
  7469 nsDocShell::ReattachEditorToWindow(nsISHEntry *aSHEntry)
  7471     NS_ASSERTION(!mEditorData,
  7472                  "Why reattach an editor when we already have one?");
  7473     NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
  7474                  "Reattaching when there's not a detached editor.");
  7476     if (mEditorData || !aSHEntry)
  7477         return;
  7479     mEditorData = aSHEntry->ForgetEditorData();
  7480     if (mEditorData) {
  7481 #ifdef DEBUG
  7482         nsresult rv =
  7483 #endif
  7484         mEditorData->ReattachToWindow(this);
  7485         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
  7489 void
  7490 nsDocShell::DetachEditorFromWindow()
  7492     if (!mEditorData || mEditorData->WaitingForLoad()) {
  7493         // If there's nothing to detach, or if the editor data is actually set
  7494         // up for the _new_ page that's coming in, don't detach.
  7495         return;
  7498     NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
  7499                  "Detaching editor when it's already detached.");
  7501     nsresult res = mEditorData->DetachFromWindow();
  7502     NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
  7504     if (NS_SUCCEEDED(res)) {
  7505         // Make mOSHE hold the owning ref to the editor data.
  7506         if (mOSHE)
  7507             mOSHE->SetEditorData(mEditorData.forget());
  7508         else
  7509             mEditorData = nullptr;
  7512 #ifdef DEBUG
  7514         bool isEditable;
  7515         GetEditable(&isEditable);
  7516         NS_ASSERTION(!isEditable,
  7517                      "Window is still editable after detaching editor.");
  7519 #endif // DEBUG
  7522 nsresult
  7523 nsDocShell::CaptureState()
  7525     if (!mOSHE || mOSHE == mLSHE) {
  7526         // No entry to save into, or we're replacing the existing entry.
  7527         return NS_ERROR_FAILURE;
  7530     if (!mScriptGlobal)
  7531         return NS_ERROR_FAILURE;
  7533     nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState();
  7534     NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE);
  7536 #ifdef DEBUG_PAGE_CACHE
  7537     nsCOMPtr<nsIURI> uri;
  7538     mOSHE->GetURI(getter_AddRefs(uri));
  7539     nsAutoCString spec;
  7540     if (uri)
  7541         uri->GetSpec(spec);
  7542     printf("Saving presentation into session history\n");
  7543     printf("  SH URI: %s\n", spec.get());
  7544 #endif
  7546     nsresult rv = mOSHE->SetWindowState(windowState);
  7547     NS_ENSURE_SUCCESS(rv, rv);
  7549     // Suspend refresh URIs and save off the timer queue
  7550     rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
  7551     NS_ENSURE_SUCCESS(rv, rv);
  7553     // Capture the current content viewer bounds.
  7554     if (mContentViewer) {
  7555         nsIntRect bounds;
  7556         mContentViewer->GetBounds(bounds);
  7557         rv = mOSHE->SetViewerBounds(bounds);
  7558         NS_ENSURE_SUCCESS(rv, rv);
  7561     // Capture the docshell hierarchy.
  7562     mOSHE->ClearChildShells();
  7564     uint32_t childCount = mChildList.Length();
  7565     for (uint32_t i = 0; i < childCount; ++i) {
  7566         nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
  7567         NS_ASSERTION(childShell, "null child shell");
  7569         mOSHE->AddChildShell(childShell);
  7572     return NS_OK;
  7575 NS_IMETHODIMP
  7576 nsDocShell::RestorePresentationEvent::Run()
  7578     if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory()))
  7579         NS_WARNING("RestoreFromHistory failed");
  7580     return NS_OK;
  7583 NS_IMETHODIMP
  7584 nsDocShell::BeginRestore(nsIContentViewer *aContentViewer, bool aTop)
  7586     nsresult rv;
  7587     if (!aContentViewer) {
  7588         rv = EnsureContentViewer();
  7589         NS_ENSURE_SUCCESS(rv, rv);
  7591         aContentViewer = mContentViewer;
  7594     // Dispatch events for restoring the presentation.  We try to simulate
  7595     // the progress notifications loading the document would cause, so we add
  7596     // the document's channel to the loadgroup to initiate stateChange
  7597     // notifications.
  7599     nsCOMPtr<nsIDOMDocument> domDoc;
  7600     aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
  7601     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  7602     if (doc) {
  7603         nsIChannel *channel = doc->GetChannel();
  7604         if (channel) {
  7605             mEODForCurrentDocument = false;
  7606             mIsRestoringDocument = true;
  7607             mLoadGroup->AddRequest(channel, nullptr);
  7608             mIsRestoringDocument = false;
  7612     if (!aTop) {
  7613         // This point corresponds to us having gotten OnStartRequest or
  7614         // STATE_START, so do the same thing that CreateContentViewer does at
  7615         // this point to ensure that unload/pagehide events for this document
  7616         // will fire when it's unloaded again.
  7617         mFiredUnloadEvent = false;
  7619         // For non-top frames, there is no notion of making sure that the
  7620         // previous document is in the domwindow when STATE_START notifications
  7621         // happen.  We can just call BeginRestore for all of the child shells
  7622         // now.
  7623         rv = BeginRestoreChildren();
  7624         NS_ENSURE_SUCCESS(rv, rv);
  7627     return NS_OK;
  7630 nsresult
  7631 nsDocShell::BeginRestoreChildren()
  7633     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  7634     while (iter.HasMore()) {
  7635         nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
  7636         if (child) {
  7637             nsresult rv = child->BeginRestore(nullptr, false);
  7638             NS_ENSURE_SUCCESS(rv, rv);
  7641     return NS_OK;
  7644 NS_IMETHODIMP
  7645 nsDocShell::FinishRestore()
  7647     // First we call finishRestore() on our children.  In the simulated load,
  7648     // all of the child frames finish loading before the main document.
  7650     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  7651     while (iter.HasMore()) {
  7652         nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
  7653         if (child) {
  7654             child->FinishRestore();
  7658     if (mOSHE && mOSHE->HasDetachedEditor()) {
  7659       ReattachEditorToWindow(mOSHE);
  7662     nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
  7663     if (doc) {
  7664         // Finally, we remove the request from the loadgroup.  This will
  7665         // cause onStateChange(STATE_STOP) to fire, which will fire the
  7666         // pageshow event to the chrome.
  7668         nsIChannel *channel = doc->GetChannel();
  7669         if (channel) {
  7670             mIsRestoringDocument = true;
  7671             mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
  7672             mIsRestoringDocument = false;
  7676     return NS_OK;
  7679 NS_IMETHODIMP
  7680 nsDocShell::GetRestoringDocument(bool *aRestoring)
  7682     *aRestoring = mIsRestoringDocument;
  7683     return NS_OK;
  7686 nsresult
  7687 nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, bool *aRestoring)
  7689     NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
  7690                  "RestorePresentation should only be called for history loads");
  7692     nsCOMPtr<nsIContentViewer> viewer;
  7693     aSHEntry->GetContentViewer(getter_AddRefs(viewer));
  7695 #ifdef DEBUG_PAGE_CACHE
  7696     nsCOMPtr<nsIURI> uri;
  7697     aSHEntry->GetURI(getter_AddRefs(uri));
  7699     nsAutoCString spec;
  7700     if (uri)
  7701         uri->GetSpec(spec);
  7702 #endif
  7704     *aRestoring = false;
  7706     if (!viewer) {
  7707 #ifdef DEBUG_PAGE_CACHE
  7708         printf("no saved presentation for uri: %s\n", spec.get());
  7709 #endif
  7710         return NS_OK;
  7713     // We need to make sure the content viewer's container is this docshell.
  7714     // In subframe navigation, it's possible for the docshell that the
  7715     // content viewer was originally loaded into to be replaced with a
  7716     // different one.  We don't currently support restoring the presentation
  7717     // in that case.
  7719     nsCOMPtr<nsIDocShell> container;
  7720     viewer->GetContainer(getter_AddRefs(container));
  7721     if (!::SameCOMIdentity(container, GetAsSupports(this))) {
  7722 #ifdef DEBUG_PAGE_CACHE
  7723         printf("No valid container, clearing presentation\n");
  7724 #endif
  7725         aSHEntry->SetContentViewer(nullptr);
  7726         return NS_ERROR_FAILURE;
  7729     NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
  7731 #ifdef DEBUG_PAGE_CACHE
  7732     printf("restoring presentation from session history: %s\n", spec.get());
  7733 #endif
  7735     SetHistoryEntry(&mLSHE, aSHEntry);
  7737     // Add the request to our load group.  We do this before swapping out
  7738     // the content viewers so that consumers of STATE_START can access
  7739     // the old document.  We only deal with the toplevel load at this time --
  7740     // to be consistent with normal document loading, subframes cannot start
  7741     // loading until after data arrives, which is after STATE_START completes.
  7743     BeginRestore(viewer, true);
  7745     // Post an event that will remove the request after we've returned
  7746     // to the event loop.  This mimics the way it is called by nsIChannel
  7747     // implementations.
  7749     // Revoke any pending restore (just in case)
  7750     NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
  7751         "should only have one RestorePresentationEvent");
  7752     mRestorePresentationEvent.Revoke();
  7754     nsRefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
  7755     nsresult rv = NS_DispatchToCurrentThread(evt);
  7756     if (NS_SUCCEEDED(rv)) {
  7757         mRestorePresentationEvent = evt.get();
  7758         // The rest of the restore processing will happen on our event
  7759         // callback.
  7760         *aRestoring = true;
  7763     return rv;
  7766 nsresult
  7767 nsDocShell::RestoreFromHistory()
  7769     mRestorePresentationEvent.Forget();
  7771     // This section of code follows the same ordering as CreateContentViewer.
  7772     if (!mLSHE)
  7773         return NS_ERROR_FAILURE;
  7775     nsCOMPtr<nsIContentViewer> viewer;
  7776     mLSHE->GetContentViewer(getter_AddRefs(viewer));
  7777     if (!viewer)
  7778         return NS_ERROR_FAILURE;
  7780     if (mSavingOldViewer) {
  7781         // We determined that it was safe to cache the document presentation
  7782         // at the time we initiated the new load.  We need to check whether
  7783         // it's still safe to do so, since there may have been DOM mutations
  7784         // or new requests initiated.
  7785         nsCOMPtr<nsIDOMDocument> domDoc;
  7786         viewer->GetDOMDocument(getter_AddRefs(domDoc));
  7787         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  7788         nsIRequest *request = nullptr;
  7789         if (doc)
  7790             request = doc->GetChannel();
  7791         mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
  7794     nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV(
  7795         do_QueryInterface(mContentViewer));
  7796     nsCOMPtr<nsIMarkupDocumentViewer> newMUDV(
  7797         do_QueryInterface(viewer));
  7798     int32_t minFontSize = 0;
  7799     float textZoom = 1.0f;
  7800     float pageZoom = 1.0f;
  7801     bool styleDisabled = false;
  7802     if (oldMUDV && newMUDV) {
  7803         oldMUDV->GetMinFontSize(&minFontSize);
  7804         oldMUDV->GetTextZoom(&textZoom);
  7805         oldMUDV->GetFullZoom(&pageZoom);
  7806         oldMUDV->GetAuthorStyleDisabled(&styleDisabled);
  7809     // Protect against mLSHE going away via a load triggered from
  7810     // pagehide or unload.
  7811     nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
  7813     // Make sure to blow away our mLoadingURI just in case.  No loads
  7814     // from inside this pagehide.
  7815     mLoadingURI = nullptr;
  7817     // Notify the old content viewer that it's being hidden.
  7818     FirePageHideNotification(!mSavingOldViewer);
  7820     // If mLSHE was changed as a result of the pagehide event, then
  7821     // something else was loaded.  Don't finish restoring.
  7822     if (mLSHE != origLSHE)
  7823       return NS_OK;
  7825     // Set mFiredUnloadEvent = false so that the unload handler for the
  7826     // *new* document will fire.
  7827     mFiredUnloadEvent = false;
  7829     mURIResultedInDocument = true;
  7830     nsCOMPtr<nsISHistory> rootSH;
  7831     GetRootSessionHistory(getter_AddRefs(rootSH));
  7832     if (rootSH) {
  7833         nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
  7834         rootSH->GetIndex(&mPreviousTransIndex);
  7835         hist->UpdateIndex();
  7836         rootSH->GetIndex(&mLoadedTransIndex);
  7837 #ifdef DEBUG_PAGE_CACHE
  7838         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
  7839                    mLoadedTransIndex);
  7840 #endif
  7843     // Rather than call Embed(), we will retrieve the viewer from the session
  7844     // history entry and swap it in.
  7845     // XXX can we refactor this so that we can just call Embed()?
  7846     PersistLayoutHistoryState();
  7847     nsresult rv;
  7848     if (mContentViewer) {
  7849         if (mSavingOldViewer && NS_FAILED(CaptureState())) {
  7850             if (mOSHE) {
  7851                 mOSHE->SyncPresentationState();
  7853             mSavingOldViewer = false;
  7857     mSavedRefreshURIList = nullptr;
  7859     // In cases where we use a transient about:blank viewer between loads,
  7860     // we never show the transient viewer, so _its_ previous viewer is never
  7861     // unhooked from the view hierarchy.  Destroy any such previous viewer now,
  7862     // before we grab the root view sibling, so that we don't grab a view
  7863     // that's about to go away.
  7865     if (mContentViewer) {
  7866         nsCOMPtr<nsIContentViewer> previousViewer;
  7867         mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
  7868         if (previousViewer) {
  7869             mContentViewer->SetPreviousViewer(nullptr);
  7870             previousViewer->Destroy();
  7874     // Save off the root view's parent and sibling so that we can insert the
  7875     // new content viewer's root view at the same position.  Also save the
  7876     // bounds of the root view's widget.
  7878     nsView *rootViewSibling = nullptr, *rootViewParent = nullptr;
  7879     nsIntRect newBounds(0, 0, 0, 0);
  7881     nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell();
  7882     if (oldPresShell) {
  7883         nsViewManager *vm = oldPresShell->GetViewManager();
  7884         if (vm) {
  7885             nsView *oldRootView = vm->GetRootView();
  7887             if (oldRootView) {
  7888                 rootViewSibling = oldRootView->GetNextSibling();
  7889                 rootViewParent = oldRootView->GetParent();
  7891                 mContentViewer->GetBounds(newBounds);
  7896     nsCOMPtr<nsIContent> container;
  7897     nsCOMPtr<nsIDocument> sibling;
  7898     if (rootViewParent && rootViewParent->GetParent()) {
  7899         nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
  7900         container = frame ? frame->GetContent() : nullptr;
  7902     if (rootViewSibling) {
  7903         nsIFrame *frame = rootViewSibling->GetFrame();
  7904         sibling = frame ? frame->PresContext()->PresShell()->GetDocument() : nullptr;
  7907     // Transfer ownership to mContentViewer.  By ensuring that either the
  7908     // docshell or the session history, but not both, have references to the
  7909     // content viewer, we prevent the viewer from being torn down after
  7910     // Destroy() is called.
  7912     if (mContentViewer) {
  7913         mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
  7914         viewer->SetPreviousViewer(mContentViewer);
  7916     if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
  7917         // We don't plan to save a viewer in mOSHE; tell it to drop
  7918         // any other state it's holding.
  7919         mOSHE->SyncPresentationState();
  7922     // Order the mContentViewer setup just like Embed does.
  7923     mContentViewer = nullptr;
  7925     // Now that we're about to switch documents, forget all of our children.
  7926     // Note that we cached them as needed up in CaptureState above.
  7927     DestroyChildren();
  7929     mContentViewer.swap(viewer);
  7931     // Grab all of the related presentation from the SHEntry now.
  7932     // Clearing the viewer from the SHEntry will clear all of this state.
  7933     nsCOMPtr<nsISupports> windowState;
  7934     mLSHE->GetWindowState(getter_AddRefs(windowState));
  7935     mLSHE->SetWindowState(nullptr);
  7937     bool sticky;
  7938     mLSHE->GetSticky(&sticky);
  7940     nsCOMPtr<nsIDOMDocument> domDoc;
  7941     mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
  7943     nsCOMArray<nsIDocShellTreeItem> childShells;
  7944     int32_t i = 0;
  7945     nsCOMPtr<nsIDocShellTreeItem> child;
  7946     while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
  7947            child) {
  7948         childShells.AppendObject(child);
  7951     // get the previous content viewer size
  7952     nsIntRect oldBounds(0, 0, 0, 0);
  7953     mLSHE->GetViewerBounds(oldBounds);
  7955     // Restore the refresh URI list.  The refresh timers will be restarted
  7956     // when EndPageLoad() is called.
  7957     nsCOMPtr<nsISupportsArray> refreshURIList;
  7958     mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
  7960     // Reattach to the window object.
  7961     mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive
  7962     rv = mContentViewer->Open(windowState, mLSHE);
  7963     mIsRestoringDocument = false;
  7965     // Hack to keep nsDocShellEditorData alive across the
  7966     // SetContentViewer(nullptr) call below.
  7967     nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
  7969     // Now remove it from the cached presentation.
  7970     mLSHE->SetContentViewer(nullptr);
  7971     mEODForCurrentDocument = false;
  7973     mLSHE->SetEditorData(data.forget());
  7975 #ifdef DEBUG
  7977      nsCOMPtr<nsISupportsArray> refreshURIs;
  7978      mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
  7979      nsCOMPtr<nsIDocShellTreeItem> childShell;
  7980      mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
  7981      NS_ASSERTION(!refreshURIs && !childShell,
  7982                   "SHEntry should have cleared presentation state");
  7984 #endif
  7986     // Restore the sticky state of the viewer.  The viewer has set this state
  7987     // on the history entry in Destroy() just before marking itself non-sticky,
  7988     // to avoid teardown of the presentation.
  7989     mContentViewer->SetSticky(sticky);
  7991     NS_ENSURE_SUCCESS(rv, rv);
  7993     // mLSHE is now our currently-loaded document.
  7994     SetHistoryEntry(&mOSHE, mLSHE);
  7996     // XXX special wyciwyg handling in Embed()?
  7998     // We aren't going to restore any items from the LayoutHistoryState,
  7999     // but we don't want them to stay around in case the page is reloaded.
  8000     SetLayoutHistoryState(nullptr);
  8002     // This is the end of our Embed() replacement
  8004     mSavingOldViewer = false;
  8005     mEODForCurrentDocument = false;
  8007     // Tell the event loop to favor plevents over user events, see comments
  8008     // in CreateContentViewer.
  8009     if (++gNumberOfDocumentsLoading == 1)
  8010         FavorPerformanceHint(true);
  8013     if (oldMUDV && newMUDV) {
  8014         newMUDV->SetMinFontSize(minFontSize);
  8015         newMUDV->SetTextZoom(textZoom);
  8016         newMUDV->SetFullZoom(pageZoom);
  8017         newMUDV->SetAuthorStyleDisabled(styleDisabled);
  8020     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
  8021     uint32_t parentSuspendCount = 0;
  8022     if (document) {
  8023         nsCOMPtr<nsIDocShellTreeItem> parent;
  8024         GetParent(getter_AddRefs(parent));
  8025         nsCOMPtr<nsIDocument> d = do_GetInterface(parent);
  8026         if (d) {
  8027             if (d->EventHandlingSuppressed()) {
  8028                 document->SuppressEventHandling(nsIDocument::eEvents,
  8029                                                 d->EventHandlingSuppressed());
  8032             // Ick, it'd be nicer to not rewalk all of the subdocs here.
  8033             if (d->AnimationsPaused()) {
  8034                 document->SuppressEventHandling(nsIDocument::eAnimationsOnly,
  8035                                                 d->AnimationsPaused());
  8038             nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
  8039             if (parentWindow) {
  8040                 parentSuspendCount = parentWindow->TimeoutSuspendCount();
  8044         // Use the uri from the mLSHE we had when we entered this function
  8045         // (which need not match the document's URI if anchors are involved),
  8046         // since that's the history entry we're loading.  Note that if we use
  8047         // origLSHE we don't have to worry about whether the entry in question
  8048         // is still mLSHE or whether it's now mOSHE.
  8049         nsCOMPtr<nsIURI> uri;
  8050         origLSHE->GetURI(getter_AddRefs(uri));
  8051         SetCurrentURI(uri, document->GetChannel(), true, 0);
  8054     // This is the end of our CreateContentViewer() replacement.
  8055     // Now we simulate a load.  First, we restore the state of the javascript
  8056     // window object.
  8057     nsCOMPtr<nsPIDOMWindow> privWin =
  8058         do_GetInterface(static_cast<nsIInterfaceRequestor*>(this));
  8059     NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
  8061     rv = privWin->RestoreWindowState(windowState);
  8062     NS_ENSURE_SUCCESS(rv, rv);
  8064     // Now, dispatch a title change event which would happen as the
  8065     // <head> is parsed.
  8066     document->NotifyPossibleTitleChange(false);
  8068     // Now we simulate appending child docshells for subframes.
  8069     for (i = 0; i < childShells.Count(); ++i) {
  8070         nsIDocShellTreeItem *childItem = childShells.ObjectAt(i);
  8071         nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
  8073         // Make sure to not clobber the state of the child.  Since AddChild
  8074         // always clobbers it, save it off first.
  8075         bool allowPlugins;
  8076         childShell->GetAllowPlugins(&allowPlugins);
  8078         bool allowJavascript;
  8079         childShell->GetAllowJavascript(&allowJavascript);
  8081         bool allowRedirects;
  8082         childShell->GetAllowMetaRedirects(&allowRedirects);
  8084         bool allowSubframes;
  8085         childShell->GetAllowSubframes(&allowSubframes);
  8087         bool allowImages;
  8088         childShell->GetAllowImages(&allowImages);
  8090         bool allowMedia = childShell->GetAllowMedia();
  8092         bool allowDNSPrefetch;
  8093         childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
  8095         bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
  8097         uint32_t defaultLoadFlags;
  8098         childShell->GetDefaultLoadFlags(&defaultLoadFlags);
  8100         // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
  8101         // that the child inherits our state. Among other things, this means
  8102         // that the child inherits our mIsActive and mInPrivateBrowsing, which
  8103         // is what we want.
  8104         AddChild(childItem);
  8106         childShell->SetAllowPlugins(allowPlugins);
  8107         childShell->SetAllowJavascript(allowJavascript);
  8108         childShell->SetAllowMetaRedirects(allowRedirects);
  8109         childShell->SetAllowSubframes(allowSubframes);
  8110         childShell->SetAllowImages(allowImages);
  8111         childShell->SetAllowMedia(allowMedia);
  8112         childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
  8113         childShell->SetAllowContentRetargeting(allowContentRetargeting);
  8114         childShell->SetDefaultLoadFlags(defaultLoadFlags);
  8116         rv = childShell->BeginRestore(nullptr, false);
  8117         NS_ENSURE_SUCCESS(rv, rv);
  8120     nsCOMPtr<nsIPresShell> shell = GetPresShell();
  8122     // We may be displayed on a different monitor (or in a different
  8123     // HiDPI mode) than when we got into the history list.  So we need
  8124     // to check if this has happened. See bug 838239.
  8126     // Because the prescontext normally handles resolution changes via
  8127     // a runnable (see nsPresContext::UIResolutionChanged), its device
  8128     // context won't be -immediately- updated as a result of calling
  8129     // shell->BackingScaleFactorChanged().
  8131     // But we depend on that device context when adjusting the view size
  8132     // via mContentViewer->SetBounds(newBounds) below. So we need to
  8133     // explicitly tell it to check for changed resolution here.
  8134     if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) {
  8135         shell->BackingScaleFactorChanged();
  8138     nsViewManager *newVM = shell ? shell->GetViewManager() : nullptr;
  8139     nsView *newRootView = newVM ? newVM->GetRootView() : nullptr;
  8141     // Insert the new root view at the correct location in the view tree.
  8142     if (container) {
  8143         nsSubDocumentFrame* subDocFrame = do_QueryFrame(container->GetPrimaryFrame());
  8144         rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr;
  8146     if (sibling &&
  8147         sibling->GetShell() &&
  8148         sibling->GetShell()->GetViewManager()) {
  8149         rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView();
  8150     } else {
  8151         rootViewSibling = nullptr;
  8153     if (rootViewParent && newRootView && newRootView->GetParent() != rootViewParent) {
  8154         nsViewManager *parentVM = rootViewParent->GetViewManager();
  8155         if (parentVM) {
  8156             // InsertChild(parent, child, sib, true) inserts the child after
  8157             // sib in content order, which is before sib in view order. BUT
  8158             // when sib is null it inserts at the end of the the document
  8159             // order, i.e., first in view order.  But when oldRootSibling is
  8160             // null, the old root as at the end of the view list --- last in
  8161             // content order --- and we want to call InsertChild(parent, child,
  8162             // nullptr, false) in that case.
  8163             parentVM->InsertChild(rootViewParent, newRootView,
  8164                                   rootViewSibling,
  8165                                   rootViewSibling ? true : false);
  8167             NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
  8168                          "error in InsertChild");
  8172     // If parent is suspended, increase suspension count.
  8173     // This can't be done as early as event suppression since this
  8174     // depends on docshell tree.
  8175     if (parentSuspendCount) {
  8176       privWin->SuspendTimeouts(parentSuspendCount, false);
  8179     // Now that all of the child docshells have been put into place, we can
  8180     // restart the timers for the window and all of the child frames.
  8181     privWin->ResumeTimeouts();
  8183     // Restore the refresh URI list.  The refresh timers will be restarted
  8184     // when EndPageLoad() is called.
  8185     mRefreshURIList = refreshURIList;
  8187     // Meta-refresh timers have been restarted for this shell, but not
  8188     // for our children.  Walk the child shells and restart their timers.
  8189     nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
  8190     while (iter.HasMore()) {
  8191         nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
  8192         if (child)
  8193             child->ResumeRefreshURIs();
  8196     // Make sure this presentation is the same size as the previous
  8197     // presentation.  If this is not the same size we showed it at last time,
  8198     // then we need to resize the widget.
  8200     // XXXbryner   This interacts poorly with Firefox's infobar.  If the old
  8201     // presentation had the infobar visible, then we will resize the new
  8202     // presentation to that smaller size.  However, firing the locationchanged
  8203     // event will hide the infobar, which will immediately resize the window
  8204     // back to the larger size.  A future optimization might be to restore
  8205     // the presentation at the "wrong" size, then fire the locationchanged
  8206     // event and check whether the docshell's new size is the same as the
  8207     // cached viewer size (skipping the resize if they are equal).
  8209     if (newRootView) {
  8210         if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
  8211 #ifdef DEBUG_PAGE_CACHE
  8212             printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
  8213                    newBounds.y, newBounds.width, newBounds.height);
  8214 #endif
  8215             mContentViewer->SetBounds(newBounds);
  8216         } else {
  8217             nsIScrollableFrame *rootScrollFrame =
  8218               shell->GetRootScrollFrameAsScrollableExternal();
  8219             if (rootScrollFrame) {
  8220                 rootScrollFrame->PostScrolledAreaEventForCurrentArea();
  8225     // The FinishRestore call below can kill these, null them out so we don't
  8226     // have invalid pointer lying around.
  8227     newRootView = rootViewSibling = rootViewParent = nullptr;
  8228     newVM = nullptr;
  8230     // Simulate the completion of the load.
  8231     nsDocShell::FinishRestore();
  8233     // Restart plugins, and paint the content.
  8234     if (shell) {
  8235         shell->Thaw();
  8238     return privWin->FireDelayedDOMEvents();
  8241 NS_IMETHODIMP
  8242 nsDocShell::CreateContentViewer(const char *aContentType,
  8243                                 nsIRequest * request,
  8244                                 nsIStreamListener ** aContentHandler)
  8246     *aContentHandler = nullptr;
  8248     // Can we check the content type of the current content viewer
  8249     // and reuse it without destroying it and re-creating it?
  8251     NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
  8253     // Instantiate the content viewer object
  8254     nsCOMPtr<nsIContentViewer> viewer;
  8255     nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup,
  8256                                       aContentHandler, getter_AddRefs(viewer));
  8258     if (NS_FAILED(rv))
  8259         return rv;
  8261     // Notify the current document that it is about to be unloaded!!
  8262     //
  8263     // It is important to fire the unload() notification *before* any state
  8264     // is changed within the DocShell - otherwise, javascript will get the
  8265     // wrong information :-(
  8266     //
  8268     if (mSavingOldViewer) {
  8269         // We determined that it was safe to cache the document presentation
  8270         // at the time we initiated the new load.  We need to check whether
  8271         // it's still safe to do so, since there may have been DOM mutations
  8272         // or new requests initiated.
  8273         nsCOMPtr<nsIDOMDocument> domDoc;
  8274         viewer->GetDOMDocument(getter_AddRefs(domDoc));
  8275         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  8276         mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
  8279     NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
  8281     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
  8282     if (aOpenedChannel) {
  8283         aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
  8285     FirePageHideNotification(!mSavingOldViewer);
  8286     mLoadingURI = nullptr;
  8288     // Set mFiredUnloadEvent = false so that the unload handler for the
  8289     // *new* document will fire.
  8290     mFiredUnloadEvent = false;
  8292     // we've created a new document so go ahead and call
  8293     // OnLoadingSite(), but don't fire OnLocationChange()
  8294     // notifications before we've called Embed(). See bug 284993.
  8295     mURIResultedInDocument = true;
  8297     if (mLoadType == LOAD_ERROR_PAGE) {
  8298         // We need to set the SH entry and our current URI here and not
  8299         // at the moment we load the page. We want the same behavior 
  8300         // of Stop() as for a normal page load. See bug 514232 for details.
  8302         // Revert mLoadType to load type to state the page load failed,
  8303         // following function calls need it.
  8304         mLoadType = mFailedLoadType;
  8306         nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
  8308         // Make sure we have a URI to set currentURI.
  8309         nsCOMPtr<nsIURI> failedURI;
  8310         if (failedChannel) {
  8311             NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
  8314         if (!failedURI) {
  8315             failedURI = mFailedURI;
  8317         if (!failedURI) {
  8318             // We need a URI object to store a session history entry, so make up a URI
  8319             NS_NewURI(getter_AddRefs(failedURI), "about:blank");
  8322         // When we don't have failedURI, something wrong will happen. See
  8323         // bug 291876.
  8324         MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
  8326         mFailedChannel = nullptr;
  8327         mFailedURI = nullptr;
  8329         // Create an shistory entry for the old load.
  8330         if (failedURI) {
  8331             bool errorOnLocationChangeNeeded =
  8332                 OnNewURI(failedURI, failedChannel, nullptr, mLoadType, false,
  8333                          false, false);
  8335             if (errorOnLocationChangeNeeded) {
  8336                 FireOnLocationChange(this, failedChannel, failedURI,
  8337                                      LOCATION_CHANGE_ERROR_PAGE);
  8341         // Be sure to have a correct mLSHE, it may have been cleared by
  8342         // EndPageLoad. See bug 302115.
  8343         if (mSessionHistory && !mLSHE) {
  8344             int32_t idx;
  8345             mSessionHistory->GetRequestedIndex(&idx);
  8346             if (idx == -1)
  8347                 mSessionHistory->GetIndex(&idx);
  8348             mSessionHistory->GetEntryAtIndex(idx, false,
  8349                                              getter_AddRefs(mLSHE));
  8352         mLoadType = LOAD_ERROR_PAGE;
  8355     bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
  8357     // let's try resetting the load group if we need to...
  8358     nsCOMPtr<nsILoadGroup> currentLoadGroup;
  8359     NS_ENSURE_SUCCESS(aOpenedChannel->
  8360                       GetLoadGroup(getter_AddRefs(currentLoadGroup)),
  8361                       NS_ERROR_FAILURE);
  8363     if (currentLoadGroup != mLoadGroup) {
  8364         nsLoadFlags loadFlags = 0;
  8366         //Cancel any URIs that are currently loading...
  8367         /// XXX: Need to do this eventually      Stop();
  8368         //
  8369         // Retarget the document to this loadgroup...
  8370         //
  8371         /* First attach the channel to the right loadgroup
  8372          * and then remove from the old loadgroup. This 
  8373          * puts the notifications in the right order and
  8374          * we don't null-out mLSHE in OnStateChange() for 
  8375          * all redirected urls
  8376          */
  8377         aOpenedChannel->SetLoadGroup(mLoadGroup);
  8379         // Mark the channel as being a document URI...
  8380         aOpenedChannel->GetLoadFlags(&loadFlags);
  8381         loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
  8383         aOpenedChannel->SetLoadFlags(loadFlags);
  8385         mLoadGroup->AddRequest(request, nullptr);
  8386         if (currentLoadGroup)
  8387             currentLoadGroup->RemoveRequest(request, nullptr,
  8388                                             NS_BINDING_RETARGETED);
  8390         // Update the notification callbacks, so that progress and
  8391         // status information are sent to the right docshell...
  8392         aOpenedChannel->SetNotificationCallbacks(this);
  8395     NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nullptr),
  8396                       NS_ERROR_FAILURE);
  8398     mSavedRefreshURIList = nullptr;
  8399     mSavingOldViewer = false;
  8400     mEODForCurrentDocument = false;
  8402     // if this document is part of a multipart document,
  8403     // the ID can be used to distinguish it from the other parts.
  8404     nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(request));
  8405     if (multiPartChannel) {
  8406       nsCOMPtr<nsIPresShell> shell = GetPresShell();
  8407       if (NS_SUCCEEDED(rv) && shell) {
  8408         nsIDocument *doc = shell->GetDocument();
  8409         if (doc) {
  8410           uint32_t partID;
  8411           multiPartChannel->GetPartID(&partID);
  8412           doc->SetPartID(partID);
  8417     // Give hint to native plevent dispatch mechanism. If a document
  8418     // is loading the native plevent dispatch mechanism should favor
  8419     // performance over normal native event dispatch priorities.
  8420     if (++gNumberOfDocumentsLoading == 1) {
  8421       // Hint to favor performance for the plevent notification mechanism.
  8422       // We want the pages to load as fast as possible even if its means 
  8423       // native messages might be starved.
  8424       FavorPerformanceHint(true);
  8427     if (onLocationChangeNeeded) {
  8428       FireOnLocationChange(this, request, mCurrentURI, 0);
  8431     return NS_OK;
  8434 nsresult
  8435 nsDocShell::NewContentViewerObj(const char *aContentType,
  8436                                 nsIRequest * request, nsILoadGroup * aLoadGroup,
  8437                                 nsIStreamListener ** aContentHandler,
  8438                                 nsIContentViewer ** aViewer)
  8440     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
  8442     nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
  8443         nsContentUtils::FindInternalContentViewer(aContentType);
  8444     if (!docLoaderFactory) {
  8445         return NS_ERROR_FAILURE;
  8448     // Now create an instance of the content viewer
  8449     // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
  8450     nsresult rv = docLoaderFactory->CreateInstance("view",
  8451                                                    aOpenedChannel,
  8452                                                    aLoadGroup, aContentType,
  8453                                                    this,
  8454                                                    nullptr,
  8455                                                    aContentHandler,
  8456                                                    aViewer);
  8457     NS_ENSURE_SUCCESS(rv, rv);
  8459     (*aViewer)->SetContainer(this);
  8460     return NS_OK;
  8463 NS_IMETHODIMP
  8464 nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
  8466     //
  8467     // Copy content viewer state from previous or parent content viewer.
  8468     //
  8469     // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
  8470     //
  8471     // Do NOT to maintain a reference to the old content viewer outside
  8472     // of this "copying" block, or it will not be destroyed until the end of
  8473     // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
  8474     //
  8475     // In this block of code, if we get an error result, we return it
  8476     // but if we get a null pointer, that's perfectly legal for parent
  8477     // and parentContentViewer.
  8478     //
  8480     int32_t x = 0;
  8481     int32_t y = 0;
  8482     int32_t cx = 0;
  8483     int32_t cy = 0;
  8485     // This will get the size from the current content viewer or from the
  8486     // Init settings
  8487     DoGetPositionAndSize(&x, &y, &cx, &cy);
  8489     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
  8490     NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
  8491                       NS_ERROR_FAILURE);
  8492     nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
  8494     nsAutoCString forceCharset;
  8495     nsAutoCString hintCharset;
  8496     int32_t hintCharsetSource;
  8497     int32_t minFontSize;
  8498     float textZoom;
  8499     float pageZoom;
  8500     bool styleDisabled;
  8501     // |newMUDV| also serves as a flag to set the data from the above vars
  8502     nsCOMPtr<nsIMarkupDocumentViewer> newMUDV;
  8504     if (mContentViewer || parent) {
  8505         nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV;
  8506         if (mContentViewer) {
  8507             // Get any interesting state from old content viewer
  8508             // XXX: it would be far better to just reuse the document viewer ,
  8509             //      since we know we're just displaying the same document as before
  8510             oldMUDV = do_QueryInterface(mContentViewer);
  8512             // Tell the old content viewer to hibernate in session history when
  8513             // it is destroyed.
  8515             if (mSavingOldViewer && NS_FAILED(CaptureState())) {
  8516                 if (mOSHE) {
  8517                     mOSHE->SyncPresentationState();
  8519                 mSavingOldViewer = false;
  8522         else {
  8523             // No old content viewer, so get state from parent's content viewer
  8524             nsCOMPtr<nsIContentViewer> parentContentViewer;
  8525             parent->GetContentViewer(getter_AddRefs(parentContentViewer));
  8526             oldMUDV = do_QueryInterface(parentContentViewer);
  8529         if (oldMUDV) {
  8530             nsresult rv;
  8532             newMUDV = do_QueryInterface(aNewViewer,&rv);
  8533             if (newMUDV) {
  8534                 NS_ENSURE_SUCCESS(oldMUDV->
  8535                                   GetForceCharacterSet(forceCharset),
  8536                                   NS_ERROR_FAILURE);
  8537                 NS_ENSURE_SUCCESS(oldMUDV->
  8538                                   GetHintCharacterSet(hintCharset),
  8539                                   NS_ERROR_FAILURE);
  8540                 NS_ENSURE_SUCCESS(oldMUDV->
  8541                                   GetHintCharacterSetSource(&hintCharsetSource),
  8542                                   NS_ERROR_FAILURE);
  8543                 NS_ENSURE_SUCCESS(oldMUDV->
  8544                                   GetMinFontSize(&minFontSize),
  8545                                   NS_ERROR_FAILURE);
  8546                 NS_ENSURE_SUCCESS(oldMUDV->
  8547                                   GetTextZoom(&textZoom),
  8548                                   NS_ERROR_FAILURE);
  8549                 NS_ENSURE_SUCCESS(oldMUDV->
  8550                                   GetFullZoom(&pageZoom),
  8551                                   NS_ERROR_FAILURE);
  8552                 NS_ENSURE_SUCCESS(oldMUDV->
  8553                                   GetAuthorStyleDisabled(&styleDisabled),
  8554                                   NS_ERROR_FAILURE);
  8559     nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
  8560     // Ensure that the content viewer is destroyed *after* the GC - bug 71515
  8561     nsCOMPtr<nsIContentViewer> kungfuDeathGrip = mContentViewer;
  8562     if (mContentViewer) {
  8563         // Stop any activity that may be happening in the old document before
  8564         // releasing it...
  8565         mContentViewer->Stop();
  8567         // Try to extract the canvas background color from the old
  8568         // presentation shell, so we can use it for the next document.
  8569         nsCOMPtr<nsIPresShell> shell;
  8570         mContentViewer->GetPresShell(getter_AddRefs(shell));
  8572         if (shell) {
  8573             bgcolor = shell->GetCanvasBackground();
  8576         mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
  8577         aNewViewer->SetPreviousViewer(mContentViewer);
  8579     if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
  8580         // We don't plan to save a viewer in mOSHE; tell it to drop
  8581         // any other state it's holding.
  8582         mOSHE->SyncPresentationState();
  8585     mContentViewer = nullptr;
  8587     // Now that we're about to switch documents, forget all of our children.
  8588     // Note that we cached them as needed up in CaptureState above.
  8589     DestroyChildren();
  8591     mContentViewer = aNewViewer;
  8593     nsCOMPtr<nsIWidget> widget;
  8594     NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
  8596     nsIntRect bounds(x, y, cx, cy);
  8598     mContentViewer->SetNavigationTiming(mTiming);
  8600     if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
  8601         mContentViewer = nullptr;
  8602         NS_ERROR("ContentViewer Initialization failed");
  8603         return NS_ERROR_FAILURE;
  8606     // If we have old state to copy, set the old state onto the new content
  8607     // viewer
  8608     if (newMUDV) {
  8609         NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
  8610                           NS_ERROR_FAILURE);
  8611         NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset),
  8612                           NS_ERROR_FAILURE);
  8613         NS_ENSURE_SUCCESS(newMUDV->
  8614                           SetHintCharacterSetSource(hintCharsetSource),
  8615                           NS_ERROR_FAILURE);
  8616         NS_ENSURE_SUCCESS(newMUDV->SetMinFontSize(minFontSize),
  8617                           NS_ERROR_FAILURE);
  8618         NS_ENSURE_SUCCESS(newMUDV->SetTextZoom(textZoom),
  8619                           NS_ERROR_FAILURE);
  8620         NS_ENSURE_SUCCESS(newMUDV->SetFullZoom(pageZoom),
  8621                           NS_ERROR_FAILURE);
  8622         NS_ENSURE_SUCCESS(newMUDV->SetAuthorStyleDisabled(styleDisabled),
  8623                           NS_ERROR_FAILURE);
  8626     // Stuff the bgcolor from the old pres shell into the new
  8627     // pres shell. This improves page load continuity.
  8628     nsCOMPtr<nsIPresShell> shell;
  8629     mContentViewer->GetPresShell(getter_AddRefs(shell));
  8631     if (shell) {
  8632         shell->SetCanvasBackground(bgcolor);
  8635 // XXX: It looks like the LayoutState gets restored again in Embed()
  8636 //      right after the call to SetupNewViewer(...)
  8638     // We don't show the mContentViewer yet, since we want to draw the old page
  8639     // until we have enough of the new page to show.  Just return with the new
  8640     // viewer still set to hidden.
  8642     return NS_OK;
  8645 nsresult
  8646 nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry)
  8648     nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
  8649     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
  8651     nsCOMPtr<nsIStructuredCloneContainer> scContainer;
  8652     if (shEntry) {
  8653         nsresult rv = shEntry->GetStateData(getter_AddRefs(scContainer));
  8654         NS_ENSURE_SUCCESS(rv, rv);
  8656         // If shEntry is null, just set the document's state object to null.
  8659     // It's OK for scContainer too be null here; that just means there's no
  8660     // state data associated with this history entry.
  8661     document->SetStateObject(scContainer);
  8663     return NS_OK;
  8666 nsresult
  8667 nsDocShell::CheckLoadingPermissions()
  8669     // This method checks whether the caller may load content into
  8670     // this docshell. Even though we've done our best to hide windows
  8671     // from code that doesn't have the right to access them, it's
  8672     // still possible for an evil site to open a window and access
  8673     // frames in the new window through window.frames[] (which is
  8674     // allAccess for historic reasons), so we still need to do this
  8675     // check on load.
  8676     nsresult rv = NS_OK, sameOrigin = NS_OK;
  8678     if (!gValidateOrigin || !IsFrame()) {
  8679         // Origin validation was turned off, or we're not a frame.
  8680         // Permit all loads.
  8682         return rv;
  8685     nsCOMPtr<nsIScriptSecurityManager> securityManager =
  8686       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  8687     NS_ENSURE_SUCCESS(rv, rv);
  8689     // We're a frame. Check that the caller has write permission to
  8690     // the parent before allowing it to load anything into this
  8691     // docshell.
  8692     nsCOMPtr<nsIPrincipal> subjPrincipal;
  8693     rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal));
  8694     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv);
  8696     // Check if the caller is from the same origin as this docshell,
  8697     // or any of its ancestors.
  8698     nsCOMPtr<nsIDocShellTreeItem> item(this);
  8699     do {
  8700         nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item));
  8701         nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
  8703         nsIPrincipal *p;
  8704         if (!sop || !(p = sop->GetPrincipal())) {
  8705             return NS_ERROR_UNEXPECTED;
  8708         // Compare origins
  8709         bool subsumes;
  8710         sameOrigin = subjPrincipal->Subsumes(p, &subsumes);
  8711         if (NS_SUCCEEDED(sameOrigin)) {
  8712             if (subsumes) {
  8713                 // Same origin, permit load
  8715                 return sameOrigin;
  8718             sameOrigin = NS_ERROR_DOM_PROP_ACCESS_DENIED;
  8721         nsCOMPtr<nsIDocShellTreeItem> tmp;
  8722         item->GetSameTypeParent(getter_AddRefs(tmp));
  8723         item.swap(tmp);
  8724     } while (item);
  8726     return sameOrigin;
  8729 //*****************************************************************************
  8730 // nsDocShell: Site Loading
  8731 //*****************************************************************************   
  8732 namespace
  8735 #ifdef MOZ_PLACES
  8736 // Callback used by CopyFavicon to inform the favicon service that one URI
  8737 // (mNewURI) has the same favicon URI (OnComplete's aFaviconURI) as another.
  8738 class nsCopyFaviconCallback MOZ_FINAL : public nsIFaviconDataCallback
  8740 public:
  8741     NS_DECL_ISUPPORTS
  8743     nsCopyFaviconCallback(nsIURI *aNewURI, bool aInPrivateBrowsing)
  8744       : mNewURI(aNewURI)
  8745       , mInPrivateBrowsing(aInPrivateBrowsing)
  8749     NS_IMETHODIMP
  8750     OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen,
  8751                const uint8_t *aData, const nsACString &aMimeType)
  8753         // Continue only if there is an associated favicon.
  8754         if (!aFaviconURI) {
  8755           return NS_OK;
  8758         NS_ASSERTION(aDataLen == 0,
  8759                      "We weren't expecting the callback to deliver data.");
  8760         nsCOMPtr<mozIAsyncFavicons> favSvc =
  8761             do_GetService("@mozilla.org/browser/favicon-service;1");
  8762         NS_ENSURE_STATE(favSvc);
  8764         return favSvc->SetAndFetchFaviconForPage(mNewURI, aFaviconURI,
  8765                                                  false,
  8766                                                  mInPrivateBrowsing ?
  8767                                                    nsIFaviconService::FAVICON_LOAD_PRIVATE :
  8768                                                    nsIFaviconService::FAVICON_LOAD_NON_PRIVATE,
  8769                                                  nullptr);
  8772 private:
  8773     nsCOMPtr<nsIURI> mNewURI;
  8774     bool mInPrivateBrowsing;
  8775 };
  8777 NS_IMPL_ISUPPORTS(nsCopyFaviconCallback, nsIFaviconDataCallback)
  8778 #endif
  8780 // Tell the favicon service that aNewURI has the same favicon as aOldURI.
  8781 void CopyFavicon(nsIURI *aOldURI, nsIURI *aNewURI, bool inPrivateBrowsing)
  8783 #ifdef MOZ_PLACES
  8784     nsCOMPtr<mozIAsyncFavicons> favSvc =
  8785         do_GetService("@mozilla.org/browser/favicon-service;1");
  8786     if (favSvc) {
  8787         nsCOMPtr<nsIFaviconDataCallback> callback =
  8788             new nsCopyFaviconCallback(aNewURI, inPrivateBrowsing);
  8789         favSvc->GetFaviconURLForPage(aOldURI, callback);
  8791 #endif
  8794 } // anonymous namespace
  8796 class InternalLoadEvent : public nsRunnable
  8798 public:
  8799     InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
  8800                       nsISupports * aOwner, uint32_t aFlags,
  8801                       const char* aTypeHint, nsIInputStream * aPostData,
  8802                       nsIInputStream * aHeadersData, uint32_t aLoadType,
  8803                       nsISHEntry * aSHEntry, bool aFirstParty,
  8804                       const nsAString &aSrcdoc, nsIDocShell* aSourceDocShell,
  8805                       nsIURI * aBaseURI) :
  8806         mSrcdoc(aSrcdoc),
  8807         mDocShell(aDocShell),
  8808         mURI(aURI),
  8809         mReferrer(aReferrer),
  8810         mOwner(aOwner),
  8811         mPostData(aPostData),
  8812         mHeadersData(aHeadersData),
  8813         mSHEntry(aSHEntry),
  8814         mFlags(aFlags),
  8815         mLoadType(aLoadType),
  8816         mFirstParty(aFirstParty),
  8817         mSourceDocShell(aSourceDocShell),
  8818         mBaseURI(aBaseURI)
  8820         // Make sure to keep null things null as needed
  8821         if (aTypeHint) {
  8822             mTypeHint = aTypeHint;
  8826     NS_IMETHOD Run() {
  8827         return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
  8828                                        nullptr, mTypeHint.get(),
  8829                                        NullString(), mPostData, mHeadersData,
  8830                                        mLoadType, mSHEntry, mFirstParty,
  8831                                        mSrcdoc, mSourceDocShell, mBaseURI,
  8832                                        nullptr, nullptr);
  8835 private:
  8837     // Use IDL strings so .get() returns null by default
  8838     nsXPIDLString mWindowTarget;
  8839     nsXPIDLCString mTypeHint;
  8840     nsString mSrcdoc;
  8842     nsRefPtr<nsDocShell> mDocShell;
  8843     nsCOMPtr<nsIURI> mURI;
  8844     nsCOMPtr<nsIURI> mReferrer;
  8845     nsCOMPtr<nsISupports> mOwner;
  8846     nsCOMPtr<nsIInputStream> mPostData;
  8847     nsCOMPtr<nsIInputStream> mHeadersData;
  8848     nsCOMPtr<nsISHEntry> mSHEntry;
  8849     uint32_t mFlags;
  8850     uint32_t mLoadType;
  8851     bool mFirstParty;
  8852     nsCOMPtr<nsIDocShell> mSourceDocShell;
  8853     nsCOMPtr<nsIURI> mBaseURI;
  8854 };
  8856 /**
  8857  * Returns true if we started an asynchronous load (i.e., from the network), but
  8858  * the document we're loading there hasn't yet become this docshell's active
  8859  * document.
  8861  * When JustStartedNetworkLoad is true, you should be careful about modifying
  8862  * mLoadType and mLSHE.  These are both set when the asynchronous load first
  8863  * starts, and the load expects that, when it eventually runs InternalLoad,
  8864  * mLoadType and mLSHE will have their original values.
  8865  */
  8866 bool
  8867 nsDocShell::JustStartedNetworkLoad()
  8869     return mDocumentRequest &&
  8870            mDocumentRequest != GetCurrentDocChannel();
  8873 NS_IMETHODIMP
  8874 nsDocShell::InternalLoad(nsIURI * aURI,
  8875                          nsIURI * aReferrer,
  8876                          nsISupports * aOwner,
  8877                          uint32_t aFlags,
  8878                          const char16_t *aWindowTarget,
  8879                          const char* aTypeHint,
  8880                          const nsAString& aFileName,
  8881                          nsIInputStream * aPostData,
  8882                          nsIInputStream * aHeadersData,
  8883                          uint32_t aLoadType,
  8884                          nsISHEntry * aSHEntry,
  8885                          bool aFirstParty,
  8886                          const nsAString &aSrcdoc,
  8887                          nsIDocShell* aSourceDocShell,
  8888                          nsIURI* aBaseURI,
  8889                          nsIDocShell** aDocShell,
  8890                          nsIRequest** aRequest)
  8892     nsresult rv = NS_OK;
  8893     mOriginalUriString.Truncate();
  8895 #ifdef PR_LOGGING
  8896     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
  8897         nsAutoCString spec;
  8898         if (aURI)
  8899             aURI->GetSpec(spec);
  8900         PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
  8902 #endif
  8903     // Initialize aDocShell/aRequest
  8904     if (aDocShell) {
  8905         *aDocShell = nullptr;
  8907     if (aRequest) {
  8908         *aRequest = nullptr;
  8911     if (!aURI) {
  8912         return NS_ERROR_NULL_POINTER;
  8915     NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
  8917     NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
  8919     // wyciwyg urls can only be loaded through history. Any normal load of
  8920     // wyciwyg through docshell is  illegal. Disallow such loads.
  8921     if (aLoadType & LOAD_CMD_NORMAL) {
  8922         bool isWyciwyg = false;
  8923         rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);   
  8924         if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) 
  8925             return NS_ERROR_FAILURE;
  8928     bool bIsJavascript = false;
  8929     if (NS_FAILED(aURI->SchemeIs("javascript", &bIsJavascript))) {
  8930         bIsJavascript = false;
  8933     //
  8934     // First, notify any nsIContentPolicy listeners about the document load.
  8935     // Only abort the load if a content policy listener explicitly vetos it!
  8936     //
  8937     nsCOMPtr<Element> requestingElement;
  8938     // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
  8939     if (mScriptGlobal)
  8940         requestingElement = mScriptGlobal->GetFrameElementInternal();
  8942     nsRefPtr<nsGlobalWindow> MMADeathGrip = mScriptGlobal;
  8944     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
  8945     uint32_t contentType;
  8946     bool isNewDocShell = false;
  8947     bool isTargetTopLevelDocShell = false;
  8948     nsCOMPtr<nsIDocShell> targetDocShell;
  8949     if (aWindowTarget && *aWindowTarget) {
  8950         // Locate the target DocShell.
  8951         nsCOMPtr<nsIDocShellTreeItem> targetItem;
  8952         rv = FindItemWithName(aWindowTarget, nullptr, this,
  8953                               getter_AddRefs(targetItem));
  8954         NS_ENSURE_SUCCESS(rv, rv);
  8956         targetDocShell = do_QueryInterface(targetItem);
  8957         // If the targetDocShell doesn't exist, then this is a new docShell
  8958         // and we should consider this a TYPE_DOCUMENT load
  8959         isNewDocShell = !targetDocShell;
  8961         // If the targetDocShell and the rootDocShell are the same, then the
  8962         // targetDocShell is the top level document and hence we should
  8963         // consider this TYPE_DOCUMENT
  8964         if (targetDocShell) {
  8965           nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
  8966           targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
  8967           NS_ASSERTION(sameTypeRoot, "No document shell root tree item from targetDocShell!");
  8968           nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
  8969           NS_ASSERTION(rootShell, "No root docshell from document shell root tree item.");
  8971           if (targetDocShell == rootShell) {
  8972             isTargetTopLevelDocShell = true;
  8976     if (IsFrame() && !isNewDocShell && !isTargetTopLevelDocShell) {
  8977         NS_ASSERTION(requestingElement, "A frame but no DOM element!?");
  8978         contentType = nsIContentPolicy::TYPE_SUBDOCUMENT;
  8979     } else {
  8980         contentType = nsIContentPolicy::TYPE_DOCUMENT;
  8983     nsISupports* context = requestingElement;
  8984     if (!context) {
  8985         context = ToSupports(mScriptGlobal);
  8988     // XXXbz would be nice to know the loading principal here... but we don't
  8989     nsCOMPtr<nsIPrincipal> loadingPrincipal = do_QueryInterface(aOwner);
  8990     if (!loadingPrincipal && aReferrer) {
  8991         nsCOMPtr<nsIScriptSecurityManager> secMan =
  8992             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  8993         NS_ENSURE_SUCCESS(rv, rv);
  8995         rv = secMan->GetSimpleCodebasePrincipal(aReferrer,
  8996                                                 getter_AddRefs(loadingPrincipal));
  8999     rv = NS_CheckContentLoadPolicy(contentType,
  9000                                    aURI,
  9001                                    loadingPrincipal,
  9002                                    context,
  9003                                    EmptyCString(), //mime guess
  9004                                    nullptr,         //extra
  9005                                    &shouldLoad);
  9007     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
  9008         if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
  9009             return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
  9012         return NS_ERROR_CONTENT_BLOCKED;
  9015     nsCOMPtr<nsISupports> owner(aOwner);
  9016     //
  9017     // Get an owner from the current document if necessary.  Note that we only
  9018     // do this for URIs that inherit a security context and local file URIs;
  9019     // in particular we do NOT do this for about:blank.  This way, random
  9020     // about:blank loads that have no owner (which basically means they were
  9021     // done by someone from chrome manually messing with our nsIWebNavigation
  9022     // or by C++ setting document.location) don't get a funky principal.  If
  9023     // callers want something interesting to happen with the about:blank
  9024     // principal in this case, they should pass an owner in.
  9025     //
  9027         bool inherits;
  9028         // One more twist: Don't inherit the owner for external loads.
  9029         if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
  9030             (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) &&
  9031             NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
  9032                                                                     &inherits)) &&
  9033             inherits) {
  9035             owner = GetInheritedPrincipal(true);
  9039     // Don't allow loads that would inherit our security context
  9040     // if this document came from an unsafe channel.
  9042         bool willInherit;
  9043         // This condition needs to match the one in
  9044         // nsContentUtils::SetUpChannelOwner.
  9045         // Except we reverse the rv check to be safe in case
  9046         // nsContentUtils::URIInheritsSecurityContext fails here and
  9047         // succeeds there.
  9048         rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
  9049         if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
  9050             nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
  9051             do {
  9052                 nsCOMPtr<nsIDocShell> itemDocShell =
  9053                     do_QueryInterface(treeItem);
  9054                 bool isUnsafe;
  9055                 if (itemDocShell &&
  9056                     NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
  9057                     isUnsafe) {
  9058                     return NS_ERROR_DOM_SECURITY_ERR;
  9061                 nsCOMPtr<nsIDocShellTreeItem> parent;
  9062                 treeItem->GetSameTypeParent(getter_AddRefs(parent));
  9063                 parent.swap(treeItem);
  9064             } while (treeItem);
  9068     //
  9069     // Resolve the window target before going any further...
  9070     // If the load has been targeted to another DocShell, then transfer the
  9071     // load to it...
  9072     //
  9073     if (aWindowTarget && *aWindowTarget) {
  9074         // We've already done our owner-inheriting.  Mask out that bit, so we
  9075         // don't try inheriting an owner from the target window if we came up
  9076         // with a null owner above.
  9077         aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
  9079         bool isNewWindow = false;
  9080         if (!targetDocShell) {
  9081             // If the docshell's document is sandboxed, only open a new window
  9082             // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
  9083             // (i.e. if allow-popups is specified)
  9084             NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
  9085             nsIDocument* doc = mContentViewer->GetDocument();
  9086             uint32_t sandboxFlags = 0;
  9088             if (doc) {
  9089                 sandboxFlags = doc->GetSandboxFlags();
  9090                 if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
  9091                     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  9095             nsCOMPtr<nsPIDOMWindow> win =
  9096                 do_GetInterface(GetAsSupports(this));
  9097             NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
  9099             nsDependentString name(aWindowTarget);
  9100             nsCOMPtr<nsIDOMWindow> newWin;
  9101             nsAutoCString spec;
  9102             if (aURI)
  9103                 aURI->GetSpec(spec);
  9104             rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
  9105                                      name,          // window name
  9106                                      EmptyString(), // Features
  9107                                      getter_AddRefs(newWin));
  9109             // In some cases the Open call doesn't actually result in a new
  9110             // window being opened.  We can detect these cases by examining the
  9111             // document in |newWin|, if any.
  9112             nsCOMPtr<nsPIDOMWindow> piNewWin = do_QueryInterface(newWin);
  9113             if (piNewWin) {
  9114                 nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
  9115                 if (!newDoc || newDoc->IsInitialDocument()) {
  9116                     isNewWindow = true;
  9117                     aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
  9121             nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
  9122             targetDocShell = do_QueryInterface(webNav);
  9125         //
  9126         // Transfer the load to the target DocShell...  Pass nullptr as the
  9127         // window target name from to prevent recursive retargeting!
  9128         //
  9129         if (NS_SUCCEEDED(rv) && targetDocShell) {
  9130             rv = targetDocShell->InternalLoad(aURI,
  9131                                               aReferrer,
  9132                                               owner,
  9133                                               aFlags,
  9134                                               nullptr,         // No window target
  9135                                               aTypeHint,
  9136                                               NullString(),    // No forced download
  9137                                               aPostData,
  9138                                               aHeadersData,
  9139                                               aLoadType,
  9140                                               aSHEntry,
  9141                                               aFirstParty,
  9142                                               aSrcdoc,
  9143                                               aSourceDocShell,
  9144                                               aBaseURI,
  9145                                               aDocShell,
  9146                                               aRequest);
  9147             if (rv == NS_ERROR_NO_CONTENT) {
  9148                 // XXXbz except we never reach this code!
  9149                 if (isNewWindow) {
  9150                     //
  9151                     // At this point, a new window has been created, but the
  9152                     // URI did not have any data associated with it...
  9153                     //
  9154                     // So, the best we can do, is to tear down the new window
  9155                     // that was just created!
  9156                     //
  9157                     nsCOMPtr<nsIDOMWindow> domWin =
  9158                         do_GetInterface(targetDocShell);
  9159                     if (domWin) {
  9160                         domWin->Close();
  9163                 //
  9164                 // NS_ERROR_NO_CONTENT should not be returned to the
  9165                 // caller... This is an internal error code indicating that
  9166                 // the URI had no data associated with it - probably a 
  9167                 // helper-app style protocol (ie. mailto://)
  9168                 //
  9169                 rv = NS_OK;
  9171             else if (isNewWindow) {
  9172                 // XXX: Once new windows are created hidden, the new
  9173                 //      window will need to be made visible...  For now,
  9174                 //      do nothing.
  9178         // Else we ran out of memory, or were a popup and got blocked,
  9179         // or something.
  9181         return rv;
  9184     //
  9185     // Load is being targetted at this docshell so return an error if the
  9186     // docshell is in the process of being destroyed.
  9187     //
  9188     if (mIsBeingDestroyed) {
  9189         return NS_ERROR_FAILURE;
  9192     NS_ENSURE_STATE(!HasUnloadedParent());
  9194     rv = CheckLoadingPermissions();
  9195     if (NS_FAILED(rv)) {
  9196         return rv;
  9199     if (mFiredUnloadEvent) {
  9200         if (IsOKToLoadURI(aURI)) {
  9201             NS_PRECONDITION(!aWindowTarget || !*aWindowTarget,
  9202                             "Shouldn't have a window target here!");
  9204             // If this is a replace load, make whatever load triggered
  9205             // the unload event also a replace load, so we don't
  9206             // create extra history entries.
  9207             if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
  9208                 mLoadType = LOAD_NORMAL_REPLACE;
  9211             // Do this asynchronously
  9212             nsCOMPtr<nsIRunnable> ev =
  9213                 new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
  9214                                       aTypeHint, aPostData, aHeadersData,
  9215                                       aLoadType, aSHEntry, aFirstParty, aSrcdoc,
  9216                                       aSourceDocShell, aBaseURI);
  9217             return NS_DispatchToCurrentThread(ev);
  9220         // Just ignore this load attempt
  9221         return NS_OK;
  9224     // If a source docshell has been passed, check to see if we are sandboxed
  9225     // from it as the result of an iframe or CSP sandbox.
  9226     if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
  9227         return NS_ERROR_DOM_INVALID_ACCESS_ERR;
  9230     // If this docshell is owned by a frameloader, make sure to cancel
  9231     // possible frameloader initialization before loading a new page.
  9232     nsCOMPtr<nsIDocShellTreeItem> parent;
  9233     GetParent(getter_AddRefs(parent));
  9234     if (parent) {
  9235         nsCOMPtr<nsIDocument> doc = do_GetInterface(parent);
  9236         if (doc) {
  9237             doc->TryCancelFrameLoaderInitialization(this);
  9241     // Before going any further vet loads initiated by external programs.
  9242     if (aLoadType == LOAD_NORMAL_EXTERNAL) {
  9243         // Disallow external chrome: loads targetted at content windows
  9244         bool isChrome = false;
  9245         if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
  9246             NS_WARNING("blocked external chrome: url -- use '-chrome' option");
  9247             return NS_ERROR_FAILURE;
  9250         // clear the decks to prevent context bleed-through (bug 298255)
  9251         rv = CreateAboutBlankContentViewer(nullptr, nullptr);
  9252         if (NS_FAILED(rv))
  9253             return NS_ERROR_FAILURE;
  9255         // reset loadType so we don't have to add lots of tests for
  9256         // LOAD_NORMAL_EXTERNAL after this point
  9257         aLoadType = LOAD_NORMAL;
  9260     mAllowKeywordFixup =
  9261       (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
  9262     mURIResultedInDocument = false;  // reset the clock...
  9264     if (aLoadType == LOAD_NORMAL ||
  9265         aLoadType == LOAD_STOP_CONTENT ||
  9266         LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
  9267         aLoadType == LOAD_HISTORY ||
  9268         aLoadType == LOAD_LINK) {
  9270         nsCOMPtr<nsIURI> currentURI = mCurrentURI;
  9271         // Split currentURI and aURI on the '#' character.  Make sure we read
  9272         // the return values of SplitURIAtHash; if it fails, we don't want to
  9273         // allow a short-circuited navigation.
  9274         nsAutoCString curBeforeHash, curHash, newBeforeHash, newHash;
  9275         nsresult splitRv1, splitRv2;
  9276         splitRv1 = currentURI ?
  9277             nsContentUtils::SplitURIAtHash(currentURI,
  9278                                            curBeforeHash, curHash) :
  9279             NS_ERROR_FAILURE;
  9280         splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash);
  9282         bool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
  9283                                   NS_SUCCEEDED(splitRv2) &&
  9284                                   curBeforeHash.Equals(newBeforeHash);
  9286         if (!sameExceptHashes && sURIFixup && currentURI &&
  9287             NS_SUCCEEDED(splitRv2)) {
  9288           // Maybe aURI came from the exposable form of currentURI?
  9289           nsCOMPtr<nsIURI> currentExposableURI;
  9290           rv = sURIFixup->CreateExposableURI(currentURI,
  9291                                              getter_AddRefs(currentExposableURI));
  9292           NS_ENSURE_SUCCESS(rv, rv);
  9293           splitRv1 = nsContentUtils::SplitURIAtHash(currentExposableURI,
  9294                                                     curBeforeHash, curHash);
  9295           sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
  9296             curBeforeHash.Equals(newBeforeHash);
  9299         bool historyNavBetweenSameDoc = false;
  9300         if (mOSHE && aSHEntry) {
  9301             // We're doing a history load.
  9303             mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
  9305 #ifdef DEBUG
  9306             if (historyNavBetweenSameDoc) {
  9307                 nsCOMPtr<nsIInputStream> currentPostData;
  9308                 mOSHE->GetPostData(getter_AddRefs(currentPostData));
  9309                 NS_ASSERTION(currentPostData == aPostData,
  9310                              "Different POST data for entries for the same page?");
  9312 #endif
  9315         // A short-circuited load happens when we navigate between two SHEntries
  9316         // for the same document.  We do a short-circuited load under two
  9317         // circumstances.  Either
  9318         //
  9319         //  a) we're navigating between two different SHEntries which share a
  9320         //     document, or
  9321         //
  9322         //  b) we're navigating to a new shentry whose URI differs from the
  9323         //     current URI only in its hash, the new hash is non-empty, and
  9324         //     we're not doing a POST.
  9325         //
  9326         // The restriction tha the SHEntries in (a) must be different ensures
  9327         // that history.go(0) and the like trigger full refreshes, rather than
  9328         // short-circuited loads.
  9329         bool doShortCircuitedLoad =
  9330           (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
  9331           (!aSHEntry && aPostData == nullptr &&
  9332            sameExceptHashes && !newHash.IsEmpty());
  9334         if (doShortCircuitedLoad) {
  9335             // Save the position of the scrollers.
  9336             nscoord cx = 0, cy = 0;
  9337             GetCurScrollPos(ScrollOrientation_X, &cx);
  9338             GetCurScrollPos(ScrollOrientation_Y, &cy);
  9340             // ScrollToAnchor doesn't necessarily cause us to scroll the window;
  9341             // the function decides whether a scroll is appropriate based on the
  9342             // arguments it receives.  But even if we don't end up scrolling,
  9343             // ScrollToAnchor performs other important tasks, such as informing
  9344             // the presShell that we have a new hash.  See bug 680257.
  9345             rv = ScrollToAnchor(curHash, newHash, aLoadType);
  9346             NS_ENSURE_SUCCESS(rv, rv);
  9348             // Reset mLoadType to its original value once we exit this block,
  9349             // because this short-circuited load might have started after a
  9350             // normal, network load, and we don't want to clobber its load type.
  9351             // See bug 737307.
  9352             AutoRestore<uint32_t> loadTypeResetter(mLoadType);
  9354             // If a non-short-circuit load (i.e., a network load) is pending,
  9355             // make this a replacement load, so that we don't add a SHEntry here
  9356             // and the network load goes into the SHEntry it expects to.
  9357             if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
  9358                 mLoadType = LOAD_NORMAL_REPLACE;
  9360             else {
  9361                 mLoadType = aLoadType;
  9364             mURIResultedInDocument = true;
  9366             nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
  9368             /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
  9369              * SetCurrentURI() called from OnNewURI() will send proper
  9370              * onLocationChange() notifications to the browser to update
  9371              * back/forward buttons.
  9372              */
  9373             SetHistoryEntry(&mLSHE, aSHEntry);
  9375             /* This is a anchor traversal with in the same page.
  9376              * call OnNewURI() so that, this traversal will be 
  9377              * recorded in session and global history.
  9378              */
  9379             nsCOMPtr<nsISupports> owner;
  9380             if (mOSHE) {
  9381                 mOSHE->GetOwner(getter_AddRefs(owner));
  9383             // Pass true for aCloneSHChildren, since we're not
  9384             // changing documents here, so all of our subframes are
  9385             // still relevant to the new session history entry.
  9386             //
  9387             // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
  9388             // flag on firing onLocationChange(...).
  9389             // Anyway, aCloneSHChildren param is simply reflecting
  9390             // doShortCircuitedLoad in this scope.
  9391             OnNewURI(aURI, nullptr, owner, mLoadType, true, true, true);
  9393             nsCOMPtr<nsIInputStream> postData;
  9394             nsCOMPtr<nsISupports> cacheKey;
  9396             if (mOSHE) {
  9397                 /* save current position of scroller(s) (bug 59774) */
  9398                 mOSHE->SetScrollPosition(cx, cy);
  9399                 // Get the postdata and page ident from the current page, if
  9400                 // the new load is being done via normal means.  Note that
  9401                 // "normal means" can be checked for just by checking for
  9402                 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
  9403                 // above -- it filters out some LOAD_CMD_NORMAL cases that we
  9404                 // wouldn't want here.
  9405                 if (aLoadType & LOAD_CMD_NORMAL) {
  9406                     mOSHE->GetPostData(getter_AddRefs(postData));
  9407                     mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
  9409                     // Link our new SHEntry to the old SHEntry's back/forward
  9410                     // cache data, since the two SHEntries correspond to the
  9411                     // same document.
  9412                     if (mLSHE)
  9413                         mLSHE->AdoptBFCacheEntry(mOSHE);
  9417             /* Assign mOSHE to mLSHE. This will either be a new entry created
  9418              * by OnNewURI() for normal loads or aSHEntry for history loads.
  9419              */
  9420             if (mLSHE) {
  9421                 SetHistoryEntry(&mOSHE, mLSHE);
  9422                 // Save the postData obtained from the previous page
  9423                 // in to the session history entry created for the 
  9424                 // anchor page, so that any history load of the anchor
  9425                 // page will restore the appropriate postData.
  9426                 if (postData)
  9427                     mOSHE->SetPostData(postData);
  9429                 // Make sure we won't just repost without hitting the
  9430                 // cache first
  9431                 if (cacheKey)
  9432                     mOSHE->SetCacheKey(cacheKey);
  9435             /* restore previous position of scroller(s), if we're moving
  9436              * back in history (bug 59774)
  9437              */
  9438             if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL))
  9440                 nscoord bx, by;
  9441                 mOSHE->GetScrollPosition(&bx, &by);
  9442                 SetCurScrollPosEx(bx, by);
  9445             /* Restore the original LSHE if we were loading something
  9446              * while short-circuited load was initiated.
  9447              */
  9448             SetHistoryEntry(&mLSHE, oldLSHE);
  9449             /* Set the title for the SH entry for this target url. so that
  9450              * SH menus in go/back/forward buttons won't be empty for this.
  9451              */
  9452             if (mSessionHistory) {
  9453                 int32_t index = -1;
  9454                 mSessionHistory->GetIndex(&index);
  9455                 nsCOMPtr<nsISHEntry> shEntry;
  9456                 mSessionHistory->GetEntryAtIndex(index, false,
  9457                                                  getter_AddRefs(shEntry));
  9458                 NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
  9459                 shEntry->SetTitle(mTitle);
  9462             /* Set the title for the Global History entry for this anchor url.
  9463              */
  9464             if (mUseGlobalHistory && !mInPrivateBrowsing) {
  9465                 nsCOMPtr<IHistory> history = services::GetHistoryService();
  9466                 if (history) {
  9467                     history->SetURITitle(aURI, mTitle);
  9469                 else if (mGlobalHistory) {
  9470                     mGlobalHistory->SetPageTitle(aURI, mTitle);
  9474             // Set the doc's URI according to the new history entry's URI.
  9475             nsCOMPtr<nsIDocument> doc =
  9476               do_GetInterface(GetAsSupports(this));
  9477             NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
  9478             doc->SetDocumentURI(aURI);
  9480             SetDocCurrentStateObj(mOSHE);
  9482             // Dispatch the popstate and hashchange events, as appropriate.
  9483             //
  9484             // The event dispatch below can cause us to re-enter script and
  9485             // destroy the docshell, nulling out mScriptGlobal. Hold a stack
  9486             // reference to avoid null derefs. See bug 914521.
  9487             nsRefPtr<nsGlobalWindow> win = mScriptGlobal;
  9488             if (win) {
  9489                 // Fire a hashchange event URIs differ, and only in their hashes.
  9490                 bool doHashchange = sameExceptHashes && !curHash.Equals(newHash);
  9492                 if (historyNavBetweenSameDoc || doHashchange) {
  9493                     win->DispatchSyncPopState();
  9496                 if (doHashchange) {
  9497                     // Note that currentURI hasn't changed because it's on the
  9498                     // stack, so we can just use it directly as the old URI.
  9499                     win->DispatchAsyncHashchange(currentURI, aURI);
  9503             // Inform the favicon service that the favicon for oldURI also
  9504             // applies to aURI.
  9505             CopyFavicon(currentURI, aURI, mInPrivateBrowsing);
  9507             return NS_OK;
  9511     // mContentViewer->PermitUnload can destroy |this| docShell, which
  9512     // causes the next call of CanSavePresentation to crash. 
  9513     // Hold onto |this| until we return, to prevent a crash from happening. 
  9514     // (bug#331040)
  9515     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
  9517     // Don't init timing for javascript:, since it generally doesn't
  9518     // actually start a load or anything.  If it does, we'll init
  9519     // timing then, from OnStateChange.
  9521     // XXXbz mTiming should know what channel it's for, so we don't
  9522     // need this hackery.  Note that this is still broken in cases
  9523     // when we're loading something that's not javascript: and the
  9524     // beforeunload handler denies the load.  That will screw up
  9525     // timing for the next load!
  9526     if (!bIsJavascript) {
  9527         MaybeInitTiming();
  9529     bool timeBeforeUnload = aFileName.IsVoid();
  9530     if (mTiming && timeBeforeUnload) {
  9531       mTiming->NotifyBeforeUnload();
  9533     // Check if the page doesn't want to be unloaded. The javascript:
  9534     // protocol handler deals with this for javascript: URLs.
  9535     if (!bIsJavascript && aFileName.IsVoid() && mContentViewer) {
  9536         bool okToUnload;
  9537         rv = mContentViewer->PermitUnload(false, &okToUnload);
  9539         if (NS_SUCCEEDED(rv) && !okToUnload) {
  9540             // The user chose not to unload the page, interrupt the
  9541             // load.
  9542             return NS_OK;
  9546     if (mTiming && timeBeforeUnload) {
  9547       mTiming->NotifyUnloadAccepted(mCurrentURI);
  9550     // Check for saving the presentation here, before calling Stop().
  9551     // This is necessary so that we can catch any pending requests.
  9552     // Since the new request has not been created yet, we pass null for the
  9553     // new request parameter.
  9554     // Also pass nullptr for the document, since it doesn't affect the return
  9555     // value for our purposes here.
  9556     bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
  9558     // Don't stop current network activity for javascript: URL's since
  9559     // they might not result in any data, and thus nothing should be
  9560     // stopped in those cases. In the case where they do result in
  9561     // data, the javascript: URL channel takes care of stopping
  9562     // current network activity.
  9563     if (!bIsJavascript && aFileName.IsVoid()) {
  9564         // Stop any current network activity.
  9565         // Also stop content if this is a zombie doc. otherwise 
  9566         // the onload will be delayed by other loads initiated in the 
  9567         // background by the first document that
  9568         // didn't fully load before the next load was initiated.
  9569         // If not a zombie, don't stop content until data 
  9570         // starts arriving from the new URI...
  9572         nsCOMPtr<nsIContentViewer> zombieViewer;
  9573         if (mContentViewer) {
  9574             mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
  9577         if (zombieViewer ||
  9578             LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
  9579             rv = Stop(nsIWebNavigation::STOP_ALL);
  9580         } else {
  9581             rv = Stop(nsIWebNavigation::STOP_NETWORK);
  9584         if (NS_FAILED(rv)) 
  9585             return rv;
  9588     mLoadType = aLoadType;
  9590     // mLSHE should be assigned to aSHEntry, only after Stop() has
  9591     // been called. But when loading an error page, do not clear the
  9592     // mLSHE for the real page.
  9593     if (mLoadType != LOAD_ERROR_PAGE)
  9594         SetHistoryEntry(&mLSHE, aSHEntry);
  9596     mSavingOldViewer = savePresentation;
  9598     // If we have a saved content viewer in history, restore and show it now.
  9599     if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
  9600         // Make sure our history ID points to the same ID as
  9601         // SHEntry's docshell ID.
  9602         aSHEntry->GetDocshellID(&mHistoryID);
  9604         // It's possible that the previous viewer of mContentViewer is the
  9605         // viewer that will end up in aSHEntry when it gets closed.  If that's
  9606         // the case, we need to go ahead and force it into its shentry so we
  9607         // can restore it.
  9608         if (mContentViewer) {
  9609             nsCOMPtr<nsIContentViewer> prevViewer;
  9610             mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
  9611             if (prevViewer) {
  9612 #ifdef DEBUG
  9613                 nsCOMPtr<nsIContentViewer> prevPrevViewer;
  9614                 prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
  9615                 NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
  9616 #endif
  9617                 nsCOMPtr<nsISHEntry> viewerEntry;
  9618                 prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
  9619                 if (viewerEntry == aSHEntry) {
  9620                     // Make sure this viewer ends up in the right place
  9621                     mContentViewer->SetPreviousViewer(nullptr);
  9622                     prevViewer->Destroy();
  9626         nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
  9627         bool restoring;
  9628         rv = RestorePresentation(aSHEntry, &restoring);
  9629         if (restoring)
  9630             return rv;
  9632         // We failed to restore the presentation, so clean up.
  9633         // Both the old and new history entries could potentially be in
  9634         // an inconsistent state.
  9635         if (NS_FAILED(rv)) {
  9636             if (oldEntry)
  9637                 oldEntry->SyncPresentationState();
  9639             aSHEntry->SyncPresentationState();
  9643     nsAutoString srcdoc;
  9644     if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC)
  9645       srcdoc = aSrcdoc;
  9646     else
  9647       srcdoc = NullString();
  9649     mozilla::net::SeerPredict(aURI, nullptr, nsINetworkSeer::PREDICT_LOAD,
  9650                               this, nullptr);
  9652     nsCOMPtr<nsIRequest> req;
  9653     rv = DoURILoad(aURI, aReferrer,
  9654                    !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
  9655                    owner, aTypeHint, aFileName, aPostData, aHeadersData,
  9656                    aFirstParty, aDocShell, getter_AddRefs(req),
  9657                    (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
  9658                    (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
  9659                    (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
  9660                    srcdoc, aBaseURI);
  9661     if (req && aRequest)
  9662         NS_ADDREF(*aRequest = req);
  9664     if (NS_FAILED(rv)) {
  9665         nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
  9666         DisplayLoadError(rv, aURI, nullptr, chan);
  9669     return rv;
  9672 nsIPrincipal*
  9673 nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
  9675     nsCOMPtr<nsIDocument> document;
  9676     bool inheritedFromCurrent = false;
  9678     if (aConsiderCurrentDocument && mContentViewer) {
  9679         document = mContentViewer->GetDocument();
  9680         inheritedFromCurrent = true;
  9683     if (!document) {
  9684         nsCOMPtr<nsIDocShellTreeItem> parentItem;
  9685         GetSameTypeParent(getter_AddRefs(parentItem));
  9686         if (parentItem) {
  9687             document = do_GetInterface(parentItem);
  9691     if (!document) {
  9692         if (!aConsiderCurrentDocument) {
  9693             return nullptr;
  9696         // Make sure we end up with _something_ as the principal no matter
  9697         // what.
  9698         EnsureContentViewer();  // If this fails, we'll just get a null
  9699                                 // docViewer and bail.
  9701         if (!mContentViewer)
  9702             return nullptr;
  9703         document = mContentViewer->GetDocument();
  9706     //-- Get the document's principal
  9707     if (document) {
  9708         nsIPrincipal *docPrincipal = document->NodePrincipal();
  9710         // Don't allow loads in typeContent docShells to inherit the system
  9711         // principal from existing documents.
  9712         if (inheritedFromCurrent &&
  9713             mItemType == typeContent &&
  9714             nsContentUtils::IsSystemPrincipal(docPrincipal)) {
  9715             return nullptr;
  9718         return docPrincipal;
  9721     return nullptr;
  9724 nsresult
  9725 nsDocShell::DoURILoad(nsIURI * aURI,
  9726                       nsIURI * aReferrerURI,
  9727                       bool aSendReferrer,
  9728                       nsISupports * aOwner,
  9729                       const char * aTypeHint,
  9730                       const nsAString & aFileName,
  9731                       nsIInputStream * aPostData,
  9732                       nsIInputStream * aHeadersData,
  9733                       bool aFirstParty,
  9734                       nsIDocShell ** aDocShell,
  9735                       nsIRequest ** aRequest,
  9736                       bool aIsNewWindowTarget,
  9737                       bool aBypassClassifier,
  9738                       bool aForceAllowCookies,
  9739                       const nsAString &aSrcdoc,
  9740                       nsIURI * aBaseURI)
  9742 #ifdef MOZ_VISUAL_EVENT_TRACER
  9743     nsAutoCString urlSpec;
  9744     aURI->GetAsciiSpec(urlSpec);
  9745     MOZ_EVENT_TRACER_NAME_OBJECT(this, urlSpec.BeginReading());
  9746     MOZ_EVENT_TRACER_EXEC(this, "docshell::pageload");
  9747 #endif
  9749     nsresult rv;
  9750     nsCOMPtr<nsIURILoader> uriLoader;
  9752     uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
  9753     if (NS_FAILED(rv)) return rv;
  9755     nsLoadFlags loadFlags = mDefaultLoadFlags;
  9756     if (aFirstParty) {
  9757         // tag first party URL loads
  9758         loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
  9761     if (mLoadType == LOAD_ERROR_PAGE) {
  9762         // Error pages are LOAD_BACKGROUND
  9763         loadFlags |= nsIChannel::LOAD_BACKGROUND;
  9766     // check for Content Security Policy to pass along with the
  9767     // new channel we are creating
  9768     nsCOMPtr<nsIChannelPolicy> channelPolicy;
  9769     if (IsFrame()) {
  9770         // check the parent docshell for a CSP
  9771         nsCOMPtr<nsIContentSecurityPolicy> csp;
  9772         nsCOMPtr<nsIDocShellTreeItem> parentItem;
  9773         GetSameTypeParent(getter_AddRefs(parentItem));
  9774         nsCOMPtr<nsIDocument> doc = do_GetInterface(parentItem);
  9775         if (doc) {
  9776             rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
  9777             NS_ENSURE_SUCCESS(rv, rv);
  9778             if (csp) {
  9779                 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
  9780                 channelPolicy->SetContentSecurityPolicy(csp);
  9781                 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
  9785         // Only allow view-source scheme in top-level docshells. view-source is
  9786         // the only scheme to which this applies at the moment due to potential
  9787         // timing attacks to read data from cross-origin iframes. If this widens
  9788         // we should add a protocol flag for whether the scheme is allowed in
  9789         // frames and use something like nsNetUtil::NS_URIChainHasFlags.
  9790         nsCOMPtr<nsIURI> tempURI = aURI;
  9791         nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
  9792         while (nestedURI) {
  9793             // view-source should always be an nsINestedURI, loop and check the
  9794             // scheme on this and all inner URIs that are also nested URIs.
  9795             bool isViewSource = false;
  9796             rv = tempURI->SchemeIs("view-source", &isViewSource);
  9797             if (NS_FAILED(rv) || isViewSource) {
  9798                 return NS_ERROR_UNKNOWN_PROTOCOL;
  9800             nestedURI->GetInnerURI(getter_AddRefs(tempURI));
  9801             nestedURI = do_QueryInterface(tempURI);
  9805     // open a channel for the url
  9806     nsCOMPtr<nsIChannel> channel;
  9808     bool isSrcdoc = !aSrcdoc.IsVoid();
  9809     if (!isSrcdoc) {
  9810         rv = NS_NewChannel(getter_AddRefs(channel),
  9811                            aURI,
  9812                            nullptr,
  9813                            nullptr,
  9814                            static_cast<nsIInterfaceRequestor *>(this),
  9815                            loadFlags,
  9816                            channelPolicy);
  9817         if (NS_FAILED(rv)) {
  9818             if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
  9819                 // This is a uri with a protocol scheme we don't know how
  9820                 // to handle.  Embedders might still be interested in
  9821                 // handling the load, though, so we fire a notification
  9822                 // before throwing the load away.
  9823                 bool abort = false;
  9824                 nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
  9825                 if (NS_SUCCEEDED(rv2) && abort) {
  9826                     // Hey, they're handling the load for us!  How convenient!
  9827                     return NS_OK;
  9830             return rv;
  9832         if (aBaseURI) {
  9833             nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
  9834             if (vsc) {
  9835                 vsc->SetBaseURI(aBaseURI);
  9839     else {
  9840         nsAutoCString scheme;
  9841         rv = aURI->GetScheme(scheme);
  9842         NS_ENSURE_SUCCESS(rv,rv);
  9843         bool isViewSource;
  9844         aURI->SchemeIs("view-source",&isViewSource);
  9846         if (isViewSource) {
  9847             nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance();
  9848             NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE);
  9850             rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, aBaseURI,
  9851                                        getter_AddRefs(channel));
  9852             NS_ENSURE_SUCCESS(rv, rv);
  9854         else {
  9855             rv = NS_NewInputStreamChannel(getter_AddRefs(channel),aURI,
  9856                                           aSrcdoc,
  9857                                           NS_LITERAL_CSTRING("text/html"),
  9858                                           true);
  9859             NS_ENSURE_SUCCESS(rv, rv);
  9860             nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
  9861             MOZ_ASSERT(isc);
  9862             isc->SetBaseURI(aBaseURI);
  9866     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
  9867         do_QueryInterface(channel);
  9868     if (appCacheChannel) {
  9869         // Any document load should not inherit application cache.
  9870         appCacheChannel->SetInheritApplicationCache(false);
  9872         // Loads with the correct permissions should check for a matching
  9873         // application cache.
  9874         if (GeckoProcessType_Default != XRE_GetProcessType()) {
  9875             // Permission will be checked in the parent process
  9876             appCacheChannel->SetChooseApplicationCache(true);
  9877         } else {
  9878             nsCOMPtr<nsIScriptSecurityManager> secMan =
  9879                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
  9881             if (secMan) {
  9882                 nsCOMPtr<nsIPrincipal> principal;
  9883                 secMan->GetDocShellCodebasePrincipal(aURI, this, getter_AddRefs(principal));
  9884                 appCacheChannel->SetChooseApplicationCache(
  9885                     NS_ShouldCheckAppCache(principal, mInPrivateBrowsing));
  9890     // Make sure to give the caller a channel if we managed to create one
  9891     // This is important for correct error page/session history interaction
  9892     if (aRequest)
  9893         NS_ADDREF(*aRequest = channel);
  9895     channel->SetOriginalURI(aURI);
  9896     if (aTypeHint && *aTypeHint) {
  9897         channel->SetContentType(nsDependentCString(aTypeHint));
  9898         mContentTypeHint = aTypeHint;
  9899     } else {
  9900         mContentTypeHint.Truncate();
  9903     if (!aFileName.IsVoid()) {
  9904         rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
  9905         NS_ENSURE_SUCCESS(rv, rv);
  9906         if (!aFileName.IsEmpty()) {
  9907             rv = channel->SetContentDispositionFilename(aFileName);
  9908             NS_ENSURE_SUCCESS(rv, rv);
  9912     if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
  9913         mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
  9914           rv = SetMixedContentChannel(channel);
  9915           NS_ENSURE_SUCCESS(rv, rv);
  9916     } else if (mMixedContentChannel) {
  9917       /*
  9918        * If the user "Disables Protection on This Page", we call
  9919        * SetMixedContentChannel for the first time, otherwise
  9920        * mMixedContentChannel is still null.
  9921        * Later, if the new channel passes a same orign check, we remember the
  9922        * users decision by calling SetMixedContentChannel using the new channel.
  9923        * This way, the user does not have to click the disable protection button
  9924        * over and over for browsing the same site.
  9925        */
  9926       rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel);
  9927       if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) {
  9928         SetMixedContentChannel(nullptr);
  9932     //hack
  9933     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  9934     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
  9935     if (httpChannelInternal) {
  9936       if (aForceAllowCookies) {
  9937         httpChannelInternal->SetForceAllowThirdPartyCookie(true);
  9939       if (aFirstParty) {
  9940         httpChannelInternal->SetDocumentURI(aURI);
  9941       } else {
  9942         httpChannelInternal->SetDocumentURI(aReferrerURI);
  9946     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
  9947     if (props)
  9949       // save true referrer for those who need it (e.g. xpinstall whitelisting)
  9950       // Currently only http and ftp channels support this.
  9951       props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
  9952                                     aReferrerURI);
  9955     //
  9956     // If this is a HTTP channel, then set up the HTTP specific information
  9957     // (ie. POST data, referrer, ...)
  9958     //
  9959     if (httpChannel) {
  9960         nsCOMPtr<nsICachingChannel>  cacheChannel(do_QueryInterface(httpChannel));
  9961         /* Get the cache Key from SH */
  9962         nsCOMPtr<nsISupports> cacheKey;
  9963         if (mLSHE) {
  9964             mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
  9966         else if (mOSHE)          // for reload cases
  9967             mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
  9969         // figure out if we need to set the post data stream on the channel...
  9970         // right now, this is only done for http channels.....
  9971         if (aPostData) {
  9972             // XXX it's a bit of a hack to rewind the postdata stream here but
  9973             // it has to be done in case the post data is being reused multiple
  9974             // times.
  9975             nsCOMPtr<nsISeekableStream>
  9976                 postDataSeekable(do_QueryInterface(aPostData));
  9977             if (postDataSeekable) {
  9978                 rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
  9979                 NS_ENSURE_SUCCESS(rv, rv);
  9982             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
  9983             NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
  9985             // we really need to have a content type associated with this stream!!
  9986             uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1);
  9987             /* If there is a valid postdata *and* it is a History Load,
  9988              * set up the cache key on the channel, to retrieve the
  9989              * data *only* from the cache. If it is a normal reload, the 
  9990              * cache is free to go to the server for updated postdata. 
  9991              */
  9992             if (cacheChannel && cacheKey) {
  9993                 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
  9994                     cacheChannel->SetCacheKey(cacheKey);
  9995                     uint32_t loadFlags;
  9996                     if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags)))
  9997                         channel->SetLoadFlags(loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
  9999                 else if (mLoadType == LOAD_RELOAD_NORMAL)
 10000                     cacheChannel->SetCacheKey(cacheKey);
 10003         else {
 10004             /* If there is no postdata, set the cache key on the channel, and
 10005              * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
 10006              * will be free to get it from net if it is not found in cache.
 10007              * New cache may use it creatively on CGI pages with GET
 10008              * method and even on those that say "no-cache"
 10009              */
 10010             if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL 
 10011                 || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
 10012                 if (cacheChannel && cacheKey)
 10013                     cacheChannel->SetCacheKey(cacheKey);
 10016         if (aHeadersData) {
 10017             rv = AddHeadersToChannel(aHeadersData, httpChannel);
 10019         // Set the referrer explicitly
 10020         if (aReferrerURI && aSendReferrer) {
 10021             // Referrer is currenly only set for link clicks here.
 10022             httpChannel->SetReferrer(aReferrerURI);
 10026     nsCOMPtr<nsIPrincipal> ownerPrincipal;
 10028     // If the content being loaded should be sandboxed with respect to origin
 10029     // we need to create a new null principal here, and then tell
 10030     // nsContentUtils::SetUpChannelOwner to force it to be set as the
 10031     // channel owner.
 10032     if (mSandboxFlags & SANDBOXED_ORIGIN) {
 10033         ownerPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
 10034     } else {
 10035         // Not sandboxed - we allow the content to assume its natural owner.
 10036         ownerPrincipal = do_QueryInterface(aOwner);
 10039     nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true,
 10040                                       (mSandboxFlags & SANDBOXED_ORIGIN) ||
 10041                                       isSrcdoc);
 10043     nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
 10044     if (scriptChannel) {
 10045         // Allow execution against our context if the principals match
 10046         scriptChannel->
 10047             SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
 10050     if (aIsNewWindowTarget) {
 10051         nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
 10052         if (props) {
 10053             props->SetPropertyAsBool(
 10054                 NS_LITERAL_STRING("docshell.newWindowTarget"),
 10055                 true);
 10059     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
 10060     if (timedChannel) {
 10061         timedChannel->SetTimingEnabled(true);
 10062         if (IsFrame()) {
 10063             timedChannel->SetInitiatorType(NS_LITERAL_STRING("subdocument"));
 10067     rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
 10069     //
 10070     // If the channel load failed, we failed and nsIWebProgress just ain't
 10071     // gonna happen.
 10072     //
 10073     if (NS_SUCCEEDED(rv)) {
 10074         if (aDocShell) {
 10075           *aDocShell = this;
 10076           NS_ADDREF(*aDocShell);
 10080     return rv;
 10083 static NS_METHOD
 10084 AppendSegmentToString(nsIInputStream *in,
 10085                       void *closure,
 10086                       const char *fromRawSegment,
 10087                       uint32_t toOffset,
 10088                       uint32_t count,
 10089                       uint32_t *writeCount)
 10091     // aFromSegment now contains aCount bytes of data.
 10093     nsAutoCString *buf = static_cast<nsAutoCString *>(closure);
 10094     buf->Append(fromRawSegment, count);
 10096     // Indicate that we have consumed all of aFromSegment
 10097     *writeCount = count;
 10098     return NS_OK;
 10101 NS_IMETHODIMP
 10102 nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData,
 10103                                 nsIChannel *aGenericChannel)
 10105     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
 10106     NS_ENSURE_STATE(httpChannel);
 10108     uint32_t numRead;
 10109     nsAutoCString headersString;
 10110     nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
 10111                                              &headersString,
 10112                                              UINT32_MAX,
 10113                                              &numRead);
 10114     NS_ENSURE_SUCCESS(rv, rv);
 10116     // used during the manipulation of the String from the InputStream
 10117     nsAutoCString headerName;
 10118     nsAutoCString headerValue;
 10119     int32_t crlf;
 10120     int32_t colon;
 10122     //
 10123     // Iterate over the headersString: for each "\r\n" delimited chunk,
 10124     // add the value as a header to the nsIHttpChannel
 10125     //
 10127     static const char kWhitespace[] = "\b\t\r\n ";
 10128     while (true) {
 10129         crlf = headersString.Find("\r\n");
 10130         if (crlf == kNotFound)
 10131             return NS_OK;
 10133         const nsCSubstring &oneHeader = StringHead(headersString, crlf);
 10135         colon = oneHeader.FindChar(':');
 10136         if (colon == kNotFound)
 10137             return NS_ERROR_UNEXPECTED;
 10139         headerName = StringHead(oneHeader, colon);
 10140         headerValue = Substring(oneHeader, colon + 1);
 10142         headerName.Trim(kWhitespace);
 10143         headerValue.Trim(kWhitespace);
 10145         headersString.Cut(0, crlf + 2);
 10147         //
 10148         // FINALLY: we can set the header!
 10149         // 
 10151         rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
 10152         NS_ENSURE_SUCCESS(rv, rv);
 10155     NS_NOTREACHED("oops");
 10156     return NS_ERROR_UNEXPECTED;
 10159 nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
 10160                                    nsIURILoader * aURILoader,
 10161                                    bool aBypassClassifier)
 10163     nsresult rv;
 10164     // Mark the channel as being a document URI and allow content sniffing...
 10165     nsLoadFlags loadFlags = 0;
 10166     (void) aChannel->GetLoadFlags(&loadFlags);
 10167     loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
 10168                  nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
 10170     // Load attributes depend on load type...
 10171     switch (mLoadType) {
 10172     case LOAD_HISTORY:
 10174             // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
 10175             // push/replaceState (bug 669671).
 10176             bool uriModified = false;
 10177             if (mLSHE) {
 10178                 mLSHE->GetURIWasModified(&uriModified);
 10181             if (!uriModified)
 10182                 loadFlags |= nsIRequest::VALIDATE_NEVER;
 10184         break;
 10186     case LOAD_RELOAD_CHARSET_CHANGE:
 10187         loadFlags |= nsIRequest::LOAD_FROM_CACHE;
 10188         break;
 10190     case LOAD_RELOAD_NORMAL:
 10191     case LOAD_REFRESH:
 10192         loadFlags |= nsIRequest::VALIDATE_ALWAYS;
 10193         break;
 10195     case LOAD_NORMAL_BYPASS_CACHE:
 10196     case LOAD_NORMAL_BYPASS_PROXY:
 10197     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
 10198     case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
 10199     case LOAD_RELOAD_BYPASS_CACHE:
 10200     case LOAD_RELOAD_BYPASS_PROXY:
 10201     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
 10202     case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
 10203     case LOAD_REPLACE_BYPASS_CACHE:
 10204         loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
 10205                      nsIRequest::LOAD_FRESH_CONNECTION;
 10206         break;
 10208     case LOAD_NORMAL:
 10209     case LOAD_LINK:
 10210         // Set cache checking flags
 10211         switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
 10212         case 0:
 10213             loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
 10214             break;
 10215         case 1:
 10216             loadFlags |= nsIRequest::VALIDATE_ALWAYS;
 10217             break;
 10218         case 2:
 10219             loadFlags |= nsIRequest::VALIDATE_NEVER;
 10220             break;
 10222         break;
 10225     if (!aBypassClassifier) {
 10226         loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
 10229     (void) aChannel->SetLoadFlags(loadFlags);
 10231     uint32_t openFlags = 0;
 10232     if (mLoadType == LOAD_LINK) {
 10233         openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
 10235     if (!mAllowContentRetargeting) {
 10236         openFlags |= nsIURILoader::DONT_RETARGET;
 10238     rv = aURILoader->OpenURI(aChannel, openFlags, this);
 10239     NS_ENSURE_SUCCESS(rv, rv);
 10241     return NS_OK;
 10244 nsresult
 10245 nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
 10246                            uint32_t aLoadType)
 10248     if (!mCurrentURI) {
 10249         return NS_OK;
 10252     nsCOMPtr<nsIPresShell> shell = GetPresShell();
 10253     if (!shell) {
 10254         // If we failed to get the shell, or if there is no shell,
 10255         // nothing left to do here.
 10256         return NS_OK;
 10259     nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
 10260     if (rootScroll) {
 10261         rootScroll->ClearDidHistoryRestore();
 10264     // If we have no new anchor, we do not want to scroll, unless there is a
 10265     // current anchor and we are doing a history load.  So return if we have no
 10266     // new anchor, and there is no current anchor or the load is not a history
 10267     // load.
 10268     if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) &&
 10269         aNewHash.IsEmpty()) {
 10270         return NS_OK;
 10273     // Take the '#' off aNewHash to get the ref name.  (aNewHash might be empty,
 10274     // but that's fine.)
 10275     nsDependentCSubstring newHashName(aNewHash, 1);
 10277     // Both the new and current URIs refer to the same page. We can now
 10278     // browse to the hash stored in the new URI.
 10280     if (!newHashName.IsEmpty()) {
 10281         // anchor is there, but if it's a load from history,
 10282         // we don't have any anchor jumping to do
 10283         bool scroll = aLoadType != LOAD_HISTORY &&
 10284                         aLoadType != LOAD_RELOAD_NORMAL;
 10286         char *str = ToNewCString(newHashName);
 10287         if (!str) {
 10288             return NS_ERROR_OUT_OF_MEMORY;
 10291         // nsUnescape modifies the string that is passed into it.
 10292         nsUnescape(str);
 10294         // We assume that the bytes are in UTF-8, as it says in the
 10295         // spec:
 10296         // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
 10298         // We try the UTF-8 string first, and then try the document's
 10299         // charset (see below).  If the string is not UTF-8,
 10300         // conversion will fail and give us an empty Unicode string.
 10301         // In that case, we should just fall through to using the
 10302         // page's charset.
 10303         nsresult rv = NS_ERROR_FAILURE;
 10304         NS_ConvertUTF8toUTF16 uStr(str);
 10305         if (!uStr.IsEmpty()) {
 10306             rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll);
 10308         nsMemory::Free(str);
 10310         // Above will fail if the anchor name is not UTF-8.  Need to
 10311         // convert from document charset to unicode.
 10312         if (NS_FAILED(rv)) {
 10314             // Get a document charset
 10315             NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
 10316             nsIDocument* doc = mContentViewer->GetDocument();
 10317             NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 10318             const nsACString &aCharset = doc->GetDocumentCharacterSet();
 10320             nsCOMPtr<nsITextToSubURI> textToSubURI =
 10321                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
 10322             NS_ENSURE_SUCCESS(rv, rv);
 10324             // Unescape and convert to unicode
 10325             nsXPIDLString uStr;
 10327             rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
 10328                                                   PromiseFlatCString(newHashName).get(),
 10329                                                   getter_Copies(uStr));
 10330             NS_ENSURE_SUCCESS(rv, rv);
 10332             // Ignore return value of GoToAnchor, since it will return an error
 10333             // if there is no such anchor in the document, which is actually a
 10334             // success condition for us (we want to update the session history
 10335             // with the new URI no matter whether we actually scrolled
 10336             // somewhere).
 10337             //
 10338             // When newHashName contains "%00", unescaped string may be empty.
 10339             // And GoToAnchor asserts if we ask it to scroll to an empty ref.
 10340             shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty());
 10343     else {
 10345         // Tell the shell it's at an anchor, without scrolling.
 10346         shell->GoToAnchor(EmptyString(), false);
 10348         // An empty anchor was found, but if it's a load from history,
 10349         // we don't have to jump to the top of the page. Scrollbar 
 10350         // position will be restored by the caller, based on positions
 10351         // stored in session history.
 10352         if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
 10353             return NS_OK;
 10354         // An empty anchor. Scroll to the top of the page.  Ignore the
 10355         // return value; failure to scroll here (e.g. if there is no
 10356         // root scrollframe) is not grounds for canceling the load!
 10357         SetCurScrollPosEx(0, 0);
 10360     return NS_OK;
 10363 void
 10364 nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
 10366     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
 10367     if (httpChannel) {
 10368         nsCOMPtr<nsIURI> referrer;
 10369         nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
 10370         if (NS_SUCCEEDED(rv)) {
 10371             SetReferrerURI(referrer);
 10376 bool
 10377 nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
 10378                      uint32_t aLoadType, bool aFireOnLocationChange,
 10379                      bool aAddToGlobalHistory, bool aCloneSHChildren)
 10381     NS_PRECONDITION(aURI, "uri is null");
 10382     NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
 10384 #if defined(PR_LOGGING) && defined(DEBUG)
 10385     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
 10386         nsAutoCString spec;
 10387         aURI->GetSpec(spec);
 10389         nsAutoCString chanName;
 10390         if (aChannel)
 10391             aChannel->GetName(chanName);
 10392         else
 10393             chanName.AssignLiteral("<no channel>");
 10395         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
 10396                ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
 10397                 chanName.get(), aLoadType));
 10399 #endif
 10401     bool equalUri = false;
 10403     // Get the post data and the HTTP response code from the channel.
 10404     uint32_t responseStatus = 0;
 10405     nsCOMPtr<nsIInputStream> inputStream;
 10406     if (aChannel) {
 10407         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
 10409         // Check if the HTTPChannel is hiding under a multiPartChannel
 10410         if (!httpChannel)  {
 10411             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
 10414         if (httpChannel) {
 10415             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
 10416             if (uploadChannel) {
 10417                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
 10420             // If the response status indicates an error, unlink this session
 10421             // history entry from any entries sharing its document.
 10422             nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
 10423             if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
 10424                 mLSHE->AbandonBFCacheEntry();
 10429     // Determine if this type of load should update history.
 10430     bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY ||
 10431                             aLoadType == LOAD_ERROR_PAGE ||
 10432                             aLoadType & LOAD_CMD_HISTORY);
 10434     // We don't update session history on reload.
 10435     bool updateSHistory = updateGHistory && (!(aLoadType & LOAD_CMD_RELOAD));
 10437     /* Create SH Entry (mLSHE) only if there is a  SessionHistory object (mSessionHistory) in
 10438      * the current frame or in the root docshell
 10439      */
 10440     nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
 10441     if (!rootSH) {
 10442         // Get the handle to SH from the root docshell          
 10443         GetRootSessionHistory(getter_AddRefs(rootSH));
 10444         if (!rootSH) {
 10445             updateSHistory = false;
 10446             updateGHistory = false; // XXX Why global history too?
 10448     }  // rootSH
 10450     // Check if the url to be loaded is the same as the one already loaded.
 10451     if (mCurrentURI)
 10452         aURI->Equals(mCurrentURI, &equalUri);
 10454 #ifdef DEBUG
 10455     bool shAvailable = (rootSH != nullptr);
 10457     // XXX This log message is almost useless because |updateSHistory|
 10458     //     and |updateGHistory| are not correct at this point.
 10460     PR_LOG(gDocShellLog, PR_LOG_DEBUG,
 10461            ("  shAvailable=%i updateSHistory=%i updateGHistory=%i"
 10462             " equalURI=%i\n",
 10463             shAvailable, updateSHistory, updateGHistory, equalUri));
 10465     if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
 10466         NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?");
 10468 #endif
 10470     /* If the url to be loaded is the same as the one already there,
 10471      * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
 10472      * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
 10473      * AddToSessionHistory() won't mess with the current SHEntry and
 10474      * if this page has any frame children, it also will be handled
 10475      * properly. see bug 83684
 10477      * NB: If mOSHE is null but we have a current URI, then it means
 10478      * that we must be at the transient about:blank content viewer
 10479      * (asserted above) and we should let the normal load continue,
 10480      * since there's nothing to replace.
 10482      * XXX Hopefully changing the loadType at this time will not hurt  
 10483      *  anywhere. The other way to take care of sequentially repeating
 10484      *  frameset pages is to add new methods to nsIDocShellTreeItem.
 10485      * Hopefully I don't have to do that. 
 10486      */
 10487     if (equalUri &&
 10488         mOSHE &&
 10489         (mLoadType == LOAD_NORMAL ||
 10490          mLoadType == LOAD_LINK ||
 10491          mLoadType == LOAD_STOP_CONTENT) &&
 10492         !inputStream)
 10494         mLoadType = LOAD_NORMAL_REPLACE;
 10497     // If this is a refresh to the currently loaded url, we don't
 10498     // have to update session or global history.
 10499     if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
 10500         SetHistoryEntry(&mLSHE, mOSHE);
 10503     /* If the user pressed shift-reload, cache will create a new cache key
 10504      * for the page. Save the new cacheKey in Session History. 
 10505      * see bug 90098
 10506      */
 10507     if (aChannel &&
 10508         (aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
 10509          aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
 10510          aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
 10511          aLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT)) {
 10512         NS_ASSERTION(!updateSHistory,
 10513                      "We shouldn't be updating session history for forced"
 10514                      " reloads!");
 10516         nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
 10517         nsCOMPtr<nsISupports>  cacheKey;
 10518         // Get the Cache Key and store it in SH.
 10519         if (cacheChannel)
 10520             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
 10521         // If we already have a loading history entry, store the new cache key
 10522         // in it.  Otherwise, since we're doing a reload and won't be updating
 10523         // our history entry, store the cache key in our current history entry.
 10524         if (mLSHE)
 10525             mLSHE->SetCacheKey(cacheKey);
 10526         else if (mOSHE)
 10527             mOSHE->SetCacheKey(cacheKey);
 10529         // Since we're force-reloading, clear all the sub frame history.
 10530         ClearFrameHistory(mLSHE);
 10531         ClearFrameHistory(mOSHE);
 10534     if (aLoadType == LOAD_RELOAD_NORMAL) {
 10535         nsCOMPtr<nsISHEntry> currentSH;
 10536         bool oshe = false;
 10537         GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
 10538         bool dynamicallyAddedChild = false;
 10539         if (currentSH) {
 10540           currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
 10542         if (dynamicallyAddedChild) {
 10543           ClearFrameHistory(currentSH);
 10547     if (aLoadType == LOAD_REFRESH) {
 10548         ClearFrameHistory(mLSHE);
 10549         ClearFrameHistory(mOSHE);
 10552     if (updateSHistory) { 
 10553         // Update session history if necessary...
 10554         if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
 10555             /* This is  a fresh page getting loaded for the first time
 10556              *.Create a Entry for it and add it to SH, if this is the
 10557              * rootDocShell
 10558              */
 10559             (void) AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren,
 10560                                        getter_AddRefs(mLSHE));
 10564     // If this is a POST request, we do not want to include this in global
 10565     // history.
 10566     if (updateGHistory &&
 10567         aAddToGlobalHistory && 
 10568         !ChannelIsPost(aChannel)) {
 10569         nsCOMPtr<nsIURI> previousURI;
 10570         uint32_t previousFlags = 0;
 10572         if (aLoadType & LOAD_CMD_RELOAD) {
 10573             // On a reload request, we don't set redirecting flags.
 10574             previousURI = aURI;
 10575         } else {
 10576             ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
 10577                              &previousFlags);
 10580         // Note: We don't use |referrer| when our global history is
 10581         //       based on IHistory.
 10582         nsCOMPtr<nsIURI> referrer;
 10583         // Treat referrer as null if there is an error getting it.
 10584         (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
 10586         AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
 10589     // If this was a history load or a refresh,
 10590     // update the index in SH. 
 10591     if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) {
 10592         nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
 10593         if (shInternal) {
 10594             rootSH->GetIndex(&mPreviousTransIndex);
 10595             shInternal->UpdateIndex();
 10596             rootSH->GetIndex(&mLoadedTransIndex);
 10597 #ifdef DEBUG_PAGE_CACHE
 10598             printf("Previous index: %d, Loaded index: %d\n\n",
 10599                    mPreviousTransIndex, mLoadedTransIndex);
 10600 #endif
 10604     // aCloneSHChildren exactly means "we are not loading a new document".
 10605     uint32_t locationFlags = aCloneSHChildren?
 10606                                  uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
 10608     bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
 10609                                                 aFireOnLocationChange,
 10610                                                 locationFlags);
 10611     // Make sure to store the referrer from the channel, if any
 10612     SetupReferrerFromChannel(aChannel);
 10613     return onLocationChangeNeeded;
 10616 bool
 10617 nsDocShell::OnLoadingSite(nsIChannel * aChannel, bool aFireOnLocationChange,
 10618                           bool aAddToGlobalHistory)
 10620     nsCOMPtr<nsIURI> uri;
 10621     // If this a redirect, use the final url (uri)
 10622     // else use the original url
 10623     //
 10624     // Note that this should match what documents do (see nsDocument::Reset).
 10625     NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
 10626     NS_ENSURE_TRUE(uri, false);
 10628     // Pass false for aCloneSHChildren, since we're loading a new page here.
 10629     return OnNewURI(uri, aChannel, nullptr, mLoadType, aFireOnLocationChange,
 10630                     aAddToGlobalHistory, false);
 10634 void
 10635 nsDocShell::SetReferrerURI(nsIURI * aURI)
 10637     mReferrerURI = aURI;        // This assigment addrefs
 10640 //*****************************************************************************
 10641 // nsDocShell: Session History
 10642 //*****************************************************************************
 10644 NS_IMETHODIMP
 10645 nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
 10646                      const nsAString& aURL, bool aReplace, JSContext* aCx)
 10648     // Implements History.pushState and History.replaceState
 10650     // Here's what we do, roughly in the order specified by HTML5:
 10651     // 1. Serialize aData using structured clone.
 10652     // 2. If the third argument is present,
 10653     //     a. Resolve the url, relative to the first script's base URL
 10654     //     b. If (a) fails, raise a SECURITY_ERR
 10655     //     c. Compare the resulting absolute URL to the document's address.  If
 10656     //        any part of the URLs difer other than the <path>, <query>, and
 10657     //        <fragment> components, raise a SECURITY_ERR and abort.
 10658     // 3. If !aReplace:
 10659     //     Remove from the session history all entries after the current entry,
 10660     //     as we would after a regular navigation, and save the current
 10661     //     entry's scroll position (bug 590573).
 10662     // 4. As apropriate, either add a state object entry to the session history
 10663     //    after the current entry with the following properties, or modify the
 10664     //    current session history entry to set
 10665     //      a. cloned data as the state object,
 10666     //      b. if the third argument was present, the absolute URL found in
 10667     //         step 2
 10668     //    Also clear the new history entry's POST data (see bug 580069).
 10669     // 5. If aReplace is false (i.e. we're doing a pushState instead of a
 10670     //    replaceState), notify bfcache that we've navigated to a new page.
 10671     // 6. If the third argument is present, set the document's current address
 10672     //    to the absolute URL found in step 2.
 10673     //
 10674     // It's important that this function not run arbitrary scripts after step 1
 10675     // and before completing step 5.  For example, if a script called
 10676     // history.back() before we completed step 5, bfcache might destroy an
 10677     // active content viewer.  Since EvictOutOfRangeContentViewers at the end of
 10678     // step 5 might run script, we can't just put a script blocker around the
 10679     // critical section.
 10680     //
 10681     // Note that we completely ignore the aTitle parameter.
 10683     nsresult rv;
 10685     // Don't clobber the load type of an existing network load.
 10686     AutoRestore<uint32_t> loadTypeResetter(mLoadType);
 10688     // pushState effectively becomes replaceState when we've started a network
 10689     // load but haven't adopted its document yet.  This mirrors what we do with
 10690     // changes to the hash at this stage of the game.
 10691     if (JustStartedNetworkLoad()) {
 10692         aReplace = true;
 10695     nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
 10696     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 10698     // Step 1: Serialize aData using structured clone.
 10699     nsCOMPtr<nsIStructuredCloneContainer> scContainer;
 10701     // scContainer->Init might cause arbitrary JS to run, and this code might
 10702     // navigate the page we're on, potentially to a different origin! (bug
 10703     // 634834)  To protect against this, we abort if our principal changes due
 10704     // to the InitFromJSVal() call.
 10706         nsCOMPtr<nsIDocument> origDocument =
 10707             do_GetInterface(GetAsSupports(this));
 10708         if (!origDocument)
 10709             return NS_ERROR_DOM_SECURITY_ERR;
 10710         nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
 10712         scContainer = new nsStructuredCloneContainer();
 10713         JSContext *cx = aCx;
 10714         nsCxPusher pusher;
 10715         if (!cx) {
 10716             cx = nsContentUtils::GetContextFromDocument(document);
 10717             pusher.Push(cx);
 10719         rv = scContainer->InitFromJSVal(aData, cx);
 10721         // If we're running in the document's context and the structured clone
 10722         // failed, clear the context's pending exception.  See bug 637116.
 10723         if (NS_FAILED(rv) && !aCx) {
 10724             JS_ClearPendingException(aCx);
 10726         NS_ENSURE_SUCCESS(rv, rv);
 10728         nsCOMPtr<nsIDocument> newDocument =
 10729             do_GetInterface(GetAsSupports(this));
 10730         if (!newDocument)
 10731             return NS_ERROR_DOM_SECURITY_ERR;
 10732         nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
 10734         bool principalsEqual = false;
 10735         origPrincipal->Equals(newPrincipal, &principalsEqual);
 10736         NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
 10739     // Check that the state object isn't too long.
 10740     // Default max length: 640k bytes.
 10741     int32_t maxStateObjSize =
 10742         Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
 10743     if (maxStateObjSize < 0) {
 10744         maxStateObjSize = 0;
 10747     uint64_t scSize;
 10748     rv = scContainer->GetSerializedNBytes(&scSize);
 10749     NS_ENSURE_SUCCESS(rv, rv);
 10751     NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize,
 10752                    NS_ERROR_ILLEGAL_VALUE);
 10754     // Step 2: Resolve aURL
 10755     bool equalURIs = true;
 10756     nsCOMPtr<nsIURI> currentURI;
 10757     if (sURIFixup && mCurrentURI) {
 10758         rv = sURIFixup->CreateExposableURI(mCurrentURI,
 10759                                            getter_AddRefs(currentURI));
 10760         NS_ENSURE_SUCCESS(rv, rv);
 10761     } else {
 10762         currentURI = mCurrentURI;
 10764     nsCOMPtr<nsIURI> oldURI = currentURI;
 10765     nsCOMPtr<nsIURI> newURI;
 10766     if (aURL.Length() == 0) {
 10767         newURI = currentURI;
 10769     else {
 10770         // 2a: Resolve aURL relative to mURI
 10772         nsIURI* docBaseURI = document->GetDocBaseURI();
 10773         if (!docBaseURI)
 10774             return NS_ERROR_FAILURE;
 10776         nsAutoCString spec;
 10777         docBaseURI->GetSpec(spec);
 10779         nsAutoCString charset;
 10780         rv = docBaseURI->GetOriginCharset(charset);
 10781         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 10783         rv = NS_NewURI(getter_AddRefs(newURI), aURL,
 10784                        charset.get(), docBaseURI);
 10786         // 2b: If 2a fails, raise a SECURITY_ERR
 10787         if (NS_FAILED(rv)) {
 10788             return NS_ERROR_DOM_SECURITY_ERR;
 10791         // 2c: Same-origin check.
 10792         if (!nsContentUtils::URIIsLocalFile(newURI)) {
 10793             // In addition to checking that the security manager says that
 10794             // the new URI has the same origin as our current URI, we also
 10795             // check that the two URIs have the same userpass. (The
 10796             // security manager says that |http://foo.com| and
 10797             // |http://me@foo.com| have the same origin.)  currentURI
 10798             // won't contain the password part of the userpass, so this
 10799             // means that it's never valid to specify a password in a
 10800             // pushState or replaceState URI.
 10802             nsCOMPtr<nsIScriptSecurityManager> secMan =
 10803                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
 10804             NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
 10806             // It's very important that we check that newURI is of the same
 10807             // origin as currentURI, not docBaseURI, because a page can
 10808             // set docBaseURI arbitrarily to any domain.
 10809             nsAutoCString currentUserPass, newUserPass;
 10810             NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
 10811                               NS_ERROR_FAILURE);
 10812             NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass),
 10813                               NS_ERROR_FAILURE);
 10814             if (NS_FAILED(secMan->CheckSameOriginURI(currentURI,
 10815                                                      newURI, true)) ||
 10816                 !currentUserPass.Equals(newUserPass)) {
 10818                 return NS_ERROR_DOM_SECURITY_ERR;
 10821         else {
 10822             // It's a file:// URI
 10823             nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
 10824                 do_QueryInterface(document);
 10826             if (!docScriptObj) {
 10827                 return NS_ERROR_DOM_SECURITY_ERR;
 10830             nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
 10832             if (!principal ||
 10833                 NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
 10835                 return NS_ERROR_DOM_SECURITY_ERR;
 10839         if (currentURI) {
 10840             currentURI->Equals(newURI, &equalURIs);
 10842         else {
 10843             equalURIs = false;
 10846     } // end of same-origin check
 10848     // Step 3: Create a new entry in the session history. This will erase
 10849     // all SHEntries after the new entry and make this entry the current
 10850     // one.  This operation may modify mOSHE, which we need later, so we
 10851     // keep a reference here.
 10852     NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
 10853     nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
 10855     mLoadType = LOAD_PUSHSTATE;
 10857     nsCOMPtr<nsISHEntry> newSHEntry;
 10858     if (!aReplace) {
 10859         // Save the current scroll position (bug 590573).
 10860         nscoord cx = 0, cy = 0;
 10861         GetCurScrollPos(ScrollOrientation_X, &cx);
 10862         GetCurScrollPos(ScrollOrientation_Y, &cy);
 10863         mOSHE->SetScrollPosition(cx, cy);
 10865         // Since we're not changing which page we have loaded, pass
 10866         // true for aCloneChildren.
 10867         rv = AddToSessionHistory(newURI, nullptr, nullptr, true,
 10868                                  getter_AddRefs(newSHEntry));
 10869         NS_ENSURE_SUCCESS(rv, rv);
 10871         NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
 10873         // Link the new SHEntry to the old SHEntry's BFCache entry, since the
 10874         // two entries correspond to the same document.
 10875         NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE),
 10876                           NS_ERROR_FAILURE);
 10878         // Set the new SHEntry's title (bug 655273).
 10879         nsString title;
 10880         mOSHE->GetTitle(getter_Copies(title));
 10881         newSHEntry->SetTitle(title);
 10883         // AddToSessionHistory may not modify mOSHE.  In case it doesn't,
 10884         // we'll just set mOSHE here.
 10885         mOSHE = newSHEntry;
 10887     } else {
 10888         newSHEntry = mOSHE;
 10889         newSHEntry->SetURI(newURI);
 10892     // Step 4: Modify new/original session history entry and clear its POST
 10893     // data, if there is any.
 10894     newSHEntry->SetStateData(scContainer);
 10895     newSHEntry->SetPostData(nullptr);
 10897     // If this push/replaceState changed the document's current URI and the new
 10898     // URI differs from the old URI in more than the hash, or if the old
 10899     // SHEntry's URI was modified in this way by a push/replaceState call
 10900     // set URIWasModified to true for the current SHEntry (bug 669671).
 10901     bool sameExceptHashes = true, oldURIWasModified = false;
 10902     newURI->EqualsExceptRef(currentURI, &sameExceptHashes);
 10903     oldOSHE->GetURIWasModified(&oldURIWasModified);
 10904     newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
 10906     // Step 5: If aReplace is false, indicating that we're doing a pushState
 10907     // rather than a replaceState, notify bfcache that we've added a page to
 10908     // the history so it can evict content viewers if appropriate. Otherwise
 10909     // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
 10910     // was replaced.
 10911     nsCOMPtr<nsISHistory> rootSH;
 10912     GetRootSessionHistory(getter_AddRefs(rootSH));
 10913     NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
 10915     nsCOMPtr<nsISHistoryInternal> internalSH =
 10916         do_QueryInterface(rootSH);
 10917     NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
 10919     if (!aReplace) {
 10920         int32_t curIndex = -1;
 10921         rv = rootSH->GetIndex(&curIndex);
 10922         if (NS_SUCCEEDED(rv) && curIndex > -1) {
 10923             internalSH->EvictOutOfRangeContentViewers(curIndex);
 10925     } else {
 10926         nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry);
 10928         int32_t index = -1;
 10929         rv = rootSH->GetIndexOfEntry(rootSHEntry, &index);
 10930         if (NS_SUCCEEDED(rv) && index > -1) {
 10931             internalSH->ReplaceEntry(index, rootSHEntry);
 10935     // Step 6: If the document's URI changed, update document's URI and update
 10936     // global history.
 10937     //
 10938     // We need to call FireOnLocationChange so that the browser's address bar
 10939     // gets updated and the back button is enabled, but we only need to
 10940     // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
 10941     // since SetCurrentURI will call FireOnLocationChange for us.
 10942     //
 10943     // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
 10944     // nullptr for aRequest param to FireOnLocationChange(...). Such an update
 10945     // notification is allowed only when we know docshell is not loading a new
 10946     // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
 10947     // FireOnLocationChange(...) breaks security UI.
 10948     if (!equalURIs) {
 10949         SetCurrentURI(newURI, nullptr, true, LOCATION_CHANGE_SAME_DOCUMENT);
 10950         document->SetDocumentURI(newURI);
 10952         AddURIVisit(newURI, oldURI, oldURI, 0);
 10954         // AddURIVisit doesn't set the title for the new URI in global history,
 10955         // so do that here.
 10956         if (mUseGlobalHistory && !mInPrivateBrowsing) {
 10957             nsCOMPtr<IHistory> history = services::GetHistoryService();
 10958             if (history) {
 10959                 history->SetURITitle(newURI, mTitle);
 10961             else if (mGlobalHistory) {
 10962                 mGlobalHistory->SetPageTitle(newURI, mTitle);
 10966         // Inform the favicon service that our old favicon applies to this new
 10967         // URI.
 10968         CopyFavicon(oldURI, newURI, mInPrivateBrowsing);
 10970     else {
 10971         FireDummyOnLocationChange();
 10973     document->SetStateObject(scContainer);
 10975     return NS_OK;
 10978 bool
 10979 nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
 10981     // I believe none of the about: urls should go in the history. But then
 10982     // that could just be me... If the intent is only deny about:blank then we
 10983     // should just do a spec compare, rather than two gets of the scheme and
 10984     // then the path.  -Gagan
 10985     nsresult rv;
 10986     nsAutoCString buf, pref;
 10988     rv = aURI->GetScheme(buf);
 10989     if (NS_FAILED(rv))
 10990         return false;
 10992     if (buf.Equals("about")) {
 10993         rv = aURI->GetPath(buf);
 10994         if (NS_FAILED(rv))
 10995             return false;
 10997         if (buf.Equals("blank")) {
 10998             return false;
 11002     rv = Preferences::GetDefaultCString("browser.newtab.url", &pref);
 11004     if (NS_FAILED(rv)) {
 11005         return true;
 11008     rv = aURI->GetSpec(buf);
 11009     NS_ENSURE_SUCCESS(rv, true);
 11011     return !buf.Equals(pref);
 11014 nsresult
 11015 nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
 11016                                 nsISupports* aOwner, bool aCloneChildren,
 11017                                 nsISHEntry ** aNewEntry)
 11019     NS_PRECONDITION(aURI, "uri is null");
 11020     NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
 11022 #if defined(PR_LOGGING) && defined(DEBUG)
 11023     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
 11024         nsAutoCString spec;
 11025         aURI->GetSpec(spec);
 11027         nsAutoCString chanName;
 11028         if (aChannel)
 11029             aChannel->GetName(chanName);
 11030         else
 11031             chanName.AssignLiteral("<no channel>");
 11033         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
 11034                ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(),
 11035                 chanName.get()));
 11037 #endif
 11039     nsresult rv = NS_OK;
 11040     nsCOMPtr<nsISHEntry> entry;
 11041     bool shouldPersist;
 11043     shouldPersist = ShouldAddToSessionHistory(aURI);
 11045     // Get a handle to the root docshell 
 11046     nsCOMPtr<nsIDocShellTreeItem> root;
 11047     GetSameTypeRootTreeItem(getter_AddRefs(root));     
 11048     /*
 11049      * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
 11050      * the existing SH entry in the page and replace the url and
 11051      * other vitalities.
 11052      */
 11053     if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
 11054         root != static_cast<nsIDocShellTreeItem *>(this)) {
 11055         // This is a subframe 
 11056         entry = mOSHE;
 11057         nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
 11058         if (shContainer) {
 11059             int32_t childCount = 0;
 11060             shContainer->GetChildCount(&childCount);
 11061             // Remove all children of this entry 
 11062             for (int32_t i = childCount - 1; i >= 0; i--) {
 11063                 nsCOMPtr<nsISHEntry> child;
 11064                 shContainer->GetChildAt(i, getter_AddRefs(child));
 11065                 shContainer->RemoveChild(child);
 11066             }  // for
 11067             entry->AbandonBFCacheEntry();
 11068         }  // shContainer
 11071     // Create a new entry if necessary.
 11072     if (!entry) {
 11073         entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
 11075         if (!entry) {
 11076             return NS_ERROR_OUT_OF_MEMORY;
 11080     // Get the post data & referrer
 11081     nsCOMPtr<nsIInputStream> inputStream;
 11082     nsCOMPtr<nsIURI> referrerURI;
 11083     nsCOMPtr<nsISupports> cacheKey;
 11084     nsCOMPtr<nsISupports> owner = aOwner;
 11085     bool expired = false;
 11086     bool discardLayoutState = false;
 11087     nsCOMPtr<nsICachingChannel> cacheChannel;
 11088     if (aChannel) {
 11089         cacheChannel = do_QueryInterface(aChannel);
 11091         /* If there is a caching channel, get the Cache Key and store it
 11092          * in SH.
 11093          */
 11094         if (cacheChannel) {
 11095             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
 11097         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
 11099         // Check if the httpChannel is hiding under a multipartChannel
 11100         if (!httpChannel) {
 11101             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
 11103         if (httpChannel) {
 11104             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
 11105             if (uploadChannel) {
 11106                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
 11108             httpChannel->GetReferrer(getter_AddRefs(referrerURI));
 11110             discardLayoutState = ShouldDiscardLayoutState(httpChannel);
 11112         aChannel->GetOwner(getter_AddRefs(owner));
 11115     //Title is set in nsDocShell::SetTitle()
 11116     entry->Create(aURI,              // uri
 11117                   EmptyString(),     // Title
 11118                   inputStream,       // Post data stream
 11119                   nullptr,            // LayoutHistory state
 11120                   cacheKey,          // CacheKey
 11121                   mContentTypeHint,  // Content-type
 11122                   owner,             // Channel or provided owner
 11123                   mHistoryID,
 11124                   mDynamicallyCreated);
 11125     entry->SetReferrerURI(referrerURI);
 11126     nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
 11127     if (inStrmChan) {
 11128         bool isSrcdocChannel;
 11129         inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
 11130         if (isSrcdocChannel) {
 11131             nsAutoString srcdoc;
 11132             inStrmChan->GetSrcdocData(srcdoc);
 11133             entry->SetSrcdocData(srcdoc);
 11134             nsCOMPtr<nsIURI> baseURI;
 11135             inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
 11136             entry->SetBaseURI(baseURI);
 11139     /* If cache got a 'no-store', ask SH not to store
 11140      * HistoryLayoutState. By default, SH will set this
 11141      * flag to true and save HistoryLayoutState.
 11142      */    
 11143     if (discardLayoutState) {
 11144         entry->SetSaveLayoutStateFlag(false);
 11146     if (cacheChannel) {
 11147         // Check if the page has expired from cache
 11148         uint32_t expTime = 0;
 11149         cacheChannel->GetCacheTokenExpirationTime(&expTime);
 11150         uint32_t now = PRTimeToSeconds(PR_Now());
 11151         if (expTime <=  now)
 11152             expired = true;
 11154     if (expired)
 11155         entry->SetExpirationStatus(true);
 11158     if (root == static_cast<nsIDocShellTreeItem *>(this) && mSessionHistory) {
 11159         // If we need to clone our children onto the new session
 11160         // history entry, do so now.
 11161         if (aCloneChildren && mOSHE) {
 11162             uint32_t cloneID;
 11163             mOSHE->GetID(&cloneID);
 11164             nsCOMPtr<nsISHEntry> newEntry;
 11165             CloneAndReplace(mOSHE, this, cloneID, entry, true, getter_AddRefs(newEntry));
 11166             NS_ASSERTION(entry == newEntry, "The new session history should be in the new entry");
 11169         // This is the root docshell
 11170         if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {            
 11171             // Replace current entry in session history.
 11172             int32_t  index = 0;   
 11173             mSessionHistory->GetIndex(&index);
 11174             nsCOMPtr<nsISHistoryInternal>   shPrivate(do_QueryInterface(mSessionHistory));
 11175             // Replace the current entry with the new entry
 11176             if (shPrivate)
 11177                 rv = shPrivate->ReplaceEntry(index, entry);          
 11179         else {
 11180             // Add to session history
 11181             nsCOMPtr<nsISHistoryInternal>
 11182                 shPrivate(do_QueryInterface(mSessionHistory));
 11183             NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
 11184             mSessionHistory->GetIndex(&mPreviousTransIndex);
 11185             rv = shPrivate->AddEntry(entry, shouldPersist);
 11186             mSessionHistory->GetIndex(&mLoadedTransIndex);
 11187 #ifdef DEBUG_PAGE_CACHE
 11188             printf("Previous index: %d, Loaded index: %d\n\n",
 11189                    mPreviousTransIndex, mLoadedTransIndex);
 11190 #endif
 11193     else {  
 11194         // This is a subframe.
 11195         if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
 11196                                            LOAD_FLAGS_REPLACE_HISTORY))
 11197             rv = DoAddChildSHEntry(entry, mChildOffset, aCloneChildren);
 11200     // Return the new SH entry...
 11201     if (aNewEntry) {
 11202         *aNewEntry = nullptr;
 11203         if (NS_SUCCEEDED(rv)) {
 11204             *aNewEntry = entry;
 11205             NS_ADDREF(*aNewEntry);
 11209     return rv;
 11213 NS_IMETHODIMP
 11214 nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType)
 11216     if (!IsNavigationAllowed()) {
 11217         return NS_OK;
 11220     nsCOMPtr<nsIURI> uri;
 11221     nsCOMPtr<nsIInputStream> postData;
 11222     nsCOMPtr<nsIURI> referrerURI;
 11223     nsAutoCString contentType;
 11224     nsCOMPtr<nsISupports> owner;
 11226     NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
 11228     NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
 11229     NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
 11230                       NS_ERROR_FAILURE);
 11231     NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
 11232                       NS_ERROR_FAILURE);
 11233     NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
 11234     NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)),
 11235                       NS_ERROR_FAILURE);
 11237     // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
 11238     // that's the only thing holding a ref to aEntry that will cause aEntry to
 11239     // die while we're loading it.  So hold a strong ref to aEntry here, just
 11240     // in case.
 11241     nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
 11242     bool isJS;
 11243     nsresult rv = uri->SchemeIs("javascript", &isJS);
 11244     if (NS_FAILED(rv) || isJS) {
 11245         // We're loading a URL that will execute script from inside asyncOpen.
 11246         // Replace the current document with about:blank now to prevent
 11247         // anything from the current document from leaking into any JavaScript
 11248         // code in the URL.
 11249         nsCOMPtr<nsIPrincipal> prin = do_QueryInterface(owner);
 11250         // Don't cache the presentation if we're going to just reload the
 11251         // current entry. Caching would lead to trying to save the different
 11252         // content viewers in the same nsISHEntry object.
 11253         rv = CreateAboutBlankContentViewer(prin, nullptr, aEntry != mOSHE);
 11255         if (NS_FAILED(rv)) {
 11256             // The creation of the intermittent about:blank content
 11257             // viewer failed for some reason (potentially because the
 11258             // user prevented it). Interrupt the history load.
 11259             return NS_OK;
 11262         if (!owner) {
 11263             // Ensure that we have an owner.  Otherwise javascript: URIs will
 11264             // pick it up from the about:blank page we just loaded, and we
 11265             // don't really want even that in this case.
 11266             owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
 11267             NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY);
 11271     /* If there is a valid postdata *and* the user pressed
 11272      * reload or shift-reload, take user's permission before we  
 11273      * repost the data to the server.
 11274      */
 11275     if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
 11276       bool repost;
 11277       rv = ConfirmRepost(&repost);
 11278       if (NS_FAILED(rv)) return rv;
 11280       // If the user pressed cancel in the dialog, return.  We're done here.
 11281       if (!repost)
 11282         return NS_BINDING_ABORTED;
 11285     // Do not inherit owner from document (security-critical!);
 11286     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
 11288     nsAutoString srcdoc;
 11289     bool isSrcdoc;
 11290     nsCOMPtr<nsIURI> baseURI;
 11291     aEntry->GetIsSrcdocEntry(&isSrcdoc);
 11292     if (isSrcdoc) {
 11293         aEntry->GetSrcdocData(srcdoc);
 11294         aEntry->GetBaseURI(getter_AddRefs(baseURI));
 11295         flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
 11297     else {
 11298         srcdoc = NullString();
 11301     // Passing nullptr as aSourceDocShell gives the same behaviour as before
 11302     // aSourceDocShell was introduced. According to spec we should be passing
 11303     // the source browsing context that was used when the history entry was
 11304     // first created. bug 947716 has been created to address this issue.
 11305     rv = InternalLoad(uri,
 11306                       referrerURI,
 11307                       owner,
 11308                       flags,
 11309                       nullptr,            // No window target
 11310                       contentType.get(),  // Type hint
 11311                       NullString(),       // No forced file download
 11312                       postData,           // Post data stream
 11313                       nullptr,            // No headers stream
 11314                       aLoadType,          // Load type
 11315                       aEntry,             // SHEntry
 11316                       true,
 11317                       srcdoc,
 11318                       nullptr,            // Source docshell, see comment above
 11319                       baseURI,
 11320                       nullptr,            // No nsIDocShell
 11321                       nullptr);           // No nsIRequest
 11322     return rv;
 11325 NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(bool* aShould)
 11327     *aShould = false;
 11328     if (mOSHE) {
 11329         // Don't capture historystate and save it in history
 11330         // if the page asked not to do so.
 11331         mOSHE->GetSaveLayoutStateFlag(aShould);
 11334     return NS_OK;
 11337 NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState()
 11339     nsresult  rv = NS_OK;
 11341     if (mOSHE) {
 11342         nsCOMPtr<nsIPresShell> shell = GetPresShell();
 11343         if (shell) {
 11344             nsCOMPtr<nsILayoutHistoryState> layoutState;
 11345             rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
 11349     return rv;
 11352 /* static */ nsresult
 11353 nsDocShell::WalkHistoryEntries(nsISHEntry *aRootEntry,
 11354                                nsDocShell *aRootShell,
 11355                                WalkHistoryEntriesFunc aCallback,
 11356                                void *aData)
 11358     NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
 11360     nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
 11361     if (!container)
 11362         return NS_ERROR_FAILURE;
 11364     int32_t childCount;
 11365     container->GetChildCount(&childCount);
 11366     for (int32_t i = 0; i < childCount; i++) {
 11367         nsCOMPtr<nsISHEntry> childEntry;
 11368         container->GetChildAt(i, getter_AddRefs(childEntry));
 11369         if (!childEntry) {
 11370             // childEntry can be null for valid reasons, for example if the
 11371             // docshell at index i never loaded anything useful.
 11372             // Remember to clone also nulls in the child array (bug 464064).
 11373             aCallback(nullptr, nullptr, i, aData);
 11374             continue;
 11377         nsDocShell *childShell = nullptr;
 11378         if (aRootShell) {
 11379             // Walk the children of aRootShell and see if one of them
 11380             // has srcChild as a SHEntry.
 11382             nsTObserverArray<nsDocLoader*>::ForwardIterator iter(aRootShell->mChildList);
 11383             while (iter.HasMore()) {
 11384                 nsDocShell *child = static_cast<nsDocShell*>(iter.GetNext());
 11386                 if (child->HasHistoryEntry(childEntry)) {
 11387                     childShell = child;
 11388                     break;
 11392         nsresult rv = aCallback(childEntry, childShell, i, aData);
 11393         NS_ENSURE_SUCCESS(rv, rv);
 11396     return NS_OK;
 11399 // callback data for WalkHistoryEntries
 11400 struct MOZ_STACK_CLASS CloneAndReplaceData
 11402     CloneAndReplaceData(uint32_t aCloneID, nsISHEntry *aReplaceEntry,
 11403                         bool aCloneChildren, nsISHEntry *aDestTreeParent)
 11404         : cloneID(aCloneID),
 11405           cloneChildren(aCloneChildren),
 11406           replaceEntry(aReplaceEntry),
 11407           destTreeParent(aDestTreeParent) { }
 11409     uint32_t              cloneID;
 11410     bool                  cloneChildren;
 11411     nsISHEntry           *replaceEntry;
 11412     nsISHEntry           *destTreeParent;
 11413     nsCOMPtr<nsISHEntry>  resultEntry;
 11414 };
 11416 /* static */ nsresult
 11417 nsDocShell::CloneAndReplaceChild(nsISHEntry *aEntry, nsDocShell *aShell,
 11418                                  int32_t aEntryIndex, void *aData)
 11420     nsCOMPtr<nsISHEntry> dest;
 11422     CloneAndReplaceData *data = static_cast<CloneAndReplaceData*>(aData);
 11423     uint32_t cloneID = data->cloneID;
 11424     nsISHEntry *replaceEntry = data->replaceEntry;
 11426     nsCOMPtr<nsISHContainer> container =
 11427       do_QueryInterface(data->destTreeParent);
 11428     if (!aEntry) {
 11429         if (container) {
 11430             container->AddChild(nullptr, aEntryIndex);
 11432         return NS_OK;
 11435     uint32_t srcID;
 11436     aEntry->GetID(&srcID);
 11438     nsresult rv = NS_OK;
 11439     if (srcID == cloneID) {
 11440         // Replace the entry
 11441         dest = replaceEntry;
 11442     } else {
 11443         // Clone the SHEntry...
 11444         rv = aEntry->Clone(getter_AddRefs(dest));
 11445         NS_ENSURE_SUCCESS(rv, rv);
 11447     dest->SetIsSubFrame(true);
 11449     if (srcID != cloneID || data->cloneChildren) {
 11450         // Walk the children
 11451         CloneAndReplaceData childData(cloneID, replaceEntry,
 11452                                       data->cloneChildren, dest);
 11453         rv = WalkHistoryEntries(aEntry, aShell,
 11454                                 CloneAndReplaceChild, &childData);
 11455         NS_ENSURE_SUCCESS(rv, rv);
 11458     if (srcID != cloneID && aShell) {
 11459         aShell->SwapHistoryEntries(aEntry, dest);
 11462     if (container)
 11463         container->AddChild(dest, aEntryIndex);
 11465     data->resultEntry = dest;
 11466     return rv;
 11469 /* static */ nsresult
 11470 nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
 11471                                    nsDocShell *aSrcShell,
 11472                                    uint32_t aCloneID,
 11473                                    nsISHEntry *aReplaceEntry,
 11474                                    bool aCloneChildren,
 11475                                    nsISHEntry **aResultEntry)
 11477     NS_ENSURE_ARG_POINTER(aResultEntry);
 11478     NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
 11480     CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr);
 11481     nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
 11483     data.resultEntry.swap(*aResultEntry);
 11484     return rv;
 11487 void
 11488 nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
 11490     if (aOldEntry == mOSHE)
 11491         mOSHE = aNewEntry;
 11493     if (aOldEntry == mLSHE)
 11494         mLSHE = aNewEntry;
 11498 struct SwapEntriesData
 11500     nsDocShell *ignoreShell;     // constant; the shell to ignore
 11501     nsISHEntry *destTreeRoot;    // constant; the root of the dest tree
 11502     nsISHEntry *destTreeParent;  // constant; the node under destTreeRoot
 11503                                  // whose children will correspond to aEntry
 11504 };
 11507 nsresult
 11508 nsDocShell::SetChildHistoryEntry(nsISHEntry *aEntry, nsDocShell *aShell,
 11509                                  int32_t aEntryIndex, void *aData)
 11511     SwapEntriesData *data = static_cast<SwapEntriesData*>(aData);
 11512     nsDocShell *ignoreShell = data->ignoreShell;
 11514     if (!aShell || aShell == ignoreShell)
 11515         return NS_OK;
 11517     nsISHEntry *destTreeRoot = data->destTreeRoot;
 11519     nsCOMPtr<nsISHEntry> destEntry;
 11520     nsCOMPtr<nsISHContainer> container =
 11521         do_QueryInterface(data->destTreeParent);
 11523     if (container) {
 11524         // aEntry is a clone of some child of destTreeParent, but since the
 11525         // trees aren't necessarily in sync, we'll have to locate it.
 11526         // Note that we could set aShell's entry to null if we don't find a
 11527         // corresponding entry under destTreeParent.
 11529         uint32_t targetID, id;
 11530         aEntry->GetID(&targetID);
 11532         // First look at the given index, since this is the common case.
 11533         nsCOMPtr<nsISHEntry> entry;
 11534         container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
 11535         if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
 11536             destEntry.swap(entry);
 11537         } else {
 11538             int32_t childCount;
 11539             container->GetChildCount(&childCount);
 11540             for (int32_t i = 0; i < childCount; ++i) {
 11541                 container->GetChildAt(i, getter_AddRefs(entry));
 11542                 if (!entry)
 11543                     continue;
 11545                 entry->GetID(&id);
 11546                 if (id == targetID) {
 11547                     destEntry.swap(entry);
 11548                     break;
 11552     } else {
 11553         destEntry = destTreeRoot;
 11556     aShell->SwapHistoryEntries(aEntry, destEntry);
 11558     // Now handle the children of aEntry.
 11559     SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
 11560     return WalkHistoryEntries(aEntry, aShell,
 11561                               SetChildHistoryEntry, &childData);
 11565 static nsISHEntry*
 11566 GetRootSHEntry(nsISHEntry *aEntry)
 11568     nsCOMPtr<nsISHEntry> rootEntry = aEntry;
 11569     nsISHEntry *result = nullptr;
 11570     while (rootEntry) {
 11571         result = rootEntry;
 11572         result->GetParent(getter_AddRefs(rootEntry));
 11575     return result;
 11579 void
 11580 nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry> *aPtr, nsISHEntry *aEntry)
 11582     // We need to sync up the docshell and session history trees for
 11583     // subframe navigation.  If the load was in a subframe, we forward up to
 11584     // the root docshell, which will then recursively sync up all docshells
 11585     // to their corresponding entries in the new session history tree.
 11586     // If we don't do this, then we can cache a content viewer on the wrong
 11587     // cloned entry, and subsequently restore it at the wrong time.
 11589     nsISHEntry *newRootEntry = GetRootSHEntry(aEntry);
 11590     if (newRootEntry) {
 11591         // newRootEntry is now the new root entry.
 11592         // Find the old root entry as well.
 11594         // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
 11595         // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
 11596         nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
 11597         if (oldRootEntry) {
 11598             nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
 11599             GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
 11600             nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
 11601             if (rootShell) { // if we're the root just set it, nothing to swap
 11602                 SwapEntriesData data = { this, newRootEntry };
 11603                 nsIDocShell *rootIDocShell =
 11604                     static_cast<nsIDocShell*>(rootShell);
 11605                 nsDocShell *rootDocShell = static_cast<nsDocShell*>
 11606                                                       (rootIDocShell);
 11608 #ifdef DEBUG
 11609                 nsresult rv =
 11610 #endif
 11611                 SetChildHistoryEntry(oldRootEntry, rootDocShell,
 11612                                                    0, &data);
 11613                 NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
 11618     *aPtr = aEntry;
 11622 nsresult
 11623 nsDocShell::GetRootSessionHistory(nsISHistory ** aReturn)
 11625     nsresult rv;
 11627     nsCOMPtr<nsIDocShellTreeItem> root;
 11628     //Get the root docshell
 11629     rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
 11630     // QI to nsIWebNavigation
 11631     nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
 11632     if (rootAsWebnav) {
 11633         // Get the handle to SH from the root docshell
 11634         rv = rootAsWebnav->GetSessionHistory(aReturn);
 11636     return rv;
 11639 nsresult
 11640 nsDocShell::GetHttpChannel(nsIChannel * aChannel, nsIHttpChannel ** aReturn)
 11642     NS_ENSURE_ARG_POINTER(aReturn);
 11643     if (!aChannel)
 11644         return NS_ERROR_FAILURE;
 11646     nsCOMPtr<nsIMultiPartChannel>  multiPartChannel(do_QueryInterface(aChannel));
 11647     if (multiPartChannel) {
 11648         nsCOMPtr<nsIChannel> baseChannel;
 11649         multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
 11650         nsCOMPtr<nsIHttpChannel>  httpChannel(do_QueryInterface(baseChannel));
 11651         *aReturn = httpChannel;
 11652         NS_IF_ADDREF(*aReturn);
 11654     return NS_OK;
 11657 bool 
 11658 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel)
 11660     // By default layout State will be saved. 
 11661     if (!aChannel)
 11662         return false;
 11664     // figure out if SH should be saving layout state 
 11665     nsCOMPtr<nsISupports> securityInfo;
 11666     bool noStore = false, noCache = false;
 11667     aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
 11668     aChannel->IsNoStoreResponse(&noStore);
 11669     aChannel->IsNoCacheResponse(&noCache);
 11671     return (noStore || (noCache && securityInfo));
 11674 NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
 11676   NS_ENSURE_ARG_POINTER(aEditor);
 11678   if (!mEditorData) {
 11679     *aEditor = nullptr;
 11680     return NS_OK;
 11683   return mEditorData->GetEditor(aEditor);
 11686 NS_IMETHODIMP nsDocShell::SetEditor(nsIEditor * aEditor)
 11688   nsresult rv = EnsureEditorData();
 11689   if (NS_FAILED(rv)) return rv;
 11691   return mEditorData->SetEditor(aEditor);
 11695 NS_IMETHODIMP nsDocShell::GetEditable(bool *aEditable)
 11697   NS_ENSURE_ARG_POINTER(aEditable);
 11698   *aEditable = mEditorData && mEditorData->GetEditable();
 11699   return NS_OK;
 11703 NS_IMETHODIMP nsDocShell::GetHasEditingSession(bool *aHasEditingSession)
 11705   NS_ENSURE_ARG_POINTER(aHasEditingSession);
 11707   if (mEditorData)
 11709     nsCOMPtr<nsIEditingSession> editingSession;
 11710     mEditorData->GetEditingSession(getter_AddRefs(editingSession));
 11711     *aHasEditingSession = (editingSession.get() != nullptr);
 11713   else
 11715     *aHasEditingSession = false;
 11718   return NS_OK;
 11721 NS_IMETHODIMP nsDocShell::MakeEditable(bool inWaitForUriLoad)
 11723   nsresult rv = EnsureEditorData();
 11724   if (NS_FAILED(rv)) return rv;
 11726   return mEditorData->MakeEditable(inWaitForUriLoad);
 11729 bool
 11730 nsDocShell::ChannelIsPost(nsIChannel* aChannel)
 11732     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
 11733     if (!httpChannel) {
 11734         return false;
 11737     nsAutoCString method;
 11738     httpChannel->GetRequestMethod(method);
 11739     return method.Equals("POST");
 11742 void
 11743 nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
 11744                              nsIURI** aURI,
 11745                              uint32_t* aChannelRedirectFlags)
 11747     nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
 11748     if (!props) {
 11749         return;
 11752     nsresult rv = props->GetPropertyAsInterface(
 11753         NS_LITERAL_STRING("docshell.previousURI"),
 11754         NS_GET_IID(nsIURI),
 11755         reinterpret_cast<void**>(aURI)
 11756     );
 11758     if (NS_FAILED(rv)) {
 11759         // There is no last visit for this channel, so this must be the first
 11760         // link.  Link the visit to the referrer of this request, if any.
 11761         // Treat referrer as null if there is an error getting it.
 11762         (void)NS_GetReferrerFromChannel(aChannel, aURI);
 11764     else {
 11765       rv = props->GetPropertyAsUint32(
 11766           NS_LITERAL_STRING("docshell.previousFlags"),
 11767           aChannelRedirectFlags
 11768       );
 11770       NS_WARN_IF_FALSE(
 11771           NS_SUCCEEDED(rv),
 11772           "Could not fetch previous flags, URI will be treated like referrer"
 11773       );
 11777 void
 11778 nsDocShell::SaveLastVisit(nsIChannel* aChannel,
 11779                           nsIURI* aURI,
 11780                           uint32_t aChannelRedirectFlags)
 11782     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
 11783     if (!props || !aURI) {
 11784         return;
 11787     props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
 11788                                   aURI);
 11789     props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
 11790                                aChannelRedirectFlags);
 11793 void
 11794 nsDocShell::AddURIVisit(nsIURI* aURI,
 11795                         nsIURI* aReferrerURI,
 11796                         nsIURI* aPreviousURI,
 11797                         uint32_t aChannelRedirectFlags,
 11798                         uint32_t aResponseStatus)
 11800     MOZ_ASSERT(aURI, "Visited URI is null!");
 11801     MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE &&
 11802                mLoadType != LOAD_BYPASS_HISTORY,
 11803                "Do not add error or bypass pages to global history");
 11805     // Only content-type docshells save URI visits.  Also don't do
 11806     // anything here if we're not supposed to use global history.
 11807     if (mItemType != typeContent || !mUseGlobalHistory || mInPrivateBrowsing) {
 11808         return;
 11811     nsCOMPtr<IHistory> history = services::GetHistoryService();
 11813     if (history) {
 11814         uint32_t visitURIFlags = 0;
 11816         if (!IsFrame()) {
 11817             visitURIFlags |= IHistory::TOP_LEVEL;
 11820         if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
 11821             visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
 11823         else if (aChannelRedirectFlags &
 11824                  nsIChannelEventSink::REDIRECT_PERMANENT) {
 11825             visitURIFlags |= IHistory::REDIRECT_PERMANENT;
 11828         if (aResponseStatus >= 300 && aResponseStatus < 400) {
 11829             visitURIFlags |= IHistory::REDIRECT_SOURCE;
 11831         // Errors 400-501 and 505 are considered unrecoverable, in the sense a
 11832         // simple retry attempt by the user is unlikely to solve them.
 11833         // 408 is special cased, since may actually indicate a temporary
 11834         // connection problem.
 11835         else if (aResponseStatus != 408 &&
 11836                  ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
 11837                    aResponseStatus == 505)) {
 11838             visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
 11841         (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
 11843     else if (mGlobalHistory) {
 11844         // Falls back to sync global history interface.
 11845         (void)mGlobalHistory->AddURI(aURI,
 11846                                      !!aChannelRedirectFlags,
 11847                                      !IsFrame(),
 11848                                      aReferrerURI);
 11852 //*****************************************************************************
 11853 // nsDocShell: Helper Routines
 11854 //*****************************************************************************
 11856 NS_IMETHODIMP
 11857 nsDocShell::SetLoadType(uint32_t aLoadType)
 11859     mLoadType = aLoadType;
 11860     return NS_OK;
 11863 NS_IMETHODIMP
 11864 nsDocShell::GetLoadType(uint32_t * aLoadType)
 11866     *aLoadType = mLoadType;
 11867     return NS_OK;
 11870 nsresult
 11871 nsDocShell::ConfirmRepost(bool * aRepost)
 11873   nsCOMPtr<nsIPrompt> prompter;
 11874   CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
 11875   if (!prompter) {
 11876       return NS_ERROR_NOT_AVAILABLE;
 11879   nsCOMPtr<nsIStringBundleService> stringBundleService =
 11880     mozilla::services::GetStringBundleService();
 11881   if (!stringBundleService)
 11882     return NS_ERROR_FAILURE;
 11884   nsCOMPtr<nsIStringBundle> appBundle;
 11885   nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
 11886                                                   getter_AddRefs(appBundle));
 11887   NS_ENSURE_SUCCESS(rv, rv);
 11889   nsCOMPtr<nsIStringBundle> brandBundle;
 11890   rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle));
 11891   NS_ENSURE_SUCCESS(rv, rv);
 11893   NS_ASSERTION(prompter && brandBundle && appBundle,
 11894                "Unable to set up repost prompter.");
 11896   nsXPIDLString brandName;
 11897   rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"),
 11898                                       getter_Copies(brandName));
 11900   nsXPIDLString msgString, button0Title;
 11901   if (NS_FAILED(rv)) { // No brand, use the generic version.
 11902     rv = appBundle->GetStringFromName(MOZ_UTF16("confirmRepostPrompt"),
 11903                                       getter_Copies(msgString));
 11905   else {
 11906     // Brand available - if the app has an override file with formatting, the app name will
 11907     // be included. Without an override, the prompt will look like the generic version.
 11908     const char16_t *formatStrings[] = { brandName.get() };
 11909     rv = appBundle->FormatStringFromName(MOZ_UTF16("confirmRepostPrompt"),
 11910                                          formatStrings, ArrayLength(formatStrings),
 11911                                          getter_Copies(msgString));
 11913   if (NS_FAILED(rv)) return rv;
 11915   rv = appBundle->GetStringFromName(MOZ_UTF16("resendButton.label"),
 11916                                     getter_Copies(button0Title));
 11917   if (NS_FAILED(rv)) return rv;
 11919   int32_t buttonPressed;
 11920   // The actual value here is irrelevant, but we can't pass an invalid
 11921   // bool through XPConnect.
 11922   bool checkState = false;
 11923   rv = prompter->
 11924          ConfirmEx(nullptr, msgString.get(),
 11925                    (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
 11926                    (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
 11927                    button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed);
 11928   if (NS_FAILED(rv)) return rv;
 11930   *aRepost = (buttonPressed == 0);
 11931   return NS_OK;
 11934 NS_IMETHODIMP
 11935 nsDocShell::GetPromptAndStringBundle(nsIPrompt ** aPrompt,
 11936                                      nsIStringBundle ** aStringBundle)
 11938     NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void **) aPrompt),
 11939                       NS_ERROR_FAILURE);
 11941     nsCOMPtr<nsIStringBundleService> stringBundleService =
 11942       mozilla::services::GetStringBundleService();
 11943     NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
 11945     NS_ENSURE_SUCCESS(stringBundleService->
 11946                       CreateBundle(kAppstringsBundleURL,
 11947                                    aStringBundle),
 11948                       NS_ERROR_FAILURE);
 11950     return NS_OK;
 11953 NS_IMETHODIMP
 11954 nsDocShell::GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent,
 11955                            int32_t * aOffset)
 11957     NS_ENSURE_ARG_POINTER(aChild || aParent);
 11959     nsCOMPtr<nsIDOMNodeList> childNodes;
 11960     NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
 11961                       NS_ERROR_FAILURE);
 11962     NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
 11964     int32_t i = 0;
 11966     for (; true; i++) {
 11967         nsCOMPtr<nsIDOMNode> childNode;
 11968         NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
 11969                           NS_ERROR_FAILURE);
 11970         NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
 11972         if (childNode.get() == aChild) {
 11973             *aOffset = i;
 11974             return NS_OK;
 11978     return NS_ERROR_FAILURE;
 11981 nsIScrollableFrame *
 11982 nsDocShell::GetRootScrollFrame()
 11984     nsCOMPtr<nsIPresShell> shell = GetPresShell();
 11985     NS_ENSURE_TRUE(shell, nullptr);
 11987     return shell->GetRootScrollFrameAsScrollableExternal();
 11990 NS_IMETHODIMP
 11991 nsDocShell::EnsureScriptEnvironment()
 11993     if (mScriptGlobal)
 11994         return NS_OK;
 11996     if (mIsBeingDestroyed) {
 11997         return NS_ERROR_NOT_AVAILABLE;
 12000 #ifdef DEBUG
 12001     NS_ASSERTION(!mInEnsureScriptEnv,
 12002                  "Infinite loop! Calling EnsureScriptEnvironment() from "
 12003                  "within EnsureScriptEnvironment()!");
 12005     // Yeah, this isn't re-entrant safe, but that's ok since if we
 12006     // re-enter this method, we'll infinitely loop...
 12007     AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
 12008     mInEnsureScriptEnv = true;
 12009 #endif
 12011     nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
 12012     NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
 12014     uint32_t chromeFlags;
 12015     browserChrome->GetChromeFlags(&chromeFlags);
 12017     bool isModalContentWindow = (mItemType == typeContent) &&
 12018         (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW);
 12019     // There can be various other content docshells associated with the
 12020     // top-level window, like sidebars. Make sure that we only create an
 12021     // nsGlobalModalWindow for the primary content shell.
 12022     if (isModalContentWindow) {
 12023         nsCOMPtr<nsIDocShellTreeItem> primaryItem;
 12024         nsresult rv = mTreeOwner->GetPrimaryContentShell(getter_AddRefs(primaryItem));
 12025         NS_ENSURE_SUCCESS(rv, rv);
 12026         isModalContentWindow = (primaryItem == this);
 12029     // If our window is modal and we're not opened as chrome, make
 12030     // this window a modal content window.
 12031     mScriptGlobal =
 12032         NS_NewScriptGlobalObject(mItemType == typeChrome, isModalContentWindow);
 12033     MOZ_ASSERT(mScriptGlobal);
 12035     mScriptGlobal->SetDocShell(this);
 12037     // Ensure the script object is set up to run script.
 12038     return mScriptGlobal->EnsureScriptEnvironment();
 12042 NS_IMETHODIMP
 12043 nsDocShell::EnsureEditorData()
 12045     bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
 12046     if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
 12047         // We shouldn't recreate the editor data if it already exists, or
 12048         // we're shutting down, or we already have a detached editor data
 12049         // stored in the session history. We should only have one editordata
 12050         // per docshell.
 12051         mEditorData = new nsDocShellEditorData(this);
 12054     return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
 12057 nsresult
 12058 nsDocShell::EnsureTransferableHookData()
 12060     if (!mTransferableHookData) {
 12061         mTransferableHookData = new nsTransferableHookData();
 12062         if (!mTransferableHookData) return NS_ERROR_OUT_OF_MEMORY;
 12065     return NS_OK;
 12069 NS_IMETHODIMP nsDocShell::EnsureFind()
 12071     nsresult rv;
 12072     if (!mFind)
 12074         mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
 12075         if (NS_FAILED(rv)) return rv;
 12078     // we promise that the nsIWebBrowserFind that we return has been set
 12079     // up to point to the focused, or content window, so we have to
 12080     // set that up each time.
 12082     nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
 12083     NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
 12085     // default to our window
 12086     nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(scriptGO);
 12087     nsCOMPtr<nsPIDOMWindow> windowToSearch;
 12088     nsFocusManager::GetFocusedDescendant(ourWindow, true, getter_AddRefs(windowToSearch));
 12090     nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
 12091     if (!findInFrames) return NS_ERROR_NO_INTERFACE;
 12093     rv = findInFrames->SetRootSearchFrame(ourWindow);
 12094     if (NS_FAILED(rv)) return rv;
 12095     rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
 12096     if (NS_FAILED(rv)) return rv;
 12098     return NS_OK;
 12101 bool
 12102 nsDocShell::IsFrame()
 12104     nsCOMPtr<nsIDocShellTreeItem> parent;
 12105     GetSameTypeParent(getter_AddRefs(parent));
 12106     return !!parent;
 12109 /* boolean IsBeingDestroyed (); */
 12110 NS_IMETHODIMP 
 12111 nsDocShell::IsBeingDestroyed(bool *aDoomed)
 12113   NS_ENSURE_ARG(aDoomed);
 12114   *aDoomed = mIsBeingDestroyed;
 12115   return NS_OK;
 12119 NS_IMETHODIMP 
 12120 nsDocShell::GetIsExecutingOnLoadHandler(bool *aResult)
 12122   NS_ENSURE_ARG(aResult);
 12123   *aResult = mIsExecutingOnLoadHandler;
 12124   return NS_OK;
 12127 NS_IMETHODIMP
 12128 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState **aLayoutHistoryState)
 12130   if (mOSHE)
 12131     mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
 12132   return NS_OK;
 12135 NS_IMETHODIMP
 12136 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState)
 12138   if (mOSHE)
 12139     mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
 12140   return NS_OK;
 12143 //*****************************************************************************
 12144 //***    nsRefreshTimer: Object Management
 12145 //*****************************************************************************
 12147 nsRefreshTimer::nsRefreshTimer()
 12148     : mDelay(0), mRepeat(false), mMetaRefresh(false)
 12152 nsRefreshTimer::~nsRefreshTimer()
 12156 //*****************************************************************************
 12157 // nsRefreshTimer::nsISupports
 12158 //*****************************************************************************   
 12160 NS_IMPL_ADDREF(nsRefreshTimer)
 12161 NS_IMPL_RELEASE(nsRefreshTimer)
 12163 NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
 12164     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
 12165     NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
 12166 NS_INTERFACE_MAP_END_THREADSAFE
 12168 ///*****************************************************************************
 12169 // nsRefreshTimer::nsITimerCallback
 12170 //******************************************************************************
 12171 NS_IMETHODIMP
 12172 nsRefreshTimer::Notify(nsITimer * aTimer)
 12174     NS_ASSERTION(mDocShell, "DocShell is somehow null");
 12176     if (mDocShell && aTimer) {
 12177         // Get the delay count to determine load type
 12178         uint32_t delay = 0;
 12179         aTimer->GetDelay(&delay);
 12180         mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer);
 12182     return NS_OK;
 12185 //*****************************************************************************
 12186 // nsDocShell::InterfaceRequestorProxy
 12187 //*****************************************************************************
 12188 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor* p)
 12190     if (p) {
 12191         mWeakPtr = do_GetWeakReference(p);
 12195 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
 12197     mWeakPtr = nullptr;
 12200 NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor) 
 12202 NS_IMETHODIMP 
 12203 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID & aIID, void **aSink)
 12205     NS_ENSURE_ARG_POINTER(aSink);
 12206     nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
 12207     if (ifReq) {
 12208         return ifReq->GetInterface(aIID, aSink);
 12210     *aSink = nullptr;
 12211     return NS_NOINTERFACE;
 12214 nsresult
 12215 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer)
 12217     if (!aContentViewer)
 12218         return NS_ERROR_FAILURE;
 12220     nsCOMPtr<nsIURI> baseURI;
 12221     nsresult rv = NS_ERROR_NOT_AVAILABLE;
 12223     if (sURIFixup)
 12224         rv = sURIFixup->CreateExposableURI(mCurrentURI,
 12225                                            getter_AddRefs(baseURI));
 12227     // Get the current document and set the base uri
 12228     if (baseURI) {
 12229         nsIDocument* document = aContentViewer->GetDocument();
 12230         if (document) {
 12231             rv = document->SetBaseURI(baseURI);
 12234     return rv;
 12237 //*****************************************************************************
 12238 // nsDocShell::nsIAuthPromptProvider
 12239 //*****************************************************************************
 12241 NS_IMETHODIMP
 12242 nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
 12243                           void** aResult)
 12245     // a priority prompt request will override a false mAllowAuth setting
 12246     bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
 12248     if (!mAllowAuth && !priorityPrompt)
 12249         return NS_ERROR_NOT_AVAILABLE;
 12251     // we're either allowing auth, or it's a proxy request
 12252     nsresult rv;
 12253     nsCOMPtr<nsIPromptFactory> wwatch =
 12254       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
 12255     NS_ENSURE_SUCCESS(rv, rv);
 12257     rv = EnsureScriptEnvironment();
 12258     NS_ENSURE_SUCCESS(rv, rv);
 12260     // Get the an auth prompter for our window so that the parenting
 12261     // of the dialogs works as it should when using tabs.
 12263     return wwatch->GetPrompt(mScriptGlobal, iid,
 12264                              reinterpret_cast<void**>(aResult));
 12267 //*****************************************************************************
 12268 // nsDocShell::nsILoadContext
 12269 //*****************************************************************************
 12270 NS_IMETHODIMP
 12271 nsDocShell::GetAssociatedWindow(nsIDOMWindow** aWindow)
 12273     CallGetInterface(this, aWindow);
 12274     return NS_OK;
 12277 NS_IMETHODIMP
 12278 nsDocShell::GetTopWindow(nsIDOMWindow** aWindow)
 12280     nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this));
 12281     if (win) {
 12282         win->GetTop(aWindow);
 12284     return NS_OK;
 12287 NS_IMETHODIMP
 12288 nsDocShell::GetTopFrameElement(nsIDOMElement** aElement)
 12290     *aElement = nullptr;
 12291     nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this));
 12292     if (!win) {
 12293         return NS_OK;
 12296     nsCOMPtr<nsIDOMWindow> top;
 12297     win->GetScriptableTop(getter_AddRefs(top));
 12298     NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
 12300     // GetFrameElement, /not/ GetScriptableFrameElement -- if |top| is inside
 12301     // <iframe mozbrowser>, we want to return the iframe, not null.
 12302     return top->GetFrameElement(aElement);
 12305 NS_IMETHODIMP
 12306 nsDocShell::IsAppOfType(uint32_t aAppType, bool *aIsOfType)
 12308     nsCOMPtr<nsIDocShell> shell = this;
 12309     while (shell) {
 12310         uint32_t type;
 12311         shell->GetAppType(&type);
 12312         if (type == aAppType) {
 12313             *aIsOfType = true;
 12314             return NS_OK;
 12316         nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(shell);
 12317         nsCOMPtr<nsIDocShellTreeItem> parent;
 12318         item->GetParent(getter_AddRefs(parent));
 12319         shell = do_QueryInterface(parent);
 12322     *aIsOfType = false;
 12323     return NS_OK;
 12326 NS_IMETHODIMP
 12327 nsDocShell::GetIsContent(bool *aIsContent)
 12329     *aIsContent = (mItemType == typeContent);
 12330     return NS_OK;
 12333 bool
 12334 nsDocShell::IsOKToLoadURI(nsIURI* aURI)
 12336     NS_PRECONDITION(aURI, "Must have a URI!");
 12338     if (!mFiredUnloadEvent) {
 12339         return true;
 12342     if (!mLoadingURI) {
 12343         return false;
 12346     nsCOMPtr<nsIScriptSecurityManager> secMan =
 12347         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
 12348     return
 12349         secMan &&
 12350         NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
 12353 //
 12354 // Routines for selection and clipboard
 12355 //
 12356 nsresult
 12357 nsDocShell::GetControllerForCommand(const char * inCommand,
 12358                                     nsIController** outController)
 12360     NS_ENSURE_ARG_POINTER(outController);
 12361     *outController = nullptr;
 12363     NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
 12365     nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
 12366     NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
 12368     return root->GetControllerForCommand(inCommand, outController);
 12371 NS_IMETHODIMP
 12372 nsDocShell::IsCommandEnabled(const char * inCommand, bool* outEnabled)
 12374   NS_ENSURE_ARG_POINTER(outEnabled);
 12375   *outEnabled = false;
 12377   nsresult rv = NS_ERROR_FAILURE;
 12379   nsCOMPtr<nsIController> controller;
 12380   rv = GetControllerForCommand (inCommand, getter_AddRefs(controller));
 12381   if (controller)
 12382     rv = controller->IsCommandEnabled(inCommand, outEnabled);
 12384   return rv;
 12387 NS_IMETHODIMP
 12388 nsDocShell::DoCommand(const char * inCommand)
 12390   nsresult rv = NS_ERROR_FAILURE;
 12392   nsCOMPtr<nsIController> controller;
 12393   rv = GetControllerForCommand(inCommand, getter_AddRefs(controller));
 12394   if (controller)
 12395     rv = controller->DoCommand(inCommand);
 12397   return rv;
 12400 nsresult
 12401 nsDocShell::EnsureCommandHandler()
 12403   if (!mCommandManager)
 12405     nsCOMPtr<nsPICommandUpdater> commandUpdater =
 12406       do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
 12407     if (!commandUpdater) return NS_ERROR_OUT_OF_MEMORY;
 12409     nsCOMPtr<nsIDOMWindow> domWindow =
 12410       do_GetInterface(static_cast<nsIInterfaceRequestor *>(this));
 12412     nsresult rv = commandUpdater->Init(domWindow);
 12413     if (NS_SUCCEEDED(rv))
 12414       mCommandManager = do_QueryInterface(commandUpdater);
 12417   return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
 12420 NS_IMETHODIMP
 12421 nsDocShell::CanCutSelection(bool* aResult)
 12423   return IsCommandEnabled("cmd_cut", aResult);
 12426 NS_IMETHODIMP
 12427 nsDocShell::CanCopySelection(bool* aResult)
 12429   return IsCommandEnabled("cmd_copy", aResult);
 12432 NS_IMETHODIMP
 12433 nsDocShell::CanCopyLinkLocation(bool* aResult)
 12435   return IsCommandEnabled("cmd_copyLink", aResult);
 12438 NS_IMETHODIMP
 12439 nsDocShell::CanCopyImageLocation(bool* aResult)
 12441   return IsCommandEnabled("cmd_copyImageLocation",
 12442                           aResult);
 12445 NS_IMETHODIMP
 12446 nsDocShell::CanCopyImageContents(bool* aResult)
 12448   return IsCommandEnabled("cmd_copyImageContents",
 12449                           aResult);
 12452 NS_IMETHODIMP
 12453 nsDocShell::CanPaste(bool* aResult)
 12455   return IsCommandEnabled("cmd_paste", aResult);
 12458 NS_IMETHODIMP
 12459 nsDocShell::CutSelection(void)
 12461   return DoCommand ( "cmd_cut" );
 12464 NS_IMETHODIMP
 12465 nsDocShell::CopySelection(void)
 12467   return DoCommand ( "cmd_copy" );
 12470 NS_IMETHODIMP
 12471 nsDocShell::CopyLinkLocation(void)
 12473   return DoCommand ( "cmd_copyLink" );
 12476 NS_IMETHODIMP
 12477 nsDocShell::CopyImageLocation(void)
 12479   return DoCommand ( "cmd_copyImageLocation" );
 12482 NS_IMETHODIMP
 12483 nsDocShell::CopyImageContents(void)
 12485   return DoCommand ( "cmd_copyImageContents" );
 12488 NS_IMETHODIMP
 12489 nsDocShell::Paste(void)
 12491   return DoCommand ( "cmd_paste" );
 12494 NS_IMETHODIMP
 12495 nsDocShell::SelectAll(void)
 12497   return DoCommand ( "cmd_selectAll" );
 12500 //
 12501 // SelectNone
 12502 //
 12503 // Collapses the current selection, insertion point ends up at beginning
 12504 // of previous selection.
 12505 //
 12506 NS_IMETHODIMP
 12507 nsDocShell::SelectNone(void)
 12509   return DoCommand ( "cmd_selectNone" );
 12512 //----------------------------------------------------------------------
 12514 // link handling
 12516 class OnLinkClickEvent : public nsRunnable {
 12517 public:
 12518   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
 12519                    nsIURI* aURI,
 12520                    const char16_t* aTargetSpec,
 12521                    const nsAString& aFileName,
 12522                    nsIInputStream* aPostDataStream,
 12523                    nsIInputStream* aHeadersDataStream,
 12524                    bool aIsTrusted);
 12526   NS_IMETHOD Run() {
 12527     nsAutoPopupStatePusher popupStatePusher(mPopupState);
 12529     nsCxPusher pusher;
 12530     if (mIsTrusted || pusher.Push(mContent)) {
 12531       mHandler->OnLinkClickSync(mContent, mURI,
 12532                                 mTargetSpec.get(), mFileName,
 12533                                 mPostDataStream, mHeadersDataStream,
 12534                                 nullptr, nullptr);
 12536     return NS_OK;
 12539 private:
 12540   nsRefPtr<nsDocShell>     mHandler;
 12541   nsCOMPtr<nsIURI>         mURI;
 12542   nsString                 mTargetSpec;
 12543   nsString                mFileName;
 12544   nsCOMPtr<nsIInputStream> mPostDataStream;
 12545   nsCOMPtr<nsIInputStream> mHeadersDataStream;
 12546   nsCOMPtr<nsIContent>     mContent;
 12547   PopupControlState        mPopupState;
 12548   bool                     mIsTrusted;
 12549 };
 12551 OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
 12552                                    nsIContent *aContent,
 12553                                    nsIURI* aURI,
 12554                                    const char16_t* aTargetSpec,
 12555                                    const nsAString& aFileName,
 12556                                    nsIInputStream* aPostDataStream,
 12557                                    nsIInputStream* aHeadersDataStream,
 12558                                    bool aIsTrusted)
 12559   : mHandler(aHandler)
 12560   , mURI(aURI)
 12561   , mTargetSpec(aTargetSpec)
 12562   , mFileName(aFileName)
 12563   , mPostDataStream(aPostDataStream)
 12564   , mHeadersDataStream(aHeadersDataStream)
 12565   , mContent(aContent)
 12566   , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
 12567   , mIsTrusted(aIsTrusted)
 12571 //----------------------------------------
 12573 NS_IMETHODIMP
 12574 nsDocShell::OnLinkClick(nsIContent* aContent,
 12575                         nsIURI* aURI,
 12576                         const char16_t* aTargetSpec,
 12577                         const nsAString& aFileName,
 12578                         nsIInputStream* aPostDataStream,
 12579                         nsIInputStream* aHeadersDataStream,
 12580                         bool aIsTrusted)
 12582   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
 12584   if (!IsOKToLoadURI(aURI)) {
 12585     return NS_OK;
 12588   // On history navigation through Back/Forward buttons, don't execute
 12589   // automatic JavaScript redirection such as |anchorElement.click()| or
 12590   // |formElement.submit()|.
 12591   //
 12592   // XXX |formElement.submit()| bypasses this checkpoint because it calls
 12593   //     nsDocShell::OnLinkClickSync(...) instead.
 12594   if (ShouldBlockLoadingForBackButton()) {
 12595     return NS_OK;
 12598   if (aContent->IsEditable()) {
 12599     return NS_OK;
 12602   nsresult rv = NS_ERROR_FAILURE;
 12603   nsAutoString target;
 12605   nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
 12606   if (browserChrome3) {
 12607     nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
 12608     nsAutoString oldTarget(aTargetSpec);
 12609     rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
 12610                                                linkNode, mIsAppTab, target);
 12613   if (NS_FAILED(rv))
 12614     target = aTargetSpec;  
 12616   nsCOMPtr<nsIRunnable> ev =
 12617       new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName, 
 12618                            aPostDataStream, aHeadersDataStream, aIsTrusted);
 12619   return NS_DispatchToCurrentThread(ev);
 12622 NS_IMETHODIMP
 12623 nsDocShell::OnLinkClickSync(nsIContent *aContent,
 12624                             nsIURI* aURI,
 12625                             const char16_t* aTargetSpec,
 12626                             const nsAString& aFileName,
 12627                             nsIInputStream* aPostDataStream,
 12628                             nsIInputStream* aHeadersDataStream,
 12629                             nsIDocShell** aDocShell,
 12630                             nsIRequest** aRequest)
 12632   // Initialize the DocShell / Request
 12633   if (aDocShell) {
 12634     *aDocShell = nullptr;
 12636   if (aRequest) {
 12637     *aRequest = nullptr;
 12640   if (!IsOKToLoadURI(aURI)) {
 12641     return NS_OK;
 12644   // XXX When the linking node was HTMLFormElement, it is synchronous event.
 12645   //     That is, the caller of this method is not |OnLinkClickEvent::Run()|
 12646   //     but |HTMLFormElement::SubmitSubmission(...)|.
 12647   if (nsGkAtoms::form == aContent->Tag() && ShouldBlockLoadingForBackButton()) {
 12648     return NS_OK;
 12651   if (aContent->IsEditable()) {
 12652     return NS_OK;
 12656     // defer to an external protocol handler if necessary...
 12657     nsCOMPtr<nsIExternalProtocolService> extProtService =
 12658         do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
 12659     if (extProtService) {
 12660       nsAutoCString scheme;
 12661       aURI->GetScheme(scheme);
 12662       if (!scheme.IsEmpty()) {
 12663         // if the URL scheme does not correspond to an exposed protocol, then we
 12664         // need to hand this link click over to the external protocol handler.
 12665         bool isExposed;
 12666         nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
 12667         if (NS_SUCCEEDED(rv) && !isExposed) {
 12668           return extProtService->LoadURI(aURI, this); 
 12674   // Get the owner document of the link that was clicked, this will be
 12675   // the document that the link is in, or the last document that the
 12676   // link was in. From that document, we'll get the URI to use as the
 12677   // referer, since the current URI in this docshell may be a
 12678   // new document that we're in the process of loading.
 12679   nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
 12680   NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
 12682   // Now check that the refererDoc's inner window is the current inner
 12683   // window for mScriptGlobal.  If it's not, then we don't want to
 12684   // follow this link.
 12685   nsPIDOMWindow* refererInner = refererDoc->GetInnerWindow();
 12686   NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
 12687   if (!mScriptGlobal ||
 12688       mScriptGlobal->GetCurrentInnerWindow() != refererInner) {
 12689       // We're no longer the current inner window
 12690       return NS_OK;
 12693   nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
 12695   // referer could be null here in some odd cases, but that's ok,
 12696   // we'll just load the link w/o sending a referer in those cases.
 12698   nsAutoString target(aTargetSpec);
 12700   // If this is an anchor element, grab its type property to use as a hint
 12701   nsAutoString typeHint;
 12702   nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent));
 12703   if (anchor) {
 12704     anchor->GetType(typeHint);
 12705     NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
 12706     nsAutoCString type, dummy;
 12707     NS_ParseContentType(utf8Hint, type, dummy);
 12708     CopyUTF8toUTF16(type, typeHint);
 12711   // Clone the URI now, in case a content policy or something messes
 12712   // with it under InternalLoad; we do _not_ want to change the URI
 12713   // our caller passed in.
 12714   nsCOMPtr<nsIURI> clonedURI;
 12715   aURI->Clone(getter_AddRefs(clonedURI));
 12716   if (!clonedURI) {
 12717     return NS_ERROR_OUT_OF_MEMORY;
 12720   nsresult rv = InternalLoad(clonedURI,                 // New URI
 12721                              referer,                   // Referer URI
 12722                              aContent->NodePrincipal(), // Owner is our node's
 12723                                                         // principal
 12724                              INTERNAL_LOAD_FLAGS_NONE,
 12725                              target.get(),              // Window target
 12726                              NS_LossyConvertUTF16toASCII(typeHint).get(),
 12727                              aFileName,                 // Download as file
 12728                              aPostDataStream,           // Post data stream
 12729                              aHeadersDataStream,        // Headers stream
 12730                              LOAD_LINK,                 // Load type
 12731                              nullptr,                   // No SHEntry
 12732                              true,                      // first party site
 12733                              NullString(),              // No srcdoc
 12734                              this,                      // We are the source
 12735                              nullptr,                   // baseURI not needed
 12736                              aDocShell,                 // DocShell out-param
 12737                              aRequest);                 // Request out-param
 12738   if (NS_SUCCEEDED(rv)) {
 12739     DispatchPings(aContent, aURI, referer);
 12741   return rv;
 12744 NS_IMETHODIMP
 12745 nsDocShell::OnOverLink(nsIContent* aContent,
 12746                        nsIURI* aURI,
 12747                        const char16_t* aTargetSpec)
 12749   if (aContent->IsEditable()) {
 12750     return NS_OK;
 12753   nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
 12754   nsresult rv = NS_ERROR_FAILURE;
 12756   nsCOMPtr<nsIWebBrowserChrome> browserChrome;
 12757   if (!browserChrome2) {
 12758     browserChrome = do_GetInterface(mTreeOwner);
 12759     if (!browserChrome)
 12760       return rv;
 12763   nsCOMPtr<nsITextToSubURI> textToSubURI =
 12764       do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
 12765   if (NS_FAILED(rv))
 12766     return rv;
 12768   // use url origin charset to unescape the URL
 12769   nsAutoCString charset;
 12770   rv = aURI->GetOriginCharset(charset);
 12771   NS_ENSURE_SUCCESS(rv, rv);
 12773   nsAutoCString spec;
 12774   rv = aURI->GetSpec(spec);
 12775   NS_ENSURE_SUCCESS(rv, rv);
 12777   nsAutoString uStr;
 12778   rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr);    
 12779   NS_ENSURE_SUCCESS(rv, rv);
 12781   mozilla::net::SeerPredict(aURI, mCurrentURI, nsINetworkSeer::PREDICT_LINK,
 12782                             this, nullptr);
 12784   if (browserChrome2) {
 12785     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
 12786     rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
 12787                                               uStr, element);
 12788   } else {
 12789     rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
 12791   return rv;
 12794 NS_IMETHODIMP
 12795 nsDocShell::OnLeaveLink()
 12797   nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
 12798   nsresult rv = NS_ERROR_FAILURE;
 12800   if (browserChrome)  {
 12801       rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
 12802                                     EmptyString().get());
 12804   return rv;
 12807 bool
 12808 nsDocShell::ShouldBlockLoadingForBackButton()
 12810   if (!(mLoadType & LOAD_CMD_HISTORY) ||
 12811       EventStateManager::IsHandlingUserInput() ||
 12812       !Preferences::GetBool("accessibility.blockjsredirection")) {
 12813     return false;
 12816   bool canGoForward = false;
 12817   GetCanGoForward(&canGoForward);
 12818   return canGoForward;
 12821 bool 
 12822 nsDocShell::PluginsAllowedInCurrentDoc()
 12824   bool pluginsAllowed = false;
 12826   if (!mContentViewer) {
 12827     return false;
 12830   nsIDocument* doc = mContentViewer->GetDocument();
 12831   if (!doc) {
 12832     return false;
 12835   doc->GetAllowPlugins(&pluginsAllowed);
 12836   return pluginsAllowed;
 12839 //----------------------------------------------------------------------
 12840 // Web Shell Services API
 12842 //This functions is only called when a new charset is detected in loading a document. 
 12843 //Its name should be changed to "CharsetReloadDocument"
 12844 NS_IMETHODIMP
 12845 nsDocShell::ReloadDocument(const char* aCharset,
 12846                            int32_t aSource)
 12849   // XXX hack. keep the aCharset and aSource wait to pick it up
 12850   nsCOMPtr<nsIContentViewer> cv;
 12851   NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
 12852   if (cv)
 12854     nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);  
 12855     if (muDV)
 12857       int32_t hint;
 12858       muDV->GetHintCharacterSetSource(&hint);
 12859       if (aSource > hint)
 12861         nsCString charset(aCharset);
 12862         muDV->SetHintCharacterSet(charset);
 12863         muDV->SetHintCharacterSetSource(aSource);
 12864         if(eCharsetReloadRequested != mCharsetReloadState) 
 12866           mCharsetReloadState = eCharsetReloadRequested;
 12867           return Reload(LOAD_FLAGS_CHARSET_CHANGE);
 12872   //return failure if this request is not accepted due to mCharsetReloadState
 12873   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
 12877 NS_IMETHODIMP
 12878 nsDocShell::StopDocumentLoad(void)
 12880   if(eCharsetReloadRequested != mCharsetReloadState) 
 12882     Stop(nsIWebNavigation::STOP_ALL);
 12883     return NS_OK;
 12885   //return failer if this request is not accepted due to mCharsetReloadState
 12886   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
 12889 NS_IMETHODIMP
 12890 nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
 12892   *aPrintPreview = nullptr;
 12893 #if NS_PRINT_PREVIEW
 12894   nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
 12895   if (!print || !print->IsInitializedForPrintPreview()) {
 12896     Stop(nsIWebNavigation::STOP_ALL);
 12897     nsCOMPtr<nsIPrincipal> principal =
 12898       do_CreateInstance("@mozilla.org/nullprincipal;1");
 12899     NS_ENSURE_STATE(principal);
 12900     nsresult rv = CreateAboutBlankContentViewer(principal, nullptr);
 12901     NS_ENSURE_SUCCESS(rv, rv);
 12902     print = do_QueryInterface(mContentViewer);
 12903     NS_ENSURE_STATE(print);
 12904     print->InitializeForPrintPreview();
 12906   nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
 12907   result.forget(aPrintPreview);
 12908   return NS_OK;
 12909 #else
 12910   return NS_ERROR_NOT_IMPLEMENTED;
 12911 #endif
 12915 #ifdef DEBUG
 12916 unsigned long nsDocShell::gNumberOfDocShells = 0;
 12917 #endif
 12919 NS_IMETHODIMP
 12920 nsDocShell::GetCanExecuteScripts(bool *aResult)
 12922   *aResult = mCanExecuteScripts;
 12923   return NS_OK;
 12926 NS_IMETHODIMP
 12927 nsDocShell::SetIsApp(uint32_t aOwnAppId)
 12929     mOwnOrContainingAppId = aOwnAppId;
 12930     if (aOwnAppId != nsIScriptSecurityManager::NO_APP_ID &&
 12931         aOwnAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
 12932         mFrameType = eFrameTypeApp;
 12933     } else {
 12934         mFrameType = eFrameTypeRegular;
 12937     return NS_OK;
 12940 NS_IMETHODIMP
 12941 nsDocShell::SetIsBrowserInsideApp(uint32_t aContainingAppId)
 12943     mOwnOrContainingAppId = aContainingAppId;
 12944     mFrameType = eFrameTypeBrowser;
 12945     return NS_OK;
 12948 /* [infallible] */ NS_IMETHODIMP
 12949 nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
 12951     *aIsBrowser = (mFrameType == eFrameTypeBrowser);
 12952     return NS_OK;
 12955 /* [infallible] */ NS_IMETHODIMP
 12956 nsDocShell::GetIsApp(bool* aIsApp)
 12958     *aIsApp = (mFrameType == eFrameTypeApp);
 12959     return NS_OK;
 12962 /* [infallible] */ NS_IMETHODIMP
 12963 nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp)
 12965     switch (mFrameType) {
 12966         case eFrameTypeRegular:
 12967             *aIsBrowserOrApp = false;
 12968             break;
 12969         case eFrameTypeBrowser:
 12970         case eFrameTypeApp:
 12971             *aIsBrowserOrApp = true;
 12972             break;
 12975     return NS_OK;
 12978 nsDocShell::FrameType
 12979 nsDocShell::GetInheritedFrameType()
 12981     if (mFrameType != eFrameTypeRegular) {
 12982         return mFrameType;
 12985     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
 12986     GetSameTypeParent(getter_AddRefs(parentAsItem));
 12988     nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
 12989     if (!parent) {
 12990         return eFrameTypeRegular;
 12993     return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
 12996 /* [infallible] */ NS_IMETHODIMP
 12997 nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
 12999     *aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser);
 13000     return NS_OK;
 13003 /* [infallible] */ NS_IMETHODIMP
 13004 nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp)
 13006     switch (GetInheritedFrameType()) {
 13007         case eFrameTypeRegular:
 13008             *aIsInBrowserOrApp = false;
 13009             break;
 13010         case eFrameTypeBrowser:
 13011         case eFrameTypeApp:
 13012             *aIsInBrowserOrApp = true;
 13013             break;
 13016     return NS_OK;
 13019 /* [infallible] */ NS_IMETHODIMP
 13020 nsDocShell::GetAppId(uint32_t* aAppId)
 13022     if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
 13023         *aAppId = mOwnOrContainingAppId;
 13024         return NS_OK;
 13027     nsCOMPtr<nsIDocShell> parent;
 13028     GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
 13030     if (!parent) {
 13031         *aAppId = nsIScriptSecurityManager::NO_APP_ID;
 13032         return NS_OK;
 13035     return parent->GetAppId(aAppId);
 13038 NS_IMETHODIMP
 13039 nsDocShell::GetAppManifestURL(nsAString& aAppManifestURL)
 13041   uint32_t appId;
 13042   GetAppId(&appId);
 13044   if (appId != nsIScriptSecurityManager::NO_APP_ID &&
 13045       appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
 13046     nsCOMPtr<nsIAppsService> appsService =
 13047       do_GetService(APPS_SERVICE_CONTRACTID);
 13048     NS_ASSERTION(appsService, "No AppsService available");
 13049     appsService->GetManifestURLByLocalId(appId, aAppManifestURL);
 13050   } else {
 13051     aAppManifestURL.SetLength(0);
 13054   return NS_OK;
 13057 NS_IMETHODIMP
 13058 nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
 13060     if (TabChild* tabChild = TabChild::GetFrom(this)) {
 13061         *aOut = tabChild->IsAsyncPanZoomEnabled();
 13062         return NS_OK;
 13064     *aOut = false;
 13065     return NS_OK;
 13068 bool
 13069 nsDocShell::HasUnloadedParent()
 13071     nsCOMPtr<nsIDocShellTreeItem> currentTreeItem = this;
 13072     while (currentTreeItem) {
 13073         nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
 13074         currentTreeItem->GetParent(getter_AddRefs(parentTreeItem));
 13075         nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem);
 13076         if (parent) {
 13077             bool inUnload = false;
 13078             parent->GetIsInUnload(&inUnload);
 13079             if (inUnload) {
 13080                 return true;
 13083         currentTreeItem.swap(parentTreeItem);
 13085     return false;
 13088 bool
 13089 nsDocShell::IsInvisible()
 13091     return mInvisible;
 13094 void
 13095 nsDocShell::SetInvisible(bool aInvisible)
 13097     mInvisible = aInvisible;

mercurial