LCOV - code coverage report
Current view: directory - docshell/base - nsDocShell.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 4954 0 0.0 %
Date: 2012-06-02 Functions: 349 0 0.0 %

       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                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is the Mozilla browser.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications, Inc.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Travis Bogard <travis@netscape.com>
      25                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      26                 :  *   Peter Annema <disttsc@bart.nl>
      27                 :  *   Dan Rosen <dr@netscape.com>
      28                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      29                 :  *
      30                 :  * Alternatively, the contents of this file may be used under the terms of
      31                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      32                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      33                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      34                 :  * of those above. If you wish to allow use of your version of this file only
      35                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      36                 :  * use your version of this file under the terms of the MPL, indicate your
      37                 :  * decision by deleting the provisions above and replace them with the notice
      38                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      39                 :  * the provisions above, a recipient may use your version of this file under
      40                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      41                 :  *
      42                 :  * ***** END LICENSE BLOCK ***** */
      43                 : 
      44                 : #include "mozilla/Util.h"
      45                 : 
      46                 : #ifdef MOZ_LOGGING
      47                 : // so we can get logging even in release builds (but only for some things)
      48                 : #define FORCE_PR_LOG 1
      49                 : #endif
      50                 : 
      51                 : #include "nsIBrowserDOMWindow.h"
      52                 : #include "nsIComponentManager.h"
      53                 : #include "nsIContent.h"
      54                 : #include "mozilla/dom/Element.h"
      55                 : #include "nsIDocument.h"
      56                 : #include "nsIDOMDocument.h"
      57                 : #include "nsIDOMElement.h"
      58                 : #include "nsIDOMStorage.h"
      59                 : #include "nsPIDOMStorage.h"
      60                 : #include "nsIContentViewer.h"
      61                 : #include "nsIDocumentLoaderFactory.h"
      62                 : #include "nsCURILoader.h"
      63                 : #include "nsURILoader.h"
      64                 : #include "nsDocShellCID.h"
      65                 : #include "nsLayoutCID.h"
      66                 : #include "nsDOMCID.h"
      67                 : #include "nsIDOMScriptObjectFactory.h"
      68                 : #include "nsNetUtil.h"
      69                 : #include "nsRect.h"
      70                 : #include "prprf.h"
      71                 : #include "prenv.h"
      72                 : #include "nsIMarkupDocumentViewer.h"
      73                 : #include "nsXPIDLString.h"
      74                 : #include "nsReadableUtils.h"
      75                 : #include "nsIDOMChromeWindow.h"
      76                 : #include "nsIDOMWindow.h"
      77                 : #include "nsIWebBrowserChrome.h"
      78                 : #include "nsPoint.h"
      79                 : #include "nsGfxCIID.h"
      80                 : #include "nsIObserverService.h"
      81                 : #include "nsIPrompt.h"
      82                 : #include "nsIAuthPrompt.h"
      83                 : #include "nsIAuthPrompt2.h"
      84                 : #include "nsTextFormatter.h"
      85                 : #include "nsIChannelEventSink.h"
      86                 : #include "nsIAsyncVerifyRedirectCallback.h"
      87                 : #include "nsIUploadChannel.h"
      88                 : #include "nsISecurityEventSink.h"
      89                 : #include "mozilla/FunctionTimer.h"
      90                 : #include "nsIScriptSecurityManager.h"
      91                 : #include "nsIJSContextStack.h"
      92                 : #include "nsIScriptObjectPrincipal.h"
      93                 : #include "nsIScrollableFrame.h"
      94                 : #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
      95                 : #include "nsICategoryManager.h"
      96                 : #include "nsXPCOMCID.h"
      97                 : #include "nsISeekableStream.h"
      98                 : #include "nsAutoPtr.h"
      99                 : #include "nsIWritablePropertyBag2.h"
     100                 : #include "nsIAppShell.h"
     101                 : #include "nsWidgetsCID.h"
     102                 : #include "nsDOMJSUtils.h"
     103                 : #include "nsIInterfaceRequestorUtils.h"
     104                 : #include "nsIView.h"
     105                 : #include "nsIViewManager.h"
     106                 : #include "nsIScriptChannel.h"
     107                 : #include "nsIOfflineCacheUpdate.h"
     108                 : #include "nsITimedChannel.h"
     109                 : #include "nsCPrefetchService.h"
     110                 : #include "nsJSON.h"
     111                 : #include "IHistory.h"
     112                 : #include "mozilla/Services.h"
     113                 : #include "mozilla/Preferences.h"
     114                 : #include "mozilla/Telemetry.h"
     115                 : #include "mozilla/AutoRestore.h"
     116                 : 
     117                 : // we want to explore making the document own the load group
     118                 : // so we can associate the document URI with the load group.
     119                 : // until this point, we have an evil hack:
     120                 : #include "nsIHttpChannelInternal.h"  
     121                 : 
     122                 : 
     123                 : // Local Includes
     124                 : #include "nsDocShell.h"
     125                 : #include "nsDocShellLoadInfo.h"
     126                 : #include "nsCDefaultURIFixup.h"
     127                 : #include "nsDocShellEnumerator.h"
     128                 : #include "nsSHistory.h"
     129                 : #include "nsDocShellEditorData.h"
     130                 : 
     131                 : // Helper Classes
     132                 : #include "nsDOMError.h"
     133                 : #include "nsEscape.h"
     134                 : 
     135                 : // Interfaces Needed
     136                 : #include "nsIUploadChannel.h"
     137                 : #include "nsIProgressEventSink.h"
     138                 : #include "nsIWebProgress.h"
     139                 : #include "nsILayoutHistoryState.h"
     140                 : #include "nsITimer.h"
     141                 : #include "nsISHistoryInternal.h"
     142                 : #include "nsIPrincipal.h"
     143                 : #include "nsIFileURL.h"
     144                 : #include "nsIHistoryEntry.h"
     145                 : #include "nsISHistoryListener.h"
     146                 : #include "nsIWindowWatcher.h"
     147                 : #include "nsIPromptFactory.h"
     148                 : #include "nsIObserver.h"
     149                 : #include "nsINestedURI.h"
     150                 : #include "nsITransportSecurityInfo.h"
     151                 : #include "nsINSSErrorsService.h"
     152                 : #include "nsIApplicationCache.h"
     153                 : #include "nsIApplicationCacheChannel.h"
     154                 : #include "nsIApplicationCacheContainer.h"
     155                 : #include "nsIPermissionManager.h"
     156                 : #include "nsStreamUtils.h"
     157                 : #include "nsIController.h"
     158                 : #include "nsPICommandUpdater.h"
     159                 : #include "nsIDOMHTMLAnchorElement.h"
     160                 : #include "nsIWebBrowserChrome3.h"
     161                 : #include "nsITabChild.h"
     162                 : #include "nsIStrictTransportSecurityService.h"
     163                 : #include "nsStructuredCloneContainer.h"
     164                 : #include "nsIStructuredCloneContainer.h"
     165                 : #include "nsIFaviconService.h"
     166                 : #include "mozIAsyncFavicons.h"
     167                 : 
     168                 : // Editor-related
     169                 : #include "nsIEditingSession.h"
     170                 : 
     171                 : #include "nsPIDOMWindow.h"
     172                 : #include "nsPIWindowRoot.h"
     173                 : #include "nsIDOMDocument.h"
     174                 : #include "nsICachingChannel.h"
     175                 : #include "nsICacheVisitor.h"
     176                 : #include "nsICacheEntryDescriptor.h"
     177                 : #include "nsIMultiPartChannel.h"
     178                 : #include "nsIWyciwygChannel.h"
     179                 : 
     180                 : // For reporting errors with the console service.
     181                 : // These can go away if error reporting is propagated up past nsDocShell.
     182                 : #include "nsIConsoleService.h"
     183                 : #include "nsIScriptError.h"
     184                 : 
     185                 : // used to dispatch urls to default protocol handlers
     186                 : #include "nsCExternalHandlerService.h"
     187                 : #include "nsIExternalProtocolService.h"
     188                 : 
     189                 : #include "nsFocusManager.h"
     190                 : 
     191                 : #include "nsITextToSubURI.h"
     192                 : 
     193                 : #include "nsIJARChannel.h"
     194                 : 
     195                 : #include "prlog.h"
     196                 : #include "prmem.h"
     197                 : 
     198                 : #include "nsISelectionDisplay.h"
     199                 : 
     200                 : #include "nsIGlobalHistory2.h"
     201                 : 
     202                 : #ifdef DEBUG_DOCSHELL_FOCUS
     203                 : #include "nsEventStateManager.h"
     204                 : #endif
     205                 : 
     206                 : #include "nsIFrame.h"
     207                 : 
     208                 : // for embedding
     209                 : #include "nsIWebBrowserChromeFocus.h"
     210                 : 
     211                 : #if NS_PRINT_PREVIEW
     212                 : #include "nsIDocumentViewerPrint.h"
     213                 : #include "nsIWebBrowserPrint.h"
     214                 : #endif
     215                 : 
     216                 : #include "nsPluginError.h"
     217                 : #include "nsContentUtils.h"
     218                 : #include "nsContentErrors.h"
     219                 : #include "nsIChannelPolicy.h"
     220                 : #include "nsIContentSecurityPolicy.h"
     221                 : 
     222                 : #include "nsXULAppAPI.h"
     223                 : 
     224                 : #include "nsDOMNavigationTiming.h"
     225                 : #include "nsITimedChannel.h"
     226                 : #include "mozilla/StartupTimeline.h"
     227                 : 
     228                 : static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
     229                 :                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
     230                 : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
     231                 : 
     232                 : #if defined(DEBUG_bryner) || defined(DEBUG_chb)
     233                 : //#define DEBUG_DOCSHELL_FOCUS
     234                 : #define DEBUG_PAGE_CACHE
     235                 : #endif
     236                 : 
     237                 : using namespace mozilla;
     238                 : 
     239                 : // Number of documents currently loading
     240                 : static PRInt32 gNumberOfDocumentsLoading = 0;
     241                 : 
     242                 : // Global count of existing docshells.
     243                 : static PRInt32 gDocShellCount = 0;
     244                 : 
     245                 : // Global reference to the URI fixup service.
     246                 : nsIURIFixup *nsDocShell::sURIFixup = 0;
     247                 : 
     248                 : // True means we validate window targets to prevent frameset
     249                 : // spoofing. Initialize this to a non-bolean value so we know to check
     250                 : // the pref on the creation of the first docshell.
     251                 : static PRUint32 gValidateOrigin = 0xffffffff;
     252                 : 
     253                 : // Hint for native dispatch of events on how long to delay after 
     254                 : // all documents have loaded in milliseconds before favoring normal
     255                 : // native event dispatch priorites over performance
     256                 : #define NS_EVENT_STARVATION_DELAY_HINT 2000
     257                 : 
     258                 : // This is needed for displaying an error message 
     259                 : // when navigation is attempted on a document when printing
     260                 : // The value arbitrary as long as it doesn't conflict with
     261                 : // any of the other values in the errors in DisplayLoadError
     262                 : #define NS_ERROR_DOCUMENT_IS_PRINTMODE  NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL,2001)
     263                 : 
     264                 : #ifdef PR_LOGGING
     265                 : #ifdef DEBUG
     266                 : static PRLogModuleInfo* gDocShellLog;
     267                 : #endif
     268                 : static PRLogModuleInfo* gDocShellLeakLog;
     269                 : #endif
     270                 : 
     271                 : const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
     272                 : const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
     273                 : 
     274                 : static void
     275               0 : FavorPerformanceHint(bool perfOverStarvation, PRUint32 starvationDelay)
     276                 : {
     277               0 :     nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
     278               0 :     if (appShell)
     279               0 :         appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
     280               0 : }
     281                 : 
     282                 : //*****************************************************************************
     283                 : // <a ping> support
     284                 : //*****************************************************************************
     285                 : 
     286                 : #define PREF_PINGS_ENABLED           "browser.send_pings"
     287                 : #define PREF_PINGS_MAX_PER_LINK      "browser.send_pings.max_per_link"
     288                 : #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
     289                 : 
     290                 : // Check prefs to see if pings are enabled and if so what restrictions might
     291                 : // be applied.
     292                 : //
     293                 : // @param maxPerLink
     294                 : //   This parameter returns the number of pings that are allowed per link click
     295                 : //
     296                 : // @param requireSameHost
     297                 : //   This parameter returns true if pings are restricted to the same host as
     298                 : //   the document in which the click occurs.  If the same host restriction is
     299                 : //   imposed, then we still allow for pings to cross over to different
     300                 : //   protocols and ports for flexibility and because it is not possible to send
     301                 : //   a ping via FTP.
     302                 : //
     303                 : // @returns
     304                 : //   true if pings are enabled and false otherwise.
     305                 : //
     306                 : static bool
     307               0 : PingsEnabled(PRInt32 *maxPerLink, bool *requireSameHost)
     308                 : {
     309               0 :   bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false);
     310                 : 
     311               0 :   *maxPerLink = 1;
     312               0 :   *requireSameHost = true;
     313                 : 
     314               0 :   if (allow) {
     315               0 :     Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, maxPerLink);
     316               0 :     Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost);
     317                 :   }
     318                 : 
     319               0 :   return allow;
     320                 : }
     321                 : 
     322                 : static bool
     323               0 : CheckPingURI(nsIURI* uri, nsIContent* content)
     324                 : {
     325               0 :   if (!uri)
     326               0 :     return false;
     327                 : 
     328                 :   // Check with nsIScriptSecurityManager
     329                 :   nsCOMPtr<nsIScriptSecurityManager> ssmgr =
     330               0 :     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
     331               0 :   NS_ENSURE_TRUE(ssmgr, false);
     332                 : 
     333                 :   nsresult rv =
     334               0 :     ssmgr->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri,
     335               0 :                                      nsIScriptSecurityManager::STANDARD);
     336               0 :   if (NS_FAILED(rv)) {
     337               0 :     return false;
     338                 :   }
     339                 : 
     340                 :   // Ignore non-HTTP(S)
     341                 :   bool match;
     342               0 :   if ((NS_FAILED(uri->SchemeIs("http", &match)) || !match) &&
     343               0 :       (NS_FAILED(uri->SchemeIs("https", &match)) || !match)) {
     344               0 :     return false;
     345                 :   }
     346                 : 
     347                 :   // Check with contentpolicy
     348               0 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
     349                 :   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING,
     350                 :                                  uri,
     351                 :                                  content->NodePrincipal(),
     352                 :                                  content,
     353               0 :                                  EmptyCString(), // mime hint
     354                 :                                  nsnull, //extra
     355               0 :                                  &shouldLoad);
     356               0 :   return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
     357                 : }
     358                 : 
     359                 : typedef void (* ForEachPingCallback)(void *closure, nsIContent *content,
     360                 :                                      nsIURI *uri, nsIIOService *ios);
     361                 : 
     362                 : static void
     363               0 : ForEachPing(nsIContent *content, ForEachPingCallback callback, void *closure)
     364                 : {
     365                 :   // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
     366                 :   //       since we'd still need to parse the resulting string.  Instead, we
     367                 :   //       just parse the raw attribute.  It might be nice if the content node
     368                 :   //       implemented an interface that exposed an enumeration of nsIURIs.
     369                 : 
     370                 :   // Make sure we are dealing with either an <A> or <AREA> element in the HTML
     371                 :   // or XHTML namespace.
     372               0 :   if (!content->IsHTML())
     373               0 :     return;
     374               0 :   nsIAtom *nameAtom = content->Tag();
     375               0 :   if (!nameAtom->Equals(NS_LITERAL_STRING("a")) &&
     376               0 :       !nameAtom->Equals(NS_LITERAL_STRING("area")))
     377               0 :     return;
     378                 : 
     379               0 :   nsCOMPtr<nsIAtom> pingAtom = do_GetAtom("ping");
     380               0 :   if (!pingAtom)
     381                 :     return;
     382                 : 
     383               0 :   nsAutoString value;
     384               0 :   content->GetAttr(kNameSpaceID_None, pingAtom, value);
     385               0 :   if (value.IsEmpty())
     386                 :     return;
     387                 : 
     388               0 :   nsCOMPtr<nsIIOService> ios = do_GetIOService();
     389               0 :   if (!ios)
     390                 :     return;
     391                 : 
     392               0 :   nsIDocument *doc = content->OwnerDoc();
     393                 : 
     394                 :   // value contains relative URIs split on spaces (U+0020)
     395               0 :   const PRUnichar *start = value.BeginReading();
     396               0 :   const PRUnichar *end   = value.EndReading();
     397               0 :   const PRUnichar *iter  = start;
     398               0 :   for (;;) {
     399               0 :     if (iter < end && *iter != ' ') {
     400               0 :       ++iter;
     401                 :     } else {  // iter is pointing at either end or a space
     402               0 :       while (*start == ' ' && start < iter)
     403               0 :         ++start;
     404               0 :       if (iter != start) {
     405               0 :         nsCOMPtr<nsIURI> uri, baseURI = content->GetBaseURI();
     406               0 :         ios->NewURI(NS_ConvertUTF16toUTF8(Substring(start, iter)),
     407               0 :                     doc->GetDocumentCharacterSet().get(),
     408               0 :                     baseURI, getter_AddRefs(uri));
     409               0 :         if (CheckPingURI(uri, content)) {
     410               0 :           callback(closure, content, uri, ios);
     411                 :         }
     412                 :       }
     413               0 :       start = iter = iter + 1;
     414               0 :       if (iter >= end)
     415                 :         break;
     416                 :     }
     417                 :   }
     418                 : }
     419                 : 
     420                 : //----------------------------------------------------------------------
     421                 : 
     422                 : // We wait this many milliseconds before killing the ping channel...
     423                 : #define PING_TIMEOUT 10000
     424                 : 
     425                 : static void
     426               0 : OnPingTimeout(nsITimer *timer, void *closure)
     427                 : {
     428               0 :   nsILoadGroup *loadGroup = static_cast<nsILoadGroup *>(closure);
     429               0 :   loadGroup->Cancel(NS_ERROR_ABORT);
     430               0 :   loadGroup->Release();
     431               0 : }
     432                 : 
     433                 : // Check to see if two URIs have the same host or not
     434                 : static bool
     435               0 : IsSameHost(nsIURI *uri1, nsIURI *uri2)
     436                 : {
     437               0 :   nsCAutoString host1, host2;
     438               0 :   uri1->GetAsciiHost(host1);
     439               0 :   uri2->GetAsciiHost(host2);
     440               0 :   return host1.Equals(host2);
     441                 : }
     442                 : 
     443                 : class nsPingListener : public nsIStreamListener
     444                 :                      , public nsIInterfaceRequestor
     445                 :                      , public nsIChannelEventSink
     446               0 : {
     447                 : public:
     448                 :   NS_DECL_ISUPPORTS
     449                 :   NS_DECL_NSIREQUESTOBSERVER
     450                 :   NS_DECL_NSISTREAMLISTENER
     451                 :   NS_DECL_NSIINTERFACEREQUESTOR
     452                 :   NS_DECL_NSICHANNELEVENTSINK
     453                 : 
     454               0 :   nsPingListener(bool requireSameHost, nsIContent* content)
     455                 :     : mRequireSameHost(requireSameHost),
     456               0 :       mContent(content)
     457               0 :   {}
     458                 : 
     459                 : private:
     460                 :   bool mRequireSameHost;
     461                 :   nsCOMPtr<nsIContent> mContent;
     462                 : };
     463                 : 
     464               0 : NS_IMPL_ISUPPORTS4(nsPingListener, nsIStreamListener, nsIRequestObserver,
     465                 :                    nsIInterfaceRequestor, nsIChannelEventSink)
     466                 : 
     467                 : NS_IMETHODIMP
     468               0 : nsPingListener::OnStartRequest(nsIRequest *request, nsISupports *context)
     469                 : {
     470               0 :   return NS_OK;
     471                 : }
     472                 : 
     473                 : NS_IMETHODIMP
     474               0 : nsPingListener::OnDataAvailable(nsIRequest *request, nsISupports *context,
     475                 :                                 nsIInputStream *stream, PRUint32 offset,
     476                 :                                 PRUint32 count)
     477                 : {
     478                 :   PRUint32 result;
     479               0 :   return stream->ReadSegments(NS_DiscardSegment, nsnull, count, &result);
     480                 : }
     481                 : 
     482                 : NS_IMETHODIMP
     483               0 : nsPingListener::OnStopRequest(nsIRequest *request, nsISupports *context,
     484                 :                               nsresult status)
     485                 : {
     486               0 :   return NS_OK;
     487                 : }
     488                 : 
     489                 : NS_IMETHODIMP
     490               0 : nsPingListener::GetInterface(const nsIID &iid, void **result)
     491                 : {
     492               0 :   if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
     493               0 :     NS_ADDREF_THIS();
     494               0 :     *result = (nsIChannelEventSink *) this;
     495               0 :     return NS_OK;
     496                 :   }
     497                 : 
     498               0 :   return NS_ERROR_NO_INTERFACE;
     499                 : }
     500                 : 
     501                 : NS_IMETHODIMP
     502               0 : nsPingListener::AsyncOnChannelRedirect(nsIChannel *oldChan, nsIChannel *newChan,
     503                 :                                        PRUint32 flags,
     504                 :                                        nsIAsyncVerifyRedirectCallback *callback)
     505                 : {
     506               0 :   nsCOMPtr<nsIURI> newURI;
     507               0 :   newChan->GetURI(getter_AddRefs(newURI));
     508                 : 
     509               0 :   if (!CheckPingURI(newURI, mContent))
     510               0 :     return NS_ERROR_ABORT;
     511                 : 
     512               0 :   if (!mRequireSameHost) {
     513               0 :     callback->OnRedirectVerifyCallback(NS_OK);
     514               0 :     return NS_OK;
     515                 :   }
     516                 : 
     517                 :   // XXXbz should this be using something more like the nsContentUtils
     518                 :   // same-origin checker?
     519               0 :   nsCOMPtr<nsIURI> oldURI;
     520               0 :   oldChan->GetURI(getter_AddRefs(oldURI));
     521               0 :   NS_ENSURE_STATE(oldURI && newURI);
     522                 : 
     523               0 :   if (!IsSameHost(oldURI, newURI))
     524               0 :     return NS_ERROR_ABORT;
     525                 : 
     526               0 :   callback->OnRedirectVerifyCallback(NS_OK);
     527               0 :   return NS_OK;
     528                 : }
     529                 : 
     530                 : struct SendPingInfo {
     531                 :   PRInt32 numPings;
     532                 :   PRInt32 maxPings;
     533                 :   bool    requireSameHost;
     534                 :   nsIURI *referrer;
     535                 : };
     536                 : 
     537                 : static void
     538               0 : SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
     539                 : {
     540               0 :   SendPingInfo *info = static_cast<SendPingInfo *>(closure);
     541               0 :   if (info->numPings >= info->maxPings)
     542               0 :     return;
     543                 : 
     544               0 :   if (info->requireSameHost) {
     545                 :     // Make sure the referrer and the given uri share the same origin.  We
     546                 :     // only require the same hostname.  The scheme and port may differ.
     547               0 :     if (!IsSameHost(uri, info->referrer))
     548               0 :       return;
     549                 :   }
     550                 : 
     551               0 :   nsIDocument *doc = content->OwnerDoc();
     552                 : 
     553               0 :   nsCOMPtr<nsIChannel> chan;
     554               0 :   ios->NewChannelFromURI(uri, getter_AddRefs(chan));
     555               0 :   if (!chan)
     556                 :     return;
     557                 : 
     558                 :   // Don't bother caching the result of this URI load.
     559               0 :   chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING);
     560                 : 
     561               0 :   nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
     562               0 :   if (!httpChan)
     563                 :     return;
     564                 : 
     565                 :   // This is needed in order for 3rd-party cookie blocking to work.
     566               0 :   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
     567               0 :   if (httpInternal)
     568               0 :     httpInternal->SetDocumentURI(doc->GetDocumentURI());
     569                 : 
     570               0 :   if (info->referrer)
     571               0 :     httpChan->SetReferrer(info->referrer);
     572                 : 
     573               0 :   httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
     574                 : 
     575                 :   // Remove extraneous request headers (to reduce request size)
     576               0 :   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
     577               0 :                              EmptyCString(), false);
     578               0 :   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
     579               0 :                              EmptyCString(), false);
     580               0 :   httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
     581               0 :                              EmptyCString(), false);
     582                 : 
     583               0 :   nsCOMPtr<nsIUploadChannel> uploadChan = do_QueryInterface(httpChan);
     584               0 :   if (!uploadChan)
     585                 :     return;
     586                 : 
     587                 :   // To avoid sending an unnecessary Content-Type header, we encode the
     588                 :   // closing portion of the headers in the POST body.
     589               0 :   NS_NAMED_LITERAL_CSTRING(uploadData, "Content-Length: 0\r\n\r\n");
     590                 : 
     591               0 :   nsCOMPtr<nsIInputStream> uploadStream;
     592               0 :   NS_NewPostDataStream(getter_AddRefs(uploadStream), false,
     593               0 :                        uploadData, 0);
     594               0 :   if (!uploadStream)
     595                 :     return;
     596                 : 
     597               0 :   uploadChan->SetUploadStream(uploadStream, EmptyCString(), -1);
     598                 : 
     599                 :   // The channel needs to have a loadgroup associated with it, so that we can
     600                 :   // cancel the channel and any redirected channels it may create.
     601                 :   nsCOMPtr<nsILoadGroup> loadGroup =
     602               0 :       do_CreateInstance(NS_LOADGROUP_CONTRACTID);
     603               0 :   if (!loadGroup)
     604                 :     return;
     605               0 :   chan->SetLoadGroup(loadGroup);
     606                 : 
     607                 :   // Construct a listener that merely discards any response.  If successful at
     608                 :   // opening the channel, then it is not necessary to hold a reference to the
     609                 :   // channel.  The networking subsystem will take care of that for us.
     610                 :   nsCOMPtr<nsIStreamListener> listener =
     611               0 :       new nsPingListener(info->requireSameHost, content);
     612               0 :   if (!listener)
     613                 :     return;
     614                 : 
     615                 :   // Observe redirects as well:
     616               0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(listener);
     617               0 :   NS_ASSERTION(callbacks, "oops");
     618               0 :   loadGroup->SetNotificationCallbacks(callbacks);
     619                 : 
     620               0 :   chan->AsyncOpen(listener, nsnull);
     621                 : 
     622                 :   // Even if AsyncOpen failed, we still count this as a successful ping.  It's
     623                 :   // possible that AsyncOpen may have failed after triggering some background
     624                 :   // process that may have written something to the network.
     625               0 :   info->numPings++;
     626                 : 
     627                 :   // Prevent ping requests from stalling and never being garbage collected...
     628                 :   nsCOMPtr<nsITimer> timer =
     629               0 :       do_CreateInstance(NS_TIMER_CONTRACTID);
     630               0 :   if (timer) {
     631               0 :     nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, loadGroup,
     632                 :                                               PING_TIMEOUT,
     633               0 :                                               nsITimer::TYPE_ONE_SHOT);
     634               0 :     if (NS_SUCCEEDED(rv)) {
     635                 :       // When the timer expires, the callback function will release this
     636                 :       // reference to the loadgroup.
     637               0 :       static_cast<nsILoadGroup *>(loadGroup.get())->AddRef();
     638               0 :       loadGroup = 0;
     639                 :     }
     640                 :   }
     641                 :   
     642                 :   // If we failed to setup the timer, then we should just cancel the channel
     643                 :   // because we won't be able to ensure that it goes away in a timely manner.
     644               0 :   if (loadGroup)
     645               0 :     chan->Cancel(NS_ERROR_ABORT);
     646                 : }
     647                 : 
     648                 : // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
     649                 : static void
     650               0 : DispatchPings(nsIContent *content, nsIURI *referrer)
     651                 : {
     652                 :   SendPingInfo info;
     653                 : 
     654               0 :   if (!PingsEnabled(&info.maxPings, &info.requireSameHost))
     655               0 :     return;
     656               0 :   if (info.maxPings == 0)
     657               0 :     return;
     658                 : 
     659               0 :   info.numPings = 0;
     660               0 :   info.referrer = referrer;
     661                 : 
     662               0 :   ForEachPing(content, SendPing, &info);
     663                 : }
     664                 : 
     665                 : static nsDOMPerformanceNavigationType
     666               0 : ConvertLoadTypeToNavigationType(PRUint32 aLoadType)
     667                 : {
     668                 :   // Not initialized, assume it's normal load.
     669               0 :   if (aLoadType == 0) {
     670               0 :     aLoadType = LOAD_NORMAL;
     671                 :   }
     672                 : 
     673               0 :   nsDOMPerformanceNavigationType result = nsIDOMPerformanceNavigation::TYPE_RESERVED;
     674               0 :   switch (aLoadType) {
     675                 :     case LOAD_NORMAL:
     676                 :     case LOAD_NORMAL_EXTERNAL:
     677                 :     case LOAD_NORMAL_BYPASS_CACHE:
     678                 :     case LOAD_NORMAL_BYPASS_PROXY:
     679                 :     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
     680                 :     case LOAD_NORMAL_REPLACE:
     681                 :     case LOAD_LINK:
     682                 :     case LOAD_STOP_CONTENT:
     683               0 :         result = nsIDOMPerformanceNavigation::TYPE_NAVIGATE;
     684               0 :         break;
     685                 :     case LOAD_HISTORY:
     686               0 :         result = nsIDOMPerformanceNavigation::TYPE_BACK_FORWARD;
     687               0 :         break;
     688                 :     case LOAD_RELOAD_NORMAL:
     689                 :     case LOAD_RELOAD_CHARSET_CHANGE:
     690                 :     case LOAD_RELOAD_BYPASS_CACHE:
     691                 :     case LOAD_RELOAD_BYPASS_PROXY:
     692                 :     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
     693               0 :         result = nsIDOMPerformanceNavigation::TYPE_RELOAD;
     694               0 :         break;
     695                 :     case LOAD_STOP_CONTENT_AND_REPLACE:
     696                 :     case LOAD_REFRESH:
     697                 :     case LOAD_BYPASS_HISTORY:
     698                 :     case LOAD_ERROR_PAGE:
     699                 :     case LOAD_PUSHSTATE:
     700               0 :         result = nsIDOMPerformanceNavigation::TYPE_RESERVED;
     701               0 :         break;
     702                 :     default:
     703                 :         // NS_NOTREACHED("Unexpected load type value");
     704               0 :         result = nsIDOMPerformanceNavigation::TYPE_RESERVED;
     705               0 :         break;
     706                 :   }
     707                 : 
     708               0 :   return result;
     709                 : }
     710                 : 
     711                 : static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
     712                 : 
     713                 : //*****************************************************************************
     714                 : //***    nsDocShell: Object Management
     715                 : //*****************************************************************************
     716                 : 
     717                 : static PRUint64 gDocshellIDCounter = 0;
     718                 : 
     719                 : // Note: operator new zeros our memory
     720               0 : nsDocShell::nsDocShell():
     721                 :     nsDocLoader(),
     722                 :     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
     723                 :     mTreeOwner(nsnull),
     724                 :     mChromeEventHandler(nsnull),
     725                 :     mCharsetReloadState(eCharsetReloadInit),
     726                 :     mChildOffset(0),
     727                 :     mBusyFlags(BUSY_FLAGS_NONE),
     728                 :     mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
     729                 :     mLoadType(0),
     730                 :     mMarginWidth(-1),
     731                 :     mMarginHeight(-1),
     732                 :     mItemType(typeContent),
     733                 :     mPreviousTransIndex(-1),
     734                 :     mLoadedTransIndex(-1),
     735                 :     mCreated(false),
     736                 :     mAllowSubframes(true),
     737                 :     mAllowPlugins(true),
     738                 :     mAllowJavascript(true),
     739                 :     mAllowMetaRedirects(true),
     740                 :     mAllowImages(true),
     741                 :     mAllowDNSPrefetch(true),
     742                 :     mAllowWindowControl(true),
     743                 :     mCreatingDocument(false),
     744                 :     mUseErrorPages(false),
     745                 :     mObserveErrorPages(true),
     746                 :     mAllowAuth(true),
     747                 :     mAllowKeywordFixup(false),
     748                 :     mIsOffScreenBrowser(false),
     749                 :     mIsActive(true),
     750                 :     mIsAppTab(false),
     751                 :     mUseGlobalHistory(false),
     752                 :     mInPrivateBrowsing(false),
     753                 :     mFiredUnloadEvent(false),
     754                 :     mEODForCurrentDocument(false),
     755                 :     mURIResultedInDocument(false),
     756                 :     mIsBeingDestroyed(false),
     757                 :     mIsExecutingOnLoadHandler(false),
     758                 :     mIsPrintingOrPP(false),
     759                 :     mSavingOldViewer(false),
     760                 : #ifdef DEBUG
     761                 :     mInEnsureScriptEnv(false),
     762                 : #endif
     763               0 :     mParentCharsetSource(0)
     764                 : {
     765               0 :     mHistoryID = ++gDocshellIDCounter;
     766               0 :     if (gDocShellCount++ == 0) {
     767               0 :         NS_ASSERTION(sURIFixup == nsnull,
     768                 :                      "Huh, sURIFixup not null in first nsDocShell ctor!");
     769                 : 
     770               0 :         CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
     771                 :     }
     772                 : 
     773                 : #ifdef PR_LOGGING
     774                 : #ifdef DEBUG
     775               0 :     if (! gDocShellLog)
     776               0 :         gDocShellLog = PR_NewLogModule("nsDocShell");
     777                 : #endif
     778               0 :     if (nsnull == gDocShellLeakLog)
     779               0 :         gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
     780               0 :     if (gDocShellLeakLog)
     781               0 :         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this));
     782                 : #endif
     783                 : 
     784                 : #ifdef DEBUG
     785                 :   // We're counting the number of |nsDocShells| to help find leaks
     786               0 :   ++gNumberOfDocShells;
     787               0 :   if (!PR_GetEnv("MOZ_QUIET")) {
     788                 :       printf("++DOCSHELL %p == %ld [id = %ld]\n", (void*) this,
     789               0 :              gNumberOfDocShells, mHistoryID);
     790                 :   }
     791                 : #endif
     792               0 : }
     793                 : 
     794               0 : nsDocShell::~nsDocShell()
     795                 : {
     796               0 :     Destroy();
     797                 : 
     798                 :     nsCOMPtr<nsISHistoryInternal>
     799               0 :         shPrivate(do_QueryInterface(mSessionHistory));
     800               0 :     if (shPrivate) {
     801               0 :         shPrivate->SetRootDocShell(nsnull);
     802                 :     }
     803                 : 
     804               0 :     if (--gDocShellCount == 0) {
     805               0 :         NS_IF_RELEASE(sURIFixup);
     806                 :     }
     807                 : 
     808                 : #ifdef PR_LOGGING
     809               0 :     if (gDocShellLeakLog)
     810               0 :         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this));
     811                 : #endif
     812                 : 
     813                 : #ifdef DEBUG
     814                 :     // We're counting the number of |nsDocShells| to help find leaks
     815               0 :     --gNumberOfDocShells;
     816               0 :     if (!PR_GetEnv("MOZ_QUIET")) {
     817                 :         printf("--DOCSHELL %p == %ld [id = %ld]\n", (void*) this,
     818               0 :                gNumberOfDocShells, mHistoryID);
     819                 :     }
     820                 : #endif
     821               0 : }
     822                 : 
     823                 : nsresult
     824               0 : nsDocShell::Init()
     825                 : {
     826               0 :     nsresult rv = nsDocLoader::Init();
     827               0 :     NS_ENSURE_SUCCESS(rv, rv);
     828                 : 
     829               0 :     NS_ASSERTION(mLoadGroup, "Something went wrong!");
     830                 : 
     831               0 :     mContentListener = new nsDSURIContentListener(this);
     832               0 :     NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
     833                 : 
     834               0 :     rv = mContentListener->Init();
     835               0 :     NS_ENSURE_SUCCESS(rv, rv);
     836                 : 
     837               0 :     if (!mStorages.Init())
     838               0 :         return NS_ERROR_OUT_OF_MEMORY;
     839                 : 
     840                 :     // We want to hold a strong ref to the loadgroup, so it better hold a weak
     841                 :     // ref to us...  use an InterfaceRequestorProxy to do this.
     842                 :     nsCOMPtr<InterfaceRequestorProxy> proxy =
     843                 :         new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>
     844               0 :                                                (this));
     845               0 :     NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
     846               0 :     mLoadGroup->SetNotificationCallbacks(proxy);
     847                 : 
     848               0 :     rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
     849               0 :     NS_ENSURE_SUCCESS(rv, rv);
     850                 :     
     851                 :     // Add as |this| a progress listener to itself.  A little weird, but
     852                 :     // simpler than reproducing all the listener-notification logic in
     853                 :     // overrides of the various methods via which nsDocLoader can be
     854                 :     // notified.   Note that this holds an nsWeakPtr to ourselves, so it's ok.
     855                 :     return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
     856               0 :                                      nsIWebProgress::NOTIFY_STATE_NETWORK);
     857                 :     
     858                 : }
     859                 : 
     860                 : void
     861               0 : nsDocShell::DestroyChildren()
     862                 : {
     863               0 :     nsCOMPtr<nsIDocShellTreeItem> shell;
     864               0 :     PRInt32 n = mChildList.Count();
     865               0 :     for (PRInt32 i = 0; i < n; i++) {
     866               0 :         shell = do_QueryInterface(ChildAt(i));
     867               0 :         NS_ASSERTION(shell, "docshell has null child");
     868                 : 
     869               0 :         if (shell) {
     870               0 :             shell->SetTreeOwner(nsnull);
     871                 :         }
     872                 :     }
     873                 : 
     874               0 :     nsDocLoader::DestroyChildren();
     875               0 : }
     876                 : 
     877                 : //*****************************************************************************
     878                 : // nsDocShell::nsISupports
     879                 : //*****************************************************************************   
     880                 : 
     881               0 : NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
     882               0 : NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
     883                 : 
     884               0 : NS_INTERFACE_MAP_BEGIN(nsDocShell)
     885               0 :     NS_INTERFACE_MAP_ENTRY(nsIDocShell)
     886               0 :     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
     887               0 :     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
     888               0 :     NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory)
     889               0 :     NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
     890               0 :     NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
     891               0 :     NS_INTERFACE_MAP_ENTRY(nsIScrollable)
     892               0 :     NS_INTERFACE_MAP_ENTRY(nsITextScroll)
     893               0 :     NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
     894               0 :     NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
     895               0 :     NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
     896               0 :     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
     897               0 :     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     898               0 :     NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
     899               0 :     NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell)
     900               0 :     NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
     901               0 :     NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
     902               0 :     NS_INTERFACE_MAP_ENTRY(nsIObserver)
     903               0 :     NS_INTERFACE_MAP_ENTRY(nsILoadContext)
     904               0 :     NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
     905               0 :     NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
     906               0 :     NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
     907               0 : NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
     908                 : 
     909                 : ///*****************************************************************************
     910                 : // nsDocShell::nsIInterfaceRequestor
     911                 : //*****************************************************************************   
     912               0 : NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
     913                 : {
     914               0 :     NS_PRECONDITION(aSink, "null out param");
     915                 : 
     916               0 :     *aSink = nsnull;
     917                 : 
     918               0 :     if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
     919               0 :         NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
     920               0 :         *aSink = mCommandManager;
     921                 :     }
     922               0 :     else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
     923               0 :         *aSink = mContentListener;
     924                 :     }
     925               0 :     else if (aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) &&
     926               0 :              NS_SUCCEEDED(EnsureScriptEnvironment())) {
     927               0 :         *aSink = mScriptGlobal;
     928                 :     }
     929               0 :     else if ((aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||
     930               0 :               aIID.Equals(NS_GET_IID(nsIDOMWindow)) ||
     931               0 :               aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) &&
     932               0 :              NS_SUCCEEDED(EnsureScriptEnvironment())) {
     933               0 :         return mScriptGlobal->QueryInterface(aIID, aSink);
     934                 :     }
     935               0 :     else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
     936               0 :              NS_SUCCEEDED(EnsureContentViewer())) {
     937               0 :         mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
     938               0 :         return *aSink ? NS_OK : NS_NOINTERFACE;
     939                 :     }
     940               0 :     else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
     941               0 :              NS_SUCCEEDED(EnsureContentViewer())) {
     942               0 :         nsCOMPtr<nsIDOMDocument> domDoc;
     943               0 :         mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
     944               0 :         if (!domDoc)
     945               0 :             return NS_NOINTERFACE;
     946               0 :         return domDoc->QueryInterface(aIID, aSink);
     947                 :     }
     948               0 :     else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
     949               0 :         *aSink = nsnull;
     950                 : 
     951                 :         // Return application cache associated with this docshell, if any
     952                 : 
     953               0 :         nsCOMPtr<nsIContentViewer> contentViewer;
     954               0 :         GetContentViewer(getter_AddRefs(contentViewer));
     955               0 :         if (!contentViewer)
     956               0 :             return NS_ERROR_NO_INTERFACE;
     957                 : 
     958               0 :         nsCOMPtr<nsIDOMDocument> domDoc;
     959               0 :         contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
     960               0 :         NS_ASSERTION(domDoc, "Should have a document.");
     961               0 :         if (!domDoc)
     962               0 :             return NS_ERROR_NO_INTERFACE;
     963                 : 
     964                 : #if defined(PR_LOGGING) && defined(DEBUG)
     965               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
     966                 :                ("nsDocShell[%p]: returning app cache container %p",
     967                 :                 this, domDoc.get()));
     968                 : #endif
     969               0 :         return domDoc->QueryInterface(aIID, aSink);
     970                 :     }
     971               0 :     else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
     972               0 :              NS_SUCCEEDED(EnsureScriptEnvironment())) {
     973                 :         nsresult rv;
     974                 :         nsCOMPtr<nsIWindowWatcher> wwatch =
     975               0 :             do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     976               0 :         NS_ENSURE_SUCCESS(rv, rv);
     977                 : 
     978               0 :         nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(mScriptGlobal));
     979                 : 
     980                 :         // Get the an auth prompter for our window so that the parenting
     981                 :         // of the dialogs works as it should when using tabs.
     982                 : 
     983                 :         nsIPrompt *prompt;
     984               0 :         rv = wwatch->GetNewPrompter(window, &prompt);
     985               0 :         NS_ENSURE_SUCCESS(rv, rv);
     986                 : 
     987               0 :         *aSink = prompt;
     988               0 :         return NS_OK;
     989                 :     }
     990               0 :     else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
     991               0 :              aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
     992               0 :         return NS_SUCCEEDED(
     993                 :                 GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
     994               0 :                 NS_OK : NS_NOINTERFACE;
     995                 :     }
     996               0 :     else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
     997               0 :         nsCOMPtr<nsISHistory> shistory;
     998                 :         nsresult
     999                 :             rv =
    1000               0 :             GetSessionHistory(getter_AddRefs(shistory));
    1001               0 :         if (NS_SUCCEEDED(rv) && shistory) {
    1002               0 :             *aSink = shistory;
    1003               0 :             NS_ADDREF((nsISupports *) * aSink);
    1004               0 :             return NS_OK;
    1005                 :         }
    1006               0 :         return NS_NOINTERFACE;
    1007                 :     }
    1008               0 :     else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
    1009               0 :         nsresult rv = EnsureFind();
    1010               0 :         if (NS_FAILED(rv)) return rv;
    1011                 : 
    1012               0 :         *aSink = mFind;
    1013               0 :         NS_ADDREF((nsISupports*)*aSink);
    1014               0 :         return NS_OK;
    1015                 :     }
    1016               0 :     else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) {
    1017               0 :       nsCOMPtr<nsIEditingSession> editingSession;
    1018               0 :       mEditorData->GetEditingSession(getter_AddRefs(editingSession));
    1019               0 :       if (editingSession)
    1020                 :       {
    1021               0 :         *aSink = editingSession;
    1022               0 :         NS_ADDREF((nsISupports *)*aSink);
    1023               0 :         return NS_OK;
    1024                 :       }  
    1025                 : 
    1026               0 :       return NS_NOINTERFACE;   
    1027                 :     }
    1028               0 :     else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) 
    1029               0 :             && NS_SUCCEEDED(EnsureTransferableHookData())) {
    1030               0 :         *aSink = mTransferableHookData;
    1031               0 :         NS_ADDREF((nsISupports *)*aSink);
    1032               0 :         return NS_OK;
    1033                 :     }
    1034               0 :     else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
    1035               0 :       nsCOMPtr<nsIPresShell> shell;
    1036               0 :       nsresult rv = GetPresShell(getter_AddRefs(shell));
    1037               0 :       if (NS_SUCCEEDED(rv) && shell)
    1038               0 :         return shell->QueryInterface(aIID,aSink);    
    1039                 :     }
    1040               0 :     else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
    1041               0 :       nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
    1042               0 :       nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
    1043               0 :       if (NS_SUCCEEDED(rv) && treeOwner)
    1044               0 :         return treeOwner->QueryInterface(aIID, aSink);
    1045                 :     }
    1046               0 :     else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
    1047               0 :       nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
    1048               0 :       nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
    1049               0 :       if (NS_SUCCEEDED(rv) && treeOwner) {
    1050               0 :         nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(treeOwner);
    1051               0 :         if (ir)
    1052               0 :           return ir->GetInterface(aIID, aSink);
    1053                 :       }
    1054                 :     }
    1055                 :     else {
    1056               0 :       return nsDocLoader::GetInterface(aIID, aSink);
    1057                 :     }
    1058                 : 
    1059               0 :     NS_IF_ADDREF(((nsISupports *) * aSink));
    1060               0 :     return *aSink ? NS_OK : NS_NOINTERFACE;
    1061                 : }
    1062                 : 
    1063                 : PRUint32
    1064               0 : nsDocShell::
    1065                 : ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType)
    1066                 : {
    1067               0 :     PRUint32 loadType = LOAD_NORMAL;
    1068                 : 
    1069               0 :     switch (aDocShellLoadType) {
    1070                 :     case nsIDocShellLoadInfo::loadNormal:
    1071               0 :         loadType = LOAD_NORMAL;
    1072               0 :         break;
    1073                 :     case nsIDocShellLoadInfo::loadNormalReplace:
    1074               0 :         loadType = LOAD_NORMAL_REPLACE;
    1075               0 :         break;
    1076                 :     case nsIDocShellLoadInfo::loadNormalExternal:
    1077               0 :         loadType = LOAD_NORMAL_EXTERNAL;
    1078               0 :         break;
    1079                 :     case nsIDocShellLoadInfo::loadHistory:
    1080               0 :         loadType = LOAD_HISTORY;
    1081               0 :         break;
    1082                 :     case nsIDocShellLoadInfo::loadNormalBypassCache:
    1083               0 :         loadType = LOAD_NORMAL_BYPASS_CACHE;
    1084               0 :         break;
    1085                 :     case nsIDocShellLoadInfo::loadNormalBypassProxy:
    1086               0 :         loadType = LOAD_NORMAL_BYPASS_PROXY;
    1087               0 :         break;
    1088                 :     case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
    1089               0 :         loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
    1090               0 :         break;
    1091                 :     case nsIDocShellLoadInfo::loadReloadNormal:
    1092               0 :         loadType = LOAD_RELOAD_NORMAL;
    1093               0 :         break;
    1094                 :     case nsIDocShellLoadInfo::loadReloadCharsetChange:
    1095               0 :         loadType = LOAD_RELOAD_CHARSET_CHANGE;
    1096               0 :         break;
    1097                 :     case nsIDocShellLoadInfo::loadReloadBypassCache:
    1098               0 :         loadType = LOAD_RELOAD_BYPASS_CACHE;
    1099               0 :         break;
    1100                 :     case nsIDocShellLoadInfo::loadReloadBypassProxy:
    1101               0 :         loadType = LOAD_RELOAD_BYPASS_PROXY;
    1102               0 :         break;
    1103                 :     case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
    1104               0 :         loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
    1105               0 :         break;
    1106                 :     case nsIDocShellLoadInfo::loadLink:
    1107               0 :         loadType = LOAD_LINK;
    1108               0 :         break;
    1109                 :     case nsIDocShellLoadInfo::loadRefresh:
    1110               0 :         loadType = LOAD_REFRESH;
    1111               0 :         break;
    1112                 :     case nsIDocShellLoadInfo::loadBypassHistory:
    1113               0 :         loadType = LOAD_BYPASS_HISTORY;
    1114               0 :         break;
    1115                 :     case nsIDocShellLoadInfo::loadStopContent:
    1116               0 :         loadType = LOAD_STOP_CONTENT;
    1117               0 :         break;
    1118                 :     case nsIDocShellLoadInfo::loadStopContentAndReplace:
    1119               0 :         loadType = LOAD_STOP_CONTENT_AND_REPLACE;
    1120               0 :         break;
    1121                 :     case nsIDocShellLoadInfo::loadPushState:
    1122               0 :         loadType = LOAD_PUSHSTATE;
    1123               0 :         break;
    1124                 :     default:
    1125               0 :         NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
    1126                 :     }
    1127                 : 
    1128               0 :     return loadType;
    1129                 : }
    1130                 : 
    1131                 : 
    1132                 : nsDocShellInfoLoadType
    1133               0 : nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType)
    1134                 : {
    1135               0 :     nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
    1136               0 :     switch (aLoadType) {
    1137                 :     case LOAD_NORMAL:
    1138               0 :         docShellLoadType = nsIDocShellLoadInfo::loadNormal;
    1139               0 :         break;
    1140                 :     case LOAD_NORMAL_REPLACE:
    1141               0 :         docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
    1142               0 :         break;
    1143                 :     case LOAD_NORMAL_EXTERNAL:
    1144               0 :         docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
    1145               0 :         break;
    1146                 :     case LOAD_NORMAL_BYPASS_CACHE:
    1147               0 :         docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
    1148               0 :         break;
    1149                 :     case LOAD_NORMAL_BYPASS_PROXY:
    1150               0 :         docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
    1151               0 :         break;
    1152                 :     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
    1153               0 :         docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
    1154               0 :         break;
    1155                 :     case LOAD_HISTORY:
    1156               0 :         docShellLoadType = nsIDocShellLoadInfo::loadHistory;
    1157               0 :         break;
    1158                 :     case LOAD_RELOAD_NORMAL:
    1159               0 :         docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
    1160               0 :         break;
    1161                 :     case LOAD_RELOAD_CHARSET_CHANGE:
    1162               0 :         docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
    1163               0 :         break;
    1164                 :     case LOAD_RELOAD_BYPASS_CACHE:
    1165               0 :         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
    1166               0 :         break;
    1167                 :     case LOAD_RELOAD_BYPASS_PROXY:
    1168               0 :         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
    1169               0 :         break;
    1170                 :     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
    1171               0 :         docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
    1172               0 :         break;
    1173                 :     case LOAD_LINK:
    1174               0 :         docShellLoadType = nsIDocShellLoadInfo::loadLink;
    1175               0 :         break;
    1176                 :     case LOAD_REFRESH:
    1177               0 :         docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
    1178               0 :         break;
    1179                 :     case LOAD_BYPASS_HISTORY:
    1180                 :     case LOAD_ERROR_PAGE:
    1181               0 :         docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
    1182               0 :         break;
    1183                 :     case LOAD_STOP_CONTENT:
    1184               0 :         docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
    1185               0 :         break;
    1186                 :     case LOAD_STOP_CONTENT_AND_REPLACE:
    1187               0 :         docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
    1188               0 :         break;
    1189                 :     case LOAD_PUSHSTATE:
    1190               0 :         docShellLoadType = nsIDocShellLoadInfo::loadPushState;
    1191               0 :         break;
    1192                 :     default:
    1193               0 :         NS_NOTREACHED("Unexpected load type value");
    1194                 :     }
    1195                 : 
    1196               0 :     return docShellLoadType;
    1197                 : }                                                                               
    1198                 : 
    1199                 : //*****************************************************************************
    1200                 : // nsDocShell::nsIDocShell
    1201                 : //*****************************************************************************   
    1202                 : NS_IMETHODIMP
    1203               0 : nsDocShell::LoadURI(nsIURI * aURI,
    1204                 :                     nsIDocShellLoadInfo * aLoadInfo,
    1205                 :                     PRUint32 aLoadFlags,
    1206                 :                     bool aFirstParty)
    1207                 : {
    1208               0 :     NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
    1209                 :                     "Unexpected flags");
    1210               0 :     NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
    1211                 :     
    1212                 :     // Note: we allow loads to get through here even if mFiredUnloadEvent is
    1213                 :     // true; that case will get handled in LoadInternal or LoadHistoryEntry.
    1214               0 :     if (IsPrintingOrPP()) {
    1215               0 :       return NS_OK; // JS may not handle returning of an error code
    1216                 :     }
    1217                 :     nsresult rv;
    1218               0 :     nsCOMPtr<nsIURI> referrer;
    1219               0 :     nsCOMPtr<nsIInputStream> postStream;
    1220               0 :     nsCOMPtr<nsIInputStream> headersStream;
    1221               0 :     nsCOMPtr<nsISupports> owner;
    1222               0 :     bool inheritOwner = false;
    1223               0 :     bool ownerIsExplicit = false;
    1224               0 :     bool sendReferrer = true;
    1225               0 :     nsCOMPtr<nsISHEntry> shEntry;
    1226               0 :     nsXPIDLString target;
    1227               0 :     PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);    
    1228                 : 
    1229               0 :     NS_ENSURE_ARG(aURI);
    1230                 : 
    1231               0 :     if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
    1232               0 :         mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
    1233               0 :         StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
    1234                 :     }
    1235                 : 
    1236                 :     // Extract the info from the DocShellLoadInfo struct...
    1237               0 :     if (aLoadInfo) {
    1238               0 :         aLoadInfo->GetReferrer(getter_AddRefs(referrer));
    1239                 : 
    1240               0 :         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
    1241               0 :         aLoadInfo->GetLoadType(&lt);
    1242                 :         // Get the appropriate loadType from nsIDocShellLoadInfo type
    1243               0 :         loadType = ConvertDocShellLoadInfoToLoadType(lt);
    1244                 : 
    1245               0 :         aLoadInfo->GetOwner(getter_AddRefs(owner));
    1246               0 :         aLoadInfo->GetInheritOwner(&inheritOwner);
    1247               0 :         aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
    1248               0 :         aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
    1249               0 :         aLoadInfo->GetTarget(getter_Copies(target));
    1250               0 :         aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
    1251               0 :         aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
    1252               0 :         aLoadInfo->GetSendReferrer(&sendReferrer);
    1253                 :     }
    1254                 : 
    1255                 : #if defined(PR_LOGGING) && defined(DEBUG)
    1256               0 :     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
    1257               0 :         nsCAutoString uristr;
    1258               0 :         aURI->GetAsciiSpec(uristr);
    1259               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    1260                 :                ("nsDocShell[%p]: loading %s with flags 0x%08x",
    1261                 :                 this, uristr.get(), aLoadFlags));
    1262                 :     }
    1263                 : #endif
    1264                 : 
    1265               0 :     if (!shEntry &&
    1266               0 :         !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
    1267                 :         // First verify if this is a subframe.
    1268               0 :         nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    1269               0 :         GetSameTypeParent(getter_AddRefs(parentAsItem));
    1270               0 :         nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
    1271                 :         PRUint32 parentLoadType;
    1272                 : 
    1273               0 :         if (parentDS && parentDS != static_cast<nsIDocShell *>(this)) {
    1274                 :             /* OK. It is a subframe. Checkout the 
    1275                 :              * parent's loadtype. If the parent was loaded thro' a history
    1276                 :              * mechanism, then get the SH entry for the child from the parent.
    1277                 :              * This is done to restore frameset navigation while going back/forward.
    1278                 :              * If the parent was loaded through any other loadType, set the
    1279                 :              * child's loadType too accordingly, so that session history does not
    1280                 :              * get confused. 
    1281                 :              */
    1282                 :             
    1283                 :             // Get the parent's load type
    1284               0 :             parentDS->GetLoadType(&parentLoadType);            
    1285                 : 
    1286               0 :             nsCOMPtr<nsIDocShellHistory> parent(do_QueryInterface(parentAsItem));
    1287               0 :             if (parent) {
    1288                 :                 // Get the ShEntry for the child from the parent
    1289               0 :                 nsCOMPtr<nsISHEntry> currentSH;
    1290               0 :                 bool oshe = false;
    1291               0 :                 parent->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
    1292               0 :                 bool dynamicallyAddedChild = mDynamicallyCreated;
    1293               0 :                 if (!dynamicallyAddedChild && !oshe && currentSH) {
    1294               0 :                     currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
    1295                 :                 }
    1296               0 :                 if (!dynamicallyAddedChild) {
    1297                 :                     // Only use the old SHEntry, if we're sure enough that
    1298                 :                     // it wasn't originally for some other frame.
    1299               0 :                     parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
    1300                 :                 }
    1301                 : 
    1302                 :                 // Make some decisions on the child frame's loadType based on the 
    1303                 :                 // parent's loadType. 
    1304               0 :                 if (mCurrentURI == nsnull) {
    1305                 :                     // This is a newly created frame. Check for exception cases first. 
    1306                 :                     // By default the subframe will inherit the parent's loadType.
    1307               0 :                     if (shEntry && (parentLoadType == LOAD_NORMAL ||
    1308                 :                                     parentLoadType == LOAD_LINK   ||
    1309               0 :                                     parentLoadType == LOAD_NORMAL_EXTERNAL)) {
    1310                 :                         // The parent was loaded normally. In this case, this *brand new* child really shouldn't
    1311                 :                         // have a SHEntry. If it does, it could be because the parent is replacing an
    1312                 :                         // existing frame with a new frame, in the onLoadHandler. We don't want this
    1313                 :                         // url to get into session history. Clear off shEntry, and set load type to
    1314                 :                         // LOAD_BYPASS_HISTORY. 
    1315               0 :                         bool inOnLoadHandler=false;
    1316               0 :                         parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
    1317               0 :                         if (inOnLoadHandler) {
    1318               0 :                             loadType = LOAD_NORMAL_REPLACE;
    1319               0 :                             shEntry = nsnull;
    1320                 :                         }
    1321                 :                     }   
    1322               0 :                     else if (parentLoadType == LOAD_REFRESH) {
    1323                 :                         // Clear shEntry. For refresh loads, we have to load
    1324                 :                         // what comes thro' the pipe, not what's in history.
    1325               0 :                         shEntry = nsnull;
    1326                 :                     }
    1327               0 :                     else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
    1328                 :                              (parentLoadType == LOAD_ERROR_PAGE) ||
    1329                 :                               (shEntry && 
    1330                 :                                ((parentLoadType & LOAD_CMD_HISTORY) || 
    1331                 :                                 (parentLoadType == LOAD_RELOAD_NORMAL) || 
    1332               0 :                                 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
    1333                 :                         // If the parent url, bypassed history or was loaded from
    1334                 :                         // history, pass on the parent's loadType to the new child 
    1335                 :                         // frame too, so that the child frame will also
    1336                 :                         // avoid getting into history. 
    1337               0 :                         loadType = parentLoadType;
    1338                 :                     }
    1339                 :                 }
    1340                 :                 else {
    1341                 :                     // This is a pre-existing subframe. If the load was not originally initiated
    1342                 :                     // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
    1343                 :                     // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading 
    1344                 :                     // a new page in this child. Check parent's and self's busy flag  and if it is set,
    1345                 :                     // we don't want this onLoadHandler load to get in to session history.
    1346               0 :                     PRUint32 parentBusy = BUSY_FLAGS_NONE;
    1347               0 :                     PRUint32 selfBusy = BUSY_FLAGS_NONE;
    1348               0 :                     parentDS->GetBusyFlags(&parentBusy);                    
    1349               0 :                     GetBusyFlags(&selfBusy);
    1350               0 :                     if (parentBusy & BUSY_FLAGS_BUSY ||
    1351                 :                         selfBusy & BUSY_FLAGS_BUSY) {
    1352               0 :                         loadType = LOAD_NORMAL_REPLACE;
    1353               0 :                         shEntry = nsnull; 
    1354                 :                     }
    1355                 :                 }
    1356                 :             } // parent
    1357                 :         } //parentDS
    1358                 :         else {  
    1359                 :             // This is the root docshell. If we got here while  
    1360                 :             // executing an onLoad Handler,this load will not go 
    1361                 :             // into session history.
    1362               0 :             bool inOnLoadHandler=false;
    1363               0 :             GetIsExecutingOnLoadHandler(&inOnLoadHandler);
    1364               0 :             if (inOnLoadHandler) {
    1365               0 :                 loadType = LOAD_NORMAL_REPLACE;
    1366                 :             }
    1367                 :         } 
    1368                 :     } // !shEntry
    1369                 : 
    1370               0 :     if (shEntry) {
    1371                 : #ifdef DEBUG
    1372               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    1373                 :               ("nsDocShell[%p]: loading from session history", this));
    1374                 : #endif
    1375                 : 
    1376               0 :         return LoadHistoryEntry(shEntry, loadType);
    1377                 :     }
    1378                 : 
    1379                 :     // Perform the load...
    1380                 : 
    1381                 :     // We need an owner (a referring principal).
    1382                 :     //
    1383                 :     // If ownerIsExplicit is not set there are 4 possibilities:
    1384                 :     // (1) If the system principal was passed in and we're a typeContent
    1385                 :     //     docshell, inherit the principal from the current document
    1386                 :     //     instead.
    1387                 :     // (2) In all other cases when the principal passed in is not null,
    1388                 :     //     use that principal.
    1389                 :     // (3) If the caller has allowed inheriting from the current document,
    1390                 :     //     or if we're being called from system code (eg chrome JS or pure
    1391                 :     //     C++) then inheritOwner should be true and InternalLoad will get
    1392                 :     //     an owner from the current document. If none of these things are
    1393                 :     //     true, then
    1394                 :     // (4) we pass a null owner into the channel, and an owner will be
    1395                 :     //     created later from the channel's internal data.
    1396                 :     //
    1397                 :     // If ownerIsExplicit *is* set, there are 4 possibilities
    1398                 :     // (1) If the system principal was passed in and we're a typeContent
    1399                 :     //     docshell, return an error.
    1400                 :     // (2) In all other cases when the principal passed in is not null,
    1401                 :     //     use that principal.
    1402                 :     // (3) If the caller has allowed inheriting from the current document,
    1403                 :     //     then inheritOwner should be true and InternalLoad will get an owner
    1404                 :     //     from the current document. If none of these things are true, then
    1405                 :     // (4) we pass a null owner into the channel, and an owner will be
    1406                 :     //     created later from the channel's internal data.
    1407                 :     //
    1408                 :     // NOTE: This all only works because the only thing the owner is used  
    1409                 :     //       for in InternalLoad is data:, javascript:, and about:blank
    1410                 :     //       URIs.  For other URIs this would all be dead wrong!
    1411                 : 
    1412                 :     nsCOMPtr<nsIScriptSecurityManager> secMan =
    1413               0 :         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    1414               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1415                 : 
    1416               0 :     if (owner && mItemType != typeChrome) {
    1417               0 :         nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
    1418                 :         bool isSystem;
    1419               0 :         rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem);
    1420               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1421                 : 
    1422               0 :         if (isSystem) {
    1423               0 :             if (ownerIsExplicit) {
    1424               0 :                 return NS_ERROR_DOM_SECURITY_ERR;
    1425                 :             }
    1426               0 :             owner = nsnull;
    1427               0 :             inheritOwner = true;
    1428                 :         }
    1429                 :     }
    1430               0 :     if (!owner && !inheritOwner && !ownerIsExplicit) {
    1431                 :         // See if there's system or chrome JS code running
    1432               0 :         rv = secMan->SubjectPrincipalIsSystem(&inheritOwner);
    1433               0 :         if (NS_FAILED(rv)) {
    1434                 :             // Set it back to false
    1435               0 :             inheritOwner = false;
    1436                 :         }
    1437                 :     }
    1438                 : 
    1439               0 :     if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
    1440               0 :         inheritOwner = false;
    1441               0 :         owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
    1442                 :     }
    1443                 : 
    1444               0 :     PRUint32 flags = 0;
    1445                 : 
    1446               0 :     if (inheritOwner)
    1447               0 :         flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
    1448                 : 
    1449               0 :     if (!sendReferrer)
    1450               0 :         flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
    1451                 :             
    1452               0 :     if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
    1453               0 :         flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
    1454                 : 
    1455               0 :     if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
    1456               0 :         flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
    1457                 : 
    1458               0 :     if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
    1459               0 :         flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
    1460                 : 
    1461               0 :     if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES)
    1462               0 :         flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
    1463                 : 
    1464                 :     return InternalLoad(aURI,
    1465                 :                         referrer,
    1466                 :                         owner,
    1467                 :                         flags,
    1468                 :                         target.get(),
    1469                 :                         nsnull,         // No type hint
    1470                 :                         postStream,
    1471                 :                         headersStream,
    1472                 :                         loadType,
    1473                 :                         nsnull,         // No SHEntry
    1474                 :                         aFirstParty,
    1475                 :                         nsnull,         // No nsIDocShell
    1476               0 :                         nsnull);        // No nsIRequest
    1477                 : }
    1478                 : 
    1479                 : NS_IMETHODIMP
    1480               0 : nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
    1481                 :                        const nsACString &aContentType,
    1482                 :                        const nsACString &aContentCharset,
    1483                 :                        nsIDocShellLoadInfo * aLoadInfo)
    1484                 : {
    1485               0 :     NS_ENSURE_ARG(aStream);
    1486                 : 
    1487               0 :     mAllowKeywordFixup = false;
    1488                 : 
    1489                 :     // if the caller doesn't pass in a URI we need to create a dummy URI. necko
    1490                 :     // currently requires a URI in various places during the load. Some consumers
    1491                 :     // do as well.
    1492               0 :     nsCOMPtr<nsIURI> uri = aURI;
    1493               0 :     if (!uri) {
    1494                 :         // HACK ALERT
    1495               0 :         nsresult rv = NS_OK;
    1496               0 :         uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
    1497               0 :         if (NS_FAILED(rv))
    1498               0 :             return rv;
    1499                 :         // Make sure that the URI spec "looks" like a protocol and path...
    1500                 :         // For now, just use a bogus protocol called "internal"
    1501               0 :         rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
    1502               0 :         if (NS_FAILED(rv))
    1503               0 :             return rv;
    1504                 :     }
    1505                 : 
    1506               0 :     PRUint32 loadType = LOAD_NORMAL;
    1507               0 :     if (aLoadInfo) {
    1508               0 :         nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
    1509               0 :         (void) aLoadInfo->GetLoadType(&lt);
    1510                 :         // Get the appropriate LoadType from nsIDocShellLoadInfo type
    1511               0 :         loadType = ConvertDocShellLoadInfoToLoadType(lt);
    1512                 :     }
    1513                 : 
    1514               0 :     NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
    1515                 : 
    1516               0 :     mLoadType = loadType;
    1517                 : 
    1518                 :     // build up a channel for this stream.
    1519               0 :     nsCOMPtr<nsIChannel> channel;
    1520               0 :     NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
    1521                 :                       (getter_AddRefs(channel), uri, aStream,
    1522                 :                        aContentType, aContentCharset),
    1523                 :                       NS_ERROR_FAILURE);
    1524                 : 
    1525                 :     nsCOMPtr<nsIURILoader>
    1526               0 :         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
    1527               0 :     NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
    1528                 : 
    1529               0 :     NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
    1530                 :                       NS_ERROR_FAILURE);
    1531               0 :     return NS_OK;
    1532                 : }
    1533                 : 
    1534                 : NS_IMETHODIMP
    1535               0 : nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo)
    1536                 : {
    1537               0 :     nsDocShellLoadInfo *loadInfo = new nsDocShellLoadInfo();
    1538               0 :     NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
    1539               0 :     nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
    1540                 : 
    1541               0 :     *aLoadInfo = localRef;
    1542               0 :     NS_ADDREF(*aLoadInfo);
    1543               0 :     return NS_OK;
    1544                 : }
    1545                 : 
    1546                 : 
    1547                 : /*
    1548                 :  * Reset state to a new content model within the current document and the document
    1549                 :  * viewer.  Called by the document before initiating an out of band document.write().
    1550                 :  */
    1551                 : NS_IMETHODIMP
    1552               0 : nsDocShell::PrepareForNewContentModel()
    1553                 : {
    1554               0 :   mEODForCurrentDocument = false;
    1555               0 :   return NS_OK;
    1556                 : }
    1557                 : 
    1558                 : 
    1559                 : NS_IMETHODIMP
    1560               0 : nsDocShell::FirePageHideNotification(bool aIsUnload)
    1561                 : {
    1562               0 :     if (mContentViewer && !mFiredUnloadEvent) {
    1563                 :         // Keep an explicit reference since calling PageHide could release
    1564                 :         // mContentViewer
    1565               0 :         nsCOMPtr<nsIContentViewer> kungFuDeathGrip(mContentViewer);
    1566               0 :         mFiredUnloadEvent = true;
    1567                 : 
    1568               0 :         if (mTiming) {
    1569               0 :             mTiming->NotifyUnloadEventStart();
    1570                 :         }
    1571                 : 
    1572               0 :         mContentViewer->PageHide(aIsUnload);
    1573                 : 
    1574               0 :         if (mTiming) {
    1575               0 :             mTiming->NotifyUnloadEventEnd();
    1576                 :         }
    1577                 : 
    1578               0 :         nsAutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
    1579               0 :         PRInt32 i, n = mChildList.Count();
    1580               0 :         kids.SetCapacity(n);
    1581               0 :         for (i = 0; i < n; i++) {
    1582               0 :             kids.AppendElement(do_QueryInterface(ChildAt(i)));
    1583                 :         }
    1584                 : 
    1585               0 :         n = kids.Length();
    1586               0 :         for (i = 0; i < n; ++i) {
    1587               0 :             if (kids[i]) {
    1588               0 :                 kids[i]->FirePageHideNotification(aIsUnload);
    1589                 :             }
    1590                 :         }
    1591                 :         // Now make sure our editor, if any, is detached before we go
    1592                 :         // any farther.
    1593               0 :         DetachEditorFromWindow();
    1594                 :     }
    1595                 : 
    1596               0 :     return NS_OK;
    1597                 : }
    1598                 : 
    1599                 : nsresult
    1600               0 : nsDocShell::MaybeInitTiming()
    1601                 : {
    1602               0 :     if (mTiming) {
    1603               0 :         return NS_OK;
    1604                 :     }
    1605                 : 
    1606               0 :     if (Preferences::GetBool("dom.enable_performance", false)) {
    1607               0 :         mTiming = new nsDOMNavigationTiming();
    1608               0 :         mTiming->NotifyNavigationStart();
    1609                 :     }
    1610               0 :     return NS_OK;
    1611                 : }
    1612                 : 
    1613                 : 
    1614                 : //
    1615                 : // Bug 13871: Prevent frameset spoofing
    1616                 : //
    1617                 : // This routine answers: 'Is origin's document from same domain as
    1618                 : // target's document?'
    1619                 : //
    1620                 : // file: uris are considered the same domain for the purpose of
    1621                 : // frame navigation regardless of script accessibility (bug 420425)
    1622                 : //
    1623                 : /* static */
    1624                 : bool
    1625               0 : nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
    1626                 :                            nsIDocShellTreeItem* aTargetTreeItem)
    1627                 : {
    1628                 :     nsCOMPtr<nsIScriptSecurityManager> securityManager =
    1629               0 :         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
    1630               0 :     NS_ENSURE_TRUE(securityManager, false);
    1631                 : 
    1632               0 :     nsCOMPtr<nsIPrincipal> subjectPrincipal;
    1633                 :     nsresult rv =
    1634               0 :         securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
    1635               0 :     NS_ENSURE_SUCCESS(rv, false);
    1636                 : 
    1637               0 :     if (subjectPrincipal) {
    1638                 :         // We're called from JS, check if UniversalXPConnect is
    1639                 :         // enabled.
    1640               0 :         bool ubwEnabled = false;
    1641               0 :         rv = securityManager->IsCapabilityEnabled("UniversalXPConnect",
    1642               0 :                                                   &ubwEnabled);
    1643               0 :         NS_ENSURE_SUCCESS(rv, false);
    1644                 : 
    1645               0 :         if (ubwEnabled) {
    1646               0 :             return true;
    1647                 :         }
    1648                 :     }
    1649                 : 
    1650                 :     // Get origin document principal
    1651               0 :     nsCOMPtr<nsIDocument> originDocument(do_GetInterface(aOriginTreeItem));
    1652               0 :     NS_ENSURE_TRUE(originDocument, false);
    1653                 : 
    1654                 :     // Get target principal
    1655               0 :     nsCOMPtr<nsIDocument> targetDocument(do_GetInterface(aTargetTreeItem));
    1656               0 :     NS_ENSURE_TRUE(targetDocument, false);
    1657                 : 
    1658                 :     bool equal;
    1659               0 :     rv = originDocument->NodePrincipal()->
    1660               0 :             Equals(targetDocument->NodePrincipal(), &equal);
    1661               0 :     if (NS_SUCCEEDED(rv) && equal) {
    1662               0 :         return true;
    1663                 :     }
    1664                 : 
    1665                 :     // Not strictly equal, special case if both are file: uris
    1666               0 :     bool originIsFile = false;
    1667               0 :     bool targetIsFile = false;
    1668               0 :     nsCOMPtr<nsIURI> originURI;
    1669               0 :     nsCOMPtr<nsIURI> targetURI;
    1670               0 :     nsCOMPtr<nsIURI> innerOriginURI;
    1671               0 :     nsCOMPtr<nsIURI> innerTargetURI;
    1672                 : 
    1673               0 :     rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
    1674               0 :     if (NS_SUCCEEDED(rv) && originURI)
    1675               0 :         innerOriginURI = NS_GetInnermostURI(originURI);
    1676                 : 
    1677               0 :     rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
    1678               0 :     if (NS_SUCCEEDED(rv) && targetURI)
    1679               0 :         innerTargetURI = NS_GetInnermostURI(targetURI);
    1680                 : 
    1681               0 :     return innerOriginURI && innerTargetURI &&
    1682               0 :         NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
    1683               0 :         NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
    1684               0 :         originIsFile && targetIsFile;
    1685                 : }
    1686                 : 
    1687                 : NS_IMETHODIMP
    1688               0 : nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
    1689                 : {
    1690               0 :     NS_ENSURE_ARG_POINTER(aPresContext);
    1691               0 :     *aPresContext = nsnull;
    1692                 : 
    1693               0 :     nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
    1694               0 :     while (viewer) {
    1695               0 :         nsCOMPtr<nsIContentViewer> prevViewer;
    1696               0 :         viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
    1697               0 :         if (!prevViewer) {
    1698               0 :             return viewer->GetPresContext(aPresContext);
    1699                 :         }
    1700               0 :         viewer = prevViewer;
    1701                 :     }
    1702                 : 
    1703               0 :     return NS_OK;
    1704                 : }
    1705                 : 
    1706                 : NS_IMETHODIMP
    1707               0 : nsDocShell::GetPresContext(nsPresContext ** aPresContext)
    1708                 : {
    1709               0 :     NS_ENSURE_ARG_POINTER(aPresContext);
    1710               0 :     *aPresContext = nsnull;
    1711                 : 
    1712               0 :     if (!mContentViewer)
    1713               0 :       return NS_OK;
    1714                 : 
    1715               0 :     return mContentViewer->GetPresContext(aPresContext);
    1716                 : }
    1717                 : 
    1718                 : NS_IMETHODIMP
    1719               0 : nsDocShell::GetPresShell(nsIPresShell ** aPresShell)
    1720                 : {
    1721               0 :     nsresult rv = NS_OK;
    1722                 : 
    1723               0 :     NS_ENSURE_ARG_POINTER(aPresShell);
    1724               0 :     *aPresShell = nsnull;
    1725                 : 
    1726               0 :     nsRefPtr<nsPresContext> presContext;
    1727               0 :     (void) GetPresContext(getter_AddRefs(presContext));
    1728                 : 
    1729               0 :     if (presContext) {
    1730               0 :         NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
    1731                 :     }
    1732                 : 
    1733               0 :     return rv;
    1734                 : }
    1735                 : 
    1736                 : NS_IMETHODIMP
    1737               0 : nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
    1738                 : {
    1739               0 :     nsresult rv = NS_OK;
    1740                 : 
    1741               0 :     NS_ENSURE_ARG_POINTER(aPresShell);
    1742               0 :     *aPresShell = nsnull;
    1743                 : 
    1744               0 :     nsRefPtr<nsPresContext> presContext;
    1745               0 :     (void) GetEldestPresContext(getter_AddRefs(presContext));
    1746                 : 
    1747               0 :     if (presContext) {
    1748               0 :         NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
    1749                 :     }
    1750                 : 
    1751               0 :     return rv;
    1752                 : }
    1753                 : 
    1754                 : NS_IMETHODIMP
    1755               0 : nsDocShell::GetContentViewer(nsIContentViewer ** aContentViewer)
    1756                 : {
    1757               0 :     NS_ENSURE_ARG_POINTER(aContentViewer);
    1758                 : 
    1759               0 :     *aContentViewer = mContentViewer;
    1760               0 :     NS_IF_ADDREF(*aContentViewer);
    1761               0 :     return NS_OK;
    1762                 : }
    1763                 : 
    1764                 : NS_IMETHODIMP
    1765               0 : nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
    1766                 : {
    1767                 :     // Weak reference. Don't addref.
    1768               0 :     mChromeEventHandler = aChromeEventHandler;
    1769                 : 
    1770               0 :     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
    1771               0 :     if (win) {
    1772               0 :         win->SetChromeEventHandler(aChromeEventHandler);
    1773                 :     }
    1774                 : 
    1775               0 :     return NS_OK;
    1776                 : }
    1777                 : 
    1778                 : NS_IMETHODIMP
    1779               0 : nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
    1780                 : {
    1781               0 :     NS_ENSURE_ARG_POINTER(aChromeEventHandler);
    1782               0 :     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mChromeEventHandler);
    1783               0 :     target.swap(*aChromeEventHandler);
    1784               0 :     return NS_OK;
    1785                 : }
    1786                 : 
    1787                 : /* void setCurrentURI (in nsIURI uri); */
    1788                 : NS_IMETHODIMP
    1789               0 : nsDocShell::SetCurrentURI(nsIURI *aURI)
    1790                 : {
    1791                 :     // Note that securityUI will set STATE_IS_INSECURE, even if
    1792                 :     // the scheme of |aURI| is "https".
    1793               0 :     SetCurrentURI(aURI, nsnull, true, 0);
    1794               0 :     return NS_OK;
    1795                 : }
    1796                 : 
    1797                 : bool
    1798               0 : nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
    1799                 :                           bool aFireOnLocationChange, PRUint32 aLocationFlags)
    1800                 : {
    1801                 : #ifdef PR_LOGGING
    1802               0 :     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
    1803               0 :         nsCAutoString spec;
    1804               0 :         if (aURI)
    1805               0 :             aURI->GetSpec(spec);
    1806               0 :         PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
    1807                 :     }
    1808                 : #endif
    1809                 : 
    1810                 :     // We don't want to send a location change when we're displaying an error
    1811                 :     // page, and we don't want to change our idea of "current URI" either
    1812               0 :     if (mLoadType == LOAD_ERROR_PAGE) {
    1813               0 :         return false;
    1814                 :     }
    1815                 : 
    1816               0 :     mCurrentURI = NS_TryToMakeImmutable(aURI);
    1817                 :     
    1818               0 :     bool isRoot = false;   // Is this the root docshell
    1819               0 :     bool isSubFrame = false;  // Is this a subframe navigation?
    1820                 : 
    1821               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
    1822                 : 
    1823               0 :     GetSameTypeRootTreeItem(getter_AddRefs(root));
    1824               0 :     if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) 
    1825                 :     {
    1826                 :         // This is the root docshell
    1827               0 :         isRoot = true;
    1828                 :     }
    1829               0 :     if (mLSHE) {
    1830               0 :         mLSHE->GetIsSubFrame(&isSubFrame);
    1831                 :     }
    1832                 : 
    1833               0 :     if (!isSubFrame && !isRoot) {
    1834                 :       /* 
    1835                 :        * We don't want to send OnLocationChange notifications when
    1836                 :        * a subframe is being loaded for the first time, while
    1837                 :        * visiting a frameset page
    1838                 :        */
    1839               0 :       return false; 
    1840                 :     }
    1841                 : 
    1842               0 :     if (aFireOnLocationChange) {
    1843               0 :         FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
    1844                 :     }
    1845               0 :     return !aFireOnLocationChange;
    1846                 : }
    1847                 : 
    1848                 : NS_IMETHODIMP
    1849               0 : nsDocShell::GetCharset(char** aCharset)
    1850                 : {
    1851               0 :     NS_ENSURE_ARG_POINTER(aCharset);
    1852               0 :     *aCharset = nsnull; 
    1853                 : 
    1854               0 :     nsCOMPtr<nsIPresShell> presShell;
    1855               0 :     GetPresShell(getter_AddRefs(presShell));
    1856               0 :     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
    1857               0 :     nsIDocument *doc = presShell->GetDocument();
    1858               0 :     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    1859               0 :     *aCharset = ToNewCString(doc->GetDocumentCharacterSet());
    1860               0 :     if (!*aCharset) {
    1861               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1862                 :     }
    1863                 : 
    1864               0 :     return NS_OK;
    1865                 : }
    1866                 : 
    1867                 : NS_IMETHODIMP
    1868               0 : nsDocShell::SetCharset(const char* aCharset)
    1869                 : {
    1870                 :     // set the default charset
    1871               0 :     nsCOMPtr<nsIContentViewer> viewer;
    1872               0 :     GetContentViewer(getter_AddRefs(viewer));
    1873               0 :     if (viewer) {
    1874               0 :       nsCOMPtr<nsIMarkupDocumentViewer> muDV(do_QueryInterface(viewer));
    1875               0 :       if (muDV) {
    1876               0 :         nsCString charset(aCharset);
    1877               0 :         NS_ENSURE_SUCCESS(muDV->SetDefaultCharacterSet(charset),
    1878                 :                           NS_ERROR_FAILURE);
    1879                 :       }
    1880                 :     }
    1881                 : 
    1882                 :     // set the charset override
    1883               0 :     nsCOMPtr<nsIAtom> csAtom = do_GetAtom(aCharset);
    1884               0 :     SetForcedCharset(csAtom);
    1885                 : 
    1886               0 :     return NS_OK;
    1887                 : } 
    1888                 : 
    1889               0 : NS_IMETHODIMP nsDocShell::SetForcedCharset(nsIAtom * aCharset)
    1890                 : {
    1891               0 :   mForcedCharset = aCharset;
    1892               0 :   return NS_OK;
    1893                 : }
    1894                 : 
    1895               0 : NS_IMETHODIMP nsDocShell::GetForcedCharset(nsIAtom ** aResult)
    1896                 : {
    1897               0 :   *aResult = mForcedCharset;
    1898               0 :   if (mForcedCharset) NS_ADDREF(*aResult);
    1899               0 :   return NS_OK;
    1900                 : }
    1901                 : 
    1902               0 : NS_IMETHODIMP nsDocShell::SetParentCharset(nsIAtom * aCharset)
    1903                 : {
    1904               0 :   mParentCharset = aCharset;
    1905               0 :   return NS_OK;
    1906                 : }
    1907                 : 
    1908               0 : NS_IMETHODIMP nsDocShell::GetParentCharset(nsIAtom ** aResult)
    1909                 : {
    1910               0 :   *aResult = mParentCharset;
    1911               0 :   if (mParentCharset) NS_ADDREF(*aResult);
    1912               0 :   return NS_OK;
    1913                 : }
    1914                 : 
    1915               0 : NS_IMETHODIMP nsDocShell::SetParentCharsetSource(PRInt32 aCharsetSource)
    1916                 : {
    1917               0 :   mParentCharsetSource = aCharsetSource;
    1918               0 :   return NS_OK;
    1919                 : }
    1920                 : 
    1921               0 : NS_IMETHODIMP nsDocShell::GetParentCharsetSource(PRInt32 * aParentCharsetSource)
    1922                 : {
    1923               0 :   *aParentCharsetSource = mParentCharsetSource;
    1924               0 :   return NS_OK;
    1925                 : }
    1926                 : 
    1927                 : NS_IMETHODIMP
    1928               0 : nsDocShell::GetChannelIsUnsafe(bool *aUnsafe)
    1929                 : {
    1930               0 :     *aUnsafe = false;
    1931                 : 
    1932               0 :     nsIChannel* channel = GetCurrentDocChannel();
    1933               0 :     if (!channel) {
    1934               0 :         return NS_OK;
    1935                 :     }
    1936                 : 
    1937               0 :     nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
    1938               0 :     if (!jarChannel) {
    1939               0 :         return NS_OK;
    1940                 :     }
    1941                 : 
    1942               0 :     return jarChannel->GetIsUnsafe(aUnsafe);
    1943                 : }
    1944                 : 
    1945                 : NS_IMETHODIMP
    1946               0 : nsDocShell::GetAllowPlugins(bool * aAllowPlugins)
    1947                 : {
    1948               0 :     NS_ENSURE_ARG_POINTER(aAllowPlugins);
    1949                 : 
    1950               0 :     *aAllowPlugins = mAllowPlugins;
    1951               0 :     if (!mAllowPlugins) {
    1952               0 :         return NS_OK;
    1953                 :     }
    1954                 : 
    1955                 :     bool unsafe;
    1956               0 :     *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
    1957               0 :     return NS_OK;
    1958                 : }
    1959                 : 
    1960                 : NS_IMETHODIMP
    1961               0 : nsDocShell::SetAllowPlugins(bool aAllowPlugins)
    1962                 : {
    1963               0 :     mAllowPlugins = aAllowPlugins;
    1964                 :     //XXX should enable or disable a plugin host
    1965               0 :     return NS_OK;
    1966                 : }
    1967                 : 
    1968                 : NS_IMETHODIMP
    1969               0 : nsDocShell::GetAllowJavascript(bool * aAllowJavascript)
    1970                 : {
    1971               0 :     NS_ENSURE_ARG_POINTER(aAllowJavascript);
    1972                 : 
    1973               0 :     *aAllowJavascript = mAllowJavascript;
    1974               0 :     if (!mAllowJavascript) {
    1975               0 :         return NS_OK;
    1976                 :     }
    1977                 : 
    1978                 :     bool unsafe;
    1979               0 :     *aAllowJavascript = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
    1980               0 :     return NS_OK;
    1981                 : }
    1982                 : 
    1983                 : NS_IMETHODIMP
    1984               0 : nsDocShell::SetAllowJavascript(bool aAllowJavascript)
    1985                 : {
    1986               0 :     mAllowJavascript = aAllowJavascript;
    1987               0 :     return NS_OK;
    1988                 : }
    1989                 : 
    1990                 : NS_IMETHODIMP
    1991               0 : nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
    1992                 : {
    1993               0 :     NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
    1994                 :     
    1995               0 :     *aUsePrivateBrowsing = mInPrivateBrowsing;
    1996               0 :     return NS_OK;
    1997                 : }
    1998                 : 
    1999                 : NS_IMETHODIMP
    2000               0 : nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
    2001                 : {
    2002               0 :     mInPrivateBrowsing = aUsePrivateBrowsing;
    2003                 : 
    2004               0 :     PRInt32 count = mChildList.Count();
    2005               0 :     for (PRInt32 i = 0; i < count; ++i) {
    2006               0 :         nsCOMPtr<nsILoadContext> shell = do_QueryInterface(ChildAt(i));
    2007               0 :         if (shell) {
    2008               0 :             shell->SetUsePrivateBrowsing(aUsePrivateBrowsing);
    2009                 :         }
    2010                 :     }
    2011               0 :     return NS_OK;
    2012                 : }
    2013                 : 
    2014               0 : NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(bool * aReturn)
    2015                 : {
    2016               0 :     NS_ENSURE_ARG_POINTER(aReturn);
    2017                 : 
    2018               0 :     *aReturn = mAllowMetaRedirects;
    2019               0 :     if (!mAllowMetaRedirects) {
    2020               0 :         return NS_OK;
    2021                 :     }
    2022                 : 
    2023                 :     bool unsafe;
    2024               0 :     *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
    2025               0 :     return NS_OK;
    2026                 : }
    2027                 : 
    2028               0 : NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(bool aValue)
    2029                 : {
    2030               0 :     mAllowMetaRedirects = aValue;
    2031               0 :     return NS_OK;
    2032                 : }
    2033                 : 
    2034               0 : NS_IMETHODIMP nsDocShell::GetAllowSubframes(bool * aAllowSubframes)
    2035                 : {
    2036               0 :     NS_ENSURE_ARG_POINTER(aAllowSubframes);
    2037                 : 
    2038               0 :     *aAllowSubframes = mAllowSubframes;
    2039               0 :     return NS_OK;
    2040                 : }
    2041                 : 
    2042               0 : NS_IMETHODIMP nsDocShell::SetAllowSubframes(bool aAllowSubframes)
    2043                 : {
    2044               0 :     mAllowSubframes = aAllowSubframes;
    2045               0 :     return NS_OK;
    2046                 : }
    2047                 : 
    2048               0 : NS_IMETHODIMP nsDocShell::GetAllowImages(bool * aAllowImages)
    2049                 : {
    2050               0 :     NS_ENSURE_ARG_POINTER(aAllowImages);
    2051                 : 
    2052               0 :     *aAllowImages = mAllowImages;
    2053               0 :     return NS_OK;
    2054                 : }
    2055                 : 
    2056               0 : NS_IMETHODIMP nsDocShell::SetAllowImages(bool aAllowImages)
    2057                 : {
    2058               0 :     mAllowImages = aAllowImages;
    2059               0 :     return NS_OK;
    2060                 : }
    2061                 : 
    2062               0 : NS_IMETHODIMP nsDocShell::GetAllowDNSPrefetch(bool * aAllowDNSPrefetch)
    2063                 : {
    2064               0 :     *aAllowDNSPrefetch = mAllowDNSPrefetch;
    2065               0 :     return NS_OK;
    2066                 : }
    2067                 : 
    2068               0 : NS_IMETHODIMP nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
    2069                 : {
    2070               0 :     mAllowDNSPrefetch = aAllowDNSPrefetch;
    2071               0 :     return NS_OK;
    2072                 : }
    2073                 : 
    2074               0 : NS_IMETHODIMP nsDocShell::GetAllowWindowControl(bool * aAllowWindowControl)
    2075                 : {
    2076               0 :     *aAllowWindowControl = mAllowWindowControl;
    2077               0 :     return NS_OK;
    2078                 : }
    2079                 : 
    2080               0 : NS_IMETHODIMP nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
    2081                 : {
    2082               0 :     mAllowWindowControl = aAllowWindowControl;
    2083               0 :     return NS_OK;
    2084                 : }
    2085                 : 
    2086                 : NS_IMETHODIMP
    2087               0 : nsDocShell::GetDocShellEnumerator(PRInt32 aItemType, PRInt32 aDirection, nsISimpleEnumerator **outEnum)
    2088                 : {
    2089               0 :     NS_ENSURE_ARG_POINTER(outEnum);
    2090               0 :     *outEnum = nsnull;
    2091                 :     
    2092               0 :     nsRefPtr<nsDocShellEnumerator> docShellEnum;
    2093               0 :     if (aDirection == ENUMERATE_FORWARDS)
    2094               0 :         docShellEnum = new nsDocShellForwardsEnumerator;
    2095                 :     else
    2096               0 :         docShellEnum = new nsDocShellBackwardsEnumerator;
    2097                 :     
    2098               0 :     if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY;
    2099                 :     
    2100               0 :     nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
    2101               0 :     if (NS_FAILED(rv)) return rv;
    2102                 : 
    2103               0 :     rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this);
    2104               0 :     if (NS_FAILED(rv)) return rv;
    2105                 : 
    2106               0 :     rv = docShellEnum->First();
    2107               0 :     if (NS_FAILED(rv)) return rv;
    2108                 : 
    2109               0 :     rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum);
    2110                 : 
    2111               0 :     return rv;
    2112                 : }
    2113                 : 
    2114                 : NS_IMETHODIMP
    2115               0 : nsDocShell::GetAppType(PRUint32 * aAppType)
    2116                 : {
    2117               0 :     *aAppType = mAppType;
    2118               0 :     return NS_OK;
    2119                 : }
    2120                 : 
    2121                 : NS_IMETHODIMP
    2122               0 : nsDocShell::SetAppType(PRUint32 aAppType)
    2123                 : {
    2124               0 :     mAppType = aAppType;
    2125               0 :     return NS_OK;
    2126                 : }
    2127                 : 
    2128                 : 
    2129                 : NS_IMETHODIMP
    2130               0 : nsDocShell::GetAllowAuth(bool * aAllowAuth)
    2131                 : {
    2132               0 :     *aAllowAuth = mAllowAuth;
    2133               0 :     return NS_OK;
    2134                 : }
    2135                 : 
    2136                 : NS_IMETHODIMP
    2137               0 : nsDocShell::SetAllowAuth(bool aAllowAuth)
    2138                 : {
    2139               0 :     mAllowAuth = aAllowAuth;
    2140               0 :     return NS_OK;
    2141                 : }
    2142                 : 
    2143                 : NS_IMETHODIMP
    2144               0 : nsDocShell::GetZoom(float *zoom)
    2145                 : {
    2146               0 :     NS_ENSURE_ARG_POINTER(zoom);
    2147               0 :     *zoom = 1.0f;
    2148               0 :     return NS_OK;
    2149                 : }
    2150                 : 
    2151                 : NS_IMETHODIMP
    2152               0 : nsDocShell::SetZoom(float zoom)
    2153                 : {
    2154               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    2155                 : }
    2156                 : 
    2157                 : NS_IMETHODIMP
    2158               0 : nsDocShell::GetMarginWidth(PRInt32 * aWidth)
    2159                 : {
    2160               0 :     NS_ENSURE_ARG_POINTER(aWidth);
    2161                 : 
    2162               0 :     *aWidth = mMarginWidth;
    2163               0 :     return NS_OK;
    2164                 : }
    2165                 : 
    2166                 : NS_IMETHODIMP
    2167               0 : nsDocShell::SetMarginWidth(PRInt32 aWidth)
    2168                 : {
    2169               0 :     mMarginWidth = aWidth;
    2170               0 :     return NS_OK;
    2171                 : }
    2172                 : 
    2173                 : NS_IMETHODIMP
    2174               0 : nsDocShell::GetMarginHeight(PRInt32 * aHeight)
    2175                 : {
    2176               0 :     NS_ENSURE_ARG_POINTER(aHeight);
    2177                 : 
    2178               0 :     *aHeight = mMarginHeight;
    2179               0 :     return NS_OK;
    2180                 : }
    2181                 : 
    2182                 : NS_IMETHODIMP
    2183               0 : nsDocShell::SetMarginHeight(PRInt32 aHeight)
    2184                 : {
    2185               0 :     mMarginHeight = aHeight;
    2186               0 :     return NS_OK;
    2187                 : }
    2188                 : 
    2189                 : NS_IMETHODIMP
    2190               0 : nsDocShell::GetBusyFlags(PRUint32 * aBusyFlags)
    2191                 : {
    2192               0 :     NS_ENSURE_ARG_POINTER(aBusyFlags);
    2193                 : 
    2194               0 :     *aBusyFlags = mBusyFlags;
    2195               0 :     return NS_OK;
    2196                 : }
    2197                 : 
    2198                 : NS_IMETHODIMP
    2199               0 : nsDocShell::TabToTreeOwner(bool aForward, bool* aTookFocus)
    2200                 : {
    2201               0 :     NS_ENSURE_ARG_POINTER(aTookFocus);
    2202                 :     
    2203               0 :     nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
    2204               0 :     if (chromeFocus) {
    2205               0 :         if (aForward)
    2206               0 :             *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement());
    2207                 :         else
    2208               0 :             *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement());
    2209                 :     } else
    2210               0 :         *aTookFocus = false;
    2211                 :     
    2212               0 :     return NS_OK;
    2213                 : }
    2214                 : 
    2215                 : NS_IMETHODIMP
    2216               0 : nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI)
    2217                 : {
    2218               0 :     NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
    2219               0 :     return NS_OK;
    2220                 : }
    2221                 : 
    2222                 : NS_IMETHODIMP
    2223               0 : nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI)
    2224                 : {
    2225               0 :     mSecurityUI = aSecurityUI;
    2226               0 :     return NS_OK;
    2227                 : }
    2228                 : 
    2229                 : NS_IMETHODIMP
    2230               0 : nsDocShell::GetUseErrorPages(bool *aUseErrorPages)
    2231                 : {
    2232               0 :     *aUseErrorPages = mUseErrorPages;
    2233               0 :     return NS_OK;
    2234                 : }
    2235                 : 
    2236                 : NS_IMETHODIMP
    2237               0 : nsDocShell::SetUseErrorPages(bool aUseErrorPages)
    2238                 : {
    2239                 :     // If mUseErrorPages is set explicitly, stop observing the pref.
    2240               0 :     if (mObserveErrorPages) {
    2241               0 :         Preferences::RemoveObserver(this, "browser.xul.error_pages.enabled");
    2242               0 :         mObserveErrorPages = false;
    2243                 :     }
    2244               0 :     mUseErrorPages = aUseErrorPages;
    2245               0 :     return NS_OK;
    2246                 : }
    2247                 : 
    2248                 : NS_IMETHODIMP
    2249               0 : nsDocShell::GetPreviousTransIndex(PRInt32 *aPreviousTransIndex)
    2250                 : {
    2251               0 :     *aPreviousTransIndex = mPreviousTransIndex;
    2252               0 :     return NS_OK;
    2253                 : }
    2254                 : 
    2255                 : NS_IMETHODIMP
    2256               0 : nsDocShell::GetLoadedTransIndex(PRInt32 *aLoadedTransIndex)
    2257                 : {
    2258               0 :     *aLoadedTransIndex = mLoadedTransIndex;
    2259               0 :     return NS_OK;
    2260                 : }
    2261                 : 
    2262                 : NS_IMETHODIMP
    2263               0 : nsDocShell::HistoryPurged(PRInt32 aNumEntries)
    2264                 : {
    2265                 :     // These indices are used for fastback cache eviction, to determine
    2266                 :     // which session history entries are candidates for content viewer
    2267                 :     // eviction.  We need to adjust by the number of entries that we
    2268                 :     // just purged from history, so that we look at the right session history
    2269                 :     // entries during eviction.
    2270               0 :     mPreviousTransIndex = NS_MAX(-1, mPreviousTransIndex - aNumEntries);
    2271               0 :     mLoadedTransIndex = NS_MAX(0, mLoadedTransIndex - aNumEntries);
    2272                 : 
    2273               0 :     PRInt32 count = mChildList.Count();
    2274               0 :     for (PRInt32 i = 0; i < count; ++i) {
    2275               0 :         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
    2276               0 :         if (shell) {
    2277               0 :             shell->HistoryPurged(aNumEntries);
    2278                 :         }
    2279                 :     }
    2280                 : 
    2281               0 :     return NS_OK;
    2282                 : }
    2283                 : 
    2284                 : nsresult
    2285               0 : nsDocShell::HistoryTransactionRemoved(PRInt32 aIndex)
    2286                 : {
    2287                 :     // These indices are used for fastback cache eviction, to determine
    2288                 :     // which session history entries are candidates for content viewer
    2289                 :     // eviction.  We need to adjust by the number of entries that we
    2290                 :     // just purged from history, so that we look at the right session history
    2291                 :     // entries during eviction.
    2292               0 :     if (aIndex == mPreviousTransIndex) {
    2293               0 :         mPreviousTransIndex = -1;
    2294               0 :     } else if (aIndex < mPreviousTransIndex) {
    2295               0 :         --mPreviousTransIndex;
    2296                 :     }
    2297               0 :     if (mLoadedTransIndex == aIndex) {
    2298               0 :         mLoadedTransIndex = 0;
    2299               0 :     } else if (aIndex < mLoadedTransIndex) {
    2300               0 :         --mLoadedTransIndex;
    2301                 :     }
    2302                 :                             
    2303               0 :     PRInt32 count = mChildList.Count();
    2304               0 :     for (PRInt32 i = 0; i < count; ++i) {
    2305               0 :         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
    2306               0 :         if (shell) {
    2307               0 :             static_cast<nsDocShell*>(shell.get())->
    2308               0 :                 HistoryTransactionRemoved(aIndex);
    2309                 :         }
    2310                 :     }
    2311                 : 
    2312               0 :     return NS_OK;
    2313                 : }
    2314                 : 
    2315                 : NS_IMETHODIMP
    2316               0 : nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
    2317                 :                                           const nsAString& aDocumentURI,
    2318                 :                                           bool aCreate,
    2319                 :                                           nsIDOMStorage** aStorage)
    2320                 : {
    2321               0 :     NS_ENSURE_ARG_POINTER(aStorage);
    2322               0 :     *aStorage = nsnull;
    2323                 : 
    2324               0 :     if (!aPrincipal)
    2325               0 :         return NS_OK;
    2326                 : 
    2327                 :     nsresult rv;
    2328                 : 
    2329               0 :     nsCOMPtr<nsIDocShellTreeItem> topItem;
    2330               0 :     rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
    2331               0 :     if (NS_FAILED(rv))
    2332               0 :         return rv;
    2333                 : 
    2334               0 :     if (!topItem)
    2335               0 :         return NS_ERROR_FAILURE;
    2336                 : 
    2337               0 :     nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
    2338               0 :     if (topDocShell != this)
    2339                 :         return topDocShell->GetSessionStorageForPrincipal(aPrincipal,
    2340                 :                                                           aDocumentURI,
    2341                 :                                                           aCreate,
    2342               0 :                                                           aStorage);
    2343                 : 
    2344               0 :     nsXPIDLCString origin;
    2345               0 :     rv = aPrincipal->GetOrigin(getter_Copies(origin));
    2346               0 :     if (NS_FAILED(rv))
    2347               0 :         return rv;
    2348                 : 
    2349               0 :     if (origin.IsEmpty())
    2350               0 :         return NS_OK;
    2351                 : 
    2352               0 :     if (!mStorages.Get(origin, aStorage) && aCreate) {
    2353                 :         nsCOMPtr<nsIDOMStorage> newstorage =
    2354               0 :             do_CreateInstance("@mozilla.org/dom/storage;2");
    2355               0 :         if (!newstorage)
    2356               0 :             return NS_ERROR_OUT_OF_MEMORY;
    2357                 : 
    2358               0 :         nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
    2359               0 :         if (!pistorage)
    2360               0 :             return NS_ERROR_FAILURE;
    2361                 : 
    2362               0 :         rv = pistorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
    2363               0 :         if (NS_FAILED(rv))
    2364               0 :             return rv;
    2365                 : 
    2366               0 :         if (!mStorages.Put(origin, newstorage))
    2367               0 :             return NS_ERROR_OUT_OF_MEMORY;
    2368                 : 
    2369               0 :         newstorage.swap(*aStorage);
    2370                 : #if defined(PR_LOGGING) && defined(DEBUG)
    2371               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    2372                 :                ("nsDocShell[%p]: created a new sessionStorage %p",
    2373                 :                 this, *aStorage));
    2374                 : #endif
    2375                 :     }
    2376               0 :     else if (*aStorage) {
    2377               0 :         nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
    2378               0 :         if (piStorage) {
    2379               0 :             nsCOMPtr<nsIPrincipal> storagePrincipal = piStorage->Principal();
    2380                 : 
    2381                 :             // The origin string used to map items in the hash table is 
    2382                 :             // an implicit security check. That check is double-confirmed 
    2383                 :             // by checking the principal a storage was demanded for 
    2384                 :             // really is the principal for which that storage was originally 
    2385                 :             // created. Originally, the check was hidden in the CanAccess 
    2386                 :             // method but it's implementation has changed.
    2387                 :             bool equals;
    2388               0 :             nsresult rv = aPrincipal->EqualsIgnoringDomain(storagePrincipal, &equals);
    2389               0 :             NS_ASSERTION(NS_SUCCEEDED(rv) && equals,
    2390                 :                          "GetSessionStorageForPrincipal got a storage "
    2391                 :                          "that could not be accessed!");
    2392                 : 
    2393               0 :             if (NS_FAILED(rv) || !equals) {
    2394               0 :                 NS_RELEASE(*aStorage);
    2395               0 :                 return NS_ERROR_DOM_SECURITY_ERR;
    2396                 :             }
    2397                 :         }
    2398                 : 
    2399                 : #if defined(PR_LOGGING) && defined(DEBUG)
    2400               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    2401                 :                ("nsDocShell[%p]: returns existing sessionStorage %p",
    2402                 :                 this, *aStorage));
    2403                 : #endif
    2404                 :     }
    2405                 : 
    2406               0 :     if (aCreate) {
    2407                 :         // We are asked to create a new storage object. This indicates
    2408                 :         // that a new windows wants it. At this moment we "fork" the existing
    2409                 :         // storage object (what it means is described in the paragraph bellow).
    2410                 :         // We must create a single object per a single window to distinguish
    2411                 :         // a window originating oparations on the storage object to succesfully
    2412                 :         // prevent dispatch of a storage event to this same window that ivoked
    2413                 :         // a change in its storage. We also do this to correctly fill
    2414                 :         // documentURI property in the storage event.
    2415                 :         //
    2416                 :         // The difference between clone and fork is that clone creates
    2417                 :         // a completelly new and independent storage, but fork only creates
    2418                 :         // a new object wrapping the storage implementation and data and
    2419                 :         // the forked storage then behaves completelly the same way as
    2420                 :         // the storage it has been forked of, all such forked storage objects
    2421                 :         // shares their state and data and change on one such object affects
    2422                 :         // all others the same way.
    2423               0 :         nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
    2424               0 :         nsCOMPtr<nsIDOMStorage> fork = piStorage->Fork(aDocumentURI);
    2425                 : #if defined(PR_LOGGING) && defined(DEBUG)
    2426               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    2427                 :                ("nsDocShell[%p]: forked sessionStorage %p to %p",
    2428                 :                 this, *aStorage, fork.get()));
    2429                 : #endif
    2430               0 :         fork.swap(*aStorage);
    2431                 :     }
    2432                 : 
    2433               0 :     return NS_OK;
    2434                 : }
    2435                 : 
    2436                 : NS_IMETHODIMP
    2437               0 : nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
    2438                 :                                     const nsAString& aDocumentURI,
    2439                 :                                     nsIDOMStorage** aStorage)
    2440                 : {
    2441               0 :     return GetSessionStorageForURI(aURI, aDocumentURI, true, aStorage);
    2442                 : }
    2443                 : 
    2444                 : nsresult
    2445               0 : nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
    2446                 :                                     const nsSubstring& aDocumentURI,
    2447                 :                                     bool aCreate,
    2448                 :                                     nsIDOMStorage** aStorage)
    2449                 : {
    2450               0 :     NS_ENSURE_ARG(aURI);
    2451               0 :     NS_ENSURE_ARG_POINTER(aStorage);
    2452                 : 
    2453               0 :     *aStorage = nsnull;
    2454                 : 
    2455                 :     nsresult rv;
    2456                 : 
    2457                 :     nsCOMPtr<nsIScriptSecurityManager> securityManager =
    2458               0 :         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    2459               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2460                 : 
    2461                 :     // This is terrible hack and should go away along with this whole method.
    2462               0 :     nsCOMPtr<nsIPrincipal> principal;
    2463               0 :     rv = securityManager->GetCodebasePrincipal(aURI, getter_AddRefs(principal));
    2464               0 :     if (NS_FAILED(rv))
    2465               0 :         return rv;
    2466                 : 
    2467               0 :     return GetSessionStorageForPrincipal(principal, aDocumentURI, aCreate, aStorage);
    2468                 : }
    2469                 : 
    2470                 : nsresult
    2471               0 : nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
    2472                 :                               nsIDOMStorage* aStorage)
    2473                 : {
    2474               0 :     NS_ENSURE_ARG_POINTER(aStorage);
    2475                 : 
    2476               0 :     if (!aPrincipal)
    2477               0 :         return NS_OK;
    2478                 : 
    2479               0 :     nsCOMPtr<nsIDocShellTreeItem> topItem;
    2480               0 :     nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
    2481               0 :     if (NS_FAILED(rv))
    2482               0 :         return rv;
    2483                 : 
    2484               0 :     if (topItem) {
    2485               0 :         nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
    2486               0 :         if (topDocShell == this) {
    2487               0 :             nsXPIDLCString origin;
    2488               0 :             rv = aPrincipal->GetOrigin(getter_Copies(origin));
    2489               0 :             if (NS_FAILED(rv))
    2490               0 :                 return rv;
    2491                 : 
    2492               0 :             if (origin.IsEmpty())
    2493               0 :                 return NS_ERROR_FAILURE;
    2494                 : 
    2495                 :             // Do not replace an existing session storage.
    2496               0 :             if (mStorages.GetWeak(origin))
    2497               0 :                 return NS_ERROR_NOT_AVAILABLE;
    2498                 : 
    2499                 : #if defined(PR_LOGGING) && defined(DEBUG)
    2500               0 :             PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    2501                 :                    ("nsDocShell[%p]: was added a sessionStorage %p",
    2502                 :                     this, aStorage));
    2503                 : #endif
    2504               0 :             if (!mStorages.Put(origin, aStorage))
    2505               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    2506                 :         }
    2507                 :         else {
    2508               0 :             return topDocShell->AddSessionStorage(aPrincipal, aStorage);
    2509                 :         }
    2510                 :     }
    2511                 : 
    2512               0 :     return NS_OK;
    2513                 : }
    2514                 : 
    2515                 : NS_IMETHODIMP
    2516               0 : nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
    2517                 : {
    2518               0 :     NS_IF_ADDREF(*aResult = GetCurrentDocChannel()); 
    2519               0 :     return NS_OK;
    2520                 : }
    2521                 : 
    2522                 : nsIChannel*
    2523               0 : nsDocShell::GetCurrentDocChannel()
    2524                 : {
    2525               0 :     if (mContentViewer) {
    2526               0 :         nsIDocument* doc = mContentViewer->GetDocument();
    2527               0 :         if (doc) {
    2528               0 :             return doc->GetChannel();
    2529                 :         }
    2530                 :     }
    2531               0 :     return nsnull;
    2532                 : }
    2533                 : 
    2534                 : //*****************************************************************************
    2535                 : // nsDocShell::nsIDocShellTreeItem
    2536                 : //*****************************************************************************   
    2537                 : 
    2538                 : NS_IMETHODIMP
    2539               0 : nsDocShell::GetName(PRUnichar ** aName)
    2540                 : {
    2541               0 :     NS_ENSURE_ARG_POINTER(aName);
    2542               0 :     *aName = ToNewUnicode(mName);
    2543               0 :     return NS_OK;
    2544                 : }
    2545                 : 
    2546                 : NS_IMETHODIMP
    2547               0 : nsDocShell::SetName(const PRUnichar * aName)
    2548                 : {
    2549               0 :     mName = aName;              // this does a copy of aName
    2550               0 :     return NS_OK;
    2551                 : }
    2552                 : 
    2553                 : NS_IMETHODIMP
    2554               0 : nsDocShell::NameEquals(const PRUnichar *aName, bool *_retval)
    2555                 : {
    2556               0 :     NS_ENSURE_ARG_POINTER(aName);
    2557               0 :     NS_ENSURE_ARG_POINTER(_retval);
    2558               0 :     *_retval = mName.Equals(aName);
    2559               0 :     return NS_OK;
    2560                 : }
    2561                 : 
    2562                 : NS_IMETHODIMP
    2563               0 : nsDocShell::GetItemType(PRInt32 * aItemType)
    2564                 : {
    2565               0 :     NS_ENSURE_ARG_POINTER(aItemType);
    2566                 : 
    2567               0 :     *aItemType = mItemType;
    2568               0 :     return NS_OK;
    2569                 : }
    2570                 : 
    2571                 : NS_IMETHODIMP
    2572               0 : nsDocShell::SetItemType(PRInt32 aItemType)
    2573                 : {
    2574               0 :     NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
    2575                 : 
    2576                 :     // Only allow setting the type on root docshells.  Those would be the ones
    2577                 :     // that have the docloader service as mParent or have no mParent at all.
    2578                 :     nsCOMPtr<nsIDocumentLoader> docLoaderService =
    2579               0 :         do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
    2580               0 :     NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
    2581                 :     
    2582               0 :     NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
    2583                 : 
    2584               0 :     mItemType = aItemType;
    2585                 : 
    2586                 :     // disable auth prompting for anything but content
    2587               0 :     mAllowAuth = mItemType == typeContent; 
    2588                 : 
    2589               0 :     nsRefPtr<nsPresContext> presContext = nsnull;
    2590               0 :     GetPresContext(getter_AddRefs(presContext));
    2591               0 :     if (presContext) {
    2592               0 :         presContext->InvalidateIsChromeCache();
    2593                 :     }
    2594                 : 
    2595               0 :     return NS_OK;
    2596                 : }
    2597                 : 
    2598                 : NS_IMETHODIMP
    2599               0 : nsDocShell::GetParent(nsIDocShellTreeItem ** aParent)
    2600                 : {
    2601               0 :     if (!mParent) {
    2602               0 :         *aParent = nsnull;
    2603                 :     } else {
    2604               0 :         CallQueryInterface(mParent, aParent);
    2605                 :     }
    2606                 :     // Note that in the case when the parent is not an nsIDocShellTreeItem we
    2607                 :     // don't want to throw; we just want to return null.
    2608               0 :     return NS_OK;
    2609                 : }
    2610                 : 
    2611                 : nsresult
    2612               0 : nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
    2613                 : {
    2614               0 :     nsDocLoader::SetDocLoaderParent(aParent);
    2615                 : 
    2616                 :     // Curse ambiguous nsISupports inheritance!
    2617               0 :     nsISupports* parent = GetAsSupports(aParent);
    2618                 : 
    2619                 :     // If parent is another docshell, we inherit all their flags for
    2620                 :     // allowing plugins, scripting etc.
    2621                 :     bool value;
    2622               0 :     nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
    2623               0 :     if (parentAsDocShell)
    2624                 :     {
    2625               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value)))
    2626                 :         {
    2627               0 :             SetAllowPlugins(value);
    2628                 :         }
    2629               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value)))
    2630                 :         {
    2631               0 :             SetAllowJavascript(value);
    2632                 :         }
    2633               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value)))
    2634                 :         {
    2635               0 :             SetAllowMetaRedirects(value);
    2636                 :         }
    2637               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value)))
    2638                 :         {
    2639               0 :             SetAllowSubframes(value);
    2640                 :         }
    2641               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value)))
    2642                 :         {
    2643               0 :             SetAllowImages(value);
    2644                 :         }
    2645               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value)))
    2646                 :         {
    2647               0 :             SetAllowWindowControl(value);
    2648                 :         }
    2649               0 :         if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value)))
    2650                 :         {
    2651               0 :             SetIsActive(value);
    2652                 :         }
    2653               0 :         if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
    2654               0 :             value = false;
    2655                 :         }
    2656               0 :         SetAllowDNSPrefetch(value);
    2657                 :     }
    2658               0 :     nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
    2659               0 :     if (parentAsLoadContext &&
    2660               0 :         NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value)))
    2661                 :     {
    2662               0 :         SetUsePrivateBrowsing(value);
    2663                 :     }
    2664                 : 
    2665               0 :     nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
    2666               0 :     if (parentURIListener)
    2667               0 :         mContentListener->SetParentContentListener(parentURIListener);
    2668               0 :     return NS_OK;
    2669                 : }
    2670                 : 
    2671                 : NS_IMETHODIMP
    2672               0 : nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
    2673                 : {
    2674               0 :     NS_ENSURE_ARG_POINTER(aParent);
    2675               0 :     *aParent = nsnull;
    2676                 : 
    2677                 :     nsCOMPtr<nsIDocShellTreeItem> parent =
    2678               0 :         do_QueryInterface(GetAsSupports(mParent));
    2679               0 :     if (!parent)
    2680               0 :         return NS_OK;
    2681                 : 
    2682                 :     PRInt32 parentType;
    2683               0 :     NS_ENSURE_SUCCESS(parent->GetItemType(&parentType), NS_ERROR_FAILURE);
    2684                 : 
    2685               0 :     if (parentType == mItemType) {
    2686               0 :         parent.swap(*aParent);
    2687                 :     }
    2688               0 :     return NS_OK;
    2689                 : }
    2690                 : 
    2691                 : NS_IMETHODIMP
    2692               0 : nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
    2693                 : {
    2694               0 :     NS_ENSURE_ARG_POINTER(aRootTreeItem);
    2695               0 :     *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
    2696                 : 
    2697               0 :     nsCOMPtr<nsIDocShellTreeItem> parent;
    2698               0 :     NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
    2699               0 :     while (parent) {
    2700               0 :         *aRootTreeItem = parent;
    2701               0 :         NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)),
    2702                 :                           NS_ERROR_FAILURE);
    2703                 :     }
    2704               0 :     NS_ADDREF(*aRootTreeItem);
    2705               0 :     return NS_OK;
    2706                 : }
    2707                 : 
    2708                 : NS_IMETHODIMP
    2709               0 : nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
    2710                 : {
    2711               0 :     NS_ENSURE_ARG_POINTER(aRootTreeItem);
    2712               0 :     *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
    2713                 : 
    2714               0 :     nsCOMPtr<nsIDocShellTreeItem> parent;
    2715               0 :     NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
    2716                 :                       NS_ERROR_FAILURE);
    2717               0 :     while (parent) {
    2718               0 :         *aRootTreeItem = parent;
    2719               0 :         NS_ENSURE_SUCCESS((*aRootTreeItem)->
    2720                 :                           GetSameTypeParent(getter_AddRefs(parent)),
    2721                 :                           NS_ERROR_FAILURE);
    2722                 :     }
    2723               0 :     NS_ADDREF(*aRootTreeItem);
    2724               0 :     return NS_OK;
    2725                 : }
    2726                 : 
    2727                 : /* static */
    2728                 : bool
    2729               0 : nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
    2730                 :                           nsIDocShellTreeItem* aAccessingItem,
    2731                 :                           bool aConsiderOpener)
    2732                 : {
    2733               0 :     NS_PRECONDITION(aTargetItem, "Must have target item!");
    2734                 : 
    2735               0 :     if (!gValidateOrigin || !aAccessingItem) {
    2736                 :         // Good to go
    2737               0 :         return true;
    2738                 :     }
    2739                 : 
    2740                 :     // XXXbz should we care if aAccessingItem or the document therein is
    2741                 :     // chrome?  Should those get extra privileges?
    2742                 : 
    2743                 :     // For historical context, see:
    2744                 :     // 
    2745                 :     // Bug 13871:  Prevent frameset spoofing
    2746                 :     // Bug 103638: Targets with same name in different windows open in wrong
    2747                 :     //             window with javascript
    2748                 :     // Bug 408052: Adopt "ancestor" frame navigation policy
    2749                 : 
    2750                 :     // Now do a security check
    2751                 :     //
    2752                 :     // Allow navigation if
    2753                 :     //  1) aAccessingItem can script aTargetItem or one of its ancestors in
    2754                 :     //     the frame hierarchy or
    2755                 :     //  2) aTargetItem is a top-level frame and aAccessingItem is its descendant
    2756                 :     //  3) aTargetItem is a top-level frame and aAccessingItem can target
    2757                 :     //     its opener per rule (1) or (2).
    2758                 : 
    2759               0 :     if (aTargetItem == aAccessingItem) {
    2760                 :         // A frame is allowed to navigate itself.
    2761               0 :         return true;  
    2762                 :     }
    2763                 : 
    2764               0 :     nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
    2765               0 :     aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
    2766                 : 
    2767               0 :     if (aTargetItem == accessingRoot) {
    2768                 :         // A frame can navigate its root.
    2769               0 :         return true;
    2770                 :     }
    2771                 : 
    2772                 :     // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
    2773               0 :     nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
    2774               0 :     do {
    2775               0 :         if (ValidateOrigin(aAccessingItem, target)) {
    2776               0 :             return true;
    2777                 :         }
    2778                 :             
    2779               0 :         nsCOMPtr<nsIDocShellTreeItem> parent;
    2780               0 :         target->GetSameTypeParent(getter_AddRefs(parent));
    2781               0 :         parent.swap(target);
    2782               0 :     } while (target);
    2783                 : 
    2784               0 :     nsCOMPtr<nsIDocShellTreeItem> targetRoot;
    2785               0 :     aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
    2786                 : 
    2787               0 :     if (aTargetItem != targetRoot) {
    2788                 :         // target is a subframe, not in accessor's frame hierarchy, and all its
    2789                 :         // ancestors have origins different from that of the accessor. Don't
    2790                 :         // allow access.
    2791               0 :         return false;
    2792                 :     }
    2793                 : 
    2794               0 :     if (!aConsiderOpener) {
    2795                 :         // All done here
    2796               0 :         return false;
    2797                 :     }
    2798                 : 
    2799               0 :     nsCOMPtr<nsIDOMWindow> targetWindow = do_GetInterface(aTargetItem);
    2800               0 :     if (!targetWindow) {
    2801               0 :         NS_ERROR("This should not happen, really");
    2802               0 :         return false;
    2803                 :     }
    2804                 : 
    2805               0 :     nsCOMPtr<nsIDOMWindow> targetOpener;
    2806               0 :     targetWindow->GetOpener(getter_AddRefs(targetOpener));
    2807               0 :     nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
    2808               0 :     nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
    2809                 : 
    2810               0 :     if (!openerItem) {
    2811               0 :         return false;
    2812                 :     }
    2813                 : 
    2814               0 :     return CanAccessItem(openerItem, aAccessingItem, false);    
    2815                 : }
    2816                 : 
    2817                 : static bool
    2818               0 : ItemIsActive(nsIDocShellTreeItem *aItem)
    2819                 : {
    2820               0 :     nsCOMPtr<nsIDOMWindow> window(do_GetInterface(aItem));
    2821                 : 
    2822               0 :     if (window) {
    2823                 :         bool isClosed;
    2824                 : 
    2825               0 :         if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) {
    2826               0 :             return true;
    2827                 :         }
    2828                 :     }
    2829                 : 
    2830               0 :     return false;
    2831                 : }
    2832                 : 
    2833                 : NS_IMETHODIMP
    2834               0 : nsDocShell::FindItemWithName(const PRUnichar * aName,
    2835                 :                              nsISupports * aRequestor,
    2836                 :                              nsIDocShellTreeItem * aOriginalRequestor,
    2837                 :                              nsIDocShellTreeItem ** _retval)
    2838                 : {
    2839               0 :     NS_ENSURE_ARG(aName);
    2840               0 :     NS_ENSURE_ARG_POINTER(_retval);
    2841                 : 
    2842                 :     // If we don't find one, we return NS_OK and a null result
    2843               0 :     *_retval = nsnull;
    2844                 : 
    2845               0 :     if (!*aName)
    2846               0 :         return NS_OK;
    2847                 : 
    2848               0 :     if (!aRequestor)
    2849                 :     {
    2850               0 :         nsCOMPtr<nsIDocShellTreeItem> foundItem;
    2851                 : 
    2852                 :         // This is the entry point into the target-finding algorithm.  Check
    2853                 :         // for special names.  This should only be done once, hence the check
    2854                 :         // for a null aRequestor.
    2855                 : 
    2856               0 :         nsDependentString name(aName);
    2857               0 :         if (name.LowerCaseEqualsLiteral("_self")) {
    2858               0 :             foundItem = this;
    2859                 :         }
    2860               0 :         else if (name.LowerCaseEqualsLiteral("_blank"))
    2861                 :         {
    2862                 :             // Just return null.  Caller must handle creating a new window with
    2863                 :             // a blank name himself.
    2864               0 :             return NS_OK;
    2865                 :         }
    2866               0 :         else if (name.LowerCaseEqualsLiteral("_parent"))
    2867                 :         {
    2868               0 :             GetSameTypeParent(getter_AddRefs(foundItem));
    2869               0 :             if(!foundItem)
    2870               0 :                 foundItem = this;
    2871                 :         }
    2872               0 :         else if (name.LowerCaseEqualsLiteral("_top"))
    2873                 :         {
    2874               0 :             GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
    2875               0 :             NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
    2876                 :         }
    2877                 :         // _main is an IE target which should be case-insensitive but isn't
    2878                 :         // see bug 217886 for details
    2879               0 :         else if (name.LowerCaseEqualsLiteral("_content") ||
    2880               0 :                  name.EqualsLiteral("_main"))
    2881                 :         {
    2882                 :             // Must pass our same type root as requestor to the
    2883                 :             // treeowner to make sure things work right.
    2884               0 :             nsCOMPtr<nsIDocShellTreeItem> root;
    2885               0 :             GetSameTypeRootTreeItem(getter_AddRefs(root));
    2886               0 :             if (mTreeOwner) {
    2887               0 :                 NS_ASSERTION(root, "Must have this; worst case it's us!");
    2888                 :                 mTreeOwner->FindItemWithName(aName, root, aOriginalRequestor,
    2889               0 :                                              getter_AddRefs(foundItem));
    2890                 :             }
    2891                 : #ifdef DEBUG
    2892                 :             else {
    2893                 :                 NS_ERROR("Someone isn't setting up the tree owner.  "
    2894                 :                          "You might like to try that.  "
    2895               0 :                          "Things will.....you know, work.");
    2896                 :                 // Note: _content should always exist.  If we don't have one
    2897                 :                 // hanging off the treeowner, just create a named window....
    2898                 :                 // so don't return here, in case we did that and can now find
    2899                 :                 // it.                
    2900                 :                 // XXXbz should we be using |root| instead of creating
    2901                 :                 // a new window?
    2902                 :             }
    2903                 : #endif
    2904                 :         }
    2905                 : 
    2906               0 :         if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
    2907               0 :             foundItem = nsnull;
    2908                 :         }
    2909                 : 
    2910               0 :         if (foundItem) {
    2911                 :             // We return foundItem here even if it's not an active
    2912                 :             // item since all the names we've dealt with so far are
    2913                 :             // special cases that we won't bother looking for further.
    2914                 : 
    2915               0 :             foundItem.swap(*_retval);
    2916               0 :             return NS_OK;
    2917                 :         }
    2918                 :     }
    2919                 : 
    2920                 :     // Keep looking
    2921                 :         
    2922                 :     // First we check our name.
    2923               0 :     if (mName.Equals(aName) && ItemIsActive(this) &&
    2924               0 :         CanAccessItem(this, aOriginalRequestor)) {
    2925               0 :         NS_ADDREF(*_retval = this);
    2926               0 :         return NS_OK;
    2927                 :     }
    2928                 : 
    2929                 :     // This QI may fail, but the places where we want to compare, comparing
    2930                 :     // against nsnull serves the same purpose.
    2931               0 :     nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
    2932                 : 
    2933                 :     // Second we check our children making sure not to ask a child if
    2934                 :     // it is the aRequestor.
    2935                 : #ifdef DEBUG
    2936                 :     nsresult rv =
    2937                 : #endif
    2938                 :     FindChildWithName(aName, true, true, reqAsTreeItem,
    2939               0 :                       aOriginalRequestor, _retval);
    2940               0 :     NS_ASSERTION(NS_SUCCEEDED(rv),
    2941                 :                  "FindChildWithName should not be failing here.");
    2942               0 :     if (*_retval)
    2943               0 :         return NS_OK;
    2944                 :         
    2945                 :     // Third if we have a parent and it isn't the requestor then we
    2946                 :     // should ask it to do the search.  If it is the requestor we
    2947                 :     // should just stop here and let the parent do the rest.  If we
    2948                 :     // don't have a parent, then we should ask the
    2949                 :     // docShellTreeOwner to do the search.
    2950                 :     nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
    2951               0 :         do_QueryInterface(GetAsSupports(mParent));
    2952               0 :     if (parentAsTreeItem) {
    2953               0 :         if (parentAsTreeItem == reqAsTreeItem)
    2954               0 :             return NS_OK;
    2955                 : 
    2956                 :         PRInt32 parentType;
    2957               0 :         parentAsTreeItem->GetItemType(&parentType);
    2958               0 :         if (parentType == mItemType) {
    2959               0 :             return parentAsTreeItem->
    2960                 :                 FindItemWithName(aName,
    2961                 :                                  static_cast<nsIDocShellTreeItem*>
    2962                 :                                             (this),
    2963                 :                                  aOriginalRequestor,
    2964               0 :                                  _retval);
    2965                 :         }
    2966                 :     }
    2967                 : 
    2968                 :     // If the parent is null or not of the same type fall through and ask tree
    2969                 :     // owner.
    2970                 : 
    2971                 :     // This may fail, but comparing against null serves the same purpose
    2972                 :     nsCOMPtr<nsIDocShellTreeOwner>
    2973               0 :         reqAsTreeOwner(do_QueryInterface(aRequestor));
    2974                 : 
    2975               0 :     if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
    2976                 :         return mTreeOwner->
    2977               0 :             FindItemWithName(aName, this, aOriginalRequestor, _retval);
    2978                 :     }
    2979                 : 
    2980               0 :     return NS_OK;
    2981                 : }
    2982                 : 
    2983                 : NS_IMETHODIMP
    2984               0 : nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)
    2985                 : {
    2986               0 :     NS_ENSURE_ARG_POINTER(aTreeOwner);
    2987                 : 
    2988               0 :     *aTreeOwner = mTreeOwner;
    2989               0 :     NS_IF_ADDREF(*aTreeOwner);
    2990               0 :     return NS_OK;
    2991                 : }
    2992                 : 
    2993                 : #ifdef DEBUG_DOCSHELL_FOCUS
    2994                 : static void 
    2995                 : PrintDocTree(nsIDocShellTreeItem * aParentNode, int aLevel)
    2996                 : {
    2997                 :   for (PRInt32 i=0;i<aLevel;i++) printf("  ");
    2998                 : 
    2999                 :   PRInt32 childWebshellCount;
    3000                 :   aParentNode->GetChildCount(&childWebshellCount);
    3001                 :   nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
    3002                 :   PRInt32 type;
    3003                 :   aParentNode->GetItemType(&type);
    3004                 :   nsCOMPtr<nsIPresShell> presShell;
    3005                 :   parentAsDocShell->GetPresShell(getter_AddRefs(presShell));
    3006                 :   nsRefPtr<nsPresContext> presContext;
    3007                 :   parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
    3008                 :   nsIDocument *doc = presShell->GetDocument();
    3009                 : 
    3010                 :   nsCOMPtr<nsIDOMWindow> domwin(doc->GetWindow());
    3011                 : 
    3012                 :   nsCOMPtr<nsIWidget> widget;
    3013                 :   nsIViewManager* vm = presShell->GetViewManager();
    3014                 :   if (vm) {
    3015                 :     vm->GetWidget(getter_AddRefs(widget));
    3016                 :   }
    3017                 :   dom::Element* rootElement = doc->GetRootElement();
    3018                 : 
    3019                 :   printf("DS %p  Ty %s  Doc %p DW %p EM %p CN %p\n",  
    3020                 :     (void*)parentAsDocShell.get(), 
    3021                 :     type==nsIDocShellTreeItem::typeChrome?"Chr":"Con", 
    3022                 :      (void*)doc, (void*)domwin.get(),
    3023                 :      (void*)presContext->EventStateManager(), (void*)rootElement);
    3024                 : 
    3025                 :   if (childWebshellCount > 0) {
    3026                 :     for (PRInt32 i=0;i<childWebshellCount;i++) {
    3027                 :       nsCOMPtr<nsIDocShellTreeItem> child;
    3028                 :       aParentNode->GetChildAt(i, getter_AddRefs(child));
    3029                 :       PrintDocTree(child, aLevel+1);
    3030                 :     }
    3031                 :   }
    3032                 : }
    3033                 : 
    3034                 : static void 
    3035                 : PrintDocTree(nsIDocShellTreeItem * aParentNode)
    3036                 : {
    3037                 :   NS_ASSERTION(aParentNode, "Pointer is null!");
    3038                 : 
    3039                 :   nsCOMPtr<nsIDocShellTreeItem> parentItem;
    3040                 :   aParentNode->GetParent(getter_AddRefs(parentItem));
    3041                 :   while (parentItem) {
    3042                 :     nsCOMPtr<nsIDocShellTreeItem>tmp;
    3043                 :     parentItem->GetParent(getter_AddRefs(tmp));
    3044                 :     if (!tmp) {
    3045                 :       break;
    3046                 :     }
    3047                 :     parentItem = tmp;
    3048                 :   }
    3049                 : 
    3050                 :   if (!parentItem) {
    3051                 :     parentItem = aParentNode;
    3052                 :   }
    3053                 : 
    3054                 :   PrintDocTree(parentItem, 0);
    3055                 : }
    3056                 : #endif
    3057                 : 
    3058                 : NS_IMETHODIMP
    3059               0 : nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
    3060                 : {
    3061                 : #ifdef DEBUG_DOCSHELL_FOCUS
    3062                 :     nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
    3063                 :     if (item) {
    3064                 :       PrintDocTree(item);
    3065                 :     }
    3066                 : #endif
    3067                 : 
    3068                 :     // Don't automatically set the progress based on the tree owner for frames
    3069               0 :     if (!IsFrame()) {
    3070                 :         nsCOMPtr<nsIWebProgress> webProgress =
    3071               0 :             do_QueryInterface(GetAsSupports(this));
    3072                 : 
    3073               0 :         if (webProgress) {
    3074                 :             nsCOMPtr<nsIWebProgressListener>
    3075               0 :                 oldListener(do_QueryInterface(mTreeOwner));
    3076                 :             nsCOMPtr<nsIWebProgressListener>
    3077               0 :                 newListener(do_QueryInterface(aTreeOwner));
    3078                 : 
    3079               0 :             if (oldListener) {
    3080               0 :                 webProgress->RemoveProgressListener(oldListener);
    3081                 :             }
    3082                 : 
    3083               0 :             if (newListener) {
    3084               0 :                 webProgress->AddProgressListener(newListener,
    3085               0 :                                                  nsIWebProgress::NOTIFY_ALL);
    3086                 :             }
    3087                 :         }
    3088                 :     }
    3089                 : 
    3090               0 :     mTreeOwner = aTreeOwner;    // Weak reference per API
    3091                 : 
    3092               0 :     PRInt32 i, n = mChildList.Count();
    3093               0 :     for (i = 0; i < n; i++) {
    3094               0 :         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
    3095               0 :         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
    3096               0 :         PRInt32 childType = ~mItemType; // Set it to not us in case the get fails
    3097               0 :         child->GetItemType(&childType); // We don't care if this fails, if it does we won't set the owner
    3098               0 :         if (childType == mItemType)
    3099               0 :             child->SetTreeOwner(aTreeOwner);
    3100                 :     }
    3101                 : 
    3102               0 :     return NS_OK;
    3103                 : }
    3104                 : 
    3105                 : NS_IMETHODIMP
    3106               0 : nsDocShell::SetChildOffset(PRUint32 aChildOffset)
    3107                 : {
    3108               0 :     mChildOffset = aChildOffset;
    3109               0 :     return NS_OK;
    3110                 : }
    3111                 : 
    3112                 : NS_IMETHODIMP
    3113               0 : nsDocShell::GetHistoryID(PRUint64* aID)
    3114                 : {
    3115               0 :   *aID = mHistoryID;
    3116               0 :   return NS_OK;
    3117                 : }
    3118                 : 
    3119                 : NS_IMETHODIMP
    3120               0 : nsDocShell::GetIsInUnload(bool* aIsInUnload)
    3121                 : {
    3122               0 :     *aIsInUnload = mFiredUnloadEvent;
    3123               0 :     return NS_OK;
    3124                 : }
    3125                 : 
    3126                 : //*****************************************************************************
    3127                 : // nsDocShell::nsIDocShellTreeNode
    3128                 : //*****************************************************************************   
    3129                 : 
    3130                 : NS_IMETHODIMP
    3131               0 : nsDocShell::GetChildCount(PRInt32 * aChildCount)
    3132                 : {
    3133               0 :     NS_ENSURE_ARG_POINTER(aChildCount);
    3134               0 :     *aChildCount = mChildList.Count();
    3135               0 :     return NS_OK;
    3136                 : }
    3137                 : 
    3138                 : 
    3139                 : 
    3140                 : NS_IMETHODIMP
    3141               0 : nsDocShell::AddChild(nsIDocShellTreeItem * aChild)
    3142                 : {
    3143               0 :     NS_ENSURE_ARG_POINTER(aChild);
    3144                 : 
    3145               0 :     nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
    3146               0 :     NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
    3147                 : 
    3148                 :     // Make sure we're not creating a loop in the docshell tree
    3149               0 :     nsDocLoader* ancestor = this;
    3150               0 :     do {
    3151               0 :         if (childAsDocLoader == ancestor) {
    3152               0 :             return NS_ERROR_ILLEGAL_VALUE;
    3153                 :         }
    3154               0 :         ancestor = ancestor->GetParent();
    3155                 :     } while (ancestor);
    3156                 :     
    3157                 :     // Make sure to remove the child from its current parent.
    3158               0 :     nsDocLoader* childsParent = childAsDocLoader->GetParent();
    3159               0 :     if (childsParent) {
    3160               0 :         childsParent->RemoveChildLoader(childAsDocLoader);
    3161                 :     }
    3162                 : 
    3163                 :     // Make sure to clear the treeowner in case this child is a different type
    3164                 :     // from us.
    3165               0 :     aChild->SetTreeOwner(nsnull);
    3166                 :     
    3167               0 :     nsresult res = AddChildLoader(childAsDocLoader);
    3168               0 :     NS_ENSURE_SUCCESS(res, res);
    3169               0 :     NS_ASSERTION(mChildList.Count() > 0,
    3170                 :                  "child list must not be empty after a successful add");
    3171                 : 
    3172               0 :     nsCOMPtr<nsIDocShellHistory> docshellhistory = do_QueryInterface(aChild);
    3173               0 :     bool dynamic = false;
    3174               0 :     docshellhistory->GetCreatedDynamically(&dynamic);
    3175               0 :     if (!dynamic) {
    3176               0 :         nsCOMPtr<nsISHEntry> currentSH;
    3177               0 :         bool oshe = false;
    3178               0 :         GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
    3179               0 :         if (currentSH) {
    3180               0 :             currentSH->HasDynamicallyAddedChild(&dynamic);
    3181                 :         }
    3182                 :     }
    3183               0 :     nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
    3184               0 :     childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Count() - 1);
    3185                 : 
    3186                 :     /* Set the child's global history if the parent has one */
    3187               0 :     if (mUseGlobalHistory) {
    3188                 :         nsCOMPtr<nsIDocShellHistory>
    3189               0 :             dsHistoryChild(do_QueryInterface(aChild));
    3190               0 :         if (dsHistoryChild)
    3191               0 :             dsHistoryChild->SetUseGlobalHistory(true);
    3192                 :     }
    3193                 : 
    3194                 : 
    3195               0 :     PRInt32 childType = ~mItemType;     // Set it to not us in case the get fails
    3196               0 :     aChild->GetItemType(&childType);
    3197               0 :     if (childType != mItemType)
    3198               0 :         return NS_OK;
    3199                 :     // Everything below here is only done when the child is the same type.
    3200                 : 
    3201                 : 
    3202               0 :     aChild->SetTreeOwner(mTreeOwner);
    3203                 : 
    3204               0 :     nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
    3205               0 :     if (!childAsDocShell)
    3206               0 :         return NS_OK;
    3207                 : 
    3208                 :     // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
    3209                 : 
    3210                 :     // Now take this document's charset and set the child's parentCharset field
    3211                 :     // to it. We'll later use that field, in the loading process, for the
    3212                 :     // charset choosing algorithm.
    3213                 :     // If we fail, at any point, we just return NS_OK.
    3214                 :     // This code has some performance impact. But this will be reduced when 
    3215                 :     // the current charset will finally be stored as an Atom, avoiding the
    3216                 :     // alias resolution extra look-up.
    3217                 : 
    3218                 :     // we are NOT going to propagate the charset is this Chrome's docshell
    3219               0 :     if (mItemType == nsIDocShellTreeItem::typeChrome)
    3220               0 :         return NS_OK;
    3221                 : 
    3222                 :     // get the parent's current charset
    3223               0 :     if (!mContentViewer)
    3224               0 :         return NS_OK;
    3225               0 :     nsIDocument* doc = mContentViewer->GetDocument();
    3226               0 :     if (!doc)
    3227               0 :         return NS_OK;
    3228               0 :     const nsACString &parentCS = doc->GetDocumentCharacterSet();
    3229                 : 
    3230               0 :     bool isWyciwyg = false;
    3231                 : 
    3232               0 :     if (mCurrentURI) {
    3233                 :         // Check if the url is wyciwyg
    3234               0 :         mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);      
    3235                 :     }
    3236                 : 
    3237               0 :     if (!isWyciwyg) {
    3238                 :         // If this docshell is loaded from a wyciwyg: URI, don't
    3239                 :         // advertise our charset since it does not in any way reflect
    3240                 :         // the actual source charset, which is what we're trying to
    3241                 :         // expose here.
    3242                 : 
    3243                 :         // set the child's parentCharset
    3244               0 :         nsCOMPtr<nsIAtom> parentCSAtom(do_GetAtom(parentCS));
    3245               0 :         res = childAsDocShell->SetParentCharset(parentCSAtom);
    3246               0 :         if (NS_FAILED(res))
    3247               0 :             return NS_OK;
    3248                 : 
    3249               0 :         PRInt32 charsetSource = doc->GetDocumentCharacterSetSource();
    3250                 : 
    3251                 :         // set the child's parentCharset
    3252               0 :         res = childAsDocShell->SetParentCharsetSource(charsetSource);
    3253               0 :         if (NS_FAILED(res))
    3254               0 :             return NS_OK;
    3255                 :     }
    3256                 : 
    3257                 :     // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
    3258                 : 
    3259               0 :     return NS_OK;
    3260                 : }
    3261                 : 
    3262                 : NS_IMETHODIMP
    3263               0 : nsDocShell::RemoveChild(nsIDocShellTreeItem * aChild)
    3264                 : {
    3265               0 :     NS_ENSURE_ARG_POINTER(aChild);
    3266                 : 
    3267               0 :     nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
    3268               0 :     NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
    3269                 :     
    3270               0 :     nsresult rv = RemoveChildLoader(childAsDocLoader);
    3271               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3272                 :     
    3273               0 :     aChild->SetTreeOwner(nsnull);
    3274                 : 
    3275               0 :     return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
    3276                 : }
    3277                 : 
    3278                 : NS_IMETHODIMP
    3279               0 : nsDocShell::GetChildAt(PRInt32 aIndex, nsIDocShellTreeItem ** aChild)
    3280                 : {
    3281               0 :     NS_ENSURE_ARG_POINTER(aChild);
    3282                 : 
    3283                 : #ifdef DEBUG
    3284               0 :     if (aIndex < 0) {
    3285               0 :       NS_WARNING("Negative index passed to GetChildAt");
    3286                 :     }
    3287               0 :     else if (aIndex >= mChildList.Count()) {
    3288               0 :       NS_WARNING("Too large an index passed to GetChildAt");
    3289                 :     }
    3290                 : #endif
    3291                 : 
    3292               0 :     nsIDocumentLoader* child = SafeChildAt(aIndex);
    3293               0 :     NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
    3294                 :     
    3295               0 :     return CallQueryInterface(child, aChild);
    3296                 : }
    3297                 : 
    3298                 : NS_IMETHODIMP
    3299               0 : nsDocShell::FindChildWithName(const PRUnichar * aName,
    3300                 :                               bool aRecurse, bool aSameType,
    3301                 :                               nsIDocShellTreeItem * aRequestor,
    3302                 :                               nsIDocShellTreeItem * aOriginalRequestor,
    3303                 :                               nsIDocShellTreeItem ** _retval)
    3304                 : {
    3305               0 :     NS_ENSURE_ARG(aName);
    3306               0 :     NS_ENSURE_ARG_POINTER(_retval);
    3307                 : 
    3308               0 :     *_retval = nsnull;          // if we don't find one, we return NS_OK and a null result 
    3309                 : 
    3310               0 :     if (!*aName)
    3311               0 :         return NS_OK;
    3312                 : 
    3313               0 :     nsXPIDLString childName;
    3314               0 :     PRInt32 i, n = mChildList.Count();
    3315               0 :     for (i = 0; i < n; i++) {
    3316               0 :         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
    3317               0 :         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
    3318                 :         PRInt32 childType;
    3319               0 :         child->GetItemType(&childType);
    3320                 : 
    3321               0 :         if (aSameType && (childType != mItemType))
    3322               0 :             continue;
    3323                 : 
    3324               0 :         bool childNameEquals = false;
    3325               0 :         child->NameEquals(aName, &childNameEquals);
    3326               0 :         if (childNameEquals && ItemIsActive(child) &&
    3327               0 :             CanAccessItem(child, aOriginalRequestor)) {
    3328               0 :             child.swap(*_retval);
    3329                 :             break;
    3330                 :         }
    3331                 : 
    3332               0 :         if (childType != mItemType)     //Only ask it to check children if it is same type
    3333               0 :             continue;
    3334                 : 
    3335               0 :         if (aRecurse && (aRequestor != child))  // Only ask the child if it isn't the requestor
    3336                 :         {
    3337                 :             // See if child contains the shell with the given name
    3338                 : #ifdef DEBUG
    3339                 :             nsresult rv =
    3340                 : #endif
    3341               0 :             child->FindChildWithName(aName, true,
    3342                 :                                      aSameType,
    3343                 :                                      static_cast<nsIDocShellTreeItem*>
    3344                 :                                                 (this),
    3345                 :                                      aOriginalRequestor,
    3346               0 :                                      _retval);
    3347               0 :             NS_ASSERTION(NS_SUCCEEDED(rv),
    3348                 :                          "FindChildWithName should not fail here");
    3349               0 :             if (*_retval)           // found it
    3350               0 :                 return NS_OK;
    3351                 :         }
    3352                 :     }
    3353               0 :     return NS_OK;
    3354                 : }
    3355                 : 
    3356                 : //*****************************************************************************
    3357                 : // nsDocShell::nsIDocShellHistory
    3358                 : //*****************************************************************************   
    3359                 : NS_IMETHODIMP
    3360               0 : nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
    3361                 : {
    3362               0 :     nsresult rv = NS_OK;
    3363                 : 
    3364               0 :     NS_ENSURE_ARG_POINTER(aResult);
    3365               0 :     *aResult = nsnull;
    3366                 : 
    3367                 :     
    3368                 :     // A nsISHEntry for a child is *only* available when the parent is in
    3369                 :     // the progress of loading a document too...
    3370                 :     
    3371               0 :     if (mLSHE) {
    3372                 :         /* Before looking for the subframe's url, check
    3373                 :          * the expiration status of the parent. If the parent
    3374                 :          * has expired from cache, then subframes will not be 
    3375                 :          * loaded from history in certain situations.  
    3376                 :          */
    3377               0 :         bool parentExpired=false;
    3378               0 :         mLSHE->GetExpirationStatus(&parentExpired);
    3379                 :         
    3380                 :         /* Get the parent's Load Type so that it can be set on the child too.
    3381                 :          * By default give a loadHistory value
    3382                 :          */
    3383               0 :         PRUint32 loadType = nsIDocShellLoadInfo::loadHistory;
    3384               0 :         mLSHE->GetLoadType(&loadType);  
    3385                 :         // If the user did a shift-reload on this frameset page, 
    3386                 :         // we don't want to load the subframes from history.
    3387               0 :         if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
    3388                 :             loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
    3389                 :             loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
    3390                 :             loadType == nsIDocShellLoadInfo::loadRefresh)
    3391               0 :             return rv;
    3392                 :         
    3393                 :         /* If the user pressed reload and the parent frame has expired
    3394                 :          *  from cache, we do not want to load the child frame from history.
    3395                 :          */
    3396               0 :         if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
    3397                 :             // The parent has expired. Return null.
    3398               0 :             *aResult = nsnull;
    3399               0 :             return rv;
    3400                 :         }
    3401                 : 
    3402               0 :         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
    3403               0 :         if (container) {
    3404                 :             // Get the child subframe from session history.
    3405               0 :             rv = container->GetChildAt(aChildOffset, aResult);            
    3406               0 :             if (*aResult) 
    3407               0 :                 (*aResult)->SetLoadType(loadType);            
    3408                 :         }
    3409                 :     }
    3410               0 :     return rv;
    3411                 : }
    3412                 : 
    3413                 : NS_IMETHODIMP
    3414               0 : nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
    3415                 :                             PRInt32 aChildOffset, PRUint32 loadType,
    3416                 :                             bool aCloneChildren)
    3417                 : {
    3418                 :     nsresult rv;
    3419                 : 
    3420               0 :     if (mLSHE && loadType != LOAD_PUSHSTATE) {
    3421                 :         /* You get here if you are currently building a 
    3422                 :          * hierarchy ie.,you just visited a frameset page
    3423                 :          */
    3424               0 :         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
    3425               0 :         if (container) {
    3426               0 :             rv = container->AddChild(aNewEntry, aChildOffset);
    3427                 :         }
    3428                 :     }
    3429               0 :     else if (!aCloneRef) {
    3430                 :         /* This is an initial load in some subframe.  Just append it if we can */
    3431               0 :         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
    3432               0 :         if (container) {
    3433               0 :             rv = container->AddChild(aNewEntry, aChildOffset);
    3434                 :         }
    3435                 :     }
    3436               0 :     else if (mSessionHistory) {
    3437                 :         /* You are currently in the rootDocShell.
    3438                 :          * You will get here when a subframe has a new url
    3439                 :          * to load and you have walked up the tree all the 
    3440                 :          * way to the top to clone the current SHEntry hierarchy
    3441                 :          * and replace the subframe where a new url was loaded with
    3442                 :          * a new entry.
    3443                 :          */
    3444               0 :         PRInt32 index = -1;
    3445               0 :         nsCOMPtr<nsIHistoryEntry> currentHE;
    3446               0 :         mSessionHistory->GetIndex(&index);
    3447               0 :         if (index < 0)
    3448               0 :             return NS_ERROR_FAILURE;
    3449                 : 
    3450               0 :         rv = mSessionHistory->GetEntryAtIndex(index, false,
    3451               0 :                                               getter_AddRefs(currentHE));
    3452               0 :         NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
    3453                 : 
    3454               0 :         nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
    3455               0 :         if (currentEntry) {
    3456               0 :             PRUint32 cloneID = 0;
    3457               0 :             nsCOMPtr<nsISHEntry> nextEntry;
    3458               0 :             aCloneRef->GetID(&cloneID);
    3459                 :             rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
    3460               0 :                                  aCloneChildren, getter_AddRefs(nextEntry));
    3461                 : 
    3462               0 :             if (NS_SUCCEEDED(rv)) {
    3463                 :                 nsCOMPtr<nsISHistoryInternal>
    3464               0 :                     shPrivate(do_QueryInterface(mSessionHistory));
    3465               0 :                 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
    3466               0 :                 rv = shPrivate->AddEntry(nextEntry, true);
    3467                 :             }
    3468                 :         }
    3469                 :     }
    3470                 :     else {
    3471                 :         /* Just pass this along */
    3472                 :         nsCOMPtr<nsIDocShellHistory> parent =
    3473               0 :             do_QueryInterface(GetAsSupports(mParent), &rv);
    3474               0 :         if (parent) {
    3475               0 :             rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
    3476               0 :                                          loadType, aCloneChildren);
    3477                 :         }          
    3478                 :     }
    3479               0 :     return rv;
    3480                 : }
    3481                 : 
    3482                 : nsresult
    3483               0 : nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset,
    3484                 :                               bool aCloneChildren)
    3485                 : {
    3486                 :     /* You will get here when you are in a subframe and
    3487                 :      * a new url has been loaded on you. 
    3488                 :      * The mOSHE in this subframe will be the previous url's
    3489                 :      * mOSHE. This mOSHE will be used as the identification
    3490                 :      * for this subframe in the  CloneAndReplace function.
    3491                 :      */
    3492                 : 
    3493                 :     // In this case, we will end up calling AddEntry, which increases the
    3494                 :     // current index by 1
    3495               0 :     nsCOMPtr<nsISHistory> rootSH;
    3496               0 :     GetRootSessionHistory(getter_AddRefs(rootSH));
    3497               0 :     if (rootSH) {
    3498               0 :         rootSH->GetIndex(&mPreviousTransIndex);
    3499                 :     }
    3500                 : 
    3501                 :     nsresult rv;
    3502                 :     nsCOMPtr<nsIDocShellHistory> parent =
    3503               0 :         do_QueryInterface(GetAsSupports(mParent), &rv);
    3504               0 :     if (parent) {
    3505               0 :         rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
    3506               0 :                                      aCloneChildren);
    3507                 :     }
    3508                 : 
    3509                 : 
    3510               0 :     if (rootSH) {
    3511               0 :         rootSH->GetIndex(&mLoadedTransIndex);
    3512                 : #ifdef DEBUG_PAGE_CACHE
    3513                 :         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
    3514                 :                mLoadedTransIndex);
    3515                 : #endif
    3516                 :     }
    3517                 : 
    3518               0 :     return rv;
    3519                 : }
    3520                 : 
    3521                 : NS_IMETHODIMP
    3522               0 : nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
    3523                 : {
    3524                 :     nsresult rv;
    3525                 : 
    3526               0 :     mUseGlobalHistory = aUseGlobalHistory;
    3527                 : 
    3528               0 :     if (!aUseGlobalHistory) {
    3529               0 :         mGlobalHistory = nsnull;
    3530               0 :         return NS_OK;
    3531                 :     }
    3532                 : 
    3533                 :     // No need to initialize mGlobalHistory if IHistory is available.
    3534               0 :     nsCOMPtr<IHistory> history = services::GetHistoryService();
    3535               0 :     if (history) {
    3536               0 :         return NS_OK;
    3537                 :     }
    3538                 : 
    3539               0 :     if (mGlobalHistory) {
    3540               0 :         return NS_OK;
    3541                 :     }
    3542                 : 
    3543               0 :     mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
    3544               0 :     return rv;
    3545                 : }
    3546                 : 
    3547                 : NS_IMETHODIMP
    3548               0 : nsDocShell::GetUseGlobalHistory(bool *aUseGlobalHistory)
    3549                 : {
    3550               0 :     *aUseGlobalHistory = mUseGlobalHistory;
    3551               0 :     return NS_OK;
    3552                 : }
    3553                 : 
    3554                 : NS_IMETHODIMP
    3555               0 : nsDocShell::RemoveFromSessionHistory()
    3556                 : {
    3557               0 :     nsCOMPtr<nsISHistoryInternal> internalHistory;
    3558               0 :     nsCOMPtr<nsISHistory> sessionHistory;
    3559               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
    3560               0 :     GetSameTypeRootTreeItem(getter_AddRefs(root));
    3561               0 :     if (root) {
    3562                 :         nsCOMPtr<nsIWebNavigation> rootAsWebnav =
    3563               0 :             do_QueryInterface(root);
    3564               0 :         if (rootAsWebnav) {
    3565               0 :             rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
    3566               0 :             internalHistory = do_QueryInterface(sessionHistory);
    3567                 :         }
    3568                 :     }
    3569               0 :     if (!internalHistory) {
    3570               0 :         return NS_OK;
    3571                 :     }
    3572                 : 
    3573               0 :     PRInt32 index = 0;
    3574               0 :     sessionHistory->GetIndex(&index);
    3575               0 :     nsAutoTArray<PRUint64, 16> ids;
    3576               0 :     ids.AppendElement(mHistoryID);
    3577               0 :     internalHistory->RemoveEntries(ids, index);
    3578               0 :     return NS_OK;
    3579                 : }
    3580                 : 
    3581                 : NS_IMETHODIMP
    3582               0 : nsDocShell::SetCreatedDynamically(bool aDynamic)
    3583                 : {
    3584               0 :     mDynamicallyCreated = aDynamic;
    3585               0 :     return NS_OK;
    3586                 : }
    3587                 : 
    3588                 : NS_IMETHODIMP
    3589               0 : nsDocShell::GetCreatedDynamically(bool* aDynamic)
    3590                 : {
    3591               0 :     *aDynamic = mDynamicallyCreated;
    3592               0 :     return NS_OK;
    3593                 : }
    3594                 : 
    3595                 : NS_IMETHODIMP
    3596               0 : nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
    3597                 : {
    3598               0 :     *aOSHE = false;
    3599               0 :     *aEntry = nsnull;
    3600               0 :     if (mLSHE) {
    3601               0 :         NS_ADDREF(*aEntry = mLSHE);
    3602               0 :     } else if (mOSHE) {
    3603               0 :         NS_ADDREF(*aEntry = mOSHE);
    3604               0 :         *aOSHE = true;
    3605                 :     }
    3606               0 :     return NS_OK;
    3607                 : }
    3608                 : 
    3609                 : void
    3610               0 : nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
    3611                 : {
    3612               0 :   nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
    3613               0 :   nsCOMPtr<nsISHistory> rootSH;
    3614               0 :   GetRootSessionHistory(getter_AddRefs(rootSH));
    3615               0 :   nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
    3616               0 :   if (!history || !shcontainer) {
    3617                 :     return;
    3618                 :   }
    3619                 : 
    3620               0 :   PRInt32 count = 0;
    3621               0 :   shcontainer->GetChildCount(&count);
    3622               0 :   nsAutoTArray<PRUint64, 16> ids;
    3623               0 :   for (PRInt32 i = 0; i < count; ++i) {
    3624               0 :     nsCOMPtr<nsISHEntry> child;
    3625               0 :     shcontainer->GetChildAt(i, getter_AddRefs(child));
    3626               0 :     if (child) {
    3627               0 :       PRUint64 id = 0;
    3628               0 :       child->GetDocshellID(&id);
    3629               0 :       ids.AppendElement(id);
    3630                 :     }
    3631                 :   }
    3632               0 :   PRInt32 index = 0;
    3633               0 :   rootSH->GetIndex(&index);
    3634               0 :   history->RemoveEntries(ids, index);
    3635                 : }
    3636                 : 
    3637                 : //-------------------------------------
    3638                 : //-- Helper Method for Print discovery
    3639                 : //-------------------------------------
    3640                 : bool 
    3641               0 : nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
    3642                 : {
    3643               0 :   if (mIsPrintingOrPP && aDisplayErrorDialog) {
    3644               0 :     DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nsnull, nsnull);
    3645                 :   }
    3646                 : 
    3647               0 :   return mIsPrintingOrPP;
    3648                 : }
    3649                 : 
    3650                 : bool
    3651               0 : nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog)
    3652                 : {
    3653               0 :     return !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
    3654                 : }
    3655                 : 
    3656                 : //*****************************************************************************
    3657                 : // nsDocShell::nsIWebNavigation
    3658                 : //*****************************************************************************   
    3659                 : 
    3660                 : NS_IMETHODIMP
    3661               0 : nsDocShell::GetCanGoBack(bool * aCanGoBack)
    3662                 : {
    3663               0 :     if (!IsNavigationAllowed(false)) {
    3664               0 :       *aCanGoBack = false;
    3665               0 :       return NS_OK; // JS may not handle returning of an error code
    3666                 :     }
    3667                 :     nsresult rv;
    3668               0 :     nsCOMPtr<nsISHistory> rootSH;
    3669               0 :     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
    3670               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
    3671               0 :     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
    3672               0 :     rv = webnav->GetCanGoBack(aCanGoBack);   
    3673               0 :     return rv;
    3674                 : 
    3675                 : }
    3676                 : 
    3677                 : NS_IMETHODIMP
    3678               0 : nsDocShell::GetCanGoForward(bool * aCanGoForward)
    3679                 : {
    3680               0 :     if (!IsNavigationAllowed(false)) {
    3681               0 :       *aCanGoForward = false;
    3682               0 :       return NS_OK; // JS may not handle returning of an error code
    3683                 :     }
    3684                 :     nsresult rv;
    3685               0 :     nsCOMPtr<nsISHistory> rootSH;
    3686               0 :     rv = GetRootSessionHistory(getter_AddRefs(rootSH)); 
    3687               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
    3688               0 :     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
    3689               0 :     rv = webnav->GetCanGoForward(aCanGoForward);
    3690               0 :     return rv;
    3691                 : 
    3692                 : }
    3693                 : 
    3694                 : NS_IMETHODIMP
    3695               0 : nsDocShell::GoBack()
    3696                 : {
    3697               0 :     if (!IsNavigationAllowed()) {
    3698               0 :       return NS_OK; // JS may not handle returning of an error code
    3699                 :     }
    3700                 :     nsresult rv;
    3701               0 :     nsCOMPtr<nsISHistory> rootSH;
    3702               0 :     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
    3703               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
    3704               0 :     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
    3705               0 :     rv = webnav->GoBack();
    3706               0 :     return rv;
    3707                 : 
    3708                 : }
    3709                 : 
    3710                 : NS_IMETHODIMP
    3711               0 : nsDocShell::GoForward()
    3712                 : {
    3713               0 :     if (!IsNavigationAllowed()) {
    3714               0 :       return NS_OK; // JS may not handle returning of an error code
    3715                 :     }
    3716                 :     nsresult rv;
    3717               0 :     nsCOMPtr<nsISHistory> rootSH;
    3718               0 :     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
    3719               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
    3720               0 :     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
    3721               0 :     rv = webnav->GoForward();
    3722               0 :     return rv;
    3723                 : 
    3724                 : }
    3725                 : 
    3726               0 : NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex)
    3727                 : {
    3728               0 :     if (!IsNavigationAllowed()) {
    3729               0 :       return NS_OK; // JS may not handle returning of an error code
    3730                 :     }
    3731                 :     nsresult rv;
    3732               0 :     nsCOMPtr<nsISHistory> rootSH;
    3733               0 :     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
    3734               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
    3735               0 :     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
    3736               0 :     rv = webnav->GotoIndex(aIndex);
    3737               0 :     return rv;
    3738                 : 
    3739                 : }
    3740                 : 
    3741                 : NS_IMETHODIMP
    3742               0 : nsDocShell::LoadURI(const PRUnichar * aURI,
    3743                 :                     PRUint32 aLoadFlags,
    3744                 :                     nsIURI * aReferringURI,
    3745                 :                     nsIInputStream * aPostStream,
    3746                 :                     nsIInputStream * aHeaderStream)
    3747                 : {
    3748               0 :     NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
    3749                 :     
    3750               0 :     if (!IsNavigationAllowed()) {
    3751               0 :       return NS_OK; // JS may not handle returning of an error code
    3752                 :     }
    3753               0 :     nsCOMPtr<nsIURI> uri;
    3754               0 :     nsresult rv = NS_OK;
    3755                 : 
    3756                 :     // Create a URI from our string; if that succeeds, we want to
    3757                 :     // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
    3758                 :     // flag.
    3759                 : 
    3760               0 :     NS_ConvertUTF16toUTF8 uriString(aURI);
    3761                 :     // Cleanup the empty spaces that might be on each end.
    3762               0 :     uriString.Trim(" ");
    3763                 :     // Eliminate embedded newlines, which single-line text fields now allow:
    3764               0 :     uriString.StripChars("\r\n");
    3765               0 :     NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
    3766                 : 
    3767               0 :     rv = NS_NewURI(getter_AddRefs(uri), uriString);
    3768               0 :     if (uri) {
    3769               0 :         aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
    3770                 :     }
    3771                 :     
    3772               0 :     if (sURIFixup) {
    3773                 :         // Call the fixup object.  This will clobber the rv from NS_NewURI
    3774                 :         // above, but that's fine with us.  Note that we need to do this even
    3775                 :         // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
    3776                 :         // (things like view-source:mozilla.org for example).
    3777               0 :         PRUint32 fixupFlags = 0;
    3778               0 :         if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
    3779               0 :           fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
    3780                 :         }
    3781               0 :         if (aLoadFlags & LOAD_FLAGS_URI_IS_UTF8) {
    3782               0 :           fixupFlags |= nsIURIFixup::FIXUP_FLAG_USE_UTF8;
    3783                 :         }
    3784                 :         rv = sURIFixup->CreateFixupURI(uriString, fixupFlags,
    3785               0 :                                        getter_AddRefs(uri));
    3786                 :     }
    3787                 :     // else no fixup service so just use the URI we created and see
    3788                 :     // what happens
    3789                 : 
    3790               0 :     if (NS_ERROR_MALFORMED_URI == rv) {
    3791               0 :         DisplayLoadError(rv, uri, aURI);
    3792                 :     }
    3793                 : 
    3794               0 :     if (NS_FAILED(rv) || !uri)
    3795               0 :         return NS_ERROR_FAILURE;
    3796                 : 
    3797                 :     PopupControlState popupState;
    3798               0 :     if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
    3799               0 :         popupState = openAllowed;
    3800               0 :         aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
    3801                 :     } else {
    3802               0 :         popupState = openOverridden;
    3803                 :     }
    3804               0 :     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
    3805               0 :     nsAutoPopupStatePusher statePusher(win, popupState);
    3806                 : 
    3807                 :     // Don't pass certain flags that aren't needed and end up confusing
    3808                 :     // ConvertLoadTypeToDocShellLoadInfo.  We do need to ensure that they are
    3809                 :     // passed to LoadURI though, since it uses them.
    3810               0 :     PRUint32 extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
    3811               0 :     aLoadFlags &= ~EXTRA_LOAD_FLAGS;
    3812                 : 
    3813               0 :     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
    3814               0 :     rv = CreateLoadInfo(getter_AddRefs(loadInfo));
    3815               0 :     if (NS_FAILED(rv)) return rv;
    3816                 :     
    3817               0 :     PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
    3818               0 :     loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
    3819               0 :     loadInfo->SetPostDataStream(aPostStream);
    3820               0 :     loadInfo->SetReferrer(aReferringURI);
    3821               0 :     loadInfo->SetHeadersStream(aHeaderStream);
    3822                 : 
    3823               0 :     rv = LoadURI(uri, loadInfo, extraFlags, true);
    3824                 : 
    3825               0 :     return rv;
    3826                 : }
    3827                 : 
    3828                 : NS_IMETHODIMP
    3829               0 : nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
    3830                 :                              const PRUnichar *aURL,
    3831                 :                              nsIChannel* aFailedChannel)
    3832                 : {
    3833                 :     // Get prompt and string bundle servcies
    3834               0 :     nsCOMPtr<nsIPrompt> prompter;
    3835               0 :     nsCOMPtr<nsIStringBundle> stringBundle;
    3836               0 :     GetPromptAndStringBundle(getter_AddRefs(prompter),
    3837               0 :                              getter_AddRefs(stringBundle));
    3838                 : 
    3839               0 :     NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
    3840               0 :     NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
    3841                 : 
    3842               0 :     nsAutoString error;
    3843               0 :     const PRUint32 kMaxFormatStrArgs = 3;
    3844               0 :     nsAutoString formatStrs[kMaxFormatStrArgs];
    3845               0 :     PRUint32 formatStrCount = 0;
    3846               0 :     bool addHostPort = false;
    3847               0 :     nsresult rv = NS_OK;
    3848               0 :     nsAutoString messageStr;
    3849               0 :     nsCAutoString cssClass;
    3850               0 :     nsCAutoString errorPage;
    3851                 : 
    3852               0 :     errorPage.AssignLiteral("neterror");
    3853                 : 
    3854                 :     // Turn the error code into a human readable error message.
    3855               0 :     if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
    3856               0 :         NS_ENSURE_ARG_POINTER(aURI);
    3857                 :         // extract the scheme
    3858               0 :         nsCAutoString scheme;
    3859               0 :         aURI->GetScheme(scheme);
    3860               0 :         CopyASCIItoUTF16(scheme, formatStrs[0]);
    3861               0 :         formatStrCount = 1;
    3862               0 :         error.AssignLiteral("protocolNotFound");
    3863                 :     }
    3864               0 :     else if (NS_ERROR_FILE_NOT_FOUND == aError) {
    3865               0 :         NS_ENSURE_ARG_POINTER(aURI);
    3866               0 :         error.AssignLiteral("fileNotFound");
    3867                 :     }
    3868               0 :     else if (NS_ERROR_UNKNOWN_HOST == aError) {
    3869               0 :         NS_ENSURE_ARG_POINTER(aURI);
    3870                 :         // Get the host
    3871               0 :         nsCAutoString host;
    3872               0 :         nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
    3873               0 :         innermostURI->GetHost(host);
    3874               0 :         CopyUTF8toUTF16(host, formatStrs[0]);
    3875               0 :         formatStrCount = 1;
    3876               0 :         error.AssignLiteral("dnsNotFound");
    3877                 :     }
    3878               0 :     else if(NS_ERROR_CONNECTION_REFUSED == aError) {
    3879               0 :         NS_ENSURE_ARG_POINTER(aURI);
    3880               0 :         addHostPort = true;
    3881               0 :         error.AssignLiteral("connectionFailure");
    3882                 :     }
    3883               0 :     else if(NS_ERROR_NET_INTERRUPT == aError) {
    3884               0 :         NS_ENSURE_ARG_POINTER(aURI);
    3885               0 :         addHostPort = true;
    3886               0 :         error.AssignLiteral("netInterrupt");
    3887                 :     }
    3888               0 :     else if (NS_ERROR_NET_TIMEOUT == aError) {
    3889               0 :         NS_ENSURE_ARG_POINTER(aURI);
    3890                 :         // Get the host
    3891               0 :         nsCAutoString host;
    3892               0 :         aURI->GetHost(host);
    3893               0 :         CopyUTF8toUTF16(host, formatStrs[0]);
    3894               0 :         formatStrCount = 1;
    3895               0 :         error.AssignLiteral("netTimeout");
    3896                 :     }
    3897               0 :     else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError) {
    3898                 :         // CSP error
    3899               0 :         cssClass.AssignLiteral("neterror");
    3900               0 :         error.AssignLiteral("cspFrameAncestorBlocked");
    3901                 :     }
    3902               0 :     else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
    3903                 :         nsCOMPtr<nsINSSErrorsService> nsserr =
    3904               0 :             do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
    3905                 : 
    3906                 :         PRUint32 errorClass;
    3907               0 :         if (!nsserr ||
    3908               0 :             NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
    3909               0 :           errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
    3910                 :         }
    3911                 : 
    3912               0 :         nsCOMPtr<nsISupports> securityInfo;
    3913               0 :         nsCOMPtr<nsITransportSecurityInfo> tsi;
    3914               0 :         if (aFailedChannel)
    3915               0 :             aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
    3916               0 :         tsi = do_QueryInterface(securityInfo);
    3917               0 :         if (tsi) {
    3918                 :             // Usually we should have aFailedChannel and get a detailed message
    3919               0 :             tsi->GetErrorMessage(getter_Copies(messageStr));
    3920                 :         }
    3921                 :         else {
    3922                 :             // No channel, let's obtain the generic error message
    3923               0 :             if (nsserr) {
    3924               0 :                 nsserr->GetErrorMessage(aError, messageStr);
    3925                 :             }
    3926                 :         }
    3927               0 :         if (!messageStr.IsEmpty()) {
    3928               0 :             if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
    3929               0 :                 error.AssignLiteral("nssBadCert");
    3930                 : 
    3931                 :                 // if this is a Strict-Transport-Security host and the cert
    3932                 :                 // is bad, don't allow overrides (STS Spec section 7.3).
    3933                 :                 nsCOMPtr<nsIStrictTransportSecurityService> stss =
    3934               0 :                           do_GetService(NS_STSSERVICE_CONTRACTID, &rv);
    3935               0 :                 NS_ENSURE_SUCCESS(rv, rv);
    3936                 : 
    3937               0 :                 bool isStsHost = false;
    3938               0 :                 rv = stss->IsStsURI(aURI, &isStsHost);
    3939               0 :                 NS_ENSURE_SUCCESS(rv, rv);
    3940                 : 
    3941               0 :                 if (isStsHost)
    3942               0 :                   cssClass.AssignLiteral("badStsCert");
    3943                 : 
    3944               0 :                 if (Preferences::GetBool(
    3945                 :                         "browser.xul.error_pages.expert_bad_cert", false)) {
    3946               0 :                     cssClass.AssignLiteral("expertBadCert");
    3947                 :                 }
    3948                 : 
    3949                 :                 // See if an alternate cert error page is registered
    3950                 :                 nsAdoptingCString alternateErrorPage =
    3951                 :                     Preferences::GetCString(
    3952               0 :                         "security.alternate_certificate_error_page");
    3953               0 :                 if (alternateErrorPage)
    3954               0 :                     errorPage.Assign(alternateErrorPage);
    3955                 :             } else {
    3956               0 :                 error.AssignLiteral("nssFailure2");
    3957                 :             }
    3958                 :         }
    3959               0 :     } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError) {
    3960               0 :         nsCAutoString host;
    3961               0 :         aURI->GetHost(host);
    3962               0 :         CopyUTF8toUTF16(host, formatStrs[0]);
    3963               0 :         formatStrCount = 1;
    3964                 : 
    3965                 :         // Malware and phishing detectors may want to use an alternate error
    3966                 :         // page, but if the pref's not set, we'll fall back on the standard page
    3967                 :         nsAdoptingCString alternateErrorPage =
    3968               0 :             Preferences::GetCString("urlclassifier.alternate_error_page");
    3969               0 :         if (alternateErrorPage)
    3970               0 :             errorPage.Assign(alternateErrorPage);
    3971                 : 
    3972               0 :         if (NS_ERROR_PHISHING_URI == aError)
    3973               0 :             error.AssignLiteral("phishingBlocked");
    3974                 :         else
    3975               0 :             error.AssignLiteral("malwareBlocked");
    3976               0 :         cssClass.AssignLiteral("blacklist");
    3977                 :     }
    3978                 :     else {
    3979                 :         // Errors requiring simple formatting
    3980               0 :         switch (aError) {
    3981                 :         case NS_ERROR_MALFORMED_URI:
    3982                 :             // URI is malformed
    3983               0 :             error.AssignLiteral("malformedURI");
    3984               0 :             break;
    3985                 :         case NS_ERROR_REDIRECT_LOOP:
    3986                 :             // Doc failed to load because the server generated too many redirects
    3987               0 :             error.AssignLiteral("redirectLoop");
    3988               0 :             break;
    3989                 :         case NS_ERROR_UNKNOWN_SOCKET_TYPE:
    3990                 :             // Doc failed to load because PSM is not installed
    3991               0 :             error.AssignLiteral("unknownSocketType");
    3992               0 :             break;
    3993                 :         case NS_ERROR_NET_RESET:
    3994                 :             // Doc failed to load because the server kept reseting the connection
    3995                 :             // before we could read any data from it
    3996               0 :             error.AssignLiteral("netReset");
    3997               0 :             break;
    3998                 :         case NS_ERROR_DOCUMENT_NOT_CACHED:
    3999                 :             // Doc failed to load because the cache does not contain a copy of
    4000                 :             // the document.
    4001               0 :             error.AssignLiteral("notCached");
    4002               0 :             break;
    4003                 :         case NS_ERROR_OFFLINE:
    4004                 :             // Doc failed to load because we are offline.
    4005               0 :             error.AssignLiteral("netOffline");
    4006               0 :             break;
    4007                 :         case NS_ERROR_DOCUMENT_IS_PRINTMODE:
    4008                 :             // Doc navigation attempted while Printing or Print Preview
    4009               0 :             error.AssignLiteral("isprinting");
    4010               0 :             break;
    4011                 :         case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
    4012                 :             // Port blocked for security reasons
    4013               0 :             addHostPort = true;
    4014               0 :             error.AssignLiteral("deniedPortAccess");
    4015               0 :             break;
    4016                 :         case NS_ERROR_UNKNOWN_PROXY_HOST:
    4017                 :             // Proxy hostname could not be resolved.
    4018               0 :             error.AssignLiteral("proxyResolveFailure");
    4019               0 :             break;
    4020                 :         case NS_ERROR_PROXY_CONNECTION_REFUSED:
    4021                 :             // Proxy connection was refused.
    4022               0 :             error.AssignLiteral("proxyConnectFailure");
    4023               0 :             break;
    4024                 :         case NS_ERROR_INVALID_CONTENT_ENCODING:
    4025                 :             // Bad Content Encoding.
    4026               0 :             error.AssignLiteral("contentEncodingError");
    4027               0 :             break;
    4028                 :         case NS_ERROR_REMOTE_XUL:
    4029                 :         {
    4030               0 :             error.AssignLiteral("remoteXUL");
    4031               0 :             break;
    4032                 :         }
    4033                 :         case NS_ERROR_UNSAFE_CONTENT_TYPE:
    4034                 :             // Channel refused to load from an unrecognized content type.
    4035               0 :             error.AssignLiteral("unsafeContentType");
    4036               0 :             break;
    4037                 :         case NS_ERROR_CORRUPTED_CONTENT:
    4038                 :             // Broken Content Detected. e.g. Content-MD5 check failure.
    4039               0 :             error.AssignLiteral("corruptedContentError");
    4040               0 :             break;
    4041                 :         }
    4042                 :     }
    4043                 : 
    4044                 :     // Test if the error should be displayed
    4045               0 :     if (error.IsEmpty()) {
    4046               0 :         return NS_OK;
    4047                 :     }
    4048                 : 
    4049                 :     // Test if the error needs to be formatted
    4050               0 :     if (!messageStr.IsEmpty()) {
    4051                 :         // already obtained message
    4052                 :     }
    4053                 :     else {
    4054               0 :         if (addHostPort) {
    4055                 :             // Build up the host:port string.
    4056               0 :             nsCAutoString hostport;
    4057               0 :             if (aURI) {
    4058               0 :                 aURI->GetHostPort(hostport);
    4059                 :             } else {
    4060               0 :                 hostport.AssignLiteral("?");
    4061                 :             }
    4062               0 :             CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
    4063                 :         }
    4064                 : 
    4065               0 :         nsCAutoString spec;
    4066               0 :         rv = NS_ERROR_NOT_AVAILABLE;
    4067               0 :         if (aURI) {
    4068                 :             // displaying "file://" is aesthetically unpleasing and could even be
    4069                 :             // confusing to the user
    4070               0 :             bool isFileURI = false;
    4071               0 :             rv = aURI->SchemeIs("file", &isFileURI);
    4072               0 :             if (NS_SUCCEEDED(rv) && isFileURI)
    4073               0 :                 aURI->GetPath(spec);
    4074                 :             else
    4075               0 :                 aURI->GetSpec(spec);
    4076                 : 
    4077               0 :             nsCAutoString charset;
    4078                 :             // unescape and convert from origin charset
    4079               0 :             aURI->GetOriginCharset(charset);
    4080                 :             nsCOMPtr<nsITextToSubURI> textToSubURI(
    4081               0 :                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
    4082               0 :             if (NS_SUCCEEDED(rv)) {
    4083               0 :                 rv = textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[formatStrCount]);
    4084                 :             }
    4085                 :         } else {
    4086               0 :             spec.AssignLiteral("?");
    4087                 :         }
    4088               0 :         if (NS_FAILED(rv))
    4089               0 :             CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
    4090               0 :         rv = NS_OK;
    4091               0 :         ++formatStrCount;
    4092                 : 
    4093                 :         const PRUnichar *strs[kMaxFormatStrArgs];
    4094               0 :         for (PRUint32 i = 0; i < formatStrCount; i++) {
    4095               0 :             strs[i] = formatStrs[i].get();
    4096                 :         }
    4097               0 :         nsXPIDLString str;
    4098               0 :         rv = stringBundle->FormatStringFromName(
    4099                 :             error.get(),
    4100               0 :             strs, formatStrCount, getter_Copies(str));
    4101               0 :         NS_ENSURE_SUCCESS(rv, rv);
    4102               0 :         messageStr.Assign(str.get());
    4103                 :     }
    4104                 : 
    4105                 :     // Display the error as a page or an alert prompt
    4106               0 :     NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
    4107               0 :     if (mUseErrorPages) {
    4108                 :         // Display an error page
    4109                 :         LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
    4110               0 :                       messageStr.get(), cssClass.get(), aFailedChannel);
    4111                 :     } 
    4112                 :     else
    4113                 :     {
    4114                 :         // The prompter reqires that our private window has a document (or it
    4115                 :         // asserts). Satisfy that assertion now since GetDocument will force
    4116                 :         // creation of one if it hasn't already been created.
    4117               0 :         nsCOMPtr<nsPIDOMWindow> pwin(do_QueryInterface(mScriptGlobal));
    4118               0 :         if (pwin) {
    4119               0 :             nsCOMPtr<nsIDOMDocument> doc;
    4120               0 :             pwin->GetDocument(getter_AddRefs(doc));
    4121                 :         }
    4122                 : 
    4123                 :         // Display a message box
    4124               0 :         prompter->Alert(nsnull, messageStr.get());
    4125                 :     }
    4126                 : 
    4127               0 :     return NS_OK;
    4128                 : }
    4129                 : 
    4130                 : 
    4131                 : NS_IMETHODIMP
    4132               0 : nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
    4133                 :                           const char *aErrorPage,
    4134                 :                           const PRUnichar *aErrorType,
    4135                 :                           const PRUnichar *aDescription,
    4136                 :                           const char *aCSSClass,
    4137                 :                           nsIChannel* aFailedChannel)
    4138                 : {
    4139                 : #if defined(PR_LOGGING) && defined(DEBUG)
    4140               0 :     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
    4141               0 :         nsCAutoString spec;
    4142               0 :         aURI->GetSpec(spec);
    4143                 : 
    4144               0 :         nsCAutoString chanName;
    4145               0 :         if (aFailedChannel)
    4146               0 :             aFailedChannel->GetName(chanName);
    4147                 :         else
    4148               0 :             chanName.AssignLiteral("<no channel>");
    4149                 : 
    4150               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    4151                 :                ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
    4152                 :                 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
    4153                 :     }
    4154                 : #endif
    4155               0 :     mFailedChannel = aFailedChannel;
    4156               0 :     mFailedURI = aURI;
    4157               0 :     mFailedLoadType = mLoadType;
    4158                 : 
    4159               0 :     if (mLSHE) {
    4160                 :         // Abandon mLSHE's BFCache entry and create a new one.  This way, if
    4161                 :         // we go back or forward to another SHEntry with the same doc
    4162                 :         // identifier, the error page won't persist.
    4163               0 :         mLSHE->AbandonBFCacheEntry();
    4164                 :     }
    4165                 : 
    4166               0 :     nsCAutoString url;
    4167               0 :     nsCAutoString charset;
    4168               0 :     if (aURI)
    4169                 :     {
    4170               0 :         nsresult rv = aURI->GetSpec(url);
    4171               0 :         rv |= aURI->GetOriginCharset(charset);
    4172               0 :         NS_ENSURE_SUCCESS(rv, rv);
    4173                 :     }
    4174               0 :     else if (aURL)
    4175                 :     {
    4176                 :         // We need a URI object to store a session history entry, so make up a URI
    4177               0 :         nsresult rv = NS_NewURI(getter_AddRefs(mFailedURI), "about:blank");
    4178               0 :         NS_ENSURE_SUCCESS(rv, rv);
    4179                 : 
    4180               0 :         CopyUTF16toUTF8(aURL, url);
    4181                 :     }
    4182                 :     else
    4183                 :     {
    4184               0 :         return NS_ERROR_INVALID_POINTER;
    4185                 :     }
    4186                 : 
    4187                 :     // Create a URL to pass all the error information through to the page.
    4188                 : 
    4189                 : #undef SAFE_ESCAPE
    4190                 : #define SAFE_ESCAPE(cstring, escArg1, escArg2)  \
    4191                 :     {                                           \
    4192                 :         char* s = nsEscape(escArg1, escArg2);   \
    4193                 :         if (!s)                                 \
    4194                 :             return NS_ERROR_OUT_OF_MEMORY;      \
    4195                 :         cstring.Adopt(s);                       \
    4196                 :     }
    4197               0 :     nsCString escapedUrl, escapedCharset, escapedError, escapedDescription,
    4198               0 :               escapedCSSClass;
    4199               0 :     SAFE_ESCAPE(escapedUrl, url.get(), url_Path);
    4200               0 :     SAFE_ESCAPE(escapedCharset, charset.get(), url_Path);
    4201               0 :     SAFE_ESCAPE(escapedError,
    4202                 :                 NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
    4203               0 :     SAFE_ESCAPE(escapedDescription,
    4204                 :                 NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
    4205               0 :     if (aCSSClass) {
    4206               0 :         SAFE_ESCAPE(escapedCSSClass, aCSSClass, url_Path);
    4207                 :     }
    4208               0 :     nsCString errorPageUrl("about:");
    4209               0 :     errorPageUrl.AppendASCII(aErrorPage);
    4210               0 :     errorPageUrl.AppendLiteral("?e=");
    4211                 : 
    4212               0 :     errorPageUrl.AppendASCII(escapedError.get());
    4213               0 :     errorPageUrl.AppendLiteral("&u=");
    4214               0 :     errorPageUrl.AppendASCII(escapedUrl.get());
    4215               0 :     if (!escapedCSSClass.IsEmpty()) {
    4216               0 :         errorPageUrl.AppendASCII("&s=");
    4217               0 :         errorPageUrl.AppendASCII(escapedCSSClass.get());
    4218                 :     }
    4219               0 :     errorPageUrl.AppendLiteral("&c=");
    4220               0 :     errorPageUrl.AppendASCII(escapedCharset.get());
    4221               0 :     errorPageUrl.AppendLiteral("&d=");
    4222               0 :     errorPageUrl.AppendASCII(escapedDescription.get());
    4223                 : 
    4224               0 :     nsCOMPtr<nsIURI> errorPageURI;
    4225               0 :     nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
    4226               0 :     NS_ENSURE_SUCCESS(rv, rv);
    4227                 : 
    4228                 :     return InternalLoad(errorPageURI, nsnull, nsnull,
    4229                 :                         INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nsnull, nsnull,
    4230                 :                         nsnull, nsnull, LOAD_ERROR_PAGE,
    4231               0 :                         nsnull, true, nsnull, nsnull);
    4232                 : }
    4233                 : 
    4234                 : 
    4235                 : NS_IMETHODIMP
    4236               0 : nsDocShell::Reload(PRUint32 aReloadFlags)
    4237                 : {
    4238               0 :     if (!IsNavigationAllowed()) {
    4239               0 :       return NS_OK; // JS may not handle returning of an error code
    4240                 :     }
    4241                 :     nsresult rv;
    4242               0 :     NS_ASSERTION(((aReloadFlags & 0xf) == 0),
    4243                 :                  "Reload command not updated to use load flags!");
    4244               0 :     NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
    4245                 :                  "Don't pass these flags to Reload");
    4246                 : 
    4247               0 :     PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
    4248               0 :     NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
    4249                 : 
    4250                 :     // Send notifications to the HistoryListener if any, about the impending reload
    4251               0 :     nsCOMPtr<nsISHistory> rootSH;
    4252               0 :     rv = GetRootSessionHistory(getter_AddRefs(rootSH));
    4253               0 :     nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
    4254               0 :     bool canReload = true; 
    4255               0 :     if (rootSH) {
    4256               0 :       nsCOMPtr<nsISHistoryListener> listener;
    4257               0 :       shistInt->GetListener(getter_AddRefs(listener));
    4258               0 :       if (listener) {
    4259               0 :         listener->OnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
    4260                 :       }
    4261                 :     }
    4262                 : 
    4263               0 :     if (!canReload)
    4264               0 :       return NS_OK;
    4265                 :     
    4266                 :     /* If you change this part of code, make sure bug 45297 does not re-occur */
    4267               0 :     if (mOSHE) {
    4268               0 :         rv = LoadHistoryEntry(mOSHE, loadType);
    4269                 :     }
    4270               0 :     else if (mLSHE) { // In case a reload happened before the current load is done
    4271               0 :         rv = LoadHistoryEntry(mLSHE, loadType);
    4272                 :     }
    4273                 :     else {
    4274               0 :         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
    4275                 : 
    4276               0 :         nsIPrincipal* principal = nsnull;
    4277               0 :         nsAutoString contentTypeHint;
    4278               0 :         if (doc) {
    4279               0 :             principal = doc->NodePrincipal();
    4280               0 :             doc->GetContentType(contentTypeHint);
    4281                 :         }
    4282                 : 
    4283                 :         rv = InternalLoad(mCurrentURI,
    4284                 :                           mReferrerURI,
    4285                 :                           principal,
    4286                 :                           INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document
    4287                 :                           nsnull,         // No window target
    4288               0 :                           NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
    4289                 :                           nsnull,         // No post data
    4290                 :                           nsnull,         // No headers data
    4291                 :                           loadType,       // Load type
    4292                 :                           nsnull,         // No SHEntry
    4293                 :                           true,
    4294                 :                           nsnull,         // No nsIDocShell
    4295               0 :                           nsnull);        // No nsIRequest
    4296                 :     }
    4297                 :     
    4298                 : 
    4299               0 :     return rv;
    4300                 : }
    4301                 : 
    4302                 : NS_IMETHODIMP
    4303               0 : nsDocShell::Stop(PRUint32 aStopFlags)
    4304                 : {
    4305                 :     // Revoke any pending event related to content viewer restoration
    4306               0 :     mRestorePresentationEvent.Revoke();
    4307                 : 
    4308               0 :     if (mLoadType == LOAD_ERROR_PAGE) {
    4309               0 :         if (mLSHE) {
    4310                 :             // Since error page loads never unset mLSHE, do so now
    4311               0 :             SetHistoryEntry(&mOSHE, mLSHE);
    4312               0 :             SetHistoryEntry(&mLSHE, nsnull);
    4313                 :         }
    4314                 : 
    4315               0 :         mFailedChannel = nsnull;
    4316               0 :         mFailedURI = nsnull;
    4317                 :     }
    4318                 : 
    4319               0 :     if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
    4320                 :         // Stop the document loading
    4321               0 :         if (mContentViewer)
    4322               0 :             mContentViewer->Stop();
    4323                 :     }
    4324                 : 
    4325               0 :     if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
    4326                 :         // Suspend any timers that were set for this loader.  We'll clear
    4327                 :         // them out for good in CreateContentViewer.
    4328               0 :         if (mRefreshURIList) {
    4329               0 :             SuspendRefreshURIs();
    4330               0 :             mSavedRefreshURIList.swap(mRefreshURIList);
    4331               0 :             mRefreshURIList = nsnull;
    4332                 :         }
    4333                 : 
    4334                 :         // XXXbz We could also pass |this| to nsIURILoader::Stop.  That will
    4335                 :         // just call Stop() on us as an nsIDocumentLoader... We need fewer
    4336                 :         // redundant apis!
    4337               0 :         Stop();
    4338                 :     }
    4339                 : 
    4340                 :     PRInt32 n;
    4341               0 :     PRInt32 count = mChildList.Count();
    4342               0 :     for (n = 0; n < count; n++) {
    4343               0 :         nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryInterface(ChildAt(n)));
    4344               0 :         if (shellAsNav)
    4345               0 :             shellAsNav->Stop(aStopFlags);
    4346                 :     }
    4347                 : 
    4348               0 :     return NS_OK;
    4349                 : }
    4350                 : 
    4351                 : NS_IMETHODIMP
    4352               0 : nsDocShell::GetDocument(nsIDOMDocument ** aDocument)
    4353                 : {
    4354               0 :     NS_ENSURE_ARG_POINTER(aDocument);
    4355               0 :     NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
    4356                 : 
    4357               0 :     return mContentViewer->GetDOMDocument(aDocument);
    4358                 : }
    4359                 : 
    4360                 : NS_IMETHODIMP
    4361               0 : nsDocShell::GetCurrentURI(nsIURI ** aURI)
    4362                 : {
    4363               0 :     NS_ENSURE_ARG_POINTER(aURI);
    4364                 : 
    4365               0 :     if (mCurrentURI) {
    4366               0 :         return NS_EnsureSafeToReturn(mCurrentURI, aURI);
    4367                 :     }
    4368                 : 
    4369               0 :     *aURI = nsnull;
    4370               0 :     return NS_OK;
    4371                 : }
    4372                 : 
    4373                 : NS_IMETHODIMP
    4374               0 : nsDocShell::GetReferringURI(nsIURI ** aURI)
    4375                 : {
    4376               0 :     NS_ENSURE_ARG_POINTER(aURI);
    4377                 : 
    4378               0 :     *aURI = mReferrerURI;
    4379               0 :     NS_IF_ADDREF(*aURI);
    4380                 : 
    4381               0 :     return NS_OK;
    4382                 : }
    4383                 : 
    4384                 : NS_IMETHODIMP
    4385               0 : nsDocShell::SetSessionHistory(nsISHistory * aSessionHistory)
    4386                 : {
    4387                 : 
    4388               0 :     NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
    4389                 :     // make sure that we are the root docshell and
    4390                 :     // set a handle to root docshell in SH.
    4391                 : 
    4392               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
    4393                 :     /* Get the root docshell. If *this* is the root docshell
    4394                 :      * then save a handle to *this* in SH. SH needs it to do
    4395                 :      * traversions thro' its entries
    4396                 :      */
    4397               0 :     GetSameTypeRootTreeItem(getter_AddRefs(root));
    4398               0 :     NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
    4399               0 :     if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) {
    4400               0 :         mSessionHistory = aSessionHistory;
    4401                 :         nsCOMPtr<nsISHistoryInternal>
    4402               0 :             shPrivate(do_QueryInterface(mSessionHistory));
    4403               0 :         NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
    4404               0 :         shPrivate->SetRootDocShell(this);
    4405               0 :         return NS_OK;
    4406                 :     }
    4407               0 :     return NS_ERROR_FAILURE;
    4408                 : 
    4409                 : }
    4410                 : 
    4411                 : 
    4412                 : NS_IMETHODIMP
    4413               0 : nsDocShell::GetSessionHistory(nsISHistory ** aSessionHistory)
    4414                 : {
    4415               0 :     NS_ENSURE_ARG_POINTER(aSessionHistory);
    4416               0 :     *aSessionHistory = mSessionHistory;
    4417               0 :     NS_IF_ADDREF(*aSessionHistory);
    4418               0 :     return NS_OK;
    4419                 : }
    4420                 : 
    4421                 : //*****************************************************************************
    4422                 : // nsDocShell::nsIWebPageDescriptor
    4423                 : //*****************************************************************************
    4424                 : NS_IMETHODIMP
    4425               0 : nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType)
    4426                 : {
    4427               0 :     nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
    4428                 : 
    4429                 :     // Currently, the opaque 'page descriptor' is an nsISHEntry...
    4430               0 :     if (!shEntryIn) {
    4431               0 :         return NS_ERROR_INVALID_POINTER;
    4432                 :     }
    4433                 : 
    4434                 :     // Now clone shEntryIn, since we might end up modifying it later on, and we
    4435                 :     // want a page descriptor to be reusable.
    4436               0 :     nsCOMPtr<nsISHEntry> shEntry;
    4437               0 :     nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
    4438               0 :     NS_ENSURE_SUCCESS(rv, rv);
    4439                 : 
    4440                 :     // Give our cloned shEntry a new bfcache entry so this load is independent
    4441                 :     // of all other loads.  (This is important, in particular, for bugs 582795
    4442                 :     // and 585298.)
    4443               0 :     rv = shEntry->AbandonBFCacheEntry();
    4444               0 :     NS_ENSURE_SUCCESS(rv, rv);
    4445                 : 
    4446                 :     //
    4447                 :     // load the page as view-source
    4448                 :     //
    4449               0 :     if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
    4450               0 :         nsCOMPtr<nsIURI> oldUri, newUri;
    4451               0 :         nsCString spec, newSpec;
    4452                 : 
    4453                 :         // Create a new view-source URI and replace the original.
    4454               0 :         rv = shEntry->GetURI(getter_AddRefs(oldUri));
    4455               0 :         if (NS_FAILED(rv))
    4456               0 :               return rv;
    4457                 : 
    4458               0 :         oldUri->GetSpec(spec);
    4459               0 :         newSpec.AppendLiteral("view-source:");
    4460               0 :         newSpec.Append(spec);
    4461                 : 
    4462               0 :         rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
    4463               0 :         if (NS_FAILED(rv)) {
    4464               0 :             return rv;
    4465                 :         }
    4466               0 :         shEntry->SetURI(newUri);
    4467                 :     }
    4468                 : 
    4469               0 :     rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
    4470               0 :     return rv;
    4471                 : }
    4472                 : 
    4473                 : NS_IMETHODIMP
    4474               0 : nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor)
    4475                 : {
    4476               0 :     NS_PRECONDITION(aPageDescriptor, "Null out param?");
    4477                 : 
    4478               0 :     *aPageDescriptor = nsnull;
    4479                 : 
    4480               0 :     nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
    4481               0 :     if (src) {
    4482               0 :         nsCOMPtr<nsISHEntry> dest;
    4483                 : 
    4484               0 :         nsresult rv = src->Clone(getter_AddRefs(dest));
    4485               0 :         if (NS_FAILED(rv)) {
    4486               0 :             return rv;
    4487                 :         }
    4488                 : 
    4489                 :         // null out inappropriate cloned attributes...
    4490               0 :         dest->SetParent(nsnull);
    4491               0 :         dest->SetIsSubFrame(false);
    4492                 :         
    4493               0 :         return CallQueryInterface(dest, aPageDescriptor);
    4494                 :     }
    4495                 : 
    4496               0 :     return NS_ERROR_NOT_AVAILABLE;
    4497                 : }
    4498                 : 
    4499                 : 
    4500                 : //*****************************************************************************
    4501                 : // nsDocShell::nsIBaseWindow
    4502                 : //*****************************************************************************   
    4503                 : 
    4504                 : NS_IMETHODIMP
    4505               0 : nsDocShell::InitWindow(nativeWindow parentNativeWindow,
    4506                 :                        nsIWidget * parentWidget, PRInt32 x, PRInt32 y,
    4507                 :                        PRInt32 cx, PRInt32 cy)
    4508                 : {
    4509               0 :     SetParentWidget(parentWidget);
    4510               0 :     SetPositionAndSize(x, y, cx, cy, false);
    4511                 : 
    4512               0 :     return NS_OK;
    4513                 : }
    4514                 : 
    4515                 : NS_IMETHODIMP
    4516               0 : nsDocShell::Create()
    4517                 : {
    4518               0 :     if (mCreated) {
    4519                 :         // We've already been created
    4520               0 :         return NS_OK;
    4521                 :     }
    4522                 : 
    4523               0 :     NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
    4524                 :                  "Unexpected item type in docshell");
    4525                 : 
    4526               0 :     NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
    4527               0 :     mCreated = true;
    4528                 : 
    4529                 :     mAllowSubframes =
    4530               0 :         Preferences::GetBool("browser.frames.enabled", mAllowSubframes);
    4531                 : 
    4532               0 :     if (gValidateOrigin == 0xffffffff) {
    4533                 :         // Check pref to see if we should prevent frameset spoofing
    4534                 :         gValidateOrigin =
    4535               0 :             Preferences::GetBool("browser.frame.validate_origin", true);
    4536                 :     }
    4537                 : 
    4538                 :     // Should we use XUL error pages instead of alerts if possible?
    4539                 :     mUseErrorPages =
    4540               0 :         Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
    4541                 : 
    4542               0 :     if (mObserveErrorPages) {
    4543               0 :         Preferences::AddStrongObserver(this, "browser.xul.error_pages.enabled");
    4544                 :     }
    4545                 : 
    4546               0 :     nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
    4547               0 :     if (serv) {
    4548                 :         const char* msg = mItemType == typeContent ?
    4549               0 :             NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
    4550               0 :         serv->NotifyObservers(GetAsSupports(this), msg, nsnull);
    4551                 :     }
    4552                 : 
    4553               0 :     return NS_OK;
    4554                 : }
    4555                 : 
    4556                 : NS_IMETHODIMP
    4557               0 : nsDocShell::Destroy()
    4558                 : {
    4559               0 :     NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
    4560                 :                  "Unexpected item type in docshell");
    4561                 : 
    4562               0 :     if (!mIsBeingDestroyed) {
    4563               0 :         nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
    4564               0 :         if (serv) {
    4565                 :             const char* msg = mItemType == typeContent ?
    4566               0 :                 NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
    4567               0 :             serv->NotifyObservers(GetAsSupports(this), msg, nsnull);
    4568                 :         }
    4569                 :     }
    4570                 :     
    4571               0 :     mIsBeingDestroyed = true;
    4572                 : 
    4573                 :     // Remove our pref observers
    4574               0 :     if (mObserveErrorPages) {
    4575               0 :         Preferences::RemoveObserver(this, "browser.xul.error_pages.enabled");
    4576               0 :         mObserveErrorPages = false;
    4577                 :     }
    4578                 : 
    4579                 :     // Make sure to blow away our mLoadingURI just in case.  No loads
    4580                 :     // from inside this pagehide.
    4581               0 :     mLoadingURI = nsnull;
    4582                 : 
    4583                 :     // Fire unload event before we blow anything away.
    4584               0 :     (void) FirePageHideNotification(true);
    4585                 : 
    4586                 :     // Clear pointers to any detached nsEditorData that's lying
    4587                 :     // around in shistory entries. Breaks cycle. See bug 430921.
    4588               0 :     if (mOSHE)
    4589               0 :       mOSHE->SetEditorData(nsnull);
    4590               0 :     if (mLSHE)
    4591               0 :       mLSHE->SetEditorData(nsnull);
    4592                 :       
    4593                 :     // Note: mContentListener can be null if Init() failed and we're being
    4594                 :     // called from the destructor.
    4595               0 :     if (mContentListener) {
    4596               0 :         mContentListener->DropDocShellreference();
    4597               0 :         mContentListener->SetParentContentListener(nsnull);
    4598                 :         // Note that we do NOT set mContentListener to null here; that
    4599                 :         // way if someone tries to do a load in us after this point
    4600                 :         // the nsDSURIContentListener will block it.  All of which
    4601                 :         // means that we should do this before calling Stop(), of
    4602                 :         // course.
    4603                 :     }
    4604                 : 
    4605                 :     // Stop any URLs that are currently being loaded...
    4606               0 :     Stop(nsIWebNavigation::STOP_ALL);
    4607                 : 
    4608               0 :     mEditorData = nsnull;
    4609                 : 
    4610               0 :     mTransferableHookData = nsnull;
    4611                 : 
    4612                 :     // Save the state of the current document, before destroying the window.
    4613                 :     // This is needed to capture the state of a frameset when the new document
    4614                 :     // causes the frameset to be destroyed...
    4615               0 :     PersistLayoutHistoryState();
    4616                 : 
    4617                 :     // Remove this docshell from its parent's child list
    4618                 :     nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
    4619               0 :         do_QueryInterface(GetAsSupports(mParent));
    4620               0 :     if (docShellParentAsItem)
    4621               0 :         docShellParentAsItem->RemoveChild(this);
    4622                 : 
    4623               0 :     if (mContentViewer) {
    4624               0 :         mContentViewer->Close(nsnull);
    4625               0 :         mContentViewer->Destroy();
    4626               0 :         mContentViewer = nsnull;
    4627                 :     }
    4628                 : 
    4629               0 :     nsDocLoader::Destroy();
    4630                 :     
    4631               0 :     mParentWidget = nsnull;
    4632               0 :     mCurrentURI = nsnull;
    4633                 : 
    4634               0 :     if (mScriptGlobal) {
    4635               0 :         nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
    4636               0 :         win->SetDocShell(nsnull);
    4637                 : 
    4638               0 :         mScriptGlobal = nsnull;
    4639                 :     }
    4640                 : 
    4641               0 :     if (mSessionHistory) {
    4642                 :         // We want to destroy these content viewers now rather than
    4643                 :         // letting their destruction wait for the session history
    4644                 :         // entries to get garbage collected.  (Bug 488394)
    4645                 :         nsCOMPtr<nsISHistoryInternal> shPrivate =
    4646               0 :             do_QueryInterface(mSessionHistory);
    4647               0 :         if (shPrivate) {
    4648               0 :             shPrivate->EvictAllContentViewers();
    4649                 :         }
    4650               0 :         mSessionHistory = nsnull;
    4651                 :     }
    4652                 : 
    4653               0 :     SetTreeOwner(nsnull);
    4654                 : 
    4655                 :     // required to break ref cycle
    4656               0 :     mSecurityUI = nsnull;
    4657                 : 
    4658                 :     // Cancel any timers that were set for this docshell; this is needed
    4659                 :     // to break the cycle between us and the timers.
    4660               0 :     CancelRefreshURITimers();
    4661               0 :     return NS_OK;
    4662                 : }
    4663                 : 
    4664                 : NS_IMETHODIMP
    4665               0 : nsDocShell::SetPosition(PRInt32 x, PRInt32 y)
    4666                 : {
    4667               0 :     mBounds.x = x;
    4668               0 :     mBounds.y = y;
    4669                 : 
    4670               0 :     if (mContentViewer)
    4671               0 :         NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE);
    4672                 : 
    4673               0 :     return NS_OK;
    4674                 : }
    4675                 : 
    4676                 : NS_IMETHODIMP
    4677               0 : nsDocShell::GetPosition(PRInt32 * aX, PRInt32 * aY)
    4678                 : {
    4679                 :     PRInt32 dummyHolder;
    4680               0 :     return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder);
    4681                 : }
    4682                 : 
    4683                 : NS_IMETHODIMP
    4684               0 : nsDocShell::SetSize(PRInt32 aCX, PRInt32 aCY, bool aRepaint)
    4685                 : {
    4686               0 :     PRInt32 x = 0, y = 0;
    4687               0 :     GetPosition(&x, &y);
    4688               0 :     return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
    4689                 : }
    4690                 : 
    4691                 : NS_IMETHODIMP
    4692               0 : nsDocShell::GetSize(PRInt32 * aCX, PRInt32 * aCY)
    4693                 : {
    4694                 :     PRInt32 dummyHolder;
    4695               0 :     return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY);
    4696                 : }
    4697                 : 
    4698                 : NS_IMETHODIMP
    4699               0 : nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
    4700                 :                                PRInt32 cy, bool fRepaint)
    4701                 : {
    4702               0 :     mBounds.x = x;
    4703               0 :     mBounds.y = y;
    4704               0 :     mBounds.width = cx;
    4705               0 :     mBounds.height = cy;
    4706                 : 
    4707                 :     // Hold strong ref, since SetBounds can make us null out mContentViewer
    4708               0 :     nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
    4709               0 :     if (viewer) {
    4710                 :         //XXX Border figured in here or is that handled elsewhere?
    4711               0 :         NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE);
    4712                 :     }
    4713                 : 
    4714               0 :     return NS_OK;
    4715                 : }
    4716                 : 
    4717                 : NS_IMETHODIMP
    4718               0 : nsDocShell::GetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
    4719                 :                                PRInt32 * cy)
    4720                 : {
    4721                 :     // We should really consider just getting this information from
    4722                 :     // our window instead of duplicating the storage and code...
    4723               0 :     if (cx || cy) {
    4724                 :         // Caller wants to know our size; make sure to give them up to
    4725                 :         // date information.
    4726               0 :         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
    4727               0 :         if (doc) {
    4728               0 :             doc->FlushPendingNotifications(Flush_Layout);
    4729                 :         }
    4730                 :     }
    4731                 :     
    4732               0 :     DoGetPositionAndSize(x, y, cx, cy);
    4733               0 :     return NS_OK;
    4734                 : }
    4735                 : 
    4736                 : void
    4737               0 : nsDocShell::DoGetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
    4738                 :                                  PRInt32 * cy)
    4739                 : {    
    4740               0 :     if (x)
    4741               0 :         *x = mBounds.x;
    4742               0 :     if (y)
    4743               0 :         *y = mBounds.y;
    4744               0 :     if (cx)
    4745               0 :         *cx = mBounds.width;
    4746               0 :     if (cy)
    4747               0 :         *cy = mBounds.height;
    4748               0 : }
    4749                 : 
    4750                 : NS_IMETHODIMP
    4751               0 : nsDocShell::Repaint(bool aForce)
    4752                 : {
    4753               0 :     nsCOMPtr<nsIPresShell> presShell;
    4754               0 :     GetPresShell(getter_AddRefs(presShell));
    4755               0 :     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
    4756                 : 
    4757               0 :     nsIViewManager* viewManager = presShell->GetViewManager();
    4758               0 :     NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
    4759                 : 
    4760               0 :     NS_ENSURE_SUCCESS(viewManager->InvalidateAllViews(), NS_ERROR_FAILURE);
    4761               0 :     return NS_OK;
    4762                 : }
    4763                 : 
    4764                 : NS_IMETHODIMP
    4765               0 : nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
    4766                 : {
    4767               0 :     NS_ENSURE_ARG_POINTER(parentWidget);
    4768                 : 
    4769               0 :     *parentWidget = mParentWidget;
    4770               0 :     NS_IF_ADDREF(*parentWidget);
    4771                 : 
    4772               0 :     return NS_OK;
    4773                 : }
    4774                 : 
    4775                 : NS_IMETHODIMP
    4776               0 : nsDocShell::SetParentWidget(nsIWidget * aParentWidget)
    4777                 : {
    4778               0 :     mParentWidget = aParentWidget;
    4779                 : 
    4780               0 :     return NS_OK;
    4781                 : }
    4782                 : 
    4783                 : NS_IMETHODIMP
    4784               0 : nsDocShell::GetParentNativeWindow(nativeWindow * parentNativeWindow)
    4785                 : {
    4786               0 :     NS_ENSURE_ARG_POINTER(parentNativeWindow);
    4787                 : 
    4788               0 :     if (mParentWidget)
    4789               0 :         *parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
    4790                 :     else
    4791               0 :         *parentNativeWindow = nsnull;
    4792                 : 
    4793               0 :     return NS_OK;
    4794                 : }
    4795                 : 
    4796                 : NS_IMETHODIMP
    4797               0 : nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
    4798                 : {
    4799               0 :     return NS_ERROR_NOT_IMPLEMENTED;
    4800                 : }
    4801                 : 
    4802                 : NS_IMETHODIMP
    4803               0 : nsDocShell::GetVisibility(bool * aVisibility)
    4804                 : {
    4805               0 :     NS_ENSURE_ARG_POINTER(aVisibility);
    4806                 : 
    4807               0 :     *aVisibility = false;
    4808                 : 
    4809               0 :     if (!mContentViewer)
    4810               0 :         return NS_OK;
    4811                 : 
    4812               0 :     nsCOMPtr<nsIPresShell> presShell;
    4813               0 :     GetPresShell(getter_AddRefs(presShell));
    4814               0 :     if (!presShell)
    4815               0 :         return NS_OK;
    4816                 : 
    4817                 :     // get the view manager
    4818               0 :     nsIViewManager* vm = presShell->GetViewManager();
    4819               0 :     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
    4820                 : 
    4821                 :     // get the root view
    4822               0 :     nsIView *view = vm->GetRootView(); // views are not ref counted
    4823               0 :     NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
    4824                 : 
    4825                 :     // if our root view is hidden, we are not visible
    4826               0 :     if (view->GetVisibility() == nsViewVisibility_kHide)
    4827               0 :         return NS_OK;
    4828                 : 
    4829                 :     // otherwise, we must walk up the document and view trees checking
    4830                 :     // for a hidden view, unless we're an off screen browser, which 
    4831                 :     // would make this test meaningless.
    4832                 : 
    4833               0 :     nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
    4834               0 :     nsCOMPtr<nsIDocShellTreeItem> parentItem;
    4835               0 :     treeItem->GetParent(getter_AddRefs(parentItem));
    4836               0 :     while (parentItem) {
    4837               0 :         nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem));
    4838               0 :         docShell->GetPresShell(getter_AddRefs(presShell));
    4839                 : 
    4840               0 :         nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem);
    4841               0 :         nsCOMPtr<nsIPresShell> pPresShell;
    4842               0 :         parentDS->GetPresShell(getter_AddRefs(pPresShell));
    4843                 : 
    4844                 :         // Null-check for crash in bug 267804
    4845               0 :         if (!pPresShell) {
    4846               0 :             NS_NOTREACHED("parent docshell has null pres shell");
    4847               0 :             return NS_OK;
    4848                 :         }
    4849                 : 
    4850                 :         nsIContent *shellContent =
    4851               0 :             pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument());
    4852               0 :         NS_ASSERTION(shellContent, "subshell not in the map");
    4853                 : 
    4854               0 :         nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nsnull;
    4855               0 :         bool isDocShellOffScreen = false;
    4856               0 :         docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
    4857               0 :         if (frame &&
    4858               0 :             !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
    4859               0 :             !isDocShellOffScreen) {
    4860               0 :             return NS_OK;
    4861                 :         }
    4862                 : 
    4863               0 :         treeItem = parentItem;
    4864               0 :         treeItem->GetParent(getter_AddRefs(parentItem));
    4865                 :     }
    4866                 : 
    4867               0 :     nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
    4868               0 :     if (!treeOwnerAsWin) {
    4869               0 :         *aVisibility = true;
    4870               0 :         return NS_OK;
    4871                 :     }
    4872                 : 
    4873                 :     // Check with the tree owner as well to give embedders a chance to
    4874                 :     // expose visibility as well.
    4875               0 :     return treeOwnerAsWin->GetVisibility(aVisibility);
    4876                 : }
    4877                 : 
    4878                 : NS_IMETHODIMP
    4879               0 : nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen) 
    4880                 : {
    4881               0 :     mIsOffScreenBrowser = aIsOffScreen;
    4882               0 :     return NS_OK;
    4883                 : }
    4884                 : 
    4885                 : NS_IMETHODIMP
    4886               0 : nsDocShell::GetIsOffScreenBrowser(bool *aIsOffScreen) 
    4887                 : {
    4888               0 :     *aIsOffScreen = mIsOffScreenBrowser;
    4889               0 :     return NS_OK;
    4890                 : }
    4891                 : 
    4892                 : NS_IMETHODIMP
    4893               0 : nsDocShell::SetIsActive(bool aIsActive)
    4894                 : {
    4895                 :   // We disallow setting active on chrome docshells.
    4896               0 :   if (mItemType == nsIDocShellTreeItem::typeChrome)
    4897               0 :     return NS_ERROR_INVALID_ARG;
    4898                 : 
    4899                 :   // Keep track ourselves.
    4900               0 :   mIsActive = aIsActive;
    4901                 : 
    4902                 :   // Tell the PresShell about it.
    4903               0 :   nsCOMPtr<nsIPresShell> pshell;
    4904               0 :   GetPresShell(getter_AddRefs(pshell));
    4905               0 :   if (pshell)
    4906               0 :     pshell->SetIsActive(aIsActive);
    4907                 : 
    4908                 :   // Tell the window about it
    4909               0 :   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mScriptGlobal);
    4910               0 :   if (win) {
    4911               0 :       win->SetIsBackground(!aIsActive);
    4912               0 :       nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
    4913               0 :       if (doc) {
    4914               0 :           doc->PostVisibilityUpdateEvent();
    4915                 :       }
    4916                 :   }
    4917                 : 
    4918                 :   // Recursively tell all of our children
    4919               0 :   PRInt32 n = mChildList.Count();
    4920               0 :   for (PRInt32 i = 0; i < n; ++i) {
    4921               0 :       nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(ChildAt(i));
    4922               0 :       if (docshell)
    4923               0 :         docshell->SetIsActive(aIsActive);
    4924                 :   }
    4925                 : 
    4926               0 :   return NS_OK;
    4927                 : }
    4928                 : 
    4929                 : NS_IMETHODIMP
    4930               0 : nsDocShell::GetIsActive(bool *aIsActive)
    4931                 : {
    4932               0 :   *aIsActive = mIsActive;
    4933               0 :   return NS_OK;
    4934                 : }
    4935                 : 
    4936                 : NS_IMETHODIMP
    4937               0 : nsDocShell::SetIsAppTab(bool aIsAppTab)
    4938                 : {
    4939               0 :   mIsAppTab = aIsAppTab;
    4940               0 :   return NS_OK;
    4941                 : }
    4942                 : 
    4943                 : NS_IMETHODIMP
    4944               0 : nsDocShell::GetIsAppTab(bool *aIsAppTab)
    4945                 : {
    4946               0 :   *aIsAppTab = mIsAppTab;
    4947               0 :   return NS_OK;
    4948                 : }
    4949                 : 
    4950                 : NS_IMETHODIMP
    4951               0 : nsDocShell::SetVisibility(bool aVisibility)
    4952                 : {
    4953               0 :     if (!mContentViewer)
    4954               0 :         return NS_OK;
    4955               0 :     if (aVisibility) {
    4956               0 :         mContentViewer->Show();
    4957                 :     }
    4958                 :     else {
    4959               0 :         mContentViewer->Hide();
    4960                 :     }
    4961                 :     
    4962               0 :     return NS_OK;
    4963                 : }
    4964                 : 
    4965                 : NS_IMETHODIMP
    4966               0 : nsDocShell::GetEnabled(bool *aEnabled)
    4967                 : {
    4968               0 :   NS_ENSURE_ARG_POINTER(aEnabled);
    4969               0 :   *aEnabled = true;
    4970               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4971                 : }
    4972                 : 
    4973                 : NS_IMETHODIMP
    4974               0 : nsDocShell::SetEnabled(bool aEnabled)
    4975                 : {
    4976               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4977                 : }
    4978                 : 
    4979                 : NS_IMETHODIMP
    4980               0 : nsDocShell::SetFocus()
    4981                 : {
    4982               0 :   return NS_OK;
    4983                 : }
    4984                 : 
    4985                 : NS_IMETHODIMP
    4986               0 : nsDocShell::GetMainWidget(nsIWidget ** aMainWidget)
    4987                 : {
    4988                 :     // We don't create our own widget, so simply return the parent one. 
    4989               0 :     return GetParentWidget(aMainWidget);
    4990                 : }
    4991                 : 
    4992                 : NS_IMETHODIMP
    4993               0 : nsDocShell::GetTitle(PRUnichar ** aTitle)
    4994                 : {
    4995               0 :     NS_ENSURE_ARG_POINTER(aTitle);
    4996                 : 
    4997               0 :     *aTitle = ToNewUnicode(mTitle);
    4998               0 :     return NS_OK;
    4999                 : }
    5000                 : 
    5001                 : NS_IMETHODIMP
    5002               0 : nsDocShell::SetTitle(const PRUnichar * aTitle)
    5003                 : {
    5004                 :     // Store local title
    5005               0 :     mTitle = aTitle;
    5006                 : 
    5007               0 :     nsCOMPtr<nsIDocShellTreeItem> parent;
    5008               0 :     GetSameTypeParent(getter_AddRefs(parent));
    5009                 : 
    5010                 :     // When title is set on the top object it should then be passed to the 
    5011                 :     // tree owner.
    5012               0 :     if (!parent) {
    5013                 :         nsCOMPtr<nsIBaseWindow>
    5014               0 :             treeOwnerAsWin(do_QueryInterface(mTreeOwner));
    5015               0 :         if (treeOwnerAsWin)
    5016               0 :             treeOwnerAsWin->SetTitle(aTitle);
    5017                 :     }
    5018                 : 
    5019               0 :     if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE && mUseGlobalHistory) {
    5020               0 :         nsCOMPtr<IHistory> history = services::GetHistoryService();
    5021               0 :         if (history) {
    5022               0 :             history->SetURITitle(mCurrentURI, mTitle);
    5023                 :         }
    5024               0 :         else if (mGlobalHistory) {
    5025               0 :             mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
    5026                 :         }
    5027                 :     }
    5028                 : 
    5029                 :     // Update SessionHistory with the document's title.
    5030               0 :     if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
    5031                 :         mLoadType != LOAD_ERROR_PAGE) {
    5032                 : 
    5033               0 :         mOSHE->SetTitle(mTitle);    
    5034                 :     }
    5035                 : 
    5036               0 :     return NS_OK;
    5037                 : }
    5038                 : 
    5039                 : //*****************************************************************************
    5040                 : // nsDocShell::nsIScrollable
    5041                 : //*****************************************************************************   
    5042                 : 
    5043                 : NS_IMETHODIMP
    5044               0 : nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation, PRInt32 * curPos)
    5045                 : {
    5046               0 :     NS_ENSURE_ARG_POINTER(curPos);
    5047                 : 
    5048               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5049               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5050                 : 
    5051               0 :     nsPoint pt = sf->GetScrollPosition();
    5052                 : 
    5053               0 :     switch (scrollOrientation) {
    5054                 :     case ScrollOrientation_X:
    5055               0 :         *curPos = pt.x;
    5056               0 :         return NS_OK;
    5057                 : 
    5058                 :     case ScrollOrientation_Y:
    5059               0 :         *curPos = pt.y;
    5060               0 :         return NS_OK;
    5061                 : 
    5062                 :     default:
    5063               0 :         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
    5064                 :     }
    5065                 : }
    5066                 : 
    5067                 : NS_IMETHODIMP
    5068               0 : nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation, PRInt32 curPos)
    5069                 : {
    5070               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5071               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5072                 : 
    5073               0 :     nsPoint pt = sf->GetScrollPosition();
    5074                 : 
    5075               0 :     switch (scrollOrientation) {
    5076                 :     case ScrollOrientation_X:
    5077               0 :         pt.x = curPos;
    5078               0 :         break;
    5079                 : 
    5080                 :     case ScrollOrientation_Y:
    5081               0 :         pt.y = curPos;
    5082               0 :         break;
    5083                 : 
    5084                 :     default:
    5085               0 :         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
    5086                 :     }
    5087                 : 
    5088               0 :     sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
    5089               0 :     return NS_OK;
    5090                 : }
    5091                 : 
    5092                 : NS_IMETHODIMP
    5093               0 : nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos, PRInt32 curVerticalPos)
    5094                 : {
    5095               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5096               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5097                 : 
    5098                 :     sf->ScrollTo(nsPoint(curHorizontalPos, curVerticalPos),
    5099               0 :                  nsIScrollableFrame::INSTANT);
    5100               0 :     return NS_OK;
    5101                 : }
    5102                 : 
    5103                 : // XXX This is wrong
    5104                 : NS_IMETHODIMP
    5105               0 : nsDocShell::GetScrollRange(PRInt32 scrollOrientation,
    5106                 :                            PRInt32 * minPos, PRInt32 * maxPos)
    5107                 : {
    5108               0 :     NS_ENSURE_ARG_POINTER(minPos && maxPos);
    5109                 : 
    5110               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5111               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5112                 : 
    5113               0 :     nsSize portSize = sf->GetScrollPortRect().Size();
    5114               0 :     nsRect range = sf->GetScrollRange();
    5115                 : 
    5116               0 :     switch (scrollOrientation) {
    5117                 :     case ScrollOrientation_X:
    5118               0 :         *minPos = range.x;
    5119               0 :         *maxPos = range.XMost() + portSize.width;
    5120               0 :         return NS_OK;
    5121                 : 
    5122                 :     case ScrollOrientation_Y:
    5123               0 :         *minPos = range.y;
    5124               0 :         *maxPos = range.YMost() + portSize.height;
    5125               0 :         return NS_OK;
    5126                 : 
    5127                 :     default:
    5128               0 :         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
    5129                 :     }
    5130                 : }
    5131                 : 
    5132                 : NS_IMETHODIMP
    5133               0 : nsDocShell::SetScrollRange(PRInt32 scrollOrientation,
    5134                 :                            PRInt32 minPos, PRInt32 maxPos)
    5135                 : {
    5136                 :     //XXX First Check
    5137                 :     /*
    5138                 :        Retrieves or Sets the valid ranges for the thumb.  When maxPos is set to 
    5139                 :        something less than the current thumb position, curPos is set = to maxPos.
    5140                 : 
    5141                 :        @return NS_OK - Setting or Getting completed successfully.
    5142                 :        NS_ERROR_INVALID_ARG - returned when curPos is not within the
    5143                 :        minPos and maxPos.
    5144                 :      */
    5145               0 :     return NS_ERROR_FAILURE;
    5146                 : }
    5147                 : 
    5148                 : NS_IMETHODIMP
    5149               0 : nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos,
    5150                 :                              PRInt32 maxHorizontalPos, PRInt32 minVerticalPos,
    5151                 :                              PRInt32 maxVerticalPos)
    5152                 : {
    5153                 :     //XXX First Check
    5154                 :     /*
    5155                 :        Retrieves or Sets the valid ranges for the thumb.  When maxPos is set to 
    5156                 :        something less than the current thumb position, curPos is set = to maxPos.
    5157                 : 
    5158                 :        @return NS_OK - Setting or Getting completed successfully.
    5159                 :        NS_ERROR_INVALID_ARG - returned when curPos is not within the
    5160                 :        minPos and maxPos.
    5161                 :      */
    5162               0 :     return NS_ERROR_FAILURE;
    5163                 : }
    5164                 : 
    5165                 : // This returns setting for all documents in this docshell
    5166                 : NS_IMETHODIMP
    5167               0 : nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
    5168                 :                                            PRInt32 * scrollbarPref)
    5169                 : {
    5170               0 :     NS_ENSURE_ARG_POINTER(scrollbarPref);
    5171               0 :     switch (scrollOrientation) {
    5172                 :     case ScrollOrientation_X:
    5173               0 :         *scrollbarPref = mDefaultScrollbarPref.x;
    5174               0 :         return NS_OK;
    5175                 : 
    5176                 :     case ScrollOrientation_Y:
    5177               0 :         *scrollbarPref = mDefaultScrollbarPref.y;
    5178               0 :         return NS_OK;
    5179                 : 
    5180                 :     default:
    5181               0 :         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
    5182                 :     }
    5183                 :     return NS_ERROR_FAILURE;
    5184                 : }
    5185                 : 
    5186                 : // Set scrolling preference for all documents in this shell
    5187                 : //
    5188                 : // There are three possible values stored in the shell:
    5189                 : //  1) nsIScrollable::Scrollbar_Never = no scrollbar
    5190                 : //  2) nsIScrollable::Scrollbar_Auto = scrollbar appears if the document
    5191                 : //     being displayed would normally have scrollbar
    5192                 : //  3) nsIScrollable::Scrollbar_Always = scrollbar always appears
    5193                 : //
    5194                 : // One important client is nsHTMLFrameInnerFrame::CreateWebShell()
    5195                 : NS_IMETHODIMP
    5196               0 : nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
    5197                 :                                            PRInt32 scrollbarPref)
    5198                 : {
    5199               0 :     switch (scrollOrientation) {
    5200                 :     case ScrollOrientation_X:
    5201               0 :         mDefaultScrollbarPref.x = scrollbarPref;
    5202               0 :         return NS_OK;
    5203                 : 
    5204                 :     case ScrollOrientation_Y:
    5205               0 :         mDefaultScrollbarPref.y = scrollbarPref;
    5206               0 :         return NS_OK;
    5207                 : 
    5208                 :     default:
    5209               0 :         NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
    5210                 :     }
    5211                 :     return NS_ERROR_FAILURE;
    5212                 : }
    5213                 : 
    5214                 : NS_IMETHODIMP
    5215               0 : nsDocShell::GetScrollbarVisibility(bool * verticalVisible,
    5216                 :                                    bool * horizontalVisible)
    5217                 : {
    5218               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5219               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5220                 : 
    5221               0 :     PRUint32 scrollbarVisibility = sf->GetScrollbarVisibility();
    5222               0 :     if (verticalVisible)
    5223               0 :         *verticalVisible = (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
    5224               0 :     if (horizontalVisible)
    5225               0 :         *horizontalVisible = (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
    5226                 : 
    5227               0 :     return NS_OK;
    5228                 : }
    5229                 : 
    5230                 : //*****************************************************************************
    5231                 : // nsDocShell::nsITextScroll
    5232                 : //*****************************************************************************   
    5233                 : 
    5234                 : NS_IMETHODIMP
    5235               0 : nsDocShell::ScrollByLines(PRInt32 numLines)
    5236                 : {
    5237               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5238               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5239                 : 
    5240                 :     sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
    5241               0 :                  nsIScrollableFrame::SMOOTH);
    5242               0 :     return NS_OK;
    5243                 : }
    5244                 : 
    5245                 : NS_IMETHODIMP
    5246               0 : nsDocShell::ScrollByPages(PRInt32 numPages)
    5247                 : {
    5248               0 :     nsIScrollableFrame* sf = GetRootScrollFrame();
    5249               0 :     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
    5250                 : 
    5251                 :     sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
    5252               0 :                  nsIScrollableFrame::SMOOTH);
    5253               0 :     return NS_OK;
    5254                 : }
    5255                 : 
    5256                 : //*****************************************************************************
    5257                 : // nsDocShell::nsIScriptGlobalObjectOwner
    5258                 : //*****************************************************************************   
    5259                 : 
    5260                 : nsIScriptGlobalObject*
    5261               0 : nsDocShell::GetScriptGlobalObject()
    5262                 : {
    5263               0 :     NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nsnull);
    5264                 : 
    5265               0 :     return mScriptGlobal;
    5266                 : }
    5267                 : 
    5268                 : //*****************************************************************************
    5269                 : // nsDocShell::nsIRefreshURI
    5270                 : //*****************************************************************************   
    5271                 : 
    5272                 : NS_IMETHODIMP
    5273               0 : nsDocShell::RefreshURI(nsIURI * aURI, PRInt32 aDelay, bool aRepeat,
    5274                 :                        bool aMetaRefresh)
    5275                 : {
    5276               0 :     NS_ENSURE_ARG(aURI);
    5277                 : 
    5278                 :     /* Check if Meta refresh/redirects are permitted. Some
    5279                 :      * embedded applications may not want to do this.
    5280                 :      * Must do this before sending out NOTIFY_REFRESH events
    5281                 :      * because listeners may have side effects (e.g. displaying a
    5282                 :      * button to manually trigger the refresh later).
    5283                 :      */
    5284               0 :     bool allowRedirects = true;
    5285               0 :     GetAllowMetaRedirects(&allowRedirects);
    5286               0 :     if (!allowRedirects)
    5287               0 :         return NS_OK;
    5288                 : 
    5289                 :     // If any web progress listeners are listening for NOTIFY_REFRESH events,
    5290                 :     // give them a chance to block this refresh.
    5291                 :     bool sameURI;
    5292               0 :     nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
    5293               0 :     if (NS_FAILED(rv))
    5294               0 :         sameURI = false;
    5295               0 :     if (!RefreshAttempted(this, aURI, aDelay, sameURI))
    5296               0 :         return NS_OK;
    5297                 : 
    5298               0 :     nsRefreshTimer *refreshTimer = new nsRefreshTimer();
    5299               0 :     NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
    5300               0 :     PRUint32 busyFlags = 0;
    5301               0 :     GetBusyFlags(&busyFlags);
    5302                 : 
    5303               0 :     nsCOMPtr<nsISupports> dataRef = refreshTimer;    // Get the ref count to 1
    5304                 : 
    5305               0 :     refreshTimer->mDocShell = this;
    5306               0 :     refreshTimer->mURI = aURI;
    5307               0 :     refreshTimer->mDelay = aDelay;
    5308               0 :     refreshTimer->mRepeat = aRepeat;
    5309               0 :     refreshTimer->mMetaRefresh = aMetaRefresh;
    5310                 : 
    5311               0 :     if (!mRefreshURIList) {
    5312               0 :         NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
    5313                 :                           NS_ERROR_FAILURE);
    5314                 :     }
    5315                 : 
    5316               0 :     if (busyFlags & BUSY_FLAGS_BUSY) {
    5317                 :         // We are busy loading another page. Don't create the
    5318                 :         // timer right now. Instead queue up the request and trigger the
    5319                 :         // timer in EndPageLoad(). 
    5320               0 :         mRefreshURIList->AppendElement(refreshTimer);
    5321                 :     }
    5322                 :     else {
    5323                 :         // There is no page loading going on right now.  Create the
    5324                 :         // timer and fire it right away.
    5325               0 :         nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
    5326               0 :         NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
    5327                 : 
    5328               0 :         mRefreshURIList->AppendElement(timer);      // owning timer ref
    5329               0 :         timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
    5330                 :     }
    5331               0 :     return NS_OK;
    5332                 : }
    5333                 : 
    5334                 : nsresult
    5335               0 : nsDocShell::ForceRefreshURIFromTimer(nsIURI * aURI,
    5336                 :                                      PRInt32 aDelay, 
    5337                 :                                      bool aMetaRefresh,
    5338                 :                                      nsITimer* aTimer)
    5339                 : {
    5340               0 :     NS_PRECONDITION(aTimer, "Must have a timer here");
    5341                 : 
    5342                 :     // Remove aTimer from mRefreshURIList if needed
    5343               0 :     if (mRefreshURIList) {
    5344               0 :         PRUint32 n = 0;
    5345               0 :         mRefreshURIList->Count(&n);
    5346                 : 
    5347               0 :         for (PRUint32 i = 0;  i < n; ++i) {
    5348               0 :             nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
    5349               0 :             if (timer == aTimer) {
    5350               0 :                 mRefreshURIList->RemoveElementAt(i);
    5351                 :                 break;
    5352                 :             }
    5353                 :         }
    5354                 :     }
    5355                 : 
    5356               0 :     return ForceRefreshURI(aURI, aDelay, aMetaRefresh);
    5357                 : }
    5358                 : 
    5359                 : NS_IMETHODIMP
    5360               0 : nsDocShell::ForceRefreshURI(nsIURI * aURI,
    5361                 :                             PRInt32 aDelay, 
    5362                 :                             bool aMetaRefresh)
    5363                 : {
    5364               0 :     NS_ENSURE_ARG(aURI);
    5365                 : 
    5366               0 :     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
    5367               0 :     CreateLoadInfo(getter_AddRefs(loadInfo));
    5368               0 :     NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
    5369                 : 
    5370                 :     /* We do need to pass in a referrer, but we don't want it to
    5371                 :      * be sent to the server.
    5372                 :      */
    5373               0 :     loadInfo->SetSendReferrer(false);
    5374                 : 
    5375                 :     /* for most refreshes the current URI is an appropriate
    5376                 :      * internal referrer
    5377                 :      */
    5378               0 :     loadInfo->SetReferrer(mCurrentURI);
    5379                 : 
    5380                 :     /* Don't ever "guess" on which owner to use to avoid picking
    5381                 :      * the current owner.
    5382                 :      */
    5383               0 :     loadInfo->SetOwnerIsExplicit(true);
    5384                 : 
    5385                 :     /* Check if this META refresh causes a redirection
    5386                 :      * to another site. 
    5387                 :      */
    5388               0 :     bool equalUri = false;
    5389               0 :     nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
    5390               0 :     if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
    5391                 :         aDelay <= REFRESH_REDIRECT_TIMER) {
    5392                 : 
    5393                 :         /* It is a META refresh based redirection within the threshold time
    5394                 :          * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
    5395                 :          * Pass a REPLACE flag to LoadURI().
    5396                 :          */
    5397               0 :         loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
    5398                 :             
    5399                 :         /* for redirects we mimic HTTP, which passes the
    5400                 :          *  original referrer
    5401                 :          */
    5402               0 :         nsCOMPtr<nsIURI> internalReferrer;
    5403               0 :         GetReferringURI(getter_AddRefs(internalReferrer));
    5404               0 :         if (internalReferrer) {
    5405               0 :             loadInfo->SetReferrer(internalReferrer);
    5406               0 :         }
    5407                 :     }
    5408                 :     else {
    5409               0 :         loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
    5410                 :     }
    5411                 : 
    5412                 :     /*
    5413                 :      * LoadURI(...) will cancel all refresh timers... This causes the
    5414                 :      * Timer and its refreshData instance to be released...
    5415                 :      */
    5416               0 :     LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
    5417                 : 
    5418               0 :     return NS_OK;
    5419                 : }
    5420                 : 
    5421                 : nsresult
    5422               0 : nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
    5423                 :                                       const nsACString & aHeader)
    5424                 : {
    5425                 :     // Refresh headers are parsed with the following format in mind
    5426                 :     // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
    5427                 :     // By the time we are here, the following is true:
    5428                 :     // header = "REFRESH"
    5429                 :     // content = "5; URL=http://uri" // note the URL attribute is
    5430                 :     // optional, if it is absent, the currently loaded url is used.
    5431                 :     // Also note that the seconds and URL separator can be either
    5432                 :     // a ';' or a ','. The ',' separator should be illegal but CNN
    5433                 :     // is using it.
    5434                 :     // 
    5435                 :     // We need to handle the following strings, where
    5436                 :     //  - X is a set of digits
    5437                 :     //  - URI is either a relative or absolute URI
    5438                 :     //
    5439                 :     // Note that URI should start with "url=" but we allow omission
    5440                 :     //
    5441                 :     // "" || ";" || "," 
    5442                 :     //  empty string. use the currently loaded URI
    5443                 :     //  and refresh immediately.
    5444                 :     // "X" || "X;" || "X,"
    5445                 :     //  Refresh the currently loaded URI in X seconds.
    5446                 :     // "X; URI" || "X, URI"
    5447                 :     //  Refresh using URI as the destination in X seconds.
    5448                 :     // "URI" || "; URI" || ", URI"
    5449                 :     //  Refresh immediately using URI as the destination.
    5450                 :     // 
    5451                 :     // Currently, anything immediately following the URI, if
    5452                 :     // separated by any char in the set "'\"\t\r\n " will be
    5453                 :     // ignored. So "10; url=go.html ; foo=bar" will work,
    5454                 :     // and so will "10; url='go.html'; foo=bar". However,
    5455                 :     // "10; url=go.html; foo=bar" will result in the uri
    5456                 :     // "go.html;" since ';' and ',' are valid uri characters.
    5457                 :     // 
    5458                 :     // Note that we need to remove any tokens wrapping the URI.
    5459                 :     // These tokens currently include spaces, double and single
    5460                 :     // quotes.
    5461                 : 
    5462                 :     // when done, seconds is 0 or the given number of seconds
    5463                 :     //            uriAttrib is empty or the URI specified
    5464               0 :     nsCAutoString uriAttrib;
    5465               0 :     PRInt32 seconds = 0;
    5466               0 :     bool specifiesSeconds = false;
    5467                 : 
    5468               0 :     nsACString::const_iterator iter, tokenStart, doneIterating;
    5469                 : 
    5470               0 :     aHeader.BeginReading(iter);
    5471               0 :     aHeader.EndReading(doneIterating);
    5472                 : 
    5473                 :     // skip leading whitespace
    5474               0 :     while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
    5475               0 :         ++iter;
    5476                 : 
    5477               0 :     tokenStart = iter;
    5478                 : 
    5479                 :     // skip leading + and -
    5480               0 :     if (iter != doneIterating && (*iter == '-' || *iter == '+'))
    5481               0 :         ++iter;
    5482                 : 
    5483                 :     // parse number
    5484               0 :     while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
    5485               0 :         seconds = seconds * 10 + (*iter - '0');
    5486               0 :         specifiesSeconds = true;
    5487               0 :         ++iter;
    5488                 :     }
    5489                 : 
    5490               0 :     if (iter != doneIterating) {
    5491                 :         // if we started with a '-', number is negative
    5492               0 :         if (*tokenStart == '-')
    5493               0 :             seconds = -seconds;
    5494                 : 
    5495                 :         // skip to next ';' or ','
    5496               0 :         nsACString::const_iterator iterAfterDigit = iter;
    5497               0 :         while (iter != doneIterating && !(*iter == ';' || *iter == ','))
    5498                 :         {
    5499               0 :             if (specifiesSeconds)
    5500                 :             {
    5501                 :                 // Non-whitespace characters here mean that the string is
    5502                 :                 // malformed but tolerate sites that specify a decimal point,
    5503                 :                 // even though meta refresh only works on whole seconds.
    5504               0 :                 if (iter == iterAfterDigit &&
    5505               0 :                     !nsCRT::IsAsciiSpace(*iter) && *iter != '.')
    5506                 :                 {
    5507                 :                     // The characters between the seconds and the next
    5508                 :                     // section are just garbage!
    5509                 :                     //   e.g. content="2a0z+,URL=http://www.mozilla.org/"
    5510                 :                     // Just ignore this redirect.
    5511               0 :                     return NS_ERROR_FAILURE;
    5512                 :                 }
    5513               0 :                 else if (nsCRT::IsAsciiSpace(*iter))
    5514                 :                 {
    5515                 :                     // We've had at least one whitespace so tolerate the mistake
    5516                 :                     // and drop through.
    5517                 :                     // e.g. content="10 foo"
    5518               0 :                     ++iter;
    5519               0 :                     break;
    5520                 :                 }
    5521                 :             }
    5522               0 :             ++iter;
    5523                 :         }
    5524                 : 
    5525                 :         // skip any remaining whitespace
    5526               0 :         while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
    5527               0 :             ++iter;
    5528                 : 
    5529                 :         // skip ';' or ','
    5530               0 :         if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
    5531               0 :             ++iter;
    5532                 :         }
    5533                 : 
    5534                 :         // skip whitespace
    5535               0 :         while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
    5536               0 :             ++iter;
    5537                 :     }
    5538                 : 
    5539                 :     // possible start of URI
    5540               0 :     tokenStart = iter;
    5541                 : 
    5542                 :     // skip "url = " to real start of URI
    5543               0 :     if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
    5544               0 :         ++iter;
    5545               0 :         if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
    5546               0 :             ++iter;
    5547               0 :             if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
    5548               0 :                 ++iter;
    5549                 : 
    5550                 :                 // skip whitespace
    5551               0 :                 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
    5552               0 :                     ++iter;
    5553                 : 
    5554               0 :                 if (iter != doneIterating && *iter == '=') {
    5555               0 :                     ++iter;
    5556                 : 
    5557                 :                     // skip whitespace
    5558               0 :                     while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
    5559               0 :                         ++iter;
    5560                 : 
    5561                 :                     // found real start of URI
    5562               0 :                     tokenStart = iter;
    5563                 :                 }
    5564                 :             }
    5565                 :         }
    5566                 :     }
    5567                 : 
    5568                 :     // skip a leading '"' or '\''.
    5569                 : 
    5570               0 :     bool isQuotedURI = false;
    5571               0 :     if (tokenStart != doneIterating && (*tokenStart == '"' || *tokenStart == '\''))
    5572                 :     {
    5573               0 :         isQuotedURI = true;
    5574               0 :         ++tokenStart;
    5575                 :     }
    5576                 : 
    5577                 :     // set iter to start of URI
    5578               0 :     iter = tokenStart;
    5579                 : 
    5580                 :     // tokenStart here points to the beginning of URI
    5581                 : 
    5582                 :     // grab the rest of the URI
    5583               0 :     while (iter != doneIterating)
    5584                 :     {
    5585               0 :         if (isQuotedURI && (*iter == '"' || *iter == '\''))
    5586               0 :             break;
    5587               0 :         ++iter;
    5588                 :     }
    5589                 : 
    5590                 :     // move iter one back if the last character is a '"' or '\''
    5591               0 :     if (iter != tokenStart && isQuotedURI) {
    5592               0 :         --iter;
    5593               0 :         if (!(*iter == '"' || *iter == '\''))
    5594               0 :             ++iter;
    5595                 :     }
    5596                 : 
    5597                 :     // URI is whatever's contained from tokenStart to iter.
    5598                 :     // note: if tokenStart == doneIterating, so is iter.
    5599                 : 
    5600               0 :     nsresult rv = NS_OK;
    5601                 : 
    5602               0 :     nsCOMPtr<nsIURI> uri;
    5603               0 :     bool specifiesURI = false;
    5604               0 :     if (tokenStart == iter) {
    5605               0 :         uri = aBaseURI;
    5606                 :     }
    5607                 :     else {
    5608               0 :         uriAttrib = Substring(tokenStart, iter);
    5609                 :         // NS_NewURI takes care of any whitespace surrounding the URL
    5610               0 :         rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nsnull, aBaseURI);
    5611               0 :         specifiesURI = true;
    5612                 :     }
    5613                 : 
    5614                 :     // No URI or seconds were specified
    5615               0 :     if (!specifiesSeconds && !specifiesURI)
    5616                 :     {
    5617                 :         // Do nothing because the alternative is to spin around in a refresh
    5618                 :         // loop forever!
    5619               0 :         return NS_ERROR_FAILURE;
    5620                 :     }
    5621                 : 
    5622               0 :     if (NS_SUCCEEDED(rv)) {
    5623                 :         nsCOMPtr<nsIScriptSecurityManager>
    5624                 :             securityManager(do_GetService
    5625               0 :                             (NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
    5626               0 :         if (NS_SUCCEEDED(rv)) {
    5627               0 :             rv = securityManager->
    5628                 :                 CheckLoadURI(aBaseURI, uri,
    5629                 :                              nsIScriptSecurityManager::
    5630               0 :                              LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
    5631                 : 
    5632               0 :             if (NS_SUCCEEDED(rv)) {
    5633               0 :                 bool isjs = true;
    5634                 :                 rv = NS_URIChainHasFlags(uri,
    5635               0 :                   nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
    5636               0 :                 NS_ENSURE_SUCCESS(rv, rv);
    5637                 : 
    5638               0 :                 if (isjs) {
    5639               0 :                     return NS_ERROR_FAILURE;
    5640                 :                 }
    5641                 :             }
    5642                 : 
    5643               0 :             if (NS_SUCCEEDED(rv)) {
    5644                 :                 // Since we can't travel back in time yet, just pretend
    5645                 :                 // negative numbers do nothing at all.
    5646               0 :                 if (seconds < 0)
    5647               0 :                     return NS_ERROR_FAILURE;
    5648                 : 
    5649               0 :                 rv = RefreshURI(uri, seconds * 1000, false, true);
    5650                 :             }
    5651                 :         }
    5652                 :     }
    5653               0 :     return rv;
    5654                 : }
    5655                 : 
    5656               0 : NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
    5657                 : {
    5658                 :     nsresult rv;
    5659               0 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
    5660               0 :     if (NS_SUCCEEDED(rv)) {
    5661               0 :         nsCAutoString refreshHeader;
    5662               0 :         rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
    5663               0 :                                             refreshHeader);
    5664                 : 
    5665               0 :         if (!refreshHeader.IsEmpty()) {
    5666               0 :             SetupReferrerFromChannel(aChannel);
    5667               0 :             rv = SetupRefreshURIFromHeader(mCurrentURI, refreshHeader);
    5668               0 :             if (NS_SUCCEEDED(rv)) {
    5669               0 :                 return NS_REFRESHURI_HEADER_FOUND;
    5670                 :             }
    5671                 :         }
    5672                 :     }
    5673               0 :     return rv;
    5674                 : }
    5675                 : 
    5676                 : static void
    5677               0 : DoCancelRefreshURITimers(nsISupportsArray* aTimerList)
    5678                 : {
    5679               0 :     if (!aTimerList)
    5680               0 :         return;
    5681                 : 
    5682               0 :     PRUint32 n=0;
    5683               0 :     aTimerList->Count(&n);
    5684                 : 
    5685               0 :     while (n) {
    5686               0 :         nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
    5687                 : 
    5688               0 :         aTimerList->RemoveElementAt(n);    // bye bye owning timer ref
    5689                 : 
    5690               0 :         if (timer)
    5691               0 :             timer->Cancel();        
    5692                 :     }
    5693                 : }
    5694                 : 
    5695                 : NS_IMETHODIMP
    5696               0 : nsDocShell::CancelRefreshURITimers()
    5697                 : {
    5698               0 :     DoCancelRefreshURITimers(mRefreshURIList);
    5699               0 :     DoCancelRefreshURITimers(mSavedRefreshURIList);
    5700               0 :     mRefreshURIList = nsnull;
    5701               0 :     mSavedRefreshURIList = nsnull;
    5702                 : 
    5703               0 :     return NS_OK;
    5704                 : }
    5705                 : 
    5706                 : NS_IMETHODIMP
    5707               0 : nsDocShell::GetRefreshPending(bool* _retval)
    5708                 : {
    5709               0 :     if (!mRefreshURIList) {
    5710               0 :         *_retval = false;
    5711               0 :         return NS_OK;
    5712                 :     }
    5713                 : 
    5714                 :     PRUint32 count;
    5715               0 :     nsresult rv = mRefreshURIList->Count(&count);
    5716               0 :     if (NS_SUCCEEDED(rv))
    5717               0 :         *_retval = (count != 0);
    5718               0 :     return rv;
    5719                 : }
    5720                 : 
    5721                 : NS_IMETHODIMP
    5722               0 : nsDocShell::SuspendRefreshURIs()
    5723                 : {
    5724               0 :     if (mRefreshURIList) {
    5725               0 :         PRUint32 n = 0;
    5726               0 :         mRefreshURIList->Count(&n);
    5727                 : 
    5728               0 :         for (PRUint32 i = 0;  i < n; ++i) {
    5729               0 :             nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
    5730               0 :             if (!timer)
    5731               0 :                 continue;  // this must be a nsRefreshURI already
    5732                 : 
    5733                 :             // Replace this timer object with a nsRefreshTimer object.
    5734               0 :             nsCOMPtr<nsITimerCallback> callback;
    5735               0 :             timer->GetCallback(getter_AddRefs(callback));
    5736                 : 
    5737               0 :             timer->Cancel();
    5738                 : 
    5739               0 :             nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
    5740               0 :             NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects");
    5741                 : 
    5742               0 :             mRefreshURIList->ReplaceElementAt(rt, i);
    5743                 :         }
    5744                 :     }
    5745                 : 
    5746                 :     // Suspend refresh URIs for our child shells as well.
    5747               0 :     PRInt32 n = mChildList.Count();
    5748                 : 
    5749               0 :     for (PRInt32 i = 0; i < n; ++i) {
    5750               0 :         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
    5751               0 :         if (shell)
    5752               0 :             shell->SuspendRefreshURIs();
    5753                 :     }
    5754                 : 
    5755               0 :     return NS_OK;
    5756                 : }
    5757                 : 
    5758                 : NS_IMETHODIMP
    5759               0 : nsDocShell::ResumeRefreshURIs()
    5760                 : {
    5761               0 :     RefreshURIFromQueue();
    5762                 : 
    5763                 :     // Resume refresh URIs for our child shells as well.
    5764               0 :     PRInt32 n = mChildList.Count();
    5765                 : 
    5766               0 :     for (PRInt32 i = 0; i < n; ++i) {
    5767               0 :         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
    5768               0 :         if (shell)
    5769               0 :             shell->ResumeRefreshURIs();
    5770                 :     }
    5771                 : 
    5772               0 :     return NS_OK;
    5773                 : }
    5774                 : 
    5775                 : nsresult
    5776               0 : nsDocShell::RefreshURIFromQueue()
    5777                 : {
    5778               0 :     if (!mRefreshURIList)
    5779               0 :         return NS_OK;
    5780               0 :     PRUint32 n = 0;
    5781               0 :     mRefreshURIList->Count(&n);
    5782                 : 
    5783               0 :     while (n) {
    5784               0 :         nsCOMPtr<nsISupports> element;
    5785               0 :         mRefreshURIList->GetElementAt(--n, getter_AddRefs(element));
    5786               0 :         nsCOMPtr<nsITimerCallback> refreshInfo(do_QueryInterface(element));
    5787                 : 
    5788               0 :         if (refreshInfo) {   
    5789                 :             // This is the nsRefreshTimer object, waiting to be
    5790                 :             // setup in a timer object and fired.                         
    5791                 :             // Create the timer and  trigger it.
    5792               0 :             PRUint32 delay = static_cast<nsRefreshTimer*>(static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
    5793               0 :             nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
    5794               0 :             if (timer) {    
    5795                 :                 // Replace the nsRefreshTimer element in the queue with
    5796                 :                 // its corresponding timer object, so that in case another
    5797                 :                 // load comes through before the timer can go off, the timer will
    5798                 :                 // get cancelled in CancelRefreshURITimer()
    5799               0 :                 mRefreshURIList->ReplaceElementAt(timer, n);
    5800               0 :                 timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
    5801                 :             }           
    5802                 :         }        
    5803                 :     }  // while
    5804                 :  
    5805               0 :     return NS_OK;
    5806                 : }
    5807                 : 
    5808                 : //*****************************************************************************
    5809                 : // nsDocShell::nsIContentViewerContainer
    5810                 : //*****************************************************************************   
    5811                 : 
    5812                 : NS_IMETHODIMP
    5813               0 : nsDocShell::Embed(nsIContentViewer * aContentViewer,
    5814                 :                   const char *aCommand, nsISupports * aExtraInfo)
    5815                 : {
    5816                 :     // Save the LayoutHistoryState of the previous document, before
    5817                 :     // setting up new document
    5818               0 :     PersistLayoutHistoryState();
    5819                 : 
    5820               0 :     nsresult rv = SetupNewViewer(aContentViewer);
    5821                 : 
    5822                 :     // If we are loading a wyciwyg url from history, change the base URI for 
    5823                 :     // the document to the original http url that created the document.write().
    5824                 :     // This makes sure that all relative urls in a document.written page loaded
    5825                 :     // via history work properly.
    5826               0 :     if (mCurrentURI &&
    5827                 :        (mLoadType & LOAD_CMD_HISTORY ||
    5828                 :         mLoadType == LOAD_RELOAD_NORMAL ||
    5829               0 :         mLoadType == LOAD_RELOAD_CHARSET_CHANGE)){
    5830               0 :         bool isWyciwyg = false;
    5831                 :         // Check if the url is wyciwyg
    5832               0 :         rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);      
    5833               0 :         if (isWyciwyg && NS_SUCCEEDED(rv))
    5834               0 :             SetBaseUrlForWyciwyg(aContentViewer);
    5835                 :     }
    5836                 :     // XXX What if SetupNewViewer fails?
    5837               0 :     if (mLSHE) {
    5838                 :         // Restore the editing state, if it's stored in session history.
    5839               0 :         if (mLSHE->HasDetachedEditor()) {
    5840               0 :             ReattachEditorToWindow(mLSHE);
    5841                 :         }
    5842                 :         // Set history.state
    5843               0 :         SetDocCurrentStateObj(mLSHE);
    5844                 : 
    5845               0 :         SetHistoryEntry(&mOSHE, mLSHE);
    5846                 :     }
    5847                 : 
    5848               0 :     bool updateHistory = true;
    5849                 : 
    5850                 :     // Determine if this type of load should update history
    5851               0 :     switch (mLoadType) {
    5852                 :     case LOAD_NORMAL_REPLACE:
    5853                 :     case LOAD_STOP_CONTENT_AND_REPLACE:
    5854                 :     case LOAD_RELOAD_BYPASS_CACHE:
    5855                 :     case LOAD_RELOAD_BYPASS_PROXY:
    5856                 :     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
    5857               0 :         updateHistory = false;
    5858               0 :         break;
    5859                 :     default:
    5860               0 :         break;
    5861                 :     }
    5862                 : 
    5863               0 :     if (!updateHistory)
    5864               0 :         SetLayoutHistoryState(nsnull);
    5865                 : 
    5866               0 :     return NS_OK;
    5867                 : }
    5868                 : 
    5869                 : /* void setIsPrinting (in boolean aIsPrinting); */
    5870                 : NS_IMETHODIMP 
    5871               0 : nsDocShell::SetIsPrinting(bool aIsPrinting)
    5872                 : {
    5873               0 :     mIsPrintingOrPP = aIsPrinting;
    5874               0 :     return NS_OK;
    5875                 : }
    5876                 : 
    5877                 : //*****************************************************************************
    5878                 : // nsDocShell::nsIWebProgressListener
    5879                 : //*****************************************************************************   
    5880                 : 
    5881                 : NS_IMETHODIMP
    5882               0 : nsDocShell::OnProgressChange(nsIWebProgress * aProgress,
    5883                 :                              nsIRequest * aRequest,
    5884                 :                              PRInt32 aCurSelfProgress,
    5885                 :                              PRInt32 aMaxSelfProgress,
    5886                 :                              PRInt32 aCurTotalProgress,
    5887                 :                              PRInt32 aMaxTotalProgress)
    5888                 : {
    5889               0 :     return NS_OK;
    5890                 : }
    5891                 : 
    5892                 : NS_IMETHODIMP
    5893               0 : nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
    5894                 :                           PRUint32 aStateFlags, nsresult aStatus)
    5895                 : {
    5896                 :     nsresult rv;
    5897                 : 
    5898               0 :     if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
    5899                 :         // Save timing statistics.
    5900               0 :         nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    5901               0 :         nsCOMPtr<nsIURI> uri;
    5902               0 :         channel->GetURI(getter_AddRefs(uri));
    5903               0 :         nsCAutoString aURI;
    5904               0 :         uri->GetAsciiSpec(aURI);
    5905               0 :         if (this == aProgress){
    5906               0 :             rv = MaybeInitTiming();
    5907               0 :             if (mTiming) {
    5908               0 :                 mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType));
    5909                 :             } 
    5910                 :         }
    5911                 : 
    5912               0 :         nsCOMPtr<nsIWyciwygChannel>  wcwgChannel(do_QueryInterface(aRequest));
    5913                 :         nsCOMPtr<nsIWebProgress> webProgress =
    5914               0 :             do_QueryInterface(GetAsSupports(this));
    5915                 : 
    5916                 :         // Was the wyciwyg document loaded on this docshell?
    5917               0 :         if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
    5918               0 :             bool equalUri = true;
    5919                 :             // Store the wyciwyg url in session history, only if it is
    5920                 :             // being loaded fresh for the first time. We don't want 
    5921                 :             // multiple entries for successive loads
    5922               0 :             if (mCurrentURI &&
    5923               0 :                 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
    5924               0 :                 !equalUri) {
    5925                 : 
    5926               0 :                 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    5927               0 :                 GetSameTypeParent(getter_AddRefs(parentAsItem));
    5928               0 :                 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
    5929               0 :                 bool inOnLoadHandler = false;
    5930               0 :                 if (parentDS) {
    5931               0 :                   parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
    5932                 :                 }
    5933               0 :                 if (inOnLoadHandler) {
    5934                 :                     // We're handling parent's load event listener, which causes
    5935                 :                     // document.write in a subdocument.
    5936                 :                     // Need to clear the session history for all child
    5937                 :                     // docshells so that we can handle them like they would
    5938                 :                     // all be added dynamically.
    5939                 :                     nsCOMPtr<nsIDocShellHistory> parent =
    5940               0 :                         do_QueryInterface(parentAsItem);
    5941               0 :                     if (parent) {
    5942               0 :                         bool oshe = false;
    5943               0 :                         nsCOMPtr<nsISHEntry> entry;
    5944               0 :                         parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
    5945               0 :                         static_cast<nsDocShell*>(parent.get())->
    5946               0 :                             ClearFrameHistory(entry);
    5947                 :                     }
    5948                 :                 }
    5949                 : 
    5950                 :                 // This is a document.write(). Get the made-up url
    5951                 :                 // from the channel and store it in session history.
    5952                 :                 // Pass false for aCloneChildren, since we're creating
    5953                 :                 // a new DOM here.
    5954                 :                 rv = AddToSessionHistory(uri, wcwgChannel, nsnull, false,
    5955               0 :                                          getter_AddRefs(mLSHE));
    5956               0 :                 SetCurrentURI(uri, aRequest, true, 0);
    5957                 :                 // Save history state of the previous page
    5958               0 :                 rv = PersistLayoutHistoryState();
    5959                 :                 // We'll never get an Embed() for this load, so just go ahead
    5960                 :                 // and SetHistoryEntry now.
    5961               0 :                 SetHistoryEntry(&mOSHE, mLSHE);
    5962                 :             }
    5963                 :         
    5964                 :         }
    5965                 :         // Page has begun to load
    5966               0 :         mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
    5967                 : 
    5968               0 :         if ((aStateFlags & STATE_RESTORING) == 0) {
    5969                 :             // Show the progress cursor if the pref is set
    5970               0 :             if (Preferences::GetBool("ui.use_activity_cursor", false)) {
    5971               0 :                 nsCOMPtr<nsIWidget> mainWidget;
    5972               0 :                 GetMainWidget(getter_AddRefs(mainWidget));
    5973               0 :                 if (mainWidget) {
    5974               0 :                     mainWidget->SetCursor(eCursor_spinning);
    5975                 :                 }
    5976                 :             }
    5977                 :         }
    5978                 :     }
    5979               0 :     else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
    5980                 :         // Page is loading
    5981               0 :         mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
    5982                 :     }
    5983               0 :     else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
    5984                 :         // Page has finished loading
    5985               0 :         mBusyFlags = BUSY_FLAGS_NONE;
    5986                 : 
    5987                 :         // Hide the progress cursor if the pref is set
    5988               0 :         if (Preferences::GetBool("ui.use_activity_cursor", false)) {
    5989               0 :             nsCOMPtr<nsIWidget> mainWidget;
    5990               0 :             GetMainWidget(getter_AddRefs(mainWidget));
    5991               0 :             if (mainWidget) {
    5992               0 :                 mainWidget->SetCursor(eCursor_standard);
    5993                 :             }
    5994                 :         }
    5995                 :     }
    5996               0 :     if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
    5997                 :         nsCOMPtr<nsIWebProgress> webProgress =
    5998               0 :             do_QueryInterface(GetAsSupports(this));
    5999                 :         // Is the document stop notification for this document?
    6000               0 :         if (aProgress == webProgress.get()) {
    6001               0 :             nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    6002               0 :             EndPageLoad(aProgress, channel, aStatus);
    6003                 :         }
    6004                 :     }
    6005                 :     // note that redirect state changes will go through here as well, but it
    6006                 :     // is better to handle those in OnRedirectStateChange where more
    6007                 :     // information is available.
    6008               0 :     return NS_OK;
    6009                 : }
    6010                 : 
    6011                 : NS_IMETHODIMP
    6012               0 : nsDocShell::OnLocationChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
    6013                 :                              nsIURI * aURI, PRUint32 aFlags)
    6014                 : {
    6015               0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    6016               0 :     return NS_OK;
    6017                 : }
    6018                 : 
    6019                 : void
    6020               0 : nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
    6021                 :                                   nsIChannel* aNewChannel,
    6022                 :                                   PRUint32 aRedirectFlags,
    6023                 :                                   PRUint32 aStateFlags)
    6024                 : {
    6025               0 :     NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
    6026                 :                  "Calling OnRedirectStateChange when there is no redirect");
    6027               0 :     if (!(aStateFlags & STATE_IS_DOCUMENT))
    6028               0 :         return; // not a toplevel document
    6029                 : 
    6030               0 :     nsCOMPtr<nsIURI> oldURI, newURI;
    6031               0 :     aOldChannel->GetURI(getter_AddRefs(oldURI));
    6032               0 :     aNewChannel->GetURI(getter_AddRefs(newURI));
    6033               0 :     if (!oldURI || !newURI) {
    6034                 :         return;
    6035                 :     }
    6036                 :     // On session restore we get a redirect from page to itself. Don't count it.
    6037               0 :     bool equals = false;
    6038               0 :     if (mTiming &&
    6039                 :         !(mLoadType == LOAD_HISTORY &&
    6040               0 :           NS_SUCCEEDED(newURI->Equals(oldURI, &equals)) && equals)) {
    6041               0 :         mTiming->NotifyRedirect(oldURI, newURI);
    6042                 :     }
    6043                 : 
    6044                 :     // Below a URI visit is saved (see AddURIVisit method doc).
    6045                 :     // The visit chain looks something like:
    6046                 :     //   ...
    6047                 :     //   Site N - 1
    6048                 :     //                =>  Site N
    6049                 :     //   (redirect to =>) Site N + 1 (we are here!)
    6050                 : 
    6051                 :     // Get N - 1 and transition type
    6052               0 :     nsCOMPtr<nsIURI> previousURI;
    6053               0 :     PRUint32 previousFlags = 0;
    6054               0 :     ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
    6055                 : 
    6056               0 :     if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
    6057               0 :         ChannelIsPost(aOldChannel)) {
    6058                 :         // 1. Internal redirects are ignored because they are specific to the
    6059                 :         //    channel implementation.
    6060                 :         // 2. POSTs are not saved by global history.
    6061                 :         //
    6062                 :         // Regardless, we need to propagate the previous visit to the new
    6063                 :         // channel.
    6064               0 :         SaveLastVisit(aNewChannel, previousURI, previousFlags);
    6065                 :     }
    6066                 :     else {
    6067               0 :         nsCOMPtr<nsIURI> referrer;
    6068                 :         // Treat referrer as null if there is an error getting it.
    6069                 :         (void)NS_GetReferrerFromChannel(aOldChannel,
    6070               0 :                                         getter_AddRefs(referrer));
    6071                 : 
    6072                 :         // Add visit N -1 => N
    6073               0 :         AddURIVisit(oldURI, referrer, previousURI, previousFlags);
    6074                 : 
    6075                 :         // Since N + 1 could be the final destination, we will not save N => N + 1
    6076                 :         // here.  OnNewURI will do that, so we will cache it.
    6077               0 :         SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
    6078                 :     }
    6079                 : 
    6080                 :     // check if the new load should go through the application cache.
    6081                 :     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
    6082               0 :         do_QueryInterface(aNewChannel);
    6083               0 :     if (appCacheChannel) {
    6084                 :         // Permission will be checked in the parent process.
    6085               0 :         if (GeckoProcessType_Default != XRE_GetProcessType())
    6086               0 :             appCacheChannel->SetChooseApplicationCache(true);
    6087                 :         else
    6088               0 :             appCacheChannel->SetChooseApplicationCache(ShouldCheckAppCache(newURI));
    6089                 :     }
    6090                 : 
    6091               0 :     if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && 
    6092                 :         mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
    6093               0 :         mLoadType = LOAD_NORMAL_REPLACE;
    6094               0 :         SetHistoryEntry(&mLSHE, nsnull);
    6095                 :     }
    6096                 : }
    6097                 : 
    6098                 : NS_IMETHODIMP
    6099               0 : nsDocShell::OnStatusChange(nsIWebProgress * aWebProgress,
    6100                 :                            nsIRequest * aRequest,
    6101                 :                            nsresult aStatus, const PRUnichar * aMessage)
    6102                 : {
    6103               0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    6104               0 :     return NS_OK;
    6105                 : }
    6106                 : 
    6107                 : NS_IMETHODIMP
    6108               0 : nsDocShell::OnSecurityChange(nsIWebProgress * aWebProgress,
    6109                 :                              nsIRequest * aRequest, PRUint32 state)
    6110                 : {
    6111               0 :     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    6112               0 :     return NS_OK;
    6113                 : }
    6114                 : 
    6115                 : 
    6116                 : nsresult
    6117               0 : nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
    6118                 :                         nsIChannel * aChannel, nsresult aStatus)
    6119                 : {
    6120               0 :     if(!aChannel)
    6121               0 :         return NS_ERROR_NULL_POINTER;
    6122                 :     
    6123               0 :     nsCOMPtr<nsIURI> url;
    6124               0 :     nsresult rv = aChannel->GetURI(getter_AddRefs(url));
    6125               0 :     if (NS_FAILED(rv)) return rv;
    6126                 : 
    6127                 :     nsCOMPtr<nsITimedChannel> timingChannel =
    6128               0 :         do_QueryInterface(aChannel);
    6129               0 :     if (timingChannel) {
    6130               0 :         TimeStamp channelCreationTime;
    6131               0 :         rv = timingChannel->GetChannelCreation(&channelCreationTime);
    6132               0 :         if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull())
    6133                 :             Telemetry::AccumulateTimeDelta(
    6134                 :                 Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
    6135               0 :                 channelCreationTime);
    6136                 :     }
    6137                 : 
    6138                 :     // Timing is picked up by the window, we don't need it anymore
    6139               0 :     mTiming = nsnull;
    6140                 : 
    6141                 :     // clean up reload state for meta charset
    6142               0 :     if (eCharsetReloadRequested == mCharsetReloadState)
    6143               0 :         mCharsetReloadState = eCharsetReloadStopOrigional;
    6144                 :     else 
    6145               0 :         mCharsetReloadState = eCharsetReloadInit;
    6146                 : 
    6147                 :     // Save a pointer to the currently-loading history entry.
    6148                 :     // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
    6149                 :     // entry further down in this method.
    6150               0 :     nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
    6151                 :   
    6152                 :     //
    6153                 :     // one of many safeguards that prevent death and destruction if
    6154                 :     // someone is so very very rude as to bring this window down
    6155                 :     // during this load handler.
    6156                 :     //
    6157               0 :     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
    6158                 : 
    6159                 :     // Notify the ContentViewer that the Document has finished loading.  This
    6160                 :     // will cause any OnLoad(...) and PopState(...) handlers to fire.
    6161               0 :     if (!mEODForCurrentDocument && mContentViewer) {
    6162               0 :         mIsExecutingOnLoadHandler = true;
    6163               0 :         mContentViewer->LoadComplete(aStatus);
    6164               0 :         mIsExecutingOnLoadHandler = false;
    6165                 : 
    6166               0 :         mEODForCurrentDocument = true;
    6167                 : 
    6168                 :         // If all documents have completed their loading
    6169                 :         // favor native event dispatch priorities
    6170                 :         // over performance
    6171               0 :         if (--gNumberOfDocumentsLoading == 0) {
    6172                 :           // Hint to use normal native event dispatch priorities 
    6173               0 :           FavorPerformanceHint(false, NS_EVENT_STARVATION_DELAY_HINT);
    6174                 :         }
    6175                 :     }
    6176                 :     /* Check if the httpChannel has any cache-control related response headers,
    6177                 :      * like no-store, no-cache. If so, update SHEntry so that 
    6178                 :      * when a user goes back/forward to this page, we appropriately do 
    6179                 :      * form value restoration or load from server.
    6180                 :      */
    6181               0 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
    6182               0 :     if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel.    
    6183               0 :         GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
    6184                 : 
    6185               0 :     if (httpChannel) {
    6186                 :         // figure out if SH should be saving layout state.
    6187               0 :         bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);       
    6188               0 :         if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
    6189                 :             (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE))
    6190               0 :             mLSHE->SetSaveLayoutStateFlag(false);            
    6191                 :     }
    6192                 : 
    6193                 :     // Clear mLSHE after calling the onLoadHandlers. This way, if the
    6194                 :     // onLoadHandler tries to load something different in
    6195                 :     // itself or one of its children, we can deal with it appropriately.
    6196               0 :     if (mLSHE) {
    6197               0 :         mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
    6198                 : 
    6199                 :         // Clear the mLSHE reference to indicate document loading is done one
    6200                 :         // way or another.
    6201               0 :         SetHistoryEntry(&mLSHE, nsnull);
    6202                 :     }
    6203                 :     // if there's a refresh header in the channel, this method
    6204                 :     // will set it up for us. 
    6205               0 :     RefreshURIFromQueue();
    6206                 : 
    6207                 :     // Test whether this is the top frame or a subframe
    6208               0 :     bool isTopFrame = true;
    6209               0 :     nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
    6210               0 :     rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
    6211               0 :     if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
    6212               0 :         isTopFrame = false;
    6213                 :     }
    6214                 : 
    6215                 :     //
    6216                 :     // If the page load failed, then deal with the error condition...
    6217                 :     // Errors are handled as follows:
    6218                 :     //   1. Check to see if it's a file not found error or bad content
    6219                 :     //      encoding error.
    6220                 :     //   2. Send the URI to a keyword server (if enabled)
    6221                 :     //   3. If the error was DNS failure, then add www and .com to the URI
    6222                 :     //      (if appropriate).
    6223                 :     //   4. Throw an error dialog box...
    6224                 :     //
    6225               0 :     if (url && NS_FAILED(aStatus)) {
    6226               0 :         if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
    6227                 :             aStatus == NS_ERROR_CORRUPTED_CONTENT ||
    6228                 :             aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
    6229               0 :             DisplayLoadError(aStatus, url, nsnull, aChannel);
    6230               0 :             return NS_OK;
    6231                 :         }
    6232                 : 
    6233               0 :         if (sURIFixup) {
    6234                 :             //
    6235                 :             // Try and make an alternative URI from the old one
    6236                 :             //
    6237               0 :             nsCOMPtr<nsIURI> newURI;
    6238                 : 
    6239               0 :             nsCAutoString oldSpec;
    6240               0 :             url->GetSpec(oldSpec);
    6241                 :       
    6242                 :             //
    6243                 :             // First try keyword fixup
    6244                 :             //
    6245               0 :             if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
    6246                 :                 bool keywordsEnabled =
    6247               0 :                     Preferences::GetBool("keyword.enabled", false);
    6248                 : 
    6249               0 :                 nsCAutoString host;
    6250               0 :                 url->GetHost(host);
    6251                 : 
    6252               0 :                 nsCAutoString scheme;
    6253               0 :                 url->GetScheme(scheme);
    6254                 : 
    6255               0 :                 PRInt32 dotLoc = host.FindChar('.');
    6256                 : 
    6257                 :                 // we should only perform a keyword search under the following
    6258                 :                 // conditions:
    6259                 :                 // (0) Pref keyword.enabled is true
    6260                 :                 // (1) the url scheme is http (or https)
    6261                 :                 // (2) the url does not have a protocol scheme
    6262                 :                 // If we don't enforce such a policy, then we end up doing
    6263                 :                 // keyword searchs on urls we don't intend like imap, file,
    6264                 :                 // mailbox, etc. This could lead to a security problem where we
    6265                 :                 // send data to the keyword server that we shouldn't be.
    6266                 :                 // Someone needs to clean up keywords in general so we can
    6267                 :                 // determine on a per url basis if we want keywords
    6268                 :                 // enabled...this is just a bandaid...
    6269               0 :                 if (keywordsEnabled && !scheme.IsEmpty() &&
    6270               0 :                     (scheme.Find("http") != 0)) {
    6271               0 :                     keywordsEnabled = false;
    6272                 :                 }
    6273                 : 
    6274               0 :                 if (keywordsEnabled && (kNotFound == dotLoc)) {
    6275                 :                     // only send non-qualified hosts to the keyword server
    6276                 :                     //
    6277                 :                     // If this string was passed through nsStandardURL by
    6278                 :                     // chance, then it may have been converted from UTF-8 to
    6279                 :                     // ACE, which would result in a completely bogus keyword
    6280                 :                     // query.  Here we try to recover the original Unicode
    6281                 :                     // value, but this is not 100% correct since the value may
    6282                 :                     // have been normalized per the IDN normalization rules.
    6283                 :                     //
    6284                 :                     // Since we don't have access to the exact original string
    6285                 :                     // that was entered by the user, this will just have to do.
    6286                 :                     bool isACE;
    6287               0 :                     nsCAutoString utf8Host;
    6288                 :                     nsCOMPtr<nsIIDNService> idnSrv =
    6289               0 :                         do_GetService(NS_IDNSERVICE_CONTRACTID);
    6290               0 :                     if (idnSrv &&
    6291               0 :                         NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
    6292               0 :                         NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host)))
    6293                 :                         sURIFixup->KeywordToURI(utf8Host,
    6294               0 :                                                 getter_AddRefs(newURI));
    6295                 :                     else
    6296               0 :                         sURIFixup->KeywordToURI(host, getter_AddRefs(newURI));
    6297                 :                 } // end keywordsEnabled
    6298                 :             }
    6299                 : 
    6300                 :             //
    6301                 :             // Now try change the address, e.g. turn http://foo into
    6302                 :             // http://www.foo.com
    6303                 :             //
    6304               0 :             if (aStatus == NS_ERROR_UNKNOWN_HOST ||
    6305                 :                 aStatus == NS_ERROR_NET_RESET) {
    6306               0 :                 bool doCreateAlternate = true;
    6307                 : 
    6308                 :                 // Skip fixup for anything except a normal document load
    6309                 :                 // operation on the topframe.
    6310                 :         
    6311               0 :                 if (mLoadType != LOAD_NORMAL || !isTopFrame) {
    6312               0 :                     doCreateAlternate = false;
    6313                 :                 }
    6314                 :                 else {
    6315                 :                     // Test if keyword lookup produced a new URI or not
    6316               0 :                     if (newURI) {
    6317               0 :                         bool sameURI = false;
    6318               0 :                         url->Equals(newURI, &sameURI);
    6319               0 :                         if (!sameURI) {
    6320                 :                             // Keyword lookup made a new URI so no need to try
    6321                 :                             // an alternate one.
    6322               0 :                             doCreateAlternate = false;
    6323                 :                         }
    6324                 :                     }
    6325                 :                 }
    6326               0 :                 if (doCreateAlternate) {
    6327               0 :                     newURI = nsnull;
    6328                 :                     sURIFixup->CreateFixupURI(oldSpec,
    6329                 :                       nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
    6330               0 :                                               getter_AddRefs(newURI));
    6331                 :                 }
    6332                 :             }
    6333                 : 
    6334                 :             // Did we make a new URI that is different to the old one? If so
    6335                 :             // load it.
    6336                 :             //
    6337               0 :             if (newURI) {
    6338                 :                 // Make sure the new URI is different from the old one,
    6339                 :                 // otherwise there's little point trying to load it again.
    6340               0 :                 bool sameURI = false;
    6341               0 :                 url->Equals(newURI, &sameURI);
    6342               0 :                 if (!sameURI) {
    6343               0 :                     nsCAutoString newSpec;
    6344               0 :                     newURI->GetSpec(newSpec);
    6345               0 :                     NS_ConvertUTF8toUTF16 newSpecW(newSpec);
    6346                 : 
    6347                 :                     return LoadURI(newSpecW.get(),  // URI string
    6348                 :                                    LOAD_FLAGS_NONE, // Load flags
    6349                 :                                    nsnull,          // Referring URI
    6350                 :                                    nsnull,          // Post data stream
    6351               0 :                                    nsnull);         // Headers stream
    6352                 :                 }
    6353                 :             }
    6354                 :         }
    6355                 : 
    6356                 :         // Well, fixup didn't work :-(
    6357                 :         // It is time to throw an error dialog box, and be done with it...
    6358                 : 
    6359                 :         // Errors to be shown only on top-level frames
    6360               0 :         if ((aStatus == NS_ERROR_UNKNOWN_HOST || 
    6361                 :              aStatus == NS_ERROR_CONNECTION_REFUSED ||
    6362                 :              aStatus == NS_ERROR_UNKNOWN_PROXY_HOST || 
    6363                 :              aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
    6364                 :             (isTopFrame || mUseErrorPages)) {
    6365               0 :             DisplayLoadError(aStatus, url, nsnull, aChannel);
    6366                 :         }
    6367                 :         // Errors to be shown for any frame
    6368               0 :         else if (aStatus == NS_ERROR_NET_TIMEOUT ||
    6369                 :                  aStatus == NS_ERROR_REDIRECT_LOOP ||
    6370                 :                  aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
    6371                 :                  aStatus == NS_ERROR_NET_INTERRUPT ||
    6372                 :                  aStatus == NS_ERROR_NET_RESET ||
    6373                 :                  aStatus == NS_ERROR_OFFLINE ||
    6374                 :                  aStatus == NS_ERROR_MALWARE_URI ||
    6375                 :                  aStatus == NS_ERROR_PHISHING_URI ||
    6376                 :                  aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
    6377                 :                  aStatus == NS_ERROR_REMOTE_XUL ||
    6378                 :                  aStatus == NS_ERROR_OFFLINE ||
    6379                 :                  NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
    6380               0 :             DisplayLoadError(aStatus, url, nsnull, aChannel);
    6381                 :         }
    6382               0 :         else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
    6383                 :             // Non-caching channels will simply return NS_ERROR_OFFLINE.
    6384                 :             // Caching channels would have to look at their flags to work
    6385                 :             // out which error to return. Or we can fix up the error here.
    6386               0 :             if (!(mLoadType & LOAD_CMD_HISTORY))
    6387               0 :                 aStatus = NS_ERROR_OFFLINE;
    6388               0 :             DisplayLoadError(aStatus, url, nsnull, aChannel);
    6389                 :         }
    6390                 :   } // if we have a host
    6391                 : 
    6392               0 :   return NS_OK;
    6393                 : }
    6394                 : 
    6395                 : 
    6396                 : //*****************************************************************************
    6397                 : // nsDocShell: Content Viewer Management
    6398                 : //*****************************************************************************   
    6399                 : 
    6400                 : NS_IMETHODIMP
    6401               0 : nsDocShell::EnsureContentViewer()
    6402                 : {
    6403               0 :     if (mContentViewer)
    6404               0 :         return NS_OK;
    6405               0 :     if (mIsBeingDestroyed)
    6406               0 :         return NS_ERROR_FAILURE;
    6407                 : 
    6408                 :     NS_TIME_FUNCTION;
    6409                 : 
    6410               0 :     nsIPrincipal* principal = nsnull;
    6411               0 :     nsCOMPtr<nsIURI> baseURI;
    6412                 : 
    6413               0 :     nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(mScriptGlobal));
    6414               0 :     if (piDOMWindow) {
    6415               0 :         principal = piDOMWindow->GetOpenerScriptPrincipal();
    6416                 :     }
    6417                 : 
    6418               0 :     if (!principal) {
    6419               0 :         principal = GetInheritedPrincipal(false);
    6420               0 :         nsCOMPtr<nsIDocShellTreeItem> parentItem;
    6421               0 :         GetSameTypeParent(getter_AddRefs(parentItem));
    6422               0 :         if (parentItem) {
    6423               0 :             nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
    6424               0 :             if (domWin) {
    6425                 :                 nsCOMPtr<nsIContent> parentContent =
    6426               0 :                     do_QueryInterface(domWin->GetFrameElementInternal());
    6427               0 :                 if (parentContent) {
    6428               0 :                     baseURI = parentContent->GetBaseURI();
    6429                 :                 }
    6430                 :             }
    6431                 :         }
    6432                 :     }
    6433                 : 
    6434               0 :     nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
    6435                 : 
    6436               0 :     if (NS_SUCCEEDED(rv)) {
    6437               0 :         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
    6438               0 :         NS_ASSERTION(doc,
    6439                 :                      "Should have doc if CreateAboutBlankContentViewer "
    6440                 :                      "succeeded!");
    6441                 : 
    6442               0 :         doc->SetIsInitialDocument(true);
    6443                 :     }
    6444                 : 
    6445               0 :     return rv;
    6446                 : }
    6447                 : 
    6448                 : nsresult
    6449               0 : nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
    6450                 :                                           nsIURI* aBaseURI,
    6451                 :                                           bool aTryToSaveOldPresentation)
    6452                 : {
    6453               0 :   nsCOMPtr<nsIDocument> blankDoc;
    6454               0 :   nsCOMPtr<nsIContentViewer> viewer;
    6455               0 :   nsresult rv = NS_ERROR_FAILURE;
    6456                 : 
    6457                 :   /* mCreatingDocument should never be true at this point. However, it's
    6458                 :      a theoretical possibility. We want to know about it and make it stop,
    6459                 :      and this sounds like a job for an assertion. */
    6460               0 :   NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted");
    6461               0 :   if (mCreatingDocument)
    6462               0 :     return NS_ERROR_FAILURE;
    6463                 : 
    6464               0 :   mCreatingDocument = true;
    6465                 : 
    6466                 :   // mContentViewer->PermitUnload may release |this| docshell.
    6467               0 :   nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
    6468                 :   
    6469               0 :   if (mContentViewer) {
    6470                 :     // We've got a content viewer already. Make sure the user
    6471                 :     // permits us to discard the current document and replace it
    6472                 :     // with about:blank. And also ensure we fire the unload events
    6473                 :     // in the current document.
    6474                 : 
    6475                 :     // Make sure timing is created. Unload gets fired first for
    6476                 :     // document loaded from the session history.
    6477               0 :     rv = MaybeInitTiming();
    6478               0 :     if (mTiming) {
    6479               0 :       mTiming->NotifyBeforeUnload();
    6480                 :     }
    6481                 : 
    6482                 :     bool okToUnload;
    6483               0 :     rv = mContentViewer->PermitUnload(false, &okToUnload);
    6484                 : 
    6485               0 :     if (NS_SUCCEEDED(rv) && !okToUnload) {
    6486                 :       // The user chose not to unload the page, interrupt the load.
    6487               0 :       return NS_ERROR_FAILURE;
    6488                 :     }
    6489                 : 
    6490                 :     mSavingOldViewer = aTryToSaveOldPresentation && 
    6491               0 :                        CanSavePresentation(LOAD_NORMAL, nsnull, nsnull);
    6492                 : 
    6493               0 :     if (mTiming) {
    6494               0 :       mTiming->NotifyUnloadAccepted(mCurrentURI);
    6495                 :     }
    6496                 : 
    6497                 :     // Make sure to blow away our mLoadingURI just in case.  No loads
    6498                 :     // from inside this pagehide.
    6499               0 :     mLoadingURI = nsnull;
    6500                 :     
    6501                 :     // Stop any in-progress loading, so that we don't accidentally trigger any
    6502                 :     // PageShow notifications from Embed() interrupting our loading below.
    6503               0 :     Stop();
    6504                 : 
    6505                 :     // Notify the current document that it is about to be unloaded!!
    6506                 :     //
    6507                 :     // It is important to fire the unload() notification *before* any state
    6508                 :     // is changed within the DocShell - otherwise, javascript will get the
    6509                 :     // wrong information :-(
    6510                 :     //
    6511               0 :     (void) FirePageHideNotification(!mSavingOldViewer);
    6512                 :   }
    6513                 : 
    6514                 :   // Now make sure we don't think we're in the middle of firing unload after
    6515                 :   // this point.  This will make us fire unload when the about:blank document
    6516                 :   // unloads... but that's ok, more or less.  Would be nice if it fired load
    6517                 :   // too, of course.
    6518               0 :   mFiredUnloadEvent = false;
    6519                 : 
    6520                 :   nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
    6521               0 :       nsContentUtils::FindInternalContentViewer("text/html");
    6522                 : 
    6523               0 :   if (docFactory) {
    6524                 :     // generate (about:blank) document to load
    6525               0 :     docFactory->CreateBlankDocument(mLoadGroup, aPrincipal,
    6526               0 :                                     getter_AddRefs(blankDoc));
    6527               0 :     if (blankDoc) {
    6528                 :       // Hack: set the base URI manually, since this document never
    6529                 :       // got Reset() with a channel.
    6530               0 :       blankDoc->SetBaseURI(aBaseURI);
    6531                 : 
    6532               0 :       blankDoc->SetContainer(static_cast<nsIDocShell *>(this));
    6533                 : 
    6534                 :       // create a content viewer for us and the new document
    6535               0 :       docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
    6536               0 :                     blankDoc, "view", getter_AddRefs(viewer));
    6537                 : 
    6538                 :       // hook 'em up
    6539               0 :       if (viewer) {
    6540               0 :         viewer->SetContainer(static_cast<nsIContentViewerContainer *>(this));
    6541               0 :         Embed(viewer, "", 0);
    6542                 : 
    6543               0 :         SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, true, 0);
    6544               0 :         rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
    6545                 :       }
    6546                 :     }
    6547                 :   }
    6548               0 :   mCreatingDocument = false;
    6549                 : 
    6550                 :   // The transient about:blank viewer doesn't have a session history entry.
    6551               0 :   SetHistoryEntry(&mOSHE, nsnull);
    6552                 : 
    6553               0 :   return rv;
    6554                 : }
    6555                 : 
    6556                 : NS_IMETHODIMP
    6557               0 : nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal)
    6558                 : {
    6559               0 :     return CreateAboutBlankContentViewer(aPrincipal, nsnull);
    6560                 : }
    6561                 : 
    6562                 : bool
    6563               0 : nsDocShell::CanSavePresentation(PRUint32 aLoadType,
    6564                 :                                 nsIRequest *aNewRequest,
    6565                 :                                 nsIDocument *aNewDocument)
    6566                 : {
    6567               0 :     if (!mOSHE)
    6568               0 :         return false; // no entry to save into
    6569                 : 
    6570               0 :     nsCOMPtr<nsIContentViewer> viewer;
    6571               0 :     mOSHE->GetContentViewer(getter_AddRefs(viewer));
    6572               0 :     if (viewer) {
    6573               0 :         NS_WARNING("mOSHE already has a content viewer!");
    6574               0 :         return false;
    6575                 :     }
    6576                 : 
    6577                 :     // Only save presentation for "normal" loads and link loads.  Anything else
    6578                 :     // probably wants to refetch the page, so caching the old presentation
    6579                 :     // would be incorrect.
    6580               0 :     if (aLoadType != LOAD_NORMAL &&
    6581                 :         aLoadType != LOAD_HISTORY &&
    6582                 :         aLoadType != LOAD_LINK &&
    6583                 :         aLoadType != LOAD_STOP_CONTENT &&
    6584                 :         aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
    6585                 :         aLoadType != LOAD_ERROR_PAGE)
    6586               0 :         return false;
    6587                 : 
    6588                 :     // If the session history entry has the saveLayoutState flag set to false,
    6589                 :     // then we should not cache the presentation.
    6590                 :     bool canSaveState;
    6591               0 :     mOSHE->GetSaveLayoutStateFlag(&canSaveState);
    6592               0 :     if (!canSaveState)
    6593               0 :         return false;
    6594                 : 
    6595                 :     // If the document is not done loading, don't cache it.
    6596               0 :     nsCOMPtr<nsPIDOMWindow> pWin = do_QueryInterface(mScriptGlobal);
    6597               0 :     if (!pWin || pWin->IsLoading())
    6598               0 :         return false;
    6599                 : 
    6600               0 :     if (pWin->WouldReuseInnerWindow(aNewDocument))
    6601               0 :         return false;
    6602                 : 
    6603                 :     // Avoid doing the work of saving the presentation state in the case where
    6604                 :     // the content viewer cache is disabled.
    6605               0 :     if (nsSHistory::GetMaxTotalViewers() == 0)
    6606               0 :         return false;
    6607                 : 
    6608                 :     // Don't cache the content viewer if we're in a subframe and the subframe
    6609                 :     // pref is disabled.
    6610                 :     bool cacheFrames =
    6611                 :         Preferences::GetBool("browser.sessionhistory.cache_subframes",
    6612               0 :                              false);
    6613               0 :     if (!cacheFrames) {
    6614               0 :         nsCOMPtr<nsIDocShellTreeItem> root;
    6615               0 :         GetSameTypeParent(getter_AddRefs(root));
    6616               0 :         if (root && root != this) {
    6617               0 :             return false;  // this is a subframe load
    6618                 :         }
    6619                 :     }
    6620                 : 
    6621                 :     // If the document does not want its presentation cached, then don't.
    6622               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(pWin->GetExtantDocument());
    6623               0 :     if (!doc || !doc->CanSavePresentation(aNewRequest))
    6624               0 :         return false;
    6625                 : 
    6626               0 :     return true;
    6627                 : }
    6628                 : 
    6629                 : void
    6630               0 : nsDocShell::ReattachEditorToWindow(nsISHEntry *aSHEntry)
    6631                 : {
    6632               0 :     NS_ASSERTION(!mEditorData,
    6633                 :                  "Why reattach an editor when we already have one?");
    6634               0 :     NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
    6635                 :                  "Reattaching when there's not a detached editor.");
    6636                 : 
    6637               0 :     if (mEditorData || !aSHEntry)
    6638               0 :         return;
    6639                 : 
    6640               0 :     mEditorData = aSHEntry->ForgetEditorData();
    6641               0 :     if (mEditorData) {
    6642                 : #ifdef DEBUG
    6643                 :         nsresult rv =
    6644                 : #endif
    6645               0 :         mEditorData->ReattachToWindow(this);
    6646               0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
    6647                 :     }
    6648                 : }
    6649                 : 
    6650                 : void
    6651               0 : nsDocShell::DetachEditorFromWindow()
    6652                 : {
    6653               0 :     if (!mEditorData || mEditorData->WaitingForLoad()) {
    6654                 :         // If there's nothing to detach, or if the editor data is actually set
    6655                 :         // up for the _new_ page that's coming in, don't detach.
    6656               0 :         return;
    6657                 :     }
    6658                 : 
    6659               0 :     NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
    6660                 :                  "Detaching editor when it's already detached.");
    6661                 : 
    6662               0 :     nsresult res = mEditorData->DetachFromWindow();
    6663               0 :     NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
    6664                 : 
    6665               0 :     if (NS_SUCCEEDED(res)) {
    6666                 :         // Make mOSHE hold the owning ref to the editor data.
    6667               0 :         if (mOSHE)
    6668               0 :             mOSHE->SetEditorData(mEditorData.forget());
    6669                 :         else
    6670               0 :             mEditorData = nsnull;
    6671                 :     }
    6672                 : 
    6673                 : #ifdef DEBUG
    6674                 :     {
    6675                 :         bool isEditable;
    6676               0 :         GetEditable(&isEditable);
    6677               0 :         NS_ASSERTION(!isEditable,
    6678                 :                      "Window is still editable after detaching editor.");
    6679                 :     }
    6680                 : #endif // DEBUG
    6681                 : }
    6682                 : 
    6683                 : nsresult
    6684               0 : nsDocShell::CaptureState()
    6685                 : {
    6686               0 :     if (!mOSHE || mOSHE == mLSHE) {
    6687                 :         // No entry to save into, or we're replacing the existing entry.
    6688               0 :         return NS_ERROR_FAILURE;
    6689                 :     }
    6690                 : 
    6691               0 :     nsCOMPtr<nsPIDOMWindow> privWin = do_QueryInterface(mScriptGlobal);
    6692               0 :     if (!privWin)
    6693               0 :         return NS_ERROR_FAILURE;
    6694                 : 
    6695               0 :     nsCOMPtr<nsISupports> windowState;
    6696               0 :     nsresult rv = privWin->SaveWindowState(getter_AddRefs(windowState));
    6697               0 :     NS_ENSURE_SUCCESS(rv, rv);
    6698                 : 
    6699                 : #ifdef DEBUG_PAGE_CACHE
    6700                 :     nsCOMPtr<nsIURI> uri;
    6701                 :     mOSHE->GetURI(getter_AddRefs(uri));
    6702                 :     nsCAutoString spec;
    6703                 :     if (uri)
    6704                 :         uri->GetSpec(spec);
    6705                 :     printf("Saving presentation into session history\n");
    6706                 :     printf("  SH URI: %s\n", spec.get());
    6707                 : #endif
    6708                 : 
    6709               0 :     rv = mOSHE->SetWindowState(windowState);
    6710               0 :     NS_ENSURE_SUCCESS(rv, rv);
    6711                 : 
    6712                 :     // Suspend refresh URIs and save off the timer queue
    6713               0 :     rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
    6714               0 :     NS_ENSURE_SUCCESS(rv, rv);
    6715                 : 
    6716                 :     // Capture the current content viewer bounds.
    6717               0 :     if (mContentViewer) {
    6718               0 :         nsIntRect bounds;
    6719               0 :         mContentViewer->GetBounds(bounds);
    6720               0 :         rv = mOSHE->SetViewerBounds(bounds);
    6721               0 :         NS_ENSURE_SUCCESS(rv, rv);
    6722                 :     }
    6723                 : 
    6724                 :     // Capture the docshell hierarchy.
    6725               0 :     mOSHE->ClearChildShells();
    6726                 : 
    6727               0 :     PRInt32 childCount = mChildList.Count();
    6728               0 :     for (PRInt32 i = 0; i < childCount; ++i) {
    6729               0 :         nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
    6730               0 :         NS_ASSERTION(childShell, "null child shell");
    6731                 : 
    6732               0 :         mOSHE->AddChildShell(childShell);
    6733                 :     }
    6734                 : 
    6735               0 :     return NS_OK;
    6736                 : }
    6737                 : 
    6738                 : NS_IMETHODIMP
    6739               0 : nsDocShell::RestorePresentationEvent::Run()
    6740                 : {
    6741               0 :     if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory()))
    6742               0 :         NS_WARNING("RestoreFromHistory failed");
    6743               0 :     return NS_OK;
    6744                 : }
    6745                 : 
    6746                 : NS_IMETHODIMP
    6747               0 : nsDocShell::BeginRestore(nsIContentViewer *aContentViewer, bool aTop)
    6748                 : {
    6749                 :     nsresult rv;
    6750               0 :     if (!aContentViewer) {
    6751               0 :         rv = EnsureContentViewer();
    6752               0 :         NS_ENSURE_SUCCESS(rv, rv);
    6753                 : 
    6754               0 :         aContentViewer = mContentViewer;
    6755                 :     }
    6756                 : 
    6757                 :     // Dispatch events for restoring the presentation.  We try to simulate
    6758                 :     // the progress notifications loading the document would cause, so we add
    6759                 :     // the document's channel to the loadgroup to initiate stateChange
    6760                 :     // notifications.
    6761                 : 
    6762               0 :     nsCOMPtr<nsIDOMDocument> domDoc;
    6763               0 :     aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
    6764               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
    6765               0 :     if (doc) {
    6766               0 :         nsIChannel *channel = doc->GetChannel();
    6767               0 :         if (channel) {
    6768               0 :             mEODForCurrentDocument = false;
    6769               0 :             mIsRestoringDocument = true;
    6770               0 :             mLoadGroup->AddRequest(channel, nsnull);
    6771               0 :             mIsRestoringDocument = false;
    6772                 :         }
    6773                 :     }
    6774                 : 
    6775               0 :     if (!aTop) {
    6776                 :         // This point corresponds to us having gotten OnStartRequest or
    6777                 :         // STATE_START, so do the same thing that CreateContentViewer does at
    6778                 :         // this point to ensure that unload/pagehide events for this document
    6779                 :         // will fire when it's unloaded again.
    6780               0 :         mFiredUnloadEvent = false;
    6781                 : 
    6782                 :         // For non-top frames, there is no notion of making sure that the
    6783                 :         // previous document is in the domwindow when STATE_START notifications
    6784                 :         // happen.  We can just call BeginRestore for all of the child shells
    6785                 :         // now.
    6786               0 :         rv = BeginRestoreChildren();
    6787               0 :         NS_ENSURE_SUCCESS(rv, rv);
    6788                 :     }
    6789                 : 
    6790               0 :     return NS_OK;
    6791                 : }
    6792                 : 
    6793                 : nsresult
    6794               0 : nsDocShell::BeginRestoreChildren()
    6795                 : {
    6796               0 :     PRInt32 n = mChildList.Count();
    6797               0 :     for (PRInt32 i = 0; i < n; ++i) {
    6798               0 :         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
    6799               0 :         if (child) {
    6800               0 :             nsresult rv = child->BeginRestore(nsnull, false);
    6801               0 :             NS_ENSURE_SUCCESS(rv, rv);
    6802                 :         }
    6803                 :     }
    6804               0 :     return NS_OK;
    6805                 : }
    6806                 : 
    6807                 : NS_IMETHODIMP
    6808               0 : nsDocShell::FinishRestore()
    6809                 : {
    6810                 :     // First we call finishRestore() on our children.  In the simulated load,
    6811                 :     // all of the child frames finish loading before the main document.
    6812                 : 
    6813               0 :     PRInt32 n = mChildList.Count();
    6814               0 :     for (PRInt32 i = 0; i < n; ++i) {
    6815               0 :         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
    6816               0 :         if (child) {
    6817               0 :             child->FinishRestore();
    6818                 :         }
    6819                 :     }
    6820                 : 
    6821               0 :     if (mOSHE && mOSHE->HasDetachedEditor()) {
    6822               0 :       ReattachEditorToWindow(mOSHE);
    6823                 :     }
    6824                 : 
    6825               0 :     nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
    6826               0 :     if (doc) {
    6827                 :         // Finally, we remove the request from the loadgroup.  This will
    6828                 :         // cause onStateChange(STATE_STOP) to fire, which will fire the
    6829                 :         // pageshow event to the chrome.
    6830                 : 
    6831               0 :         nsIChannel *channel = doc->GetChannel();
    6832               0 :         if (channel) {
    6833               0 :             mIsRestoringDocument = true;
    6834               0 :             mLoadGroup->RemoveRequest(channel, nsnull, NS_OK);
    6835               0 :             mIsRestoringDocument = false;
    6836                 :         }
    6837                 :     }
    6838                 : 
    6839               0 :     return NS_OK;
    6840                 : }
    6841                 : 
    6842                 : NS_IMETHODIMP
    6843               0 : nsDocShell::GetRestoringDocument(bool *aRestoring)
    6844                 : {
    6845               0 :     *aRestoring = mIsRestoringDocument;
    6846               0 :     return NS_OK;
    6847                 : }
    6848                 : 
    6849                 : nsresult
    6850               0 : nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, bool *aRestoring)
    6851                 : {
    6852               0 :     NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
    6853                 :                  "RestorePresentation should only be called for history loads");
    6854                 : 
    6855               0 :     nsCOMPtr<nsIContentViewer> viewer;
    6856               0 :     aSHEntry->GetContentViewer(getter_AddRefs(viewer));
    6857                 : 
    6858                 : #ifdef DEBUG_PAGE_CACHE
    6859                 :     nsCOMPtr<nsIURI> uri;
    6860                 :     aSHEntry->GetURI(getter_AddRefs(uri));
    6861                 : 
    6862                 :     nsCAutoString spec;
    6863                 :     if (uri)
    6864                 :         uri->GetSpec(spec);
    6865                 : #endif
    6866                 : 
    6867               0 :     *aRestoring = false;
    6868                 : 
    6869               0 :     if (!viewer) {
    6870                 : #ifdef DEBUG_PAGE_CACHE
    6871                 :         printf("no saved presentation for uri: %s\n", spec.get());
    6872                 : #endif
    6873               0 :         return NS_OK;
    6874                 :     }
    6875                 : 
    6876                 :     // We need to make sure the content viewer's container is this docshell.
    6877                 :     // In subframe navigation, it's possible for the docshell that the
    6878                 :     // content viewer was originally loaded into to be replaced with a
    6879                 :     // different one.  We don't currently support restoring the presentation
    6880                 :     // in that case.
    6881                 : 
    6882               0 :     nsCOMPtr<nsISupports> container;
    6883               0 :     viewer->GetContainer(getter_AddRefs(container));
    6884               0 :     if (!::SameCOMIdentity(container, GetAsSupports(this))) {
    6885                 : #ifdef DEBUG_PAGE_CACHE
    6886                 :         printf("No valid container, clearing presentation\n");
    6887                 : #endif
    6888               0 :         aSHEntry->SetContentViewer(nsnull);
    6889               0 :         return NS_ERROR_FAILURE;
    6890                 :     }
    6891                 : 
    6892               0 :     NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
    6893                 : 
    6894                 : #ifdef DEBUG_PAGE_CACHE
    6895                 :     printf("restoring presentation from session history: %s\n", spec.get());
    6896                 : #endif
    6897                 : 
    6898               0 :     SetHistoryEntry(&mLSHE, aSHEntry);
    6899                 : 
    6900                 :     // Add the request to our load group.  We do this before swapping out
    6901                 :     // the content viewers so that consumers of STATE_START can access
    6902                 :     // the old document.  We only deal with the toplevel load at this time --
    6903                 :     // to be consistent with normal document loading, subframes cannot start
    6904                 :     // loading until after data arrives, which is after STATE_START completes.
    6905                 : 
    6906               0 :     BeginRestore(viewer, true);
    6907                 : 
    6908                 :     // Post an event that will remove the request after we've returned
    6909                 :     // to the event loop.  This mimics the way it is called by nsIChannel
    6910                 :     // implementations.
    6911                 : 
    6912                 :     // Revoke any pending restore (just in case)
    6913               0 :     NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
    6914                 :         "should only have one RestorePresentationEvent");
    6915               0 :     mRestorePresentationEvent.Revoke();
    6916                 : 
    6917               0 :     nsRefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
    6918               0 :     nsresult rv = NS_DispatchToCurrentThread(evt);
    6919               0 :     if (NS_SUCCEEDED(rv)) {
    6920               0 :         mRestorePresentationEvent = evt.get();
    6921                 :         // The rest of the restore processing will happen on our event
    6922                 :         // callback.
    6923               0 :         *aRestoring = true;
    6924                 :     }
    6925                 : 
    6926               0 :     return rv;
    6927                 : }
    6928                 : 
    6929                 : nsresult
    6930               0 : nsDocShell::RestoreFromHistory()
    6931                 : {
    6932               0 :     mRestorePresentationEvent.Forget();
    6933                 : 
    6934                 :     // This section of code follows the same ordering as CreateContentViewer.
    6935               0 :     if (!mLSHE)
    6936               0 :         return NS_ERROR_FAILURE;
    6937                 : 
    6938               0 :     nsCOMPtr<nsIContentViewer> viewer;
    6939               0 :     mLSHE->GetContentViewer(getter_AddRefs(viewer));
    6940               0 :     if (!viewer)
    6941               0 :         return NS_ERROR_FAILURE;
    6942                 : 
    6943               0 :     if (mSavingOldViewer) {
    6944                 :         // We determined that it was safe to cache the document presentation
    6945                 :         // at the time we initiated the new load.  We need to check whether
    6946                 :         // it's still safe to do so, since there may have been DOM mutations
    6947                 :         // or new requests initiated.
    6948               0 :         nsCOMPtr<nsIDOMDocument> domDoc;
    6949               0 :         viewer->GetDOMDocument(getter_AddRefs(domDoc));
    6950               0 :         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
    6951               0 :         nsIRequest *request = nsnull;
    6952               0 :         if (doc)
    6953               0 :             request = doc->GetChannel();
    6954               0 :         mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
    6955                 :     }
    6956                 : 
    6957                 :     nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV(
    6958               0 :         do_QueryInterface(mContentViewer));
    6959                 :     nsCOMPtr<nsIMarkupDocumentViewer> newMUDV(
    6960               0 :         do_QueryInterface(viewer));
    6961               0 :     PRInt32 minFontSize = 0;
    6962               0 :     float textZoom = 1.0f;
    6963               0 :     float pageZoom = 1.0f;
    6964               0 :     bool styleDisabled = false;
    6965               0 :     if (oldMUDV && newMUDV) {
    6966               0 :         oldMUDV->GetMinFontSize(&minFontSize);
    6967               0 :         oldMUDV->GetTextZoom(&textZoom);
    6968               0 :         oldMUDV->GetFullZoom(&pageZoom);
    6969               0 :         oldMUDV->GetAuthorStyleDisabled(&styleDisabled);
    6970                 :     }
    6971                 : 
    6972                 :     // Protect against mLSHE going away via a load triggered from
    6973                 :     // pagehide or unload.
    6974               0 :     nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
    6975                 : 
    6976                 :     // Make sure to blow away our mLoadingURI just in case.  No loads
    6977                 :     // from inside this pagehide.
    6978               0 :     mLoadingURI = nsnull;
    6979                 :     
    6980                 :     // Notify the old content viewer that it's being hidden.
    6981               0 :     FirePageHideNotification(!mSavingOldViewer);
    6982                 : 
    6983                 :     // If mLSHE was changed as a result of the pagehide event, then
    6984                 :     // something else was loaded.  Don't finish restoring.
    6985               0 :     if (mLSHE != origLSHE)
    6986               0 :       return NS_OK;
    6987                 : 
    6988                 :     // Set mFiredUnloadEvent = false so that the unload handler for the
    6989                 :     // *new* document will fire.
    6990               0 :     mFiredUnloadEvent = false;
    6991                 : 
    6992               0 :     mURIResultedInDocument = true;
    6993               0 :     nsCOMPtr<nsISHistory> rootSH;
    6994               0 :     GetRootSessionHistory(getter_AddRefs(rootSH));
    6995               0 :     if (rootSH) {
    6996               0 :         nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
    6997               0 :         rootSH->GetIndex(&mPreviousTransIndex);
    6998               0 :         hist->UpdateIndex();
    6999               0 :         rootSH->GetIndex(&mLoadedTransIndex);
    7000                 : #ifdef DEBUG_PAGE_CACHE
    7001                 :         printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
    7002                 :                    mLoadedTransIndex);
    7003                 : #endif
    7004                 :     }
    7005                 : 
    7006                 :     // Rather than call Embed(), we will retrieve the viewer from the session
    7007                 :     // history entry and swap it in.
    7008                 :     // XXX can we refactor this so that we can just call Embed()?
    7009               0 :     PersistLayoutHistoryState();
    7010                 :     nsresult rv;
    7011               0 :     if (mContentViewer) {
    7012               0 :         if (mSavingOldViewer && NS_FAILED(CaptureState())) {
    7013               0 :             if (mOSHE) {
    7014               0 :                 mOSHE->SyncPresentationState();
    7015                 :             }
    7016               0 :             mSavingOldViewer = false;
    7017                 :         }
    7018                 :     }
    7019                 : 
    7020               0 :     mSavedRefreshURIList = nsnull;
    7021                 : 
    7022                 :     // In cases where we use a transient about:blank viewer between loads,
    7023                 :     // we never show the transient viewer, so _its_ previous viewer is never
    7024                 :     // unhooked from the view hierarchy.  Destroy any such previous viewer now,
    7025                 :     // before we grab the root view sibling, so that we don't grab a view
    7026                 :     // that's about to go away.
    7027                 : 
    7028               0 :     if (mContentViewer) {
    7029               0 :         nsCOMPtr<nsIContentViewer> previousViewer;
    7030               0 :         mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
    7031               0 :         if (previousViewer) {
    7032               0 :             mContentViewer->SetPreviousViewer(nsnull);
    7033               0 :             previousViewer->Destroy();
    7034                 :         }
    7035                 :     }
    7036                 : 
    7037                 :     // Save off the root view's parent and sibling so that we can insert the
    7038                 :     // new content viewer's root view at the same position.  Also save the
    7039                 :     // bounds of the root view's widget.
    7040                 : 
    7041               0 :     nsIView *rootViewSibling = nsnull, *rootViewParent = nsnull;
    7042               0 :     nsIntRect newBounds(0, 0, 0, 0);
    7043                 : 
    7044               0 :     nsCOMPtr<nsIPresShell> oldPresShell;
    7045               0 :     nsDocShell::GetPresShell(getter_AddRefs(oldPresShell));
    7046               0 :     if (oldPresShell) {
    7047               0 :         nsIViewManager *vm = oldPresShell->GetViewManager();
    7048               0 :         if (vm) {
    7049               0 :             nsIView *oldRootView = vm->GetRootView();
    7050                 : 
    7051               0 :             if (oldRootView) {
    7052               0 :                 rootViewSibling = oldRootView->GetNextSibling();
    7053               0 :                 rootViewParent = oldRootView->GetParent();
    7054                 : 
    7055               0 :                 mContentViewer->GetBounds(newBounds);
    7056                 :             }
    7057                 :         }
    7058                 :     }
    7059                 : 
    7060                 :     // Transfer ownership to mContentViewer.  By ensuring that either the
    7061                 :     // docshell or the session history, but not both, have references to the
    7062                 :     // content viewer, we prevent the viewer from being torn down after
    7063                 :     // Destroy() is called.
    7064                 : 
    7065               0 :     if (mContentViewer) {
    7066               0 :         mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull);
    7067               0 :         viewer->SetPreviousViewer(mContentViewer);
    7068                 :     }
    7069               0 :     if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
    7070                 :         // We don't plan to save a viewer in mOSHE; tell it to drop
    7071                 :         // any other state it's holding.
    7072               0 :         mOSHE->SyncPresentationState();
    7073                 :     }
    7074                 : 
    7075                 :     // Order the mContentViewer setup just like Embed does.
    7076               0 :     mContentViewer = nsnull;
    7077                 : 
    7078                 :     // Now that we're about to switch documents, forget all of our children.
    7079                 :     // Note that we cached them as needed up in CaptureState above.
    7080               0 :     DestroyChildren();
    7081                 : 
    7082               0 :     mContentViewer.swap(viewer);
    7083                 : 
    7084                 :     // Grab all of the related presentation from the SHEntry now.
    7085                 :     // Clearing the viewer from the SHEntry will clear all of this state.
    7086               0 :     nsCOMPtr<nsISupports> windowState;
    7087               0 :     mLSHE->GetWindowState(getter_AddRefs(windowState));
    7088               0 :     mLSHE->SetWindowState(nsnull);
    7089                 : 
    7090                 :     bool sticky;
    7091               0 :     mLSHE->GetSticky(&sticky);
    7092                 : 
    7093               0 :     nsCOMPtr<nsIDOMDocument> domDoc;
    7094               0 :     mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
    7095                 : 
    7096               0 :     nsCOMArray<nsIDocShellTreeItem> childShells;
    7097               0 :     PRInt32 i = 0;
    7098               0 :     nsCOMPtr<nsIDocShellTreeItem> child;
    7099               0 :     while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
    7100               0 :            child) {
    7101               0 :         childShells.AppendObject(child);
    7102                 :     }
    7103                 : 
    7104                 :     // get the previous content viewer size
    7105               0 :     nsIntRect oldBounds(0, 0, 0, 0);
    7106               0 :     mLSHE->GetViewerBounds(oldBounds);
    7107                 : 
    7108                 :     // Restore the refresh URI list.  The refresh timers will be restarted
    7109                 :     // when EndPageLoad() is called.
    7110               0 :     nsCOMPtr<nsISupportsArray> refreshURIList;
    7111               0 :     mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
    7112                 : 
    7113                 :     // Reattach to the window object.
    7114               0 :     rv = mContentViewer->Open(windowState, mLSHE);
    7115                 : 
    7116                 :     // Hack to keep nsDocShellEditorData alive across the
    7117                 :     // SetContentViewer(nsnull) call below.
    7118               0 :     nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
    7119                 : 
    7120                 :     // Now remove it from the cached presentation.
    7121               0 :     mLSHE->SetContentViewer(nsnull);
    7122               0 :     mEODForCurrentDocument = false;
    7123                 : 
    7124               0 :     mLSHE->SetEditorData(data.forget());
    7125                 : 
    7126                 : #ifdef DEBUG
    7127                 :  {
    7128               0 :      nsCOMPtr<nsISupportsArray> refreshURIs;
    7129               0 :      mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
    7130               0 :      nsCOMPtr<nsIDocShellTreeItem> childShell;
    7131               0 :      mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
    7132               0 :      NS_ASSERTION(!refreshURIs && !childShell,
    7133                 :                   "SHEntry should have cleared presentation state");
    7134                 :  }
    7135                 : #endif
    7136                 : 
    7137                 :     // Restore the sticky state of the viewer.  The viewer has set this state
    7138                 :     // on the history entry in Destroy() just before marking itself non-sticky,
    7139                 :     // to avoid teardown of the presentation.
    7140               0 :     mContentViewer->SetSticky(sticky);
    7141                 : 
    7142               0 :     NS_ENSURE_SUCCESS(rv, rv);
    7143                 : 
    7144                 :     // mLSHE is now our currently-loaded document.
    7145               0 :     SetHistoryEntry(&mOSHE, mLSHE);
    7146                 :     
    7147                 :     // XXX special wyciwyg handling in Embed()?
    7148                 : 
    7149                 :     // We aren't going to restore any items from the LayoutHistoryState,
    7150                 :     // but we don't want them to stay around in case the page is reloaded.
    7151               0 :     SetLayoutHistoryState(nsnull);
    7152                 : 
    7153                 :     // This is the end of our Embed() replacement
    7154                 : 
    7155               0 :     mSavingOldViewer = false;
    7156               0 :     mEODForCurrentDocument = false;
    7157                 : 
    7158                 :     // Tell the event loop to favor plevents over user events, see comments
    7159                 :     // in CreateContentViewer.
    7160               0 :     if (++gNumberOfDocumentsLoading == 1)
    7161               0 :         FavorPerformanceHint(true, NS_EVENT_STARVATION_DELAY_HINT);
    7162                 : 
    7163                 : 
    7164               0 :     if (oldMUDV && newMUDV) {
    7165               0 :         newMUDV->SetMinFontSize(minFontSize);
    7166               0 :         newMUDV->SetTextZoom(textZoom);
    7167               0 :         newMUDV->SetFullZoom(pageZoom);
    7168               0 :         newMUDV->SetAuthorStyleDisabled(styleDisabled);
    7169                 :     }
    7170                 : 
    7171               0 :     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
    7172               0 :     PRUint32 parentSuspendCount = 0;
    7173               0 :     if (document) {
    7174               0 :         nsCOMPtr<nsIDocShellTreeItem> parent;
    7175               0 :         GetParent(getter_AddRefs(parent));
    7176               0 :         nsCOMPtr<nsIDocument> d = do_GetInterface(parent);
    7177               0 :         if (d) {
    7178               0 :             if (d->EventHandlingSuppressed()) {
    7179               0 :                 document->SuppressEventHandling(d->EventHandlingSuppressed());
    7180                 :             }
    7181               0 :             nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
    7182               0 :             if (parentWindow) {
    7183               0 :                 parentSuspendCount = parentWindow->TimeoutSuspendCount();
    7184                 :             }
    7185                 :         }
    7186                 : 
    7187                 :         // Use the uri from the mLSHE we had when we entered this function
    7188                 :         // (which need not match the document's URI if anchors are involved),
    7189                 :         // since that's the history entry we're loading.  Note that if we use
    7190                 :         // origLSHE we don't have to worry about whether the entry in question
    7191                 :         // is still mLSHE or whether it's now mOSHE.
    7192               0 :         nsCOMPtr<nsIURI> uri;
    7193               0 :         origLSHE->GetURI(getter_AddRefs(uri));
    7194               0 :         SetCurrentURI(uri, document->GetChannel(), true, 0);
    7195                 :     }
    7196                 : 
    7197                 :     // This is the end of our CreateContentViewer() replacement.
    7198                 :     // Now we simulate a load.  First, we restore the state of the javascript
    7199                 :     // window object.
    7200                 :     nsCOMPtr<nsPIDOMWindow> privWin =
    7201               0 :         do_GetInterface(static_cast<nsIInterfaceRequestor*>(this));
    7202               0 :     NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
    7203                 : 
    7204               0 :     rv = privWin->RestoreWindowState(windowState);
    7205               0 :     NS_ENSURE_SUCCESS(rv, rv);
    7206                 : 
    7207                 :     // Now, dispatch a title change event which would happen as the
    7208                 :     // <head> is parsed.
    7209               0 :     document->NotifyPossibleTitleChange(false);
    7210                 : 
    7211                 :     // Now we simulate appending child docshells for subframes.
    7212               0 :     for (i = 0; i < childShells.Count(); ++i) {
    7213               0 :         nsIDocShellTreeItem *childItem = childShells.ObjectAt(i);
    7214               0 :         nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
    7215                 : 
    7216                 :         // Make sure to not clobber the state of the child.  Since AddChild
    7217                 :         // always clobbers it, save it off first.
    7218                 :         bool allowPlugins;
    7219               0 :         childShell->GetAllowPlugins(&allowPlugins);
    7220                 : 
    7221                 :         bool allowJavascript;
    7222               0 :         childShell->GetAllowJavascript(&allowJavascript);
    7223                 : 
    7224                 :         bool allowRedirects;
    7225               0 :         childShell->GetAllowMetaRedirects(&allowRedirects);
    7226                 : 
    7227                 :         bool allowSubframes;
    7228               0 :         childShell->GetAllowSubframes(&allowSubframes);
    7229                 : 
    7230                 :         bool allowImages;
    7231               0 :         childShell->GetAllowImages(&allowImages);
    7232                 : 
    7233                 :         bool allowDNSPrefetch;
    7234               0 :         childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
    7235                 : 
    7236                 :         // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
    7237                 :         // that the child inherits our state. Among other things, this means
    7238                 :         // that the child inherits our mIsActive and mInPrivateBrowsing, which
    7239                 :         // is what we want.
    7240               0 :         AddChild(childItem);
    7241                 : 
    7242               0 :         childShell->SetAllowPlugins(allowPlugins);
    7243               0 :         childShell->SetAllowJavascript(allowJavascript);
    7244               0 :         childShell->SetAllowMetaRedirects(allowRedirects);
    7245               0 :         childShell->SetAllowSubframes(allowSubframes);
    7246               0 :         childShell->SetAllowImages(allowImages);
    7247               0 :         childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
    7248                 : 
    7249               0 :         rv = childShell->BeginRestore(nsnull, false);
    7250               0 :         NS_ENSURE_SUCCESS(rv, rv);
    7251                 :     }
    7252                 : 
    7253               0 :     nsCOMPtr<nsIPresShell> shell;
    7254               0 :     nsDocShell::GetPresShell(getter_AddRefs(shell));
    7255                 : 
    7256               0 :     nsIViewManager *newVM = shell ? shell->GetViewManager() : nsnull;
    7257               0 :     nsIView *newRootView = newVM ? newVM->GetRootView() : nsnull;
    7258                 : 
    7259                 :     // Insert the new root view at the correct location in the view tree.
    7260               0 :     if (rootViewParent) {
    7261               0 :         nsIViewManager *parentVM = rootViewParent->GetViewManager();
    7262                 : 
    7263               0 :         if (parentVM && newRootView) {
    7264                 :             // InsertChild(parent, child, sib, true) inserts the child after
    7265                 :             // sib in content order, which is before sib in view order. BUT
    7266                 :             // when sib is null it inserts at the end of the the document
    7267                 :             // order, i.e., first in view order.  But when oldRootSibling is
    7268                 :             // null, the old root as at the end of the view list --- last in
    7269                 :             // content order --- and we want to call InsertChild(parent, child,
    7270                 :             // nsnull, false) in that case.
    7271                 :             parentVM->InsertChild(rootViewParent, newRootView,
    7272                 :                                   rootViewSibling,
    7273               0 :                                   rootViewSibling ? true : false);
    7274                 : 
    7275               0 :             NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
    7276                 :                          "error in InsertChild");
    7277                 :         }
    7278                 :     }
    7279                 : 
    7280                 :     // If parent is suspended, increase suspension count.
    7281                 :     // This can't be done as early as event suppression since this
    7282                 :     // depends on docshell tree.
    7283               0 :     if (parentSuspendCount) {
    7284               0 :       privWin->SuspendTimeouts(parentSuspendCount, false);
    7285                 :     }
    7286                 : 
    7287                 :     // Now that all of the child docshells have been put into place, we can
    7288                 :     // restart the timers for the window and all of the child frames.
    7289               0 :     privWin->ResumeTimeouts();
    7290                 : 
    7291                 :     // Restore the refresh URI list.  The refresh timers will be restarted
    7292                 :     // when EndPageLoad() is called.
    7293               0 :     mRefreshURIList = refreshURIList;
    7294                 : 
    7295                 :     // Meta-refresh timers have been restarted for this shell, but not
    7296                 :     // for our children.  Walk the child shells and restart their timers.
    7297               0 :     PRInt32 n = mChildList.Count();
    7298               0 :     for (i = 0; i < n; ++i) {
    7299               0 :         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
    7300               0 :         if (child)
    7301               0 :             child->ResumeRefreshURIs();
    7302                 :     }
    7303                 : 
    7304                 :     // Make sure this presentation is the same size as the previous
    7305                 :     // presentation.  If this is not the same size we showed it at last time,
    7306                 :     // then we need to resize the widget.
    7307                 : 
    7308                 :     // XXXbryner   This interacts poorly with Firefox's infobar.  If the old
    7309                 :     // presentation had the infobar visible, then we will resize the new
    7310                 :     // presentation to that smaller size.  However, firing the locationchanged
    7311                 :     // event will hide the infobar, which will immediately resize the window
    7312                 :     // back to the larger size.  A future optimization might be to restore
    7313                 :     // the presentation at the "wrong" size, then fire the locationchanged
    7314                 :     // event and check whether the docshell's new size is the same as the
    7315                 :     // cached viewer size (skipping the resize if they are equal).
    7316                 : 
    7317               0 :     if (newRootView) {
    7318               0 :         if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
    7319                 : #ifdef DEBUG_PAGE_CACHE
    7320                 :             printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
    7321                 :                    newBounds.y, newBounds.width, newBounds.height);
    7322                 : #endif
    7323               0 :             mContentViewer->SetBounds(newBounds);
    7324                 :         } else {
    7325                 :             nsIScrollableFrame *rootScrollFrame =
    7326               0 :               shell->GetRootScrollFrameAsScrollableExternal();
    7327               0 :             if (rootScrollFrame) {
    7328               0 :                 rootScrollFrame->PostScrolledAreaEventForCurrentArea();
    7329                 :             }
    7330                 :         }
    7331                 :     }
    7332                 : 
    7333                 :     // The FinishRestore call below can kill these, null them out so we don't
    7334                 :     // have invalid pointer lying around.
    7335               0 :     newRootView = rootViewSibling = rootViewParent = nsnull;
    7336               0 :     newVM = nsnull;
    7337                 : 
    7338                 :     // Simulate the completion of the load.
    7339               0 :     nsDocShell::FinishRestore();
    7340                 : 
    7341                 :     // Restart plugins, and paint the content.
    7342               0 :     if (shell) {
    7343               0 :         shell->Thaw();
    7344                 : 
    7345               0 :         newVM = shell->GetViewManager();
    7346               0 :         if (newVM) {
    7347                 :             // When we insert the root view above the resulting invalidate is
    7348                 :             // dropped because painting is suppressed in the presshell until we
    7349                 :             // call Thaw. So we issue the invalidate here.
    7350               0 :             newRootView = newVM->GetRootView();
    7351               0 :             if (newRootView) {
    7352               0 :                 newVM->InvalidateView(newRootView);
    7353                 :             }
    7354                 :         }
    7355                 :     }
    7356                 : 
    7357               0 :     return privWin->FireDelayedDOMEvents();
    7358                 : }
    7359                 : 
    7360                 : NS_IMETHODIMP
    7361               0 : nsDocShell::CreateContentViewer(const char *aContentType,
    7362                 :                                 nsIRequest * request,
    7363                 :                                 nsIStreamListener ** aContentHandler)
    7364                 : {
    7365               0 :     *aContentHandler = nsnull;
    7366                 : 
    7367                 :     // Can we check the content type of the current content viewer
    7368                 :     // and reuse it without destroying it and re-creating it?
    7369                 : 
    7370               0 :     NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
    7371                 : 
    7372                 :     // Instantiate the content viewer object
    7373               0 :     nsCOMPtr<nsIContentViewer> viewer;
    7374                 :     nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup,
    7375               0 :                                       aContentHandler, getter_AddRefs(viewer));
    7376                 : 
    7377               0 :     if (NS_FAILED(rv))
    7378               0 :         return rv;
    7379                 : 
    7380                 :     // Notify the current document that it is about to be unloaded!!
    7381                 :     //
    7382                 :     // It is important to fire the unload() notification *before* any state
    7383                 :     // is changed within the DocShell - otherwise, javascript will get the
    7384                 :     // wrong information :-(
    7385                 :     //
    7386                 : 
    7387               0 :     if (mSavingOldViewer) {
    7388                 :         // We determined that it was safe to cache the document presentation
    7389                 :         // at the time we initiated the new load.  We need to check whether
    7390                 :         // it's still safe to do so, since there may have been DOM mutations
    7391                 :         // or new requests initiated.
    7392               0 :         nsCOMPtr<nsIDOMDocument> domDoc;
    7393               0 :         viewer->GetDOMDocument(getter_AddRefs(domDoc));
    7394               0 :         nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
    7395               0 :         mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
    7396                 :     }
    7397                 : 
    7398               0 :     NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
    7399                 :     
    7400               0 :     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
    7401               0 :     if (aOpenedChannel) {
    7402               0 :         aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
    7403                 :     }
    7404               0 :     FirePageHideNotification(!mSavingOldViewer);
    7405               0 :     mLoadingURI = nsnull;
    7406                 : 
    7407                 :     // Set mFiredUnloadEvent = false so that the unload handler for the
    7408                 :     // *new* document will fire.
    7409               0 :     mFiredUnloadEvent = false;
    7410                 : 
    7411                 :     // we've created a new document so go ahead and call
    7412                 :     // OnLoadingSite(), but don't fire OnLocationChange()
    7413                 :     // notifications before we've called Embed(). See bug 284993.
    7414               0 :     mURIResultedInDocument = true;
    7415                 : 
    7416               0 :     if (mLoadType == LOAD_ERROR_PAGE) {
    7417                 :         // We need to set the SH entry and our current URI here and not
    7418                 :         // at the moment we load the page. We want the same behavior 
    7419                 :         // of Stop() as for a normal page load. See bug 514232 for details.
    7420                 : 
    7421                 :         // Revert mLoadType to load type to state the page load failed,
    7422                 :         // following function calls need it.
    7423               0 :         mLoadType = mFailedLoadType;
    7424                 : 
    7425               0 :         nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
    7426               0 :         nsCOMPtr<nsIURI> failedURI = mFailedURI;
    7427               0 :         mFailedChannel = nsnull;
    7428               0 :         mFailedURI = nsnull;
    7429                 : 
    7430                 :         // Create an shistory entry for the old load, if we have a channel
    7431               0 :         if (failedChannel) {
    7432               0 :             mURIResultedInDocument = true;
    7433               0 :             OnLoadingSite(failedChannel, true, false);
    7434               0 :         } else if (failedURI) {
    7435               0 :             mURIResultedInDocument = true;
    7436                 :             OnNewURI(failedURI, nsnull, nsnull, mLoadType, true, false,
    7437               0 :                      false);
    7438                 :         }
    7439                 : 
    7440                 :         // Be sure to have a correct mLSHE, it may have been cleared by
    7441                 :         // EndPageLoad. See bug 302115.
    7442               0 :         if (mSessionHistory && !mLSHE) {
    7443                 :             PRInt32 idx;
    7444               0 :             mSessionHistory->GetRequestedIndex(&idx);
    7445               0 :             if (idx == -1)
    7446               0 :                 mSessionHistory->GetIndex(&idx);
    7447                 : 
    7448               0 :             nsCOMPtr<nsIHistoryEntry> entry;
    7449               0 :             mSessionHistory->GetEntryAtIndex(idx, false,
    7450               0 :                                              getter_AddRefs(entry));
    7451               0 :             mLSHE = do_QueryInterface(entry);
    7452                 :         }
    7453                 : 
    7454                 :         // Set our current URI
    7455               0 :         SetCurrentURI(failedURI);
    7456                 : 
    7457               0 :         mLoadType = LOAD_ERROR_PAGE;
    7458                 :     }
    7459                 : 
    7460               0 :     bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
    7461                 : 
    7462                 :     // let's try resetting the load group if we need to...
    7463               0 :     nsCOMPtr<nsILoadGroup> currentLoadGroup;
    7464               0 :     NS_ENSURE_SUCCESS(aOpenedChannel->
    7465                 :                       GetLoadGroup(getter_AddRefs(currentLoadGroup)),
    7466                 :                       NS_ERROR_FAILURE);
    7467                 : 
    7468               0 :     if (currentLoadGroup != mLoadGroup) {
    7469               0 :         nsLoadFlags loadFlags = 0;
    7470                 : 
    7471                 :         //Cancel any URIs that are currently loading...
    7472                 :         /// XXX: Need to do this eventually      Stop();
    7473                 :         //
    7474                 :         // Retarget the document to this loadgroup...
    7475                 :         //
    7476                 :         /* First attach the channel to the right loadgroup
    7477                 :          * and then remove from the old loadgroup. This 
    7478                 :          * puts the notifications in the right order and
    7479                 :          * we don't null-out mLSHE in OnStateChange() for 
    7480                 :          * all redirected urls
    7481                 :          */
    7482               0 :         aOpenedChannel->SetLoadGroup(mLoadGroup);
    7483                 : 
    7484                 :         // Mark the channel as being a document URI...
    7485               0 :         aOpenedChannel->GetLoadFlags(&loadFlags);
    7486               0 :         loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
    7487                 : 
    7488               0 :         aOpenedChannel->SetLoadFlags(loadFlags);
    7489                 : 
    7490               0 :         mLoadGroup->AddRequest(request, nsnull);
    7491               0 :         if (currentLoadGroup)
    7492               0 :             currentLoadGroup->RemoveRequest(request, nsnull,
    7493               0 :                                             NS_BINDING_RETARGETED);
    7494                 : 
    7495                 :         // Update the notification callbacks, so that progress and
    7496                 :         // status information are sent to the right docshell...
    7497               0 :         aOpenedChannel->SetNotificationCallbacks(this);
    7498                 :     }
    7499                 : 
    7500               0 :     NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull),
    7501                 :                       NS_ERROR_FAILURE);
    7502                 : 
    7503               0 :     mSavedRefreshURIList = nsnull;
    7504               0 :     mSavingOldViewer = false;
    7505               0 :     mEODForCurrentDocument = false;
    7506                 : 
    7507                 :     // if this document is part of a multipart document,
    7508                 :     // the ID can be used to distinguish it from the other parts.
    7509               0 :     nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(request));
    7510               0 :     if (multiPartChannel) {
    7511               0 :       nsCOMPtr<nsIPresShell> shell;
    7512               0 :       rv = GetPresShell(getter_AddRefs(shell));
    7513               0 :       if (NS_SUCCEEDED(rv) && shell) {
    7514               0 :         nsIDocument *doc = shell->GetDocument();
    7515               0 :         if (doc) {
    7516                 :           PRUint32 partID;
    7517               0 :           multiPartChannel->GetPartID(&partID);
    7518               0 :           doc->SetPartID(partID);
    7519                 :         }
    7520                 :       }
    7521                 :     }
    7522                 : 
    7523                 :     // Give hint to native plevent dispatch mechanism. If a document
    7524                 :     // is loading the native plevent dispatch mechanism should favor
    7525                 :     // performance over normal native event dispatch priorities.
    7526               0 :     if (++gNumberOfDocumentsLoading == 1) {
    7527                 :       // Hint to favor performance for the plevent notification mechanism.
    7528                 :       // We want the pages to load as fast as possible even if its means 
    7529                 :       // native messages might be starved.
    7530               0 :       FavorPerformanceHint(true, NS_EVENT_STARVATION_DELAY_HINT);
    7531                 :     }
    7532                 : 
    7533               0 :     if (onLocationChangeNeeded) {
    7534               0 :       FireOnLocationChange(this, request, mCurrentURI, 0);
    7535                 :     }
    7536                 :   
    7537               0 :     return NS_OK;
    7538                 : }
    7539                 : 
    7540                 : nsresult
    7541               0 : nsDocShell::NewContentViewerObj(const char *aContentType,
    7542                 :                                 nsIRequest * request, nsILoadGroup * aLoadGroup,
    7543                 :                                 nsIStreamListener ** aContentHandler,
    7544                 :                                 nsIContentViewer ** aViewer)
    7545                 : {
    7546               0 :     nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
    7547                 : 
    7548                 :     nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
    7549               0 :         nsContentUtils::FindInternalContentViewer(aContentType);
    7550               0 :     if (!docLoaderFactory) {
    7551               0 :         return NS_ERROR_FAILURE;
    7552                 :     }
    7553                 : 
    7554                 :     // Now create an instance of the content viewer
    7555                 :     // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
    7556               0 :     nsresult rv = docLoaderFactory->CreateInstance("view",
    7557                 :                                                    aOpenedChannel,
    7558                 :                                                    aLoadGroup, aContentType,
    7559                 :                                                    static_cast<nsIContentViewerContainer*>(this),
    7560                 :                                                    nsnull,
    7561                 :                                                    aContentHandler,
    7562               0 :                                                    aViewer);
    7563               0 :     NS_ENSURE_SUCCESS(rv, rv);
    7564                 : 
    7565               0 :     (*aViewer)->SetContainer(static_cast<nsIContentViewerContainer *>(this));
    7566               0 :     return NS_OK;
    7567                 : }
    7568                 : 
    7569                 : NS_IMETHODIMP
    7570               0 : nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
    7571                 : {
    7572                 :     //
    7573                 :     // Copy content viewer state from previous or parent content viewer.
    7574                 :     //
    7575                 :     // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
    7576                 :     //
    7577                 :     // Do NOT to maintain a reference to the old content viewer outside
    7578                 :     // of this "copying" block, or it will not be destroyed until the end of
    7579                 :     // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
    7580                 :     //
    7581                 :     // In this block of code, if we get an error result, we return it
    7582                 :     // but if we get a null pointer, that's perfectly legal for parent
    7583                 :     // and parentContentViewer.
    7584                 :     //
    7585                 : 
    7586               0 :     PRInt32 x = 0;
    7587               0 :     PRInt32 y = 0;
    7588               0 :     PRInt32 cx = 0;
    7589               0 :     PRInt32 cy = 0;
    7590                 : 
    7591                 :     // This will get the size from the current content viewer or from the
    7592                 :     // Init settings
    7593               0 :     DoGetPositionAndSize(&x, &y, &cx, &cy);
    7594                 : 
    7595               0 :     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    7596               0 :     NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
    7597                 :                       NS_ERROR_FAILURE);
    7598               0 :     nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
    7599                 : 
    7600               0 :     nsCAutoString defaultCharset;
    7601               0 :     nsCAutoString forceCharset;
    7602               0 :     nsCAutoString hintCharset;
    7603                 :     PRInt32 hintCharsetSource;
    7604               0 :     nsCAutoString prevDocCharset;
    7605                 :     PRInt32 minFontSize;
    7606                 :     float textZoom;
    7607                 :     float pageZoom;
    7608                 :     bool styleDisabled;
    7609                 :     // |newMUDV| also serves as a flag to set the data from the above vars
    7610               0 :     nsCOMPtr<nsIMarkupDocumentViewer> newMUDV;
    7611                 : 
    7612               0 :     if (mContentViewer || parent) {
    7613               0 :         nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV;
    7614               0 :         if (mContentViewer) {
    7615                 :             // Get any interesting state from old content viewer
    7616                 :             // XXX: it would be far better to just reuse the document viewer ,
    7617                 :             //      since we know we're just displaying the same document as before
    7618               0 :             oldMUDV = do_QueryInterface(mContentViewer);
    7619                 : 
    7620                 :             // Tell the old content viewer to hibernate in session history when
    7621                 :             // it is destroyed.
    7622                 : 
    7623               0 :             if (mSavingOldViewer && NS_FAILED(CaptureState())) {
    7624               0 :                 if (mOSHE) {
    7625               0 :                     mOSHE->SyncPresentationState();
    7626                 :                 }
    7627               0 :                 mSavingOldViewer = false;
    7628                 :             }
    7629                 :         }
    7630                 :         else {
    7631                 :             // No old content viewer, so get state from parent's content viewer
    7632               0 :             nsCOMPtr<nsIContentViewer> parentContentViewer;
    7633               0 :             parent->GetContentViewer(getter_AddRefs(parentContentViewer));
    7634               0 :             oldMUDV = do_QueryInterface(parentContentViewer);
    7635                 :         }
    7636                 : 
    7637               0 :         if (oldMUDV) {
    7638                 :             nsresult rv;
    7639                 : 
    7640               0 :             newMUDV = do_QueryInterface(aNewViewer,&rv);
    7641               0 :             if (newMUDV) {
    7642               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7643                 :                                   GetDefaultCharacterSet(defaultCharset),
    7644                 :                                   NS_ERROR_FAILURE);
    7645               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7646                 :                                   GetForceCharacterSet(forceCharset),
    7647                 :                                   NS_ERROR_FAILURE);
    7648               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7649                 :                                   GetHintCharacterSet(hintCharset),
    7650                 :                                   NS_ERROR_FAILURE);
    7651               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7652                 :                                   GetHintCharacterSetSource(&hintCharsetSource),
    7653                 :                                   NS_ERROR_FAILURE);
    7654               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7655                 :                                   GetMinFontSize(&minFontSize),
    7656                 :                                   NS_ERROR_FAILURE);
    7657               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7658                 :                                   GetTextZoom(&textZoom),
    7659                 :                                   NS_ERROR_FAILURE);
    7660               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7661                 :                                   GetFullZoom(&pageZoom),
    7662                 :                                   NS_ERROR_FAILURE);
    7663               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7664                 :                                   GetAuthorStyleDisabled(&styleDisabled),
    7665                 :                                   NS_ERROR_FAILURE);
    7666               0 :                 NS_ENSURE_SUCCESS(oldMUDV->
    7667                 :                                   GetPrevDocCharacterSet(prevDocCharset),
    7668                 :                                   NS_ERROR_FAILURE);
    7669                 :             }
    7670                 :         }
    7671                 :     }
    7672                 : 
    7673               0 :     nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
    7674                 :     // Ensure that the content viewer is destroyed *after* the GC - bug 71515
    7675               0 :     nsCOMPtr<nsIContentViewer> kungfuDeathGrip = mContentViewer;
    7676               0 :     if (mContentViewer) {
    7677                 :         // Stop any activity that may be happening in the old document before
    7678                 :         // releasing it...
    7679               0 :         mContentViewer->Stop();
    7680                 : 
    7681                 :         // Try to extract the canvas background color from the old
    7682                 :         // presentation shell, so we can use it for the next document.
    7683               0 :         nsCOMPtr<nsIPresShell> shell;
    7684               0 :         mContentViewer->GetPresShell(getter_AddRefs(shell));
    7685                 : 
    7686               0 :         if (shell) {
    7687               0 :             bgcolor = shell->GetCanvasBackground();
    7688                 :         }
    7689                 : 
    7690               0 :         mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull);
    7691               0 :         aNewViewer->SetPreviousViewer(mContentViewer);
    7692                 :     }
    7693               0 :     if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
    7694                 :         // We don't plan to save a viewer in mOSHE; tell it to drop
    7695                 :         // any other state it's holding.
    7696               0 :         mOSHE->SyncPresentationState();
    7697                 :     }
    7698                 : 
    7699               0 :     mContentViewer = nsnull;
    7700                 : 
    7701                 :     // Now that we're about to switch documents, forget all of our children.
    7702                 :     // Note that we cached them as needed up in CaptureState above.
    7703               0 :     DestroyChildren();
    7704                 : 
    7705               0 :     mContentViewer = aNewViewer;
    7706                 : 
    7707               0 :     nsCOMPtr<nsIWidget> widget;
    7708               0 :     NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
    7709                 : 
    7710               0 :     nsIntRect bounds(x, y, cx, cy);
    7711                 : 
    7712               0 :     mContentViewer->SetNavigationTiming(mTiming);
    7713                 : 
    7714               0 :     if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
    7715               0 :         mContentViewer = nsnull;
    7716               0 :         NS_ERROR("ContentViewer Initialization failed");
    7717               0 :         return NS_ERROR_FAILURE;
    7718                 :     }
    7719                 : 
    7720                 :     // If we have old state to copy, set the old state onto the new content
    7721                 :     // viewer
    7722               0 :     if (newMUDV) {
    7723               0 :         NS_ENSURE_SUCCESS(newMUDV->SetDefaultCharacterSet(defaultCharset),
    7724                 :                           NS_ERROR_FAILURE);
    7725               0 :         NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
    7726                 :                           NS_ERROR_FAILURE);
    7727               0 :         NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset),
    7728                 :                           NS_ERROR_FAILURE);
    7729               0 :         NS_ENSURE_SUCCESS(newMUDV->
    7730                 :                           SetHintCharacterSetSource(hintCharsetSource),
    7731                 :                           NS_ERROR_FAILURE);
    7732               0 :         NS_ENSURE_SUCCESS(newMUDV->SetPrevDocCharacterSet(prevDocCharset),
    7733                 :                           NS_ERROR_FAILURE);
    7734               0 :         NS_ENSURE_SUCCESS(newMUDV->SetMinFontSize(minFontSize),
    7735                 :                           NS_ERROR_FAILURE);
    7736               0 :         NS_ENSURE_SUCCESS(newMUDV->SetTextZoom(textZoom),
    7737                 :                           NS_ERROR_FAILURE);
    7738               0 :         NS_ENSURE_SUCCESS(newMUDV->SetFullZoom(pageZoom),
    7739                 :                           NS_ERROR_FAILURE);
    7740               0 :         NS_ENSURE_SUCCESS(newMUDV->SetAuthorStyleDisabled(styleDisabled),
    7741                 :                           NS_ERROR_FAILURE);
    7742                 :     }
    7743                 : 
    7744                 :     // Stuff the bgcolor from the old pres shell into the new
    7745                 :     // pres shell. This improves page load continuity.
    7746               0 :     nsCOMPtr<nsIPresShell> shell;
    7747               0 :     mContentViewer->GetPresShell(getter_AddRefs(shell));
    7748                 : 
    7749               0 :     if (shell) {
    7750               0 :         shell->SetCanvasBackground(bgcolor);
    7751                 :     }
    7752                 : 
    7753                 : // XXX: It looks like the LayoutState gets restored again in Embed()
    7754                 : //      right after the call to SetupNewViewer(...)
    7755                 : 
    7756                 :     // We don't show the mContentViewer yet, since we want to draw the old page
    7757                 :     // until we have enough of the new page to show.  Just return with the new
    7758                 :     // viewer still set to hidden.
    7759                 : 
    7760               0 :     return NS_OK;
    7761                 : }
    7762                 : 
    7763                 : nsresult
    7764               0 : nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry)
    7765                 : {
    7766               0 :     nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
    7767               0 :     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
    7768                 : 
    7769               0 :     nsCOMPtr<nsIStructuredCloneContainer> scContainer;
    7770               0 :     if (shEntry) {
    7771               0 :         nsresult rv = shEntry->GetStateData(getter_AddRefs(scContainer));
    7772               0 :         NS_ENSURE_SUCCESS(rv, rv);
    7773                 : 
    7774                 :         // If shEntry is null, just set the document's state object to null.
    7775                 :     }
    7776                 : 
    7777                 :     // It's OK for scContainer too be null here; that just means there's no
    7778                 :     // state data associated with this history entry.
    7779               0 :     document->SetStateObject(scContainer);
    7780                 : 
    7781               0 :     return NS_OK;
    7782                 : }
    7783                 : 
    7784                 : nsresult
    7785               0 : nsDocShell::CheckLoadingPermissions()
    7786                 : {
    7787                 :     // This method checks whether the caller may load content into
    7788                 :     // this docshell. Even though we've done our best to hide windows
    7789                 :     // from code that doesn't have the right to access them, it's
    7790                 :     // still possible for an evil site to open a window and access
    7791                 :     // frames in the new window through window.frames[] (which is
    7792                 :     // allAccess for historic reasons), so we still need to do this
    7793                 :     // check on load.
    7794               0 :     nsresult rv = NS_OK, sameOrigin = NS_OK;
    7795                 : 
    7796               0 :     if (!gValidateOrigin || !IsFrame()) {
    7797                 :         // Origin validation was turned off, or we're not a frame.
    7798                 :         // Permit all loads.
    7799                 : 
    7800               0 :         return rv;
    7801                 :     }
    7802                 : 
    7803                 :     // We're a frame. Check that the caller has write permission to
    7804                 :     // the parent before allowing it to load anything into this
    7805                 :     // docshell.
    7806                 : 
    7807                 :     nsCOMPtr<nsIScriptSecurityManager> securityManager =
    7808               0 :         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    7809               0 :     NS_ENSURE_SUCCESS(rv, rv);
    7810                 : 
    7811               0 :     bool ubwEnabled = false;
    7812               0 :     rv = securityManager->IsCapabilityEnabled("UniversalXPConnect",
    7813               0 :                                               &ubwEnabled);
    7814               0 :     if (NS_FAILED(rv) || ubwEnabled) {
    7815               0 :         return rv;
    7816                 :     }
    7817                 : 
    7818               0 :     nsCOMPtr<nsIPrincipal> subjPrincipal;
    7819               0 :     rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal));
    7820               0 :     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv);
    7821                 : 
    7822                 :     // Check if the caller is from the same origin as this docshell,
    7823                 :     // or any of its ancestors.
    7824               0 :     nsCOMPtr<nsIDocShellTreeItem> item(this);
    7825               0 :     do {
    7826               0 :         nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item));
    7827               0 :         nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
    7828                 : 
    7829                 :         nsIPrincipal *p;
    7830               0 :         if (!sop || !(p = sop->GetPrincipal())) {
    7831               0 :             return NS_ERROR_UNEXPECTED;
    7832                 :         }
    7833                 : 
    7834                 :         // Compare origins
    7835                 :         bool equal;
    7836               0 :         sameOrigin = subjPrincipal->Equals(p, &equal);
    7837               0 :         if (NS_SUCCEEDED(sameOrigin)) {
    7838               0 :             if (equal) {
    7839                 :                 // Same origin, permit load
    7840                 : 
    7841               0 :                 return sameOrigin;
    7842                 :             }
    7843                 : 
    7844               0 :             sameOrigin = NS_ERROR_DOM_PROP_ACCESS_DENIED;
    7845                 :         }
    7846                 : 
    7847               0 :         nsCOMPtr<nsIDocShellTreeItem> tmp;
    7848               0 :         item->GetSameTypeParent(getter_AddRefs(tmp));
    7849               0 :         item.swap(tmp);
    7850               0 :     } while (item);
    7851                 : 
    7852               0 :     return sameOrigin;
    7853                 : }
    7854                 : 
    7855                 : //*****************************************************************************
    7856                 : // nsDocShell: Site Loading
    7857                 : //*****************************************************************************   
    7858                 : namespace
    7859                 : {
    7860                 : 
    7861                 : // Callback used by CopyFavicon to inform the favicon service that one URI
    7862                 : // (mNewURI) has the same favicon URI (OnFaviconDataAvailable's aFaviconURI) as
    7863                 : // another.
    7864                 : class nsCopyFaviconCallback : public nsIFaviconDataCallback
    7865               0 : {
    7866                 : public:
    7867                 :     NS_DECL_ISUPPORTS
    7868                 : 
    7869               0 :     nsCopyFaviconCallback(nsIURI *aNewURI)
    7870               0 :       : mNewURI(aNewURI)
    7871                 :     {
    7872               0 :     }
    7873                 : 
    7874                 :     NS_IMETHODIMP
    7875               0 :     OnFaviconDataAvailable(nsIURI *aFaviconURI, PRUint32 aDataLen,
    7876                 :                            const PRUint8 *aData, const nsACString &aMimeType)
    7877                 :     {
    7878               0 :         NS_ASSERTION(aDataLen == 0,
    7879                 :                      "We weren't expecting the callback to deliver data.");
    7880                 :         nsCOMPtr<mozIAsyncFavicons> favSvc =
    7881               0 :             do_GetService("@mozilla.org/browser/favicon-service;1");
    7882               0 :         NS_ENSURE_STATE(favSvc);
    7883                 : 
    7884               0 :         return favSvc->SetAndFetchFaviconForPage(mNewURI, aFaviconURI,
    7885               0 :                                                  false, nsnull);
    7886                 :     }
    7887                 : 
    7888                 : private:
    7889                 :     nsCOMPtr<nsIURI> mNewURI;
    7890                 : };
    7891                 : 
    7892               0 : NS_IMPL_ISUPPORTS1(nsCopyFaviconCallback, nsIFaviconDataCallback)
    7893                 : 
    7894                 : // Tell the favicon service that aNewURI has the same favicon as aOldURI.
    7895               0 : void CopyFavicon(nsIURI *aOldURI, nsIURI *aNewURI)
    7896                 : {
    7897                 :     nsCOMPtr<mozIAsyncFavicons> favSvc =
    7898               0 :         do_GetService("@mozilla.org/browser/favicon-service;1");
    7899               0 :     if (favSvc) {
    7900                 :         nsCOMPtr<nsIFaviconDataCallback> callback =
    7901               0 :             new nsCopyFaviconCallback(aNewURI);
    7902               0 :         favSvc->GetFaviconURLForPage(aOldURI, callback);
    7903                 :     }
    7904               0 : }
    7905                 : 
    7906                 : } // anonymous namespace
    7907                 : 
    7908                 : class InternalLoadEvent : public nsRunnable
    7909               0 : {
    7910                 : public:
    7911               0 :     InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
    7912                 :                       nsISupports * aOwner, PRUint32 aFlags,
    7913                 :                       const char* aTypeHint, nsIInputStream * aPostData,
    7914                 :                       nsIInputStream * aHeadersData, PRUint32 aLoadType,
    7915                 :                       nsISHEntry * aSHEntry, bool aFirstParty) :
    7916                 :         mDocShell(aDocShell),
    7917                 :         mURI(aURI),
    7918                 :         mReferrer(aReferrer),
    7919                 :         mOwner(aOwner),
    7920                 :         mPostData(aPostData),
    7921                 :         mHeadersData(aHeadersData),
    7922                 :         mSHEntry(aSHEntry),
    7923                 :         mFlags(aFlags),
    7924                 :         mLoadType(aLoadType),
    7925               0 :         mFirstParty(aFirstParty)
    7926                 :     {
    7927                 :         // Make sure to keep null things null as needed
    7928               0 :         if (aTypeHint) {
    7929               0 :             mTypeHint = aTypeHint;
    7930                 :         }
    7931               0 :     }
    7932                 :     
    7933               0 :     NS_IMETHOD Run() {
    7934               0 :         return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
    7935                 :                                        nsnull, mTypeHint.get(),
    7936                 :                                        mPostData, mHeadersData, mLoadType,
    7937               0 :                                        mSHEntry, mFirstParty, nsnull, nsnull);
    7938                 :     }
    7939                 : 
    7940                 : private:
    7941                 : 
    7942                 :     // Use IDL strings so .get() returns null by default
    7943                 :     nsXPIDLString mWindowTarget;
    7944                 :     nsXPIDLCString mTypeHint;
    7945                 : 
    7946                 :     nsRefPtr<nsDocShell> mDocShell;
    7947                 :     nsCOMPtr<nsIURI> mURI;
    7948                 :     nsCOMPtr<nsIURI> mReferrer;
    7949                 :     nsCOMPtr<nsISupports> mOwner;
    7950                 :     nsCOMPtr<nsIInputStream> mPostData;
    7951                 :     nsCOMPtr<nsIInputStream> mHeadersData;
    7952                 :     nsCOMPtr<nsISHEntry> mSHEntry;
    7953                 :     PRUint32 mFlags;
    7954                 :     PRUint32 mLoadType;
    7955                 :     bool mFirstParty;
    7956                 : };
    7957                 : 
    7958                 : NS_IMETHODIMP
    7959               0 : nsDocShell::InternalLoad(nsIURI * aURI,
    7960                 :                          nsIURI * aReferrer,
    7961                 :                          nsISupports * aOwner,
    7962                 :                          PRUint32 aFlags,
    7963                 :                          const PRUnichar *aWindowTarget,
    7964                 :                          const char* aTypeHint,
    7965                 :                          nsIInputStream * aPostData,
    7966                 :                          nsIInputStream * aHeadersData,
    7967                 :                          PRUint32 aLoadType,
    7968                 :                          nsISHEntry * aSHEntry,
    7969                 :                          bool aFirstParty,
    7970                 :                          nsIDocShell** aDocShell,
    7971                 :                          nsIRequest** aRequest)
    7972                 : {
    7973               0 :     nsresult rv = NS_OK;
    7974                 : 
    7975                 : #ifdef PR_LOGGING
    7976               0 :     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
    7977               0 :         nsCAutoString spec;
    7978               0 :         if (aURI)
    7979               0 :             aURI->GetSpec(spec);
    7980               0 :         PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
    7981                 :     }
    7982                 : #endif
    7983                 :     
    7984                 :     // Initialize aDocShell/aRequest
    7985               0 :     if (aDocShell) {
    7986               0 :         *aDocShell = nsnull;
    7987                 :     }
    7988               0 :     if (aRequest) {
    7989               0 :         *aRequest = nsnull;
    7990                 :     }
    7991                 : 
    7992               0 :     if (!aURI) {
    7993               0 :         return NS_ERROR_NULL_POINTER;
    7994                 :     }
    7995                 : 
    7996               0 :     NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
    7997                 : 
    7998               0 :     NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
    7999                 : 
    8000                 :     // wyciwyg urls can only be loaded through history. Any normal load of
    8001                 :     // wyciwyg through docshell is  illegal. Disallow such loads.
    8002               0 :     if (aLoadType & LOAD_CMD_NORMAL) {
    8003               0 :         bool isWyciwyg = false;
    8004               0 :         rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);   
    8005               0 :         if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) 
    8006               0 :             return NS_ERROR_FAILURE;
    8007                 :     }
    8008                 : 
    8009               0 :     bool bIsJavascript = false;
    8010               0 :     if (NS_FAILED(aURI->SchemeIs("javascript", &bIsJavascript))) {
    8011               0 :         bIsJavascript = false;
    8012                 :     }
    8013                 : 
    8014                 :     //
    8015                 :     // First, notify any nsIContentPolicy listeners about the document load.
    8016                 :     // Only abort the load if a content policy listener explicitly vetos it!
    8017                 :     //
    8018               0 :     nsCOMPtr<nsIDOMElement> requestingElement;
    8019                 :     // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
    8020               0 :     nsCOMPtr<nsPIDOMWindow> privateWin(do_QueryInterface(mScriptGlobal));
    8021               0 :     if (privateWin)
    8022               0 :         requestingElement = privateWin->GetFrameElementInternal();
    8023                 : 
    8024               0 :     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
    8025                 :     PRUint32 contentType;
    8026               0 :     if (IsFrame()) {
    8027               0 :         NS_ASSERTION(requestingElement, "A frame but no DOM element!?");
    8028               0 :         contentType = nsIContentPolicy::TYPE_SUBDOCUMENT;
    8029                 :     } else {
    8030               0 :         contentType = nsIContentPolicy::TYPE_DOCUMENT;
    8031                 :     }
    8032                 : 
    8033               0 :     nsISupports* context = requestingElement;
    8034               0 :     if (!context) {
    8035               0 :         context =  mScriptGlobal;
    8036                 :     }
    8037                 : 
    8038                 :     // XXXbz would be nice to know the loading principal here... but we don't
    8039               0 :     nsCOMPtr<nsIPrincipal> loadingPrincipal;
    8040               0 :     if (aReferrer) {
    8041                 :         nsCOMPtr<nsIScriptSecurityManager> secMan =
    8042               0 :             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    8043               0 :         NS_ENSURE_SUCCESS(rv, rv);
    8044                 : 
    8045               0 :         rv = secMan->GetCodebasePrincipal(aReferrer,
    8046               0 :                                           getter_AddRefs(loadingPrincipal));
    8047                 :     }
    8048                 :     
    8049                 :     rv = NS_CheckContentLoadPolicy(contentType,
    8050                 :                                    aURI,
    8051                 :                                    loadingPrincipal,
    8052                 :                                    context,
    8053               0 :                                    EmptyCString(), //mime guess
    8054                 :                                    nsnull,         //extra
    8055               0 :                                    &shouldLoad);
    8056                 : 
    8057               0 :     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
    8058               0 :         if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
    8059               0 :             return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
    8060                 :         }
    8061                 : 
    8062               0 :         return NS_ERROR_CONTENT_BLOCKED;
    8063                 :     }
    8064                 : 
    8065               0 :     nsCOMPtr<nsISupports> owner(aOwner);
    8066                 :     //
    8067                 :     // Get an owner from the current document if necessary.  Note that we only
    8068                 :     // do this for URIs that inherit a security context and local file URIs;
    8069                 :     // in particular we do NOT do this for about:blank.  This way, random
    8070                 :     // about:blank loads that have no owner (which basically means they were
    8071                 :     // done by someone from chrome manually messing with our nsIWebNavigation
    8072                 :     // or by C++ setting document.location) don't get a funky principal.  If
    8073                 :     // callers want something interesting to happen with the about:blank
    8074                 :     // principal in this case, they should pass an owner in.
    8075                 :     //
    8076                 :     {
    8077                 :         bool inherits;
    8078                 :         // One more twist: Don't inherit the owner for external loads.
    8079               0 :         if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
    8080                 :             (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) &&
    8081               0 :             NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
    8082                 :                                                                     &inherits)) &&
    8083                 :             inherits) {
    8084                 : 
    8085               0 :             owner = GetInheritedPrincipal(true);
    8086                 :         }
    8087                 :     }
    8088                 : 
    8089                 :     // Don't allow loads that would inherit our security context
    8090                 :     // if this document came from an unsafe channel.
    8091                 :     {
    8092                 :         bool willInherit;
    8093                 :         // This condition needs to match the one in
    8094                 :         // nsContentUtils::SetUpChannelOwner.
    8095                 :         // Except we reverse the rv check to be safe in case
    8096                 :         // nsContentUtils::URIInheritsSecurityContext fails here and
    8097                 :         // succeeds there.
    8098               0 :         rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
    8099               0 :         if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
    8100               0 :             nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
    8101               0 :             do {
    8102                 :                 nsCOMPtr<nsIDocShell> itemDocShell =
    8103               0 :                     do_QueryInterface(treeItem);
    8104                 :                 bool isUnsafe;
    8105               0 :                 if (itemDocShell &&
    8106               0 :                     NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
    8107                 :                     isUnsafe) {
    8108               0 :                     return NS_ERROR_DOM_SECURITY_ERR;
    8109                 :                 }
    8110                 : 
    8111               0 :                 nsCOMPtr<nsIDocShellTreeItem> parent;
    8112               0 :                 treeItem->GetSameTypeParent(getter_AddRefs(parent));
    8113               0 :                 parent.swap(treeItem);
    8114               0 :             } while (treeItem);
    8115                 :         }
    8116                 :     }
    8117                 :     
    8118                 :     //
    8119                 :     // Resolve the window target before going any further...
    8120                 :     // If the load has been targeted to another DocShell, then transfer the
    8121                 :     // load to it...
    8122                 :     //
    8123               0 :     if (aWindowTarget && *aWindowTarget) {
    8124                 :         // We've already done our owner-inheriting.  Mask out that bit, so we
    8125                 :         // don't try inheriting an owner from the target window if we came up
    8126                 :         // with a null owner above.
    8127               0 :         aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
    8128                 :         
    8129                 :         // Locate the target DocShell.
    8130                 :         // This may involve creating a new toplevel window - if necessary.
    8131                 :         //
    8132               0 :         nsCOMPtr<nsIDocShellTreeItem> targetItem;
    8133                 :         FindItemWithName(aWindowTarget, nsnull, this,
    8134               0 :                          getter_AddRefs(targetItem));
    8135                 : 
    8136               0 :         nsCOMPtr<nsIDocShell> targetDocShell = do_QueryInterface(targetItem);
    8137                 :         
    8138               0 :         bool isNewWindow = false;
    8139               0 :         if (!targetDocShell) {
    8140                 :             nsCOMPtr<nsIDOMWindow> win =
    8141               0 :                 do_GetInterface(GetAsSupports(this));
    8142               0 :             NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
    8143                 : 
    8144               0 :             nsDependentString name(aWindowTarget);
    8145               0 :             nsCOMPtr<nsIDOMWindow> newWin;
    8146               0 :             rv = win->Open(EmptyString(), // URL to load
    8147                 :                            name,          // window name
    8148               0 :                            EmptyString(), // Features
    8149               0 :                            getter_AddRefs(newWin));
    8150                 : 
    8151                 :             // In some cases the Open call doesn't actually result in a new
    8152                 :             // window being opened.  We can detect these cases by examining the
    8153                 :             // document in |newWin|, if any.
    8154               0 :             nsCOMPtr<nsPIDOMWindow> piNewWin = do_QueryInterface(newWin);
    8155               0 :             if (piNewWin) {
    8156                 :                 nsCOMPtr<nsIDocument> newDoc =
    8157               0 :                     do_QueryInterface(piNewWin->GetExtantDocument());
    8158               0 :                 if (!newDoc || newDoc->IsInitialDocument()) {
    8159               0 :                     isNewWindow = true;
    8160               0 :                     aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
    8161                 :                 }
    8162                 :             }
    8163                 : 
    8164               0 :             nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
    8165               0 :             targetDocShell = do_QueryInterface(webNav);
    8166                 :         }
    8167                 : 
    8168                 :         //
    8169                 :         // Transfer the load to the target DocShell...  Pass nsnull as the
    8170                 :         // window target name from to prevent recursive retargeting!
    8171                 :         //
    8172               0 :         if (NS_SUCCEEDED(rv) && targetDocShell) {
    8173               0 :             rv = targetDocShell->InternalLoad(aURI,
    8174                 :                                               aReferrer,
    8175                 :                                               owner,
    8176                 :                                               aFlags,
    8177                 :                                               nsnull,         // No window target
    8178                 :                                               aTypeHint,
    8179                 :                                               aPostData,
    8180                 :                                               aHeadersData,
    8181                 :                                               aLoadType,
    8182                 :                                               aSHEntry,
    8183                 :                                               aFirstParty,
    8184                 :                                               aDocShell,
    8185               0 :                                               aRequest);
    8186               0 :             if (rv == NS_ERROR_NO_CONTENT) {
    8187                 :                 // XXXbz except we never reach this code!
    8188               0 :                 if (isNewWindow) {
    8189                 :                     //
    8190                 :                     // At this point, a new window has been created, but the
    8191                 :                     // URI did not have any data associated with it...
    8192                 :                     //
    8193                 :                     // So, the best we can do, is to tear down the new window
    8194                 :                     // that was just created!
    8195                 :                     //
    8196                 :                     nsCOMPtr<nsIDOMWindow> domWin =
    8197               0 :                         do_GetInterface(targetDocShell);
    8198               0 :                     if (domWin) {
    8199               0 :                         domWin->Close();
    8200                 :                     }
    8201                 :                 }
    8202                 :                 //
    8203                 :                 // NS_ERROR_NO_CONTENT should not be returned to the
    8204                 :                 // caller... This is an internal error code indicating that
    8205                 :                 // the URI had no data associated with it - probably a 
    8206                 :                 // helper-app style protocol (ie. mailto://)
    8207                 :                 //
    8208               0 :                 rv = NS_OK;
    8209                 :             }
    8210                 :             else if (isNewWindow) {
    8211                 :                 // XXX: Once new windows are created hidden, the new
    8212                 :                 //      window will need to be made visible...  For now,
    8213                 :                 //      do nothing.
    8214                 :             }
    8215                 :         }
    8216                 : 
    8217                 :         // Else we ran out of memory, or were a popup and got blocked,
    8218                 :         // or something.
    8219                 :         
    8220               0 :         return rv;
    8221                 :     }
    8222                 : 
    8223                 :     //
    8224                 :     // Load is being targetted at this docshell so return an error if the
    8225                 :     // docshell is in the process of being destroyed.
    8226                 :     //
    8227               0 :     if (mIsBeingDestroyed) {
    8228               0 :         return NS_ERROR_FAILURE;
    8229                 :     }
    8230                 : 
    8231               0 :     rv = CheckLoadingPermissions();
    8232               0 :     if (NS_FAILED(rv)) {
    8233               0 :         return rv;
    8234                 :     }
    8235                 : 
    8236                 :     // If this docshell is owned by a frameloader, make sure to cancel
    8237                 :     // possible frameloader initialization before loading a new page.
    8238               0 :     nsCOMPtr<nsIDocShellTreeItem> parent;
    8239               0 :     GetParent(getter_AddRefs(parent));
    8240               0 :     if (parent) {
    8241               0 :       nsCOMPtr<nsIDocument> doc = do_GetInterface(parent);
    8242               0 :       if (doc) {
    8243               0 :         doc->TryCancelFrameLoaderInitialization(this);
    8244                 :       }
    8245                 :     }
    8246                 : 
    8247               0 :     if (mFiredUnloadEvent) {
    8248               0 :         if (IsOKToLoadURI(aURI)) {
    8249               0 :             NS_PRECONDITION(!aWindowTarget || !*aWindowTarget,
    8250                 :                             "Shouldn't have a window target here!");
    8251                 : 
    8252                 :             // If this is a replace load, make whatever load triggered
    8253                 :             // the unload event also a replace load, so we don't
    8254                 :             // create extra history entries.
    8255               0 :             if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
    8256               0 :                 mLoadType = LOAD_NORMAL_REPLACE;
    8257                 :             }
    8258                 :             
    8259                 :             // Do this asynchronously
    8260                 :             nsCOMPtr<nsIRunnable> ev =
    8261                 :                 new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
    8262                 :                                       aTypeHint, aPostData, aHeadersData,
    8263               0 :                                       aLoadType, aSHEntry, aFirstParty);
    8264               0 :             return NS_DispatchToCurrentThread(ev);
    8265                 :         }
    8266                 : 
    8267                 :         // Just ignore this load attempt
    8268               0 :         return NS_OK;
    8269                 :     }
    8270                 : 
    8271                 :     // Before going any further vet loads initiated by external programs.
    8272               0 :     if (aLoadType == LOAD_NORMAL_EXTERNAL) {
    8273                 :         // Disallow external chrome: loads targetted at content windows
    8274               0 :         bool isChrome = false;
    8275               0 :         if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
    8276               0 :             NS_WARNING("blocked external chrome: url -- use '-chrome' option");
    8277               0 :             return NS_ERROR_FAILURE;
    8278                 :         }
    8279                 : 
    8280                 :         // clear the decks to prevent context bleed-through (bug 298255)
    8281               0 :         rv = CreateAboutBlankContentViewer(nsnull, nsnull);
    8282               0 :         if (NS_FAILED(rv))
    8283               0 :             return NS_ERROR_FAILURE;
    8284                 : 
    8285                 :         // reset loadType so we don't have to add lots of tests for
    8286                 :         // LOAD_NORMAL_EXTERNAL after this point
    8287               0 :         aLoadType = LOAD_NORMAL;
    8288                 :     }
    8289                 : 
    8290                 :     mAllowKeywordFixup =
    8291               0 :       (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
    8292               0 :     mURIResultedInDocument = false;  // reset the clock...
    8293                 : 
    8294               0 :     if (aLoadType == LOAD_NORMAL ||
    8295                 :         aLoadType == LOAD_STOP_CONTENT ||
    8296                 :         LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
    8297                 :         aLoadType == LOAD_HISTORY ||
    8298                 :         aLoadType == LOAD_LINK) {
    8299                 : 
    8300                 :         // Split mCurrentURI and aURI on the '#' character.  Make sure we read
    8301                 :         // the return values of SplitURIAtHash; if it fails, we don't want to
    8302                 :         // allow a short-circuited navigation.
    8303               0 :         nsCAutoString curBeforeHash, curHash, newBeforeHash, newHash;
    8304                 :         nsresult splitRv1, splitRv2;
    8305                 :         splitRv1 = mCurrentURI ?
    8306                 :             nsContentUtils::SplitURIAtHash(mCurrentURI,
    8307               0 :                                            curBeforeHash, curHash) :
    8308               0 :             NS_ERROR_FAILURE;
    8309               0 :         splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash);
    8310                 : 
    8311               0 :         bool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
    8312               0 :                                   NS_SUCCEEDED(splitRv2) &&
    8313               0 :                                   curBeforeHash.Equals(newBeforeHash);
    8314                 : 
    8315               0 :         bool historyNavBetweenSameDoc = false;
    8316               0 :         if (mOSHE && aSHEntry) {
    8317                 :             // We're doing a history load.
    8318                 : 
    8319               0 :             mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
    8320                 : 
    8321                 : #ifdef DEBUG
    8322               0 :             if (historyNavBetweenSameDoc) {
    8323               0 :                 nsCOMPtr<nsIInputStream> currentPostData;
    8324               0 :                 mOSHE->GetPostData(getter_AddRefs(currentPostData));
    8325               0 :                 NS_ASSERTION(currentPostData == aPostData,
    8326                 :                              "Different POST data for entries for the same page?");
    8327                 :             }
    8328                 : #endif
    8329                 :         }
    8330                 : 
    8331                 :         // A short-circuited load happens when we navigate between two SHEntries
    8332                 :         // for the same document.  We do a short-circuited load under two
    8333                 :         // circumstances.  Either
    8334                 :         //
    8335                 :         //  a) we're navigating between two different SHEntries which share a
    8336                 :         //     document, or
    8337                 :         //
    8338                 :         //  b) we're navigating to a new shentry whose URI differs from the
    8339                 :         //     current URI only in its hash, the new hash is non-empty, and
    8340                 :         //     we're not doing a POST.
    8341                 :         //
    8342                 :         // The restriction tha the SHEntries in (a) must be different ensures
    8343                 :         // that history.go(0) and the like trigger full refreshes, rather than
    8344                 :         // short-circuited loads.
    8345                 :         bool doShortCircuitedLoad =
    8346               0 :           (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
    8347                 :           (!aSHEntry && aPostData == nsnull &&
    8348               0 :            sameExceptHashes && !newHash.IsEmpty());
    8349                 : 
    8350               0 :         if (doShortCircuitedLoad) {
    8351                 :             // Save the current URI; we need it if we fire a hashchange later.
    8352               0 :             nsCOMPtr<nsIURI> oldURI = mCurrentURI;
    8353                 : 
    8354                 :             // Save the position of the scrollers.
    8355               0 :             nscoord cx = 0, cy = 0;
    8356               0 :             GetCurScrollPos(ScrollOrientation_X, &cx);
    8357               0 :             GetCurScrollPos(ScrollOrientation_Y, &cy);
    8358                 : 
    8359                 :             // ScrollToAnchor doesn't necessarily cause us to scroll the window;
    8360                 :             // the function decides whether a scroll is appropriate based on the
    8361                 :             // arguments it receives.  But even if we don't end up scrolling,
    8362                 :             // ScrollToAnchor performs other important tasks, such as informing
    8363                 :             // the presShell that we have a new hash.  See bug 680257.
    8364               0 :             rv = ScrollToAnchor(curHash, newHash, aLoadType);
    8365               0 :             NS_ENSURE_SUCCESS(rv, rv);
    8366                 : 
    8367                 :             // Reset mLoadType to its original value once we exit this block,
    8368                 :             // because this short-circuited load might have started after a
    8369                 :             // normal, network load, and we don't want to clobber its load type.
    8370                 :             // See bug 737307.
    8371               0 :             AutoRestore<PRUint32> loadTypeResetter(mLoadType);
    8372                 : 
    8373               0 :             mLoadType = aLoadType;
    8374               0 :             mURIResultedInDocument = true;
    8375                 : 
    8376                 :             /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
    8377                 :              * SetCurrentURI() called from OnNewURI() will send proper
    8378                 :              * onLocationChange() notifications to the browser to update
    8379                 :              * back/forward buttons.
    8380                 :              */
    8381               0 :             SetHistoryEntry(&mLSHE, aSHEntry);
    8382                 : 
    8383                 :             /* This is a anchor traversal with in the same page.
    8384                 :              * call OnNewURI() so that, this traversal will be 
    8385                 :              * recorded in session and global history.
    8386                 :              */
    8387               0 :             nsCOMPtr<nsISupports> owner;
    8388               0 :             if (mOSHE) {
    8389               0 :                 mOSHE->GetOwner(getter_AddRefs(owner));
    8390                 :             }
    8391                 :             // Pass true for aCloneSHChildren, since we're not
    8392                 :             // changing documents here, so all of our subframes are
    8393                 :             // still relevant to the new session history entry.
    8394                 :             //
    8395                 :             // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
    8396                 :             // flag on firing onLocationChange(...).
    8397                 :             // Anyway, aCloneSHChildren param is simply reflecting
    8398                 :             // doShortCircuitedLoad in this scope.
    8399               0 :             OnNewURI(aURI, nsnull, owner, mLoadType, true, true, true);
    8400                 : 
    8401               0 :             nsCOMPtr<nsIInputStream> postData;
    8402               0 :             nsCOMPtr<nsISupports> cacheKey;
    8403                 : 
    8404               0 :             if (mOSHE) {
    8405                 :                 /* save current position of scroller(s) (bug 59774) */
    8406               0 :                 mOSHE->SetScrollPosition(cx, cy);
    8407                 :                 // Get the postdata and page ident from the current page, if
    8408                 :                 // the new load is being done via normal means.  Note that
    8409                 :                 // "normal means" can be checked for just by checking for
    8410                 :                 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
    8411                 :                 // above -- it filters out some LOAD_CMD_NORMAL cases that we
    8412                 :                 // wouldn't want here.
    8413               0 :                 if (aLoadType & LOAD_CMD_NORMAL) {
    8414               0 :                     mOSHE->GetPostData(getter_AddRefs(postData));
    8415               0 :                     mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
    8416                 : 
    8417                 :                     // Link our new SHEntry to the old SHEntry's back/forward
    8418                 :                     // cache data, since the two SHEntries correspond to the
    8419                 :                     // same document.
    8420               0 :                     if (mLSHE)
    8421               0 :                         mLSHE->AdoptBFCacheEntry(mOSHE);
    8422                 :                 }
    8423                 :             }
    8424                 : 
    8425                 :             /* Assign mOSHE to mLSHE. This will either be a new entry created
    8426                 :              * by OnNewURI() for normal loads or aSHEntry for history loads.
    8427                 :              */
    8428               0 :             if (mLSHE) {
    8429               0 :                 SetHistoryEntry(&mOSHE, mLSHE);
    8430                 :                 // Save the postData obtained from the previous page
    8431                 :                 // in to the session history entry created for the 
    8432                 :                 // anchor page, so that any history load of the anchor
    8433                 :                 // page will restore the appropriate postData.
    8434               0 :                 if (postData)
    8435               0 :                     mOSHE->SetPostData(postData);
    8436                 : 
    8437                 :                 // Make sure we won't just repost without hitting the
    8438                 :                 // cache first
    8439               0 :                 if (cacheKey)
    8440               0 :                     mOSHE->SetCacheKey(cacheKey);
    8441                 :             }
    8442                 : 
    8443                 :             /* restore previous position of scroller(s), if we're moving
    8444                 :              * back in history (bug 59774)
    8445                 :              */
    8446               0 :             if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL))
    8447                 :             {
    8448                 :                 nscoord bx, by;
    8449               0 :                 mOSHE->GetScrollPosition(&bx, &by);
    8450               0 :                 SetCurScrollPosEx(bx, by);
    8451                 :             }
    8452                 : 
    8453                 :             /* Clear out mLSHE so that further anchor visits get
    8454                 :              * recorded in SH and SH won't misbehave. 
    8455                 :              */
    8456               0 :             SetHistoryEntry(&mLSHE, nsnull);
    8457                 :             /* Set the title for the SH entry for this target url. so that
    8458                 :              * SH menus in go/back/forward buttons won't be empty for this.
    8459                 :              */
    8460               0 :             if (mSessionHistory) {
    8461               0 :                 PRInt32 index = -1;
    8462               0 :                 mSessionHistory->GetIndex(&index);
    8463               0 :                 nsCOMPtr<nsIHistoryEntry> hEntry;
    8464               0 :                 mSessionHistory->GetEntryAtIndex(index, false,
    8465               0 :                                                  getter_AddRefs(hEntry));
    8466               0 :                 NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE);
    8467               0 :                 nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(hEntry));
    8468               0 :                 if (shEntry)
    8469               0 :                     shEntry->SetTitle(mTitle);
    8470                 :             }
    8471                 : 
    8472                 :             /* Set the title for the Global History entry for this anchor url.
    8473                 :              */
    8474               0 :             if (mUseGlobalHistory) {
    8475               0 :                 nsCOMPtr<IHistory> history = services::GetHistoryService();
    8476               0 :                 if (history) {
    8477               0 :                     history->SetURITitle(aURI, mTitle);
    8478                 :                 }
    8479               0 :                 else if (mGlobalHistory) {
    8480               0 :                     mGlobalHistory->SetPageTitle(aURI, mTitle);
    8481                 :                 }
    8482                 :             }
    8483                 : 
    8484                 :             // Set the doc's URI according to the new history entry's URI.
    8485                 :             nsCOMPtr<nsIDocument> doc =
    8486               0 :               do_GetInterface(GetAsSupports(this));
    8487               0 :             NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    8488               0 :             doc->SetDocumentURI(aURI);
    8489                 : 
    8490               0 :             SetDocCurrentStateObj(mOSHE);
    8491                 : 
    8492                 :             // Dispatch the popstate and hashchange events, as appropriate.
    8493               0 :             nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
    8494               0 :             if (window) {
    8495                 :                 // Fire a hashchange event URIs differ, and only in their hashes.
    8496               0 :                 bool doHashchange = sameExceptHashes && !curHash.Equals(newHash);
    8497                 : 
    8498               0 :                 if (historyNavBetweenSameDoc || doHashchange) {
    8499               0 :                   window->DispatchSyncPopState();
    8500                 :                 }
    8501                 : 
    8502               0 :                 if (doHashchange) {
    8503                 :                   // Make sure to use oldURI here, not mCurrentURI, because by
    8504                 :                   // now, mCurrentURI has changed!
    8505               0 :                   window->DispatchAsyncHashchange(oldURI, aURI);
    8506                 :                 }
    8507                 :             }
    8508                 : 
    8509                 :             // Inform the favicon service that the favicon for oldURI also
    8510                 :             // applies to aURI.
    8511               0 :             CopyFavicon(oldURI, aURI);
    8512                 : 
    8513               0 :             return NS_OK;
    8514                 :         }
    8515                 :     }
    8516                 :     
    8517                 :     // mContentViewer->PermitUnload can destroy |this| docShell, which
    8518                 :     // causes the next call of CanSavePresentation to crash. 
    8519                 :     // Hold onto |this| until we return, to prevent a crash from happening. 
    8520                 :     // (bug#331040)
    8521               0 :     nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
    8522                 : 
    8523               0 :     rv = MaybeInitTiming();
    8524               0 :     if (mTiming) {
    8525               0 :       mTiming->NotifyBeforeUnload();
    8526                 :     }
    8527                 :     // Check if the page doesn't want to be unloaded. The javascript:
    8528                 :     // protocol handler deals with this for javascript: URLs.
    8529               0 :     if (!bIsJavascript && mContentViewer) {
    8530                 :         bool okToUnload;
    8531               0 :         rv = mContentViewer->PermitUnload(false, &okToUnload);
    8532                 : 
    8533               0 :         if (NS_SUCCEEDED(rv) && !okToUnload) {
    8534                 :             // The user chose not to unload the page, interrupt the
    8535                 :             // load.
    8536               0 :             return NS_OK;
    8537                 :         }
    8538                 :     }
    8539                 : 
    8540               0 :     if (mTiming) {
    8541               0 :       mTiming->NotifyUnloadAccepted(mCurrentURI);
    8542                 :     }
    8543                 : 
    8544                 :     // Check for saving the presentation here, before calling Stop().
    8545                 :     // This is necessary so that we can catch any pending requests.
    8546                 :     // Since the new request has not been created yet, we pass null for the
    8547                 :     // new request parameter.
    8548                 :     // Also pass nsnull for the document, since it doesn't affect the return
    8549                 :     // value for our purposes here.
    8550               0 :     bool savePresentation = CanSavePresentation(aLoadType, nsnull, nsnull);
    8551                 : 
    8552                 :     // Don't stop current network activity for javascript: URL's since
    8553                 :     // they might not result in any data, and thus nothing should be
    8554                 :     // stopped in those cases. In the case where they do result in
    8555                 :     // data, the javascript: URL channel takes care of stopping
    8556                 :     // current network activity.
    8557               0 :     if (!bIsJavascript) {
    8558                 :         // Stop any current network activity.
    8559                 :         // Also stop content if this is a zombie doc. otherwise 
    8560                 :         // the onload will be delayed by other loads initiated in the 
    8561                 :         // background by the first document that
    8562                 :         // didn't fully load before the next load was initiated.
    8563                 :         // If not a zombie, don't stop content until data 
    8564                 :         // starts arriving from the new URI...
    8565                 : 
    8566               0 :         nsCOMPtr<nsIContentViewer> zombieViewer;
    8567               0 :         if (mContentViewer) {
    8568               0 :             mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
    8569                 :         }
    8570                 : 
    8571               0 :         if (zombieViewer ||
    8572               0 :             LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
    8573               0 :             rv = Stop(nsIWebNavigation::STOP_ALL);
    8574                 :         } else {
    8575               0 :             rv = Stop(nsIWebNavigation::STOP_NETWORK);
    8576                 :         }
    8577                 : 
    8578               0 :         if (NS_FAILED(rv)) 
    8579               0 :             return rv;
    8580                 :     }
    8581                 : 
    8582               0 :     mLoadType = aLoadType;
    8583                 : 
    8584                 :     // mLSHE should be assigned to aSHEntry, only after Stop() has
    8585                 :     // been called. But when loading an error page, do not clear the
    8586                 :     // mLSHE for the real page.
    8587               0 :     if (mLoadType != LOAD_ERROR_PAGE)
    8588               0 :         SetHistoryEntry(&mLSHE, aSHEntry);
    8589                 : 
    8590               0 :     mSavingOldViewer = savePresentation;
    8591                 : 
    8592                 :     // If we have a saved content viewer in history, restore and show it now.
    8593               0 :     if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
    8594                 :         // Make sure our history ID points to the same ID as
    8595                 :         // SHEntry's docshell ID.
    8596               0 :         aSHEntry->GetDocshellID(&mHistoryID);
    8597                 : 
    8598                 :         // It's possible that the previous viewer of mContentViewer is the
    8599                 :         // viewer that will end up in aSHEntry when it gets closed.  If that's
    8600                 :         // the case, we need to go ahead and force it into its shentry so we
    8601                 :         // can restore it.
    8602               0 :         if (mContentViewer) {
    8603               0 :             nsCOMPtr<nsIContentViewer> prevViewer;
    8604               0 :             mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
    8605               0 :             if (prevViewer) {
    8606                 : #ifdef DEBUG
    8607               0 :                 nsCOMPtr<nsIContentViewer> prevPrevViewer;
    8608               0 :                 prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
    8609               0 :                 NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
    8610                 : #endif
    8611               0 :                 nsCOMPtr<nsISHEntry> viewerEntry;
    8612               0 :                 prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
    8613               0 :                 if (viewerEntry == aSHEntry) {
    8614                 :                     // Make sure this viewer ends up in the right place
    8615               0 :                     mContentViewer->SetPreviousViewer(nsnull);
    8616               0 :                     prevViewer->Destroy();
    8617                 :                 }
    8618                 :             }
    8619                 :         }
    8620               0 :         nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
    8621                 :         bool restoring;
    8622               0 :         rv = RestorePresentation(aSHEntry, &restoring);
    8623               0 :         if (restoring)
    8624               0 :             return rv;
    8625                 : 
    8626                 :         // We failed to restore the presentation, so clean up.
    8627                 :         // Both the old and new history entries could potentially be in
    8628                 :         // an inconsistent state.
    8629               0 :         if (NS_FAILED(rv)) {
    8630               0 :             if (oldEntry)
    8631               0 :                 oldEntry->SyncPresentationState();
    8632                 : 
    8633               0 :             aSHEntry->SyncPresentationState();
    8634                 :         }
    8635                 :     }
    8636                 : 
    8637               0 :     nsCOMPtr<nsIRequest> req;
    8638                 :     rv = DoURILoad(aURI, aReferrer,
    8639                 :                    !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
    8640                 :                    owner, aTypeHint, aPostData, aHeadersData, aFirstParty,
    8641               0 :                    aDocShell, getter_AddRefs(req),
    8642                 :                    (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
    8643                 :                    (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
    8644               0 :                    (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0);
    8645               0 :     if (req && aRequest)
    8646               0 :         NS_ADDREF(*aRequest = req);
    8647                 : 
    8648               0 :     if (NS_FAILED(rv)) {
    8649               0 :         nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
    8650               0 :         DisplayLoadError(rv, aURI, nsnull, chan);
    8651                 :     }
    8652                 : 
    8653               0 :     return rv;
    8654                 : }
    8655                 : 
    8656                 : nsIPrincipal*
    8657               0 : nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
    8658                 : {
    8659               0 :     nsCOMPtr<nsIDocument> document;
    8660               0 :     bool inheritedFromCurrent = false;
    8661                 : 
    8662               0 :     if (aConsiderCurrentDocument && mContentViewer) {
    8663               0 :         document = mContentViewer->GetDocument();
    8664               0 :         inheritedFromCurrent = true;
    8665                 :     }
    8666                 : 
    8667               0 :     if (!document) {
    8668               0 :         nsCOMPtr<nsIDocShellTreeItem> parentItem;
    8669               0 :         GetSameTypeParent(getter_AddRefs(parentItem));
    8670               0 :         if (parentItem) {
    8671               0 :             document = do_GetInterface(parentItem);
    8672                 :         }
    8673                 :     }
    8674                 : 
    8675               0 :     if (!document) {
    8676               0 :         if (!aConsiderCurrentDocument) {
    8677               0 :             return nsnull;
    8678                 :         }
    8679                 : 
    8680                 :         // Make sure we end up with _something_ as the principal no matter
    8681                 :         // what.
    8682               0 :         EnsureContentViewer();  // If this fails, we'll just get a null
    8683                 :                                 // docViewer and bail.
    8684                 : 
    8685               0 :         if (!mContentViewer)
    8686               0 :             return nsnull;
    8687               0 :         document = mContentViewer->GetDocument();
    8688                 :     }
    8689                 : 
    8690                 :     //-- Get the document's principal
    8691               0 :     if (document) {
    8692               0 :         nsIPrincipal *docPrincipal = document->NodePrincipal();
    8693                 : 
    8694                 :         // Don't allow loads in typeContent docShells to inherit the system
    8695                 :         // principal from existing documents.
    8696               0 :         if (inheritedFromCurrent &&
    8697                 :             mItemType == typeContent &&
    8698               0 :             nsContentUtils::IsSystemPrincipal(docPrincipal)) {
    8699               0 :             return nsnull;
    8700                 :         }
    8701                 : 
    8702               0 :         return docPrincipal;
    8703                 :     }
    8704                 : 
    8705               0 :     return nsnull;
    8706                 : }
    8707                 : 
    8708                 : bool
    8709               0 : nsDocShell::ShouldCheckAppCache(nsIURI *aURI)
    8710                 : {
    8711                 :     nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
    8712               0 :         do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
    8713               0 :     if (!offlineService) {
    8714               0 :         return false;
    8715                 :     }
    8716                 : 
    8717                 :     bool allowed;
    8718               0 :     nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
    8719                 :                                                           nsnull,
    8720               0 :                                                           &allowed);
    8721               0 :     return NS_SUCCEEDED(rv) && allowed;
    8722                 : }
    8723                 : 
    8724                 : nsresult
    8725               0 : nsDocShell::DoURILoad(nsIURI * aURI,
    8726                 :                       nsIURI * aReferrerURI,
    8727                 :                       bool aSendReferrer,
    8728                 :                       nsISupports * aOwner,
    8729                 :                       const char * aTypeHint,
    8730                 :                       nsIInputStream * aPostData,
    8731                 :                       nsIInputStream * aHeadersData,
    8732                 :                       bool aFirstParty,
    8733                 :                       nsIDocShell ** aDocShell,
    8734                 :                       nsIRequest ** aRequest,
    8735                 :                       bool aIsNewWindowTarget,
    8736                 :                       bool aBypassClassifier,
    8737                 :                       bool aForceAllowCookies)
    8738                 : {
    8739                 :     nsresult rv;
    8740               0 :     nsCOMPtr<nsIURILoader> uriLoader;
    8741                 : 
    8742               0 :     uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
    8743               0 :     if (NS_FAILED(rv)) return rv;
    8744                 : 
    8745               0 :     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
    8746               0 :     if (aFirstParty) {
    8747                 :         // tag first party URL loads
    8748               0 :         loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
    8749                 :     }
    8750                 : 
    8751               0 :     if (mLoadType == LOAD_ERROR_PAGE) {
    8752                 :         // Error pages are LOAD_BACKGROUND
    8753               0 :         loadFlags |= nsIChannel::LOAD_BACKGROUND;
    8754                 :     }
    8755                 : 
    8756                 :     // check for Content Security Policy to pass along with the
    8757                 :     // new channel we are creating
    8758               0 :     nsCOMPtr<nsIChannelPolicy> channelPolicy;
    8759               0 :     if (IsFrame()) {
    8760                 :         // check the parent docshell for a CSP
    8761               0 :         nsCOMPtr<nsIContentSecurityPolicy> csp;
    8762               0 :         nsCOMPtr<nsIDocShellTreeItem> parentItem;
    8763               0 :         GetSameTypeParent(getter_AddRefs(parentItem));
    8764               0 :         nsCOMPtr<nsIDocument> doc = do_GetInterface(parentItem);
    8765               0 :         if (doc) {
    8766               0 :             rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
    8767               0 :             NS_ENSURE_SUCCESS(rv, rv);
    8768               0 :             if (csp) {
    8769               0 :                 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
    8770               0 :                 channelPolicy->SetContentSecurityPolicy(csp);
    8771               0 :                 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
    8772                 :             }
    8773                 :         }
    8774                 :     }
    8775                 : 
    8776                 :     // open a channel for the url
    8777               0 :     nsCOMPtr<nsIChannel> channel;
    8778                 : 
    8779               0 :     rv = NS_NewChannel(getter_AddRefs(channel),
    8780                 :                        aURI,
    8781                 :                        nsnull,
    8782                 :                        nsnull,
    8783                 :                        static_cast<nsIInterfaceRequestor *>(this),
    8784                 :                        loadFlags,
    8785               0 :                        channelPolicy);
    8786               0 :     if (NS_FAILED(rv)) {
    8787               0 :         if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
    8788                 :             // This is a uri with a protocol scheme we don't know how
    8789                 :             // to handle.  Embedders might still be interested in
    8790                 :             // handling the load, though, so we fire a notification
    8791                 :             // before throwing the load away.
    8792               0 :             bool abort = false;
    8793               0 :             nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
    8794               0 :             if (NS_SUCCEEDED(rv2) && abort) {
    8795                 :                 // Hey, they're handling the load for us!  How convenient!
    8796               0 :                 return NS_OK;
    8797                 :             }
    8798                 :         }
    8799                 :             
    8800               0 :         return rv;
    8801                 :     }
    8802                 : 
    8803                 :     nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
    8804               0 :         do_QueryInterface(channel);
    8805               0 :     if (appCacheChannel) {
    8806                 :         // Any document load should not inherit application cache.
    8807               0 :         appCacheChannel->SetInheritApplicationCache(false);
    8808                 : 
    8809                 :         // Loads with the correct permissions should check for a matching
    8810                 :         // application cache.
    8811                 :         // Permission will be checked in the parent process
    8812               0 :         if (GeckoProcessType_Default != XRE_GetProcessType())
    8813               0 :             appCacheChannel->SetChooseApplicationCache(true);
    8814                 :         else
    8815               0 :             appCacheChannel->SetChooseApplicationCache(
    8816               0 :                 ShouldCheckAppCache(aURI));
    8817                 :     }
    8818                 : 
    8819                 :     // Make sure to give the caller a channel if we managed to create one
    8820                 :     // This is important for correct error page/session history interaction
    8821               0 :     if (aRequest)
    8822               0 :         NS_ADDREF(*aRequest = channel);
    8823                 : 
    8824               0 :     channel->SetOriginalURI(aURI);
    8825               0 :     if (aTypeHint && *aTypeHint) {
    8826               0 :         channel->SetContentType(nsDependentCString(aTypeHint));
    8827               0 :         mContentTypeHint = aTypeHint;
    8828                 :     }
    8829                 :     else {
    8830               0 :         mContentTypeHint.Truncate();
    8831                 :     }
    8832                 :     
    8833                 :     //hack
    8834               0 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    8835               0 :     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
    8836               0 :     if (httpChannelInternal) {
    8837               0 :       if (aForceAllowCookies) {
    8838               0 :         httpChannelInternal->SetForceAllowThirdPartyCookie(true);
    8839                 :       } 
    8840               0 :       if (aFirstParty) {
    8841               0 :         httpChannelInternal->SetDocumentURI(aURI);
    8842                 :       } else {
    8843               0 :         httpChannelInternal->SetDocumentURI(aReferrerURI);
    8844                 :       }
    8845                 :     }
    8846                 : 
    8847               0 :     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
    8848               0 :     if (props)
    8849                 :     {
    8850                 :       // save true referrer for those who need it (e.g. xpinstall whitelisting)
    8851                 :       // Currently only http and ftp channels support this.
    8852               0 :       props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
    8853               0 :                                     aReferrerURI);
    8854                 :     }
    8855                 : 
    8856                 :     //
    8857                 :     // If this is a HTTP channel, then set up the HTTP specific information
    8858                 :     // (ie. POST data, referrer, ...)
    8859                 :     //
    8860               0 :     if (httpChannel) {
    8861               0 :         nsCOMPtr<nsICachingChannel>  cacheChannel(do_QueryInterface(httpChannel));
    8862                 :         /* Get the cache Key from SH */
    8863               0 :         nsCOMPtr<nsISupports> cacheKey;
    8864               0 :         if (mLSHE) {
    8865               0 :             mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
    8866                 :         }
    8867               0 :         else if (mOSHE)          // for reload cases
    8868               0 :             mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
    8869                 : 
    8870                 :         // figure out if we need to set the post data stream on the channel...
    8871                 :         // right now, this is only done for http channels.....
    8872               0 :         if (aPostData) {
    8873                 :             // XXX it's a bit of a hack to rewind the postdata stream here but
    8874                 :             // it has to be done in case the post data is being reused multiple
    8875                 :             // times.
    8876                 :             nsCOMPtr<nsISeekableStream>
    8877               0 :                 postDataSeekable(do_QueryInterface(aPostData));
    8878               0 :             if (postDataSeekable) {
    8879               0 :                 rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
    8880               0 :                 NS_ENSURE_SUCCESS(rv, rv);
    8881                 :             }
    8882                 : 
    8883               0 :             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
    8884               0 :             NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
    8885                 : 
    8886                 :             // we really need to have a content type associated with this stream!!
    8887               0 :             uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1);
    8888                 :             /* If there is a valid postdata *and* it is a History Load,
    8889                 :              * set up the cache key on the channel, to retrieve the
    8890                 :              * data *only* from the cache. If it is a normal reload, the 
    8891                 :              * cache is free to go to the server for updated postdata. 
    8892                 :              */
    8893               0 :             if (cacheChannel && cacheKey) {
    8894               0 :                 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
    8895               0 :                     cacheChannel->SetCacheKey(cacheKey);
    8896                 :                     PRUint32 loadFlags;
    8897               0 :                     if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags)))
    8898               0 :                         channel->SetLoadFlags(loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
    8899                 :                 }
    8900               0 :                 else if (mLoadType == LOAD_RELOAD_NORMAL)
    8901               0 :                     cacheChannel->SetCacheKey(cacheKey);
    8902                 :             }         
    8903                 :         }
    8904                 :         else {
    8905                 :             /* If there is no postdata, set the cache key on the channel, and
    8906                 :              * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
    8907                 :              * will be free to get it from net if it is not found in cache.
    8908                 :              * New cache may use it creatively on CGI pages with GET
    8909                 :              * method and even on those that say "no-cache"
    8910                 :              */
    8911               0 :             if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL 
    8912                 :                 || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
    8913               0 :                 if (cacheChannel && cacheKey)
    8914               0 :                     cacheChannel->SetCacheKey(cacheKey);
    8915                 :             }
    8916                 :         }
    8917               0 :         if (aHeadersData) {
    8918               0 :             rv = AddHeadersToChannel(aHeadersData, httpChannel);
    8919                 :         }
    8920                 :         // Set the referrer explicitly
    8921               0 :         if (aReferrerURI && aSendReferrer) {
    8922                 :             // Referrer is currenly only set for link clicks here.
    8923               0 :             httpChannel->SetReferrer(aReferrerURI);
    8924                 :         }
    8925                 :     }
    8926                 : 
    8927               0 :     nsCOMPtr<nsIPrincipal> ownerPrincipal(do_QueryInterface(aOwner));
    8928               0 :     nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true);
    8929                 : 
    8930               0 :     nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
    8931               0 :     if (scriptChannel) {
    8932                 :         // Allow execution against our context if the principals match
    8933               0 :         scriptChannel->
    8934               0 :             SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
    8935                 :     }
    8936                 : 
    8937               0 :     if (aIsNewWindowTarget) {
    8938               0 :         nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
    8939               0 :         if (props) {
    8940               0 :             props->SetPropertyAsBool(
    8941               0 :                 NS_LITERAL_STRING("docshell.newWindowTarget"),
    8942               0 :                 true);
    8943                 :         }
    8944                 :     }
    8945                 : 
    8946               0 :     if (Preferences::GetBool("dom.enable_performance", false)) {
    8947               0 :         nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
    8948               0 :         if (timedChannel) {
    8949               0 :             timedChannel->SetTimingEnabled(true);
    8950                 :         }
    8951                 :     }
    8952                 : 
    8953               0 :     rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
    8954                 : 
    8955                 :     //
    8956                 :     // If the channel load failed, we failed and nsIWebProgress just ain't
    8957                 :     // gonna happen.
    8958                 :     //
    8959               0 :     if (NS_SUCCEEDED(rv)) {
    8960               0 :         if (aDocShell) {
    8961               0 :           *aDocShell = this;
    8962               0 :           NS_ADDREF(*aDocShell);
    8963                 :         }
    8964                 :     }
    8965                 : 
    8966               0 :     return rv;
    8967                 : }
    8968                 : 
    8969                 : static NS_METHOD
    8970               0 : AppendSegmentToString(nsIInputStream *in,
    8971                 :                       void *closure,
    8972                 :                       const char *fromRawSegment,
    8973                 :                       PRUint32 toOffset,
    8974                 :                       PRUint32 count,
    8975                 :                       PRUint32 *writeCount)
    8976                 : {
    8977                 :     // aFromSegment now contains aCount bytes of data.
    8978                 : 
    8979               0 :     nsCAutoString *buf = static_cast<nsCAutoString *>(closure);
    8980               0 :     buf->Append(fromRawSegment, count);
    8981                 : 
    8982                 :     // Indicate that we have consumed all of aFromSegment
    8983               0 :     *writeCount = count;
    8984               0 :     return NS_OK;
    8985                 : }
    8986                 : 
    8987                 : NS_IMETHODIMP
    8988               0 : nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData,
    8989                 :                                 nsIChannel *aGenericChannel)
    8990                 : {
    8991               0 :     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
    8992               0 :     NS_ENSURE_STATE(httpChannel);
    8993                 : 
    8994                 :     PRUint32 numRead;
    8995               0 :     nsCAutoString headersString;
    8996                 :     nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
    8997                 :                                              &headersString,
    8998                 :                                              PR_UINT32_MAX,
    8999               0 :                                              &numRead);
    9000               0 :     NS_ENSURE_SUCCESS(rv, rv);
    9001                 : 
    9002                 :     // used during the manipulation of the String from the InputStream
    9003               0 :     nsCAutoString headerName;
    9004               0 :     nsCAutoString headerValue;
    9005                 :     PRInt32 crlf;
    9006                 :     PRInt32 colon;
    9007                 : 
    9008                 :     //
    9009                 :     // Iterate over the headersString: for each "\r\n" delimited chunk,
    9010                 :     // add the value as a header to the nsIHttpChannel
    9011                 :     //
    9012                 : 
    9013                 :     static const char kWhitespace[] = "\b\t\r\n ";
    9014               0 :     while (true) {
    9015               0 :         crlf = headersString.Find("\r\n");
    9016               0 :         if (crlf == kNotFound)
    9017               0 :             return NS_OK;
    9018                 : 
    9019               0 :         const nsCSubstring &oneHeader = StringHead(headersString, crlf);
    9020                 : 
    9021               0 :         colon = oneHeader.FindChar(':');
    9022               0 :         if (colon == kNotFound)
    9023               0 :             return NS_ERROR_UNEXPECTED;
    9024                 : 
    9025               0 :         headerName = StringHead(oneHeader, colon);
    9026               0 :         headerValue = Substring(oneHeader, colon + 1);
    9027                 : 
    9028               0 :         headerName.Trim(kWhitespace);
    9029               0 :         headerValue.Trim(kWhitespace);
    9030                 : 
    9031               0 :         headersString.Cut(0, crlf + 2);
    9032                 : 
    9033                 :         //
    9034                 :         // FINALLY: we can set the header!
    9035                 :         // 
    9036                 : 
    9037               0 :         rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
    9038               0 :         NS_ENSURE_SUCCESS(rv, rv);
    9039                 :     }
    9040                 : 
    9041                 :     NS_NOTREACHED("oops");
    9042                 :     return NS_ERROR_UNEXPECTED;
    9043                 : }
    9044                 : 
    9045               0 : nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
    9046                 :                                    nsIURILoader * aURILoader,
    9047                 :                                    bool aBypassClassifier)
    9048                 : {
    9049                 :     nsresult rv;
    9050                 :     // Mark the channel as being a document URI and allow content sniffing...
    9051               0 :     nsLoadFlags loadFlags = 0;
    9052               0 :     (void) aChannel->GetLoadFlags(&loadFlags);
    9053                 :     loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
    9054               0 :                  nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
    9055                 : 
    9056                 :     // Load attributes depend on load type...
    9057               0 :     switch (mLoadType) {
    9058                 :     case LOAD_HISTORY:
    9059                 :         {
    9060                 :             // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
    9061                 :             // push/replaceState (bug 669671).
    9062               0 :             bool uriModified = false;
    9063               0 :             if (mLSHE) {
    9064               0 :                 mLSHE->GetURIWasModified(&uriModified);
    9065                 :             }
    9066                 : 
    9067               0 :             if (!uriModified)
    9068               0 :                 loadFlags |= nsIRequest::VALIDATE_NEVER;
    9069                 :         }
    9070               0 :         break;
    9071                 : 
    9072                 :     case LOAD_RELOAD_CHARSET_CHANGE:
    9073               0 :         loadFlags |= nsIRequest::LOAD_FROM_CACHE;
    9074               0 :         break;
    9075                 :     
    9076                 :     case LOAD_RELOAD_NORMAL:
    9077                 :     case LOAD_REFRESH:
    9078               0 :         loadFlags |= nsIRequest::VALIDATE_ALWAYS;
    9079               0 :         break;
    9080                 : 
    9081                 :     case LOAD_NORMAL_BYPASS_CACHE:
    9082                 :     case LOAD_NORMAL_BYPASS_PROXY:
    9083                 :     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
    9084                 :     case LOAD_RELOAD_BYPASS_CACHE:
    9085                 :     case LOAD_RELOAD_BYPASS_PROXY:
    9086                 :     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
    9087                 :         loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
    9088               0 :                      nsIRequest::LOAD_FRESH_CONNECTION;
    9089               0 :         break;
    9090                 : 
    9091                 :     case LOAD_NORMAL:
    9092                 :     case LOAD_LINK:
    9093                 :         // Set cache checking flags
    9094               0 :         switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
    9095                 :         case 0:
    9096               0 :             loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
    9097               0 :             break;
    9098                 :         case 1:
    9099               0 :             loadFlags |= nsIRequest::VALIDATE_ALWAYS;
    9100               0 :             break;
    9101                 :         case 2:
    9102               0 :             loadFlags |= nsIRequest::VALIDATE_NEVER;
    9103               0 :             break;
    9104                 :         }
    9105               0 :         break;
    9106                 :     }
    9107                 : 
    9108               0 :     if (!aBypassClassifier) {
    9109               0 :         loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
    9110                 :     }
    9111                 : 
    9112               0 :     (void) aChannel->SetLoadFlags(loadFlags);
    9113                 : 
    9114                 :     rv = aURILoader->OpenURI(aChannel,
    9115                 :                              (mLoadType == LOAD_LINK),
    9116               0 :                              this);
    9117               0 :     NS_ENSURE_SUCCESS(rv, rv);
    9118                 : 
    9119               0 :     return NS_OK;
    9120                 : }
    9121                 : 
    9122                 : nsresult
    9123               0 : nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
    9124                 :                            PRUint32 aLoadType)
    9125                 : {
    9126               0 :     if (!mCurrentURI) {
    9127               0 :         return NS_OK;
    9128                 :     }
    9129                 : 
    9130               0 :     nsCOMPtr<nsIPresShell> shell;
    9131               0 :     nsresult rv = GetPresShell(getter_AddRefs(shell));
    9132               0 :     if (NS_FAILED(rv) || !shell) {
    9133                 :         // If we failed to get the shell, or if there is no shell,
    9134                 :         // nothing left to do here.
    9135               0 :         return rv;
    9136                 :     }
    9137                 : 
    9138                 :     // If we have no new anchor, we do not want to scroll, unless there is a
    9139                 :     // current anchor and we are doing a history load.  So return if we have no
    9140                 :     // new anchor, and there is no current anchor or the load is not a history
    9141                 :     // load.
    9142               0 :     if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) &&
    9143               0 :         aNewHash.IsEmpty()) {
    9144               0 :         return NS_OK;
    9145                 :     }
    9146                 : 
    9147                 :     // Take the '#' off aNewHash to get the ref name.  (aNewHash might be empty,
    9148                 :     // but that's fine.)
    9149               0 :     nsDependentCSubstring newHashName(aNewHash, 1);
    9150                 : 
    9151                 :     // Both the new and current URIs refer to the same page. We can now
    9152                 :     // browse to the hash stored in the new URI.
    9153                 : 
    9154               0 :     if (!newHashName.IsEmpty()) {
    9155                 :         // anchor is there, but if it's a load from history,
    9156                 :         // we don't have any anchor jumping to do
    9157                 :         bool scroll = aLoadType != LOAD_HISTORY &&
    9158               0 :                         aLoadType != LOAD_RELOAD_NORMAL;
    9159                 : 
    9160               0 :         char *str = ToNewCString(newHashName);
    9161               0 :         if (!str) {
    9162               0 :             return NS_ERROR_OUT_OF_MEMORY;
    9163                 :         }
    9164                 : 
    9165                 :         // nsUnescape modifies the string that is passed into it.
    9166               0 :         nsUnescape(str);
    9167                 : 
    9168                 :         // We assume that the bytes are in UTF-8, as it says in the
    9169                 :         // spec:
    9170                 :         // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
    9171                 : 
    9172                 :         // We try the UTF-8 string first, and then try the document's
    9173                 :         // charset (see below).  If the string is not UTF-8,
    9174                 :         // conversion will fail and give us an empty Unicode string.
    9175                 :         // In that case, we should just fall through to using the
    9176                 :         // page's charset.
    9177               0 :         rv = NS_ERROR_FAILURE;
    9178               0 :         NS_ConvertUTF8toUTF16 uStr(str);
    9179               0 :         if (!uStr.IsEmpty()) {
    9180               0 :             rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll);
    9181                 :         }
    9182               0 :         nsMemory::Free(str);
    9183                 : 
    9184                 :         // Above will fail if the anchor name is not UTF-8.  Need to
    9185                 :         // convert from document charset to unicode.
    9186               0 :         if (NS_FAILED(rv)) {
    9187                 :                 
    9188                 :             // Get a document charset
    9189               0 :             NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
    9190               0 :             nsIDocument* doc = mContentViewer->GetDocument();
    9191               0 :             NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    9192               0 :             const nsACString &aCharset = doc->GetDocumentCharacterSet();
    9193                 : 
    9194                 :             nsCOMPtr<nsITextToSubURI> textToSubURI =
    9195               0 :                 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
    9196               0 :             NS_ENSURE_SUCCESS(rv, rv);
    9197                 : 
    9198                 :             // Unescape and convert to unicode
    9199               0 :             nsXPIDLString uStr;
    9200                 : 
    9201               0 :             rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
    9202               0 :                                                   PromiseFlatCString(newHashName).get(),
    9203               0 :                                                   getter_Copies(uStr));
    9204               0 :             NS_ENSURE_SUCCESS(rv, rv);
    9205                 : 
    9206                 :             // Ignore return value of GoToAnchor, since it will return an error
    9207                 :             // if there is no such anchor in the document, which is actually a
    9208                 :             // success condition for us (we want to update the session history
    9209                 :             // with the new URI no matter whether we actually scrolled
    9210                 :             // somewhere).
    9211               0 :             shell->GoToAnchor(uStr, scroll);
    9212                 :         }
    9213                 :     }
    9214                 :     else {
    9215                 : 
    9216                 :         // Tell the shell it's at an anchor, without scrolling.
    9217               0 :         shell->GoToAnchor(EmptyString(), false);
    9218                 :         
    9219                 :         // An empty anchor was found, but if it's a load from history,
    9220                 :         // we don't have to jump to the top of the page. Scrollbar 
    9221                 :         // position will be restored by the caller, based on positions
    9222                 :         // stored in session history.
    9223               0 :         if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
    9224               0 :             return NS_OK;
    9225                 :         // An empty anchor. Scroll to the top of the page.  Ignore the
    9226                 :         // return value; failure to scroll here (e.g. if there is no
    9227                 :         // root scrollframe) is not grounds for canceling the load!
    9228               0 :         SetCurScrollPosEx(0, 0);
    9229                 :     }
    9230                 : 
    9231               0 :     return NS_OK;
    9232                 : }
    9233                 : 
    9234                 : void
    9235               0 : nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
    9236                 : {
    9237               0 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
    9238               0 :     if (httpChannel) {
    9239               0 :         nsCOMPtr<nsIURI> referrer;
    9240               0 :         nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
    9241               0 :         if (NS_SUCCEEDED(rv)) {
    9242               0 :             SetReferrerURI(referrer);
    9243                 :         }
    9244                 :     }
    9245               0 : }
    9246                 : 
    9247                 : bool
    9248               0 : nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
    9249                 :                      PRUint32 aLoadType, bool aFireOnLocationChange,
    9250                 :                      bool aAddToGlobalHistory, bool aCloneSHChildren)
    9251                 : {
    9252               0 :     NS_PRECONDITION(aURI, "uri is null");
    9253               0 :     NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
    9254                 : 
    9255                 : #if defined(PR_LOGGING) && defined(DEBUG)
    9256               0 :     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
    9257               0 :         nsCAutoString spec;
    9258               0 :         aURI->GetSpec(spec);
    9259                 : 
    9260               0 :         nsCAutoString chanName;
    9261               0 :         if (aChannel)
    9262               0 :             aChannel->GetName(chanName);
    9263                 :         else
    9264               0 :             chanName.AssignLiteral("<no channel>");
    9265                 : 
    9266               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    9267                 :                ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
    9268                 :                 chanName.get(), aLoadType));
    9269                 :     }
    9270                 : #endif
    9271                 : 
    9272               0 :     bool updateHistory = true;
    9273               0 :     bool equalUri = false;
    9274               0 :     bool shAvailable = true;  
    9275                 : 
    9276                 :     // Get the post data from the channel
    9277               0 :     nsCOMPtr<nsIInputStream> inputStream;
    9278               0 :     if (aChannel) {
    9279               0 :         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
    9280                 : 
    9281                 :         // Check if the HTTPChannel is hiding under a multiPartChannel
    9282               0 :         if (!httpChannel)  {
    9283               0 :             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
    9284                 :         }
    9285                 : 
    9286               0 :         if (httpChannel) {
    9287               0 :             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
    9288               0 :             if (uploadChannel) {
    9289               0 :                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
    9290                 :             }
    9291                 : 
    9292                 :             // If the response status indicates an error, unlink this session
    9293                 :             // history entry from any entries sharing its document.
    9294                 :             PRUint32 responseStatus;
    9295               0 :             nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
    9296               0 :             if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
    9297               0 :                 mLSHE->AbandonBFCacheEntry();
    9298                 :             }
    9299                 :         }
    9300                 :     }
    9301                 :     /* Create SH Entry (mLSHE) only if there is a  SessionHistory object (mSessionHistory) in
    9302                 :      * the current frame or in the root docshell
    9303                 :      */
    9304               0 :     nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
    9305               0 :     if (!rootSH) {
    9306                 :         // Get the handle to SH from the root docshell          
    9307               0 :         GetRootSessionHistory(getter_AddRefs(rootSH));
    9308               0 :         if (!rootSH)
    9309               0 :             shAvailable = false;
    9310                 :     }  // rootSH
    9311                 : 
    9312                 : 
    9313                 :     // Determine if this type of load should update history.
    9314               0 :     if (aLoadType == LOAD_BYPASS_HISTORY ||
    9315                 :         aLoadType == LOAD_ERROR_PAGE ||
    9316                 :         aLoadType & LOAD_CMD_HISTORY ||
    9317                 :         aLoadType & LOAD_CMD_RELOAD)
    9318               0 :         updateHistory = false;
    9319                 : 
    9320                 :     // Check if the url to be loaded is the same as the one already loaded.
    9321               0 :     if (mCurrentURI)
    9322               0 :         aURI->Equals(mCurrentURI, &equalUri);
    9323                 : 
    9324                 : #ifdef DEBUG
    9325               0 :     PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    9326                 :            ("  shAvailable=%i updateHistory=%i equalURI=%i\n",
    9327                 :             shAvailable, updateHistory, equalUri));
    9328                 : 
    9329               0 :     if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
    9330               0 :         NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?");
    9331                 :     }
    9332                 : #endif
    9333                 : 
    9334                 :     /* If the url to be loaded is the same as the one already there,
    9335                 :      * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
    9336                 :      * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
    9337                 :      * AddToSessionHistory() won't mess with the current SHEntry and
    9338                 :      * if this page has any frame children, it also will be handled
    9339                 :      * properly. see bug 83684
    9340                 :      *
    9341                 :      * NB: If mOSHE is null but we have a current URI, then it means
    9342                 :      * that we must be at the transient about:blank content viewer
    9343                 :      * (asserted above) and we should let the normal load continue,
    9344                 :      * since there's nothing to replace.
    9345                 :      *
    9346                 :      * XXX Hopefully changing the loadType at this time will not hurt  
    9347                 :      *  anywhere. The other way to take care of sequentially repeating
    9348                 :      *  frameset pages is to add new methods to nsIDocShellTreeItem.
    9349                 :      * Hopefully I don't have to do that. 
    9350                 :      */
    9351               0 :     if (equalUri &&
    9352               0 :         mOSHE &&
    9353                 :         (mLoadType == LOAD_NORMAL ||
    9354                 :          mLoadType == LOAD_LINK ||
    9355                 :          mLoadType == LOAD_STOP_CONTENT) &&
    9356               0 :         !inputStream)
    9357                 :     {
    9358               0 :         mLoadType = LOAD_NORMAL_REPLACE;
    9359                 :     }
    9360                 : 
    9361                 :     // If this is a refresh to the currently loaded url, we don't
    9362                 :     // have to update session or global history.
    9363               0 :     if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
    9364               0 :         SetHistoryEntry(&mLSHE, mOSHE);
    9365                 :     }
    9366                 : 
    9367                 :     /* If the user pressed shift-reload, cache will create a new cache key
    9368                 :      * for the page. Save the new cacheKey in Session History. 
    9369                 :      * see bug 90098
    9370                 :      */
    9371               0 :     if (aChannel &&
    9372                 :         (aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
    9373                 :          aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
    9374                 :          aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
    9375               0 :         NS_ASSERTION(!updateHistory,
    9376                 :                      "We shouldn't be updating history for forced reloads!");
    9377                 :         
    9378               0 :         nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
    9379               0 :         nsCOMPtr<nsISupports>  cacheKey;
    9380                 :         // Get the Cache Key and store it in SH.
    9381               0 :         if (cacheChannel)
    9382               0 :             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
    9383                 :         // If we already have a loading history entry, store the new cache key
    9384                 :         // in it.  Otherwise, since we're doing a reload and won't be updating
    9385                 :         // our history entry, store the cache key in our current history entry.
    9386               0 :         if (mLSHE)
    9387               0 :             mLSHE->SetCacheKey(cacheKey);
    9388               0 :         else if (mOSHE)
    9389               0 :             mOSHE->SetCacheKey(cacheKey);
    9390                 : 
    9391                 :         // Since we're force-reloading, clear all the sub frame history.
    9392               0 :         ClearFrameHistory(mLSHE);
    9393               0 :         ClearFrameHistory(mOSHE);
    9394                 :     }
    9395                 : 
    9396               0 :     if (aLoadType == LOAD_RELOAD_NORMAL) {
    9397               0 :         nsCOMPtr<nsISHEntry> currentSH;
    9398               0 :         bool oshe = false;
    9399               0 :         GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
    9400               0 :         bool dynamicallyAddedChild = false;
    9401               0 :         if (currentSH) {
    9402               0 :           currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
    9403                 :         }
    9404               0 :         if (dynamicallyAddedChild) {
    9405               0 :           ClearFrameHistory(currentSH);
    9406                 :         }
    9407                 :     }
    9408                 : 
    9409               0 :     if (aLoadType == LOAD_REFRESH) {
    9410               0 :         ClearFrameHistory(mLSHE);
    9411               0 :         ClearFrameHistory(mOSHE);
    9412                 :     }
    9413                 : 
    9414               0 :     if (updateHistory && shAvailable) { 
    9415                 :         // Update session history if necessary...
    9416               0 :         if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
    9417                 :             /* This is  a fresh page getting loaded for the first time
    9418                 :              *.Create a Entry for it and add it to SH, if this is the
    9419                 :              * rootDocShell
    9420                 :              */
    9421                 :             (void) AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren,
    9422               0 :                                        getter_AddRefs(mLSHE));
    9423                 :         }
    9424                 : 
    9425               0 :         if (aAddToGlobalHistory) {
    9426                 :             // If this is a POST request, we do not want to include this in global
    9427                 :             // history.
    9428               0 :             if (!ChannelIsPost(aChannel)) {
    9429               0 :                 nsCOMPtr<nsIURI> previousURI;
    9430               0 :                 PRUint32 previousFlags = 0;
    9431               0 :                 ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
    9432               0 :                                  &previousFlags);
    9433                 : 
    9434               0 :                 nsCOMPtr<nsIURI> referrer;
    9435                 :                 // Treat referrer as null if there is an error getting it.
    9436                 :                 (void)NS_GetReferrerFromChannel(aChannel,
    9437               0 :                                                 getter_AddRefs(referrer));
    9438                 : 
    9439               0 :                 AddURIVisit(aURI, referrer, previousURI, previousFlags);
    9440                 :             }
    9441                 :         }
    9442                 :     }
    9443                 : 
    9444                 :     // If this was a history load or a refresh,
    9445                 :     // update the index in SH. 
    9446               0 :     if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) {
    9447               0 :         nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
    9448               0 :         if (shInternal) {
    9449               0 :             rootSH->GetIndex(&mPreviousTransIndex);
    9450               0 :             shInternal->UpdateIndex();
    9451               0 :             rootSH->GetIndex(&mLoadedTransIndex);
    9452                 : #ifdef DEBUG_PAGE_CACHE
    9453                 :             printf("Previous index: %d, Loaded index: %d\n\n",
    9454                 :                    mPreviousTransIndex, mLoadedTransIndex);
    9455                 : #endif
    9456                 :         }
    9457                 :     }
    9458                 : 
    9459                 :     // aCloneSHChildren exactly means "we are not loading a new document".
    9460                 :     PRUint32 locationFlags = aCloneSHChildren?
    9461               0 :                                  PRUint32(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
    9462                 : 
    9463                 :     bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
    9464                 :                                                 aFireOnLocationChange,
    9465               0 :                                                 locationFlags);
    9466                 :     // Make sure to store the referrer from the channel, if any
    9467               0 :     SetupReferrerFromChannel(aChannel);
    9468               0 :     return onLocationChangeNeeded;
    9469                 : }
    9470                 : 
    9471                 : bool
    9472               0 : nsDocShell::OnLoadingSite(nsIChannel * aChannel, bool aFireOnLocationChange,
    9473                 :                           bool aAddToGlobalHistory)
    9474                 : {
    9475               0 :     nsCOMPtr<nsIURI> uri;
    9476                 :     // If this a redirect, use the final url (uri)
    9477                 :     // else use the original url
    9478                 :     //
    9479                 :     // Note that this should match what documents do (see nsDocument::Reset).
    9480               0 :     NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    9481               0 :     NS_ENSURE_TRUE(uri, false);
    9482                 : 
    9483                 :     // Pass false for aCloneSHChildren, since we're loading a new page here.
    9484                 :     return OnNewURI(uri, aChannel, nsnull, mLoadType, aFireOnLocationChange,
    9485               0 :                     aAddToGlobalHistory, false);
    9486                 : 
    9487                 : }
    9488                 : 
    9489                 : void
    9490               0 : nsDocShell::SetReferrerURI(nsIURI * aURI)
    9491                 : {
    9492               0 :     mReferrerURI = aURI;        // This assigment addrefs
    9493               0 : }
    9494                 : 
    9495                 : //*****************************************************************************
    9496                 : // nsDocShell: Session History
    9497                 : //*****************************************************************************
    9498                 : 
    9499                 : NS_IMETHODIMP
    9500               0 : nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
    9501                 :                      const nsAString& aURL, bool aReplace, JSContext* aCx)
    9502                 : {
    9503                 :     // Implements History.pushState and History.replaceState
    9504                 : 
    9505                 :     // Here's what we do, roughly in the order specified by HTML5:
    9506                 :     // 1. Serialize aData using structured clone.
    9507                 :     // 2. If the third argument is present,
    9508                 :     //     a. Resolve the url, relative to the first script's base URL
    9509                 :     //     b. If (a) fails, raise a SECURITY_ERR
    9510                 :     //     c. Compare the resulting absolute URL to the document's address.  If
    9511                 :     //        any part of the URLs difer other than the <path>, <query>, and
    9512                 :     //        <fragment> components, raise a SECURITY_ERR and abort.
    9513                 :     // 3. If !aReplace:
    9514                 :     //     Remove from the session history all entries after the current entry,
    9515                 :     //     as we would after a regular navigation, and save the current
    9516                 :     //     entry's scroll position (bug 590573).
    9517                 :     // 4. As apropriate, either add a state object entry to the session history
    9518                 :     //    after the current entry with the following properties, or modify the
    9519                 :     //    current session history entry to set
    9520                 :     //      a. cloned data as the state object,
    9521                 :     //      b. if the third argument was present, the absolute URL found in
    9522                 :     //         step 2
    9523                 :     //    Also clear the new history entry's POST data (see bug 580069).
    9524                 :     // 5. If aReplace is false (i.e. we're doing a pushState instead of a
    9525                 :     //    replaceState), notify bfcache that we've navigated to a new page.
    9526                 :     // 6. If the third argument is present, set the document's current address
    9527                 :     //    to the absolute URL found in step 2.
    9528                 :     //
    9529                 :     // It's important that this function not run arbitrary scripts after step 1
    9530                 :     // and before completing step 5.  For example, if a script called
    9531                 :     // history.back() before we completed step 5, bfcache might destroy an
    9532                 :     // active content viewer.  Since EvictOutOfRangeContentViewers at the end of
    9533                 :     // step 5 might run script, we can't just put a script blocker around the
    9534                 :     // critical section.
    9535                 :     //
    9536                 :     // Note that we completely ignore the aTitle parameter.
    9537                 : 
    9538                 :     nsresult rv;
    9539                 : 
    9540               0 :     nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
    9541               0 :     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
    9542                 : 
    9543                 :     // Step 1: Serialize aData using structured clone.
    9544               0 :     nsCOMPtr<nsIStructuredCloneContainer> scContainer;
    9545                 : 
    9546                 :     // scContainer->Init might cause arbitrary JS to run, and this code might
    9547                 :     // navigate the page we're on, potentially to a different origin! (bug
    9548                 :     // 634834)  To protect against this, we abort if our principal changes due
    9549                 :     // to the InitFromVariant() call.
    9550                 :     {
    9551                 :         nsCOMPtr<nsIDocument> origDocument =
    9552               0 :             do_GetInterface(GetAsSupports(this));
    9553               0 :         if (!origDocument)
    9554               0 :             return NS_ERROR_DOM_SECURITY_ERR;
    9555               0 :         nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
    9556                 : 
    9557               0 :         scContainer = new nsStructuredCloneContainer();
    9558               0 :         JSContext *cx = aCx;
    9559               0 :         if (!cx) {
    9560               0 :             cx = nsContentUtils::GetContextFromDocument(document);
    9561                 :         }
    9562               0 :         rv = scContainer->InitFromVariant(aData, cx);
    9563                 : 
    9564                 :         // If we're running in the document's context and the structured clone
    9565                 :         // failed, clear the context's pending exception.  See bug 637116.
    9566               0 :         if (NS_FAILED(rv) && !aCx) {
    9567               0 :             JS_ClearPendingException(aCx);
    9568                 :         }
    9569               0 :         NS_ENSURE_SUCCESS(rv, rv);
    9570                 : 
    9571                 :         nsCOMPtr<nsIDocument> newDocument =
    9572               0 :             do_GetInterface(GetAsSupports(this));
    9573               0 :         if (!newDocument)
    9574               0 :             return NS_ERROR_DOM_SECURITY_ERR;
    9575               0 :         nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
    9576                 : 
    9577               0 :         bool principalsEqual = false;
    9578               0 :         origPrincipal->Equals(newPrincipal, &principalsEqual);
    9579               0 :         NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
    9580                 :     }
    9581                 : 
    9582                 :     // Check that the state object isn't too long.
    9583                 :     // Default max length: 640k bytes.
    9584                 :     PRInt32 maxStateObjSize =
    9585               0 :         Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
    9586               0 :     if (maxStateObjSize < 0) {
    9587               0 :         maxStateObjSize = 0;
    9588                 :     }
    9589                 : 
    9590                 :     PRUint64 scSize;
    9591               0 :     rv = scContainer->GetSerializedNBytes(&scSize);
    9592               0 :     NS_ENSURE_SUCCESS(rv, rv);
    9593                 : 
    9594               0 :     NS_ENSURE_TRUE(scSize <= (PRUint32)maxStateObjSize,
    9595                 :                    NS_ERROR_ILLEGAL_VALUE);
    9596                 : 
    9597                 :     // Step 2: Resolve aURL
    9598               0 :     bool equalURIs = true;
    9599               0 :     nsCOMPtr<nsIURI> oldURI = mCurrentURI;
    9600               0 :     nsCOMPtr<nsIURI> newURI;
    9601               0 :     if (aURL.Length() == 0) {
    9602               0 :         newURI = mCurrentURI;
    9603                 :     }
    9604                 :     else {
    9605                 :         // 2a: Resolve aURL relative to mURI
    9606                 : 
    9607               0 :         nsIURI* docBaseURI = document->GetDocBaseURI();
    9608               0 :         if (!docBaseURI)
    9609               0 :             return NS_ERROR_FAILURE;
    9610                 : 
    9611               0 :         nsCAutoString spec;
    9612               0 :         docBaseURI->GetSpec(spec);
    9613                 : 
    9614               0 :         nsCAutoString charset;
    9615               0 :         rv = docBaseURI->GetOriginCharset(charset);
    9616               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    9617                 : 
    9618               0 :         rv = NS_NewURI(getter_AddRefs(newURI), aURL,
    9619               0 :                        charset.get(), docBaseURI);
    9620                 : 
    9621                 :         // 2b: If 2a fails, raise a SECURITY_ERR
    9622               0 :         if (NS_FAILED(rv)) {
    9623               0 :             return NS_ERROR_DOM_SECURITY_ERR;
    9624                 :         }
    9625                 : 
    9626                 :         // 2c: Same-origin check.
    9627               0 :         if (!nsContentUtils::URIIsLocalFile(newURI)) {
    9628                 :             // In addition to checking that the security manager says that
    9629                 :             // the new URI has the same origin as our current URI, we also
    9630                 :             // check that the two URIs have the same userpass. (The
    9631                 :             // security manager says that |http://foo.com| and
    9632                 :             // |http://me@foo.com| have the same origin.)  mCurrentURI
    9633                 :             // won't contain the password part of the userpass, so this
    9634                 :             // means that it's never valid to specify a password in a
    9635                 :             // pushState or replaceState URI.
    9636                 : 
    9637                 :             nsCOMPtr<nsIScriptSecurityManager> secMan =
    9638               0 :                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
    9639               0 :             NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
    9640                 : 
    9641                 :             // It's very important that we check that newURI is of the same
    9642                 :             // origin as mCurrentURI, not docBaseURI, because a page can
    9643                 :             // set docBaseURI arbitrarily to any domain.
    9644               0 :             nsCAutoString currentUserPass, newUserPass;
    9645               0 :             NS_ENSURE_SUCCESS(mCurrentURI->GetUserPass(currentUserPass),
    9646                 :                               NS_ERROR_FAILURE);
    9647               0 :             NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass),
    9648                 :                               NS_ERROR_FAILURE);
    9649               0 :             if (NS_FAILED(secMan->CheckSameOriginURI(mCurrentURI,
    9650                 :                                                      newURI, true)) ||
    9651               0 :                 !currentUserPass.Equals(newUserPass)) {
    9652                 : 
    9653               0 :                 return NS_ERROR_DOM_SECURITY_ERR;
    9654                 :             }
    9655                 :         }
    9656                 :         else {
    9657                 :             // It's a file:// URI
    9658                 :             nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
    9659               0 :                 do_QueryInterface(document);
    9660                 : 
    9661               0 :             if (!docScriptObj) {
    9662               0 :                 return NS_ERROR_DOM_SECURITY_ERR;
    9663                 :             }
    9664                 : 
    9665               0 :             nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
    9666                 : 
    9667               0 :             if (!principal ||
    9668               0 :                 NS_FAILED(principal->CheckMayLoad(newURI, true))) {
    9669                 : 
    9670               0 :                 return NS_ERROR_DOM_SECURITY_ERR;
    9671                 :             }
    9672                 :         }
    9673                 : 
    9674               0 :         mCurrentURI->Equals(newURI, &equalURIs);
    9675                 : 
    9676                 :     } // end of same-origin check
    9677                 : 
    9678               0 :     nsCOMPtr<nsISHistory> sessionHistory = mSessionHistory;
    9679               0 :     if (!sessionHistory) {
    9680                 :         // Get the handle to SH from the root docshell
    9681               0 :         GetRootSessionHistory(getter_AddRefs(sessionHistory));
    9682                 :     }
    9683               0 :     NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
    9684                 : 
    9685                 :     nsCOMPtr<nsISHistoryInternal> shInternal =
    9686               0 :         do_QueryInterface(sessionHistory, &rv);
    9687               0 :     NS_ENSURE_SUCCESS(rv, rv);
    9688                 : 
    9689                 :     // Step 3: Create a new entry in the session history. This will erase
    9690                 :     // all SHEntries after the new entry and make this entry the current
    9691                 :     // one.  This operation may modify mOSHE, which we need later, so we
    9692                 :     // keep a reference here.
    9693               0 :     NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
    9694               0 :     nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
    9695                 : 
    9696               0 :     mLoadType = LOAD_PUSHSTATE;
    9697                 : 
    9698               0 :     nsCOMPtr<nsISHEntry> newSHEntry;
    9699               0 :     if (!aReplace) {
    9700                 :         // Save the current scroll position (bug 590573).
    9701               0 :         nscoord cx = 0, cy = 0;
    9702               0 :         GetCurScrollPos(ScrollOrientation_X, &cx);
    9703               0 :         GetCurScrollPos(ScrollOrientation_Y, &cy);
    9704               0 :         mOSHE->SetScrollPosition(cx, cy);
    9705                 : 
    9706                 :         // Since we're not changing which page we have loaded, pass
    9707                 :         // true for aCloneChildren.
    9708                 :         rv = AddToSessionHistory(newURI, nsnull, nsnull, true,
    9709               0 :                                  getter_AddRefs(newSHEntry));
    9710               0 :         NS_ENSURE_SUCCESS(rv, rv);
    9711                 : 
    9712               0 :         NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
    9713                 : 
    9714                 :         // Link the new SHEntry to the old SHEntry's BFCache entry, since the
    9715                 :         // two entries correspond to the same document.
    9716               0 :         NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE),
    9717                 :                           NS_ERROR_FAILURE);
    9718                 : 
    9719                 :         // Set the new SHEntry's title (bug 655273).
    9720               0 :         nsString title;
    9721               0 :         mOSHE->GetTitle(getter_Copies(title));
    9722               0 :         newSHEntry->SetTitle(title);
    9723                 : 
    9724                 :         // AddToSessionHistory may not modify mOSHE.  In case it doesn't,
    9725                 :         // we'll just set mOSHE here.
    9726               0 :         mOSHE = newSHEntry;
    9727                 : 
    9728                 :     } else {
    9729               0 :         newSHEntry = mOSHE;
    9730               0 :         newSHEntry->SetURI(newURI);
    9731                 :     }
    9732                 : 
    9733                 :     // Step 4: Modify new/original session history entry and clear its POST
    9734                 :     // data, if there is any.
    9735               0 :     newSHEntry->SetStateData(scContainer);
    9736               0 :     newSHEntry->SetPostData(nsnull);
    9737                 : 
    9738                 :     // If this push/replaceState changed the document's current URI and the new
    9739                 :     // URI differs from the old URI in more than the hash, or if the old
    9740                 :     // SHEntry's URI was modified in this way by a push/replaceState call
    9741                 :     // set URIWasModified to true for the current SHEntry (bug 669671).
    9742               0 :     bool sameExceptHashes = true, oldURIWasModified = false;
    9743               0 :     newURI->EqualsExceptRef(mCurrentURI, &sameExceptHashes);
    9744               0 :     oldOSHE->GetURIWasModified(&oldURIWasModified);
    9745               0 :     newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
    9746                 : 
    9747                 :     // Step 5: If aReplace is false, indicating that we're doing a pushState
    9748                 :     // rather than a replaceState, notify bfcache that we've added a page to
    9749                 :     // the history so it can evict content viewers if appropriate.
    9750               0 :     if (!aReplace) {
    9751               0 :         nsCOMPtr<nsISHistory> rootSH;
    9752               0 :         GetRootSessionHistory(getter_AddRefs(rootSH));
    9753               0 :         NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
    9754                 : 
    9755                 :         nsCOMPtr<nsISHistoryInternal> internalSH =
    9756               0 :             do_QueryInterface(rootSH);
    9757               0 :         NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
    9758                 : 
    9759               0 :         PRInt32 curIndex = -1;
    9760               0 :         rv = rootSH->GetIndex(&curIndex);
    9761               0 :         if (NS_SUCCEEDED(rv) && curIndex > -1) {
    9762               0 :             internalSH->EvictOutOfRangeContentViewers(curIndex);
    9763                 :         }
    9764                 :     }
    9765                 : 
    9766                 :     // Step 6: If the document's URI changed, update document's URI and update
    9767                 :     // global history.
    9768                 :     //
    9769                 :     // We need to call FireOnLocationChange so that the browser's address bar
    9770                 :     // gets updated and the back button is enabled, but we only need to
    9771                 :     // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
    9772                 :     // since SetCurrentURI will call FireOnLocationChange for us.
    9773                 :     //
    9774                 :     // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
    9775                 :     // nsnull for aRequest param to FireOnLocationChange(...). Such an update
    9776                 :     // notification is allowed only when we know docshell is not loading a new
    9777                 :     // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
    9778                 :     // FireOnLocationChange(...) breaks security UI.
    9779               0 :     if (!equalURIs) {
    9780               0 :         SetCurrentURI(newURI, nsnull, true, LOCATION_CHANGE_SAME_DOCUMENT);
    9781               0 :         document->SetDocumentURI(newURI);
    9782                 : 
    9783               0 :         AddURIVisit(newURI, oldURI, oldURI, 0);
    9784                 : 
    9785                 :         // AddURIVisit doesn't set the title for the new URI in global history,
    9786                 :         // so do that here.
    9787               0 :         if (mUseGlobalHistory) {
    9788               0 :             nsCOMPtr<IHistory> history = services::GetHistoryService();
    9789               0 :             if (history) {
    9790               0 :                 history->SetURITitle(newURI, mTitle);
    9791                 :             }
    9792               0 :             else if (mGlobalHistory) {
    9793               0 :                 mGlobalHistory->SetPageTitle(newURI, mTitle);
    9794                 :             }
    9795                 :         }
    9796                 : 
    9797                 :         // Inform the favicon service that our old favicon applies to this new
    9798                 :         // URI.
    9799               0 :         CopyFavicon(oldURI, newURI);
    9800                 :     }
    9801                 :     else {
    9802               0 :         FireDummyOnLocationChange();
    9803                 :     }
    9804               0 :     document->SetStateObject(scContainer);
    9805                 : 
    9806               0 :     return NS_OK;
    9807                 : }
    9808                 : 
    9809                 : bool
    9810               0 : nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
    9811                 : {
    9812                 :     // I believe none of the about: urls should go in the history. But then
    9813                 :     // that could just be me... If the intent is only deny about:blank then we
    9814                 :     // should just do a spec compare, rather than two gets of the scheme and
    9815                 :     // then the path.  -Gagan
    9816                 :     nsresult rv;
    9817               0 :     nsCAutoString buf;
    9818                 : 
    9819               0 :     rv = aURI->GetScheme(buf);
    9820               0 :     if (NS_FAILED(rv))
    9821               0 :         return false;
    9822                 : 
    9823               0 :     if (buf.Equals("about")) {
    9824               0 :         rv = aURI->GetPath(buf);
    9825               0 :         if (NS_FAILED(rv))
    9826               0 :             return false;
    9827                 : 
    9828               0 :         if (buf.Equals("blank")) {
    9829               0 :             return false;
    9830                 :         }
    9831                 :     }
    9832               0 :     return true;
    9833                 : }
    9834                 : 
    9835                 : nsresult
    9836               0 : nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
    9837                 :                                 nsISupports* aOwner, bool aCloneChildren,
    9838                 :                                 nsISHEntry ** aNewEntry)
    9839                 : {
    9840               0 :     NS_PRECONDITION(aURI, "uri is null");
    9841               0 :     NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
    9842                 : 
    9843                 : #if defined(PR_LOGGING) && defined(DEBUG)
    9844               0 :     if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
    9845               0 :         nsCAutoString spec;
    9846               0 :         aURI->GetSpec(spec);
    9847                 : 
    9848               0 :         nsCAutoString chanName;
    9849               0 :         if (aChannel)
    9850               0 :             aChannel->GetName(chanName);
    9851                 :         else
    9852               0 :             chanName.AssignLiteral("<no channel>");
    9853                 : 
    9854               0 :         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
    9855                 :                ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(),
    9856                 :                 chanName.get()));
    9857                 :     }
    9858                 : #endif
    9859                 : 
    9860               0 :     nsresult rv = NS_OK;
    9861               0 :     nsCOMPtr<nsISHEntry> entry;
    9862                 :     bool shouldPersist;
    9863                 : 
    9864               0 :     shouldPersist = ShouldAddToSessionHistory(aURI);
    9865                 : 
    9866                 :     // Get a handle to the root docshell 
    9867               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
    9868               0 :     GetSameTypeRootTreeItem(getter_AddRefs(root));     
    9869                 :     /*
    9870                 :      * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
    9871                 :      * the existing SH entry in the page and replace the url and
    9872                 :      * other vitalities.
    9873                 :      */
    9874               0 :     if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
    9875               0 :         root != static_cast<nsIDocShellTreeItem *>(this)) {
    9876                 :         // This is a subframe 
    9877               0 :         entry = mOSHE;
    9878               0 :         nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
    9879               0 :         if (shContainer) {
    9880               0 :             PRInt32 childCount = 0;
    9881               0 :             shContainer->GetChildCount(&childCount);
    9882                 :             // Remove all children of this entry 
    9883               0 :             for (PRInt32 i = childCount - 1; i >= 0; i--) {
    9884               0 :                 nsCOMPtr<nsISHEntry> child;
    9885               0 :                 shContainer->GetChildAt(i, getter_AddRefs(child));
    9886               0 :                 shContainer->RemoveChild(child);
    9887                 :             }  // for
    9888                 :         }  // shContainer
    9889                 :     }
    9890                 : 
    9891                 :     // Create a new entry if necessary.
    9892               0 :     if (!entry) {
    9893               0 :         entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
    9894                 : 
    9895               0 :         if (!entry) {
    9896               0 :             return NS_ERROR_OUT_OF_MEMORY;
    9897                 :         }
    9898                 :     }
    9899                 : 
    9900                 :     // Get the post data & referrer
    9901               0 :     nsCOMPtr<nsIInputStream> inputStream;
    9902               0 :     nsCOMPtr<nsIURI> referrerURI;
    9903               0 :     nsCOMPtr<nsISupports> cacheKey;
    9904               0 :     nsCOMPtr<nsISupports> owner = aOwner;
    9905               0 :     bool expired = false;
    9906               0 :     bool discardLayoutState = false;
    9907               0 :     nsCOMPtr<nsICachingChannel> cacheChannel;
    9908               0 :     if (aChannel) {
    9909               0 :         cacheChannel = do_QueryInterface(aChannel);
    9910                 : 
    9911                 :         /* If there is a caching channel, get the Cache Key and store it
    9912                 :          * in SH.
    9913                 :          */
    9914               0 :         if (cacheChannel) {
    9915               0 :             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
    9916                 :         }
    9917               0 :         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
    9918                 :         
    9919                 :         // Check if the httpChannel is hiding under a multipartChannel
    9920               0 :         if (!httpChannel) {
    9921               0 :             GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
    9922                 :         }
    9923               0 :         if (httpChannel) {
    9924               0 :             nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
    9925               0 :             if (uploadChannel) {
    9926               0 :                 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
    9927                 :             }
    9928               0 :             httpChannel->GetReferrer(getter_AddRefs(referrerURI));
    9929                 : 
    9930               0 :             discardLayoutState = ShouldDiscardLayoutState(httpChannel);
    9931                 :         }
    9932               0 :         aChannel->GetOwner(getter_AddRefs(owner));
    9933                 :     }
    9934                 : 
    9935                 :     //Title is set in nsDocShell::SetTitle()
    9936               0 :     entry->Create(aURI,              // uri
    9937               0 :                   EmptyString(),     // Title
    9938                 :                   inputStream,       // Post data stream
    9939                 :                   nsnull,            // LayoutHistory state
    9940                 :                   cacheKey,          // CacheKey
    9941                 :                   mContentTypeHint,  // Content-type
    9942                 :                   owner,             // Channel or provided owner
    9943                 :                   mHistoryID,
    9944               0 :                   mDynamicallyCreated);
    9945               0 :     entry->SetReferrerURI(referrerURI);
    9946                 :     /* If cache got a 'no-store', ask SH not to store
    9947                 :      * HistoryLayoutState. By default, SH will set this
    9948                 :      * flag to true and save HistoryLayoutState.
    9949                 :      */    
    9950               0 :     if (discardLayoutState) {
    9951               0 :         entry->SetSaveLayoutStateFlag(false);
    9952                 :     }
    9953               0 :     if (cacheChannel) {
    9954                 :         // Check if the page has expired from cache
    9955               0 :         PRUint32 expTime = 0;
    9956               0 :         cacheChannel->GetCacheTokenExpirationTime(&expTime);
    9957               0 :         PRUint32 now = PRTimeToSeconds(PR_Now());
    9958               0 :         if (expTime <=  now)
    9959               0 :             expired = true;
    9960                 :     }
    9961               0 :     if (expired)
    9962               0 :         entry->SetExpirationStatus(true);
    9963                 : 
    9964                 : 
    9965               0 :     if (root == static_cast<nsIDocShellTreeItem *>(this) && mSessionHistory) {
    9966                 :         // If we need to clone our children onto the new session
    9967                 :         // history entry, do so now.
    9968               0 :         if (aCloneChildren && mOSHE) {
    9969                 :             PRUint32 cloneID;
    9970               0 :             mOSHE->GetID(&cloneID);
    9971               0 :             nsCOMPtr<nsISHEntry> newEntry;
    9972               0 :             CloneAndReplace(mOSHE, this, cloneID, entry, true, getter_AddRefs(newEntry));
    9973               0 :             NS_ASSERTION(entry == newEntry, "The new session history should be in the new entry");
    9974                 :         }
    9975                 : 
    9976                 :         // This is the root docshell
    9977               0 :         if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {            
    9978                 :             // Replace current entry in session history.
    9979               0 :             PRInt32  index = 0;   
    9980               0 :             mSessionHistory->GetIndex(&index);
    9981               0 :             nsCOMPtr<nsISHistoryInternal>   shPrivate(do_QueryInterface(mSessionHistory));
    9982                 :             // Replace the current entry with the new entry
    9983               0 :             if (shPrivate)
    9984               0 :                 rv = shPrivate->ReplaceEntry(index, entry);          
    9985                 :         }
    9986                 :         else {
    9987                 :             // Add to session history
    9988                 :             nsCOMPtr<nsISHistoryInternal>
    9989               0 :                 shPrivate(do_QueryInterface(mSessionHistory));
    9990               0 :             NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
    9991               0 :             mSessionHistory->GetIndex(&mPreviousTransIndex);
    9992               0 :             rv = shPrivate->AddEntry(entry, shouldPersist);
    9993               0 :             mSessionHistory->GetIndex(&mLoadedTransIndex);
    9994                 : #ifdef DEBUG_PAGE_CACHE
    9995                 :             printf("Previous index: %d, Loaded index: %d\n\n",
    9996                 :                    mPreviousTransIndex, mLoadedTransIndex);
    9997                 : #endif
    9998                 :         }
    9999                 :     }
   10000                 :     else {  
   10001                 :         // This is a subframe.
   10002               0 :         if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
   10003                 :                                            LOAD_FLAGS_REPLACE_HISTORY))
   10004               0 :             rv = DoAddChildSHEntry(entry, mChildOffset, aCloneChildren);
   10005                 :     }
   10006                 : 
   10007                 :     // Return the new SH entry...
   10008               0 :     if (aNewEntry) {
   10009               0 :         *aNewEntry = nsnull;
   10010               0 :         if (NS_SUCCEEDED(rv)) {
   10011               0 :             *aNewEntry = entry;
   10012               0 :             NS_ADDREF(*aNewEntry);
   10013                 :         }
   10014                 :     }
   10015                 : 
   10016               0 :     return rv;
   10017                 : }
   10018                 : 
   10019                 : 
   10020                 : NS_IMETHODIMP
   10021               0 : nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
   10022                 : {
   10023               0 :     if (!IsNavigationAllowed()) {
   10024               0 :         return NS_OK;
   10025                 :     }
   10026                 :     
   10027               0 :     nsCOMPtr<nsIURI> uri;
   10028               0 :     nsCOMPtr<nsIInputStream> postData;
   10029               0 :     nsCOMPtr<nsIURI> referrerURI;
   10030               0 :     nsCAutoString contentType;
   10031               0 :     nsCOMPtr<nsISupports> owner;
   10032                 : 
   10033               0 :     NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
   10034                 : 
   10035               0 :     NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
   10036               0 :     NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
   10037                 :                       NS_ERROR_FAILURE);
   10038               0 :     NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
   10039                 :                       NS_ERROR_FAILURE);
   10040               0 :     NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
   10041               0 :     NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)),
   10042                 :                       NS_ERROR_FAILURE);
   10043                 : 
   10044                 :     // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
   10045                 :     // that's the only thing holding a ref to aEntry that will cause aEntry to
   10046                 :     // die while we're loading it.  So hold a strong ref to aEntry here, just
   10047                 :     // in case.
   10048               0 :     nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
   10049                 :     bool isJS;
   10050               0 :     nsresult rv = uri->SchemeIs("javascript", &isJS);
   10051               0 :     if (NS_FAILED(rv) || isJS) {
   10052                 :         // We're loading a URL that will execute script from inside asyncOpen.
   10053                 :         // Replace the current document with about:blank now to prevent
   10054                 :         // anything from the current document from leaking into any JavaScript
   10055                 :         // code in the URL.
   10056               0 :         nsCOMPtr<nsIPrincipal> prin = do_QueryInterface(owner);
   10057                 :         // Don't cache the presentation if we're going to just reload the
   10058                 :         // current entry. Caching would lead to trying to save the different
   10059                 :         // content viewers in the same nsISHEntry object.
   10060               0 :         rv = CreateAboutBlankContentViewer(prin, nsnull, aEntry != mOSHE);
   10061                 : 
   10062               0 :         if (NS_FAILED(rv)) {
   10063                 :             // The creation of the intermittent about:blank content
   10064                 :             // viewer failed for some reason (potentially because the
   10065                 :             // user prevented it). Interrupt the history load.
   10066               0 :             return NS_OK;
   10067                 :         }
   10068                 : 
   10069               0 :         if (!owner) {
   10070                 :             // Ensure that we have an owner.  Otherwise javascript: URIs will
   10071                 :             // pick it up from the about:blank page we just loaded, and we
   10072                 :             // don't really want even that in this case.
   10073               0 :             owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
   10074               0 :             NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY);
   10075                 :         }
   10076                 :     }
   10077                 : 
   10078                 :     /* If there is a valid postdata *and* the user pressed
   10079                 :      * reload or shift-reload, take user's permission before we  
   10080                 :      * repost the data to the server.
   10081                 :      */
   10082               0 :     if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
   10083                 :       bool repost;
   10084               0 :       rv = ConfirmRepost(&repost);
   10085               0 :       if (NS_FAILED(rv)) return rv;
   10086                 : 
   10087                 :       // If the user pressed cancel in the dialog, return.  We're done here.
   10088               0 :       if (!repost)
   10089               0 :         return NS_BINDING_ABORTED;
   10090                 :     }
   10091                 : 
   10092                 :     rv = InternalLoad(uri,
   10093                 :                       referrerURI,
   10094                 :                       owner,
   10095                 :                       INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document (security-critical!)
   10096                 :                       nsnull,            // No window target
   10097                 :                       contentType.get(), // Type hint
   10098                 :                       postData,          // Post data stream
   10099                 :                       nsnull,            // No headers stream
   10100                 :                       aLoadType,         // Load type
   10101                 :                       aEntry,            // SHEntry
   10102                 :                       true,
   10103                 :                       nsnull,            // No nsIDocShell
   10104               0 :                       nsnull);           // No nsIRequest
   10105               0 :     return rv;
   10106                 : }
   10107                 : 
   10108               0 : NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(bool* aShould)
   10109                 : {
   10110               0 :     *aShould = false;
   10111               0 :     if (mOSHE) {
   10112                 :         // Don't capture historystate and save it in history
   10113                 :         // if the page asked not to do so.
   10114               0 :         mOSHE->GetSaveLayoutStateFlag(aShould);
   10115                 :     }
   10116                 : 
   10117               0 :     return NS_OK;
   10118                 : }
   10119                 : 
   10120               0 : NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState()
   10121                 : {
   10122               0 :     nsresult  rv = NS_OK;
   10123                 :     
   10124               0 :     if (mOSHE) {
   10125               0 :         nsCOMPtr<nsIPresShell> shell;
   10126               0 :         rv = GetPresShell(getter_AddRefs(shell));
   10127               0 :         if (NS_SUCCEEDED(rv) && shell) {
   10128               0 :             nsCOMPtr<nsILayoutHistoryState> layoutState;
   10129               0 :             rv = shell->CaptureHistoryState(getter_AddRefs(layoutState),
   10130               0 :                                             true);
   10131                 :         }
   10132                 :     }
   10133                 : 
   10134               0 :     return rv;
   10135                 : }
   10136                 : 
   10137                 : /* static */ nsresult
   10138               0 : nsDocShell::WalkHistoryEntries(nsISHEntry *aRootEntry,
   10139                 :                                nsDocShell *aRootShell,
   10140                 :                                WalkHistoryEntriesFunc aCallback,
   10141                 :                                void *aData)
   10142                 : {
   10143               0 :     NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
   10144                 : 
   10145               0 :     nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
   10146               0 :     if (!container)
   10147               0 :         return NS_ERROR_FAILURE;
   10148                 : 
   10149                 :     PRInt32 childCount;
   10150               0 :     container->GetChildCount(&childCount);
   10151               0 :     for (PRInt32 i = 0; i < childCount; i++) {
   10152               0 :         nsCOMPtr<nsISHEntry> childEntry;
   10153               0 :         container->GetChildAt(i, getter_AddRefs(childEntry));
   10154               0 :         if (!childEntry) {
   10155                 :             // childEntry can be null for valid reasons, for example if the
   10156                 :             // docshell at index i never loaded anything useful.
   10157                 :             // Remember to clone also nulls in the child array (bug 464064).
   10158               0 :             aCallback(nsnull, nsnull, i, aData);
   10159               0 :             continue;
   10160                 :         }
   10161                 : 
   10162               0 :         nsDocShell *childShell = nsnull;
   10163               0 :         if (aRootShell) {
   10164                 :             // Walk the children of aRootShell and see if one of them
   10165                 :             // has srcChild as a SHEntry.
   10166                 : 
   10167               0 :             PRInt32 childCount = aRootShell->mChildList.Count();
   10168               0 :             for (PRInt32 j = 0; j < childCount; ++j) {
   10169                 :                 nsDocShell *child =
   10170               0 :                     static_cast<nsDocShell*>(aRootShell->ChildAt(j));
   10171                 : 
   10172               0 :                 if (child->HasHistoryEntry(childEntry)) {
   10173               0 :                     childShell = child;
   10174               0 :                     break;
   10175                 :                 }
   10176                 :             }
   10177                 :         }
   10178               0 :         nsresult rv = aCallback(childEntry, childShell, i, aData);
   10179               0 :         NS_ENSURE_SUCCESS(rv, rv);
   10180                 :     }
   10181                 : 
   10182               0 :     return NS_OK;
   10183                 : }
   10184                 : 
   10185                 : // callback data for WalkHistoryEntries
   10186                 : struct NS_STACK_CLASS CloneAndReplaceData
   10187               0 : {
   10188               0 :     CloneAndReplaceData(PRUint32 aCloneID, nsISHEntry *aReplaceEntry,
   10189                 :                         bool aCloneChildren, nsISHEntry *aDestTreeParent)
   10190                 :         : cloneID(aCloneID),
   10191                 :           cloneChildren(aCloneChildren),
   10192                 :           replaceEntry(aReplaceEntry),
   10193               0 :           destTreeParent(aDestTreeParent) { }
   10194                 : 
   10195                 :     PRUint32              cloneID;
   10196                 :     bool                  cloneChildren;
   10197                 :     nsISHEntry           *replaceEntry;
   10198                 :     nsISHEntry           *destTreeParent;
   10199                 :     nsCOMPtr<nsISHEntry>  resultEntry;
   10200                 : };
   10201                 : 
   10202                 : /* static */ nsresult
   10203               0 : nsDocShell::CloneAndReplaceChild(nsISHEntry *aEntry, nsDocShell *aShell,
   10204                 :                                  PRInt32 aEntryIndex, void *aData)
   10205                 : {
   10206               0 :     nsCOMPtr<nsISHEntry> dest;
   10207                 : 
   10208               0 :     CloneAndReplaceData *data = static_cast<CloneAndReplaceData*>(aData);
   10209               0 :     PRUint32 cloneID = data->cloneID;
   10210               0 :     nsISHEntry *replaceEntry = data->replaceEntry;
   10211                 : 
   10212                 :     nsCOMPtr<nsISHContainer> container =
   10213               0 :       do_QueryInterface(data->destTreeParent);
   10214               0 :     if (!aEntry) {
   10215               0 :         if (container) {
   10216               0 :             container->AddChild(nsnull, aEntryIndex);
   10217                 :         }
   10218               0 :         return NS_OK;
   10219                 :     }
   10220                 :     
   10221                 :     PRUint32 srcID;
   10222               0 :     aEntry->GetID(&srcID);
   10223                 : 
   10224               0 :     nsresult rv = NS_OK;
   10225               0 :     if (srcID == cloneID) {
   10226                 :         // Replace the entry
   10227               0 :         dest = replaceEntry;
   10228                 :     } else {
   10229                 :         // Clone the SHEntry...
   10230               0 :         rv = aEntry->Clone(getter_AddRefs(dest));
   10231               0 :         NS_ENSURE_SUCCESS(rv, rv);
   10232                 :     }
   10233               0 :     dest->SetIsSubFrame(true);
   10234                 : 
   10235               0 :     if (srcID != cloneID || data->cloneChildren) {
   10236                 :         // Walk the children
   10237                 :         CloneAndReplaceData childData(cloneID, replaceEntry,
   10238               0 :                                       data->cloneChildren, dest);
   10239                 :         rv = WalkHistoryEntries(aEntry, aShell,
   10240               0 :                                 CloneAndReplaceChild, &childData);
   10241               0 :         NS_ENSURE_SUCCESS(rv, rv);
   10242                 :     }
   10243                 : 
   10244               0 :     if (srcID != cloneID && aShell) {
   10245               0 :         aShell->SwapHistoryEntries(aEntry, dest);
   10246                 :     }
   10247                 : 
   10248               0 :     if (container)
   10249               0 :         container->AddChild(dest, aEntryIndex);
   10250                 : 
   10251               0 :     data->resultEntry = dest;
   10252               0 :     return rv;
   10253                 : }
   10254                 : 
   10255                 : /* static */ nsresult
   10256               0 : nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
   10257                 :                                    nsDocShell *aSrcShell,
   10258                 :                                    PRUint32 aCloneID,
   10259                 :                                    nsISHEntry *aReplaceEntry,
   10260                 :                                    bool aCloneChildren,
   10261                 :                                    nsISHEntry **aResultEntry)
   10262                 : {
   10263               0 :     NS_ENSURE_ARG_POINTER(aResultEntry);
   10264               0 :     NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
   10265                 : 
   10266               0 :     CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nsnull);
   10267               0 :     nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
   10268                 : 
   10269               0 :     data.resultEntry.swap(*aResultEntry);
   10270               0 :     return rv;
   10271                 : }
   10272                 : 
   10273                 : void
   10274               0 : nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
   10275                 : {
   10276               0 :     if (aOldEntry == mOSHE)
   10277               0 :         mOSHE = aNewEntry;
   10278                 : 
   10279               0 :     if (aOldEntry == mLSHE)
   10280               0 :         mLSHE = aNewEntry;
   10281               0 : }
   10282                 : 
   10283                 : 
   10284                 : struct SwapEntriesData
   10285                 : {
   10286                 :     nsDocShell *ignoreShell;     // constant; the shell to ignore
   10287                 :     nsISHEntry *destTreeRoot;    // constant; the root of the dest tree
   10288                 :     nsISHEntry *destTreeParent;  // constant; the node under destTreeRoot
   10289                 :                                  // whose children will correspond to aEntry
   10290                 : };
   10291                 : 
   10292                 : 
   10293                 : nsresult
   10294               0 : nsDocShell::SetChildHistoryEntry(nsISHEntry *aEntry, nsDocShell *aShell,
   10295                 :                                  PRInt32 aEntryIndex, void *aData)
   10296                 : {
   10297               0 :     SwapEntriesData *data = static_cast<SwapEntriesData*>(aData);
   10298               0 :     nsDocShell *ignoreShell = data->ignoreShell;
   10299                 : 
   10300               0 :     if (!aShell || aShell == ignoreShell)
   10301               0 :         return NS_OK;
   10302                 : 
   10303               0 :     nsISHEntry *destTreeRoot = data->destTreeRoot;
   10304                 : 
   10305               0 :     nsCOMPtr<nsISHEntry> destEntry;
   10306                 :     nsCOMPtr<nsISHContainer> container =
   10307               0 :         do_QueryInterface(data->destTreeParent);
   10308                 : 
   10309               0 :     if (container) {
   10310                 :         // aEntry is a clone of some child of destTreeParent, but since the
   10311                 :         // trees aren't necessarily in sync, we'll have to locate it.
   10312                 :         // Note that we could set aShell's entry to null if we don't find a
   10313                 :         // corresponding entry under destTreeParent.
   10314                 : 
   10315                 :         PRUint32 targetID, id;
   10316               0 :         aEntry->GetID(&targetID);
   10317                 : 
   10318                 :         // First look at the given index, since this is the common case.
   10319               0 :         nsCOMPtr<nsISHEntry> entry;
   10320               0 :         container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
   10321               0 :         if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
   10322               0 :             destEntry.swap(entry);
   10323                 :         } else {
   10324                 :             PRInt32 childCount;
   10325               0 :             container->GetChildCount(&childCount);
   10326               0 :             for (PRInt32 i = 0; i < childCount; ++i) {
   10327               0 :                 container->GetChildAt(i, getter_AddRefs(entry));
   10328               0 :                 if (!entry)
   10329               0 :                     continue;
   10330                 : 
   10331               0 :                 entry->GetID(&id);
   10332               0 :                 if (id == targetID) {
   10333               0 :                     destEntry.swap(entry);
   10334               0 :                     break;
   10335                 :                 }
   10336                 :             }
   10337                 :         }
   10338                 :     } else {
   10339               0 :         destEntry = destTreeRoot;
   10340                 :     }
   10341                 : 
   10342               0 :     aShell->SwapHistoryEntries(aEntry, destEntry);
   10343                 : 
   10344                 :     // Now handle the children of aEntry.
   10345               0 :     SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
   10346                 :     return WalkHistoryEntries(aEntry, aShell,
   10347               0 :                               SetChildHistoryEntry, &childData);
   10348                 : }
   10349                 : 
   10350                 : 
   10351                 : static nsISHEntry*
   10352               0 : GetRootSHEntry(nsISHEntry *aEntry)
   10353                 : {
   10354               0 :     nsCOMPtr<nsISHEntry> rootEntry = aEntry;
   10355               0 :     nsISHEntry *result = nsnull;
   10356               0 :     while (rootEntry) {
   10357               0 :         result = rootEntry;
   10358               0 :         result->GetParent(getter_AddRefs(rootEntry));
   10359                 :     }
   10360                 : 
   10361               0 :     return result;
   10362                 : }
   10363                 : 
   10364                 : 
   10365                 : void
   10366               0 : nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry> *aPtr, nsISHEntry *aEntry)
   10367                 : {
   10368                 :     // We need to sync up the docshell and session history trees for
   10369                 :     // subframe navigation.  If the load was in a subframe, we forward up to
   10370                 :     // the root docshell, which will then recursively sync up all docshells
   10371                 :     // to their corresponding entries in the new session history tree.
   10372                 :     // If we don't do this, then we can cache a content viewer on the wrong
   10373                 :     // cloned entry, and subsequently restore it at the wrong time.
   10374                 : 
   10375               0 :     nsISHEntry *newRootEntry = GetRootSHEntry(aEntry);
   10376               0 :     if (newRootEntry) {
   10377                 :         // newRootEntry is now the new root entry.
   10378                 :         // Find the old root entry as well.
   10379                 : 
   10380                 :         // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
   10381                 :         // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
   10382               0 :         nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
   10383               0 :         if (oldRootEntry) {
   10384               0 :             nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
   10385               0 :             GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
   10386               0 :             nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
   10387               0 :             if (rootShell) { // if we're the root just set it, nothing to swap
   10388               0 :                 SwapEntriesData data = { this, newRootEntry };
   10389                 :                 nsIDocShell *rootIDocShell =
   10390               0 :                     static_cast<nsIDocShell*>(rootShell);
   10391                 :                 nsDocShell *rootDocShell = static_cast<nsDocShell*>
   10392               0 :                                                       (rootIDocShell);
   10393                 : 
   10394                 : #ifdef NS_DEBUG
   10395                 :                 nsresult rv =
   10396                 : #endif
   10397                 :                 SetChildHistoryEntry(oldRootEntry, rootDocShell,
   10398               0 :                                                    0, &data);
   10399               0 :                 NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
   10400                 :             }
   10401                 :         }
   10402                 :     }
   10403                 : 
   10404               0 :     *aPtr = aEntry;
   10405               0 : }
   10406                 : 
   10407                 : 
   10408                 : nsresult
   10409               0 : nsDocShell::GetRootSessionHistory(nsISHistory ** aReturn)
   10410                 : {
   10411                 :     nsresult rv;
   10412                 : 
   10413               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
   10414                 :     //Get the root docshell
   10415               0 :     rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
   10416                 :     // QI to nsIWebNavigation
   10417               0 :     nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
   10418               0 :     if (rootAsWebnav) {
   10419                 :         // Get the handle to SH from the root docshell
   10420               0 :         rv = rootAsWebnav->GetSessionHistory(aReturn);
   10421                 :     }
   10422               0 :     return rv;
   10423                 : }
   10424                 : 
   10425                 : nsresult
   10426               0 : nsDocShell::GetHttpChannel(nsIChannel * aChannel, nsIHttpChannel ** aReturn)
   10427                 : {
   10428               0 :     NS_ENSURE_ARG_POINTER(aReturn);
   10429               0 :     if (!aChannel)
   10430               0 :         return NS_ERROR_FAILURE;
   10431                 : 
   10432               0 :     nsCOMPtr<nsIMultiPartChannel>  multiPartChannel(do_QueryInterface(aChannel));
   10433               0 :     if (multiPartChannel) {
   10434               0 :         nsCOMPtr<nsIChannel> baseChannel;
   10435               0 :         multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
   10436               0 :         nsCOMPtr<nsIHttpChannel>  httpChannel(do_QueryInterface(baseChannel));
   10437               0 :         *aReturn = httpChannel;
   10438               0 :         NS_IF_ADDREF(*aReturn);
   10439                 :     }
   10440               0 :     return NS_OK;
   10441                 : }
   10442                 : 
   10443                 : bool 
   10444               0 : nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel)
   10445                 : {    
   10446                 :     // By default layout State will be saved. 
   10447               0 :     if (!aChannel)
   10448               0 :         return false;
   10449                 : 
   10450                 :     // figure out if SH should be saving layout state 
   10451               0 :     nsCOMPtr<nsISupports> securityInfo;
   10452               0 :     bool noStore = false, noCache = false;
   10453               0 :     aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
   10454               0 :     aChannel->IsNoStoreResponse(&noStore);
   10455               0 :     aChannel->IsNoCacheResponse(&noCache);
   10456                 : 
   10457               0 :     return (noStore || (noCache && securityInfo));
   10458                 : }
   10459                 : 
   10460                 : //*****************************************************************************
   10461                 : // nsDocShell: nsIEditorDocShell
   10462                 : //*****************************************************************************   
   10463                 : 
   10464               0 : NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
   10465                 : {
   10466               0 :   NS_ENSURE_ARG_POINTER(aEditor);
   10467                 : 
   10468               0 :   if (!mEditorData) {
   10469               0 :     *aEditor = nsnull;
   10470               0 :     return NS_OK;
   10471                 :   }
   10472                 : 
   10473               0 :   return mEditorData->GetEditor(aEditor);
   10474                 : }
   10475                 : 
   10476               0 : NS_IMETHODIMP nsDocShell::SetEditor(nsIEditor * aEditor)
   10477                 : {
   10478               0 :   nsresult rv = EnsureEditorData();
   10479               0 :   if (NS_FAILED(rv)) return rv;
   10480                 : 
   10481               0 :   return mEditorData->SetEditor(aEditor);
   10482                 : }
   10483                 : 
   10484                 : 
   10485               0 : NS_IMETHODIMP nsDocShell::GetEditable(bool *aEditable)
   10486                 : {
   10487               0 :   NS_ENSURE_ARG_POINTER(aEditable);
   10488               0 :   *aEditable = mEditorData && mEditorData->GetEditable();
   10489               0 :   return NS_OK;
   10490                 : }
   10491                 : 
   10492                 : 
   10493               0 : NS_IMETHODIMP nsDocShell::GetHasEditingSession(bool *aHasEditingSession)
   10494                 : {
   10495               0 :   NS_ENSURE_ARG_POINTER(aHasEditingSession);
   10496                 :   
   10497               0 :   if (mEditorData)
   10498                 :   {
   10499               0 :     nsCOMPtr<nsIEditingSession> editingSession;
   10500               0 :     mEditorData->GetEditingSession(getter_AddRefs(editingSession));
   10501               0 :     *aHasEditingSession = (editingSession.get() != nsnull);
   10502                 :   }
   10503                 :   else
   10504                 :   {
   10505               0 :     *aHasEditingSession = false;
   10506                 :   }
   10507                 : 
   10508               0 :   return NS_OK;
   10509                 : }
   10510                 : 
   10511               0 : NS_IMETHODIMP nsDocShell::MakeEditable(bool inWaitForUriLoad)
   10512                 : {
   10513               0 :   nsresult rv = EnsureEditorData();
   10514               0 :   if (NS_FAILED(rv)) return rv;
   10515                 : 
   10516               0 :   return mEditorData->MakeEditable(inWaitForUriLoad);
   10517                 : }
   10518                 : 
   10519                 : bool
   10520               0 : nsDocShell::ChannelIsPost(nsIChannel* aChannel)
   10521                 : {
   10522               0 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
   10523               0 :     if (!httpChannel) {
   10524               0 :         return false;
   10525                 :     }
   10526                 : 
   10527               0 :     nsCAutoString method;
   10528               0 :     httpChannel->GetRequestMethod(method);
   10529               0 :     return method.Equals("POST");
   10530                 : }
   10531                 : 
   10532                 : void
   10533               0 : nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
   10534                 :                              nsIURI** aURI,
   10535                 :                              PRUint32* aChannelRedirectFlags)
   10536                 : {
   10537               0 :     nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
   10538               0 :     if (!props) {
   10539                 :         return;
   10540                 :     }
   10541                 : 
   10542               0 :     nsresult rv = props->GetPropertyAsInterface(
   10543               0 :         NS_LITERAL_STRING("docshell.previousURI"),
   10544                 :         NS_GET_IID(nsIURI),
   10545                 :         reinterpret_cast<void**>(aURI)
   10546               0 :     );
   10547                 : 
   10548               0 :     if (NS_FAILED(rv)) {
   10549                 :         // There is no last visit for this channel, so this must be the first
   10550                 :         // link.  Link the visit to the referrer of this request, if any.
   10551                 :         // Treat referrer as null if there is an error getting it.
   10552               0 :         (void)NS_GetReferrerFromChannel(aChannel, aURI);
   10553                 :     }
   10554                 :     else {
   10555               0 :       rv = props->GetPropertyAsUint32(
   10556               0 :           NS_LITERAL_STRING("docshell.previousFlags"),
   10557                 :           aChannelRedirectFlags
   10558               0 :       );
   10559                 : 
   10560               0 :       NS_WARN_IF_FALSE(
   10561                 :           NS_SUCCEEDED(rv),
   10562                 :           "Could not fetch previous flags, URI will be treated like referrer"
   10563                 :       );
   10564                 :     }
   10565                 : }
   10566                 : 
   10567                 : void
   10568               0 : nsDocShell::SaveLastVisit(nsIChannel* aChannel,
   10569                 :                           nsIURI* aURI,
   10570                 :                           PRUint32 aChannelRedirectFlags)
   10571                 : {
   10572               0 :     nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
   10573               0 :     if (!props || !aURI) {
   10574                 :         return;
   10575                 :     }
   10576                 : 
   10577               0 :     props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
   10578               0 :                                   aURI);
   10579               0 :     props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
   10580               0 :                                aChannelRedirectFlags);
   10581                 : }
   10582                 : 
   10583                 : void
   10584               0 : nsDocShell::AddURIVisit(nsIURI* aURI,
   10585                 :                         nsIURI* aReferrerURI,
   10586                 :                         nsIURI* aPreviousURI,
   10587                 :                         PRUint32 aChannelRedirectFlags)
   10588                 : {
   10589               0 :     NS_ASSERTION(aURI, "Visited URI is null!");
   10590                 : 
   10591                 :     // Only content-type docshells save URI visits.  Also don't do
   10592                 :     // anything here if we're not supposed to use global history.
   10593               0 :     if (mItemType != typeContent || !mUseGlobalHistory) {
   10594               0 :         return;
   10595                 :     }
   10596                 : 
   10597               0 :     nsCOMPtr<IHistory> history = services::GetHistoryService();
   10598                 : 
   10599               0 :     if (history) {
   10600               0 :         PRUint32 visitURIFlags = 0;
   10601                 : 
   10602               0 :         if (!IsFrame()) {
   10603               0 :             visitURIFlags |= IHistory::TOP_LEVEL;
   10604                 :         }
   10605                 : 
   10606               0 :         if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
   10607               0 :             visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
   10608                 :         }
   10609               0 :         else if (aChannelRedirectFlags &
   10610                 :                  nsIChannelEventSink::REDIRECT_PERMANENT) {
   10611               0 :             visitURIFlags |= IHistory::REDIRECT_PERMANENT;
   10612                 :         }
   10613                 : 
   10614               0 :         (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
   10615                 :     }
   10616               0 :     else if (mGlobalHistory) {
   10617                 :         // Falls back to sync global history interface.
   10618               0 :         (void)mGlobalHistory->AddURI(aURI,
   10619                 :                                      !!aChannelRedirectFlags,
   10620               0 :                                      !IsFrame(),
   10621               0 :                                      aReferrerURI);
   10622                 :     }
   10623                 : }
   10624                 : 
   10625                 : //*****************************************************************************
   10626                 : // nsDocShell: Helper Routines
   10627                 : //*****************************************************************************
   10628                 : 
   10629                 : NS_IMETHODIMP
   10630               0 : nsDocShell::SetLoadType(PRUint32 aLoadType)
   10631                 : {
   10632               0 :     mLoadType = aLoadType;
   10633               0 :     return NS_OK;
   10634                 : }
   10635                 : 
   10636                 : NS_IMETHODIMP
   10637               0 : nsDocShell::GetLoadType(PRUint32 * aLoadType)
   10638                 : {
   10639               0 :     *aLoadType = mLoadType;
   10640               0 :     return NS_OK;
   10641                 : }
   10642                 : 
   10643                 : nsresult
   10644               0 : nsDocShell::ConfirmRepost(bool * aRepost)
   10645                 : {
   10646               0 :   nsCOMPtr<nsIPrompt> prompter;
   10647               0 :   CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
   10648               0 :   if (!prompter) {
   10649               0 :       return NS_ERROR_NOT_AVAILABLE;
   10650                 :   }
   10651                 : 
   10652                 :   nsCOMPtr<nsIStringBundleService> stringBundleService =
   10653               0 :     mozilla::services::GetStringBundleService();
   10654               0 :   if (!stringBundleService)
   10655               0 :     return NS_ERROR_FAILURE;
   10656                 : 
   10657               0 :   nsCOMPtr<nsIStringBundle> appBundle;
   10658               0 :   nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
   10659               0 :                                                   getter_AddRefs(appBundle));
   10660               0 :   NS_ENSURE_SUCCESS(rv, rv);
   10661                 : 
   10662               0 :   nsCOMPtr<nsIStringBundle> brandBundle;
   10663               0 :   rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle));
   10664               0 :   NS_ENSURE_SUCCESS(rv, rv);
   10665                 : 
   10666               0 :   NS_ASSERTION(prompter && brandBundle && appBundle,
   10667                 :                "Unable to set up repost prompter.");
   10668                 : 
   10669               0 :   nsXPIDLString brandName;
   10670               0 :   rv = brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
   10671               0 :                                       getter_Copies(brandName));
   10672                 : 
   10673               0 :   nsXPIDLString msgString, button0Title;
   10674               0 :   if (NS_FAILED(rv)) { // No brand, use the generic version.
   10675               0 :     rv = appBundle->GetStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
   10676               0 :                                       getter_Copies(msgString));
   10677                 :   }
   10678                 :   else {
   10679                 :     // Brand available - if the app has an override file with formatting, the app name will
   10680                 :     // be included. Without an override, the prompt will look like the generic version.
   10681               0 :     const PRUnichar *formatStrings[] = { brandName.get() };
   10682               0 :     rv = appBundle->FormatStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
   10683                 :                                          formatStrings, ArrayLength(formatStrings),
   10684               0 :                                          getter_Copies(msgString));
   10685                 :   }
   10686               0 :   if (NS_FAILED(rv)) return rv;
   10687                 : 
   10688               0 :   rv = appBundle->GetStringFromName(NS_LITERAL_STRING("resendButton.label").get(),
   10689               0 :                                     getter_Copies(button0Title));
   10690               0 :   if (NS_FAILED(rv)) return rv;
   10691                 : 
   10692                 :   PRInt32 buttonPressed;
   10693                 :   // The actual value here is irrelevant, but we can't pass an invalid
   10694                 :   // bool through XPConnect.
   10695               0 :   bool checkState = false;
   10696               0 :   rv = prompter->
   10697                 :          ConfirmEx(nsnull, msgString.get(),
   10698                 :                    (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
   10699                 :                    (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
   10700               0 :                    button0Title.get(), nsnull, nsnull, nsnull, &checkState, &buttonPressed);
   10701               0 :   if (NS_FAILED(rv)) return rv;
   10702                 : 
   10703               0 :   *aRepost = (buttonPressed == 0);
   10704               0 :   return NS_OK;
   10705                 : }
   10706                 : 
   10707                 : NS_IMETHODIMP
   10708               0 : nsDocShell::GetPromptAndStringBundle(nsIPrompt ** aPrompt,
   10709                 :                                      nsIStringBundle ** aStringBundle)
   10710                 : {
   10711               0 :     NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void **) aPrompt),
   10712                 :                       NS_ERROR_FAILURE);
   10713                 : 
   10714                 :     nsCOMPtr<nsIStringBundleService> stringBundleService =
   10715               0 :       mozilla::services::GetStringBundleService();
   10716               0 :     NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
   10717                 : 
   10718               0 :     NS_ENSURE_SUCCESS(stringBundleService->
   10719                 :                       CreateBundle(kAppstringsBundleURL,
   10720                 :                                    aStringBundle),
   10721                 :                       NS_ERROR_FAILURE);
   10722                 : 
   10723               0 :     return NS_OK;
   10724                 : }
   10725                 : 
   10726                 : NS_IMETHODIMP
   10727               0 : nsDocShell::GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent,
   10728                 :                            PRInt32 * aOffset)
   10729                 : {
   10730               0 :     NS_ENSURE_ARG_POINTER(aChild || aParent);
   10731                 : 
   10732               0 :     nsCOMPtr<nsIDOMNodeList> childNodes;
   10733               0 :     NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
   10734                 :                       NS_ERROR_FAILURE);
   10735               0 :     NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
   10736                 : 
   10737               0 :     PRInt32 i = 0;
   10738                 : 
   10739               0 :     for (; true; i++) {
   10740               0 :         nsCOMPtr<nsIDOMNode> childNode;
   10741               0 :         NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
   10742                 :                           NS_ERROR_FAILURE);
   10743               0 :         NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
   10744                 : 
   10745               0 :         if (childNode.get() == aChild) {
   10746               0 :             *aOffset = i;
   10747               0 :             return NS_OK;
   10748                 :         }
   10749                 :     }
   10750                 : 
   10751                 :     return NS_ERROR_FAILURE;
   10752                 : }
   10753                 : 
   10754                 : nsIScrollableFrame *
   10755               0 : nsDocShell::GetRootScrollFrame()
   10756                 : {
   10757               0 :     nsCOMPtr<nsIPresShell> shell;
   10758               0 :     NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(shell)), nsnull);
   10759               0 :     NS_ENSURE_TRUE(shell, nsnull);
   10760                 : 
   10761               0 :     return shell->GetRootScrollFrameAsScrollableExternal();
   10762                 : }
   10763                 : 
   10764                 : NS_IMETHODIMP
   10765               0 : nsDocShell::EnsureScriptEnvironment()
   10766                 : {
   10767               0 :     if (mScriptGlobal)
   10768               0 :         return NS_OK;
   10769                 : 
   10770               0 :     if (mIsBeingDestroyed) {
   10771               0 :         return NS_ERROR_NOT_AVAILABLE;
   10772                 :     }
   10773                 : 
   10774                 :     NS_TIME_FUNCTION;
   10775                 : 
   10776                 : #ifdef DEBUG
   10777               0 :     NS_ASSERTION(!mInEnsureScriptEnv,
   10778                 :                  "Infinite loop! Calling EnsureScriptEnvironment() from "
   10779                 :                  "within EnsureScriptEnvironment()!");
   10780                 : 
   10781                 :     // Yeah, this isn't re-entrant safe, but that's ok since if we
   10782                 :     // re-enter this method, we'll infinitely loop...
   10783               0 :     AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
   10784               0 :     mInEnsureScriptEnv = true;
   10785                 : #endif
   10786                 : 
   10787                 :     nsCOMPtr<nsIDOMScriptObjectFactory> factory =
   10788               0 :         do_GetService(kDOMScriptObjectFactoryCID);
   10789               0 :     NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
   10790                 : 
   10791               0 :     nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
   10792               0 :     NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
   10793                 : 
   10794                 :     PRUint32 chromeFlags;
   10795               0 :     browserChrome->GetChromeFlags(&chromeFlags);
   10796                 : 
   10797                 :     bool isModalContentWindow =
   10798                 :         (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) &&
   10799               0 :         !(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
   10800                 : 
   10801                 :     // If our window is modal and we're not opened as chrome, make
   10802                 :     // this window a modal content window.
   10803               0 :     factory->NewScriptGlobalObject(mItemType == typeChrome,
   10804                 :                                    isModalContentWindow,
   10805               0 :                                    getter_AddRefs(mScriptGlobal));
   10806               0 :     NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
   10807                 : 
   10808               0 :     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
   10809               0 :     win->SetDocShell(static_cast<nsIDocShell *>(this));
   10810                 : 
   10811                 :     // Ensure the script object is set to run javascript - other languages
   10812                 :     // setup on demand.
   10813                 :     // XXXmarkh - should this be setup to run the default language for this doc?
   10814                 :     nsresult rv;
   10815               0 :     rv = mScriptGlobal->EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT);
   10816               0 :     NS_ENSURE_SUCCESS(rv, rv);
   10817                 : 
   10818               0 :     return NS_OK;
   10819                 : }
   10820                 : 
   10821                 : 
   10822                 : NS_IMETHODIMP
   10823               0 : nsDocShell::EnsureEditorData()
   10824                 : {
   10825               0 :     bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
   10826               0 :     if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
   10827                 :         // We shouldn't recreate the editor data if it already exists, or
   10828                 :         // we're shutting down, or we already have a detached editor data
   10829                 :         // stored in the session history. We should only have one editordata
   10830                 :         // per docshell.
   10831               0 :         mEditorData = new nsDocShellEditorData(this);
   10832                 :     }
   10833                 : 
   10834               0 :     return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   10835                 : }
   10836                 : 
   10837                 : nsresult
   10838               0 : nsDocShell::EnsureTransferableHookData()
   10839                 : {
   10840               0 :     if (!mTransferableHookData) {
   10841               0 :         mTransferableHookData = new nsTransferableHookData();
   10842               0 :         if (!mTransferableHookData) return NS_ERROR_OUT_OF_MEMORY;
   10843                 :     }
   10844                 : 
   10845               0 :     return NS_OK;
   10846                 : }
   10847                 : 
   10848                 : 
   10849               0 : NS_IMETHODIMP nsDocShell::EnsureFind()
   10850                 : {
   10851                 :     nsresult rv;
   10852               0 :     if (!mFind)
   10853                 :     {
   10854               0 :         mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
   10855               0 :         if (NS_FAILED(rv)) return rv;
   10856                 :     }
   10857                 :     
   10858                 :     // we promise that the nsIWebBrowserFind that we return has been set
   10859                 :     // up to point to the focused, or content window, so we have to
   10860                 :     // set that up each time.
   10861                 : 
   10862               0 :     nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
   10863               0 :     NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
   10864                 : 
   10865                 :     // default to our window
   10866               0 :     nsCOMPtr<nsIDOMWindow> windowToSearch(do_QueryInterface(mScriptGlobal));
   10867                 : 
   10868               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
   10869               0 :     GetRootTreeItem(getter_AddRefs(root));
   10870                 : 
   10871                 :     // if the active window is the same window that this docshell is in,
   10872                 :     // use the currently focused frame
   10873               0 :     nsCOMPtr<nsIDOMWindow> rootWindow = do_GetInterface(root);
   10874               0 :     nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   10875               0 :     if (fm) {
   10876               0 :       nsCOMPtr<nsIDOMWindow> activeWindow;
   10877               0 :       fm->GetActiveWindow(getter_AddRefs(activeWindow));
   10878               0 :       if (activeWindow == rootWindow)
   10879               0 :         fm->GetFocusedWindow(getter_AddRefs(windowToSearch));
   10880                 :     }
   10881                 : 
   10882               0 :     nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
   10883               0 :     if (!findInFrames) return NS_ERROR_NO_INTERFACE;
   10884                 :     
   10885               0 :     rv = findInFrames->SetRootSearchFrame(rootWindow);
   10886               0 :     if (NS_FAILED(rv)) return rv;
   10887               0 :     rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
   10888               0 :     if (NS_FAILED(rv)) return rv;
   10889                 :     
   10890               0 :     return NS_OK;
   10891                 : }
   10892                 : 
   10893                 : bool
   10894               0 : nsDocShell::IsFrame()
   10895                 : {
   10896                 :     nsCOMPtr<nsIDocShellTreeItem> parent =
   10897               0 :         do_QueryInterface(GetAsSupports(mParent));
   10898               0 :     if (parent) {
   10899               0 :         PRInt32 parentType = ~mItemType;        // Not us
   10900               0 :         parent->GetItemType(&parentType);
   10901               0 :         if (parentType == mItemType)    // This is a frame
   10902               0 :             return true;
   10903                 :     }
   10904                 : 
   10905               0 :     return false;
   10906                 : }
   10907                 : 
   10908                 : /* boolean IsBeingDestroyed (); */
   10909                 : NS_IMETHODIMP 
   10910               0 : nsDocShell::IsBeingDestroyed(bool *aDoomed)
   10911                 : {
   10912               0 :   NS_ENSURE_ARG(aDoomed);
   10913               0 :   *aDoomed = mIsBeingDestroyed;
   10914               0 :   return NS_OK;
   10915                 : }
   10916                 : 
   10917                 : 
   10918                 : NS_IMETHODIMP 
   10919               0 : nsDocShell::GetIsExecutingOnLoadHandler(bool *aResult)
   10920                 : {
   10921               0 :   NS_ENSURE_ARG(aResult);
   10922               0 :   *aResult = mIsExecutingOnLoadHandler;
   10923               0 :   return NS_OK;
   10924                 : }
   10925                 : 
   10926                 : NS_IMETHODIMP
   10927               0 : nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState **aLayoutHistoryState)
   10928                 : {
   10929               0 :   if (mOSHE)
   10930               0 :     mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
   10931               0 :   return NS_OK;
   10932                 : }
   10933                 : 
   10934                 : NS_IMETHODIMP
   10935               0 : nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState)
   10936                 : {
   10937               0 :   if (mOSHE)
   10938               0 :     mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
   10939               0 :   return NS_OK;
   10940                 : }
   10941                 : 
   10942                 : //*****************************************************************************
   10943                 : //***    nsRefreshTimer: Object Management
   10944                 : //*****************************************************************************
   10945                 : 
   10946               0 : nsRefreshTimer::nsRefreshTimer()
   10947               0 :     : mDelay(0), mRepeat(false), mMetaRefresh(false)
   10948                 : {
   10949               0 : }
   10950                 : 
   10951               0 : nsRefreshTimer::~nsRefreshTimer()
   10952                 : {
   10953               0 : }
   10954                 : 
   10955                 : //*****************************************************************************
   10956                 : // nsRefreshTimer::nsISupports
   10957                 : //*****************************************************************************   
   10958                 : 
   10959               0 : NS_IMPL_THREADSAFE_ADDREF(nsRefreshTimer)
   10960               0 : NS_IMPL_THREADSAFE_RELEASE(nsRefreshTimer)
   10961                 : 
   10962               0 : NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
   10963               0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
   10964               0 :     NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
   10965               0 : NS_INTERFACE_MAP_END_THREADSAFE
   10966                 : 
   10967                 : ///*****************************************************************************
   10968                 : // nsRefreshTimer::nsITimerCallback
   10969                 : //******************************************************************************
   10970                 : NS_IMETHODIMP
   10971               0 : nsRefreshTimer::Notify(nsITimer * aTimer)
   10972                 : {
   10973               0 :     NS_ASSERTION(mDocShell, "DocShell is somehow null");
   10974                 : 
   10975               0 :     if (mDocShell && aTimer) {
   10976                 :         // Get the delay count to determine load type
   10977               0 :         PRUint32 delay = 0;
   10978               0 :         aTimer->GetDelay(&delay);
   10979               0 :         mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer);
   10980                 :     }
   10981               0 :     return NS_OK;
   10982                 : }
   10983                 : 
   10984                 : //*****************************************************************************
   10985                 : // nsDocShell::InterfaceRequestorProxy
   10986                 : //*****************************************************************************
   10987               0 : nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor* p)
   10988                 : {
   10989               0 :     if (p) {
   10990               0 :         mWeakPtr = do_GetWeakReference(p);
   10991                 :     }
   10992               0 : }
   10993                 :  
   10994               0 : nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
   10995                 : {
   10996               0 :     mWeakPtr = nsnull;
   10997               0 : }
   10998                 : 
   10999               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor) 
   11000                 :   
   11001                 : NS_IMETHODIMP 
   11002               0 : nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID & aIID, void **aSink)
   11003                 : {
   11004               0 :     NS_ENSURE_ARG_POINTER(aSink);
   11005               0 :     nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
   11006               0 :     if (ifReq) {
   11007               0 :         return ifReq->GetInterface(aIID, aSink);
   11008                 :     }
   11009               0 :     *aSink = nsnull;
   11010               0 :     return NS_NOINTERFACE;
   11011                 : }
   11012                 : 
   11013                 : nsresult
   11014               0 : nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer)
   11015                 : {
   11016               0 :     if (!aContentViewer)
   11017               0 :         return NS_ERROR_FAILURE;
   11018                 : 
   11019               0 :     nsCOMPtr<nsIURI> baseURI;
   11020               0 :     nsresult rv = NS_ERROR_NOT_AVAILABLE;
   11021                 : 
   11022               0 :     if (sURIFixup)
   11023                 :         rv = sURIFixup->CreateExposableURI(mCurrentURI,
   11024               0 :                                            getter_AddRefs(baseURI));
   11025                 : 
   11026                 :     // Get the current document and set the base uri
   11027               0 :     if (baseURI) {
   11028               0 :         nsIDocument* document = aContentViewer->GetDocument();
   11029               0 :         if (document) {
   11030               0 :             rv = document->SetBaseURI(baseURI);
   11031                 :         }
   11032                 :     }
   11033               0 :     return rv;
   11034                 : }
   11035                 : 
   11036                 : //*****************************************************************************
   11037                 : // nsDocShell::nsIAuthPromptProvider
   11038                 : //*****************************************************************************
   11039                 : 
   11040                 : NS_IMETHODIMP
   11041               0 : nsDocShell::GetAuthPrompt(PRUint32 aPromptReason, const nsIID& iid,
   11042                 :                           void** aResult)
   11043                 : {
   11044                 :     // a priority prompt request will override a false mAllowAuth setting
   11045               0 :     bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
   11046                 : 
   11047               0 :     if (!mAllowAuth && !priorityPrompt)
   11048               0 :         return NS_ERROR_NOT_AVAILABLE;
   11049                 : 
   11050                 :     // we're either allowing auth, or it's a proxy request
   11051                 :     nsresult rv;
   11052                 :     nsCOMPtr<nsIPromptFactory> wwatch =
   11053               0 :       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
   11054               0 :     NS_ENSURE_SUCCESS(rv, rv);
   11055                 : 
   11056               0 :     rv = EnsureScriptEnvironment();
   11057               0 :     NS_ENSURE_SUCCESS(rv, rv);
   11058                 : 
   11059               0 :     nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(mScriptGlobal));
   11060                 : 
   11061                 :     // Get the an auth prompter for our window so that the parenting
   11062                 :     // of the dialogs works as it should when using tabs.
   11063                 : 
   11064               0 :     return wwatch->GetPrompt(window, iid,
   11065               0 :                              reinterpret_cast<void**>(aResult));
   11066                 : }
   11067                 : 
   11068                 : //*****************************************************************************
   11069                 : // nsDocShell::nsIObserver
   11070                 : //*****************************************************************************
   11071                 : 
   11072                 : NS_IMETHODIMP
   11073               0 : nsDocShell::Observe(nsISupports *aSubject, const char *aTopic,
   11074                 :                     const PRUnichar *aData)
   11075                 : {
   11076               0 :     nsresult rv = NS_OK;
   11077               0 :     if (mObserveErrorPages &&
   11078               0 :         !nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
   11079                 :         !nsCRT::strcmp(aData,
   11080               0 :           NS_LITERAL_STRING("browser.xul.error_pages.enabled").get())) {
   11081                 : 
   11082                 :         bool tmpbool;
   11083               0 :         rv = Preferences::GetBool("browser.xul.error_pages.enabled", &tmpbool);
   11084               0 :         if (NS_SUCCEEDED(rv))
   11085               0 :             mUseErrorPages = tmpbool;
   11086                 : 
   11087                 :     } else {
   11088               0 :         rv = NS_ERROR_UNEXPECTED;
   11089                 :     }
   11090               0 :     return rv;
   11091                 : }
   11092                 : 
   11093                 : //*****************************************************************************
   11094                 : // nsDocShell::nsILoadContext
   11095                 : //*****************************************************************************
   11096                 : NS_IMETHODIMP
   11097               0 : nsDocShell::GetAssociatedWindow(nsIDOMWindow** aWindow)
   11098                 : {
   11099               0 :     CallGetInterface(this, aWindow);
   11100               0 :     return NS_OK;
   11101                 : }
   11102                 : 
   11103                 : NS_IMETHODIMP
   11104               0 : nsDocShell::GetTopWindow(nsIDOMWindow** aWindow)
   11105                 : {
   11106               0 :     nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this));
   11107               0 :     if (win) {
   11108               0 :         win->GetTop(aWindow);
   11109                 :     }
   11110               0 :     return NS_OK;
   11111                 : }
   11112                 : 
   11113                 : NS_IMETHODIMP
   11114               0 : nsDocShell::IsAppOfType(PRUint32 aAppType, bool *aIsOfType)
   11115                 : {
   11116               0 :     nsCOMPtr<nsIDocShell> shell = this;
   11117               0 :     while (shell) {
   11118                 :         PRUint32 type;
   11119               0 :         shell->GetAppType(&type);
   11120               0 :         if (type == aAppType) {
   11121               0 :             *aIsOfType = true;
   11122               0 :             return NS_OK;
   11123                 :         }
   11124               0 :         nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(shell);
   11125               0 :         nsCOMPtr<nsIDocShellTreeItem> parent;
   11126               0 :         item->GetParent(getter_AddRefs(parent));
   11127               0 :         shell = do_QueryInterface(parent);
   11128                 :     }
   11129                 : 
   11130               0 :     *aIsOfType = false;
   11131               0 :     return NS_OK;
   11132                 : }
   11133                 : 
   11134                 : NS_IMETHODIMP
   11135               0 : nsDocShell::GetIsContent(bool *aIsContent)
   11136                 : {
   11137               0 :     *aIsContent = (mItemType == typeContent);
   11138               0 :     return NS_OK;
   11139                 : }
   11140                 : 
   11141                 : bool
   11142               0 : nsDocShell::IsOKToLoadURI(nsIURI* aURI)
   11143                 : {
   11144               0 :     NS_PRECONDITION(aURI, "Must have a URI!");
   11145                 :     
   11146               0 :     if (!mFiredUnloadEvent) {
   11147               0 :         return true;
   11148                 :     }
   11149                 : 
   11150               0 :     if (!mLoadingURI) {
   11151               0 :         return false;
   11152                 :     }
   11153                 : 
   11154                 :     nsCOMPtr<nsIScriptSecurityManager> secMan =
   11155               0 :         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   11156                 :     return
   11157                 :         secMan &&
   11158               0 :         NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
   11159                 : }
   11160                 : 
   11161                 : //
   11162                 : // Routines for selection and clipboard
   11163                 : //
   11164                 : nsresult
   11165               0 : nsDocShell::GetControllerForCommand(const char * inCommand,
   11166                 :                                     nsIController** outController)
   11167                 : {
   11168               0 :   NS_ENSURE_ARG_POINTER(outController);
   11169               0 :   *outController = nsnull;
   11170                 : 
   11171               0 :   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mScriptGlobal));
   11172               0 :   if (window) {
   11173               0 :       nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
   11174               0 :       if (root) {
   11175               0 :           return root->GetControllerForCommand(inCommand, outController);
   11176                 :       }
   11177                 :   }
   11178                 : 
   11179               0 :   return NS_ERROR_FAILURE;
   11180                 : }
   11181                 : 
   11182                 : nsresult
   11183               0 : nsDocShell::IsCommandEnabled(const char * inCommand, bool* outEnabled)
   11184                 : {
   11185               0 :   NS_ENSURE_ARG_POINTER(outEnabled);
   11186               0 :   *outEnabled = false;
   11187                 : 
   11188               0 :   nsresult rv = NS_ERROR_FAILURE;
   11189                 :   
   11190               0 :   nsCOMPtr<nsIController> controller;
   11191               0 :   rv = GetControllerForCommand (inCommand, getter_AddRefs(controller));
   11192               0 :   if (controller)
   11193               0 :     rv = controller->IsCommandEnabled(inCommand, outEnabled);
   11194                 :   
   11195               0 :   return rv;
   11196                 : }
   11197                 : 
   11198                 : nsresult
   11199               0 : nsDocShell::DoCommand(const char * inCommand)
   11200                 : {
   11201               0 :   nsresult rv = NS_ERROR_FAILURE;
   11202                 :   
   11203               0 :   nsCOMPtr<nsIController> controller;
   11204               0 :   rv = GetControllerForCommand(inCommand, getter_AddRefs(controller));
   11205               0 :   if (controller)
   11206               0 :     rv = controller->DoCommand(inCommand);
   11207                 :   
   11208               0 :   return rv;
   11209                 : }
   11210                 : 
   11211                 : nsresult
   11212               0 : nsDocShell::EnsureCommandHandler()
   11213                 : {
   11214               0 :   if (!mCommandManager)
   11215                 :   {
   11216                 :     nsCOMPtr<nsPICommandUpdater> commandUpdater =
   11217               0 :       do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
   11218               0 :     if (!commandUpdater) return NS_ERROR_OUT_OF_MEMORY;
   11219                 :     
   11220                 :     nsCOMPtr<nsIDOMWindow> domWindow =
   11221               0 :       do_GetInterface(static_cast<nsIInterfaceRequestor *>(this));
   11222                 : 
   11223               0 :     nsresult rv = commandUpdater->Init(domWindow);
   11224               0 :     if (NS_SUCCEEDED(rv))
   11225               0 :       mCommandManager = do_QueryInterface(commandUpdater);
   11226                 :   }
   11227                 :   
   11228               0 :   return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
   11229                 : }
   11230                 : 
   11231                 : NS_IMETHODIMP
   11232               0 : nsDocShell::CanCutSelection(bool* aResult)
   11233                 : {
   11234               0 :   return IsCommandEnabled("cmd_cut", aResult);
   11235                 : }
   11236                 : 
   11237                 : NS_IMETHODIMP
   11238               0 : nsDocShell::CanCopySelection(bool* aResult)
   11239                 : {
   11240               0 :   return IsCommandEnabled("cmd_copy", aResult);
   11241                 : }
   11242                 : 
   11243                 : NS_IMETHODIMP
   11244               0 : nsDocShell::CanCopyLinkLocation(bool* aResult)
   11245                 : {
   11246               0 :   return IsCommandEnabled("cmd_copyLink", aResult);
   11247                 : }
   11248                 : 
   11249                 : NS_IMETHODIMP
   11250               0 : nsDocShell::CanCopyImageLocation(bool* aResult)
   11251                 : {
   11252                 :   return IsCommandEnabled("cmd_copyImageLocation",
   11253               0 :                           aResult);
   11254                 : }
   11255                 : 
   11256                 : NS_IMETHODIMP
   11257               0 : nsDocShell::CanCopyImageContents(bool* aResult)
   11258                 : {
   11259                 :   return IsCommandEnabled("cmd_copyImageContents",
   11260               0 :                           aResult);
   11261                 : }
   11262                 : 
   11263                 : NS_IMETHODIMP
   11264               0 : nsDocShell::CanPaste(bool* aResult)
   11265                 : {
   11266               0 :   return IsCommandEnabled("cmd_paste", aResult);
   11267                 : }
   11268                 : 
   11269                 : NS_IMETHODIMP
   11270               0 : nsDocShell::CutSelection(void)
   11271                 : {
   11272               0 :   return DoCommand ( "cmd_cut" );
   11273                 : }
   11274                 : 
   11275                 : NS_IMETHODIMP
   11276               0 : nsDocShell::CopySelection(void)
   11277                 : {
   11278               0 :   return DoCommand ( "cmd_copy" );
   11279                 : }
   11280                 : 
   11281                 : NS_IMETHODIMP
   11282               0 : nsDocShell::CopyLinkLocation(void)
   11283                 : {
   11284               0 :   return DoCommand ( "cmd_copyLink" );
   11285                 : }
   11286                 : 
   11287                 : NS_IMETHODIMP
   11288               0 : nsDocShell::CopyImageLocation(void)
   11289                 : {
   11290               0 :   return DoCommand ( "cmd_copyImageLocation" );
   11291                 : }
   11292                 : 
   11293                 : NS_IMETHODIMP
   11294               0 : nsDocShell::CopyImageContents(void)
   11295                 : {
   11296               0 :   return DoCommand ( "cmd_copyImageContents" );
   11297                 : }
   11298                 : 
   11299                 : NS_IMETHODIMP
   11300               0 : nsDocShell::Paste(void)
   11301                 : {
   11302               0 :   return DoCommand ( "cmd_paste" );
   11303                 : }
   11304                 : 
   11305                 : NS_IMETHODIMP
   11306               0 : nsDocShell::SelectAll(void)
   11307                 : {
   11308               0 :   return DoCommand ( "cmd_selectAll" );
   11309                 : }
   11310                 : 
   11311                 : //
   11312                 : // SelectNone
   11313                 : //
   11314                 : // Collapses the current selection, insertion point ends up at beginning
   11315                 : // of previous selection.
   11316                 : //
   11317                 : NS_IMETHODIMP
   11318               0 : nsDocShell::SelectNone(void)
   11319                 : {
   11320               0 :   return DoCommand ( "cmd_selectNone" );
   11321                 : }
   11322                 : 
   11323                 : //----------------------------------------------------------------------
   11324                 : 
   11325                 : // link handling
   11326                 : 
   11327               0 : class OnLinkClickEvent : public nsRunnable {
   11328                 : public:
   11329                 :   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
   11330                 :                    nsIURI* aURI,
   11331                 :                    const PRUnichar* aTargetSpec,
   11332                 :                    nsIInputStream* aPostDataStream, 
   11333                 :                    nsIInputStream* aHeadersDataStream,
   11334                 :                    bool aIsTrusted);
   11335                 : 
   11336               0 :   NS_IMETHOD Run() {
   11337               0 :     nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mHandler->mScriptGlobal));
   11338               0 :     nsAutoPopupStatePusher popupStatePusher(window, mPopupState);
   11339                 : 
   11340               0 :     nsCxPusher pusher;
   11341               0 :     if (mIsTrusted || pusher.Push(mContent)) {
   11342               0 :       mHandler->OnLinkClickSync(mContent, mURI,
   11343                 :                                 mTargetSpec.get(), mPostDataStream,
   11344                 :                                 mHeadersDataStream,
   11345               0 :                                 nsnull, nsnull);
   11346                 :     }
   11347               0 :     return NS_OK;
   11348                 :   }
   11349                 : 
   11350                 : private:
   11351                 :   nsRefPtr<nsDocShell>     mHandler;
   11352                 :   nsCOMPtr<nsIURI>         mURI;
   11353                 :   nsString                 mTargetSpec;
   11354                 :   nsCOMPtr<nsIInputStream> mPostDataStream;
   11355                 :   nsCOMPtr<nsIInputStream> mHeadersDataStream;
   11356                 :   nsCOMPtr<nsIContent>     mContent;
   11357                 :   PopupControlState        mPopupState;
   11358                 :   bool                     mIsTrusted;
   11359                 : };
   11360                 : 
   11361               0 : OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
   11362                 :                                    nsIContent *aContent,
   11363                 :                                    nsIURI* aURI,
   11364                 :                                    const PRUnichar* aTargetSpec,
   11365                 :                                    nsIInputStream* aPostDataStream,
   11366                 :                                    nsIInputStream* aHeadersDataStream,
   11367                 :                                    bool aIsTrusted)
   11368                 :   : mHandler(aHandler)
   11369                 :   , mURI(aURI)
   11370                 :   , mTargetSpec(aTargetSpec)
   11371                 :   , mPostDataStream(aPostDataStream)
   11372                 :   , mHeadersDataStream(aHeadersDataStream)
   11373                 :   , mContent(aContent)
   11374               0 :   , mIsTrusted(aIsTrusted)
   11375                 : {
   11376               0 :   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mHandler->mScriptGlobal));
   11377                 : 
   11378               0 :   mPopupState = window->GetPopupControlState();
   11379               0 : }
   11380                 : 
   11381                 : //----------------------------------------
   11382                 : 
   11383                 : NS_IMETHODIMP
   11384               0 : nsDocShell::OnLinkClick(nsIContent* aContent,
   11385                 :                         nsIURI* aURI,
   11386                 :                         const PRUnichar* aTargetSpec,
   11387                 :                         nsIInputStream* aPostDataStream,
   11388                 :                         nsIInputStream* aHeadersDataStream,
   11389                 :                         bool aIsTrusted)
   11390                 : {
   11391               0 :   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
   11392                 : 
   11393               0 :   if (!IsOKToLoadURI(aURI)) {
   11394               0 :     return NS_OK;
   11395                 :   }
   11396                 : 
   11397               0 :   if (aContent->IsEditable()) {
   11398               0 :     return NS_OK;
   11399                 :   }
   11400                 : 
   11401               0 :   nsresult rv = NS_ERROR_FAILURE;
   11402               0 :   nsAutoString target;
   11403                 : 
   11404               0 :   nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
   11405               0 :   if (browserChrome3) {
   11406               0 :     nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
   11407               0 :     nsAutoString oldTarget(aTargetSpec);
   11408               0 :     rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
   11409               0 :                                                linkNode, mIsAppTab, target);
   11410                 :   }
   11411                 :   
   11412               0 :   if (NS_FAILED(rv))
   11413               0 :     target = aTargetSpec;  
   11414                 : 
   11415                 :   nsCOMPtr<nsIRunnable> ev =
   11416                 :       new OnLinkClickEvent(this, aContent, aURI, target.get(),
   11417               0 :                            aPostDataStream, aHeadersDataStream, aIsTrusted);
   11418               0 :   return NS_DispatchToCurrentThread(ev);
   11419                 : }
   11420                 : 
   11421                 : NS_IMETHODIMP
   11422               0 : nsDocShell::OnLinkClickSync(nsIContent *aContent,
   11423                 :                             nsIURI* aURI,
   11424                 :                             const PRUnichar* aTargetSpec,
   11425                 :                             nsIInputStream* aPostDataStream,
   11426                 :                             nsIInputStream* aHeadersDataStream,
   11427                 :                             nsIDocShell** aDocShell,
   11428                 :                             nsIRequest** aRequest)
   11429                 : {
   11430                 :   // Initialize the DocShell / Request
   11431               0 :   if (aDocShell) {
   11432               0 :     *aDocShell = nsnull;
   11433                 :   }
   11434               0 :   if (aRequest) {
   11435               0 :     *aRequest = nsnull;
   11436                 :   }
   11437                 : 
   11438               0 :   if (!IsOKToLoadURI(aURI)) {
   11439               0 :     return NS_OK;
   11440                 :   }
   11441                 : 
   11442               0 :   if (aContent->IsEditable()) {
   11443               0 :     return NS_OK;
   11444                 :   }
   11445                 : 
   11446                 :   {
   11447                 :     // defer to an external protocol handler if necessary...
   11448                 :     nsCOMPtr<nsIExternalProtocolService> extProtService =
   11449               0 :         do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
   11450               0 :     if (extProtService) {
   11451               0 :       nsCAutoString scheme;
   11452               0 :       aURI->GetScheme(scheme);
   11453               0 :       if (!scheme.IsEmpty()) {
   11454                 :         // if the URL scheme does not correspond to an exposed protocol, then we
   11455                 :         // need to hand this link click over to the external protocol handler.
   11456                 :         bool isExposed;
   11457               0 :         nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
   11458               0 :         if (NS_SUCCEEDED(rv) && !isExposed) {
   11459               0 :           return extProtService->LoadURI(aURI, this); 
   11460                 :         }
   11461                 :       }
   11462                 :     }
   11463                 :   }
   11464                 : 
   11465                 :   // Get the owner document of the link that was clicked, this will be
   11466                 :   // the document that the link is in, or the last document that the
   11467                 :   // link was in. From that document, we'll get the URI to use as the
   11468                 :   // referer, since the current URI in this docshell may be a
   11469                 :   // new document that we're in the process of loading.
   11470               0 :   nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
   11471               0 :   NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
   11472                 : 
   11473                 :   // Now check that the refererDoc's inner window is the current inner
   11474                 :   // window for mScriptGlobal.  If it's not, then we don't want to
   11475                 :   // follow this link.
   11476               0 :   nsPIDOMWindow* refererInner = refererDoc->GetInnerWindow();
   11477               0 :   NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
   11478               0 :   nsCOMPtr<nsPIDOMWindow> outerWindow = do_QueryInterface(mScriptGlobal);
   11479               0 :   if (!outerWindow || outerWindow->GetCurrentInnerWindow() != refererInner) {
   11480                 :       // We're no longer the current inner window
   11481               0 :       return NS_OK;
   11482                 :   }
   11483                 : 
   11484               0 :   nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
   11485                 : 
   11486                 :   // referer could be null here in some odd cases, but that's ok,
   11487                 :   // we'll just load the link w/o sending a referer in those cases.
   11488                 : 
   11489               0 :   nsAutoString target(aTargetSpec);
   11490                 : 
   11491                 :   // If this is an anchor element, grab its type property to use as a hint
   11492               0 :   nsAutoString typeHint;
   11493               0 :   nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent));
   11494               0 :   if (anchor) {
   11495               0 :     anchor->GetType(typeHint);
   11496               0 :     NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
   11497               0 :     nsCAutoString type, dummy;
   11498               0 :     NS_ParseContentType(utf8Hint, type, dummy);
   11499               0 :     CopyUTF8toUTF16(type, typeHint);
   11500                 :   }
   11501                 : 
   11502                 :   // Clone the URI now, in case a content policy or something messes
   11503                 :   // with it under InternalLoad; we do _not_ want to change the URI
   11504                 :   // our caller passed in.
   11505               0 :   nsCOMPtr<nsIURI> clonedURI;
   11506               0 :   aURI->Clone(getter_AddRefs(clonedURI));
   11507               0 :   if (!clonedURI) {
   11508               0 :     return NS_ERROR_OUT_OF_MEMORY;
   11509                 :   }
   11510                 :   
   11511                 :   nsresult rv = InternalLoad(clonedURI,                 // New URI
   11512                 :                              referer,                   // Referer URI
   11513               0 :                              aContent->NodePrincipal(), // Owner is our node's
   11514                 :                                                         // principal
   11515                 :                              INTERNAL_LOAD_FLAGS_NONE,
   11516                 :                              target.get(),              // Window target
   11517               0 :                              NS_LossyConvertUTF16toASCII(typeHint).get(),
   11518                 :                              aPostDataStream,           // Post data stream
   11519                 :                              aHeadersDataStream,        // Headers stream
   11520                 :                              LOAD_LINK,                 // Load type
   11521                 :                              nsnull,                    // No SHEntry
   11522                 :                              true,                   // first party site
   11523                 :                              aDocShell,                 // DocShell out-param
   11524               0 :                              aRequest);                 // Request out-param
   11525               0 :   if (NS_SUCCEEDED(rv)) {
   11526               0 :     DispatchPings(aContent, referer);
   11527                 :   }
   11528               0 :   return rv;
   11529                 : }
   11530                 : 
   11531                 : NS_IMETHODIMP
   11532               0 : nsDocShell::OnOverLink(nsIContent* aContent,
   11533                 :                        nsIURI* aURI,
   11534                 :                        const PRUnichar* aTargetSpec)
   11535                 : {
   11536               0 :   if (aContent->IsEditable()) {
   11537               0 :     return NS_OK;
   11538                 :   }
   11539                 : 
   11540               0 :   nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
   11541               0 :   nsresult rv = NS_ERROR_FAILURE;
   11542                 : 
   11543               0 :   nsCOMPtr<nsIWebBrowserChrome> browserChrome;
   11544               0 :   if (!browserChrome2) {
   11545               0 :     browserChrome = do_GetInterface(mTreeOwner);
   11546               0 :     if (!browserChrome)
   11547               0 :       return rv;
   11548                 :   }
   11549                 : 
   11550                 :   nsCOMPtr<nsITextToSubURI> textToSubURI =
   11551               0 :       do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
   11552               0 :   if (NS_FAILED(rv))
   11553               0 :     return rv;
   11554                 : 
   11555                 :   // use url origin charset to unescape the URL
   11556               0 :   nsCAutoString charset;
   11557               0 :   rv = aURI->GetOriginCharset(charset);
   11558               0 :   NS_ENSURE_SUCCESS(rv, rv);
   11559                 : 
   11560               0 :   nsCAutoString spec;
   11561               0 :   rv = aURI->GetSpec(spec);
   11562               0 :   NS_ENSURE_SUCCESS(rv, rv);
   11563                 : 
   11564               0 :   nsAutoString uStr;
   11565               0 :   rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr);    
   11566               0 :   NS_ENSURE_SUCCESS(rv, rv);
   11567                 : 
   11568               0 :   if (browserChrome2) {
   11569               0 :     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
   11570               0 :     rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
   11571               0 :                                               uStr, element);
   11572                 :   } else {
   11573               0 :     rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
   11574                 :   }
   11575               0 :   return rv;
   11576                 : }
   11577                 : 
   11578                 : NS_IMETHODIMP
   11579               0 : nsDocShell::OnLeaveLink()
   11580                 : {
   11581               0 :   nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
   11582               0 :   nsresult rv = NS_ERROR_FAILURE;
   11583                 : 
   11584               0 :   if (browserChrome)  {
   11585               0 :       rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
   11586               0 :                                     EmptyString().get());
   11587                 :   }
   11588               0 :   return rv;
   11589                 : }
   11590                 : 
   11591                 : //----------------------------------------------------------------------
   11592                 : // Web Shell Services API
   11593                 : 
   11594                 : //This functions is only called when a new charset is detected in loading a document. 
   11595                 : //Its name should be changed to "CharsetReloadDocument"
   11596                 : NS_IMETHODIMP
   11597               0 : nsDocShell::ReloadDocument(const char* aCharset,
   11598                 :                            PRInt32 aSource)
   11599                 : {
   11600                 : 
   11601                 :   // XXX hack. keep the aCharset and aSource wait to pick it up
   11602               0 :   nsCOMPtr<nsIContentViewer> cv;
   11603               0 :   NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
   11604               0 :   if (cv)
   11605                 :   {
   11606               0 :     nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);  
   11607               0 :     if (muDV)
   11608                 :     {
   11609                 :       PRInt32 hint;
   11610               0 :       muDV->GetHintCharacterSetSource(&hint);
   11611               0 :       if (aSource > hint)
   11612                 :       {
   11613               0 :         nsCString charset(aCharset);
   11614               0 :         muDV->SetHintCharacterSet(charset);
   11615               0 :         muDV->SetHintCharacterSetSource(aSource);
   11616               0 :         if(eCharsetReloadRequested != mCharsetReloadState) 
   11617                 :         {
   11618               0 :           mCharsetReloadState = eCharsetReloadRequested;
   11619               0 :           return Reload(LOAD_FLAGS_CHARSET_CHANGE);
   11620                 :         }
   11621                 :       }
   11622                 :     }
   11623                 :   }
   11624                 :   //return failure if this request is not accepted due to mCharsetReloadState
   11625               0 :   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
   11626                 : }
   11627                 : 
   11628                 : 
   11629                 : NS_IMETHODIMP
   11630               0 : nsDocShell::StopDocumentLoad(void)
   11631                 : {
   11632               0 :   if(eCharsetReloadRequested != mCharsetReloadState) 
   11633                 :   {
   11634               0 :     Stop(nsIWebNavigation::STOP_ALL);
   11635               0 :     return NS_OK;
   11636                 :   }
   11637                 :   //return failer if this request is not accepted due to mCharsetReloadState
   11638               0 :   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
   11639                 : }
   11640                 : 
   11641                 : NS_IMETHODIMP
   11642               0 : nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
   11643                 : {
   11644               0 :   *aPrintPreview = nsnull;
   11645                 : #if NS_PRINT_PREVIEW
   11646               0 :   nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
   11647               0 :   if (!print || !print->IsInitializedForPrintPreview()) {
   11648               0 :     Stop(nsIWebNavigation::STOP_ALL);
   11649                 :     nsCOMPtr<nsIPrincipal> principal =
   11650               0 :       do_CreateInstance("@mozilla.org/nullprincipal;1");
   11651               0 :     NS_ENSURE_STATE(principal);
   11652               0 :     nsresult rv = CreateAboutBlankContentViewer(principal, nsnull);
   11653               0 :     NS_ENSURE_SUCCESS(rv, rv);
   11654               0 :     print = do_QueryInterface(mContentViewer);
   11655               0 :     NS_ENSURE_STATE(print);
   11656               0 :     print->InitializeForPrintPreview();
   11657                 :   }
   11658               0 :   nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
   11659               0 :   result.forget(aPrintPreview);
   11660               0 :   return NS_OK;
   11661                 : #else
   11662                 :   return NS_ERROR_NOT_IMPLEMENTED;
   11663                 : #endif
   11664                 : }
   11665                 : 
   11666                 : 
   11667                 : #ifdef DEBUG
   11668                 : unsigned long nsDocShell::gNumberOfDocShells = 0;
   11669                 : #endif
   11670                 : 
   11671                 : NS_IMETHODIMP
   11672               0 : nsDocShell::GetCanExecuteScripts(bool *aResult)
   11673                 : {
   11674               0 :   NS_ENSURE_ARG_POINTER(aResult);
   11675               0 :   *aResult = false; // disallow by default
   11676                 : 
   11677               0 :   nsCOMPtr<nsIDocShell> docshell = this;
   11678                 :   nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem =
   11679               0 :       do_QueryInterface(docshell);
   11680                 : 
   11681               0 :   if (globalObjTreeItem)
   11682                 :   {
   11683               0 :       nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
   11684               0 :       nsCOMPtr<nsIDocShellTreeItem> parentItem;
   11685               0 :       bool firstPass = true;
   11686               0 :       bool lookForParents = false;
   11687                 : 
   11688                 :       // Walk up the docshell tree to see if any containing docshell disallows scripts
   11689               0 :       do
   11690                 :       {
   11691               0 :           nsresult rv = docshell->GetAllowJavascript(aResult);
   11692               0 :           if (NS_FAILED(rv)) return rv;
   11693               0 :           if (!*aResult) {
   11694               0 :               nsDocShell* realDocshell = static_cast<nsDocShell*>(docshell.get());
   11695               0 :               if (realDocshell->mContentViewer) {
   11696               0 :                   nsIDocument* doc = realDocshell->mContentViewer->GetDocument();
   11697               0 :                   if (doc && doc->HasFlag(NODE_IS_EDITABLE) &&
   11698               0 :                       realDocshell->mEditorData) {
   11699               0 :                       nsCOMPtr<nsIEditingSession> editSession;
   11700               0 :                       realDocshell->mEditorData->GetEditingSession(getter_AddRefs(editSession));
   11701               0 :                       bool jsDisabled = false;
   11702               0 :                       if (editSession &&
   11703               0 :                           NS_SUCCEEDED(rv = editSession->GetJsAndPluginsDisabled(&jsDisabled))) {
   11704               0 :                           if (firstPass) {
   11705               0 :                               if (jsDisabled) {
   11706                 :                                   // We have a docshell which has been explicitly set
   11707                 :                                   // to design mode, so we disallow scripts.
   11708               0 :                                   return NS_OK;
   11709                 :                               }
   11710                 :                               // The docshell was not explicitly set to design mode,
   11711                 :                               // so it must be so because a parent was explicitly
   11712                 :                               // set to design mode.  We don't need to look at higher
   11713                 :                               // docshells.
   11714               0 :                               *aResult = true;
   11715                 :                               break;
   11716               0 :                           } else if (lookForParents && jsDisabled) {
   11717                 :                               // If a parent was explicitly set to design mode,
   11718                 :                               // we should allow script execution on the child.
   11719               0 :                               *aResult = true;
   11720                 :                               break;
   11721                 :                           }
   11722                 :                           // If the child docshell allows scripting, and the
   11723                 :                           // parent is inside design mode, we don't need to look
   11724                 :                           // further.
   11725               0 :                           *aResult = true;
   11726               0 :                           return NS_OK;
   11727                 :                       }
   11728               0 :                       NS_WARNING("The editing session does not work?");
   11729               0 :                       return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
   11730                 :                   }
   11731               0 :                   if (firstPass) {
   11732                 :                       // Don't be too hard on docshells on the first pass.
   11733                 :                       // There may be a parent docshell which has been set
   11734                 :                       // to design mode, so look for it.
   11735               0 :                       lookForParents = true;
   11736                 :                   } else {
   11737                 :                       // We have a docshell which disallows scripts
   11738                 :                       // and is not editable, so we shouldn't allow
   11739                 :                       // scripts at all.
   11740               0 :                       return NS_OK;
   11741                 :                   }
   11742                 :               }
   11743               0 :           } else if (lookForParents) {
   11744                 :               // The parent docshell was not explicitly set to design
   11745                 :               // mode, so js on the child docshell was disabled for
   11746                 :               // another reason.  Therefore, we need to disable js.
   11747               0 :               *aResult = false;
   11748               0 :               return NS_OK;
   11749                 :           }
   11750               0 :           firstPass = false;
   11751                 : 
   11752               0 :           treeItem->GetParent(getter_AddRefs(parentItem));
   11753               0 :           treeItem.swap(parentItem);
   11754               0 :           docshell = do_QueryInterface(treeItem);
   11755                 : #ifdef DEBUG
   11756               0 :           if (treeItem && !docshell) {
   11757               0 :             NS_ERROR("cannot get a docshell from a treeItem!");
   11758                 :           }
   11759                 : #endif // DEBUG
   11760               0 :       } while (treeItem && docshell);
   11761                 :   }
   11762                 : 
   11763               0 :   return NS_OK;
   11764                 : }
   11765                 : 
   11766                 : NS_IMETHODIMP
   11767               0 : nsDocShell::GetIsBrowserFrame(bool *aOut)
   11768                 : {
   11769               0 :   NS_ENSURE_ARG_POINTER(aOut);
   11770               0 :   *aOut = mIsBrowserFrame;
   11771               0 :   return NS_OK;
   11772                 : }
   11773                 : 
   11774                 : NS_IMETHODIMP
   11775               0 : nsDocShell::SetIsBrowserFrame(bool aValue)
   11776                 : {
   11777               0 :   mIsBrowserFrame = aValue;
   11778               0 :   return NS_OK;
   11779                 : }

Generated by: LCOV version 1.7