docshell/base/nsDocShell.cpp

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

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

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

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=4 sw=4 tw=80 et: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "nsDocShell.h"
michael@0 8
michael@0 9 #include <algorithm>
michael@0 10
michael@0 11 #include "mozilla/ArrayUtils.h"
michael@0 12 #include "mozilla/Attributes.h"
michael@0 13 #include "mozilla/AutoRestore.h"
michael@0 14 #include "mozilla/Casting.h"
michael@0 15 #include "mozilla/dom/ContentChild.h"
michael@0 16 #include "mozilla/dom/Element.h"
michael@0 17 #include "mozilla/dom/TabChild.h"
michael@0 18 #include "mozilla/EventStateManager.h"
michael@0 19 #include "mozilla/Preferences.h"
michael@0 20 #include "mozilla/Services.h"
michael@0 21 #include "mozilla/StartupTimeline.h"
michael@0 22 #include "mozilla/Telemetry.h"
michael@0 23 #include "mozilla/unused.h"
michael@0 24 #include "mozilla/VisualEventTracer.h"
michael@0 25
michael@0 26 #ifdef MOZ_LOGGING
michael@0 27 // so we can get logging even in release builds (but only for some things)
michael@0 28 #define FORCE_PR_LOG 1
michael@0 29 #endif
michael@0 30
michael@0 31 #include "nsIContent.h"
michael@0 32 #include "nsIDocument.h"
michael@0 33 #include "nsIDOMDocument.h"
michael@0 34 #include "nsIDOMElement.h"
michael@0 35 #include "nsIDOMStorage.h"
michael@0 36 #include "nsPIDOMStorage.h"
michael@0 37 #include "nsIContentViewer.h"
michael@0 38 #include "nsIDocumentLoaderFactory.h"
michael@0 39 #include "nsCURILoader.h"
michael@0 40 #include "nsDocShellCID.h"
michael@0 41 #include "nsDOMCID.h"
michael@0 42 #include "nsNetUtil.h"
michael@0 43 #include "nsRect.h"
michael@0 44 #include "prenv.h"
michael@0 45 #include "nsIMarkupDocumentViewer.h"
michael@0 46 #include "nsIDOMWindow.h"
michael@0 47 #include "nsIWebBrowserChrome.h"
michael@0 48 #include "nsPoint.h"
michael@0 49 #include "nsIObserverService.h"
michael@0 50 #include "nsIPrompt.h"
michael@0 51 #include "nsIAuthPrompt.h"
michael@0 52 #include "nsIAuthPrompt2.h"
michael@0 53 #include "nsIChannelEventSink.h"
michael@0 54 #include "nsIAsyncVerifyRedirectCallback.h"
michael@0 55 #include "nsIScriptSecurityManager.h"
michael@0 56 #include "nsIScriptObjectPrincipal.h"
michael@0 57 #include "nsIScrollableFrame.h"
michael@0 58 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
michael@0 59 #include "nsISeekableStream.h"
michael@0 60 #include "nsAutoPtr.h"
michael@0 61 #include "nsIWritablePropertyBag2.h"
michael@0 62 #include "nsIAppShell.h"
michael@0 63 #include "nsWidgetsCID.h"
michael@0 64 #include "nsIInterfaceRequestorUtils.h"
michael@0 65 #include "nsView.h"
michael@0 66 #include "nsViewManager.h"
michael@0 67 #include "nsIScriptChannel.h"
michael@0 68 #include "nsITimedChannel.h"
michael@0 69 #include "nsIPrivacyTransitionObserver.h"
michael@0 70 #include "nsIReflowObserver.h"
michael@0 71 #include "nsIScrollObserver.h"
michael@0 72 #include "nsIDocShellTreeItem.h"
michael@0 73 #include "nsIChannel.h"
michael@0 74 #include "IHistory.h"
michael@0 75 #include "nsViewSourceHandler.h"
michael@0 76
michael@0 77 // we want to explore making the document own the load group
michael@0 78 // so we can associate the document URI with the load group.
michael@0 79 // until this point, we have an evil hack:
michael@0 80 #include "nsIHttpChannelInternal.h"
michael@0 81 #include "nsPILoadGroupInternal.h"
michael@0 82
michael@0 83 // Local Includes
michael@0 84 #include "nsDocShellLoadInfo.h"
michael@0 85 #include "nsCDefaultURIFixup.h"
michael@0 86 #include "nsDocShellEnumerator.h"
michael@0 87 #include "nsSHistory.h"
michael@0 88 #include "nsDocShellEditorData.h"
michael@0 89
michael@0 90 // Helper Classes
michael@0 91 #include "nsError.h"
michael@0 92 #include "nsEscape.h"
michael@0 93
michael@0 94 // Interfaces Needed
michael@0 95 #include "nsIUploadChannel.h"
michael@0 96 #include "nsIUploadChannel2.h"
michael@0 97 #include "nsIWebProgress.h"
michael@0 98 #include "nsILayoutHistoryState.h"
michael@0 99 #include "nsITimer.h"
michael@0 100 #include "nsISHistoryInternal.h"
michael@0 101 #include "nsIPrincipal.h"
michael@0 102 #include "nsISHEntry.h"
michael@0 103 #include "nsIWindowWatcher.h"
michael@0 104 #include "nsIPromptFactory.h"
michael@0 105 #include "nsITransportSecurityInfo.h"
michael@0 106 #include "nsINSSErrorsService.h"
michael@0 107 #include "nsIApplicationCacheChannel.h"
michael@0 108 #include "nsIApplicationCacheContainer.h"
michael@0 109 #include "nsStreamUtils.h"
michael@0 110 #include "nsIController.h"
michael@0 111 #include "nsPICommandUpdater.h"
michael@0 112 #include "nsIDOMHTMLAnchorElement.h"
michael@0 113 #include "nsIWebBrowserChrome3.h"
michael@0 114 #include "nsITabChild.h"
michael@0 115 #include "nsISiteSecurityService.h"
michael@0 116 #include "nsStructuredCloneContainer.h"
michael@0 117 #include "nsIStructuredCloneContainer.h"
michael@0 118 #ifdef MOZ_PLACES
michael@0 119 #include "nsIFaviconService.h"
michael@0 120 #include "mozIAsyncFavicons.h"
michael@0 121 #endif
michael@0 122 #include "nsINetworkSeer.h"
michael@0 123
michael@0 124 // Editor-related
michael@0 125 #include "nsIEditingSession.h"
michael@0 126
michael@0 127 #include "nsPIDOMWindow.h"
michael@0 128 #include "nsGlobalWindow.h"
michael@0 129 #include "nsPIWindowRoot.h"
michael@0 130 #include "nsICachingChannel.h"
michael@0 131 #include "nsIMultiPartChannel.h"
michael@0 132 #include "nsIWyciwygChannel.h"
michael@0 133
michael@0 134 // For reporting errors with the console service.
michael@0 135 // These can go away if error reporting is propagated up past nsDocShell.
michael@0 136 #include "nsIScriptError.h"
michael@0 137
michael@0 138 // used to dispatch urls to default protocol handlers
michael@0 139 #include "nsCExternalHandlerService.h"
michael@0 140 #include "nsIExternalProtocolService.h"
michael@0 141
michael@0 142 #include "nsFocusManager.h"
michael@0 143
michael@0 144 #include "nsITextToSubURI.h"
michael@0 145
michael@0 146 #include "nsIJARChannel.h"
michael@0 147
michael@0 148 #include "prlog.h"
michael@0 149
michael@0 150 #include "nsISelectionDisplay.h"
michael@0 151
michael@0 152 #include "nsIGlobalHistory2.h"
michael@0 153
michael@0 154 #include "nsIFrame.h"
michael@0 155 #include "nsSubDocumentFrame.h"
michael@0 156
michael@0 157 // for embedding
michael@0 158 #include "nsIWebBrowserChromeFocus.h"
michael@0 159
michael@0 160 #if NS_PRINT_PREVIEW
michael@0 161 #include "nsIDocumentViewerPrint.h"
michael@0 162 #include "nsIWebBrowserPrint.h"
michael@0 163 #endif
michael@0 164
michael@0 165 #include "nsContentUtils.h"
michael@0 166 #include "nsCxPusher.h"
michael@0 167 #include "nsIChannelPolicy.h"
michael@0 168 #include "nsIContentSecurityPolicy.h"
michael@0 169 #include "nsSandboxFlags.h"
michael@0 170 #include "mozIThirdPartyUtil.h"
michael@0 171 #include "nsXULAppAPI.h"
michael@0 172 #include "nsDOMNavigationTiming.h"
michael@0 173 #include "nsISecurityUITelemetry.h"
michael@0 174 #include "nsIAppsService.h"
michael@0 175 #include "nsDSURIContentListener.h"
michael@0 176 #include "nsDocShellLoadTypes.h"
michael@0 177 #include "nsDocShellTransferableHooks.h"
michael@0 178 #include "nsICommandManager.h"
michael@0 179 #include "nsIDOMNode.h"
michael@0 180 #include "nsIDocShellTreeOwner.h"
michael@0 181 #include "nsIHttpChannel.h"
michael@0 182 #include "nsISHContainer.h"
michael@0 183 #include "nsISHistory.h"
michael@0 184 #include "nsISecureBrowserUI.h"
michael@0 185 #include "nsIStringBundle.h"
michael@0 186 #include "nsISupportsArray.h"
michael@0 187 #include "nsIURIFixup.h"
michael@0 188 #include "nsIURILoader.h"
michael@0 189 #include "nsIWebBrowserFind.h"
michael@0 190 #include "nsIWidget.h"
michael@0 191 #include "mozilla/dom/EncodingUtils.h"
michael@0 192
michael@0 193 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
michael@0 194
michael@0 195 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
michael@0 196 //#define DEBUG_DOCSHELL_FOCUS
michael@0 197 #define DEBUG_PAGE_CACHE
michael@0 198 #endif
michael@0 199
michael@0 200 #ifdef XP_WIN
michael@0 201 #include <process.h>
michael@0 202 #define getpid _getpid
michael@0 203 #else
michael@0 204 #include <unistd.h> // for getpid()
michael@0 205 #endif
michael@0 206
michael@0 207 using namespace mozilla;
michael@0 208 using namespace mozilla::dom;
michael@0 209
michael@0 210 // True means sUseErrorPages has been added to preferences var cache.
michael@0 211 static bool gAddedPreferencesVarCache = false;
michael@0 212
michael@0 213 bool nsDocShell::sUseErrorPages = false;
michael@0 214
michael@0 215 // Number of documents currently loading
michael@0 216 static int32_t gNumberOfDocumentsLoading = 0;
michael@0 217
michael@0 218 // Global count of existing docshells.
michael@0 219 static int32_t gDocShellCount = 0;
michael@0 220
michael@0 221 // Global count of docshells with the private attribute set
michael@0 222 static uint32_t gNumberOfPrivateDocShells = 0;
michael@0 223
michael@0 224 // Global reference to the URI fixup service.
michael@0 225 nsIURIFixup *nsDocShell::sURIFixup = 0;
michael@0 226
michael@0 227 // True means we validate window targets to prevent frameset
michael@0 228 // spoofing. Initialize this to a non-bolean value so we know to check
michael@0 229 // the pref on the creation of the first docshell.
michael@0 230 static uint32_t gValidateOrigin = 0xffffffff;
michael@0 231
michael@0 232 // Hint for native dispatch of events on how long to delay after
michael@0 233 // all documents have loaded in milliseconds before favoring normal
michael@0 234 // native event dispatch priorites over performance
michael@0 235 // Can be overridden with docshell.event_starvation_delay_hint pref.
michael@0 236 #define NS_EVENT_STARVATION_DELAY_HINT 2000
michael@0 237
michael@0 238 #ifdef PR_LOGGING
michael@0 239 #ifdef DEBUG
michael@0 240 static PRLogModuleInfo* gDocShellLog;
michael@0 241 #endif
michael@0 242 static PRLogModuleInfo* gDocShellLeakLog;
michael@0 243 #endif
michael@0 244
michael@0 245 const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
michael@0 246 const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
michael@0 247
michael@0 248 static void
michael@0 249 FavorPerformanceHint(bool perfOverStarvation)
michael@0 250 {
michael@0 251 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
michael@0 252 if (appShell) {
michael@0 253 appShell->FavorPerformanceHint(perfOverStarvation,
michael@0 254 Preferences::GetUint("docshell.event_starvation_delay_hint",
michael@0 255 NS_EVENT_STARVATION_DELAY_HINT));
michael@0 256 }
michael@0 257 }
michael@0 258
michael@0 259 //*****************************************************************************
michael@0 260 // <a ping> support
michael@0 261 //*****************************************************************************
michael@0 262
michael@0 263 #define PREF_PINGS_ENABLED "browser.send_pings"
michael@0 264 #define PREF_PINGS_MAX_PER_LINK "browser.send_pings.max_per_link"
michael@0 265 #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
michael@0 266
michael@0 267 // Check prefs to see if pings are enabled and if so what restrictions might
michael@0 268 // be applied.
michael@0 269 //
michael@0 270 // @param maxPerLink
michael@0 271 // This parameter returns the number of pings that are allowed per link click
michael@0 272 //
michael@0 273 // @param requireSameHost
michael@0 274 // This parameter returns true if pings are restricted to the same host as
michael@0 275 // the document in which the click occurs. If the same host restriction is
michael@0 276 // imposed, then we still allow for pings to cross over to different
michael@0 277 // protocols and ports for flexibility and because it is not possible to send
michael@0 278 // a ping via FTP.
michael@0 279 //
michael@0 280 // @returns
michael@0 281 // true if pings are enabled and false otherwise.
michael@0 282 //
michael@0 283 static bool
michael@0 284 PingsEnabled(int32_t *maxPerLink, bool *requireSameHost)
michael@0 285 {
michael@0 286 bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false);
michael@0 287
michael@0 288 *maxPerLink = 1;
michael@0 289 *requireSameHost = true;
michael@0 290
michael@0 291 if (allow) {
michael@0 292 Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, maxPerLink);
michael@0 293 Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost);
michael@0 294 }
michael@0 295
michael@0 296 return allow;
michael@0 297 }
michael@0 298
michael@0 299 static bool
michael@0 300 CheckPingURI(nsIURI* uri, nsIContent* content)
michael@0 301 {
michael@0 302 if (!uri)
michael@0 303 return false;
michael@0 304
michael@0 305 // Check with nsIScriptSecurityManager
michael@0 306 nsCOMPtr<nsIScriptSecurityManager> ssmgr =
michael@0 307 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 308 NS_ENSURE_TRUE(ssmgr, false);
michael@0 309
michael@0 310 nsresult rv =
michael@0 311 ssmgr->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri,
michael@0 312 nsIScriptSecurityManager::STANDARD);
michael@0 313 if (NS_FAILED(rv)) {
michael@0 314 return false;
michael@0 315 }
michael@0 316
michael@0 317 // Ignore non-HTTP(S)
michael@0 318 bool match;
michael@0 319 if ((NS_FAILED(uri->SchemeIs("http", &match)) || !match) &&
michael@0 320 (NS_FAILED(uri->SchemeIs("https", &match)) || !match)) {
michael@0 321 return false;
michael@0 322 }
michael@0 323
michael@0 324 // Check with contentpolicy
michael@0 325 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
michael@0 326 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING,
michael@0 327 uri,
michael@0 328 content->NodePrincipal(),
michael@0 329 content,
michael@0 330 EmptyCString(), // mime hint
michael@0 331 nullptr, //extra
michael@0 332 &shouldLoad);
michael@0 333 return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
michael@0 334 }
michael@0 335
michael@0 336 typedef void (* ForEachPingCallback)(void *closure, nsIContent *content,
michael@0 337 nsIURI *uri, nsIIOService *ios);
michael@0 338
michael@0 339 static void
michael@0 340 ForEachPing(nsIContent *content, ForEachPingCallback callback, void *closure)
michael@0 341 {
michael@0 342 // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
michael@0 343 // since we'd still need to parse the resulting string. Instead, we
michael@0 344 // just parse the raw attribute. It might be nice if the content node
michael@0 345 // implemented an interface that exposed an enumeration of nsIURIs.
michael@0 346
michael@0 347 // Make sure we are dealing with either an <A> or <AREA> element in the HTML
michael@0 348 // or XHTML namespace.
michael@0 349 if (!content->IsHTML())
michael@0 350 return;
michael@0 351 nsIAtom *nameAtom = content->Tag();
michael@0 352 if (nameAtom != nsGkAtoms::a && nameAtom != nsGkAtoms::area)
michael@0 353 return;
michael@0 354
michael@0 355 nsCOMPtr<nsIAtom> pingAtom = do_GetAtom("ping");
michael@0 356 if (!pingAtom)
michael@0 357 return;
michael@0 358
michael@0 359 nsAutoString value;
michael@0 360 content->GetAttr(kNameSpaceID_None, pingAtom, value);
michael@0 361 if (value.IsEmpty())
michael@0 362 return;
michael@0 363
michael@0 364 nsCOMPtr<nsIIOService> ios = do_GetIOService();
michael@0 365 if (!ios)
michael@0 366 return;
michael@0 367
michael@0 368 nsIDocument *doc = content->OwnerDoc();
michael@0 369
michael@0 370 // value contains relative URIs split on spaces (U+0020)
michael@0 371 const char16_t *start = value.BeginReading();
michael@0 372 const char16_t *end = value.EndReading();
michael@0 373 const char16_t *iter = start;
michael@0 374 for (;;) {
michael@0 375 if (iter < end && *iter != ' ') {
michael@0 376 ++iter;
michael@0 377 } else { // iter is pointing at either end or a space
michael@0 378 while (*start == ' ' && start < iter)
michael@0 379 ++start;
michael@0 380 if (iter != start) {
michael@0 381 nsCOMPtr<nsIURI> uri, baseURI = content->GetBaseURI();
michael@0 382 ios->NewURI(NS_ConvertUTF16toUTF8(Substring(start, iter)),
michael@0 383 doc->GetDocumentCharacterSet().get(),
michael@0 384 baseURI, getter_AddRefs(uri));
michael@0 385 if (CheckPingURI(uri, content)) {
michael@0 386 callback(closure, content, uri, ios);
michael@0 387 }
michael@0 388 }
michael@0 389 start = iter = iter + 1;
michael@0 390 if (iter >= end)
michael@0 391 break;
michael@0 392 }
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 //----------------------------------------------------------------------
michael@0 397
michael@0 398 // We wait this many milliseconds before killing the ping channel...
michael@0 399 #define PING_TIMEOUT 10000
michael@0 400
michael@0 401 static void
michael@0 402 OnPingTimeout(nsITimer *timer, void *closure)
michael@0 403 {
michael@0 404 nsILoadGroup *loadGroup = static_cast<nsILoadGroup *>(closure);
michael@0 405 if (loadGroup)
michael@0 406 loadGroup->Cancel(NS_ERROR_ABORT);
michael@0 407 }
michael@0 408
michael@0 409 // Check to see if two URIs have the same host or not
michael@0 410 static bool
michael@0 411 IsSameHost(nsIURI *uri1, nsIURI *uri2)
michael@0 412 {
michael@0 413 nsAutoCString host1, host2;
michael@0 414 uri1->GetAsciiHost(host1);
michael@0 415 uri2->GetAsciiHost(host2);
michael@0 416 return host1.Equals(host2);
michael@0 417 }
michael@0 418
michael@0 419 class nsPingListener MOZ_FINAL : public nsIStreamListener
michael@0 420 , public nsIInterfaceRequestor
michael@0 421 , public nsIChannelEventSink
michael@0 422 {
michael@0 423 public:
michael@0 424 NS_DECL_ISUPPORTS
michael@0 425 NS_DECL_NSIREQUESTOBSERVER
michael@0 426 NS_DECL_NSISTREAMLISTENER
michael@0 427 NS_DECL_NSIINTERFACEREQUESTOR
michael@0 428 NS_DECL_NSICHANNELEVENTSINK
michael@0 429
michael@0 430 nsPingListener(bool requireSameHost, nsIContent* content, nsILoadGroup* loadGroup)
michael@0 431 : mRequireSameHost(requireSameHost),
michael@0 432 mContent(content),
michael@0 433 mLoadGroup(loadGroup)
michael@0 434 {}
michael@0 435
michael@0 436 ~nsPingListener();
michael@0 437
michael@0 438 nsresult StartTimeout();
michael@0 439
michael@0 440 private:
michael@0 441 bool mRequireSameHost;
michael@0 442 nsCOMPtr<nsIContent> mContent;
michael@0 443 nsCOMPtr<nsILoadGroup> mLoadGroup;
michael@0 444 nsCOMPtr<nsITimer> mTimer;
michael@0 445 };
michael@0 446
michael@0 447 NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver,
michael@0 448 nsIInterfaceRequestor, nsIChannelEventSink)
michael@0 449
michael@0 450 nsPingListener::~nsPingListener()
michael@0 451 {
michael@0 452 if (mTimer) {
michael@0 453 mTimer->Cancel();
michael@0 454 mTimer = nullptr;
michael@0 455 }
michael@0 456 }
michael@0 457
michael@0 458 nsresult
michael@0 459 nsPingListener::StartTimeout()
michael@0 460 {
michael@0 461 nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
michael@0 462
michael@0 463 if (timer) {
michael@0 464 nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, mLoadGroup,
michael@0 465 PING_TIMEOUT,
michael@0 466 nsITimer::TYPE_ONE_SHOT);
michael@0 467 if (NS_SUCCEEDED(rv)) {
michael@0 468 mTimer = timer;
michael@0 469 return NS_OK;
michael@0 470 }
michael@0 471 }
michael@0 472
michael@0 473 return NS_ERROR_OUT_OF_MEMORY;
michael@0 474 }
michael@0 475
michael@0 476 NS_IMETHODIMP
michael@0 477 nsPingListener::OnStartRequest(nsIRequest *request, nsISupports *context)
michael@0 478 {
michael@0 479 return NS_OK;
michael@0 480 }
michael@0 481
michael@0 482 NS_IMETHODIMP
michael@0 483 nsPingListener::OnDataAvailable(nsIRequest *request, nsISupports *context,
michael@0 484 nsIInputStream *stream, uint64_t offset,
michael@0 485 uint32_t count)
michael@0 486 {
michael@0 487 uint32_t result;
michael@0 488 return stream->ReadSegments(NS_DiscardSegment, nullptr, count, &result);
michael@0 489 }
michael@0 490
michael@0 491 NS_IMETHODIMP
michael@0 492 nsPingListener::OnStopRequest(nsIRequest *request, nsISupports *context,
michael@0 493 nsresult status)
michael@0 494 {
michael@0 495 mLoadGroup = nullptr;
michael@0 496
michael@0 497 if (mTimer) {
michael@0 498 mTimer->Cancel();
michael@0 499 mTimer = nullptr;
michael@0 500 }
michael@0 501
michael@0 502 return NS_OK;
michael@0 503 }
michael@0 504
michael@0 505 NS_IMETHODIMP
michael@0 506 nsPingListener::GetInterface(const nsIID &iid, void **result)
michael@0 507 {
michael@0 508 if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
michael@0 509 NS_ADDREF_THIS();
michael@0 510 *result = (nsIChannelEventSink *) this;
michael@0 511 return NS_OK;
michael@0 512 }
michael@0 513
michael@0 514 return NS_ERROR_NO_INTERFACE;
michael@0 515 }
michael@0 516
michael@0 517 NS_IMETHODIMP
michael@0 518 nsPingListener::AsyncOnChannelRedirect(nsIChannel *oldChan, nsIChannel *newChan,
michael@0 519 uint32_t flags,
michael@0 520 nsIAsyncVerifyRedirectCallback *callback)
michael@0 521 {
michael@0 522 nsCOMPtr<nsIURI> newURI;
michael@0 523 newChan->GetURI(getter_AddRefs(newURI));
michael@0 524
michael@0 525 if (!CheckPingURI(newURI, mContent))
michael@0 526 return NS_ERROR_ABORT;
michael@0 527
michael@0 528 if (!mRequireSameHost) {
michael@0 529 callback->OnRedirectVerifyCallback(NS_OK);
michael@0 530 return NS_OK;
michael@0 531 }
michael@0 532
michael@0 533 // XXXbz should this be using something more like the nsContentUtils
michael@0 534 // same-origin checker?
michael@0 535 nsCOMPtr<nsIURI> oldURI;
michael@0 536 oldChan->GetURI(getter_AddRefs(oldURI));
michael@0 537 NS_ENSURE_STATE(oldURI && newURI);
michael@0 538
michael@0 539 if (!IsSameHost(oldURI, newURI))
michael@0 540 return NS_ERROR_ABORT;
michael@0 541
michael@0 542 callback->OnRedirectVerifyCallback(NS_OK);
michael@0 543 return NS_OK;
michael@0 544 }
michael@0 545
michael@0 546 struct SendPingInfo {
michael@0 547 int32_t numPings;
michael@0 548 int32_t maxPings;
michael@0 549 bool requireSameHost;
michael@0 550 nsIURI *target;
michael@0 551 nsIURI *referrer;
michael@0 552 };
michael@0 553
michael@0 554 static void
michael@0 555 SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
michael@0 556 {
michael@0 557 SendPingInfo *info = static_cast<SendPingInfo *>(closure);
michael@0 558 if (info->numPings >= info->maxPings)
michael@0 559 return;
michael@0 560
michael@0 561 if (info->requireSameHost) {
michael@0 562 // Make sure the referrer and the given uri share the same origin. We
michael@0 563 // only require the same hostname. The scheme and port may differ.
michael@0 564 if (!IsSameHost(uri, info->referrer))
michael@0 565 return;
michael@0 566 }
michael@0 567
michael@0 568 nsIDocument *doc = content->OwnerDoc();
michael@0 569
michael@0 570 nsCOMPtr<nsIChannel> chan;
michael@0 571 ios->NewChannelFromURI(uri, getter_AddRefs(chan));
michael@0 572 if (!chan)
michael@0 573 return;
michael@0 574
michael@0 575 // Don't bother caching the result of this URI load.
michael@0 576 chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING);
michael@0 577
michael@0 578 nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
michael@0 579 if (!httpChan)
michael@0 580 return;
michael@0 581
michael@0 582 // This is needed in order for 3rd-party cookie blocking to work.
michael@0 583 nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
michael@0 584 if (httpInternal)
michael@0 585 httpInternal->SetDocumentURI(doc->GetDocumentURI());
michael@0 586
michael@0 587
michael@0 588 httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
michael@0 589
michael@0 590 // Remove extraneous request headers (to reduce request size)
michael@0 591 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
michael@0 592 EmptyCString(), false);
michael@0 593 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
michael@0 594 EmptyCString(), false);
michael@0 595 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
michael@0 596 EmptyCString(), false);
michael@0 597
michael@0 598 // Always send a Ping-To header.
michael@0 599 nsAutoCString pingTo;
michael@0 600 if (NS_SUCCEEDED(info->target->GetSpec(pingTo)))
michael@0 601 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
michael@0 602
michael@0 603 nsCOMPtr<nsIScriptSecurityManager> sm =
michael@0 604 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 605
michael@0 606 if (sm && info->referrer) {
michael@0 607 bool referrerIsSecure;
michael@0 608 uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
michael@0 609 nsresult rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
michael@0 610
michael@0 611 // Default to sending less data if NS_URIChainHasFlags() fails.
michael@0 612 referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
michael@0 613
michael@0 614 bool sameOrigin =
michael@0 615 NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, uri, false));
michael@0 616
michael@0 617 // If both the address of the document containing the hyperlink being
michael@0 618 // audited and "ping URL" have the same origin or the document containing
michael@0 619 // the hyperlink being audited was not retrieved over an encrypted
michael@0 620 // connection, send a Ping-From header.
michael@0 621 if (sameOrigin || !referrerIsSecure) {
michael@0 622 nsAutoCString pingFrom;
michael@0 623 if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom)))
michael@0 624 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom, false);
michael@0 625 }
michael@0 626
michael@0 627 // If the document containing the hyperlink being audited was not retrieved
michael@0 628 // over an encrypted connection and its address does not have the same
michael@0 629 // origin as "ping URL", send a referrer.
michael@0 630 if (!sameOrigin && !referrerIsSecure)
michael@0 631 httpChan->SetReferrer(info->referrer);
michael@0 632 }
michael@0 633
michael@0 634 nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan);
michael@0 635 if (!uploadChan)
michael@0 636 return;
michael@0 637
michael@0 638 NS_NAMED_LITERAL_CSTRING(uploadData, "PING");
michael@0 639
michael@0 640 nsCOMPtr<nsIInputStream> uploadStream;
michael@0 641 NS_NewPostDataStream(getter_AddRefs(uploadStream), false, uploadData);
michael@0 642 if (!uploadStream)
michael@0 643 return;
michael@0 644
michael@0 645 uploadChan->ExplicitSetUploadStream(uploadStream,
michael@0 646 NS_LITERAL_CSTRING("text/ping"), uploadData.Length(),
michael@0 647 NS_LITERAL_CSTRING("POST"), false);
michael@0 648
michael@0 649 // The channel needs to have a loadgroup associated with it, so that we can
michael@0 650 // cancel the channel and any redirected channels it may create.
michael@0 651 nsCOMPtr<nsILoadGroup> loadGroup =
michael@0 652 do_CreateInstance(NS_LOADGROUP_CONTRACTID);
michael@0 653 if (!loadGroup)
michael@0 654 return;
michael@0 655 chan->SetLoadGroup(loadGroup);
michael@0 656
michael@0 657 // Construct a listener that merely discards any response. If successful at
michael@0 658 // opening the channel, then it is not necessary to hold a reference to the
michael@0 659 // channel. The networking subsystem will take care of that for us.
michael@0 660 nsPingListener *pingListener =
michael@0 661 new nsPingListener(info->requireSameHost, content, loadGroup);
michael@0 662 if (!pingListener)
michael@0 663 return;
michael@0 664
michael@0 665 nsCOMPtr<nsIStreamListener> listener(pingListener);
michael@0 666
michael@0 667 // Observe redirects as well:
michael@0 668 nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(listener);
michael@0 669 NS_ASSERTION(callbacks, "oops");
michael@0 670 loadGroup->SetNotificationCallbacks(callbacks);
michael@0 671
michael@0 672 chan->AsyncOpen(listener, nullptr);
michael@0 673
michael@0 674 // Even if AsyncOpen failed, we still count this as a successful ping. It's
michael@0 675 // possible that AsyncOpen may have failed after triggering some background
michael@0 676 // process that may have written something to the network.
michael@0 677 info->numPings++;
michael@0 678
michael@0 679 // Prevent ping requests from stalling and never being garbage collected...
michael@0 680 if (NS_FAILED(pingListener->StartTimeout())) {
michael@0 681 // If we failed to setup the timer, then we should just cancel the channel
michael@0 682 // because we won't be able to ensure that it goes away in a timely manner.
michael@0 683 chan->Cancel(NS_ERROR_ABORT);
michael@0 684 }
michael@0 685 }
michael@0 686
michael@0 687 // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
michael@0 688 static void
michael@0 689 DispatchPings(nsIContent *content, nsIURI *target, nsIURI *referrer)
michael@0 690 {
michael@0 691 SendPingInfo info;
michael@0 692
michael@0 693 if (!PingsEnabled(&info.maxPings, &info.requireSameHost))
michael@0 694 return;
michael@0 695 if (info.maxPings == 0)
michael@0 696 return;
michael@0 697
michael@0 698 info.numPings = 0;
michael@0 699 info.target = target;
michael@0 700 info.referrer = referrer;
michael@0 701
michael@0 702 ForEachPing(content, SendPing, &info);
michael@0 703 }
michael@0 704
michael@0 705 static nsDOMPerformanceNavigationType
michael@0 706 ConvertLoadTypeToNavigationType(uint32_t aLoadType)
michael@0 707 {
michael@0 708 // Not initialized, assume it's normal load.
michael@0 709 if (aLoadType == 0) {
michael@0 710 aLoadType = LOAD_NORMAL;
michael@0 711 }
michael@0 712
michael@0 713 nsDOMPerformanceNavigationType result = dom::PerformanceNavigation::TYPE_RESERVED;
michael@0 714 switch (aLoadType) {
michael@0 715 case LOAD_NORMAL:
michael@0 716 case LOAD_NORMAL_EXTERNAL:
michael@0 717 case LOAD_NORMAL_BYPASS_CACHE:
michael@0 718 case LOAD_NORMAL_BYPASS_PROXY:
michael@0 719 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
michael@0 720 case LOAD_NORMAL_REPLACE:
michael@0 721 case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
michael@0 722 case LOAD_LINK:
michael@0 723 case LOAD_STOP_CONTENT:
michael@0 724 case LOAD_REPLACE_BYPASS_CACHE:
michael@0 725 result = dom::PerformanceNavigation::TYPE_NAVIGATE;
michael@0 726 break;
michael@0 727 case LOAD_HISTORY:
michael@0 728 result = dom::PerformanceNavigation::TYPE_BACK_FORWARD;
michael@0 729 break;
michael@0 730 case LOAD_RELOAD_NORMAL:
michael@0 731 case LOAD_RELOAD_CHARSET_CHANGE:
michael@0 732 case LOAD_RELOAD_BYPASS_CACHE:
michael@0 733 case LOAD_RELOAD_BYPASS_PROXY:
michael@0 734 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
michael@0 735 case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
michael@0 736 result = dom::PerformanceNavigation::TYPE_RELOAD;
michael@0 737 break;
michael@0 738 case LOAD_STOP_CONTENT_AND_REPLACE:
michael@0 739 case LOAD_REFRESH:
michael@0 740 case LOAD_BYPASS_HISTORY:
michael@0 741 case LOAD_ERROR_PAGE:
michael@0 742 case LOAD_PUSHSTATE:
michael@0 743 result = dom::PerformanceNavigation::TYPE_RESERVED;
michael@0 744 break;
michael@0 745 default:
michael@0 746 // NS_NOTREACHED("Unexpected load type value");
michael@0 747 result = dom::PerformanceNavigation::TYPE_RESERVED;
michael@0 748 break;
michael@0 749 }
michael@0 750
michael@0 751 return result;
michael@0 752 }
michael@0 753
michael@0 754 static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
michael@0 755
michael@0 756 static void
michael@0 757 IncreasePrivateDocShellCount()
michael@0 758 {
michael@0 759 gNumberOfPrivateDocShells++;
michael@0 760 if (gNumberOfPrivateDocShells > 1 ||
michael@0 761 XRE_GetProcessType() != GeckoProcessType_Content) {
michael@0 762 return;
michael@0 763 }
michael@0 764
michael@0 765 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
michael@0 766 cc->SendPrivateDocShellsExist(true);
michael@0 767 }
michael@0 768
michael@0 769 static void
michael@0 770 DecreasePrivateDocShellCount()
michael@0 771 {
michael@0 772 MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
michael@0 773 gNumberOfPrivateDocShells--;
michael@0 774 if (!gNumberOfPrivateDocShells)
michael@0 775 {
michael@0 776 if (XRE_GetProcessType() == GeckoProcessType_Content) {
michael@0 777 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
michael@0 778 cc->SendPrivateDocShellsExist(false);
michael@0 779 return;
michael@0 780 }
michael@0 781
michael@0 782 nsCOMPtr<nsIObserverService> obsvc = mozilla::services::GetObserverService();
michael@0 783 if (obsvc) {
michael@0 784 obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
michael@0 785 }
michael@0 786 }
michael@0 787 }
michael@0 788
michael@0 789 //*****************************************************************************
michael@0 790 //*** nsDocShell: Object Management
michael@0 791 //*****************************************************************************
michael@0 792
michael@0 793 static uint64_t gDocshellIDCounter = 0;
michael@0 794
michael@0 795 // Note: operator new zeros our memory
michael@0 796 nsDocShell::nsDocShell():
michael@0 797 nsDocLoader(),
michael@0 798 mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
michael@0 799 mTreeOwner(nullptr),
michael@0 800 mChromeEventHandler(nullptr),
michael@0 801 mCharsetReloadState(eCharsetReloadInit),
michael@0 802 mChildOffset(0),
michael@0 803 mBusyFlags(BUSY_FLAGS_NONE),
michael@0 804 mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
michael@0 805 mLoadType(0),
michael@0 806 mMarginWidth(-1),
michael@0 807 mMarginHeight(-1),
michael@0 808 mItemType(typeContent),
michael@0 809 mPreviousTransIndex(-1),
michael@0 810 mLoadedTransIndex(-1),
michael@0 811 mSandboxFlags(0),
michael@0 812 mFullscreenAllowed(CHECK_ATTRIBUTES),
michael@0 813 mCreated(false),
michael@0 814 mAllowSubframes(true),
michael@0 815 mAllowPlugins(true),
michael@0 816 mAllowJavascript(true),
michael@0 817 mAllowMetaRedirects(true),
michael@0 818 mAllowImages(true),
michael@0 819 mAllowMedia(true),
michael@0 820 mAllowDNSPrefetch(true),
michael@0 821 mAllowWindowControl(true),
michael@0 822 mAllowContentRetargeting(true),
michael@0 823 mCreatingDocument(false),
michael@0 824 mUseErrorPages(false),
michael@0 825 mObserveErrorPages(true),
michael@0 826 mAllowAuth(true),
michael@0 827 mAllowKeywordFixup(false),
michael@0 828 mIsOffScreenBrowser(false),
michael@0 829 mIsActive(true),
michael@0 830 mIsAppTab(false),
michael@0 831 mUseGlobalHistory(false),
michael@0 832 mInPrivateBrowsing(false),
michael@0 833 mUseRemoteTabs(false),
michael@0 834 mDeviceSizeIsPageSize(false),
michael@0 835 mCanExecuteScripts(false),
michael@0 836 mFiredUnloadEvent(false),
michael@0 837 mEODForCurrentDocument(false),
michael@0 838 mURIResultedInDocument(false),
michael@0 839 mIsBeingDestroyed(false),
michael@0 840 mIsExecutingOnLoadHandler(false),
michael@0 841 mIsPrintingOrPP(false),
michael@0 842 mSavingOldViewer(false),
michael@0 843 #ifdef DEBUG
michael@0 844 mInEnsureScriptEnv(false),
michael@0 845 #endif
michael@0 846 mAffectPrivateSessionLifetime(true),
michael@0 847 mInvisible(false),
michael@0 848 mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
michael@0 849 mFrameType(eFrameTypeRegular),
michael@0 850 mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID),
michael@0 851 mParentCharsetSource(0)
michael@0 852 {
michael@0 853 mHistoryID = ++gDocshellIDCounter;
michael@0 854 if (gDocShellCount++ == 0) {
michael@0 855 NS_ASSERTION(sURIFixup == nullptr,
michael@0 856 "Huh, sURIFixup not null in first nsDocShell ctor!");
michael@0 857
michael@0 858 CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
michael@0 859 }
michael@0 860
michael@0 861 #ifdef PR_LOGGING
michael@0 862 #ifdef DEBUG
michael@0 863 if (! gDocShellLog)
michael@0 864 gDocShellLog = PR_NewLogModule("nsDocShell");
michael@0 865 #endif
michael@0 866 if (nullptr == gDocShellLeakLog)
michael@0 867 gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
michael@0 868 if (gDocShellLeakLog)
michael@0 869 PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this));
michael@0 870 #endif
michael@0 871
michael@0 872 #ifdef DEBUG
michael@0 873 // We're counting the number of |nsDocShells| to help find leaks
michael@0 874 ++gNumberOfDocShells;
michael@0 875 if (!PR_GetEnv("MOZ_QUIET")) {
michael@0 876 printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
michael@0 877 (void*) this,
michael@0 878 gNumberOfDocShells,
michael@0 879 getpid(),
michael@0 880 SafeCast<unsigned long long>(mHistoryID));
michael@0 881 }
michael@0 882 #endif
michael@0 883 }
michael@0 884
michael@0 885 nsDocShell::~nsDocShell()
michael@0 886 {
michael@0 887 Destroy();
michael@0 888
michael@0 889 nsCOMPtr<nsISHistoryInternal>
michael@0 890 shPrivate(do_QueryInterface(mSessionHistory));
michael@0 891 if (shPrivate) {
michael@0 892 shPrivate->SetRootDocShell(nullptr);
michael@0 893 }
michael@0 894
michael@0 895 if (--gDocShellCount == 0) {
michael@0 896 NS_IF_RELEASE(sURIFixup);
michael@0 897 }
michael@0 898
michael@0 899 #ifdef PR_LOGGING
michael@0 900 if (gDocShellLeakLog)
michael@0 901 PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this));
michael@0 902 #endif
michael@0 903
michael@0 904 #ifdef DEBUG
michael@0 905 // We're counting the number of |nsDocShells| to help find leaks
michael@0 906 --gNumberOfDocShells;
michael@0 907 if (!PR_GetEnv("MOZ_QUIET")) {
michael@0 908 printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
michael@0 909 (void*) this,
michael@0 910 gNumberOfDocShells,
michael@0 911 getpid(),
michael@0 912 SafeCast<unsigned long long>(mHistoryID));
michael@0 913 }
michael@0 914 #endif
michael@0 915 }
michael@0 916
michael@0 917 nsresult
michael@0 918 nsDocShell::Init()
michael@0 919 {
michael@0 920 nsresult rv = nsDocLoader::Init();
michael@0 921 NS_ENSURE_SUCCESS(rv, rv);
michael@0 922
michael@0 923 NS_ASSERTION(mLoadGroup, "Something went wrong!");
michael@0 924
michael@0 925 mContentListener = new nsDSURIContentListener(this);
michael@0 926 NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
michael@0 927
michael@0 928 rv = mContentListener->Init();
michael@0 929 NS_ENSURE_SUCCESS(rv, rv);
michael@0 930
michael@0 931 // We want to hold a strong ref to the loadgroup, so it better hold a weak
michael@0 932 // ref to us... use an InterfaceRequestorProxy to do this.
michael@0 933 nsCOMPtr<nsIInterfaceRequestor> proxy =
michael@0 934 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>
michael@0 935 (this));
michael@0 936 NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
michael@0 937 mLoadGroup->SetNotificationCallbacks(proxy);
michael@0 938
michael@0 939 rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
michael@0 940 NS_ENSURE_SUCCESS(rv, rv);
michael@0 941
michael@0 942 // Add as |this| a progress listener to itself. A little weird, but
michael@0 943 // simpler than reproducing all the listener-notification logic in
michael@0 944 // overrides of the various methods via which nsDocLoader can be
michael@0 945 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
michael@0 946 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
michael@0 947 nsIWebProgress::NOTIFY_STATE_NETWORK);
michael@0 948
michael@0 949 }
michael@0 950
michael@0 951 void
michael@0 952 nsDocShell::DestroyChildren()
michael@0 953 {
michael@0 954 nsCOMPtr<nsIDocShellTreeItem> shell;
michael@0 955 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 956 while (iter.HasMore()) {
michael@0 957 shell = do_QueryObject(iter.GetNext());
michael@0 958 NS_ASSERTION(shell, "docshell has null child");
michael@0 959
michael@0 960 if (shell) {
michael@0 961 shell->SetTreeOwner(nullptr);
michael@0 962 }
michael@0 963 }
michael@0 964
michael@0 965 nsDocLoader::DestroyChildren();
michael@0 966 }
michael@0 967
michael@0 968 //*****************************************************************************
michael@0 969 // nsDocShell::nsISupports
michael@0 970 //*****************************************************************************
michael@0 971
michael@0 972 NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
michael@0 973 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
michael@0 974
michael@0 975 NS_INTERFACE_MAP_BEGIN(nsDocShell)
michael@0 976 NS_INTERFACE_MAP_ENTRY(nsIDocShell)
michael@0 977 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
michael@0 978 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
michael@0 979 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
michael@0 980 NS_INTERFACE_MAP_ENTRY(nsIScrollable)
michael@0 981 NS_INTERFACE_MAP_ENTRY(nsITextScroll)
michael@0 982 NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
michael@0 983 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
michael@0 984 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
michael@0 985 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
michael@0 986 NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
michael@0 987 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
michael@0 988 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
michael@0 989 NS_INTERFACE_MAP_ENTRY(nsILoadContext)
michael@0 990 NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
michael@0 991 NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
michael@0 992 NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
michael@0 993 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
michael@0 994 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
michael@0 995
michael@0 996 ///*****************************************************************************
michael@0 997 // nsDocShell::nsIInterfaceRequestor
michael@0 998 //*****************************************************************************
michael@0 999 NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
michael@0 1000 {
michael@0 1001 NS_PRECONDITION(aSink, "null out param");
michael@0 1002
michael@0 1003 *aSink = nullptr;
michael@0 1004
michael@0 1005 if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
michael@0 1006 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
michael@0 1007 *aSink = mCommandManager;
michael@0 1008 }
michael@0 1009 else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
michael@0 1010 *aSink = mContentListener;
michael@0 1011 }
michael@0 1012 else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
michael@0 1013 aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||
michael@0 1014 aIID.Equals(NS_GET_IID(nsIDOMWindow)) ||
michael@0 1015 aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) &&
michael@0 1016 NS_SUCCEEDED(EnsureScriptEnvironment())) {
michael@0 1017 return mScriptGlobal->QueryInterface(aIID, aSink);
michael@0 1018 }
michael@0 1019 else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
michael@0 1020 NS_SUCCEEDED(EnsureContentViewer())) {
michael@0 1021 mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
michael@0 1022 return *aSink ? NS_OK : NS_NOINTERFACE;
michael@0 1023 }
michael@0 1024 else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
michael@0 1025 NS_SUCCEEDED(EnsureContentViewer())) {
michael@0 1026 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
michael@0 1027 doc.forget(aSink);
michael@0 1028 return *aSink ? NS_OK : NS_NOINTERFACE;
michael@0 1029 }
michael@0 1030 else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
michael@0 1031 *aSink = nullptr;
michael@0 1032
michael@0 1033 // Return application cache associated with this docshell, if any
michael@0 1034
michael@0 1035 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 1036 GetContentViewer(getter_AddRefs(contentViewer));
michael@0 1037 if (!contentViewer)
michael@0 1038 return NS_ERROR_NO_INTERFACE;
michael@0 1039
michael@0 1040 nsCOMPtr<nsIDOMDocument> domDoc;
michael@0 1041 contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
michael@0 1042 NS_ASSERTION(domDoc, "Should have a document.");
michael@0 1043 if (!domDoc)
michael@0 1044 return NS_ERROR_NO_INTERFACE;
michael@0 1045
michael@0 1046 #if defined(PR_LOGGING) && defined(DEBUG)
michael@0 1047 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 1048 ("nsDocShell[%p]: returning app cache container %p",
michael@0 1049 this, domDoc.get()));
michael@0 1050 #endif
michael@0 1051 return domDoc->QueryInterface(aIID, aSink);
michael@0 1052 }
michael@0 1053 else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
michael@0 1054 NS_SUCCEEDED(EnsureScriptEnvironment())) {
michael@0 1055 nsresult rv;
michael@0 1056 nsCOMPtr<nsIWindowWatcher> wwatch =
michael@0 1057 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
michael@0 1058 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1059
michael@0 1060 // Get the an auth prompter for our window so that the parenting
michael@0 1061 // of the dialogs works as it should when using tabs.
michael@0 1062 nsIPrompt *prompt;
michael@0 1063 rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt);
michael@0 1064 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1065
michael@0 1066 *aSink = prompt;
michael@0 1067 return NS_OK;
michael@0 1068 }
michael@0 1069 else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
michael@0 1070 aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
michael@0 1071 return NS_SUCCEEDED(
michael@0 1072 GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
michael@0 1073 NS_OK : NS_NOINTERFACE;
michael@0 1074 }
michael@0 1075 else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
michael@0 1076 nsCOMPtr<nsISHistory> shistory;
michael@0 1077 nsresult
michael@0 1078 rv =
michael@0 1079 GetSessionHistory(getter_AddRefs(shistory));
michael@0 1080 if (NS_SUCCEEDED(rv) && shistory) {
michael@0 1081 *aSink = shistory;
michael@0 1082 NS_ADDREF((nsISupports *) * aSink);
michael@0 1083 return NS_OK;
michael@0 1084 }
michael@0 1085 return NS_NOINTERFACE;
michael@0 1086 }
michael@0 1087 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
michael@0 1088 nsresult rv = EnsureFind();
michael@0 1089 if (NS_FAILED(rv)) return rv;
michael@0 1090
michael@0 1091 *aSink = mFind;
michael@0 1092 NS_ADDREF((nsISupports*)*aSink);
michael@0 1093 return NS_OK;
michael@0 1094 }
michael@0 1095 else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) {
michael@0 1096 nsCOMPtr<nsIEditingSession> editingSession;
michael@0 1097 mEditorData->GetEditingSession(getter_AddRefs(editingSession));
michael@0 1098 if (editingSession)
michael@0 1099 {
michael@0 1100 *aSink = editingSession;
michael@0 1101 NS_ADDREF((nsISupports *)*aSink);
michael@0 1102 return NS_OK;
michael@0 1103 }
michael@0 1104
michael@0 1105 return NS_NOINTERFACE;
michael@0 1106 }
michael@0 1107 else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList))
michael@0 1108 && NS_SUCCEEDED(EnsureTransferableHookData())) {
michael@0 1109 *aSink = mTransferableHookData;
michael@0 1110 NS_ADDREF((nsISupports *)*aSink);
michael@0 1111 return NS_OK;
michael@0 1112 }
michael@0 1113 else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
michael@0 1114 nsIPresShell* shell = GetPresShell();
michael@0 1115 if (shell)
michael@0 1116 return shell->QueryInterface(aIID,aSink);
michael@0 1117 }
michael@0 1118 else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
michael@0 1119 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
michael@0 1120 nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
michael@0 1121 if (NS_SUCCEEDED(rv) && treeOwner)
michael@0 1122 return treeOwner->QueryInterface(aIID, aSink);
michael@0 1123 }
michael@0 1124 else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
michael@0 1125 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
michael@0 1126 nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
michael@0 1127 if (NS_SUCCEEDED(rv) && treeOwner) {
michael@0 1128 nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(treeOwner);
michael@0 1129 if (ir)
michael@0 1130 return ir->GetInterface(aIID, aSink);
michael@0 1131 }
michael@0 1132 }
michael@0 1133 else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
michael@0 1134 nsCOMPtr<nsITabChild> tabChild =
michael@0 1135 do_GetInterface(static_cast<nsIDocShell*>(this));
michael@0 1136 nsCOMPtr<nsIContentFrameMessageManager> mm;
michael@0 1137 if (tabChild) {
michael@0 1138 tabChild->
michael@0 1139 GetMessageManager(getter_AddRefs(mm));
michael@0 1140 } else {
michael@0 1141 nsCOMPtr<nsPIDOMWindow> win =
michael@0 1142 do_GetInterface(static_cast<nsIDocShell*>(this));
michael@0 1143 if (win) {
michael@0 1144 mm = do_QueryInterface(win->GetParentTarget());
michael@0 1145 }
michael@0 1146 }
michael@0 1147 *aSink = mm.get();
michael@0 1148 }
michael@0 1149 else {
michael@0 1150 return nsDocLoader::GetInterface(aIID, aSink);
michael@0 1151 }
michael@0 1152
michael@0 1153 NS_IF_ADDREF(((nsISupports *) * aSink));
michael@0 1154 return *aSink ? NS_OK : NS_NOINTERFACE;
michael@0 1155 }
michael@0 1156
michael@0 1157 uint32_t
michael@0 1158 nsDocShell::
michael@0 1159 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType)
michael@0 1160 {
michael@0 1161 uint32_t loadType = LOAD_NORMAL;
michael@0 1162
michael@0 1163 switch (aDocShellLoadType) {
michael@0 1164 case nsIDocShellLoadInfo::loadNormal:
michael@0 1165 loadType = LOAD_NORMAL;
michael@0 1166 break;
michael@0 1167 case nsIDocShellLoadInfo::loadNormalReplace:
michael@0 1168 loadType = LOAD_NORMAL_REPLACE;
michael@0 1169 break;
michael@0 1170 case nsIDocShellLoadInfo::loadNormalExternal:
michael@0 1171 loadType = LOAD_NORMAL_EXTERNAL;
michael@0 1172 break;
michael@0 1173 case nsIDocShellLoadInfo::loadHistory:
michael@0 1174 loadType = LOAD_HISTORY;
michael@0 1175 break;
michael@0 1176 case nsIDocShellLoadInfo::loadNormalBypassCache:
michael@0 1177 loadType = LOAD_NORMAL_BYPASS_CACHE;
michael@0 1178 break;
michael@0 1179 case nsIDocShellLoadInfo::loadNormalBypassProxy:
michael@0 1180 loadType = LOAD_NORMAL_BYPASS_PROXY;
michael@0 1181 break;
michael@0 1182 case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
michael@0 1183 loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
michael@0 1184 break;
michael@0 1185 case nsIDocShellLoadInfo::loadNormalAllowMixedContent:
michael@0 1186 loadType = LOAD_NORMAL_ALLOW_MIXED_CONTENT;
michael@0 1187 break;
michael@0 1188 case nsIDocShellLoadInfo::loadReloadNormal:
michael@0 1189 loadType = LOAD_RELOAD_NORMAL;
michael@0 1190 break;
michael@0 1191 case nsIDocShellLoadInfo::loadReloadCharsetChange:
michael@0 1192 loadType = LOAD_RELOAD_CHARSET_CHANGE;
michael@0 1193 break;
michael@0 1194 case nsIDocShellLoadInfo::loadReloadBypassCache:
michael@0 1195 loadType = LOAD_RELOAD_BYPASS_CACHE;
michael@0 1196 break;
michael@0 1197 case nsIDocShellLoadInfo::loadReloadBypassProxy:
michael@0 1198 loadType = LOAD_RELOAD_BYPASS_PROXY;
michael@0 1199 break;
michael@0 1200 case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
michael@0 1201 loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
michael@0 1202 break;
michael@0 1203 case nsIDocShellLoadInfo::loadLink:
michael@0 1204 loadType = LOAD_LINK;
michael@0 1205 break;
michael@0 1206 case nsIDocShellLoadInfo::loadRefresh:
michael@0 1207 loadType = LOAD_REFRESH;
michael@0 1208 break;
michael@0 1209 case nsIDocShellLoadInfo::loadBypassHistory:
michael@0 1210 loadType = LOAD_BYPASS_HISTORY;
michael@0 1211 break;
michael@0 1212 case nsIDocShellLoadInfo::loadStopContent:
michael@0 1213 loadType = LOAD_STOP_CONTENT;
michael@0 1214 break;
michael@0 1215 case nsIDocShellLoadInfo::loadStopContentAndReplace:
michael@0 1216 loadType = LOAD_STOP_CONTENT_AND_REPLACE;
michael@0 1217 break;
michael@0 1218 case nsIDocShellLoadInfo::loadPushState:
michael@0 1219 loadType = LOAD_PUSHSTATE;
michael@0 1220 break;
michael@0 1221 case nsIDocShellLoadInfo::loadReplaceBypassCache:
michael@0 1222 loadType = LOAD_REPLACE_BYPASS_CACHE;
michael@0 1223 break;
michael@0 1224 case nsIDocShellLoadInfo::loadReloadMixedContent:
michael@0 1225 loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
michael@0 1226 break;
michael@0 1227 default:
michael@0 1228 NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
michael@0 1229 }
michael@0 1230
michael@0 1231 return loadType;
michael@0 1232 }
michael@0 1233
michael@0 1234
michael@0 1235 nsDocShellInfoLoadType
michael@0 1236 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType)
michael@0 1237 {
michael@0 1238 nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
michael@0 1239 switch (aLoadType) {
michael@0 1240 case LOAD_NORMAL:
michael@0 1241 docShellLoadType = nsIDocShellLoadInfo::loadNormal;
michael@0 1242 break;
michael@0 1243 case LOAD_NORMAL_REPLACE:
michael@0 1244 docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
michael@0 1245 break;
michael@0 1246 case LOAD_NORMAL_EXTERNAL:
michael@0 1247 docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
michael@0 1248 break;
michael@0 1249 case LOAD_NORMAL_BYPASS_CACHE:
michael@0 1250 docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
michael@0 1251 break;
michael@0 1252 case LOAD_NORMAL_BYPASS_PROXY:
michael@0 1253 docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
michael@0 1254 break;
michael@0 1255 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
michael@0 1256 docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
michael@0 1257 break;
michael@0 1258 case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
michael@0 1259 docShellLoadType = nsIDocShellLoadInfo::loadNormalAllowMixedContent;
michael@0 1260 break;
michael@0 1261 case LOAD_HISTORY:
michael@0 1262 docShellLoadType = nsIDocShellLoadInfo::loadHistory;
michael@0 1263 break;
michael@0 1264 case LOAD_RELOAD_NORMAL:
michael@0 1265 docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
michael@0 1266 break;
michael@0 1267 case LOAD_RELOAD_CHARSET_CHANGE:
michael@0 1268 docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
michael@0 1269 break;
michael@0 1270 case LOAD_RELOAD_BYPASS_CACHE:
michael@0 1271 docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
michael@0 1272 break;
michael@0 1273 case LOAD_RELOAD_BYPASS_PROXY:
michael@0 1274 docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
michael@0 1275 break;
michael@0 1276 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
michael@0 1277 docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
michael@0 1278 break;
michael@0 1279 case LOAD_LINK:
michael@0 1280 docShellLoadType = nsIDocShellLoadInfo::loadLink;
michael@0 1281 break;
michael@0 1282 case LOAD_REFRESH:
michael@0 1283 docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
michael@0 1284 break;
michael@0 1285 case LOAD_BYPASS_HISTORY:
michael@0 1286 case LOAD_ERROR_PAGE:
michael@0 1287 docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
michael@0 1288 break;
michael@0 1289 case LOAD_STOP_CONTENT:
michael@0 1290 docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
michael@0 1291 break;
michael@0 1292 case LOAD_STOP_CONTENT_AND_REPLACE:
michael@0 1293 docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
michael@0 1294 break;
michael@0 1295 case LOAD_PUSHSTATE:
michael@0 1296 docShellLoadType = nsIDocShellLoadInfo::loadPushState;
michael@0 1297 break;
michael@0 1298 case LOAD_REPLACE_BYPASS_CACHE:
michael@0 1299 docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
michael@0 1300 break;
michael@0 1301 case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
michael@0 1302 docShellLoadType = nsIDocShellLoadInfo::loadReloadMixedContent;
michael@0 1303 break;
michael@0 1304 default:
michael@0 1305 NS_NOTREACHED("Unexpected load type value");
michael@0 1306 }
michael@0 1307
michael@0 1308 return docShellLoadType;
michael@0 1309 }
michael@0 1310
michael@0 1311 //*****************************************************************************
michael@0 1312 // nsDocShell::nsIDocShell
michael@0 1313 //*****************************************************************************
michael@0 1314 NS_IMETHODIMP
michael@0 1315 nsDocShell::LoadURI(nsIURI * aURI,
michael@0 1316 nsIDocShellLoadInfo * aLoadInfo,
michael@0 1317 uint32_t aLoadFlags,
michael@0 1318 bool aFirstParty)
michael@0 1319 {
michael@0 1320 NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
michael@0 1321 "Unexpected flags");
michael@0 1322 NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
michael@0 1323
michael@0 1324 // Note: we allow loads to get through here even if mFiredUnloadEvent is
michael@0 1325 // true; that case will get handled in LoadInternal or LoadHistoryEntry.
michael@0 1326 if (IsPrintingOrPP()) {
michael@0 1327 return NS_OK; // JS may not handle returning of an error code
michael@0 1328 }
michael@0 1329 nsCOMPtr<nsIURI> referrer;
michael@0 1330 nsCOMPtr<nsIInputStream> postStream;
michael@0 1331 nsCOMPtr<nsIInputStream> headersStream;
michael@0 1332 nsCOMPtr<nsISupports> owner;
michael@0 1333 bool inheritOwner = false;
michael@0 1334 bool ownerIsExplicit = false;
michael@0 1335 bool sendReferrer = true;
michael@0 1336 bool isSrcdoc = false;
michael@0 1337 nsCOMPtr<nsISHEntry> shEntry;
michael@0 1338 nsXPIDLString target;
michael@0 1339 nsAutoString srcdoc;
michael@0 1340 nsCOMPtr<nsIDocShell> sourceDocShell;
michael@0 1341 nsCOMPtr<nsIURI> baseURI;
michael@0 1342
michael@0 1343 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
michael@0 1344
michael@0 1345 NS_ENSURE_ARG(aURI);
michael@0 1346
michael@0 1347 if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
michael@0 1348 mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
michael@0 1349 StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
michael@0 1350 }
michael@0 1351
michael@0 1352 // Extract the info from the DocShellLoadInfo struct...
michael@0 1353 if (aLoadInfo) {
michael@0 1354 aLoadInfo->GetReferrer(getter_AddRefs(referrer));
michael@0 1355
michael@0 1356 nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
michael@0 1357 aLoadInfo->GetLoadType(&lt);
michael@0 1358 // Get the appropriate loadType from nsIDocShellLoadInfo type
michael@0 1359 loadType = ConvertDocShellLoadInfoToLoadType(lt);
michael@0 1360
michael@0 1361 aLoadInfo->GetOwner(getter_AddRefs(owner));
michael@0 1362 aLoadInfo->GetInheritOwner(&inheritOwner);
michael@0 1363 aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
michael@0 1364 aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
michael@0 1365 aLoadInfo->GetTarget(getter_Copies(target));
michael@0 1366 aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
michael@0 1367 aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
michael@0 1368 aLoadInfo->GetSendReferrer(&sendReferrer);
michael@0 1369 aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
michael@0 1370 aLoadInfo->GetSrcdocData(srcdoc);
michael@0 1371 aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
michael@0 1372 aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
michael@0 1373 }
michael@0 1374
michael@0 1375 #if defined(PR_LOGGING) && defined(DEBUG)
michael@0 1376 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
michael@0 1377 nsAutoCString uristr;
michael@0 1378 aURI->GetAsciiSpec(uristr);
michael@0 1379 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 1380 ("nsDocShell[%p]: loading %s with flags 0x%08x",
michael@0 1381 this, uristr.get(), aLoadFlags));
michael@0 1382 }
michael@0 1383 #endif
michael@0 1384
michael@0 1385 if (!shEntry &&
michael@0 1386 !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
michael@0 1387 // First verify if this is a subframe.
michael@0 1388 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
michael@0 1389 GetSameTypeParent(getter_AddRefs(parentAsItem));
michael@0 1390 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
michael@0 1391 uint32_t parentLoadType;
michael@0 1392
michael@0 1393 if (parentDS && parentDS != static_cast<nsIDocShell *>(this)) {
michael@0 1394 /* OK. It is a subframe. Checkout the
michael@0 1395 * parent's loadtype. If the parent was loaded thro' a history
michael@0 1396 * mechanism, then get the SH entry for the child from the parent.
michael@0 1397 * This is done to restore frameset navigation while going back/forward.
michael@0 1398 * If the parent was loaded through any other loadType, set the
michael@0 1399 * child's loadType too accordingly, so that session history does not
michael@0 1400 * get confused.
michael@0 1401 */
michael@0 1402
michael@0 1403 // Get the parent's load type
michael@0 1404 parentDS->GetLoadType(&parentLoadType);
michael@0 1405
michael@0 1406 // Get the ShEntry for the child from the parent
michael@0 1407 nsCOMPtr<nsISHEntry> currentSH;
michael@0 1408 bool oshe = false;
michael@0 1409 parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
michael@0 1410 bool dynamicallyAddedChild = mDynamicallyCreated;
michael@0 1411 if (!dynamicallyAddedChild && !oshe && currentSH) {
michael@0 1412 currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
michael@0 1413 }
michael@0 1414 if (!dynamicallyAddedChild) {
michael@0 1415 // Only use the old SHEntry, if we're sure enough that
michael@0 1416 // it wasn't originally for some other frame.
michael@0 1417 parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
michael@0 1418 }
michael@0 1419
michael@0 1420 // Make some decisions on the child frame's loadType based on the
michael@0 1421 // parent's loadType.
michael@0 1422 if (mCurrentURI == nullptr) {
michael@0 1423 // This is a newly created frame. Check for exception cases first.
michael@0 1424 // By default the subframe will inherit the parent's loadType.
michael@0 1425 if (shEntry && (parentLoadType == LOAD_NORMAL ||
michael@0 1426 parentLoadType == LOAD_LINK ||
michael@0 1427 parentLoadType == LOAD_NORMAL_EXTERNAL)) {
michael@0 1428 // The parent was loaded normally. In this case, this *brand new* child really shouldn't
michael@0 1429 // have a SHEntry. If it does, it could be because the parent is replacing an
michael@0 1430 // existing frame with a new frame, in the onLoadHandler. We don't want this
michael@0 1431 // url to get into session history. Clear off shEntry, and set load type to
michael@0 1432 // LOAD_BYPASS_HISTORY.
michael@0 1433 bool inOnLoadHandler=false;
michael@0 1434 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
michael@0 1435 if (inOnLoadHandler) {
michael@0 1436 loadType = LOAD_NORMAL_REPLACE;
michael@0 1437 shEntry = nullptr;
michael@0 1438 }
michael@0 1439 } else if (parentLoadType == LOAD_REFRESH) {
michael@0 1440 // Clear shEntry. For refresh loads, we have to load
michael@0 1441 // what comes thro' the pipe, not what's in history.
michael@0 1442 shEntry = nullptr;
michael@0 1443 } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
michael@0 1444 (shEntry &&
michael@0 1445 ((parentLoadType & LOAD_CMD_HISTORY) ||
michael@0 1446 (parentLoadType == LOAD_RELOAD_NORMAL) ||
michael@0 1447 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
michael@0 1448 // If the parent url, bypassed history or was loaded from
michael@0 1449 // history, pass on the parent's loadType to the new child
michael@0 1450 // frame too, so that the child frame will also
michael@0 1451 // avoid getting into history.
michael@0 1452 loadType = parentLoadType;
michael@0 1453 } else if (parentLoadType == LOAD_ERROR_PAGE) {
michael@0 1454 // If the parent document is an error page, we don't
michael@0 1455 // want to update global/session history. However,
michael@0 1456 // this child frame is not an error page.
michael@0 1457 loadType = LOAD_BYPASS_HISTORY;
michael@0 1458 } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
michael@0 1459 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
michael@0 1460 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
michael@0 1461 // the new frame should inherit the parent's load type so that it also
michael@0 1462 // bypasses the cache and/or proxy
michael@0 1463 loadType = parentLoadType;
michael@0 1464 }
michael@0 1465 } else {
michael@0 1466 // This is a pre-existing subframe. If the load was not originally initiated
michael@0 1467 // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
michael@0 1468 // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading
michael@0 1469 // a new page in this child. Check parent's and self's busy flag and if it is set,
michael@0 1470 // we don't want this onLoadHandler load to get in to session history.
michael@0 1471 uint32_t parentBusy = BUSY_FLAGS_NONE;
michael@0 1472 uint32_t selfBusy = BUSY_FLAGS_NONE;
michael@0 1473 parentDS->GetBusyFlags(&parentBusy);
michael@0 1474 GetBusyFlags(&selfBusy);
michael@0 1475 if (parentBusy & BUSY_FLAGS_BUSY ||
michael@0 1476 selfBusy & BUSY_FLAGS_BUSY) {
michael@0 1477 loadType = LOAD_NORMAL_REPLACE;
michael@0 1478 shEntry = nullptr;
michael@0 1479 }
michael@0 1480 }
michael@0 1481 } //parentDS
michael@0 1482 else {
michael@0 1483 // This is the root docshell. If we got here while
michael@0 1484 // executing an onLoad Handler,this load will not go
michael@0 1485 // into session history.
michael@0 1486 bool inOnLoadHandler=false;
michael@0 1487 GetIsExecutingOnLoadHandler(&inOnLoadHandler);
michael@0 1488 if (inOnLoadHandler) {
michael@0 1489 loadType = LOAD_NORMAL_REPLACE;
michael@0 1490 }
michael@0 1491 }
michael@0 1492 } // !shEntry
michael@0 1493
michael@0 1494 if (shEntry) {
michael@0 1495 #ifdef DEBUG
michael@0 1496 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 1497 ("nsDocShell[%p]: loading from session history", this));
michael@0 1498 #endif
michael@0 1499
michael@0 1500 return LoadHistoryEntry(shEntry, loadType);
michael@0 1501 }
michael@0 1502
michael@0 1503 // On history navigation via Back/Forward buttons, don't execute
michael@0 1504 // automatic JavaScript redirection such as |location.href = ...| or
michael@0 1505 // |window.open()|
michael@0 1506 //
michael@0 1507 // LOAD_NORMAL: window.open(...) etc.
michael@0 1508 // LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
michael@0 1509 if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
michael@0 1510 ShouldBlockLoadingForBackButton()) {
michael@0 1511 return NS_OK;
michael@0 1512 }
michael@0 1513
michael@0 1514 // Perform the load...
michael@0 1515
michael@0 1516 // We need an owner (a referring principal).
michael@0 1517 //
michael@0 1518 // If ownerIsExplicit is not set there are 4 possibilities:
michael@0 1519 // (1) If the system principal or an expanded principal was passed
michael@0 1520 // in and we're a typeContent docshell, inherit the principal
michael@0 1521 // from the current document instead.
michael@0 1522 // (2) In all other cases when the principal passed in is not null,
michael@0 1523 // use that principal.
michael@0 1524 // (3) If the caller has allowed inheriting from the current document,
michael@0 1525 // or if we're being called from system code (eg chrome JS or pure
michael@0 1526 // C++) then inheritOwner should be true and InternalLoad will get
michael@0 1527 // an owner from the current document. If none of these things are
michael@0 1528 // true, then
michael@0 1529 // (4) we pass a null owner into the channel, and an owner will be
michael@0 1530 // created later from the channel's internal data.
michael@0 1531 //
michael@0 1532 // If ownerIsExplicit *is* set, there are 4 possibilities
michael@0 1533 // (1) If the system principal or an expanded principal was passed in
michael@0 1534 // and we're a typeContent docshell, return an error.
michael@0 1535 // (2) In all other cases when the principal passed in is not null,
michael@0 1536 // use that principal.
michael@0 1537 // (3) If the caller has allowed inheriting from the current document,
michael@0 1538 // then inheritOwner should be true and InternalLoad will get an owner
michael@0 1539 // from the current document. If none of these things are true, then
michael@0 1540 // (4) we pass a null owner into the channel, and an owner will be
michael@0 1541 // created later from the channel's internal data.
michael@0 1542 //
michael@0 1543 // NOTE: This all only works because the only thing the owner is used
michael@0 1544 // for in InternalLoad is data:, javascript:, and about:blank
michael@0 1545 // URIs. For other URIs this would all be dead wrong!
michael@0 1546
michael@0 1547 if (owner && mItemType != typeChrome) {
michael@0 1548 nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
michael@0 1549 if (nsContentUtils::IsSystemOrExpandedPrincipal(ownerPrincipal)) {
michael@0 1550 if (ownerIsExplicit) {
michael@0 1551 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 1552 }
michael@0 1553 owner = nullptr;
michael@0 1554 inheritOwner = true;
michael@0 1555 }
michael@0 1556 }
michael@0 1557 if (!owner && !inheritOwner && !ownerIsExplicit) {
michael@0 1558 // See if there's system or chrome JS code running
michael@0 1559 inheritOwner = nsContentUtils::IsSystemPrincipal(
michael@0 1560 nsContentUtils::GetSubjectPrincipal());
michael@0 1561 }
michael@0 1562
michael@0 1563 if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
michael@0 1564 inheritOwner = false;
michael@0 1565 owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
michael@0 1566 }
michael@0 1567
michael@0 1568 uint32_t flags = 0;
michael@0 1569
michael@0 1570 if (inheritOwner)
michael@0 1571 flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
michael@0 1572
michael@0 1573 if (!sendReferrer)
michael@0 1574 flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
michael@0 1575
michael@0 1576 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
michael@0 1577 flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
michael@0 1578
michael@0 1579 if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS)
michael@0 1580 flags |= INTERNAL_LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
michael@0 1581
michael@0 1582 if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
michael@0 1583 flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
michael@0 1584
michael@0 1585 if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
michael@0 1586 flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
michael@0 1587
michael@0 1588 if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES)
michael@0 1589 flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
michael@0 1590
michael@0 1591 if (isSrcdoc)
michael@0 1592 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
michael@0 1593
michael@0 1594 return InternalLoad(aURI,
michael@0 1595 referrer,
michael@0 1596 owner,
michael@0 1597 flags,
michael@0 1598 target.get(),
michael@0 1599 nullptr, // No type hint
michael@0 1600 NullString(), // No forced download
michael@0 1601 postStream,
michael@0 1602 headersStream,
michael@0 1603 loadType,
michael@0 1604 nullptr, // No SHEntry
michael@0 1605 aFirstParty,
michael@0 1606 srcdoc,
michael@0 1607 sourceDocShell,
michael@0 1608 baseURI,
michael@0 1609 nullptr, // No nsIDocShell
michael@0 1610 nullptr); // No nsIRequest
michael@0 1611 }
michael@0 1612
michael@0 1613 NS_IMETHODIMP
michael@0 1614 nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
michael@0 1615 const nsACString &aContentType,
michael@0 1616 const nsACString &aContentCharset,
michael@0 1617 nsIDocShellLoadInfo * aLoadInfo)
michael@0 1618 {
michael@0 1619 NS_ENSURE_ARG(aStream);
michael@0 1620
michael@0 1621 mAllowKeywordFixup = false;
michael@0 1622
michael@0 1623 // if the caller doesn't pass in a URI we need to create a dummy URI. necko
michael@0 1624 // currently requires a URI in various places during the load. Some consumers
michael@0 1625 // do as well.
michael@0 1626 nsCOMPtr<nsIURI> uri = aURI;
michael@0 1627 if (!uri) {
michael@0 1628 // HACK ALERT
michael@0 1629 nsresult rv = NS_OK;
michael@0 1630 uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
michael@0 1631 if (NS_FAILED(rv))
michael@0 1632 return rv;
michael@0 1633 // Make sure that the URI spec "looks" like a protocol and path...
michael@0 1634 // For now, just use a bogus protocol called "internal"
michael@0 1635 rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
michael@0 1636 if (NS_FAILED(rv))
michael@0 1637 return rv;
michael@0 1638 }
michael@0 1639
michael@0 1640 uint32_t loadType = LOAD_NORMAL;
michael@0 1641 if (aLoadInfo) {
michael@0 1642 nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
michael@0 1643 (void) aLoadInfo->GetLoadType(&lt);
michael@0 1644 // Get the appropriate LoadType from nsIDocShellLoadInfo type
michael@0 1645 loadType = ConvertDocShellLoadInfoToLoadType(lt);
michael@0 1646 }
michael@0 1647
michael@0 1648 NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
michael@0 1649
michael@0 1650 mLoadType = loadType;
michael@0 1651
michael@0 1652 // build up a channel for this stream.
michael@0 1653 nsCOMPtr<nsIChannel> channel;
michael@0 1654 NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
michael@0 1655 (getter_AddRefs(channel), uri, aStream,
michael@0 1656 aContentType, aContentCharset),
michael@0 1657 NS_ERROR_FAILURE);
michael@0 1658
michael@0 1659 nsCOMPtr<nsIURILoader>
michael@0 1660 uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
michael@0 1661 NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
michael@0 1662
michael@0 1663 NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
michael@0 1664 NS_ERROR_FAILURE);
michael@0 1665 return NS_OK;
michael@0 1666 }
michael@0 1667
michael@0 1668 NS_IMETHODIMP
michael@0 1669 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo)
michael@0 1670 {
michael@0 1671 nsDocShellLoadInfo *loadInfo = new nsDocShellLoadInfo();
michael@0 1672 NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
michael@0 1673 nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
michael@0 1674
michael@0 1675 *aLoadInfo = localRef;
michael@0 1676 NS_ADDREF(*aLoadInfo);
michael@0 1677 return NS_OK;
michael@0 1678 }
michael@0 1679
michael@0 1680
michael@0 1681 /*
michael@0 1682 * Reset state to a new content model within the current document and the document
michael@0 1683 * viewer. Called by the document before initiating an out of band document.write().
michael@0 1684 */
michael@0 1685 NS_IMETHODIMP
michael@0 1686 nsDocShell::PrepareForNewContentModel()
michael@0 1687 {
michael@0 1688 mEODForCurrentDocument = false;
michael@0 1689 return NS_OK;
michael@0 1690 }
michael@0 1691
michael@0 1692
michael@0 1693 NS_IMETHODIMP
michael@0 1694 nsDocShell::FirePageHideNotification(bool aIsUnload)
michael@0 1695 {
michael@0 1696 if (mContentViewer && !mFiredUnloadEvent) {
michael@0 1697 // Keep an explicit reference since calling PageHide could release
michael@0 1698 // mContentViewer
michael@0 1699 nsCOMPtr<nsIContentViewer> kungFuDeathGrip(mContentViewer);
michael@0 1700 mFiredUnloadEvent = true;
michael@0 1701
michael@0 1702 if (mTiming) {
michael@0 1703 mTiming->NotifyUnloadEventStart();
michael@0 1704 }
michael@0 1705
michael@0 1706 mContentViewer->PageHide(aIsUnload);
michael@0 1707
michael@0 1708 if (mTiming) {
michael@0 1709 mTiming->NotifyUnloadEventEnd();
michael@0 1710 }
michael@0 1711
michael@0 1712 nsAutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
michael@0 1713 uint32_t n = mChildList.Length();
michael@0 1714 kids.SetCapacity(n);
michael@0 1715 for (uint32_t i = 0; i < n; i++) {
michael@0 1716 kids.AppendElement(do_QueryInterface(ChildAt(i)));
michael@0 1717 }
michael@0 1718
michael@0 1719 n = kids.Length();
michael@0 1720 for (uint32_t i = 0; i < n; ++i) {
michael@0 1721 if (kids[i]) {
michael@0 1722 kids[i]->FirePageHideNotification(aIsUnload);
michael@0 1723 }
michael@0 1724 }
michael@0 1725 // Now make sure our editor, if any, is detached before we go
michael@0 1726 // any farther.
michael@0 1727 DetachEditorFromWindow();
michael@0 1728 }
michael@0 1729
michael@0 1730 return NS_OK;
michael@0 1731 }
michael@0 1732
michael@0 1733 void
michael@0 1734 nsDocShell::MaybeInitTiming()
michael@0 1735 {
michael@0 1736 if (mTiming) {
michael@0 1737 return;
michael@0 1738 }
michael@0 1739
michael@0 1740 mTiming = new nsDOMNavigationTiming();
michael@0 1741 mTiming->NotifyNavigationStart();
michael@0 1742 }
michael@0 1743
michael@0 1744
michael@0 1745 //
michael@0 1746 // Bug 13871: Prevent frameset spoofing
michael@0 1747 //
michael@0 1748 // This routine answers: 'Is origin's document from same domain as
michael@0 1749 // target's document?'
michael@0 1750 //
michael@0 1751 // file: uris are considered the same domain for the purpose of
michael@0 1752 // frame navigation regardless of script accessibility (bug 420425)
michael@0 1753 //
michael@0 1754 /* static */
michael@0 1755 bool
michael@0 1756 nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
michael@0 1757 nsIDocShellTreeItem* aTargetTreeItem)
michael@0 1758 {
michael@0 1759 // We want to bypass this check for chrome callers, but only if there's
michael@0 1760 // JS on the stack. System callers still need to do it.
michael@0 1761 if (nsContentUtils::GetCurrentJSContext() && nsContentUtils::IsCallerChrome()) {
michael@0 1762 return true;
michael@0 1763 }
michael@0 1764
michael@0 1765 // Get origin document principal
michael@0 1766 nsCOMPtr<nsIDocument> originDocument(do_GetInterface(aOriginTreeItem));
michael@0 1767 NS_ENSURE_TRUE(originDocument, false);
michael@0 1768
michael@0 1769 // Get target principal
michael@0 1770 nsCOMPtr<nsIDocument> targetDocument(do_GetInterface(aTargetTreeItem));
michael@0 1771 NS_ENSURE_TRUE(targetDocument, false);
michael@0 1772
michael@0 1773 bool equal;
michael@0 1774 nsresult rv = originDocument->NodePrincipal()->Equals(targetDocument->NodePrincipal(),
michael@0 1775 &equal);
michael@0 1776 if (NS_SUCCEEDED(rv) && equal) {
michael@0 1777 return true;
michael@0 1778 }
michael@0 1779
michael@0 1780 // Not strictly equal, special case if both are file: uris
michael@0 1781 bool originIsFile = false;
michael@0 1782 bool targetIsFile = false;
michael@0 1783 nsCOMPtr<nsIURI> originURI;
michael@0 1784 nsCOMPtr<nsIURI> targetURI;
michael@0 1785 nsCOMPtr<nsIURI> innerOriginURI;
michael@0 1786 nsCOMPtr<nsIURI> innerTargetURI;
michael@0 1787
michael@0 1788 rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
michael@0 1789 if (NS_SUCCEEDED(rv) && originURI)
michael@0 1790 innerOriginURI = NS_GetInnermostURI(originURI);
michael@0 1791
michael@0 1792 rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
michael@0 1793 if (NS_SUCCEEDED(rv) && targetURI)
michael@0 1794 innerTargetURI = NS_GetInnermostURI(targetURI);
michael@0 1795
michael@0 1796 return innerOriginURI && innerTargetURI &&
michael@0 1797 NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
michael@0 1798 NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
michael@0 1799 originIsFile && targetIsFile;
michael@0 1800 }
michael@0 1801
michael@0 1802 NS_IMETHODIMP
michael@0 1803 nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
michael@0 1804 {
michael@0 1805 NS_ENSURE_ARG_POINTER(aPresContext);
michael@0 1806 *aPresContext = nullptr;
michael@0 1807
michael@0 1808 nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
michael@0 1809 while (viewer) {
michael@0 1810 nsCOMPtr<nsIContentViewer> prevViewer;
michael@0 1811 viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
michael@0 1812 if (!prevViewer) {
michael@0 1813 return viewer->GetPresContext(aPresContext);
michael@0 1814 }
michael@0 1815 viewer = prevViewer;
michael@0 1816 }
michael@0 1817
michael@0 1818 return NS_OK;
michael@0 1819 }
michael@0 1820
michael@0 1821 NS_IMETHODIMP
michael@0 1822 nsDocShell::GetPresContext(nsPresContext ** aPresContext)
michael@0 1823 {
michael@0 1824 NS_ENSURE_ARG_POINTER(aPresContext);
michael@0 1825 *aPresContext = nullptr;
michael@0 1826
michael@0 1827 if (!mContentViewer)
michael@0 1828 return NS_OK;
michael@0 1829
michael@0 1830 return mContentViewer->GetPresContext(aPresContext);
michael@0 1831 }
michael@0 1832
michael@0 1833 NS_IMETHODIMP_(nsIPresShell*)
michael@0 1834 nsDocShell::GetPresShell()
michael@0 1835 {
michael@0 1836 nsRefPtr<nsPresContext> presContext;
michael@0 1837 (void) GetPresContext(getter_AddRefs(presContext));
michael@0 1838 return presContext ? presContext->GetPresShell() : nullptr;
michael@0 1839 }
michael@0 1840
michael@0 1841 NS_IMETHODIMP
michael@0 1842 nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
michael@0 1843 {
michael@0 1844 nsresult rv = NS_OK;
michael@0 1845
michael@0 1846 NS_ENSURE_ARG_POINTER(aPresShell);
michael@0 1847 *aPresShell = nullptr;
michael@0 1848
michael@0 1849 nsRefPtr<nsPresContext> presContext;
michael@0 1850 (void) GetEldestPresContext(getter_AddRefs(presContext));
michael@0 1851
michael@0 1852 if (presContext) {
michael@0 1853 NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
michael@0 1854 }
michael@0 1855
michael@0 1856 return rv;
michael@0 1857 }
michael@0 1858
michael@0 1859 NS_IMETHODIMP
michael@0 1860 nsDocShell::GetContentViewer(nsIContentViewer ** aContentViewer)
michael@0 1861 {
michael@0 1862 NS_ENSURE_ARG_POINTER(aContentViewer);
michael@0 1863
michael@0 1864 *aContentViewer = mContentViewer;
michael@0 1865 NS_IF_ADDREF(*aContentViewer);
michael@0 1866 return NS_OK;
michael@0 1867 }
michael@0 1868
michael@0 1869 NS_IMETHODIMP
michael@0 1870 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
michael@0 1871 {
michael@0 1872 // Weak reference. Don't addref.
michael@0 1873 nsCOMPtr<EventTarget> handler = do_QueryInterface(aChromeEventHandler);
michael@0 1874 mChromeEventHandler = handler.get();
michael@0 1875
michael@0 1876 if (mScriptGlobal) {
michael@0 1877 mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
michael@0 1878 }
michael@0 1879
michael@0 1880 return NS_OK;
michael@0 1881 }
michael@0 1882
michael@0 1883 NS_IMETHODIMP
michael@0 1884 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
michael@0 1885 {
michael@0 1886 NS_ENSURE_ARG_POINTER(aChromeEventHandler);
michael@0 1887 nsCOMPtr<EventTarget> handler = mChromeEventHandler;
michael@0 1888 handler.forget(aChromeEventHandler);
michael@0 1889 return NS_OK;
michael@0 1890 }
michael@0 1891
michael@0 1892 /* void setCurrentURI (in nsIURI uri); */
michael@0 1893 NS_IMETHODIMP
michael@0 1894 nsDocShell::SetCurrentURI(nsIURI *aURI)
michael@0 1895 {
michael@0 1896 // Note that securityUI will set STATE_IS_INSECURE, even if
michael@0 1897 // the scheme of |aURI| is "https".
michael@0 1898 SetCurrentURI(aURI, nullptr, true, 0);
michael@0 1899 return NS_OK;
michael@0 1900 }
michael@0 1901
michael@0 1902 bool
michael@0 1903 nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
michael@0 1904 bool aFireOnLocationChange, uint32_t aLocationFlags)
michael@0 1905 {
michael@0 1906 #ifdef PR_LOGGING
michael@0 1907 if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
michael@0 1908 nsAutoCString spec;
michael@0 1909 if (aURI)
michael@0 1910 aURI->GetSpec(spec);
michael@0 1911 PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
michael@0 1912 }
michael@0 1913 #endif
michael@0 1914
michael@0 1915 // We don't want to send a location change when we're displaying an error
michael@0 1916 // page, and we don't want to change our idea of "current URI" either
michael@0 1917 if (mLoadType == LOAD_ERROR_PAGE) {
michael@0 1918 return false;
michael@0 1919 }
michael@0 1920
michael@0 1921 mCurrentURI = NS_TryToMakeImmutable(aURI);
michael@0 1922
michael@0 1923 bool isRoot = false; // Is this the root docshell
michael@0 1924 bool isSubFrame = false; // Is this a subframe navigation?
michael@0 1925
michael@0 1926 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 1927
michael@0 1928 GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 1929 if (root.get() == static_cast<nsIDocShellTreeItem *>(this))
michael@0 1930 {
michael@0 1931 // This is the root docshell
michael@0 1932 isRoot = true;
michael@0 1933 }
michael@0 1934 if (mLSHE) {
michael@0 1935 mLSHE->GetIsSubFrame(&isSubFrame);
michael@0 1936 }
michael@0 1937
michael@0 1938 if (!isSubFrame && !isRoot) {
michael@0 1939 /*
michael@0 1940 * We don't want to send OnLocationChange notifications when
michael@0 1941 * a subframe is being loaded for the first time, while
michael@0 1942 * visiting a frameset page
michael@0 1943 */
michael@0 1944 return false;
michael@0 1945 }
michael@0 1946
michael@0 1947 if (aFireOnLocationChange) {
michael@0 1948 FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
michael@0 1949 }
michael@0 1950 return !aFireOnLocationChange;
michael@0 1951 }
michael@0 1952
michael@0 1953 NS_IMETHODIMP
michael@0 1954 nsDocShell::GetCharset(nsACString& aCharset)
michael@0 1955 {
michael@0 1956 aCharset.Truncate();
michael@0 1957
michael@0 1958 nsIPresShell* presShell = GetPresShell();
michael@0 1959 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
michael@0 1960 nsIDocument *doc = presShell->GetDocument();
michael@0 1961 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
michael@0 1962 aCharset = doc->GetDocumentCharacterSet();
michael@0 1963 return NS_OK;
michael@0 1964 }
michael@0 1965
michael@0 1966 NS_IMETHODIMP
michael@0 1967 nsDocShell::GatherCharsetMenuTelemetry()
michael@0 1968 {
michael@0 1969 nsCOMPtr<nsIContentViewer> viewer;
michael@0 1970 GetContentViewer(getter_AddRefs(viewer));
michael@0 1971 if (!viewer) {
michael@0 1972 return NS_OK;
michael@0 1973 }
michael@0 1974
michael@0 1975 nsIDocument* doc = viewer->GetDocument();
michael@0 1976 if (!doc || doc->WillIgnoreCharsetOverride()) {
michael@0 1977 return NS_OK;
michael@0 1978 }
michael@0 1979
michael@0 1980 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true);
michael@0 1981
michael@0 1982 bool isFileURL = false;
michael@0 1983 nsIURI* url = doc->GetOriginalURI();
michael@0 1984 if (url) {
michael@0 1985 url->SchemeIs("file", &isFileURL);
michael@0 1986 }
michael@0 1987
michael@0 1988 int32_t charsetSource = doc->GetDocumentCharacterSetSource();
michael@0 1989 switch (charsetSource) {
michael@0 1990 case kCharsetFromTopLevelDomain:
michael@0 1991 // Unlabeled doc on a domain that we map to a fallback encoding
michael@0 1992 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7);
michael@0 1993 break;
michael@0 1994 case kCharsetFromFallback:
michael@0 1995 case kCharsetFromDocTypeDefault:
michael@0 1996 case kCharsetFromCache:
michael@0 1997 case kCharsetFromParentFrame:
michael@0 1998 case kCharsetFromHintPrevDoc:
michael@0 1999 // Changing charset on an unlabeled doc.
michael@0 2000 if (isFileURL) {
michael@0 2001 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
michael@0 2002 } else {
michael@0 2003 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1);
michael@0 2004 }
michael@0 2005 break;
michael@0 2006 case kCharsetFromAutoDetection:
michael@0 2007 // Changing charset on unlabeled doc where chardet fired
michael@0 2008 if (isFileURL) {
michael@0 2009 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2);
michael@0 2010 } else {
michael@0 2011 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3);
michael@0 2012 }
michael@0 2013 break;
michael@0 2014 case kCharsetFromMetaPrescan:
michael@0 2015 case kCharsetFromMetaTag:
michael@0 2016 case kCharsetFromChannel:
michael@0 2017 // Changing charset on a doc that had a charset label.
michael@0 2018 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4);
michael@0 2019 break;
michael@0 2020 case kCharsetFromParentForced:
michael@0 2021 case kCharsetFromUserForced:
michael@0 2022 // Changing charset on a document that already had an override.
michael@0 2023 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5);
michael@0 2024 break;
michael@0 2025 case kCharsetFromIrreversibleAutoDetection:
michael@0 2026 case kCharsetFromOtherComponent:
michael@0 2027 case kCharsetFromByteOrderMark:
michael@0 2028 case kCharsetUninitialized:
michael@0 2029 default:
michael@0 2030 // Bug. This isn't supposed to happen.
michael@0 2031 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6);
michael@0 2032 break;
michael@0 2033 }
michael@0 2034 return NS_OK;
michael@0 2035 }
michael@0 2036
michael@0 2037 NS_IMETHODIMP
michael@0 2038 nsDocShell::SetCharset(const nsACString& aCharset)
michael@0 2039 {
michael@0 2040 // set the charset override
michael@0 2041 return SetForcedCharset(aCharset);
michael@0 2042 }
michael@0 2043
michael@0 2044 NS_IMETHODIMP nsDocShell::SetForcedCharset(const nsACString& aCharset)
michael@0 2045 {
michael@0 2046 if (aCharset.IsEmpty()) {
michael@0 2047 mForcedCharset.Truncate();
michael@0 2048 return NS_OK;
michael@0 2049 }
michael@0 2050 nsAutoCString encoding;
michael@0 2051 if (!EncodingUtils::FindEncodingForLabel(aCharset, encoding)) {
michael@0 2052 // Reject unknown labels
michael@0 2053 return NS_ERROR_INVALID_ARG;
michael@0 2054 }
michael@0 2055 if (!EncodingUtils::IsAsciiCompatible(encoding)) {
michael@0 2056 // Reject XSS hazards
michael@0 2057 return NS_ERROR_INVALID_ARG;
michael@0 2058 }
michael@0 2059 mForcedCharset = encoding;
michael@0 2060 return NS_OK;
michael@0 2061 }
michael@0 2062
michael@0 2063 NS_IMETHODIMP nsDocShell::GetForcedCharset(nsACString& aResult)
michael@0 2064 {
michael@0 2065 aResult = mForcedCharset;
michael@0 2066 return NS_OK;
michael@0 2067 }
michael@0 2068
michael@0 2069 void
michael@0 2070 nsDocShell::SetParentCharset(const nsACString& aCharset,
michael@0 2071 int32_t aCharsetSource,
michael@0 2072 nsIPrincipal* aPrincipal)
michael@0 2073 {
michael@0 2074 mParentCharset = aCharset;
michael@0 2075 mParentCharsetSource = aCharsetSource;
michael@0 2076 mParentCharsetPrincipal = aPrincipal;
michael@0 2077 }
michael@0 2078
michael@0 2079 void
michael@0 2080 nsDocShell::GetParentCharset(nsACString& aCharset,
michael@0 2081 int32_t* aCharsetSource,
michael@0 2082 nsIPrincipal** aPrincipal)
michael@0 2083 {
michael@0 2084 aCharset = mParentCharset;
michael@0 2085 *aCharsetSource = mParentCharsetSource;
michael@0 2086 NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
michael@0 2087 }
michael@0 2088
michael@0 2089 NS_IMETHODIMP
michael@0 2090 nsDocShell::GetChannelIsUnsafe(bool *aUnsafe)
michael@0 2091 {
michael@0 2092 *aUnsafe = false;
michael@0 2093
michael@0 2094 nsIChannel* channel = GetCurrentDocChannel();
michael@0 2095 if (!channel) {
michael@0 2096 return NS_OK;
michael@0 2097 }
michael@0 2098
michael@0 2099 nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
michael@0 2100 if (!jarChannel) {
michael@0 2101 return NS_OK;
michael@0 2102 }
michael@0 2103
michael@0 2104 return jarChannel->GetIsUnsafe(aUnsafe);
michael@0 2105 }
michael@0 2106
michael@0 2107 NS_IMETHODIMP
michael@0 2108 nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded)
michael@0 2109 {
michael@0 2110 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 2111 *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
michael@0 2112 return NS_OK;
michael@0 2113 }
michael@0 2114
michael@0 2115 NS_IMETHODIMP
michael@0 2116 nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked)
michael@0 2117 {
michael@0 2118 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 2119 *aHasMixedActiveContentBlocked = doc && doc->GetHasMixedActiveContentBlocked();
michael@0 2120 return NS_OK;
michael@0 2121 }
michael@0 2122
michael@0 2123 NS_IMETHODIMP
michael@0 2124 nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded)
michael@0 2125 {
michael@0 2126 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 2127 *aHasMixedDisplayContentLoaded = doc && doc->GetHasMixedDisplayContentLoaded();
michael@0 2128 return NS_OK;
michael@0 2129 }
michael@0 2130
michael@0 2131 NS_IMETHODIMP
michael@0 2132 nsDocShell::GetHasMixedDisplayContentBlocked(bool* aHasMixedDisplayContentBlocked)
michael@0 2133 {
michael@0 2134 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 2135 *aHasMixedDisplayContentBlocked = doc && doc->GetHasMixedDisplayContentBlocked();
michael@0 2136 return NS_OK;
michael@0 2137 }
michael@0 2138
michael@0 2139 NS_IMETHODIMP
michael@0 2140 nsDocShell::GetAllowPlugins(bool * aAllowPlugins)
michael@0 2141 {
michael@0 2142 NS_ENSURE_ARG_POINTER(aAllowPlugins);
michael@0 2143
michael@0 2144 *aAllowPlugins = mAllowPlugins;
michael@0 2145 if (!mAllowPlugins) {
michael@0 2146 return NS_OK;
michael@0 2147 }
michael@0 2148
michael@0 2149 bool unsafe;
michael@0 2150 *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
michael@0 2151 return NS_OK;
michael@0 2152 }
michael@0 2153
michael@0 2154 NS_IMETHODIMP
michael@0 2155 nsDocShell::SetAllowPlugins(bool aAllowPlugins)
michael@0 2156 {
michael@0 2157 mAllowPlugins = aAllowPlugins;
michael@0 2158 //XXX should enable or disable a plugin host
michael@0 2159 return NS_OK;
michael@0 2160 }
michael@0 2161
michael@0 2162 NS_IMETHODIMP
michael@0 2163 nsDocShell::GetAllowJavascript(bool * aAllowJavascript)
michael@0 2164 {
michael@0 2165 NS_ENSURE_ARG_POINTER(aAllowJavascript);
michael@0 2166
michael@0 2167 *aAllowJavascript = mAllowJavascript;
michael@0 2168 return NS_OK;
michael@0 2169 }
michael@0 2170
michael@0 2171 NS_IMETHODIMP
michael@0 2172 nsDocShell::SetAllowJavascript(bool aAllowJavascript)
michael@0 2173 {
michael@0 2174 mAllowJavascript = aAllowJavascript;
michael@0 2175 RecomputeCanExecuteScripts();
michael@0 2176 return NS_OK;
michael@0 2177 }
michael@0 2178
michael@0 2179 NS_IMETHODIMP
michael@0 2180 nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
michael@0 2181 {
michael@0 2182 NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
michael@0 2183
michael@0 2184 *aUsePrivateBrowsing = mInPrivateBrowsing;
michael@0 2185 return NS_OK;
michael@0 2186 }
michael@0 2187
michael@0 2188 NS_IMETHODIMP
michael@0 2189 nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
michael@0 2190 {
michael@0 2191 nsContentUtils::ReportToConsoleNonLocalized(
michael@0 2192 NS_LITERAL_STRING("Only internal code is allowed to set the usePrivateBrowsing attribute"),
michael@0 2193 nsIScriptError::warningFlag,
michael@0 2194 NS_LITERAL_CSTRING("Internal API Used"),
michael@0 2195 mContentViewer ? mContentViewer->GetDocument() : nullptr);
michael@0 2196
michael@0 2197 return SetPrivateBrowsing(aUsePrivateBrowsing);
michael@0 2198 }
michael@0 2199
michael@0 2200 NS_IMETHODIMP
michael@0 2201 nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
michael@0 2202 {
michael@0 2203 bool changed = aUsePrivateBrowsing != mInPrivateBrowsing;
michael@0 2204 if (changed) {
michael@0 2205 mInPrivateBrowsing = aUsePrivateBrowsing;
michael@0 2206 if (mAffectPrivateSessionLifetime) {
michael@0 2207 if (aUsePrivateBrowsing) {
michael@0 2208 IncreasePrivateDocShellCount();
michael@0 2209 } else {
michael@0 2210 DecreasePrivateDocShellCount();
michael@0 2211 }
michael@0 2212 }
michael@0 2213 }
michael@0 2214
michael@0 2215 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 2216 while (iter.HasMore()) {
michael@0 2217 nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext());
michael@0 2218 if (shell) {
michael@0 2219 shell->SetPrivateBrowsing(aUsePrivateBrowsing);
michael@0 2220 }
michael@0 2221 }
michael@0 2222
michael@0 2223 if (changed) {
michael@0 2224 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
michael@0 2225 while (iter.HasMore()) {
michael@0 2226 nsWeakPtr ref = iter.GetNext();
michael@0 2227 nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
michael@0 2228 if (!obs) {
michael@0 2229 mPrivacyObservers.RemoveElement(ref);
michael@0 2230 } else {
michael@0 2231 obs->PrivateModeChanged(aUsePrivateBrowsing);
michael@0 2232 }
michael@0 2233 }
michael@0 2234 }
michael@0 2235 return NS_OK;
michael@0 2236 }
michael@0 2237
michael@0 2238 NS_IMETHODIMP
michael@0 2239 nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
michael@0 2240 {
michael@0 2241 NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
michael@0 2242
michael@0 2243 *aUseRemoteTabs = mUseRemoteTabs;
michael@0 2244 return NS_OK;
michael@0 2245 }
michael@0 2246
michael@0 2247 NS_IMETHODIMP
michael@0 2248 nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
michael@0 2249 {
michael@0 2250 #ifdef MOZ_CRASHREPORTER
michael@0 2251 if (aUseRemoteTabs) {
michael@0 2252 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
michael@0 2253 NS_LITERAL_CSTRING("1"));
michael@0 2254 }
michael@0 2255 #endif
michael@0 2256
michael@0 2257 mUseRemoteTabs = aUseRemoteTabs;
michael@0 2258 return NS_OK;
michael@0 2259 }
michael@0 2260
michael@0 2261 NS_IMETHODIMP
michael@0 2262 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
michael@0 2263 {
michael@0 2264 bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
michael@0 2265 if (change && mInPrivateBrowsing) {
michael@0 2266 if (aAffectLifetime) {
michael@0 2267 IncreasePrivateDocShellCount();
michael@0 2268 } else {
michael@0 2269 DecreasePrivateDocShellCount();
michael@0 2270 }
michael@0 2271 }
michael@0 2272 mAffectPrivateSessionLifetime = aAffectLifetime;
michael@0 2273
michael@0 2274 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 2275 while (iter.HasMore()) {
michael@0 2276 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
michael@0 2277 if (shell) {
michael@0 2278 shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
michael@0 2279 }
michael@0 2280 }
michael@0 2281 return NS_OK;
michael@0 2282 }
michael@0 2283
michael@0 2284 NS_IMETHODIMP
michael@0 2285 nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime)
michael@0 2286 {
michael@0 2287 *aAffectLifetime = mAffectPrivateSessionLifetime;
michael@0 2288 return NS_OK;
michael@0 2289 }
michael@0 2290
michael@0 2291 NS_IMETHODIMP
michael@0 2292 nsDocShell::AddWeakPrivacyTransitionObserver(nsIPrivacyTransitionObserver* aObserver)
michael@0 2293 {
michael@0 2294 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
michael@0 2295 if (!weakObs) {
michael@0 2296 return NS_ERROR_NOT_AVAILABLE;
michael@0 2297 }
michael@0 2298 return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
michael@0 2299 }
michael@0 2300
michael@0 2301 NS_IMETHODIMP
michael@0 2302 nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver)
michael@0 2303 {
michael@0 2304 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
michael@0 2305 if (!weakObs) {
michael@0 2306 return NS_ERROR_FAILURE;
michael@0 2307 }
michael@0 2308 return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
michael@0 2309 }
michael@0 2310
michael@0 2311 NS_IMETHODIMP
michael@0 2312 nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver)
michael@0 2313 {
michael@0 2314 nsWeakPtr obs = do_GetWeakReference(aObserver);
michael@0 2315 return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
michael@0 2316 }
michael@0 2317
michael@0 2318 NS_IMETHODIMP
michael@0 2319 nsDocShell::NotifyReflowObservers(bool aInterruptible,
michael@0 2320 DOMHighResTimeStamp aStart,
michael@0 2321 DOMHighResTimeStamp aEnd)
michael@0 2322 {
michael@0 2323 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
michael@0 2324 while (iter.HasMore()) {
michael@0 2325 nsWeakPtr ref = iter.GetNext();
michael@0 2326 nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
michael@0 2327 if (!obs) {
michael@0 2328 mReflowObservers.RemoveElement(ref);
michael@0 2329 } else if (aInterruptible) {
michael@0 2330 obs->ReflowInterruptible(aStart, aEnd);
michael@0 2331 } else {
michael@0 2332 obs->Reflow(aStart, aEnd);
michael@0 2333 }
michael@0 2334 }
michael@0 2335 return NS_OK;
michael@0 2336 }
michael@0 2337
michael@0 2338 NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(bool * aReturn)
michael@0 2339 {
michael@0 2340 NS_ENSURE_ARG_POINTER(aReturn);
michael@0 2341
michael@0 2342 *aReturn = mAllowMetaRedirects;
michael@0 2343 if (!mAllowMetaRedirects) {
michael@0 2344 return NS_OK;
michael@0 2345 }
michael@0 2346
michael@0 2347 bool unsafe;
michael@0 2348 *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
michael@0 2349 return NS_OK;
michael@0 2350 }
michael@0 2351
michael@0 2352 NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(bool aValue)
michael@0 2353 {
michael@0 2354 mAllowMetaRedirects = aValue;
michael@0 2355 return NS_OK;
michael@0 2356 }
michael@0 2357
michael@0 2358 NS_IMETHODIMP nsDocShell::GetAllowSubframes(bool * aAllowSubframes)
michael@0 2359 {
michael@0 2360 NS_ENSURE_ARG_POINTER(aAllowSubframes);
michael@0 2361
michael@0 2362 *aAllowSubframes = mAllowSubframes;
michael@0 2363 return NS_OK;
michael@0 2364 }
michael@0 2365
michael@0 2366 NS_IMETHODIMP nsDocShell::SetAllowSubframes(bool aAllowSubframes)
michael@0 2367 {
michael@0 2368 mAllowSubframes = aAllowSubframes;
michael@0 2369 return NS_OK;
michael@0 2370 }
michael@0 2371
michael@0 2372 NS_IMETHODIMP nsDocShell::GetAllowImages(bool * aAllowImages)
michael@0 2373 {
michael@0 2374 NS_ENSURE_ARG_POINTER(aAllowImages);
michael@0 2375
michael@0 2376 *aAllowImages = mAllowImages;
michael@0 2377 return NS_OK;
michael@0 2378 }
michael@0 2379
michael@0 2380 NS_IMETHODIMP nsDocShell::SetAllowImages(bool aAllowImages)
michael@0 2381 {
michael@0 2382 mAllowImages = aAllowImages;
michael@0 2383 return NS_OK;
michael@0 2384 }
michael@0 2385
michael@0 2386 NS_IMETHODIMP nsDocShell::GetAllowMedia(bool * aAllowMedia)
michael@0 2387 {
michael@0 2388 *aAllowMedia = mAllowMedia;
michael@0 2389 return NS_OK;
michael@0 2390 }
michael@0 2391
michael@0 2392 NS_IMETHODIMP nsDocShell::SetAllowMedia(bool aAllowMedia)
michael@0 2393 {
michael@0 2394 mAllowMedia = aAllowMedia;
michael@0 2395
michael@0 2396 // Mute or unmute audio contexts attached to the inner window.
michael@0 2397 if (mScriptGlobal) {
michael@0 2398 nsPIDOMWindow* innerWin = mScriptGlobal->GetCurrentInnerWindow();
michael@0 2399 if (innerWin) {
michael@0 2400 if (aAllowMedia) {
michael@0 2401 innerWin->UnmuteAudioContexts();
michael@0 2402 } else {
michael@0 2403 innerWin->MuteAudioContexts();
michael@0 2404 }
michael@0 2405 }
michael@0 2406 }
michael@0 2407
michael@0 2408 return NS_OK;
michael@0 2409 }
michael@0 2410
michael@0 2411 NS_IMETHODIMP nsDocShell::GetAllowDNSPrefetch(bool * aAllowDNSPrefetch)
michael@0 2412 {
michael@0 2413 *aAllowDNSPrefetch = mAllowDNSPrefetch;
michael@0 2414 return NS_OK;
michael@0 2415 }
michael@0 2416
michael@0 2417 NS_IMETHODIMP nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
michael@0 2418 {
michael@0 2419 mAllowDNSPrefetch = aAllowDNSPrefetch;
michael@0 2420 return NS_OK;
michael@0 2421 }
michael@0 2422
michael@0 2423 NS_IMETHODIMP nsDocShell::GetAllowWindowControl(bool * aAllowWindowControl)
michael@0 2424 {
michael@0 2425 *aAllowWindowControl = mAllowWindowControl;
michael@0 2426 return NS_OK;
michael@0 2427 }
michael@0 2428
michael@0 2429 NS_IMETHODIMP nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
michael@0 2430 {
michael@0 2431 mAllowWindowControl = aAllowWindowControl;
michael@0 2432 return NS_OK;
michael@0 2433 }
michael@0 2434
michael@0 2435 NS_IMETHODIMP
michael@0 2436 nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting)
michael@0 2437 {
michael@0 2438 *aAllowContentRetargeting = mAllowContentRetargeting;
michael@0 2439 return NS_OK;
michael@0 2440 }
michael@0 2441
michael@0 2442 NS_IMETHODIMP
michael@0 2443 nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting)
michael@0 2444 {
michael@0 2445 mAllowContentRetargeting = aAllowContentRetargeting;
michael@0 2446 return NS_OK;
michael@0 2447 }
michael@0 2448
michael@0 2449 NS_IMETHODIMP
michael@0 2450 nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
michael@0 2451 {
michael@0 2452 NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
michael@0 2453
michael@0 2454 // Browsers and apps have their mFullscreenAllowed retrieved from their
michael@0 2455 // corresponding iframe in their parent upon creation.
michael@0 2456 if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
michael@0 2457 *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
michael@0 2458 return NS_OK;
michael@0 2459 }
michael@0 2460
michael@0 2461 // Assume false until we determine otherwise...
michael@0 2462 *aFullscreenAllowed = false;
michael@0 2463
michael@0 2464 // For non-browsers/apps, check that the enclosing iframe element
michael@0 2465 // has the allowfullscreen attribute set to true. If any ancestor
michael@0 2466 // iframe does not have mozallowfullscreen=true, then fullscreen is
michael@0 2467 // prohibited.
michael@0 2468 nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(GetAsSupports(this));
michael@0 2469 if (!win) {
michael@0 2470 return NS_OK;
michael@0 2471 }
michael@0 2472 nsCOMPtr<nsIContent> frameElement = do_QueryInterface(win->GetFrameElementInternal());
michael@0 2473 if (frameElement &&
michael@0 2474 frameElement->IsHTML(nsGkAtoms::iframe) &&
michael@0 2475 !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) &&
michael@0 2476 !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) {
michael@0 2477 return NS_OK;
michael@0 2478 }
michael@0 2479
michael@0 2480 // If we have no parent then we're the root docshell; no ancestor of the
michael@0 2481 // original docshell doesn't have a allowfullscreen attribute, so
michael@0 2482 // report fullscreen as allowed.
michael@0 2483 nsCOMPtr<nsIDocShellTreeItem> dsti = do_GetInterface(GetAsSupports(this));
michael@0 2484 NS_ENSURE_TRUE(dsti, NS_OK);
michael@0 2485
michael@0 2486 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
michael@0 2487 dsti->GetParent(getter_AddRefs(parentTreeItem));
michael@0 2488 if (!parentTreeItem) {
michael@0 2489 *aFullscreenAllowed = true;
michael@0 2490 return NS_OK;
michael@0 2491 }
michael@0 2492 // Otherwise, we have a parent, continue the checking for
michael@0 2493 // mozFullscreenAllowed in the parent docshell's ancestors.
michael@0 2494 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem);
michael@0 2495 NS_ENSURE_TRUE(parent, NS_OK);
michael@0 2496
michael@0 2497 return parent->GetFullscreenAllowed(aFullscreenAllowed);
michael@0 2498 }
michael@0 2499
michael@0 2500 NS_IMETHODIMP
michael@0 2501 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
michael@0 2502 {
michael@0 2503 if (!nsIDocShell::GetIsBrowserOrApp()) {
michael@0 2504 // Only allow setting of fullscreenAllowed on content/process boundaries.
michael@0 2505 // At non-boundaries the fullscreenAllowed attribute is calculated based on
michael@0 2506 // whether all enclosing frames have the "mozFullscreenAllowed" attribute
michael@0 2507 // set to "true". fullscreenAllowed is set at the process boundaries to
michael@0 2508 // propagate the value of the parent's "mozFullscreenAllowed" attribute
michael@0 2509 // across process boundaries.
michael@0 2510 return NS_ERROR_UNEXPECTED;
michael@0 2511 }
michael@0 2512 mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS);
michael@0 2513 return NS_OK;
michael@0 2514 }
michael@0 2515
michael@0 2516 NS_IMETHODIMP
michael@0 2517 nsDocShell::GetMayEnableCharacterEncodingMenu(bool* aMayEnableCharacterEncodingMenu)
michael@0 2518 {
michael@0 2519 *aMayEnableCharacterEncodingMenu = false;
michael@0 2520 if (!mContentViewer) {
michael@0 2521 return NS_OK;
michael@0 2522 }
michael@0 2523 nsIDocument* doc = mContentViewer->GetDocument();
michael@0 2524 if (!doc) {
michael@0 2525 return NS_OK;
michael@0 2526 }
michael@0 2527 if (doc->WillIgnoreCharsetOverride()) {
michael@0 2528 return NS_OK;
michael@0 2529 }
michael@0 2530
michael@0 2531 *aMayEnableCharacterEncodingMenu = true;
michael@0 2532 return NS_OK;
michael@0 2533 }
michael@0 2534
michael@0 2535 NS_IMETHODIMP
michael@0 2536 nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection, nsISimpleEnumerator **outEnum)
michael@0 2537 {
michael@0 2538 NS_ENSURE_ARG_POINTER(outEnum);
michael@0 2539 *outEnum = nullptr;
michael@0 2540
michael@0 2541 nsRefPtr<nsDocShellEnumerator> docShellEnum;
michael@0 2542 if (aDirection == ENUMERATE_FORWARDS)
michael@0 2543 docShellEnum = new nsDocShellForwardsEnumerator;
michael@0 2544 else
michael@0 2545 docShellEnum = new nsDocShellBackwardsEnumerator;
michael@0 2546
michael@0 2547 if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY;
michael@0 2548
michael@0 2549 nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
michael@0 2550 if (NS_FAILED(rv)) return rv;
michael@0 2551
michael@0 2552 rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this);
michael@0 2553 if (NS_FAILED(rv)) return rv;
michael@0 2554
michael@0 2555 rv = docShellEnum->First();
michael@0 2556 if (NS_FAILED(rv)) return rv;
michael@0 2557
michael@0 2558 rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum);
michael@0 2559
michael@0 2560 return rv;
michael@0 2561 }
michael@0 2562
michael@0 2563 NS_IMETHODIMP
michael@0 2564 nsDocShell::GetAppType(uint32_t * aAppType)
michael@0 2565 {
michael@0 2566 *aAppType = mAppType;
michael@0 2567 return NS_OK;
michael@0 2568 }
michael@0 2569
michael@0 2570 NS_IMETHODIMP
michael@0 2571 nsDocShell::SetAppType(uint32_t aAppType)
michael@0 2572 {
michael@0 2573 mAppType = aAppType;
michael@0 2574 return NS_OK;
michael@0 2575 }
michael@0 2576
michael@0 2577
michael@0 2578 NS_IMETHODIMP
michael@0 2579 nsDocShell::GetAllowAuth(bool * aAllowAuth)
michael@0 2580 {
michael@0 2581 *aAllowAuth = mAllowAuth;
michael@0 2582 return NS_OK;
michael@0 2583 }
michael@0 2584
michael@0 2585 NS_IMETHODIMP
michael@0 2586 nsDocShell::SetAllowAuth(bool aAllowAuth)
michael@0 2587 {
michael@0 2588 mAllowAuth = aAllowAuth;
michael@0 2589 return NS_OK;
michael@0 2590 }
michael@0 2591
michael@0 2592 NS_IMETHODIMP
michael@0 2593 nsDocShell::GetZoom(float *zoom)
michael@0 2594 {
michael@0 2595 NS_ENSURE_ARG_POINTER(zoom);
michael@0 2596 *zoom = 1.0f;
michael@0 2597 return NS_OK;
michael@0 2598 }
michael@0 2599
michael@0 2600 NS_IMETHODIMP
michael@0 2601 nsDocShell::SetZoom(float zoom)
michael@0 2602 {
michael@0 2603 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 2604 }
michael@0 2605
michael@0 2606 NS_IMETHODIMP
michael@0 2607 nsDocShell::GetMarginWidth(int32_t * aWidth)
michael@0 2608 {
michael@0 2609 NS_ENSURE_ARG_POINTER(aWidth);
michael@0 2610
michael@0 2611 *aWidth = mMarginWidth;
michael@0 2612 return NS_OK;
michael@0 2613 }
michael@0 2614
michael@0 2615 NS_IMETHODIMP
michael@0 2616 nsDocShell::SetMarginWidth(int32_t aWidth)
michael@0 2617 {
michael@0 2618 mMarginWidth = aWidth;
michael@0 2619 return NS_OK;
michael@0 2620 }
michael@0 2621
michael@0 2622 NS_IMETHODIMP
michael@0 2623 nsDocShell::GetMarginHeight(int32_t * aHeight)
michael@0 2624 {
michael@0 2625 NS_ENSURE_ARG_POINTER(aHeight);
michael@0 2626
michael@0 2627 *aHeight = mMarginHeight;
michael@0 2628 return NS_OK;
michael@0 2629 }
michael@0 2630
michael@0 2631 NS_IMETHODIMP
michael@0 2632 nsDocShell::SetMarginHeight(int32_t aHeight)
michael@0 2633 {
michael@0 2634 mMarginHeight = aHeight;
michael@0 2635 return NS_OK;
michael@0 2636 }
michael@0 2637
michael@0 2638 NS_IMETHODIMP
michael@0 2639 nsDocShell::GetBusyFlags(uint32_t * aBusyFlags)
michael@0 2640 {
michael@0 2641 NS_ENSURE_ARG_POINTER(aBusyFlags);
michael@0 2642
michael@0 2643 *aBusyFlags = mBusyFlags;
michael@0 2644 return NS_OK;
michael@0 2645 }
michael@0 2646
michael@0 2647 NS_IMETHODIMP
michael@0 2648 nsDocShell::TabToTreeOwner(bool aForward, bool* aTookFocus)
michael@0 2649 {
michael@0 2650 NS_ENSURE_ARG_POINTER(aTookFocus);
michael@0 2651
michael@0 2652 nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
michael@0 2653 if (chromeFocus) {
michael@0 2654 if (aForward)
michael@0 2655 *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement());
michael@0 2656 else
michael@0 2657 *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement());
michael@0 2658 } else
michael@0 2659 *aTookFocus = false;
michael@0 2660
michael@0 2661 return NS_OK;
michael@0 2662 }
michael@0 2663
michael@0 2664 NS_IMETHODIMP
michael@0 2665 nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI)
michael@0 2666 {
michael@0 2667 NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
michael@0 2668 return NS_OK;
michael@0 2669 }
michael@0 2670
michael@0 2671 NS_IMETHODIMP
michael@0 2672 nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI)
michael@0 2673 {
michael@0 2674 mSecurityUI = aSecurityUI;
michael@0 2675 mSecurityUI->SetDocShell(this);
michael@0 2676 return NS_OK;
michael@0 2677 }
michael@0 2678
michael@0 2679 NS_IMETHODIMP
michael@0 2680 nsDocShell::GetUseErrorPages(bool *aUseErrorPages)
michael@0 2681 {
michael@0 2682 *aUseErrorPages = UseErrorPages();
michael@0 2683 return NS_OK;
michael@0 2684 }
michael@0 2685
michael@0 2686 NS_IMETHODIMP
michael@0 2687 nsDocShell::SetUseErrorPages(bool aUseErrorPages)
michael@0 2688 {
michael@0 2689 // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
michael@0 2690 if (mObserveErrorPages) {
michael@0 2691 mObserveErrorPages = false;
michael@0 2692 }
michael@0 2693 mUseErrorPages = aUseErrorPages;
michael@0 2694 return NS_OK;
michael@0 2695 }
michael@0 2696
michael@0 2697 NS_IMETHODIMP
michael@0 2698 nsDocShell::GetPreviousTransIndex(int32_t *aPreviousTransIndex)
michael@0 2699 {
michael@0 2700 *aPreviousTransIndex = mPreviousTransIndex;
michael@0 2701 return NS_OK;
michael@0 2702 }
michael@0 2703
michael@0 2704 NS_IMETHODIMP
michael@0 2705 nsDocShell::GetLoadedTransIndex(int32_t *aLoadedTransIndex)
michael@0 2706 {
michael@0 2707 *aLoadedTransIndex = mLoadedTransIndex;
michael@0 2708 return NS_OK;
michael@0 2709 }
michael@0 2710
michael@0 2711 NS_IMETHODIMP
michael@0 2712 nsDocShell::HistoryPurged(int32_t aNumEntries)
michael@0 2713 {
michael@0 2714 // These indices are used for fastback cache eviction, to determine
michael@0 2715 // which session history entries are candidates for content viewer
michael@0 2716 // eviction. We need to adjust by the number of entries that we
michael@0 2717 // just purged from history, so that we look at the right session history
michael@0 2718 // entries during eviction.
michael@0 2719 mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries);
michael@0 2720 mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries);
michael@0 2721
michael@0 2722 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 2723 while (iter.HasMore()) {
michael@0 2724 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
michael@0 2725 if (shell) {
michael@0 2726 shell->HistoryPurged(aNumEntries);
michael@0 2727 }
michael@0 2728 }
michael@0 2729
michael@0 2730 return NS_OK;
michael@0 2731 }
michael@0 2732
michael@0 2733 nsresult
michael@0 2734 nsDocShell::HistoryTransactionRemoved(int32_t aIndex)
michael@0 2735 {
michael@0 2736 // These indices are used for fastback cache eviction, to determine
michael@0 2737 // which session history entries are candidates for content viewer
michael@0 2738 // eviction. We need to adjust by the number of entries that we
michael@0 2739 // just purged from history, so that we look at the right session history
michael@0 2740 // entries during eviction.
michael@0 2741 if (aIndex == mPreviousTransIndex) {
michael@0 2742 mPreviousTransIndex = -1;
michael@0 2743 } else if (aIndex < mPreviousTransIndex) {
michael@0 2744 --mPreviousTransIndex;
michael@0 2745 }
michael@0 2746 if (mLoadedTransIndex == aIndex) {
michael@0 2747 mLoadedTransIndex = 0;
michael@0 2748 } else if (aIndex < mLoadedTransIndex) {
michael@0 2749 --mLoadedTransIndex;
michael@0 2750 }
michael@0 2751
michael@0 2752 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 2753 while (iter.HasMore()) {
michael@0 2754 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
michael@0 2755 if (shell) {
michael@0 2756 static_cast<nsDocShell*>(shell.get())->
michael@0 2757 HistoryTransactionRemoved(aIndex);
michael@0 2758 }
michael@0 2759 }
michael@0 2760
michael@0 2761 return NS_OK;
michael@0 2762 }
michael@0 2763
michael@0 2764 nsIDOMStorageManager*
michael@0 2765 nsDocShell::TopSessionStorageManager()
michael@0 2766 {
michael@0 2767 nsresult rv;
michael@0 2768
michael@0 2769 nsCOMPtr<nsIDocShellTreeItem> topItem;
michael@0 2770 rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
michael@0 2771 if (NS_FAILED(rv)) {
michael@0 2772 return nullptr;
michael@0 2773 }
michael@0 2774
michael@0 2775 if (!topItem) {
michael@0 2776 return nullptr;
michael@0 2777 }
michael@0 2778
michael@0 2779 nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
michael@0 2780 if (topDocShell != this) {
michael@0 2781 return topDocShell->TopSessionStorageManager();
michael@0 2782 }
michael@0 2783
michael@0 2784 if (!mSessionStorageManager) {
michael@0 2785 mSessionStorageManager =
michael@0 2786 do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1");
michael@0 2787 }
michael@0 2788
michael@0 2789 return mSessionStorageManager;
michael@0 2790 }
michael@0 2791
michael@0 2792 NS_IMETHODIMP
michael@0 2793 nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
michael@0 2794 const nsAString& aDocumentURI,
michael@0 2795 bool aCreate,
michael@0 2796 nsIDOMStorage** aStorage)
michael@0 2797 {
michael@0 2798 nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager();
michael@0 2799 if (!manager) {
michael@0 2800 return NS_ERROR_UNEXPECTED;
michael@0 2801 }
michael@0 2802
michael@0 2803 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
michael@0 2804 do_GetService(THIRDPARTYUTIL_CONTRACTID);
michael@0 2805 if (!thirdPartyUtil)
michael@0 2806 return NS_ERROR_FAILURE;
michael@0 2807
michael@0 2808 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 2809 nsCOMPtr<nsIURI> firstPartyIsolationURI;
michael@0 2810 nsresult rv = thirdPartyUtil->GetFirstPartyIsolationURI(nullptr, doc,
michael@0 2811 getter_AddRefs(firstPartyIsolationURI));
michael@0 2812 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2813
michael@0 2814 if (aCreate) {
michael@0 2815 return manager->CreateStorageForFirstParty(firstPartyIsolationURI,
michael@0 2816 aPrincipal, aDocumentURI,
michael@0 2817 mInPrivateBrowsing, aStorage);
michael@0 2818 }
michael@0 2819
michael@0 2820 return manager->GetStorageForFirstParty(firstPartyIsolationURI, aPrincipal,
michael@0 2821 mInPrivateBrowsing, aStorage);
michael@0 2822 }
michael@0 2823
michael@0 2824 // Bacause it is not called from anywhere, nsDocShell::AddSessionStorage()
michael@0 2825 // does not need to be modified to isolate DOM Storage to the first party URI.
michael@0 2826 nsresult
michael@0 2827 nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
michael@0 2828 nsIDOMStorage* aStorage)
michael@0 2829 {
michael@0 2830 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(aStorage);
michael@0 2831 nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
michael@0 2832 if (storagePrincipal != aPrincipal) {
michael@0 2833 NS_ERROR("Wanting to add a sessionStorage for different principal");
michael@0 2834 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 2835 }
michael@0 2836
michael@0 2837 nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager();
michael@0 2838 if (!manager) {
michael@0 2839 return NS_ERROR_UNEXPECTED;
michael@0 2840 }
michael@0 2841
michael@0 2842 return manager->CloneStorage(aStorage);
michael@0 2843 }
michael@0 2844
michael@0 2845 NS_IMETHODIMP
michael@0 2846 nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
michael@0 2847 {
michael@0 2848 NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
michael@0 2849 return NS_OK;
michael@0 2850 }
michael@0 2851
michael@0 2852 nsIChannel*
michael@0 2853 nsDocShell::GetCurrentDocChannel()
michael@0 2854 {
michael@0 2855 if (mContentViewer) {
michael@0 2856 nsIDocument* doc = mContentViewer->GetDocument();
michael@0 2857 if (doc) {
michael@0 2858 return doc->GetChannel();
michael@0 2859 }
michael@0 2860 }
michael@0 2861 return nullptr;
michael@0 2862 }
michael@0 2863
michael@0 2864 NS_IMETHODIMP
michael@0 2865 nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver)
michael@0 2866 {
michael@0 2867 nsWeakPtr weakObs = do_GetWeakReference(aObserver);
michael@0 2868 if (!weakObs) {
michael@0 2869 return NS_ERROR_FAILURE;
michael@0 2870 }
michael@0 2871 return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
michael@0 2872 }
michael@0 2873
michael@0 2874 NS_IMETHODIMP
michael@0 2875 nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
michael@0 2876 {
michael@0 2877 nsWeakPtr obs = do_GetWeakReference(aObserver);
michael@0 2878 return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
michael@0 2879 }
michael@0 2880
michael@0 2881 NS_IMETHODIMP
michael@0 2882 nsDocShell::NotifyScrollObservers()
michael@0 2883 {
michael@0 2884 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
michael@0 2885 while (iter.HasMore()) {
michael@0 2886 nsWeakPtr ref = iter.GetNext();
michael@0 2887 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
michael@0 2888 if (obs) {
michael@0 2889 obs->ScrollPositionChanged();
michael@0 2890 } else {
michael@0 2891 mScrollObservers.RemoveElement(ref);
michael@0 2892 }
michael@0 2893 }
michael@0 2894 return NS_OK;
michael@0 2895 }
michael@0 2896
michael@0 2897 //*****************************************************************************
michael@0 2898 // nsDocShell::nsIDocShellTreeItem
michael@0 2899 //*****************************************************************************
michael@0 2900
michael@0 2901 NS_IMETHODIMP
michael@0 2902 nsDocShell::GetName(nsAString& aName)
michael@0 2903 {
michael@0 2904 aName = mName;
michael@0 2905 return NS_OK;
michael@0 2906 }
michael@0 2907
michael@0 2908 NS_IMETHODIMP
michael@0 2909 nsDocShell::SetName(const nsAString& aName)
michael@0 2910 {
michael@0 2911 mName = aName;
michael@0 2912 return NS_OK;
michael@0 2913 }
michael@0 2914
michael@0 2915 NS_IMETHODIMP
michael@0 2916 nsDocShell::NameEquals(const char16_t *aName, bool *_retval)
michael@0 2917 {
michael@0 2918 NS_ENSURE_ARG_POINTER(aName);
michael@0 2919 NS_ENSURE_ARG_POINTER(_retval);
michael@0 2920 *_retval = mName.Equals(aName);
michael@0 2921 return NS_OK;
michael@0 2922 }
michael@0 2923
michael@0 2924 /* virtual */ int32_t
michael@0 2925 nsDocShell::ItemType()
michael@0 2926 {
michael@0 2927 return mItemType;
michael@0 2928 }
michael@0 2929
michael@0 2930 NS_IMETHODIMP
michael@0 2931 nsDocShell::GetItemType(int32_t * aItemType)
michael@0 2932 {
michael@0 2933 NS_ENSURE_ARG_POINTER(aItemType);
michael@0 2934
michael@0 2935 *aItemType = ItemType();
michael@0 2936 return NS_OK;
michael@0 2937 }
michael@0 2938
michael@0 2939 NS_IMETHODIMP
michael@0 2940 nsDocShell::SetItemType(int32_t aItemType)
michael@0 2941 {
michael@0 2942 NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
michael@0 2943
michael@0 2944 // Only allow setting the type on root docshells. Those would be the ones
michael@0 2945 // that have the docloader service as mParent or have no mParent at all.
michael@0 2946 nsCOMPtr<nsIDocumentLoader> docLoaderService =
michael@0 2947 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
michael@0 2948 NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
michael@0 2949
michael@0 2950 NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
michael@0 2951
michael@0 2952 mItemType = aItemType;
michael@0 2953
michael@0 2954 // disable auth prompting for anything but content
michael@0 2955 mAllowAuth = mItemType == typeContent;
michael@0 2956
michael@0 2957 nsRefPtr<nsPresContext> presContext = nullptr;
michael@0 2958 GetPresContext(getter_AddRefs(presContext));
michael@0 2959 if (presContext) {
michael@0 2960 presContext->UpdateIsChrome();
michael@0 2961 }
michael@0 2962
michael@0 2963 return NS_OK;
michael@0 2964 }
michael@0 2965
michael@0 2966 NS_IMETHODIMP
michael@0 2967 nsDocShell::GetParent(nsIDocShellTreeItem ** aParent)
michael@0 2968 {
michael@0 2969 if (!mParent) {
michael@0 2970 *aParent = nullptr;
michael@0 2971 } else {
michael@0 2972 CallQueryInterface(mParent, aParent);
michael@0 2973 }
michael@0 2974 // Note that in the case when the parent is not an nsIDocShellTreeItem we
michael@0 2975 // don't want to throw; we just want to return null.
michael@0 2976 return NS_OK;
michael@0 2977 }
michael@0 2978
michael@0 2979 already_AddRefed<nsDocShell>
michael@0 2980 nsDocShell::GetParentDocshell()
michael@0 2981 {
michael@0 2982 nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
michael@0 2983 return docshell.forget().downcast<nsDocShell>();
michael@0 2984 }
michael@0 2985
michael@0 2986 void
michael@0 2987 nsDocShell::RecomputeCanExecuteScripts()
michael@0 2988 {
michael@0 2989 bool old = mCanExecuteScripts;
michael@0 2990 nsRefPtr<nsDocShell> parent = GetParentDocshell();
michael@0 2991
michael@0 2992 // If we have no tree owner, that means that we've been detached from the
michael@0 2993 // docshell tree (this is distinct from having no parent dochshell, which
michael@0 2994 // is the case for root docshells). It would be nice to simply disallow
michael@0 2995 // script in detached docshells, but bug 986542 demonstrates that this
michael@0 2996 // behavior breaks at least one website.
michael@0 2997 //
michael@0 2998 // So instead, we use our previous value, unless mAllowJavascript has been
michael@0 2999 // explicitly set to false.
michael@0 3000 if (!mTreeOwner) {
michael@0 3001 mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
michael@0 3002 // If scripting has been explicitly disabled on our docshell, we're done.
michael@0 3003 } else if (!mAllowJavascript) {
michael@0 3004 mCanExecuteScripts = false;
michael@0 3005 // If we have a parent, inherit.
michael@0 3006 } else if (parent) {
michael@0 3007 mCanExecuteScripts = parent->mCanExecuteScripts;
michael@0 3008 // Otherwise, we're the root of the tree, and we haven't explicitly disabled
michael@0 3009 // script. Allow.
michael@0 3010 } else {
michael@0 3011 mCanExecuteScripts = true;
michael@0 3012 }
michael@0 3013
michael@0 3014 // Inform our active DOM window.
michael@0 3015 //
michael@0 3016 // This will pass the outer, which will be in the scope of the active inner.
michael@0 3017 if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
michael@0 3018 xpc::Scriptability& scriptability =
michael@0 3019 xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
michael@0 3020 scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
michael@0 3021 }
michael@0 3022
michael@0 3023 // If our value has changed, our children might be affected. Recompute their
michael@0 3024 // value as well.
michael@0 3025 if (old != mCanExecuteScripts) {
michael@0 3026 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 3027 while (iter.HasMore()) {
michael@0 3028 static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
michael@0 3029 }
michael@0 3030 }
michael@0 3031 }
michael@0 3032
michael@0 3033 nsresult
michael@0 3034 nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
michael@0 3035 {
michael@0 3036 bool wasFrame = IsFrame();
michael@0 3037
michael@0 3038 nsDocLoader::SetDocLoaderParent(aParent);
michael@0 3039
michael@0 3040 nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
michael@0 3041 if (wasFrame != IsFrame() && priorityGroup) {
michael@0 3042 priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
michael@0 3043 }
michael@0 3044
michael@0 3045 // Curse ambiguous nsISupports inheritance!
michael@0 3046 nsISupports* parent = GetAsSupports(aParent);
michael@0 3047
michael@0 3048 // If parent is another docshell, we inherit all their flags for
michael@0 3049 // allowing plugins, scripting etc.
michael@0 3050 bool value;
michael@0 3051 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
michael@0 3052 if (parentAsDocShell)
michael@0 3053 {
michael@0 3054 if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value)))
michael@0 3055 {
michael@0 3056 SetAllowPlugins(value);
michael@0 3057 }
michael@0 3058 if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value)))
michael@0 3059 {
michael@0 3060 SetAllowJavascript(value);
michael@0 3061 }
michael@0 3062 if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value)))
michael@0 3063 {
michael@0 3064 SetAllowMetaRedirects(value);
michael@0 3065 }
michael@0 3066 if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value)))
michael@0 3067 {
michael@0 3068 SetAllowSubframes(value);
michael@0 3069 }
michael@0 3070 if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value)))
michael@0 3071 {
michael@0 3072 SetAllowImages(value);
michael@0 3073 }
michael@0 3074 SetAllowMedia(parentAsDocShell->GetAllowMedia());
michael@0 3075 if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value)))
michael@0 3076 {
michael@0 3077 SetAllowWindowControl(value);
michael@0 3078 }
michael@0 3079 SetAllowContentRetargeting(
michael@0 3080 parentAsDocShell->GetAllowContentRetargeting());
michael@0 3081 if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value)))
michael@0 3082 {
michael@0 3083 SetIsActive(value);
michael@0 3084 }
michael@0 3085 if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
michael@0 3086 value = false;
michael@0 3087 }
michael@0 3088 SetAllowDNSPrefetch(value);
michael@0 3089 value = parentAsDocShell->GetAffectPrivateSessionLifetime();
michael@0 3090 SetAffectPrivateSessionLifetime(value);
michael@0 3091 uint32_t flags;
michael@0 3092 if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags)))
michael@0 3093 {
michael@0 3094 SetDefaultLoadFlags(flags);
michael@0 3095 }
michael@0 3096
michael@0 3097 }
michael@0 3098
michael@0 3099 nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
michael@0 3100 if (parentAsLoadContext &&
michael@0 3101 NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value)))
michael@0 3102 {
michael@0 3103 SetPrivateBrowsing(value);
michael@0 3104 }
michael@0 3105
michael@0 3106 nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
michael@0 3107 if (parentURIListener)
michael@0 3108 mContentListener->SetParentContentListener(parentURIListener);
michael@0 3109
michael@0 3110 // Our parent has changed. Recompute scriptability.
michael@0 3111 RecomputeCanExecuteScripts();
michael@0 3112
michael@0 3113 return NS_OK;
michael@0 3114 }
michael@0 3115
michael@0 3116 NS_IMETHODIMP
michael@0 3117 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
michael@0 3118 {
michael@0 3119 NS_ENSURE_ARG_POINTER(aParent);
michael@0 3120 *aParent = nullptr;
michael@0 3121
michael@0 3122 if (nsIDocShell::GetIsBrowserOrApp()) {
michael@0 3123 return NS_OK;
michael@0 3124 }
michael@0 3125
michael@0 3126 nsCOMPtr<nsIDocShellTreeItem> parent =
michael@0 3127 do_QueryInterface(GetAsSupports(mParent));
michael@0 3128 if (!parent)
michael@0 3129 return NS_OK;
michael@0 3130
michael@0 3131 if (parent->ItemType() == mItemType) {
michael@0 3132 parent.swap(*aParent);
michael@0 3133 }
michael@0 3134 return NS_OK;
michael@0 3135 }
michael@0 3136
michael@0 3137 NS_IMETHODIMP
michael@0 3138 nsDocShell::GetSameTypeParentIgnoreBrowserAndAppBoundaries(nsIDocShell** aParent)
michael@0 3139 {
michael@0 3140 NS_ENSURE_ARG_POINTER(aParent);
michael@0 3141 *aParent = nullptr;
michael@0 3142
michael@0 3143 nsCOMPtr<nsIDocShellTreeItem> parent =
michael@0 3144 do_QueryInterface(GetAsSupports(mParent));
michael@0 3145 if (!parent)
michael@0 3146 return NS_OK;
michael@0 3147
michael@0 3148 if (parent->ItemType() == mItemType) {
michael@0 3149 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent);
michael@0 3150 parentDS.forget(aParent);
michael@0 3151 }
michael@0 3152 return NS_OK;
michael@0 3153 }
michael@0 3154
michael@0 3155 NS_IMETHODIMP
michael@0 3156 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
michael@0 3157 {
michael@0 3158 NS_ENSURE_ARG_POINTER(aRootTreeItem);
michael@0 3159 *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
michael@0 3160
michael@0 3161 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 3162 NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
michael@0 3163 while (parent) {
michael@0 3164 *aRootTreeItem = parent;
michael@0 3165 NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)),
michael@0 3166 NS_ERROR_FAILURE);
michael@0 3167 }
michael@0 3168 NS_ADDREF(*aRootTreeItem);
michael@0 3169 return NS_OK;
michael@0 3170 }
michael@0 3171
michael@0 3172 NS_IMETHODIMP
michael@0 3173 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
michael@0 3174 {
michael@0 3175 NS_ENSURE_ARG_POINTER(aRootTreeItem);
michael@0 3176 *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
michael@0 3177
michael@0 3178 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 3179 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
michael@0 3180 NS_ERROR_FAILURE);
michael@0 3181 while (parent) {
michael@0 3182 *aRootTreeItem = parent;
michael@0 3183 NS_ENSURE_SUCCESS((*aRootTreeItem)->
michael@0 3184 GetSameTypeParent(getter_AddRefs(parent)),
michael@0 3185 NS_ERROR_FAILURE);
michael@0 3186 }
michael@0 3187 NS_ADDREF(*aRootTreeItem);
michael@0 3188 return NS_OK;
michael@0 3189 }
michael@0 3190
michael@0 3191 /* static */
michael@0 3192 bool
michael@0 3193 nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
michael@0 3194 nsIDocShellTreeItem* aAccessingItem,
michael@0 3195 bool aConsiderOpener)
michael@0 3196 {
michael@0 3197 NS_PRECONDITION(aTargetItem, "Must have target item!");
michael@0 3198
michael@0 3199 if (!gValidateOrigin || !aAccessingItem) {
michael@0 3200 // Good to go
michael@0 3201 return true;
michael@0 3202 }
michael@0 3203
michael@0 3204 // XXXbz should we care if aAccessingItem or the document therein is
michael@0 3205 // chrome? Should those get extra privileges?
michael@0 3206
michael@0 3207 // For historical context, see:
michael@0 3208 //
michael@0 3209 // Bug 13871: Prevent frameset spoofing
michael@0 3210 // Bug 103638: Targets with same name in different windows open in wrong
michael@0 3211 // window with javascript
michael@0 3212 // Bug 408052: Adopt "ancestor" frame navigation policy
michael@0 3213
michael@0 3214 // Now do a security check.
michael@0 3215 //
michael@0 3216 // Disallow navigation if the two frames are not part of the same app, or if
michael@0 3217 // they have different is-in-browser-element states.
michael@0 3218 //
michael@0 3219 // Allow navigation if
michael@0 3220 // 1) aAccessingItem can script aTargetItem or one of its ancestors in
michael@0 3221 // the frame hierarchy or
michael@0 3222 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
michael@0 3223 // 3) aTargetItem is a top-level frame and aAccessingItem can target
michael@0 3224 // its opener per rule (1) or (2).
michael@0 3225
michael@0 3226 if (aTargetItem == aAccessingItem) {
michael@0 3227 // A frame is allowed to navigate itself.
michael@0 3228 return true;
michael@0 3229 }
michael@0 3230
michael@0 3231 nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
michael@0 3232 nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
michael@0 3233 if (!!targetDS != !!accessingDS) {
michael@0 3234 // We must be able to convert both or neither to nsIDocShell.
michael@0 3235 return false;
michael@0 3236 }
michael@0 3237
michael@0 3238 if (targetDS && accessingDS &&
michael@0 3239 (targetDS->GetIsInBrowserElement() !=
michael@0 3240 accessingDS->GetIsInBrowserElement() ||
michael@0 3241 targetDS->GetAppId() != accessingDS->GetAppId())) {
michael@0 3242 return false;
michael@0 3243 }
michael@0 3244
michael@0 3245 nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
michael@0 3246 aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
michael@0 3247
michael@0 3248 if (aTargetItem == accessingRoot) {
michael@0 3249 // A frame can navigate its root.
michael@0 3250 return true;
michael@0 3251 }
michael@0 3252
michael@0 3253 // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
michael@0 3254 nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
michael@0 3255 do {
michael@0 3256 if (ValidateOrigin(aAccessingItem, target)) {
michael@0 3257 return true;
michael@0 3258 }
michael@0 3259
michael@0 3260 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 3261 target->GetSameTypeParent(getter_AddRefs(parent));
michael@0 3262 parent.swap(target);
michael@0 3263 } while (target);
michael@0 3264
michael@0 3265 nsCOMPtr<nsIDocShellTreeItem> targetRoot;
michael@0 3266 aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
michael@0 3267
michael@0 3268 if (aTargetItem != targetRoot) {
michael@0 3269 // target is a subframe, not in accessor's frame hierarchy, and all its
michael@0 3270 // ancestors have origins different from that of the accessor. Don't
michael@0 3271 // allow access.
michael@0 3272 return false;
michael@0 3273 }
michael@0 3274
michael@0 3275 if (!aConsiderOpener) {
michael@0 3276 // All done here
michael@0 3277 return false;
michael@0 3278 }
michael@0 3279
michael@0 3280 nsCOMPtr<nsIDOMWindow> targetWindow = do_GetInterface(aTargetItem);
michael@0 3281 if (!targetWindow) {
michael@0 3282 NS_ERROR("This should not happen, really");
michael@0 3283 return false;
michael@0 3284 }
michael@0 3285
michael@0 3286 nsCOMPtr<nsIDOMWindow> targetOpener;
michael@0 3287 targetWindow->GetOpener(getter_AddRefs(targetOpener));
michael@0 3288 nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
michael@0 3289 nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
michael@0 3290
michael@0 3291 if (!openerItem) {
michael@0 3292 return false;
michael@0 3293 }
michael@0 3294
michael@0 3295 return CanAccessItem(openerItem, aAccessingItem, false);
michael@0 3296 }
michael@0 3297
michael@0 3298 static bool
michael@0 3299 ItemIsActive(nsIDocShellTreeItem *aItem)
michael@0 3300 {
michael@0 3301 nsCOMPtr<nsIDOMWindow> window(do_GetInterface(aItem));
michael@0 3302
michael@0 3303 if (window) {
michael@0 3304 bool isClosed;
michael@0 3305
michael@0 3306 if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) {
michael@0 3307 return true;
michael@0 3308 }
michael@0 3309 }
michael@0 3310
michael@0 3311 return false;
michael@0 3312 }
michael@0 3313
michael@0 3314 NS_IMETHODIMP
michael@0 3315 nsDocShell::FindItemWithName(const char16_t * aName,
michael@0 3316 nsISupports * aRequestor,
michael@0 3317 nsIDocShellTreeItem * aOriginalRequestor,
michael@0 3318 nsIDocShellTreeItem ** _retval)
michael@0 3319 {
michael@0 3320 NS_ENSURE_ARG(aName);
michael@0 3321 NS_ENSURE_ARG_POINTER(_retval);
michael@0 3322
michael@0 3323 // If we don't find one, we return NS_OK and a null result
michael@0 3324 *_retval = nullptr;
michael@0 3325
michael@0 3326 if (!*aName)
michael@0 3327 return NS_OK;
michael@0 3328
michael@0 3329 if (aRequestor) {
michael@0 3330 // If aRequestor is not null we don't need to check special names, so
michael@0 3331 // just hand straight off to the search by actual name function.
michael@0 3332 return DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
michael@0 3333 _retval);
michael@0 3334 } else {
michael@0 3335
michael@0 3336 // This is the entry point into the target-finding algorithm. Check
michael@0 3337 // for special names. This should only be done once, hence the check
michael@0 3338 // for a null aRequestor.
michael@0 3339
michael@0 3340 nsCOMPtr<nsIDocShellTreeItem> foundItem;
michael@0 3341 nsDependentString name(aName);
michael@0 3342 if (name.LowerCaseEqualsLiteral("_self")) {
michael@0 3343 foundItem = this;
michael@0 3344 }
michael@0 3345 else if (name.LowerCaseEqualsLiteral("_blank"))
michael@0 3346 {
michael@0 3347 // Just return null. Caller must handle creating a new window with
michael@0 3348 // a blank name himself.
michael@0 3349 return NS_OK;
michael@0 3350 }
michael@0 3351 else if (name.LowerCaseEqualsLiteral("_parent"))
michael@0 3352 {
michael@0 3353 GetSameTypeParent(getter_AddRefs(foundItem));
michael@0 3354 if(!foundItem)
michael@0 3355 foundItem = this;
michael@0 3356 }
michael@0 3357 else if (name.LowerCaseEqualsLiteral("_top"))
michael@0 3358 {
michael@0 3359 GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
michael@0 3360 NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
michael@0 3361 }
michael@0 3362 // _main is an IE target which should be case-insensitive but isn't
michael@0 3363 // see bug 217886 for details
michael@0 3364 else if (name.LowerCaseEqualsLiteral("_content") ||
michael@0 3365 name.EqualsLiteral("_main"))
michael@0 3366 {
michael@0 3367 // Must pass our same type root as requestor to the
michael@0 3368 // treeowner to make sure things work right.
michael@0 3369 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 3370 GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 3371 if (mTreeOwner) {
michael@0 3372 NS_ASSERTION(root, "Must have this; worst case it's us!");
michael@0 3373 mTreeOwner->FindItemWithName(aName, root, aOriginalRequestor,
michael@0 3374 getter_AddRefs(foundItem));
michael@0 3375 }
michael@0 3376 #ifdef DEBUG
michael@0 3377 else {
michael@0 3378 NS_ERROR("Someone isn't setting up the tree owner. "
michael@0 3379 "You might like to try that. "
michael@0 3380 "Things will.....you know, work.");
michael@0 3381 // Note: _content should always exist. If we don't have one
michael@0 3382 // hanging off the treeowner, just create a named window....
michael@0 3383 // so don't return here, in case we did that and can now find
michael@0 3384 // it.
michael@0 3385 // XXXbz should we be using |root| instead of creating
michael@0 3386 // a new window?
michael@0 3387 }
michael@0 3388 #endif
michael@0 3389 } else {
michael@0 3390 // Do the search for item by an actual name.
michael@0 3391 DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
michael@0 3392 getter_AddRefs(foundItem));
michael@0 3393 }
michael@0 3394
michael@0 3395 if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
michael@0 3396 foundItem = nullptr;
michael@0 3397 }
michael@0 3398
michael@0 3399 // DoFindItemWithName only returns active items and we don't check if
michael@0 3400 // the item is active for the special cases.
michael@0 3401 if (foundItem) {
michael@0 3402 foundItem.swap(*_retval);
michael@0 3403 }
michael@0 3404 return NS_OK;
michael@0 3405 }
michael@0 3406 }
michael@0 3407
michael@0 3408 nsresult
michael@0 3409 nsDocShell::DoFindItemWithName(const char16_t* aName,
michael@0 3410 nsISupports* aRequestor,
michael@0 3411 nsIDocShellTreeItem* aOriginalRequestor,
michael@0 3412 nsIDocShellTreeItem** _retval)
michael@0 3413 {
michael@0 3414 // First we check our name.
michael@0 3415 if (mName.Equals(aName) && ItemIsActive(this) &&
michael@0 3416 CanAccessItem(this, aOriginalRequestor)) {
michael@0 3417 NS_ADDREF(*_retval = this);
michael@0 3418 return NS_OK;
michael@0 3419 }
michael@0 3420
michael@0 3421 // This QI may fail, but the places where we want to compare, comparing
michael@0 3422 // against nullptr serves the same purpose.
michael@0 3423 nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
michael@0 3424
michael@0 3425 // Second we check our children making sure not to ask a child if
michael@0 3426 // it is the aRequestor.
michael@0 3427 #ifdef DEBUG
michael@0 3428 nsresult rv =
michael@0 3429 #endif
michael@0 3430 FindChildWithName(aName, true, true, reqAsTreeItem,
michael@0 3431 aOriginalRequestor, _retval);
michael@0 3432 NS_ASSERTION(NS_SUCCEEDED(rv),
michael@0 3433 "FindChildWithName should not be failing here.");
michael@0 3434 if (*_retval)
michael@0 3435 return NS_OK;
michael@0 3436
michael@0 3437 // Third if we have a parent and it isn't the requestor then we
michael@0 3438 // should ask it to do the search. If it is the requestor we
michael@0 3439 // should just stop here and let the parent do the rest. If we
michael@0 3440 // don't have a parent, then we should ask the
michael@0 3441 // docShellTreeOwner to do the search.
michael@0 3442 nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
michael@0 3443 do_QueryInterface(GetAsSupports(mParent));
michael@0 3444 if (parentAsTreeItem) {
michael@0 3445 if (parentAsTreeItem == reqAsTreeItem)
michael@0 3446 return NS_OK;
michael@0 3447
michael@0 3448 if (parentAsTreeItem->ItemType() == mItemType) {
michael@0 3449 return parentAsTreeItem->
michael@0 3450 FindItemWithName(aName,
michael@0 3451 static_cast<nsIDocShellTreeItem*>
michael@0 3452 (this),
michael@0 3453 aOriginalRequestor,
michael@0 3454 _retval);
michael@0 3455 }
michael@0 3456 }
michael@0 3457
michael@0 3458 // If the parent is null or not of the same type fall through and ask tree
michael@0 3459 // owner.
michael@0 3460
michael@0 3461 // This may fail, but comparing against null serves the same purpose
michael@0 3462 nsCOMPtr<nsIDocShellTreeOwner>
michael@0 3463 reqAsTreeOwner(do_QueryInterface(aRequestor));
michael@0 3464
michael@0 3465 if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
michael@0 3466 return mTreeOwner->
michael@0 3467 FindItemWithName(aName, this, aOriginalRequestor, _retval);
michael@0 3468 }
michael@0 3469
michael@0 3470 return NS_OK;
michael@0 3471 }
michael@0 3472
michael@0 3473 bool
michael@0 3474 nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell)
michael@0 3475 {
michael@0 3476 // If no target then not sandboxed.
michael@0 3477 if (!aTargetDocShell) {
michael@0 3478 return false;
michael@0 3479 }
michael@0 3480
michael@0 3481 // We cannot be sandboxed from ourselves.
michael@0 3482 if (aTargetDocShell == this) {
michael@0 3483 return false;
michael@0 3484 }
michael@0 3485
michael@0 3486 // Default the sandbox flags to our flags, so that if we can't retrieve the
michael@0 3487 // active document, we will still enforce our own.
michael@0 3488 uint32_t sandboxFlags = mSandboxFlags;
michael@0 3489 if (mContentViewer) {
michael@0 3490 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
michael@0 3491 if (doc) {
michael@0 3492 sandboxFlags = doc->GetSandboxFlags();
michael@0 3493 }
michael@0 3494 }
michael@0 3495
michael@0 3496 // If no flags, we are not sandboxed at all.
michael@0 3497 if (!sandboxFlags) {
michael@0 3498 return false;
michael@0 3499 }
michael@0 3500
michael@0 3501 // If aTargetDocShell has an ancestor, it is not top level.
michael@0 3502 nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
michael@0 3503 aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
michael@0 3504 if (ancestorOfTarget) {
michael@0 3505 do {
michael@0 3506 // We are not sandboxed if we are an ancestor of target.
michael@0 3507 if (ancestorOfTarget == this) {
michael@0 3508 return false;
michael@0 3509 }
michael@0 3510 nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
michael@0 3511 ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
michael@0 3512 tempTreeItem.swap(ancestorOfTarget);
michael@0 3513 } while (ancestorOfTarget);
michael@0 3514
michael@0 3515 // Otherwise, we are sandboxed from aTargetDocShell.
michael@0 3516 return true;
michael@0 3517 }
michael@0 3518
michael@0 3519 // aTargetDocShell is top level, are we the "one permitted sandboxed
michael@0 3520 // navigator", i.e. did we open aTargetDocShell?
michael@0 3521 nsCOMPtr<nsIDocShell> permittedNavigator;
michael@0 3522 aTargetDocShell->
michael@0 3523 GetOnePermittedSandboxedNavigator(getter_AddRefs(permittedNavigator));
michael@0 3524 if (permittedNavigator == this) {
michael@0 3525 return false;
michael@0 3526 }
michael@0 3527
michael@0 3528 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
michael@0 3529 // from our top.
michael@0 3530 if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
michael@0 3531 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
michael@0 3532 GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
michael@0 3533 if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) {
michael@0 3534 return false;
michael@0 3535 }
michael@0 3536 }
michael@0 3537
michael@0 3538 // Otherwise, we are sandboxed from aTargetDocShell.
michael@0 3539 return true;
michael@0 3540 }
michael@0 3541
michael@0 3542 NS_IMETHODIMP
michael@0 3543 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)
michael@0 3544 {
michael@0 3545 NS_ENSURE_ARG_POINTER(aTreeOwner);
michael@0 3546
michael@0 3547 *aTreeOwner = mTreeOwner;
michael@0 3548 NS_IF_ADDREF(*aTreeOwner);
michael@0 3549 return NS_OK;
michael@0 3550 }
michael@0 3551
michael@0 3552 #ifdef DEBUG_DOCSHELL_FOCUS
michael@0 3553 static void
michael@0 3554 PrintDocTree(nsIDocShellTreeItem * aParentNode, int aLevel)
michael@0 3555 {
michael@0 3556 for (int32_t i=0;i<aLevel;i++) printf(" ");
michael@0 3557
michael@0 3558 int32_t childWebshellCount;
michael@0 3559 aParentNode->GetChildCount(&childWebshellCount);
michael@0 3560 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
michael@0 3561 int32_t type = aParentNode->ItemType();
michael@0 3562 nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
michael@0 3563 nsRefPtr<nsPresContext> presContext;
michael@0 3564 parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
michael@0 3565 nsIDocument *doc = presShell->GetDocument();
michael@0 3566
michael@0 3567 nsCOMPtr<nsIDOMWindow> domwin(doc->GetWindow());
michael@0 3568
michael@0 3569 nsCOMPtr<nsIWidget> widget;
michael@0 3570 nsViewManager* vm = presShell->GetViewManager();
michael@0 3571 if (vm) {
michael@0 3572 vm->GetWidget(getter_AddRefs(widget));
michael@0 3573 }
michael@0 3574 dom::Element* rootElement = doc->GetRootElement();
michael@0 3575
michael@0 3576 printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
michael@0 3577 (void*)parentAsDocShell.get(),
michael@0 3578 type==nsIDocShellTreeItem::typeChrome?"Chr":"Con",
michael@0 3579 (void*)doc, (void*)domwin.get(),
michael@0 3580 (void*)presContext->EventStateManager(), (void*)rootElement);
michael@0 3581
michael@0 3582 if (childWebshellCount > 0) {
michael@0 3583 for (int32_t i=0;i<childWebshellCount;i++) {
michael@0 3584 nsCOMPtr<nsIDocShellTreeItem> child;
michael@0 3585 aParentNode->GetChildAt(i, getter_AddRefs(child));
michael@0 3586 PrintDocTree(child, aLevel+1);
michael@0 3587 }
michael@0 3588 }
michael@0 3589 }
michael@0 3590
michael@0 3591 static void
michael@0 3592 PrintDocTree(nsIDocShellTreeItem * aParentNode)
michael@0 3593 {
michael@0 3594 NS_ASSERTION(aParentNode, "Pointer is null!");
michael@0 3595
michael@0 3596 nsCOMPtr<nsIDocShellTreeItem> parentItem;
michael@0 3597 aParentNode->GetParent(getter_AddRefs(parentItem));
michael@0 3598 while (parentItem) {
michael@0 3599 nsCOMPtr<nsIDocShellTreeItem>tmp;
michael@0 3600 parentItem->GetParent(getter_AddRefs(tmp));
michael@0 3601 if (!tmp) {
michael@0 3602 break;
michael@0 3603 }
michael@0 3604 parentItem = tmp;
michael@0 3605 }
michael@0 3606
michael@0 3607 if (!parentItem) {
michael@0 3608 parentItem = aParentNode;
michael@0 3609 }
michael@0 3610
michael@0 3611 PrintDocTree(parentItem, 0);
michael@0 3612 }
michael@0 3613 #endif
michael@0 3614
michael@0 3615 NS_IMETHODIMP
michael@0 3616 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
michael@0 3617 {
michael@0 3618 #ifdef DEBUG_DOCSHELL_FOCUS
michael@0 3619 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
michael@0 3620 if (item) {
michael@0 3621 PrintDocTree(item);
michael@0 3622 }
michael@0 3623 #endif
michael@0 3624
michael@0 3625 // Don't automatically set the progress based on the tree owner for frames
michael@0 3626 if (!IsFrame()) {
michael@0 3627 nsCOMPtr<nsIWebProgress> webProgress =
michael@0 3628 do_QueryInterface(GetAsSupports(this));
michael@0 3629
michael@0 3630 if (webProgress) {
michael@0 3631 nsCOMPtr<nsIWebProgressListener>
michael@0 3632 oldListener(do_QueryInterface(mTreeOwner));
michael@0 3633 nsCOMPtr<nsIWebProgressListener>
michael@0 3634 newListener(do_QueryInterface(aTreeOwner));
michael@0 3635
michael@0 3636 if (oldListener) {
michael@0 3637 webProgress->RemoveProgressListener(oldListener);
michael@0 3638 }
michael@0 3639
michael@0 3640 if (newListener) {
michael@0 3641 webProgress->AddProgressListener(newListener,
michael@0 3642 nsIWebProgress::NOTIFY_ALL);
michael@0 3643 }
michael@0 3644 }
michael@0 3645 }
michael@0 3646
michael@0 3647 mTreeOwner = aTreeOwner; // Weak reference per API
michael@0 3648
michael@0 3649 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 3650 while (iter.HasMore()) {
michael@0 3651 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
michael@0 3652 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
michael@0 3653
michael@0 3654 if (child->ItemType() == mItemType)
michael@0 3655 child->SetTreeOwner(aTreeOwner);
michael@0 3656 }
michael@0 3657
michael@0 3658 // Our tree owner has changed. Recompute scriptability.
michael@0 3659 //
michael@0 3660 // Note that this is near-redundant with the recomputation in
michael@0 3661 // SetDocLoaderParent(), but not so for the root DocShell, where the call to
michael@0 3662 // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
michael@0 3663 // and we never set another parent. Given that this is neither expensive nor
michael@0 3664 // performance-critical, let's be safe and unconditionally recompute this
michael@0 3665 // state whenever dependent state changes.
michael@0 3666 RecomputeCanExecuteScripts();
michael@0 3667
michael@0 3668 return NS_OK;
michael@0 3669 }
michael@0 3670
michael@0 3671 NS_IMETHODIMP
michael@0 3672 nsDocShell::SetChildOffset(uint32_t aChildOffset)
michael@0 3673 {
michael@0 3674 mChildOffset = aChildOffset;
michael@0 3675 return NS_OK;
michael@0 3676 }
michael@0 3677
michael@0 3678 NS_IMETHODIMP
michael@0 3679 nsDocShell::GetHistoryID(uint64_t* aID)
michael@0 3680 {
michael@0 3681 *aID = mHistoryID;
michael@0 3682 return NS_OK;
michael@0 3683 }
michael@0 3684
michael@0 3685 NS_IMETHODIMP
michael@0 3686 nsDocShell::GetIsInUnload(bool* aIsInUnload)
michael@0 3687 {
michael@0 3688 *aIsInUnload = mFiredUnloadEvent;
michael@0 3689 return NS_OK;
michael@0 3690 }
michael@0 3691
michael@0 3692 NS_IMETHODIMP
michael@0 3693 nsDocShell::GetChildCount(int32_t * aChildCount)
michael@0 3694 {
michael@0 3695 NS_ENSURE_ARG_POINTER(aChildCount);
michael@0 3696 *aChildCount = mChildList.Length();
michael@0 3697 return NS_OK;
michael@0 3698 }
michael@0 3699
michael@0 3700
michael@0 3701
michael@0 3702 NS_IMETHODIMP
michael@0 3703 nsDocShell::AddChild(nsIDocShellTreeItem * aChild)
michael@0 3704 {
michael@0 3705 NS_ENSURE_ARG_POINTER(aChild);
michael@0 3706
michael@0 3707 nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
michael@0 3708 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
michael@0 3709
michael@0 3710 // Make sure we're not creating a loop in the docshell tree
michael@0 3711 nsDocLoader* ancestor = this;
michael@0 3712 do {
michael@0 3713 if (childAsDocLoader == ancestor) {
michael@0 3714 return NS_ERROR_ILLEGAL_VALUE;
michael@0 3715 }
michael@0 3716 ancestor = ancestor->GetParent();
michael@0 3717 } while (ancestor);
michael@0 3718
michael@0 3719 // Make sure to remove the child from its current parent.
michael@0 3720 nsDocLoader* childsParent = childAsDocLoader->GetParent();
michael@0 3721 if (childsParent) {
michael@0 3722 childsParent->RemoveChildLoader(childAsDocLoader);
michael@0 3723 }
michael@0 3724
michael@0 3725 // Make sure to clear the treeowner in case this child is a different type
michael@0 3726 // from us.
michael@0 3727 aChild->SetTreeOwner(nullptr);
michael@0 3728
michael@0 3729 nsresult res = AddChildLoader(childAsDocLoader);
michael@0 3730 NS_ENSURE_SUCCESS(res, res);
michael@0 3731 NS_ASSERTION(!mChildList.IsEmpty(),
michael@0 3732 "child list must not be empty after a successful add");
michael@0 3733
michael@0 3734 nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
michael@0 3735 bool dynamic = false;
michael@0 3736 childDocShell->GetCreatedDynamically(&dynamic);
michael@0 3737 if (!dynamic) {
michael@0 3738 nsCOMPtr<nsISHEntry> currentSH;
michael@0 3739 bool oshe = false;
michael@0 3740 GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
michael@0 3741 if (currentSH) {
michael@0 3742 currentSH->HasDynamicallyAddedChild(&dynamic);
michael@0 3743 }
michael@0 3744 }
michael@0 3745 childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
michael@0 3746
michael@0 3747 /* Set the child's global history if the parent has one */
michael@0 3748 if (mUseGlobalHistory) {
michael@0 3749 childDocShell->SetUseGlobalHistory(true);
michael@0 3750 }
michael@0 3751
michael@0 3752 if (aChild->ItemType() != mItemType) {
michael@0 3753 return NS_OK;
michael@0 3754 }
michael@0 3755
michael@0 3756 aChild->SetTreeOwner(mTreeOwner);
michael@0 3757
michael@0 3758 nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
michael@0 3759 if (!childAsDocShell)
michael@0 3760 return NS_OK;
michael@0 3761
michael@0 3762 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
michael@0 3763
michael@0 3764 // Now take this document's charset and set the child's parentCharset field
michael@0 3765 // to it. We'll later use that field, in the loading process, for the
michael@0 3766 // charset choosing algorithm.
michael@0 3767 // If we fail, at any point, we just return NS_OK.
michael@0 3768 // This code has some performance impact. But this will be reduced when
michael@0 3769 // the current charset will finally be stored as an Atom, avoiding the
michael@0 3770 // alias resolution extra look-up.
michael@0 3771
michael@0 3772 // we are NOT going to propagate the charset is this Chrome's docshell
michael@0 3773 if (mItemType == nsIDocShellTreeItem::typeChrome)
michael@0 3774 return NS_OK;
michael@0 3775
michael@0 3776 // get the parent's current charset
michael@0 3777 if (!mContentViewer)
michael@0 3778 return NS_OK;
michael@0 3779 nsIDocument* doc = mContentViewer->GetDocument();
michael@0 3780 if (!doc)
michael@0 3781 return NS_OK;
michael@0 3782
michael@0 3783 bool isWyciwyg = false;
michael@0 3784
michael@0 3785 if (mCurrentURI) {
michael@0 3786 // Check if the url is wyciwyg
michael@0 3787 mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
michael@0 3788 }
michael@0 3789
michael@0 3790 if (!isWyciwyg) {
michael@0 3791 // If this docshell is loaded from a wyciwyg: URI, don't
michael@0 3792 // advertise our charset since it does not in any way reflect
michael@0 3793 // the actual source charset, which is what we're trying to
michael@0 3794 // expose here.
michael@0 3795
michael@0 3796 const nsACString &parentCS = doc->GetDocumentCharacterSet();
michael@0 3797 int32_t charsetSource = doc->GetDocumentCharacterSetSource();
michael@0 3798 // set the child's parentCharset
michael@0 3799 childAsDocShell->SetParentCharset(parentCS,
michael@0 3800 charsetSource,
michael@0 3801 doc->NodePrincipal());
michael@0 3802 }
michael@0 3803
michael@0 3804 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
michael@0 3805
michael@0 3806 return NS_OK;
michael@0 3807 }
michael@0 3808
michael@0 3809 NS_IMETHODIMP
michael@0 3810 nsDocShell::RemoveChild(nsIDocShellTreeItem * aChild)
michael@0 3811 {
michael@0 3812 NS_ENSURE_ARG_POINTER(aChild);
michael@0 3813
michael@0 3814 nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
michael@0 3815 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
michael@0 3816
michael@0 3817 nsresult rv = RemoveChildLoader(childAsDocLoader);
michael@0 3818 NS_ENSURE_SUCCESS(rv, rv);
michael@0 3819
michael@0 3820 aChild->SetTreeOwner(nullptr);
michael@0 3821
michael@0 3822 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
michael@0 3823 }
michael@0 3824
michael@0 3825 NS_IMETHODIMP
michael@0 3826 nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem ** aChild)
michael@0 3827 {
michael@0 3828 NS_ENSURE_ARG_POINTER(aChild);
michael@0 3829
michael@0 3830 #ifdef DEBUG
michael@0 3831 if (aIndex < 0) {
michael@0 3832 NS_WARNING("Negative index passed to GetChildAt");
michael@0 3833 } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
michael@0 3834 NS_WARNING("Too large an index passed to GetChildAt");
michael@0 3835 }
michael@0 3836 #endif
michael@0 3837
michael@0 3838 nsIDocumentLoader* child = ChildAt(aIndex);
michael@0 3839 NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
michael@0 3840
michael@0 3841 return CallQueryInterface(child, aChild);
michael@0 3842 }
michael@0 3843
michael@0 3844 NS_IMETHODIMP
michael@0 3845 nsDocShell::FindChildWithName(const char16_t * aName,
michael@0 3846 bool aRecurse, bool aSameType,
michael@0 3847 nsIDocShellTreeItem * aRequestor,
michael@0 3848 nsIDocShellTreeItem * aOriginalRequestor,
michael@0 3849 nsIDocShellTreeItem ** _retval)
michael@0 3850 {
michael@0 3851 NS_ENSURE_ARG(aName);
michael@0 3852 NS_ENSURE_ARG_POINTER(_retval);
michael@0 3853
michael@0 3854 *_retval = nullptr; // if we don't find one, we return NS_OK and a null result
michael@0 3855
michael@0 3856 if (!*aName)
michael@0 3857 return NS_OK;
michael@0 3858
michael@0 3859 nsXPIDLString childName;
michael@0 3860 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 3861 while (iter.HasMore()) {
michael@0 3862 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
michael@0 3863 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
michael@0 3864 int32_t childType = child->ItemType();
michael@0 3865
michael@0 3866 if (aSameType && (childType != mItemType))
michael@0 3867 continue;
michael@0 3868
michael@0 3869 bool childNameEquals = false;
michael@0 3870 child->NameEquals(aName, &childNameEquals);
michael@0 3871 if (childNameEquals && ItemIsActive(child) &&
michael@0 3872 CanAccessItem(child, aOriginalRequestor)) {
michael@0 3873 child.swap(*_retval);
michael@0 3874 break;
michael@0 3875 }
michael@0 3876
michael@0 3877 if (childType != mItemType) //Only ask it to check children if it is same type
michael@0 3878 continue;
michael@0 3879
michael@0 3880 if (aRecurse && (aRequestor != child)) // Only ask the child if it isn't the requestor
michael@0 3881 {
michael@0 3882 // See if child contains the shell with the given name
michael@0 3883 #ifdef DEBUG
michael@0 3884 nsresult rv =
michael@0 3885 #endif
michael@0 3886 child->FindChildWithName(aName, true,
michael@0 3887 aSameType,
michael@0 3888 static_cast<nsIDocShellTreeItem*>
michael@0 3889 (this),
michael@0 3890 aOriginalRequestor,
michael@0 3891 _retval);
michael@0 3892 NS_ASSERTION(NS_SUCCEEDED(rv),
michael@0 3893 "FindChildWithName should not fail here");
michael@0 3894 if (*_retval) // found it
michael@0 3895 return NS_OK;
michael@0 3896 }
michael@0 3897 }
michael@0 3898 return NS_OK;
michael@0 3899 }
michael@0 3900
michael@0 3901 NS_IMETHODIMP
michael@0 3902 nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry ** aResult)
michael@0 3903 {
michael@0 3904 nsresult rv = NS_OK;
michael@0 3905
michael@0 3906 NS_ENSURE_ARG_POINTER(aResult);
michael@0 3907 *aResult = nullptr;
michael@0 3908
michael@0 3909
michael@0 3910 // A nsISHEntry for a child is *only* available when the parent is in
michael@0 3911 // the progress of loading a document too...
michael@0 3912
michael@0 3913 if (mLSHE) {
michael@0 3914 /* Before looking for the subframe's url, check
michael@0 3915 * the expiration status of the parent. If the parent
michael@0 3916 * has expired from cache, then subframes will not be
michael@0 3917 * loaded from history in certain situations.
michael@0 3918 */
michael@0 3919 bool parentExpired=false;
michael@0 3920 mLSHE->GetExpirationStatus(&parentExpired);
michael@0 3921
michael@0 3922 /* Get the parent's Load Type so that it can be set on the child too.
michael@0 3923 * By default give a loadHistory value
michael@0 3924 */
michael@0 3925 uint32_t loadType = nsIDocShellLoadInfo::loadHistory;
michael@0 3926 mLSHE->GetLoadType(&loadType);
michael@0 3927 // If the user did a shift-reload on this frameset page,
michael@0 3928 // we don't want to load the subframes from history.
michael@0 3929 if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
michael@0 3930 loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
michael@0 3931 loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
michael@0 3932 loadType == nsIDocShellLoadInfo::loadRefresh)
michael@0 3933 return rv;
michael@0 3934
michael@0 3935 /* If the user pressed reload and the parent frame has expired
michael@0 3936 * from cache, we do not want to load the child frame from history.
michael@0 3937 */
michael@0 3938 if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
michael@0 3939 // The parent has expired. Return null.
michael@0 3940 *aResult = nullptr;
michael@0 3941 return rv;
michael@0 3942 }
michael@0 3943
michael@0 3944 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
michael@0 3945 if (container) {
michael@0 3946 // Get the child subframe from session history.
michael@0 3947 rv = container->GetChildAt(aChildOffset, aResult);
michael@0 3948 if (*aResult)
michael@0 3949 (*aResult)->SetLoadType(loadType);
michael@0 3950 }
michael@0 3951 }
michael@0 3952 return rv;
michael@0 3953 }
michael@0 3954
michael@0 3955 NS_IMETHODIMP
michael@0 3956 nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
michael@0 3957 int32_t aChildOffset, uint32_t loadType,
michael@0 3958 bool aCloneChildren)
michael@0 3959 {
michael@0 3960 nsresult rv;
michael@0 3961
michael@0 3962 if (mLSHE && loadType != LOAD_PUSHSTATE) {
michael@0 3963 /* You get here if you are currently building a
michael@0 3964 * hierarchy ie.,you just visited a frameset page
michael@0 3965 */
michael@0 3966 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
michael@0 3967 if (container) {
michael@0 3968 rv = container->AddChild(aNewEntry, aChildOffset);
michael@0 3969 }
michael@0 3970 }
michael@0 3971 else if (!aCloneRef) {
michael@0 3972 /* This is an initial load in some subframe. Just append it if we can */
michael@0 3973 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
michael@0 3974 if (container) {
michael@0 3975 rv = container->AddChild(aNewEntry, aChildOffset);
michael@0 3976 }
michael@0 3977 }
michael@0 3978 else if (mSessionHistory) {
michael@0 3979 /* You are currently in the rootDocShell.
michael@0 3980 * You will get here when a subframe has a new url
michael@0 3981 * to load and you have walked up the tree all the
michael@0 3982 * way to the top to clone the current SHEntry hierarchy
michael@0 3983 * and replace the subframe where a new url was loaded with
michael@0 3984 * a new entry.
michael@0 3985 */
michael@0 3986 int32_t index = -1;
michael@0 3987 nsCOMPtr<nsISHEntry> currentHE;
michael@0 3988 mSessionHistory->GetIndex(&index);
michael@0 3989 if (index < 0)
michael@0 3990 return NS_ERROR_FAILURE;
michael@0 3991
michael@0 3992 rv = mSessionHistory->GetEntryAtIndex(index, false,
michael@0 3993 getter_AddRefs(currentHE));
michael@0 3994 NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
michael@0 3995
michael@0 3996 nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
michael@0 3997 if (currentEntry) {
michael@0 3998 uint32_t cloneID = 0;
michael@0 3999 nsCOMPtr<nsISHEntry> nextEntry;
michael@0 4000 aCloneRef->GetID(&cloneID);
michael@0 4001 rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
michael@0 4002 aCloneChildren, getter_AddRefs(nextEntry));
michael@0 4003
michael@0 4004 if (NS_SUCCEEDED(rv)) {
michael@0 4005 nsCOMPtr<nsISHistoryInternal>
michael@0 4006 shPrivate(do_QueryInterface(mSessionHistory));
michael@0 4007 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
michael@0 4008 rv = shPrivate->AddEntry(nextEntry, true);
michael@0 4009 }
michael@0 4010 }
michael@0 4011 }
michael@0 4012 else {
michael@0 4013 /* Just pass this along */
michael@0 4014 nsCOMPtr<nsIDocShell> parent =
michael@0 4015 do_QueryInterface(GetAsSupports(mParent), &rv);
michael@0 4016 if (parent) {
michael@0 4017 rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
michael@0 4018 loadType, aCloneChildren);
michael@0 4019 }
michael@0 4020 }
michael@0 4021 return rv;
michael@0 4022 }
michael@0 4023
michael@0 4024 nsresult
michael@0 4025 nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, int32_t aChildOffset,
michael@0 4026 bool aCloneChildren)
michael@0 4027 {
michael@0 4028 /* You will get here when you are in a subframe and
michael@0 4029 * a new url has been loaded on you.
michael@0 4030 * The mOSHE in this subframe will be the previous url's
michael@0 4031 * mOSHE. This mOSHE will be used as the identification
michael@0 4032 * for this subframe in the CloneAndReplace function.
michael@0 4033 */
michael@0 4034
michael@0 4035 // In this case, we will end up calling AddEntry, which increases the
michael@0 4036 // current index by 1
michael@0 4037 nsCOMPtr<nsISHistory> rootSH;
michael@0 4038 GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4039 if (rootSH) {
michael@0 4040 rootSH->GetIndex(&mPreviousTransIndex);
michael@0 4041 }
michael@0 4042
michael@0 4043 nsresult rv;
michael@0 4044 nsCOMPtr<nsIDocShell> parent =
michael@0 4045 do_QueryInterface(GetAsSupports(mParent), &rv);
michael@0 4046 if (parent) {
michael@0 4047 rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
michael@0 4048 aCloneChildren);
michael@0 4049 }
michael@0 4050
michael@0 4051
michael@0 4052 if (rootSH) {
michael@0 4053 rootSH->GetIndex(&mLoadedTransIndex);
michael@0 4054 #ifdef DEBUG_PAGE_CACHE
michael@0 4055 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
michael@0 4056 mLoadedTransIndex);
michael@0 4057 #endif
michael@0 4058 }
michael@0 4059
michael@0 4060 return rv;
michael@0 4061 }
michael@0 4062
michael@0 4063 NS_IMETHODIMP
michael@0 4064 nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
michael@0 4065 {
michael@0 4066 nsresult rv;
michael@0 4067
michael@0 4068 mUseGlobalHistory = aUseGlobalHistory;
michael@0 4069
michael@0 4070 if (!aUseGlobalHistory) {
michael@0 4071 mGlobalHistory = nullptr;
michael@0 4072 return NS_OK;
michael@0 4073 }
michael@0 4074
michael@0 4075 // No need to initialize mGlobalHistory if IHistory is available.
michael@0 4076 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 4077 if (history) {
michael@0 4078 return NS_OK;
michael@0 4079 }
michael@0 4080
michael@0 4081 if (mGlobalHistory) {
michael@0 4082 return NS_OK;
michael@0 4083 }
michael@0 4084
michael@0 4085 mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
michael@0 4086 return rv;
michael@0 4087 }
michael@0 4088
michael@0 4089 NS_IMETHODIMP
michael@0 4090 nsDocShell::GetUseGlobalHistory(bool *aUseGlobalHistory)
michael@0 4091 {
michael@0 4092 *aUseGlobalHistory = mUseGlobalHistory;
michael@0 4093 return NS_OK;
michael@0 4094 }
michael@0 4095
michael@0 4096 NS_IMETHODIMP
michael@0 4097 nsDocShell::RemoveFromSessionHistory()
michael@0 4098 {
michael@0 4099 nsCOMPtr<nsISHistoryInternal> internalHistory;
michael@0 4100 nsCOMPtr<nsISHistory> sessionHistory;
michael@0 4101 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 4102 GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 4103 if (root) {
michael@0 4104 nsCOMPtr<nsIWebNavigation> rootAsWebnav =
michael@0 4105 do_QueryInterface(root);
michael@0 4106 if (rootAsWebnav) {
michael@0 4107 rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
michael@0 4108 internalHistory = do_QueryInterface(sessionHistory);
michael@0 4109 }
michael@0 4110 }
michael@0 4111 if (!internalHistory) {
michael@0 4112 return NS_OK;
michael@0 4113 }
michael@0 4114
michael@0 4115 int32_t index = 0;
michael@0 4116 sessionHistory->GetIndex(&index);
michael@0 4117 nsAutoTArray<uint64_t, 16> ids;
michael@0 4118 ids.AppendElement(mHistoryID);
michael@0 4119 internalHistory->RemoveEntries(ids, index);
michael@0 4120 return NS_OK;
michael@0 4121 }
michael@0 4122
michael@0 4123 NS_IMETHODIMP
michael@0 4124 nsDocShell::SetCreatedDynamically(bool aDynamic)
michael@0 4125 {
michael@0 4126 mDynamicallyCreated = aDynamic;
michael@0 4127 return NS_OK;
michael@0 4128 }
michael@0 4129
michael@0 4130 NS_IMETHODIMP
michael@0 4131 nsDocShell::GetCreatedDynamically(bool* aDynamic)
michael@0 4132 {
michael@0 4133 *aDynamic = mDynamicallyCreated;
michael@0 4134 return NS_OK;
michael@0 4135 }
michael@0 4136
michael@0 4137 NS_IMETHODIMP
michael@0 4138 nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
michael@0 4139 {
michael@0 4140 *aOSHE = false;
michael@0 4141 *aEntry = nullptr;
michael@0 4142 if (mLSHE) {
michael@0 4143 NS_ADDREF(*aEntry = mLSHE);
michael@0 4144 } else if (mOSHE) {
michael@0 4145 NS_ADDREF(*aEntry = mOSHE);
michael@0 4146 *aOSHE = true;
michael@0 4147 }
michael@0 4148 return NS_OK;
michael@0 4149 }
michael@0 4150
michael@0 4151 nsIScriptGlobalObject*
michael@0 4152 nsDocShell::GetScriptGlobalObject()
michael@0 4153 {
michael@0 4154 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
michael@0 4155 return mScriptGlobal;
michael@0 4156 }
michael@0 4157
michael@0 4158 NS_IMETHODIMP
michael@0 4159 nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
michael@0 4160 {
michael@0 4161 if (mDeviceSizeIsPageSize != aValue) {
michael@0 4162 mDeviceSizeIsPageSize = aValue;
michael@0 4163 nsRefPtr<nsPresContext> presContext;
michael@0 4164 GetPresContext(getter_AddRefs(presContext));
michael@0 4165 if (presContext) {
michael@0 4166 presContext->MediaFeatureValuesChanged(presContext->eAlwaysRebuildStyle);
michael@0 4167 }
michael@0 4168 }
michael@0 4169 return NS_OK;
michael@0 4170 }
michael@0 4171
michael@0 4172 NS_IMETHODIMP
michael@0 4173 nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
michael@0 4174 {
michael@0 4175 *aValue = mDeviceSizeIsPageSize;
michael@0 4176 return NS_OK;
michael@0 4177 }
michael@0 4178
michael@0 4179 void
michael@0 4180 nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
michael@0 4181 {
michael@0 4182 nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
michael@0 4183 nsCOMPtr<nsISHistory> rootSH;
michael@0 4184 GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4185 nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
michael@0 4186 if (!history || !shcontainer) {
michael@0 4187 return;
michael@0 4188 }
michael@0 4189
michael@0 4190 int32_t count = 0;
michael@0 4191 shcontainer->GetChildCount(&count);
michael@0 4192 nsAutoTArray<uint64_t, 16> ids;
michael@0 4193 for (int32_t i = 0; i < count; ++i) {
michael@0 4194 nsCOMPtr<nsISHEntry> child;
michael@0 4195 shcontainer->GetChildAt(i, getter_AddRefs(child));
michael@0 4196 if (child) {
michael@0 4197 uint64_t id = 0;
michael@0 4198 child->GetDocshellID(&id);
michael@0 4199 ids.AppendElement(id);
michael@0 4200 }
michael@0 4201 }
michael@0 4202 int32_t index = 0;
michael@0 4203 rootSH->GetIndex(&index);
michael@0 4204 history->RemoveEntries(ids, index);
michael@0 4205 }
michael@0 4206
michael@0 4207 //-------------------------------------
michael@0 4208 //-- Helper Method for Print discovery
michael@0 4209 //-------------------------------------
michael@0 4210 bool
michael@0 4211 nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
michael@0 4212 {
michael@0 4213 if (mIsPrintingOrPP && aDisplayErrorDialog) {
michael@0 4214 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
michael@0 4215 }
michael@0 4216
michael@0 4217 return mIsPrintingOrPP;
michael@0 4218 }
michael@0 4219
michael@0 4220 bool
michael@0 4221 nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog)
michael@0 4222 {
michael@0 4223 bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
michael@0 4224 if (!isAllowed) {
michael@0 4225 return false;
michael@0 4226 }
michael@0 4227 if (!mContentViewer) {
michael@0 4228 return true;
michael@0 4229 }
michael@0 4230 bool firingBeforeUnload;
michael@0 4231 mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
michael@0 4232 return !firingBeforeUnload;
michael@0 4233 }
michael@0 4234
michael@0 4235 //*****************************************************************************
michael@0 4236 // nsDocShell::nsIWebNavigation
michael@0 4237 //*****************************************************************************
michael@0 4238
michael@0 4239 NS_IMETHODIMP
michael@0 4240 nsDocShell::GetCanGoBack(bool * aCanGoBack)
michael@0 4241 {
michael@0 4242 if (!IsNavigationAllowed(false)) {
michael@0 4243 *aCanGoBack = false;
michael@0 4244 return NS_OK; // JS may not handle returning of an error code
michael@0 4245 }
michael@0 4246 nsresult rv;
michael@0 4247 nsCOMPtr<nsISHistory> rootSH;
michael@0 4248 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4249 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
michael@0 4250 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
michael@0 4251 rv = webnav->GetCanGoBack(aCanGoBack);
michael@0 4252 return rv;
michael@0 4253
michael@0 4254 }
michael@0 4255
michael@0 4256 NS_IMETHODIMP
michael@0 4257 nsDocShell::GetCanGoForward(bool * aCanGoForward)
michael@0 4258 {
michael@0 4259 if (!IsNavigationAllowed(false)) {
michael@0 4260 *aCanGoForward = false;
michael@0 4261 return NS_OK; // JS may not handle returning of an error code
michael@0 4262 }
michael@0 4263 nsresult rv;
michael@0 4264 nsCOMPtr<nsISHistory> rootSH;
michael@0 4265 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4266 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
michael@0 4267 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
michael@0 4268 rv = webnav->GetCanGoForward(aCanGoForward);
michael@0 4269 return rv;
michael@0 4270
michael@0 4271 }
michael@0 4272
michael@0 4273 NS_IMETHODIMP
michael@0 4274 nsDocShell::GoBack()
michael@0 4275 {
michael@0 4276 if (!IsNavigationAllowed()) {
michael@0 4277 return NS_OK; // JS may not handle returning of an error code
michael@0 4278 }
michael@0 4279 nsresult rv;
michael@0 4280 nsCOMPtr<nsISHistory> rootSH;
michael@0 4281 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4282 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
michael@0 4283 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
michael@0 4284 rv = webnav->GoBack();
michael@0 4285 return rv;
michael@0 4286
michael@0 4287 }
michael@0 4288
michael@0 4289 NS_IMETHODIMP
michael@0 4290 nsDocShell::GoForward()
michael@0 4291 {
michael@0 4292 if (!IsNavigationAllowed()) {
michael@0 4293 return NS_OK; // JS may not handle returning of an error code
michael@0 4294 }
michael@0 4295 nsresult rv;
michael@0 4296 nsCOMPtr<nsISHistory> rootSH;
michael@0 4297 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4298 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
michael@0 4299 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
michael@0 4300 rv = webnav->GoForward();
michael@0 4301 return rv;
michael@0 4302
michael@0 4303 }
michael@0 4304
michael@0 4305 NS_IMETHODIMP nsDocShell::GotoIndex(int32_t aIndex)
michael@0 4306 {
michael@0 4307 if (!IsNavigationAllowed()) {
michael@0 4308 return NS_OK; // JS may not handle returning of an error code
michael@0 4309 }
michael@0 4310 nsresult rv;
michael@0 4311 nsCOMPtr<nsISHistory> rootSH;
michael@0 4312 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4313 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
michael@0 4314 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
michael@0 4315 rv = webnav->GotoIndex(aIndex);
michael@0 4316 return rv;
michael@0 4317
michael@0 4318 }
michael@0 4319
michael@0 4320 NS_IMETHODIMP
michael@0 4321 nsDocShell::LoadURI(const char16_t * aURI,
michael@0 4322 uint32_t aLoadFlags,
michael@0 4323 nsIURI * aReferringURI,
michael@0 4324 nsIInputStream * aPostStream,
michael@0 4325 nsIInputStream * aHeaderStream)
michael@0 4326 {
michael@0 4327 return LoadURIWithBase(aURI, aLoadFlags, aReferringURI, aPostStream,
michael@0 4328 aHeaderStream, nullptr);
michael@0 4329 }
michael@0 4330
michael@0 4331 NS_IMETHODIMP
michael@0 4332 nsDocShell::LoadURIWithBase(const char16_t * aURI,
michael@0 4333 uint32_t aLoadFlags,
michael@0 4334 nsIURI * aReferringURI,
michael@0 4335 nsIInputStream * aPostStream,
michael@0 4336 nsIInputStream * aHeaderStream,
michael@0 4337 nsIURI * aBaseURI)
michael@0 4338 {
michael@0 4339 NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
michael@0 4340
michael@0 4341 if (!IsNavigationAllowed()) {
michael@0 4342 return NS_OK; // JS may not handle returning of an error code
michael@0 4343 }
michael@0 4344 nsCOMPtr<nsIURI> uri;
michael@0 4345 nsCOMPtr<nsIInputStream> postStream(aPostStream);
michael@0 4346 nsresult rv = NS_OK;
michael@0 4347
michael@0 4348 // Create a URI from our string; if that succeeds, we want to
michael@0 4349 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
michael@0 4350 // flag.
michael@0 4351
michael@0 4352 NS_ConvertUTF16toUTF8 uriString(aURI);
michael@0 4353 // Cleanup the empty spaces that might be on each end.
michael@0 4354 uriString.Trim(" ");
michael@0 4355 // Eliminate embedded newlines, which single-line text fields now allow:
michael@0 4356 uriString.StripChars("\r\n");
michael@0 4357 NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
michael@0 4358
michael@0 4359 rv = NS_NewURI(getter_AddRefs(uri), uriString);
michael@0 4360 if (uri) {
michael@0 4361 aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
michael@0 4362 }
michael@0 4363
michael@0 4364 if (sURIFixup) {
michael@0 4365 // Call the fixup object. This will clobber the rv from NS_NewURI
michael@0 4366 // above, but that's fine with us. Note that we need to do this even
michael@0 4367 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
michael@0 4368 // (things like view-source:mozilla.org for example).
michael@0 4369 uint32_t fixupFlags = 0;
michael@0 4370 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
michael@0 4371 fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
michael@0 4372 }
michael@0 4373 if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
michael@0 4374 fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
michael@0 4375 }
michael@0 4376 nsCOMPtr<nsIInputStream> fixupStream;
michael@0 4377 rv = sURIFixup->CreateFixupURI(uriString, fixupFlags,
michael@0 4378 getter_AddRefs(fixupStream),
michael@0 4379 getter_AddRefs(uri));
michael@0 4380 if (fixupStream) {
michael@0 4381 // CreateFixupURI only returns a post data stream if it succeeded
michael@0 4382 // and changed the URI, in which case we should override the
michael@0 4383 // passed-in post data.
michael@0 4384 postStream = fixupStream;
michael@0 4385 }
michael@0 4386 }
michael@0 4387 // else no fixup service so just use the URI we created and see
michael@0 4388 // what happens
michael@0 4389
michael@0 4390 if (NS_ERROR_MALFORMED_URI == rv) {
michael@0 4391 DisplayLoadError(rv, uri, aURI, nullptr);
michael@0 4392 }
michael@0 4393
michael@0 4394 if (NS_FAILED(rv) || !uri)
michael@0 4395 return NS_ERROR_FAILURE;
michael@0 4396
michael@0 4397 PopupControlState popupState;
michael@0 4398 if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
michael@0 4399 popupState = openAllowed;
michael@0 4400 aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
michael@0 4401 } else {
michael@0 4402 popupState = openOverridden;
michael@0 4403 }
michael@0 4404 nsAutoPopupStatePusher statePusher(popupState);
michael@0 4405
michael@0 4406 // Don't pass certain flags that aren't needed and end up confusing
michael@0 4407 // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
michael@0 4408 // passed to LoadURI though, since it uses them.
michael@0 4409 uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
michael@0 4410 aLoadFlags &= ~EXTRA_LOAD_FLAGS;
michael@0 4411
michael@0 4412 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
michael@0 4413 rv = CreateLoadInfo(getter_AddRefs(loadInfo));
michael@0 4414 if (NS_FAILED(rv)) return rv;
michael@0 4415
michael@0 4416 /*
michael@0 4417 * If the user "Disables Protection on This Page", we have to make sure to
michael@0 4418 * remember the users decision when opening links in child tabs [Bug 906190]
michael@0 4419 */
michael@0 4420 uint32_t loadType;
michael@0 4421 if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
michael@0 4422 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
michael@0 4423 } else {
michael@0 4424 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
michael@0 4425 }
michael@0 4426
michael@0 4427 loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
michael@0 4428 loadInfo->SetPostDataStream(postStream);
michael@0 4429 loadInfo->SetReferrer(aReferringURI);
michael@0 4430 loadInfo->SetHeadersStream(aHeaderStream);
michael@0 4431 loadInfo->SetBaseURI(aBaseURI);
michael@0 4432
michael@0 4433 rv = LoadURI(uri, loadInfo, extraFlags, true);
michael@0 4434
michael@0 4435 // Save URI string in case it's needed later when
michael@0 4436 // sending to search engine service in EndPageLoad()
michael@0 4437 mOriginalUriString = uriString;
michael@0 4438
michael@0 4439 return rv;
michael@0 4440 }
michael@0 4441
michael@0 4442 NS_IMETHODIMP
michael@0 4443 nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
michael@0 4444 const char16_t *aURL,
michael@0 4445 nsIChannel* aFailedChannel)
michael@0 4446 {
michael@0 4447 // Get prompt and string bundle servcies
michael@0 4448 nsCOMPtr<nsIPrompt> prompter;
michael@0 4449 nsCOMPtr<nsIStringBundle> stringBundle;
michael@0 4450 GetPromptAndStringBundle(getter_AddRefs(prompter),
michael@0 4451 getter_AddRefs(stringBundle));
michael@0 4452
michael@0 4453 NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
michael@0 4454 NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
michael@0 4455
michael@0 4456 nsAutoString error;
michael@0 4457 const uint32_t kMaxFormatStrArgs = 3;
michael@0 4458 nsAutoString formatStrs[kMaxFormatStrArgs];
michael@0 4459 uint32_t formatStrCount = 0;
michael@0 4460 bool addHostPort = false;
michael@0 4461 nsresult rv = NS_OK;
michael@0 4462 nsAutoString messageStr;
michael@0 4463 nsAutoCString cssClass;
michael@0 4464 nsAutoCString errorPage;
michael@0 4465
michael@0 4466 errorPage.AssignLiteral("neterror");
michael@0 4467
michael@0 4468 // Turn the error code into a human readable error message.
michael@0 4469 if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
michael@0 4470 NS_ENSURE_ARG_POINTER(aURI);
michael@0 4471
michael@0 4472 // Extract the schemes into a comma delimited list.
michael@0 4473 nsAutoCString scheme;
michael@0 4474 aURI->GetScheme(scheme);
michael@0 4475 CopyASCIItoUTF16(scheme, formatStrs[0]);
michael@0 4476 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
michael@0 4477 while (nestedURI) {
michael@0 4478 nsCOMPtr<nsIURI> tempURI;
michael@0 4479 nsresult rv2;
michael@0 4480 rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
michael@0 4481 if (NS_SUCCEEDED(rv2) && tempURI) {
michael@0 4482 tempURI->GetScheme(scheme);
michael@0 4483 formatStrs[0].Append(NS_LITERAL_STRING(", "));
michael@0 4484 AppendASCIItoUTF16(scheme, formatStrs[0]);
michael@0 4485 }
michael@0 4486 nestedURI = do_QueryInterface(tempURI);
michael@0 4487 }
michael@0 4488 formatStrCount = 1;
michael@0 4489 error.AssignLiteral("unknownProtocolFound");
michael@0 4490 }
michael@0 4491 else if (NS_ERROR_FILE_NOT_FOUND == aError) {
michael@0 4492 NS_ENSURE_ARG_POINTER(aURI);
michael@0 4493 error.AssignLiteral("fileNotFound");
michael@0 4494 }
michael@0 4495 else if (NS_ERROR_UNKNOWN_HOST == aError) {
michael@0 4496 NS_ENSURE_ARG_POINTER(aURI);
michael@0 4497 // Get the host
michael@0 4498 nsAutoCString host;
michael@0 4499 nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
michael@0 4500 innermostURI->GetHost(host);
michael@0 4501 CopyUTF8toUTF16(host, formatStrs[0]);
michael@0 4502 formatStrCount = 1;
michael@0 4503 error.AssignLiteral("dnsNotFound");
michael@0 4504 }
michael@0 4505 else if(NS_ERROR_CONNECTION_REFUSED == aError) {
michael@0 4506 NS_ENSURE_ARG_POINTER(aURI);
michael@0 4507 addHostPort = true;
michael@0 4508 error.AssignLiteral("connectionFailure");
michael@0 4509 }
michael@0 4510 else if(NS_ERROR_NET_INTERRUPT == aError) {
michael@0 4511 NS_ENSURE_ARG_POINTER(aURI);
michael@0 4512 addHostPort = true;
michael@0 4513 error.AssignLiteral("netInterrupt");
michael@0 4514 }
michael@0 4515 else if (NS_ERROR_NET_TIMEOUT == aError) {
michael@0 4516 NS_ENSURE_ARG_POINTER(aURI);
michael@0 4517 // Get the host
michael@0 4518 nsAutoCString host;
michael@0 4519 aURI->GetHost(host);
michael@0 4520 CopyUTF8toUTF16(host, formatStrs[0]);
michael@0 4521 formatStrCount = 1;
michael@0 4522 error.AssignLiteral("netTimeout");
michael@0 4523 }
michael@0 4524 else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError) {
michael@0 4525 // CSP error
michael@0 4526 cssClass.AssignLiteral("neterror");
michael@0 4527 error.AssignLiteral("cspFrameAncestorBlocked");
michael@0 4528 }
michael@0 4529 else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
michael@0 4530 nsCOMPtr<nsINSSErrorsService> nsserr =
michael@0 4531 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
michael@0 4532
michael@0 4533 uint32_t errorClass;
michael@0 4534 if (!nsserr ||
michael@0 4535 NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
michael@0 4536 errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
michael@0 4537 }
michael@0 4538
michael@0 4539 nsCOMPtr<nsISupports> securityInfo;
michael@0 4540 nsCOMPtr<nsITransportSecurityInfo> tsi;
michael@0 4541 if (aFailedChannel)
michael@0 4542 aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
michael@0 4543 tsi = do_QueryInterface(securityInfo);
michael@0 4544 if (tsi) {
michael@0 4545 // Usually we should have aFailedChannel and get a detailed message
michael@0 4546 tsi->GetErrorMessage(getter_Copies(messageStr));
michael@0 4547 }
michael@0 4548 else {
michael@0 4549 // No channel, let's obtain the generic error message
michael@0 4550 if (nsserr) {
michael@0 4551 nsserr->GetErrorMessage(aError, messageStr);
michael@0 4552 }
michael@0 4553 }
michael@0 4554 if (!messageStr.IsEmpty()) {
michael@0 4555 if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
michael@0 4556 error.AssignLiteral("nssBadCert");
michael@0 4557
michael@0 4558 // if this is a Strict-Transport-Security host and the cert
michael@0 4559 // is bad, don't allow overrides (STS Spec section 7.3).
michael@0 4560 nsCOMPtr<nsISiteSecurityService> sss =
michael@0 4561 do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
michael@0 4562 NS_ENSURE_SUCCESS(rv, rv);
michael@0 4563 uint32_t flags =
michael@0 4564 mInPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
michael@0 4565
michael@0 4566 bool isStsHost = false;
michael@0 4567 rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
michael@0 4568 aURI, flags, &isStsHost);
michael@0 4569 NS_ENSURE_SUCCESS(rv, rv);
michael@0 4570
michael@0 4571 uint32_t bucketId;
michael@0 4572 if (isStsHost) {
michael@0 4573 cssClass.AssignLiteral("badStsCert");
michael@0 4574 //measuring STS separately allows us to measure click through
michael@0 4575 //rates easily
michael@0 4576 bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
michael@0 4577 } else {
michael@0 4578 bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
michael@0 4579 }
michael@0 4580
michael@0 4581
michael@0 4582 if (Preferences::GetBool(
michael@0 4583 "browser.xul.error_pages.expert_bad_cert", false)) {
michael@0 4584 cssClass.AssignLiteral("expertBadCert");
michael@0 4585 }
michael@0 4586
michael@0 4587 // See if an alternate cert error page is registered
michael@0 4588 nsAdoptingCString alternateErrorPage =
michael@0 4589 Preferences::GetCString(
michael@0 4590 "security.alternate_certificate_error_page");
michael@0 4591 if (alternateErrorPage)
michael@0 4592 errorPage.Assign(alternateErrorPage);
michael@0 4593
michael@0 4594 if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror"))
michael@0 4595 mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
michael@0 4596
michael@0 4597 } else {
michael@0 4598 error.AssignLiteral("nssFailure2");
michael@0 4599 }
michael@0 4600 }
michael@0 4601 } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError) {
michael@0 4602 nsAutoCString host;
michael@0 4603 aURI->GetHost(host);
michael@0 4604 CopyUTF8toUTF16(host, formatStrs[0]);
michael@0 4605 formatStrCount = 1;
michael@0 4606
michael@0 4607 // Malware and phishing detectors may want to use an alternate error
michael@0 4608 // page, but if the pref's not set, we'll fall back on the standard page
michael@0 4609 nsAdoptingCString alternateErrorPage =
michael@0 4610 Preferences::GetCString("urlclassifier.alternate_error_page");
michael@0 4611 if (alternateErrorPage)
michael@0 4612 errorPage.Assign(alternateErrorPage);
michael@0 4613
michael@0 4614 uint32_t bucketId;
michael@0 4615 if (NS_ERROR_PHISHING_URI == aError) {
michael@0 4616 error.AssignLiteral("phishingBlocked");
michael@0 4617 bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME :
michael@0 4618 nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP ;
michael@0 4619 } else {
michael@0 4620 error.AssignLiteral("malwareBlocked");
michael@0 4621 bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME :
michael@0 4622 nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP ;
michael@0 4623 }
michael@0 4624
michael@0 4625 if (errorPage.EqualsIgnoreCase("blocked"))
michael@0 4626 mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI,
michael@0 4627 bucketId);
michael@0 4628
michael@0 4629 cssClass.AssignLiteral("blacklist");
michael@0 4630 } else if (NS_ERROR_CONTENT_CRASHED == aError) {
michael@0 4631 errorPage.AssignLiteral("tabcrashed");
michael@0 4632 error.AssignLiteral("tabcrashed");
michael@0 4633
michael@0 4634 nsCOMPtr<EventTarget> handler = mChromeEventHandler;
michael@0 4635 if (handler) {
michael@0 4636 nsCOMPtr<Element> element = do_QueryInterface(handler);
michael@0 4637 element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
michael@0 4638 }
michael@0 4639
michael@0 4640 // DisplayLoadError requires a non-empty messageStr to proceed and call LoadErrorPage.
michael@0 4641 // If the page doesn't have a title, we will use a blank space which will be trimmed
michael@0 4642 // and thus treated as empty by the front-end.
michael@0 4643 if (messageStr.IsEmpty()) {
michael@0 4644 messageStr.Assign(NS_LITERAL_STRING(" "));
michael@0 4645 }
michael@0 4646 }
michael@0 4647 else {
michael@0 4648 // Errors requiring simple formatting
michael@0 4649 switch (aError) {
michael@0 4650 case NS_ERROR_MALFORMED_URI:
michael@0 4651 // URI is malformed
michael@0 4652 error.AssignLiteral("malformedURI");
michael@0 4653 break;
michael@0 4654 case NS_ERROR_REDIRECT_LOOP:
michael@0 4655 // Doc failed to load because the server generated too many redirects
michael@0 4656 error.AssignLiteral("redirectLoop");
michael@0 4657 break;
michael@0 4658 case NS_ERROR_UNKNOWN_SOCKET_TYPE:
michael@0 4659 // Doc failed to load because PSM is not installed
michael@0 4660 error.AssignLiteral("unknownSocketType");
michael@0 4661 break;
michael@0 4662 case NS_ERROR_NET_RESET:
michael@0 4663 // Doc failed to load because the server kept reseting the connection
michael@0 4664 // before we could read any data from it
michael@0 4665 error.AssignLiteral("netReset");
michael@0 4666 break;
michael@0 4667 case NS_ERROR_DOCUMENT_NOT_CACHED:
michael@0 4668 // Doc failed to load because the cache does not contain a copy of
michael@0 4669 // the document.
michael@0 4670 error.AssignLiteral("notCached");
michael@0 4671 break;
michael@0 4672 case NS_ERROR_OFFLINE:
michael@0 4673 // Doc failed to load because we are offline.
michael@0 4674 error.AssignLiteral("netOffline");
michael@0 4675 break;
michael@0 4676 case NS_ERROR_DOCUMENT_IS_PRINTMODE:
michael@0 4677 // Doc navigation attempted while Printing or Print Preview
michael@0 4678 error.AssignLiteral("isprinting");
michael@0 4679 break;
michael@0 4680 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
michael@0 4681 // Port blocked for security reasons
michael@0 4682 addHostPort = true;
michael@0 4683 error.AssignLiteral("deniedPortAccess");
michael@0 4684 break;
michael@0 4685 case NS_ERROR_UNKNOWN_PROXY_HOST:
michael@0 4686 // Proxy hostname could not be resolved.
michael@0 4687 error.AssignLiteral("proxyResolveFailure");
michael@0 4688 break;
michael@0 4689 case NS_ERROR_PROXY_CONNECTION_REFUSED:
michael@0 4690 // Proxy connection was refused.
michael@0 4691 error.AssignLiteral("proxyConnectFailure");
michael@0 4692 break;
michael@0 4693 case NS_ERROR_INVALID_CONTENT_ENCODING:
michael@0 4694 // Bad Content Encoding.
michael@0 4695 error.AssignLiteral("contentEncodingError");
michael@0 4696 break;
michael@0 4697 case NS_ERROR_REMOTE_XUL:
michael@0 4698 {
michael@0 4699 error.AssignLiteral("remoteXUL");
michael@0 4700 break;
michael@0 4701 }
michael@0 4702 case NS_ERROR_UNSAFE_CONTENT_TYPE:
michael@0 4703 // Channel refused to load from an unrecognized content type.
michael@0 4704 error.AssignLiteral("unsafeContentType");
michael@0 4705 break;
michael@0 4706 case NS_ERROR_CORRUPTED_CONTENT:
michael@0 4707 // Broken Content Detected. e.g. Content-MD5 check failure.
michael@0 4708 error.AssignLiteral("corruptedContentError");
michael@0 4709 break;
michael@0 4710 default:
michael@0 4711 break;
michael@0 4712 }
michael@0 4713 }
michael@0 4714
michael@0 4715 // Test if the error should be displayed
michael@0 4716 if (error.IsEmpty()) {
michael@0 4717 return NS_OK;
michael@0 4718 }
michael@0 4719
michael@0 4720 // Test if the error needs to be formatted
michael@0 4721 if (!messageStr.IsEmpty()) {
michael@0 4722 // already obtained message
michael@0 4723 }
michael@0 4724 else {
michael@0 4725 if (addHostPort) {
michael@0 4726 // Build up the host:port string.
michael@0 4727 nsAutoCString hostport;
michael@0 4728 if (aURI) {
michael@0 4729 aURI->GetHostPort(hostport);
michael@0 4730 } else {
michael@0 4731 hostport.AssignLiteral("?");
michael@0 4732 }
michael@0 4733 CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
michael@0 4734 }
michael@0 4735
michael@0 4736 nsAutoCString spec;
michael@0 4737 rv = NS_ERROR_NOT_AVAILABLE;
michael@0 4738 if (aURI) {
michael@0 4739 // displaying "file://" is aesthetically unpleasing and could even be
michael@0 4740 // confusing to the user
michael@0 4741 bool isFileURI = false;
michael@0 4742 rv = aURI->SchemeIs("file", &isFileURI);
michael@0 4743 if (NS_SUCCEEDED(rv) && isFileURI)
michael@0 4744 aURI->GetPath(spec);
michael@0 4745 else
michael@0 4746 aURI->GetSpec(spec);
michael@0 4747
michael@0 4748 nsAutoCString charset;
michael@0 4749 // unescape and convert from origin charset
michael@0 4750 aURI->GetOriginCharset(charset);
michael@0 4751 nsCOMPtr<nsITextToSubURI> textToSubURI(
michael@0 4752 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
michael@0 4753 if (NS_SUCCEEDED(rv)) {
michael@0 4754 rv = textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[formatStrCount]);
michael@0 4755 }
michael@0 4756 } else {
michael@0 4757 spec.AssignLiteral("?");
michael@0 4758 }
michael@0 4759 if (NS_FAILED(rv))
michael@0 4760 CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
michael@0 4761 rv = NS_OK;
michael@0 4762 ++formatStrCount;
michael@0 4763
michael@0 4764 const char16_t *strs[kMaxFormatStrArgs];
michael@0 4765 for (uint32_t i = 0; i < formatStrCount; i++) {
michael@0 4766 strs[i] = formatStrs[i].get();
michael@0 4767 }
michael@0 4768 nsXPIDLString str;
michael@0 4769 rv = stringBundle->FormatStringFromName(
michael@0 4770 error.get(),
michael@0 4771 strs, formatStrCount, getter_Copies(str));
michael@0 4772 NS_ENSURE_SUCCESS(rv, rv);
michael@0 4773 messageStr.Assign(str.get());
michael@0 4774 }
michael@0 4775
michael@0 4776 // Display the error as a page or an alert prompt
michael@0 4777 NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
michael@0 4778
michael@0 4779 if (UseErrorPages()) {
michael@0 4780 // Display an error page
michael@0 4781 LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
michael@0 4782 messageStr.get(), cssClass.get(), aFailedChannel);
michael@0 4783 }
michael@0 4784 else
michael@0 4785 {
michael@0 4786 // The prompter reqires that our private window has a document (or it
michael@0 4787 // asserts). Satisfy that assertion now since GetDoc will force
michael@0 4788 // creation of one if it hasn't already been created.
michael@0 4789 if (mScriptGlobal) {
michael@0 4790 unused << mScriptGlobal->GetDoc();
michael@0 4791 }
michael@0 4792
michael@0 4793 // Display a message box
michael@0 4794 prompter->Alert(nullptr, messageStr.get());
michael@0 4795 }
michael@0 4796
michael@0 4797 return NS_OK;
michael@0 4798 }
michael@0 4799
michael@0 4800
michael@0 4801 NS_IMETHODIMP
michael@0 4802 nsDocShell::LoadErrorPage(nsIURI *aURI, const char16_t *aURL,
michael@0 4803 const char *aErrorPage,
michael@0 4804 const char16_t *aErrorType,
michael@0 4805 const char16_t *aDescription,
michael@0 4806 const char *aCSSClass,
michael@0 4807 nsIChannel* aFailedChannel)
michael@0 4808 {
michael@0 4809 #if defined(PR_LOGGING) && defined(DEBUG)
michael@0 4810 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
michael@0 4811 nsAutoCString spec;
michael@0 4812 aURI->GetSpec(spec);
michael@0 4813
michael@0 4814 nsAutoCString chanName;
michael@0 4815 if (aFailedChannel)
michael@0 4816 aFailedChannel->GetName(chanName);
michael@0 4817 else
michael@0 4818 chanName.AssignLiteral("<no channel>");
michael@0 4819
michael@0 4820 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 4821 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
michael@0 4822 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
michael@0 4823 }
michael@0 4824 #endif
michael@0 4825 mFailedChannel = aFailedChannel;
michael@0 4826 mFailedURI = aURI;
michael@0 4827 mFailedLoadType = mLoadType;
michael@0 4828
michael@0 4829 if (mLSHE) {
michael@0 4830 // Abandon mLSHE's BFCache entry and create a new one. This way, if
michael@0 4831 // we go back or forward to another SHEntry with the same doc
michael@0 4832 // identifier, the error page won't persist.
michael@0 4833 mLSHE->AbandonBFCacheEntry();
michael@0 4834 }
michael@0 4835
michael@0 4836 nsAutoCString url;
michael@0 4837 nsAutoCString charset;
michael@0 4838 if (aURI)
michael@0 4839 {
michael@0 4840 nsresult rv = aURI->GetSpec(url);
michael@0 4841 NS_ENSURE_SUCCESS(rv, rv);
michael@0 4842 rv = aURI->GetOriginCharset(charset);
michael@0 4843 NS_ENSURE_SUCCESS(rv, rv);
michael@0 4844 }
michael@0 4845 else if (aURL)
michael@0 4846 {
michael@0 4847 CopyUTF16toUTF8(aURL, url);
michael@0 4848 }
michael@0 4849 else
michael@0 4850 {
michael@0 4851 return NS_ERROR_INVALID_POINTER;
michael@0 4852 }
michael@0 4853
michael@0 4854 // Create a URL to pass all the error information through to the page.
michael@0 4855
michael@0 4856 #undef SAFE_ESCAPE
michael@0 4857 #define SAFE_ESCAPE(cstring, escArg1, escArg2) \
michael@0 4858 { \
michael@0 4859 char* s = nsEscape(escArg1, escArg2); \
michael@0 4860 if (!s) \
michael@0 4861 return NS_ERROR_OUT_OF_MEMORY; \
michael@0 4862 cstring.Adopt(s); \
michael@0 4863 }
michael@0 4864 nsCString escapedUrl, escapedCharset, escapedError, escapedDescription,
michael@0 4865 escapedCSSClass;
michael@0 4866 SAFE_ESCAPE(escapedUrl, url.get(), url_Path);
michael@0 4867 SAFE_ESCAPE(escapedCharset, charset.get(), url_Path);
michael@0 4868 SAFE_ESCAPE(escapedError,
michael@0 4869 NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
michael@0 4870 SAFE_ESCAPE(escapedDescription,
michael@0 4871 NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
michael@0 4872 if (aCSSClass) {
michael@0 4873 SAFE_ESCAPE(escapedCSSClass, aCSSClass, url_Path);
michael@0 4874 }
michael@0 4875 nsCString errorPageUrl("about:");
michael@0 4876 errorPageUrl.AppendASCII(aErrorPage);
michael@0 4877 errorPageUrl.AppendLiteral("?e=");
michael@0 4878
michael@0 4879 errorPageUrl.AppendASCII(escapedError.get());
michael@0 4880 errorPageUrl.AppendLiteral("&u=");
michael@0 4881 errorPageUrl.AppendASCII(escapedUrl.get());
michael@0 4882 if (!escapedCSSClass.IsEmpty()) {
michael@0 4883 errorPageUrl.AppendLiteral("&s=");
michael@0 4884 errorPageUrl.AppendASCII(escapedCSSClass.get());
michael@0 4885 }
michael@0 4886 errorPageUrl.AppendLiteral("&c=");
michael@0 4887 errorPageUrl.AppendASCII(escapedCharset.get());
michael@0 4888
michael@0 4889 nsAutoCString frameType(FrameTypeToString(mFrameType));
michael@0 4890 errorPageUrl.AppendLiteral("&f=");
michael@0 4891 errorPageUrl.AppendASCII(frameType.get());
michael@0 4892
michael@0 4893 // Append the manifest URL if the error comes from an app.
michael@0 4894 nsString manifestURL;
michael@0 4895 nsresult rv = GetAppManifestURL(manifestURL);
michael@0 4896 if (manifestURL.Length() > 0) {
michael@0 4897 nsCString manifestParam;
michael@0 4898 SAFE_ESCAPE(manifestParam,
michael@0 4899 NS_ConvertUTF16toUTF8(manifestURL).get(),
michael@0 4900 url_Path);
michael@0 4901 errorPageUrl.AppendLiteral("&m=");
michael@0 4902 errorPageUrl.AppendASCII(manifestParam.get());
michael@0 4903 }
michael@0 4904
michael@0 4905 // netError.xhtml's getDescription only handles the "d" parameter at the
michael@0 4906 // end of the URL, so append it last.
michael@0 4907 errorPageUrl.AppendLiteral("&d=");
michael@0 4908 errorPageUrl.AppendASCII(escapedDescription.get());
michael@0 4909
michael@0 4910 nsCOMPtr<nsIURI> errorPageURI;
michael@0 4911 rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
michael@0 4912 NS_ENSURE_SUCCESS(rv, rv);
michael@0 4913
michael@0 4914 return InternalLoad(errorPageURI, nullptr, nullptr,
michael@0 4915 INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr, nullptr,
michael@0 4916 NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
michael@0 4917 nullptr, true, NullString(), this, nullptr, nullptr,
michael@0 4918 nullptr);
michael@0 4919 }
michael@0 4920
michael@0 4921
michael@0 4922 NS_IMETHODIMP
michael@0 4923 nsDocShell::Reload(uint32_t aReloadFlags)
michael@0 4924 {
michael@0 4925 if (!IsNavigationAllowed()) {
michael@0 4926 return NS_OK; // JS may not handle returning of an error code
michael@0 4927 }
michael@0 4928 nsresult rv;
michael@0 4929 NS_ASSERTION(((aReloadFlags & 0xf) == 0),
michael@0 4930 "Reload command not updated to use load flags!");
michael@0 4931 NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
michael@0 4932 "Don't pass these flags to Reload");
michael@0 4933
michael@0 4934 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
michael@0 4935 NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
michael@0 4936
michael@0 4937 // Send notifications to the HistoryListener if any, about the impending reload
michael@0 4938 nsCOMPtr<nsISHistory> rootSH;
michael@0 4939 rv = GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 4940 nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
michael@0 4941 bool canReload = true;
michael@0 4942 if (rootSH) {
michael@0 4943 shistInt->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
michael@0 4944 }
michael@0 4945
michael@0 4946 if (!canReload)
michael@0 4947 return NS_OK;
michael@0 4948
michael@0 4949 /* If you change this part of code, make sure bug 45297 does not re-occur */
michael@0 4950 if (mOSHE) {
michael@0 4951 rv = LoadHistoryEntry(mOSHE, loadType);
michael@0 4952 }
michael@0 4953 else if (mLSHE) { // In case a reload happened before the current load is done
michael@0 4954 rv = LoadHistoryEntry(mLSHE, loadType);
michael@0 4955 }
michael@0 4956 else {
michael@0 4957 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 4958
michael@0 4959 // Do not inherit owner from document
michael@0 4960 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
michael@0 4961 nsAutoString srcdoc;
michael@0 4962 nsIPrincipal* principal = nullptr;
michael@0 4963 nsAutoString contentTypeHint;
michael@0 4964 nsCOMPtr<nsIURI> baseURI;
michael@0 4965 if (doc) {
michael@0 4966 principal = doc->NodePrincipal();
michael@0 4967 doc->GetContentType(contentTypeHint);
michael@0 4968
michael@0 4969 if (doc->IsSrcdocDocument()) {
michael@0 4970 doc->GetSrcdocData(srcdoc);
michael@0 4971 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
michael@0 4972 baseURI = doc->GetBaseURI();
michael@0 4973 }
michael@0 4974 }
michael@0 4975 rv = InternalLoad(mCurrentURI,
michael@0 4976 mReferrerURI,
michael@0 4977 principal,
michael@0 4978 flags,
michael@0 4979 nullptr, // No window target
michael@0 4980 NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
michael@0 4981 NullString(), // No forced download
michael@0 4982 nullptr, // No post data
michael@0 4983 nullptr, // No headers data
michael@0 4984 loadType, // Load type
michael@0 4985 nullptr, // No SHEntry
michael@0 4986 true,
michael@0 4987 srcdoc, // srcdoc argument for iframe
michael@0 4988 this, // For reloads we are the source
michael@0 4989 baseURI,
michael@0 4990 nullptr, // No nsIDocShell
michael@0 4991 nullptr); // No nsIRequest
michael@0 4992 }
michael@0 4993
michael@0 4994 return rv;
michael@0 4995 }
michael@0 4996
michael@0 4997 NS_IMETHODIMP
michael@0 4998 nsDocShell::Stop(uint32_t aStopFlags)
michael@0 4999 {
michael@0 5000 // Revoke any pending event related to content viewer restoration
michael@0 5001 mRestorePresentationEvent.Revoke();
michael@0 5002
michael@0 5003 if (mLoadType == LOAD_ERROR_PAGE) {
michael@0 5004 if (mLSHE) {
michael@0 5005 // Since error page loads never unset mLSHE, do so now
michael@0 5006 SetHistoryEntry(&mOSHE, mLSHE);
michael@0 5007 SetHistoryEntry(&mLSHE, nullptr);
michael@0 5008 }
michael@0 5009
michael@0 5010 mFailedChannel = nullptr;
michael@0 5011 mFailedURI = nullptr;
michael@0 5012 }
michael@0 5013
michael@0 5014 if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
michael@0 5015 // Stop the document loading
michael@0 5016 if (mContentViewer) {
michael@0 5017 nsCOMPtr<nsIContentViewer> cv = mContentViewer;
michael@0 5018 cv->Stop();
michael@0 5019 }
michael@0 5020 }
michael@0 5021
michael@0 5022 if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
michael@0 5023 // Suspend any timers that were set for this loader. We'll clear
michael@0 5024 // them out for good in CreateContentViewer.
michael@0 5025 if (mRefreshURIList) {
michael@0 5026 SuspendRefreshURIs();
michael@0 5027 mSavedRefreshURIList.swap(mRefreshURIList);
michael@0 5028 mRefreshURIList = nullptr;
michael@0 5029 }
michael@0 5030
michael@0 5031 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
michael@0 5032 // just call Stop() on us as an nsIDocumentLoader... We need fewer
michael@0 5033 // redundant apis!
michael@0 5034 Stop();
michael@0 5035 }
michael@0 5036
michael@0 5037 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 5038 while (iter.HasMore()) {
michael@0 5039 nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext()));
michael@0 5040 if (shellAsNav)
michael@0 5041 shellAsNav->Stop(aStopFlags);
michael@0 5042 }
michael@0 5043
michael@0 5044 return NS_OK;
michael@0 5045 }
michael@0 5046
michael@0 5047 NS_IMETHODIMP
michael@0 5048 nsDocShell::GetDocument(nsIDOMDocument ** aDocument)
michael@0 5049 {
michael@0 5050 NS_ENSURE_ARG_POINTER(aDocument);
michael@0 5051 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
michael@0 5052
michael@0 5053 return mContentViewer->GetDOMDocument(aDocument);
michael@0 5054 }
michael@0 5055
michael@0 5056 NS_IMETHODIMP
michael@0 5057 nsDocShell::GetCurrentURI(nsIURI ** aURI)
michael@0 5058 {
michael@0 5059 NS_ENSURE_ARG_POINTER(aURI);
michael@0 5060
michael@0 5061 if (mCurrentURI) {
michael@0 5062 return NS_EnsureSafeToReturn(mCurrentURI, aURI);
michael@0 5063 }
michael@0 5064
michael@0 5065 *aURI = nullptr;
michael@0 5066 return NS_OK;
michael@0 5067 }
michael@0 5068
michael@0 5069 NS_IMETHODIMP
michael@0 5070 nsDocShell::GetReferringURI(nsIURI ** aURI)
michael@0 5071 {
michael@0 5072 NS_ENSURE_ARG_POINTER(aURI);
michael@0 5073
michael@0 5074 *aURI = mReferrerURI;
michael@0 5075 NS_IF_ADDREF(*aURI);
michael@0 5076
michael@0 5077 return NS_OK;
michael@0 5078 }
michael@0 5079
michael@0 5080 NS_IMETHODIMP
michael@0 5081 nsDocShell::SetSessionHistory(nsISHistory * aSessionHistory)
michael@0 5082 {
michael@0 5083
michael@0 5084 NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
michael@0 5085 // make sure that we are the root docshell and
michael@0 5086 // set a handle to root docshell in SH.
michael@0 5087
michael@0 5088 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 5089 /* Get the root docshell. If *this* is the root docshell
michael@0 5090 * then save a handle to *this* in SH. SH needs it to do
michael@0 5091 * traversions thro' its entries
michael@0 5092 */
michael@0 5093 GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 5094 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
michael@0 5095 if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) {
michael@0 5096 mSessionHistory = aSessionHistory;
michael@0 5097 nsCOMPtr<nsISHistoryInternal>
michael@0 5098 shPrivate(do_QueryInterface(mSessionHistory));
michael@0 5099 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
michael@0 5100 shPrivate->SetRootDocShell(this);
michael@0 5101 return NS_OK;
michael@0 5102 }
michael@0 5103 return NS_ERROR_FAILURE;
michael@0 5104
michael@0 5105 }
michael@0 5106
michael@0 5107
michael@0 5108 NS_IMETHODIMP
michael@0 5109 nsDocShell::GetSessionHistory(nsISHistory ** aSessionHistory)
michael@0 5110 {
michael@0 5111 NS_ENSURE_ARG_POINTER(aSessionHistory);
michael@0 5112 *aSessionHistory = mSessionHistory;
michael@0 5113 NS_IF_ADDREF(*aSessionHistory);
michael@0 5114 return NS_OK;
michael@0 5115 }
michael@0 5116
michael@0 5117 //*****************************************************************************
michael@0 5118 // nsDocShell::nsIWebPageDescriptor
michael@0 5119 //*****************************************************************************
michael@0 5120 NS_IMETHODIMP
michael@0 5121 nsDocShell::LoadPage(nsISupports *aPageDescriptor, uint32_t aDisplayType)
michael@0 5122 {
michael@0 5123 nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
michael@0 5124
michael@0 5125 // Currently, the opaque 'page descriptor' is an nsISHEntry...
michael@0 5126 if (!shEntryIn) {
michael@0 5127 return NS_ERROR_INVALID_POINTER;
michael@0 5128 }
michael@0 5129
michael@0 5130 // Now clone shEntryIn, since we might end up modifying it later on, and we
michael@0 5131 // want a page descriptor to be reusable.
michael@0 5132 nsCOMPtr<nsISHEntry> shEntry;
michael@0 5133 nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
michael@0 5134 NS_ENSURE_SUCCESS(rv, rv);
michael@0 5135
michael@0 5136 // Give our cloned shEntry a new bfcache entry so this load is independent
michael@0 5137 // of all other loads. (This is important, in particular, for bugs 582795
michael@0 5138 // and 585298.)
michael@0 5139 rv = shEntry->AbandonBFCacheEntry();
michael@0 5140 NS_ENSURE_SUCCESS(rv, rv);
michael@0 5141
michael@0 5142 //
michael@0 5143 // load the page as view-source
michael@0 5144 //
michael@0 5145 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
michael@0 5146 nsCOMPtr<nsIURI> oldUri, newUri;
michael@0 5147 nsCString spec, newSpec;
michael@0 5148
michael@0 5149 // Create a new view-source URI and replace the original.
michael@0 5150 rv = shEntry->GetURI(getter_AddRefs(oldUri));
michael@0 5151 if (NS_FAILED(rv))
michael@0 5152 return rv;
michael@0 5153
michael@0 5154 oldUri->GetSpec(spec);
michael@0 5155 newSpec.AppendLiteral("view-source:");
michael@0 5156 newSpec.Append(spec);
michael@0 5157
michael@0 5158 rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
michael@0 5159 if (NS_FAILED(rv)) {
michael@0 5160 return rv;
michael@0 5161 }
michael@0 5162 shEntry->SetURI(newUri);
michael@0 5163 }
michael@0 5164
michael@0 5165 rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
michael@0 5166 return rv;
michael@0 5167 }
michael@0 5168
michael@0 5169 NS_IMETHODIMP
michael@0 5170 nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor)
michael@0 5171 {
michael@0 5172 NS_PRECONDITION(aPageDescriptor, "Null out param?");
michael@0 5173
michael@0 5174 *aPageDescriptor = nullptr;
michael@0 5175
michael@0 5176 nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
michael@0 5177 if (src) {
michael@0 5178 nsCOMPtr<nsISHEntry> dest;
michael@0 5179
michael@0 5180 nsresult rv = src->Clone(getter_AddRefs(dest));
michael@0 5181 if (NS_FAILED(rv)) {
michael@0 5182 return rv;
michael@0 5183 }
michael@0 5184
michael@0 5185 // null out inappropriate cloned attributes...
michael@0 5186 dest->SetParent(nullptr);
michael@0 5187 dest->SetIsSubFrame(false);
michael@0 5188
michael@0 5189 return CallQueryInterface(dest, aPageDescriptor);
michael@0 5190 }
michael@0 5191
michael@0 5192 return NS_ERROR_NOT_AVAILABLE;
michael@0 5193 }
michael@0 5194
michael@0 5195
michael@0 5196 //*****************************************************************************
michael@0 5197 // nsDocShell::nsIBaseWindow
michael@0 5198 //*****************************************************************************
michael@0 5199
michael@0 5200 NS_IMETHODIMP
michael@0 5201 nsDocShell::InitWindow(nativeWindow parentNativeWindow,
michael@0 5202 nsIWidget * parentWidget, int32_t x, int32_t y,
michael@0 5203 int32_t cx, int32_t cy)
michael@0 5204 {
michael@0 5205 SetParentWidget(parentWidget);
michael@0 5206 SetPositionAndSize(x, y, cx, cy, false);
michael@0 5207
michael@0 5208 return NS_OK;
michael@0 5209 }
michael@0 5210
michael@0 5211 NS_IMETHODIMP
michael@0 5212 nsDocShell::Create()
michael@0 5213 {
michael@0 5214 if (mCreated) {
michael@0 5215 // We've already been created
michael@0 5216 return NS_OK;
michael@0 5217 }
michael@0 5218
michael@0 5219 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
michael@0 5220 "Unexpected item type in docshell");
michael@0 5221
michael@0 5222 NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
michael@0 5223 mCreated = true;
michael@0 5224
michael@0 5225 mAllowSubframes =
michael@0 5226 Preferences::GetBool("browser.frames.enabled", mAllowSubframes);
michael@0 5227
michael@0 5228 if (gValidateOrigin == 0xffffffff) {
michael@0 5229 // Check pref to see if we should prevent frameset spoofing
michael@0 5230 gValidateOrigin =
michael@0 5231 Preferences::GetBool("browser.frame.validate_origin", true);
michael@0 5232 }
michael@0 5233
michael@0 5234 // Should we use XUL error pages instead of alerts if possible?
michael@0 5235 mUseErrorPages =
michael@0 5236 Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
michael@0 5237
michael@0 5238 if(!gAddedPreferencesVarCache) {
michael@0 5239 Preferences::AddBoolVarCache(&sUseErrorPages,
michael@0 5240 "browser.xul.error_pages.enabled",
michael@0 5241 mUseErrorPages);
michael@0 5242 gAddedPreferencesVarCache = true;
michael@0 5243 }
michael@0 5244
michael@0 5245 mDeviceSizeIsPageSize =
michael@0 5246 Preferences::GetBool("docshell.device_size_is_page_size",
michael@0 5247 mDeviceSizeIsPageSize);
michael@0 5248
michael@0 5249 nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
michael@0 5250 if (serv) {
michael@0 5251 const char* msg = mItemType == typeContent ?
michael@0 5252 NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
michael@0 5253 serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
michael@0 5254 }
michael@0 5255
michael@0 5256 return NS_OK;
michael@0 5257 }
michael@0 5258
michael@0 5259 NS_IMETHODIMP
michael@0 5260 nsDocShell::Destroy()
michael@0 5261 {
michael@0 5262 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
michael@0 5263 "Unexpected item type in docshell");
michael@0 5264
michael@0 5265 if (!mIsBeingDestroyed) {
michael@0 5266 nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
michael@0 5267 if (serv) {
michael@0 5268 const char* msg = mItemType == typeContent ?
michael@0 5269 NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
michael@0 5270 serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
michael@0 5271 }
michael@0 5272 }
michael@0 5273
michael@0 5274 mIsBeingDestroyed = true;
michael@0 5275
michael@0 5276 // Remove our pref observers
michael@0 5277 if (mObserveErrorPages) {
michael@0 5278 mObserveErrorPages = false;
michael@0 5279 }
michael@0 5280
michael@0 5281 // Make sure to blow away our mLoadingURI just in case. No loads
michael@0 5282 // from inside this pagehide.
michael@0 5283 mLoadingURI = nullptr;
michael@0 5284
michael@0 5285 // Fire unload event before we blow anything away.
michael@0 5286 (void) FirePageHideNotification(true);
michael@0 5287
michael@0 5288 // Clear pointers to any detached nsEditorData that's lying
michael@0 5289 // around in shistory entries. Breaks cycle. See bug 430921.
michael@0 5290 if (mOSHE)
michael@0 5291 mOSHE->SetEditorData(nullptr);
michael@0 5292 if (mLSHE)
michael@0 5293 mLSHE->SetEditorData(nullptr);
michael@0 5294
michael@0 5295 // Note: mContentListener can be null if Init() failed and we're being
michael@0 5296 // called from the destructor.
michael@0 5297 if (mContentListener) {
michael@0 5298 mContentListener->DropDocShellreference();
michael@0 5299 mContentListener->SetParentContentListener(nullptr);
michael@0 5300 // Note that we do NOT set mContentListener to null here; that
michael@0 5301 // way if someone tries to do a load in us after this point
michael@0 5302 // the nsDSURIContentListener will block it. All of which
michael@0 5303 // means that we should do this before calling Stop(), of
michael@0 5304 // course.
michael@0 5305 }
michael@0 5306
michael@0 5307 // Stop any URLs that are currently being loaded...
michael@0 5308 Stop(nsIWebNavigation::STOP_ALL);
michael@0 5309
michael@0 5310 mEditorData = nullptr;
michael@0 5311
michael@0 5312 mTransferableHookData = nullptr;
michael@0 5313
michael@0 5314 // Save the state of the current document, before destroying the window.
michael@0 5315 // This is needed to capture the state of a frameset when the new document
michael@0 5316 // causes the frameset to be destroyed...
michael@0 5317 PersistLayoutHistoryState();
michael@0 5318
michael@0 5319 // Remove this docshell from its parent's child list
michael@0 5320 nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
michael@0 5321 do_QueryInterface(GetAsSupports(mParent));
michael@0 5322 if (docShellParentAsItem)
michael@0 5323 docShellParentAsItem->RemoveChild(this);
michael@0 5324
michael@0 5325 if (mContentViewer) {
michael@0 5326 mContentViewer->Close(nullptr);
michael@0 5327 mContentViewer->Destroy();
michael@0 5328 mContentViewer = nullptr;
michael@0 5329 }
michael@0 5330
michael@0 5331 nsDocLoader::Destroy();
michael@0 5332
michael@0 5333 mParentWidget = nullptr;
michael@0 5334 mCurrentURI = nullptr;
michael@0 5335
michael@0 5336 if (mScriptGlobal) {
michael@0 5337 mScriptGlobal->DetachFromDocShell();
michael@0 5338 mScriptGlobal = nullptr;
michael@0 5339 }
michael@0 5340
michael@0 5341 if (mSessionHistory) {
michael@0 5342 // We want to destroy these content viewers now rather than
michael@0 5343 // letting their destruction wait for the session history
michael@0 5344 // entries to get garbage collected. (Bug 488394)
michael@0 5345 nsCOMPtr<nsISHistoryInternal> shPrivate =
michael@0 5346 do_QueryInterface(mSessionHistory);
michael@0 5347 if (shPrivate) {
michael@0 5348 shPrivate->EvictAllContentViewers();
michael@0 5349 }
michael@0 5350 mSessionHistory = nullptr;
michael@0 5351 }
michael@0 5352
michael@0 5353 SetTreeOwner(nullptr);
michael@0 5354
michael@0 5355 mOnePermittedSandboxedNavigator = nullptr;
michael@0 5356
michael@0 5357 // required to break ref cycle
michael@0 5358 mSecurityUI = nullptr;
michael@0 5359
michael@0 5360 // Cancel any timers that were set for this docshell; this is needed
michael@0 5361 // to break the cycle between us and the timers.
michael@0 5362 CancelRefreshURITimers();
michael@0 5363
michael@0 5364 if (mInPrivateBrowsing) {
michael@0 5365 mInPrivateBrowsing = false;
michael@0 5366 if (mAffectPrivateSessionLifetime) {
michael@0 5367 DecreasePrivateDocShellCount();
michael@0 5368 }
michael@0 5369 }
michael@0 5370
michael@0 5371 return NS_OK;
michael@0 5372 }
michael@0 5373
michael@0 5374 NS_IMETHODIMP
michael@0 5375 nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
michael@0 5376 {
michael@0 5377 if (mParentWidget) {
michael@0 5378 *aScale = mParentWidget->GetDefaultScale().scale;
michael@0 5379 return NS_OK;
michael@0 5380 }
michael@0 5381
michael@0 5382 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
michael@0 5383 if (ownerWindow) {
michael@0 5384 return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
michael@0 5385 }
michael@0 5386
michael@0 5387 *aScale = 1.0;
michael@0 5388 return NS_OK;
michael@0 5389 }
michael@0 5390
michael@0 5391 NS_IMETHODIMP
michael@0 5392 nsDocShell::SetPosition(int32_t x, int32_t y)
michael@0 5393 {
michael@0 5394 mBounds.x = x;
michael@0 5395 mBounds.y = y;
michael@0 5396
michael@0 5397 if (mContentViewer)
michael@0 5398 NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE);
michael@0 5399
michael@0 5400 return NS_OK;
michael@0 5401 }
michael@0 5402
michael@0 5403 NS_IMETHODIMP
michael@0 5404 nsDocShell::GetPosition(int32_t * aX, int32_t * aY)
michael@0 5405 {
michael@0 5406 int32_t dummyHolder;
michael@0 5407 return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder);
michael@0 5408 }
michael@0 5409
michael@0 5410 NS_IMETHODIMP
michael@0 5411 nsDocShell::SetSize(int32_t aCX, int32_t aCY, bool aRepaint)
michael@0 5412 {
michael@0 5413 int32_t x = 0, y = 0;
michael@0 5414 GetPosition(&x, &y);
michael@0 5415 return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
michael@0 5416 }
michael@0 5417
michael@0 5418 NS_IMETHODIMP
michael@0 5419 nsDocShell::GetSize(int32_t * aCX, int32_t * aCY)
michael@0 5420 {
michael@0 5421 int32_t dummyHolder;
michael@0 5422 return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY);
michael@0 5423 }
michael@0 5424
michael@0 5425 NS_IMETHODIMP
michael@0 5426 nsDocShell::SetPositionAndSize(int32_t x, int32_t y, int32_t cx,
michael@0 5427 int32_t cy, bool fRepaint)
michael@0 5428 {
michael@0 5429 mBounds.x = x;
michael@0 5430 mBounds.y = y;
michael@0 5431 mBounds.width = cx;
michael@0 5432 mBounds.height = cy;
michael@0 5433
michael@0 5434 // Hold strong ref, since SetBounds can make us null out mContentViewer
michael@0 5435 nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
michael@0 5436 if (viewer) {
michael@0 5437 //XXX Border figured in here or is that handled elsewhere?
michael@0 5438 NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE);
michael@0 5439 }
michael@0 5440
michael@0 5441 return NS_OK;
michael@0 5442 }
michael@0 5443
michael@0 5444 NS_IMETHODIMP
michael@0 5445 nsDocShell::GetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx,
michael@0 5446 int32_t * cy)
michael@0 5447 {
michael@0 5448 if (mParentWidget) {
michael@0 5449 // ensure size is up-to-date if window has changed resolution
michael@0 5450 nsIntRect r;
michael@0 5451 mParentWidget->GetClientBounds(r);
michael@0 5452 SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, false);
michael@0 5453 }
michael@0 5454
michael@0 5455 // We should really consider just getting this information from
michael@0 5456 // our window instead of duplicating the storage and code...
michael@0 5457 if (cx || cy) {
michael@0 5458 // Caller wants to know our size; make sure to give them up to
michael@0 5459 // date information.
michael@0 5460 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
michael@0 5461 if (doc) {
michael@0 5462 doc->FlushPendingNotifications(Flush_Layout);
michael@0 5463 }
michael@0 5464 }
michael@0 5465
michael@0 5466 DoGetPositionAndSize(x, y, cx, cy);
michael@0 5467 return NS_OK;
michael@0 5468 }
michael@0 5469
michael@0 5470 void
michael@0 5471 nsDocShell::DoGetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx,
michael@0 5472 int32_t * cy)
michael@0 5473 {
michael@0 5474 if (x)
michael@0 5475 *x = mBounds.x;
michael@0 5476 if (y)
michael@0 5477 *y = mBounds.y;
michael@0 5478 if (cx)
michael@0 5479 *cx = mBounds.width;
michael@0 5480 if (cy)
michael@0 5481 *cy = mBounds.height;
michael@0 5482 }
michael@0 5483
michael@0 5484 NS_IMETHODIMP
michael@0 5485 nsDocShell::Repaint(bool aForce)
michael@0 5486 {
michael@0 5487 nsCOMPtr<nsIPresShell> presShell =GetPresShell();
michael@0 5488 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
michael@0 5489
michael@0 5490 nsViewManager* viewManager = presShell->GetViewManager();
michael@0 5491 NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
michael@0 5492
michael@0 5493 viewManager->InvalidateAllViews();
michael@0 5494 return NS_OK;
michael@0 5495 }
michael@0 5496
michael@0 5497 NS_IMETHODIMP
michael@0 5498 nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
michael@0 5499 {
michael@0 5500 NS_ENSURE_ARG_POINTER(parentWidget);
michael@0 5501
michael@0 5502 *parentWidget = mParentWidget;
michael@0 5503 NS_IF_ADDREF(*parentWidget);
michael@0 5504
michael@0 5505 return NS_OK;
michael@0 5506 }
michael@0 5507
michael@0 5508 NS_IMETHODIMP
michael@0 5509 nsDocShell::SetParentWidget(nsIWidget * aParentWidget)
michael@0 5510 {
michael@0 5511 mParentWidget = aParentWidget;
michael@0 5512
michael@0 5513 return NS_OK;
michael@0 5514 }
michael@0 5515
michael@0 5516 NS_IMETHODIMP
michael@0 5517 nsDocShell::GetParentNativeWindow(nativeWindow * parentNativeWindow)
michael@0 5518 {
michael@0 5519 NS_ENSURE_ARG_POINTER(parentNativeWindow);
michael@0 5520
michael@0 5521 if (mParentWidget)
michael@0 5522 *parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
michael@0 5523 else
michael@0 5524 *parentNativeWindow = nullptr;
michael@0 5525
michael@0 5526 return NS_OK;
michael@0 5527 }
michael@0 5528
michael@0 5529 NS_IMETHODIMP
michael@0 5530 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
michael@0 5531 {
michael@0 5532 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 5533 }
michael@0 5534
michael@0 5535 NS_IMETHODIMP
michael@0 5536 nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
michael@0 5537 {
michael@0 5538 // the nativeHandle should be accessed from nsIXULWindow
michael@0 5539 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 5540 }
michael@0 5541
michael@0 5542 NS_IMETHODIMP
michael@0 5543 nsDocShell::GetVisibility(bool * aVisibility)
michael@0 5544 {
michael@0 5545 NS_ENSURE_ARG_POINTER(aVisibility);
michael@0 5546
michael@0 5547 *aVisibility = false;
michael@0 5548
michael@0 5549 if (!mContentViewer)
michael@0 5550 return NS_OK;
michael@0 5551
michael@0 5552 nsCOMPtr<nsIPresShell> presShell = GetPresShell();
michael@0 5553 if (!presShell)
michael@0 5554 return NS_OK;
michael@0 5555
michael@0 5556 // get the view manager
michael@0 5557 nsViewManager* vm = presShell->GetViewManager();
michael@0 5558 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
michael@0 5559
michael@0 5560 // get the root view
michael@0 5561 nsView *view = vm->GetRootView(); // views are not ref counted
michael@0 5562 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
michael@0 5563
michael@0 5564 // if our root view is hidden, we are not visible
michael@0 5565 if (view->GetVisibility() == nsViewVisibility_kHide)
michael@0 5566 return NS_OK;
michael@0 5567
michael@0 5568 // otherwise, we must walk up the document and view trees checking
michael@0 5569 // for a hidden view, unless we're an off screen browser, which
michael@0 5570 // would make this test meaningless.
michael@0 5571
michael@0 5572 nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
michael@0 5573 nsCOMPtr<nsIDocShellTreeItem> parentItem;
michael@0 5574 treeItem->GetParent(getter_AddRefs(parentItem));
michael@0 5575 while (parentItem) {
michael@0 5576 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem));
michael@0 5577 presShell = docShell->GetPresShell();
michael@0 5578
michael@0 5579 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem);
michael@0 5580 nsCOMPtr<nsIPresShell> pPresShell = parentDS->GetPresShell();
michael@0 5581
michael@0 5582 // Null-check for crash in bug 267804
michael@0 5583 if (!pPresShell) {
michael@0 5584 NS_NOTREACHED("parent docshell has null pres shell");
michael@0 5585 return NS_OK;
michael@0 5586 }
michael@0 5587
michael@0 5588 nsIContent *shellContent =
michael@0 5589 pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument());
michael@0 5590 NS_ASSERTION(shellContent, "subshell not in the map");
michael@0 5591
michael@0 5592 nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nullptr;
michael@0 5593 bool isDocShellOffScreen = false;
michael@0 5594 docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
michael@0 5595 if (frame &&
michael@0 5596 !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
michael@0 5597 !isDocShellOffScreen) {
michael@0 5598 return NS_OK;
michael@0 5599 }
michael@0 5600
michael@0 5601 treeItem = parentItem;
michael@0 5602 treeItem->GetParent(getter_AddRefs(parentItem));
michael@0 5603 }
michael@0 5604
michael@0 5605 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
michael@0 5606 if (!treeOwnerAsWin) {
michael@0 5607 *aVisibility = true;
michael@0 5608 return NS_OK;
michael@0 5609 }
michael@0 5610
michael@0 5611 // Check with the tree owner as well to give embedders a chance to
michael@0 5612 // expose visibility as well.
michael@0 5613 return treeOwnerAsWin->GetVisibility(aVisibility);
michael@0 5614 }
michael@0 5615
michael@0 5616 NS_IMETHODIMP
michael@0 5617 nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen)
michael@0 5618 {
michael@0 5619 mIsOffScreenBrowser = aIsOffScreen;
michael@0 5620 return NS_OK;
michael@0 5621 }
michael@0 5622
michael@0 5623 NS_IMETHODIMP
michael@0 5624 nsDocShell::GetIsOffScreenBrowser(bool *aIsOffScreen)
michael@0 5625 {
michael@0 5626 *aIsOffScreen = mIsOffScreenBrowser;
michael@0 5627 return NS_OK;
michael@0 5628 }
michael@0 5629
michael@0 5630 NS_IMETHODIMP
michael@0 5631 nsDocShell::SetIsActive(bool aIsActive)
michael@0 5632 {
michael@0 5633 // We disallow setting active on chrome docshells.
michael@0 5634 if (mItemType == nsIDocShellTreeItem::typeChrome)
michael@0 5635 return NS_ERROR_INVALID_ARG;
michael@0 5636
michael@0 5637 // Keep track ourselves.
michael@0 5638 mIsActive = aIsActive;
michael@0 5639
michael@0 5640 // Tell the PresShell about it.
michael@0 5641 nsCOMPtr<nsIPresShell> pshell = GetPresShell();
michael@0 5642 if (pshell)
michael@0 5643 pshell->SetIsActive(aIsActive);
michael@0 5644
michael@0 5645 // Tell the window about it
michael@0 5646 if (mScriptGlobal) {
michael@0 5647 mScriptGlobal->SetIsBackground(!aIsActive);
michael@0 5648 if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
michael@0 5649 doc->PostVisibilityUpdateEvent();
michael@0 5650 }
michael@0 5651 }
michael@0 5652
michael@0 5653 // Recursively tell all of our children, but don't tell <iframe mozbrowser>
michael@0 5654 // children; they handle their state separately.
michael@0 5655 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 5656 while (iter.HasMore()) {
michael@0 5657 nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
michael@0 5658 if (!docshell) {
michael@0 5659 continue;
michael@0 5660 }
michael@0 5661
michael@0 5662 if (!docshell->GetIsBrowserOrApp()) {
michael@0 5663 docshell->SetIsActive(aIsActive);
michael@0 5664 }
michael@0 5665 }
michael@0 5666
michael@0 5667 return NS_OK;
michael@0 5668 }
michael@0 5669
michael@0 5670 NS_IMETHODIMP
michael@0 5671 nsDocShell::GetIsActive(bool *aIsActive)
michael@0 5672 {
michael@0 5673 *aIsActive = mIsActive;
michael@0 5674 return NS_OK;
michael@0 5675 }
michael@0 5676
michael@0 5677 NS_IMETHODIMP
michael@0 5678 nsDocShell::SetIsAppTab(bool aIsAppTab)
michael@0 5679 {
michael@0 5680 mIsAppTab = aIsAppTab;
michael@0 5681 return NS_OK;
michael@0 5682 }
michael@0 5683
michael@0 5684 NS_IMETHODIMP
michael@0 5685 nsDocShell::GetIsAppTab(bool *aIsAppTab)
michael@0 5686 {
michael@0 5687 *aIsAppTab = mIsAppTab;
michael@0 5688 return NS_OK;
michael@0 5689 }
michael@0 5690
michael@0 5691 NS_IMETHODIMP
michael@0 5692 nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags)
michael@0 5693 {
michael@0 5694 mSandboxFlags = aSandboxFlags;
michael@0 5695 return NS_OK;
michael@0 5696 }
michael@0 5697
michael@0 5698 NS_IMETHODIMP
michael@0 5699 nsDocShell::GetSandboxFlags(uint32_t *aSandboxFlags)
michael@0 5700 {
michael@0 5701 *aSandboxFlags = mSandboxFlags;
michael@0 5702 return NS_OK;
michael@0 5703 }
michael@0 5704
michael@0 5705 NS_IMETHODIMP
michael@0 5706 nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
michael@0 5707 {
michael@0 5708 if (mOnePermittedSandboxedNavigator) {
michael@0 5709 NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
michael@0 5710 return NS_OK;
michael@0 5711 }
michael@0 5712
michael@0 5713 mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
michael@0 5714 NS_ASSERTION(mOnePermittedSandboxedNavigator,
michael@0 5715 "One Permitted Sandboxed Navigator must support weak references.");
michael@0 5716
michael@0 5717 return NS_OK;
michael@0 5718 }
michael@0 5719
michael@0 5720 NS_IMETHODIMP
michael@0 5721 nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator)
michael@0 5722 {
michael@0 5723 NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
michael@0 5724 nsCOMPtr<nsIDocShell> permittedNavigator =
michael@0 5725 do_QueryReferent(mOnePermittedSandboxedNavigator);
michael@0 5726 NS_IF_ADDREF(*aSandboxedNavigator = permittedNavigator);
michael@0 5727 return NS_OK;
michael@0 5728 }
michael@0 5729
michael@0 5730 NS_IMETHODIMP
michael@0 5731 nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)
michael@0 5732 {
michael@0 5733 mDefaultLoadFlags = aDefaultLoadFlags;
michael@0 5734
michael@0 5735 // Tell the load group to set these flags all requests in the group
michael@0 5736 if (mLoadGroup) {
michael@0 5737 mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
michael@0 5738 } else {
michael@0 5739 NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to");
michael@0 5740 }
michael@0 5741
michael@0 5742 // Recursively tell all of our children. We *do not* skip
michael@0 5743 // <iframe mozbrowser> children - if someone sticks custom flags in this
michael@0 5744 // docShell then they too get the same flags.
michael@0 5745 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 5746 while (iter.HasMore()) {
michael@0 5747 nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
michael@0 5748 if (!docshell) {
michael@0 5749 continue;
michael@0 5750 }
michael@0 5751 docshell->SetDefaultLoadFlags(aDefaultLoadFlags);
michael@0 5752 }
michael@0 5753 return NS_OK;
michael@0 5754 }
michael@0 5755
michael@0 5756 NS_IMETHODIMP
michael@0 5757 nsDocShell::GetDefaultLoadFlags(uint32_t *aDefaultLoadFlags)
michael@0 5758 {
michael@0 5759 *aDefaultLoadFlags = mDefaultLoadFlags;
michael@0 5760 return NS_OK;
michael@0 5761 }
michael@0 5762
michael@0 5763
michael@0 5764 NS_IMETHODIMP
michael@0 5765 nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
michael@0 5766 {
michael@0 5767 #ifdef DEBUG
michael@0 5768 // if the channel is non-null
michael@0 5769 if (aMixedContentChannel) {
michael@0 5770 // Get the root docshell.
michael@0 5771 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 5772 GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 5773 NS_WARN_IF_FALSE(
michael@0 5774 root.get() == static_cast<nsIDocShellTreeItem *>(this),
michael@0 5775 "Setting mMixedContentChannel on a docshell that is not the root docshell"
michael@0 5776 );
michael@0 5777 }
michael@0 5778 #endif
michael@0 5779 mMixedContentChannel = aMixedContentChannel;
michael@0 5780 return NS_OK;
michael@0 5781 }
michael@0 5782
michael@0 5783 NS_IMETHODIMP
michael@0 5784 nsDocShell::GetMixedContentChannel(nsIChannel **aMixedContentChannel)
michael@0 5785 {
michael@0 5786 NS_ENSURE_ARG_POINTER(aMixedContentChannel);
michael@0 5787 NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
michael@0 5788 return NS_OK;
michael@0 5789 }
michael@0 5790
michael@0 5791 NS_IMETHODIMP
michael@0 5792 nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection, bool* aAllowMixedContent, bool* aIsRootDocShell)
michael@0 5793 {
michael@0 5794 *aRootHasSecureConnection = true;
michael@0 5795 *aAllowMixedContent = false;
michael@0 5796 *aIsRootDocShell = false;
michael@0 5797
michael@0 5798 nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
michael@0 5799 GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
michael@0 5800 NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
michael@0 5801 *aIsRootDocShell = sameTypeRoot.get() == static_cast<nsIDocShellTreeItem *>(this);
michael@0 5802
michael@0 5803 // now get the document from sameTypeRoot
michael@0 5804 nsCOMPtr<nsIDocument> rootDoc = do_GetInterface(sameTypeRoot);
michael@0 5805 if (rootDoc) {
michael@0 5806 nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
michael@0 5807
michael@0 5808 // For things with system principal (e.g. scratchpad) there is no uri
michael@0 5809 // aRootHasSecureConnection should be false.
michael@0 5810 nsCOMPtr<nsIURI> rootUri;
michael@0 5811 if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
michael@0 5812 NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
michael@0 5813 NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) {
michael@0 5814 *aRootHasSecureConnection = false;
michael@0 5815 }
michael@0 5816
michael@0 5817 // Check the root doc's channel against the root docShell's mMixedContentChannel to see
michael@0 5818 // if they are the same. If they are the same, the user has overriden
michael@0 5819 // the block.
michael@0 5820 nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot);
michael@0 5821 nsCOMPtr<nsIChannel> mixedChannel;
michael@0 5822 rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
michael@0 5823 *aAllowMixedContent = mixedChannel && (mixedChannel == rootDoc->GetChannel());
michael@0 5824 }
michael@0 5825
michael@0 5826 return NS_OK;
michael@0 5827 }
michael@0 5828
michael@0 5829 NS_IMETHODIMP
michael@0 5830 nsDocShell::SetVisibility(bool aVisibility)
michael@0 5831 {
michael@0 5832 // Show()/Hide() may change mContentViewer.
michael@0 5833 nsCOMPtr<nsIContentViewer> cv = mContentViewer;
michael@0 5834 if (!cv)
michael@0 5835 return NS_OK;
michael@0 5836 if (aVisibility) {
michael@0 5837 cv->Show();
michael@0 5838 }
michael@0 5839 else {
michael@0 5840 cv->Hide();
michael@0 5841 }
michael@0 5842
michael@0 5843 return NS_OK;
michael@0 5844 }
michael@0 5845
michael@0 5846 NS_IMETHODIMP
michael@0 5847 nsDocShell::GetEnabled(bool *aEnabled)
michael@0 5848 {
michael@0 5849 NS_ENSURE_ARG_POINTER(aEnabled);
michael@0 5850 *aEnabled = true;
michael@0 5851 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 5852 }
michael@0 5853
michael@0 5854 NS_IMETHODIMP
michael@0 5855 nsDocShell::SetEnabled(bool aEnabled)
michael@0 5856 {
michael@0 5857 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 5858 }
michael@0 5859
michael@0 5860 NS_IMETHODIMP
michael@0 5861 nsDocShell::SetFocus()
michael@0 5862 {
michael@0 5863 return NS_OK;
michael@0 5864 }
michael@0 5865
michael@0 5866 NS_IMETHODIMP
michael@0 5867 nsDocShell::GetMainWidget(nsIWidget ** aMainWidget)
michael@0 5868 {
michael@0 5869 // We don't create our own widget, so simply return the parent one.
michael@0 5870 return GetParentWidget(aMainWidget);
michael@0 5871 }
michael@0 5872
michael@0 5873 NS_IMETHODIMP
michael@0 5874 nsDocShell::GetTitle(char16_t ** aTitle)
michael@0 5875 {
michael@0 5876 NS_ENSURE_ARG_POINTER(aTitle);
michael@0 5877
michael@0 5878 *aTitle = ToNewUnicode(mTitle);
michael@0 5879 return NS_OK;
michael@0 5880 }
michael@0 5881
michael@0 5882 NS_IMETHODIMP
michael@0 5883 nsDocShell::SetTitle(const char16_t * aTitle)
michael@0 5884 {
michael@0 5885 // Store local title
michael@0 5886 mTitle = aTitle;
michael@0 5887
michael@0 5888 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 5889 GetSameTypeParent(getter_AddRefs(parent));
michael@0 5890
michael@0 5891 // When title is set on the top object it should then be passed to the
michael@0 5892 // tree owner.
michael@0 5893 if (!parent) {
michael@0 5894 nsCOMPtr<nsIBaseWindow>
michael@0 5895 treeOwnerAsWin(do_QueryInterface(mTreeOwner));
michael@0 5896 if (treeOwnerAsWin)
michael@0 5897 treeOwnerAsWin->SetTitle(aTitle);
michael@0 5898 }
michael@0 5899
michael@0 5900 if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE && mUseGlobalHistory &&
michael@0 5901 !mInPrivateBrowsing) {
michael@0 5902 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 5903 if (history) {
michael@0 5904 history->SetURITitle(mCurrentURI, mTitle);
michael@0 5905 }
michael@0 5906 else if (mGlobalHistory) {
michael@0 5907 mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
michael@0 5908 }
michael@0 5909 }
michael@0 5910
michael@0 5911 // Update SessionHistory with the document's title.
michael@0 5912 if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
michael@0 5913 mLoadType != LOAD_ERROR_PAGE) {
michael@0 5914
michael@0 5915 mOSHE->SetTitle(mTitle);
michael@0 5916 }
michael@0 5917
michael@0 5918 return NS_OK;
michael@0 5919 }
michael@0 5920
michael@0 5921 nsresult
michael@0 5922 nsDocShell::GetCurScrollPos(int32_t scrollOrientation, int32_t * curPos)
michael@0 5923 {
michael@0 5924 NS_ENSURE_ARG_POINTER(curPos);
michael@0 5925
michael@0 5926 nsIScrollableFrame* sf = GetRootScrollFrame();
michael@0 5927 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
michael@0 5928
michael@0 5929 nsPoint pt = sf->GetScrollPosition();
michael@0 5930
michael@0 5931 switch (scrollOrientation) {
michael@0 5932 case ScrollOrientation_X:
michael@0 5933 *curPos = pt.x;
michael@0 5934 return NS_OK;
michael@0 5935
michael@0 5936 case ScrollOrientation_Y:
michael@0 5937 *curPos = pt.y;
michael@0 5938 return NS_OK;
michael@0 5939
michael@0 5940 default:
michael@0 5941 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
michael@0 5942 }
michael@0 5943 }
michael@0 5944
michael@0 5945 nsresult
michael@0 5946 nsDocShell::SetCurScrollPosEx(int32_t curHorizontalPos, int32_t curVerticalPos)
michael@0 5947 {
michael@0 5948 nsIScrollableFrame* sf = GetRootScrollFrame();
michael@0 5949 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
michael@0 5950
michael@0 5951 sf->ScrollTo(nsPoint(curHorizontalPos, curVerticalPos),
michael@0 5952 nsIScrollableFrame::INSTANT);
michael@0 5953 return NS_OK;
michael@0 5954 }
michael@0 5955
michael@0 5956 //*****************************************************************************
michael@0 5957 // nsDocShell::nsIScrollable
michael@0 5958 //*****************************************************************************
michael@0 5959
michael@0 5960 NS_IMETHODIMP
michael@0 5961 nsDocShell::GetDefaultScrollbarPreferences(int32_t scrollOrientation,
michael@0 5962 int32_t * scrollbarPref)
michael@0 5963 {
michael@0 5964 NS_ENSURE_ARG_POINTER(scrollbarPref);
michael@0 5965 switch (scrollOrientation) {
michael@0 5966 case ScrollOrientation_X:
michael@0 5967 *scrollbarPref = mDefaultScrollbarPref.x;
michael@0 5968 return NS_OK;
michael@0 5969
michael@0 5970 case ScrollOrientation_Y:
michael@0 5971 *scrollbarPref = mDefaultScrollbarPref.y;
michael@0 5972 return NS_OK;
michael@0 5973
michael@0 5974 default:
michael@0 5975 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
michael@0 5976 }
michael@0 5977 return NS_ERROR_FAILURE;
michael@0 5978 }
michael@0 5979
michael@0 5980 NS_IMETHODIMP
michael@0 5981 nsDocShell::SetDefaultScrollbarPreferences(int32_t scrollOrientation,
michael@0 5982 int32_t scrollbarPref)
michael@0 5983 {
michael@0 5984 switch (scrollOrientation) {
michael@0 5985 case ScrollOrientation_X:
michael@0 5986 mDefaultScrollbarPref.x = scrollbarPref;
michael@0 5987 return NS_OK;
michael@0 5988
michael@0 5989 case ScrollOrientation_Y:
michael@0 5990 mDefaultScrollbarPref.y = scrollbarPref;
michael@0 5991 return NS_OK;
michael@0 5992
michael@0 5993 default:
michael@0 5994 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
michael@0 5995 }
michael@0 5996 return NS_ERROR_FAILURE;
michael@0 5997 }
michael@0 5998
michael@0 5999 NS_IMETHODIMP
michael@0 6000 nsDocShell::GetScrollbarVisibility(bool * verticalVisible,
michael@0 6001 bool * horizontalVisible)
michael@0 6002 {
michael@0 6003 nsIScrollableFrame* sf = GetRootScrollFrame();
michael@0 6004 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
michael@0 6005
michael@0 6006 uint32_t scrollbarVisibility = sf->GetScrollbarVisibility();
michael@0 6007 if (verticalVisible)
michael@0 6008 *verticalVisible = (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
michael@0 6009 if (horizontalVisible)
michael@0 6010 *horizontalVisible = (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
michael@0 6011
michael@0 6012 return NS_OK;
michael@0 6013 }
michael@0 6014
michael@0 6015 //*****************************************************************************
michael@0 6016 // nsDocShell::nsITextScroll
michael@0 6017 //*****************************************************************************
michael@0 6018
michael@0 6019 NS_IMETHODIMP
michael@0 6020 nsDocShell::ScrollByLines(int32_t numLines)
michael@0 6021 {
michael@0 6022 nsIScrollableFrame* sf = GetRootScrollFrame();
michael@0 6023 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
michael@0 6024
michael@0 6025 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
michael@0 6026 nsIScrollableFrame::SMOOTH);
michael@0 6027 return NS_OK;
michael@0 6028 }
michael@0 6029
michael@0 6030 NS_IMETHODIMP
michael@0 6031 nsDocShell::ScrollByPages(int32_t numPages)
michael@0 6032 {
michael@0 6033 nsIScrollableFrame* sf = GetRootScrollFrame();
michael@0 6034 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
michael@0 6035
michael@0 6036 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
michael@0 6037 nsIScrollableFrame::SMOOTH);
michael@0 6038 return NS_OK;
michael@0 6039 }
michael@0 6040
michael@0 6041 //*****************************************************************************
michael@0 6042 // nsDocShell::nsIRefreshURI
michael@0 6043 //*****************************************************************************
michael@0 6044
michael@0 6045 NS_IMETHODIMP
michael@0 6046 nsDocShell::RefreshURI(nsIURI * aURI, int32_t aDelay, bool aRepeat,
michael@0 6047 bool aMetaRefresh)
michael@0 6048 {
michael@0 6049 NS_ENSURE_ARG(aURI);
michael@0 6050
michael@0 6051 /* Check if Meta refresh/redirects are permitted. Some
michael@0 6052 * embedded applications may not want to do this.
michael@0 6053 * Must do this before sending out NOTIFY_REFRESH events
michael@0 6054 * because listeners may have side effects (e.g. displaying a
michael@0 6055 * button to manually trigger the refresh later).
michael@0 6056 */
michael@0 6057 bool allowRedirects = true;
michael@0 6058 GetAllowMetaRedirects(&allowRedirects);
michael@0 6059 if (!allowRedirects)
michael@0 6060 return NS_OK;
michael@0 6061
michael@0 6062 // If any web progress listeners are listening for NOTIFY_REFRESH events,
michael@0 6063 // give them a chance to block this refresh.
michael@0 6064 bool sameURI;
michael@0 6065 nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
michael@0 6066 if (NS_FAILED(rv))
michael@0 6067 sameURI = false;
michael@0 6068 if (!RefreshAttempted(this, aURI, aDelay, sameURI))
michael@0 6069 return NS_OK;
michael@0 6070
michael@0 6071 nsRefreshTimer *refreshTimer = new nsRefreshTimer();
michael@0 6072 NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
michael@0 6073 uint32_t busyFlags = 0;
michael@0 6074 GetBusyFlags(&busyFlags);
michael@0 6075
michael@0 6076 nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1
michael@0 6077
michael@0 6078 refreshTimer->mDocShell = this;
michael@0 6079 refreshTimer->mURI = aURI;
michael@0 6080 refreshTimer->mDelay = aDelay;
michael@0 6081 refreshTimer->mRepeat = aRepeat;
michael@0 6082 refreshTimer->mMetaRefresh = aMetaRefresh;
michael@0 6083
michael@0 6084 if (!mRefreshURIList) {
michael@0 6085 NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
michael@0 6086 NS_ERROR_FAILURE);
michael@0 6087 }
michael@0 6088
michael@0 6089 if (busyFlags & BUSY_FLAGS_BUSY) {
michael@0 6090 // We are busy loading another page. Don't create the
michael@0 6091 // timer right now. Instead queue up the request and trigger the
michael@0 6092 // timer in EndPageLoad().
michael@0 6093 mRefreshURIList->AppendElement(refreshTimer);
michael@0 6094 }
michael@0 6095 else {
michael@0 6096 // There is no page loading going on right now. Create the
michael@0 6097 // timer and fire it right away.
michael@0 6098 nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 6099 NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
michael@0 6100
michael@0 6101 mRefreshURIList->AppendElement(timer); // owning timer ref
michael@0 6102 timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
michael@0 6103 }
michael@0 6104 return NS_OK;
michael@0 6105 }
michael@0 6106
michael@0 6107 nsresult
michael@0 6108 nsDocShell::ForceRefreshURIFromTimer(nsIURI * aURI,
michael@0 6109 int32_t aDelay,
michael@0 6110 bool aMetaRefresh,
michael@0 6111 nsITimer* aTimer)
michael@0 6112 {
michael@0 6113 NS_PRECONDITION(aTimer, "Must have a timer here");
michael@0 6114
michael@0 6115 // Remove aTimer from mRefreshURIList if needed
michael@0 6116 if (mRefreshURIList) {
michael@0 6117 uint32_t n = 0;
michael@0 6118 mRefreshURIList->Count(&n);
michael@0 6119
michael@0 6120 for (uint32_t i = 0; i < n; ++i) {
michael@0 6121 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
michael@0 6122 if (timer == aTimer) {
michael@0 6123 mRefreshURIList->RemoveElementAt(i);
michael@0 6124 break;
michael@0 6125 }
michael@0 6126 }
michael@0 6127 }
michael@0 6128
michael@0 6129 return ForceRefreshURI(aURI, aDelay, aMetaRefresh);
michael@0 6130 }
michael@0 6131
michael@0 6132 NS_IMETHODIMP
michael@0 6133 nsDocShell::ForceRefreshURI(nsIURI * aURI,
michael@0 6134 int32_t aDelay,
michael@0 6135 bool aMetaRefresh)
michael@0 6136 {
michael@0 6137 NS_ENSURE_ARG(aURI);
michael@0 6138
michael@0 6139 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
michael@0 6140 CreateLoadInfo(getter_AddRefs(loadInfo));
michael@0 6141 NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
michael@0 6142
michael@0 6143 /* We do need to pass in a referrer, but we don't want it to
michael@0 6144 * be sent to the server.
michael@0 6145 */
michael@0 6146 loadInfo->SetSendReferrer(false);
michael@0 6147
michael@0 6148 /* for most refreshes the current URI is an appropriate
michael@0 6149 * internal referrer
michael@0 6150 */
michael@0 6151 loadInfo->SetReferrer(mCurrentURI);
michael@0 6152
michael@0 6153 /* Don't ever "guess" on which owner to use to avoid picking
michael@0 6154 * the current owner.
michael@0 6155 */
michael@0 6156 loadInfo->SetOwnerIsExplicit(true);
michael@0 6157
michael@0 6158 /* Check if this META refresh causes a redirection
michael@0 6159 * to another site.
michael@0 6160 */
michael@0 6161 bool equalUri = false;
michael@0 6162 nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
michael@0 6163 if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
michael@0 6164 aDelay <= REFRESH_REDIRECT_TIMER) {
michael@0 6165
michael@0 6166 /* It is a META refresh based redirection within the threshold time
michael@0 6167 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
michael@0 6168 * Pass a REPLACE flag to LoadURI().
michael@0 6169 */
michael@0 6170 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
michael@0 6171
michael@0 6172 /* for redirects we mimic HTTP, which passes the
michael@0 6173 * original referrer
michael@0 6174 */
michael@0 6175 nsCOMPtr<nsIURI> internalReferrer;
michael@0 6176 GetReferringURI(getter_AddRefs(internalReferrer));
michael@0 6177 if (internalReferrer) {
michael@0 6178 loadInfo->SetReferrer(internalReferrer);
michael@0 6179 }
michael@0 6180 }
michael@0 6181 else {
michael@0 6182 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
michael@0 6183 }
michael@0 6184
michael@0 6185 /*
michael@0 6186 * LoadURI(...) will cancel all refresh timers... This causes the
michael@0 6187 * Timer and its refreshData instance to be released...
michael@0 6188 */
michael@0 6189 LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
michael@0 6190
michael@0 6191 return NS_OK;
michael@0 6192 }
michael@0 6193
michael@0 6194 nsresult
michael@0 6195 nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
michael@0 6196 nsIPrincipal* aPrincipal,
michael@0 6197 const nsACString & aHeader)
michael@0 6198 {
michael@0 6199 // Refresh headers are parsed with the following format in mind
michael@0 6200 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
michael@0 6201 // By the time we are here, the following is true:
michael@0 6202 // header = "REFRESH"
michael@0 6203 // content = "5; URL=http://uri" // note the URL attribute is
michael@0 6204 // optional, if it is absent, the currently loaded url is used.
michael@0 6205 // Also note that the seconds and URL separator can be either
michael@0 6206 // a ';' or a ','. The ',' separator should be illegal but CNN
michael@0 6207 // is using it.
michael@0 6208 //
michael@0 6209 // We need to handle the following strings, where
michael@0 6210 // - X is a set of digits
michael@0 6211 // - URI is either a relative or absolute URI
michael@0 6212 //
michael@0 6213 // Note that URI should start with "url=" but we allow omission
michael@0 6214 //
michael@0 6215 // "" || ";" || ","
michael@0 6216 // empty string. use the currently loaded URI
michael@0 6217 // and refresh immediately.
michael@0 6218 // "X" || "X;" || "X,"
michael@0 6219 // Refresh the currently loaded URI in X seconds.
michael@0 6220 // "X; URI" || "X, URI"
michael@0 6221 // Refresh using URI as the destination in X seconds.
michael@0 6222 // "URI" || "; URI" || ", URI"
michael@0 6223 // Refresh immediately using URI as the destination.
michael@0 6224 //
michael@0 6225 // Currently, anything immediately following the URI, if
michael@0 6226 // separated by any char in the set "'\"\t\r\n " will be
michael@0 6227 // ignored. So "10; url=go.html ; foo=bar" will work,
michael@0 6228 // and so will "10; url='go.html'; foo=bar". However,
michael@0 6229 // "10; url=go.html; foo=bar" will result in the uri
michael@0 6230 // "go.html;" since ';' and ',' are valid uri characters.
michael@0 6231 //
michael@0 6232 // Note that we need to remove any tokens wrapping the URI.
michael@0 6233 // These tokens currently include spaces, double and single
michael@0 6234 // quotes.
michael@0 6235
michael@0 6236 // when done, seconds is 0 or the given number of seconds
michael@0 6237 // uriAttrib is empty or the URI specified
michael@0 6238 MOZ_ASSERT(aPrincipal);
michael@0 6239
michael@0 6240 nsAutoCString uriAttrib;
michael@0 6241 int32_t seconds = 0;
michael@0 6242 bool specifiesSeconds = false;
michael@0 6243
michael@0 6244 nsACString::const_iterator iter, tokenStart, doneIterating;
michael@0 6245
michael@0 6246 aHeader.BeginReading(iter);
michael@0 6247 aHeader.EndReading(doneIterating);
michael@0 6248
michael@0 6249 // skip leading whitespace
michael@0 6250 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
michael@0 6251 ++iter;
michael@0 6252
michael@0 6253 tokenStart = iter;
michael@0 6254
michael@0 6255 // skip leading + and -
michael@0 6256 if (iter != doneIterating && (*iter == '-' || *iter == '+'))
michael@0 6257 ++iter;
michael@0 6258
michael@0 6259 // parse number
michael@0 6260 while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
michael@0 6261 seconds = seconds * 10 + (*iter - '0');
michael@0 6262 specifiesSeconds = true;
michael@0 6263 ++iter;
michael@0 6264 }
michael@0 6265
michael@0 6266 if (iter != doneIterating) {
michael@0 6267 // if we started with a '-', number is negative
michael@0 6268 if (*tokenStart == '-')
michael@0 6269 seconds = -seconds;
michael@0 6270
michael@0 6271 // skip to next ';' or ','
michael@0 6272 nsACString::const_iterator iterAfterDigit = iter;
michael@0 6273 while (iter != doneIterating && !(*iter == ';' || *iter == ','))
michael@0 6274 {
michael@0 6275 if (specifiesSeconds)
michael@0 6276 {
michael@0 6277 // Non-whitespace characters here mean that the string is
michael@0 6278 // malformed but tolerate sites that specify a decimal point,
michael@0 6279 // even though meta refresh only works on whole seconds.
michael@0 6280 if (iter == iterAfterDigit &&
michael@0 6281 !nsCRT::IsAsciiSpace(*iter) && *iter != '.')
michael@0 6282 {
michael@0 6283 // The characters between the seconds and the next
michael@0 6284 // section are just garbage!
michael@0 6285 // e.g. content="2a0z+,URL=http://www.mozilla.org/"
michael@0 6286 // Just ignore this redirect.
michael@0 6287 return NS_ERROR_FAILURE;
michael@0 6288 }
michael@0 6289 else if (nsCRT::IsAsciiSpace(*iter))
michael@0 6290 {
michael@0 6291 // We've had at least one whitespace so tolerate the mistake
michael@0 6292 // and drop through.
michael@0 6293 // e.g. content="10 foo"
michael@0 6294 ++iter;
michael@0 6295 break;
michael@0 6296 }
michael@0 6297 }
michael@0 6298 ++iter;
michael@0 6299 }
michael@0 6300
michael@0 6301 // skip any remaining whitespace
michael@0 6302 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
michael@0 6303 ++iter;
michael@0 6304
michael@0 6305 // skip ';' or ','
michael@0 6306 if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
michael@0 6307 ++iter;
michael@0 6308 }
michael@0 6309
michael@0 6310 // skip whitespace
michael@0 6311 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
michael@0 6312 ++iter;
michael@0 6313 }
michael@0 6314
michael@0 6315 // possible start of URI
michael@0 6316 tokenStart = iter;
michael@0 6317
michael@0 6318 // skip "url = " to real start of URI
michael@0 6319 if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
michael@0 6320 ++iter;
michael@0 6321 if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
michael@0 6322 ++iter;
michael@0 6323 if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
michael@0 6324 ++iter;
michael@0 6325
michael@0 6326 // skip whitespace
michael@0 6327 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
michael@0 6328 ++iter;
michael@0 6329
michael@0 6330 if (iter != doneIterating && *iter == '=') {
michael@0 6331 ++iter;
michael@0 6332
michael@0 6333 // skip whitespace
michael@0 6334 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
michael@0 6335 ++iter;
michael@0 6336
michael@0 6337 // found real start of URI
michael@0 6338 tokenStart = iter;
michael@0 6339 }
michael@0 6340 }
michael@0 6341 }
michael@0 6342 }
michael@0 6343
michael@0 6344 // skip a leading '"' or '\''.
michael@0 6345
michael@0 6346 bool isQuotedURI = false;
michael@0 6347 if (tokenStart != doneIterating && (*tokenStart == '"' || *tokenStart == '\''))
michael@0 6348 {
michael@0 6349 isQuotedURI = true;
michael@0 6350 ++tokenStart;
michael@0 6351 }
michael@0 6352
michael@0 6353 // set iter to start of URI
michael@0 6354 iter = tokenStart;
michael@0 6355
michael@0 6356 // tokenStart here points to the beginning of URI
michael@0 6357
michael@0 6358 // grab the rest of the URI
michael@0 6359 while (iter != doneIterating)
michael@0 6360 {
michael@0 6361 if (isQuotedURI && (*iter == '"' || *iter == '\''))
michael@0 6362 break;
michael@0 6363 ++iter;
michael@0 6364 }
michael@0 6365
michael@0 6366 // move iter one back if the last character is a '"' or '\''
michael@0 6367 if (iter != tokenStart && isQuotedURI) {
michael@0 6368 --iter;
michael@0 6369 if (!(*iter == '"' || *iter == '\''))
michael@0 6370 ++iter;
michael@0 6371 }
michael@0 6372
michael@0 6373 // URI is whatever's contained from tokenStart to iter.
michael@0 6374 // note: if tokenStart == doneIterating, so is iter.
michael@0 6375
michael@0 6376 nsresult rv = NS_OK;
michael@0 6377
michael@0 6378 nsCOMPtr<nsIURI> uri;
michael@0 6379 bool specifiesURI = false;
michael@0 6380 if (tokenStart == iter) {
michael@0 6381 uri = aBaseURI;
michael@0 6382 }
michael@0 6383 else {
michael@0 6384 uriAttrib = Substring(tokenStart, iter);
michael@0 6385 // NS_NewURI takes care of any whitespace surrounding the URL
michael@0 6386 rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI);
michael@0 6387 specifiesURI = true;
michael@0 6388 }
michael@0 6389
michael@0 6390 // No URI or seconds were specified
michael@0 6391 if (!specifiesSeconds && !specifiesURI)
michael@0 6392 {
michael@0 6393 // Do nothing because the alternative is to spin around in a refresh
michael@0 6394 // loop forever!
michael@0 6395 return NS_ERROR_FAILURE;
michael@0 6396 }
michael@0 6397
michael@0 6398 if (NS_SUCCEEDED(rv)) {
michael@0 6399 nsCOMPtr<nsIScriptSecurityManager>
michael@0 6400 securityManager(do_GetService
michael@0 6401 (NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
michael@0 6402 if (NS_SUCCEEDED(rv)) {
michael@0 6403 rv = securityManager->
michael@0 6404 CheckLoadURIWithPrincipal(aPrincipal, uri,
michael@0 6405 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
michael@0 6406
michael@0 6407 if (NS_SUCCEEDED(rv)) {
michael@0 6408 bool isjs = true;
michael@0 6409 rv = NS_URIChainHasFlags(uri,
michael@0 6410 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
michael@0 6411 NS_ENSURE_SUCCESS(rv, rv);
michael@0 6412
michael@0 6413 if (isjs) {
michael@0 6414 return NS_ERROR_FAILURE;
michael@0 6415 }
michael@0 6416 }
michael@0 6417
michael@0 6418 if (NS_SUCCEEDED(rv)) {
michael@0 6419 // Since we can't travel back in time yet, just pretend
michael@0 6420 // negative numbers do nothing at all.
michael@0 6421 if (seconds < 0)
michael@0 6422 return NS_ERROR_FAILURE;
michael@0 6423
michael@0 6424 rv = RefreshURI(uri, seconds * 1000, false, true);
michael@0 6425 }
michael@0 6426 }
michael@0 6427 }
michael@0 6428 return rv;
michael@0 6429 }
michael@0 6430
michael@0 6431 NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
michael@0 6432 {
michael@0 6433 nsresult rv;
michael@0 6434 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
michael@0 6435 if (NS_SUCCEEDED(rv)) {
michael@0 6436 nsAutoCString refreshHeader;
michael@0 6437 rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
michael@0 6438 refreshHeader);
michael@0 6439
michael@0 6440 if (!refreshHeader.IsEmpty()) {
michael@0 6441 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 6442 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 6443 NS_ENSURE_SUCCESS(rv, rv);
michael@0 6444
michael@0 6445 nsCOMPtr<nsIPrincipal> principal;
michael@0 6446 rv = secMan->GetChannelPrincipal(aChannel, getter_AddRefs(principal));
michael@0 6447 NS_ENSURE_SUCCESS(rv, rv);
michael@0 6448
michael@0 6449 SetupReferrerFromChannel(aChannel);
michael@0 6450 rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader);
michael@0 6451 if (NS_SUCCEEDED(rv)) {
michael@0 6452 return NS_REFRESHURI_HEADER_FOUND;
michael@0 6453 }
michael@0 6454 }
michael@0 6455 }
michael@0 6456 return rv;
michael@0 6457 }
michael@0 6458
michael@0 6459 static void
michael@0 6460 DoCancelRefreshURITimers(nsISupportsArray* aTimerList)
michael@0 6461 {
michael@0 6462 if (!aTimerList)
michael@0 6463 return;
michael@0 6464
michael@0 6465 uint32_t n=0;
michael@0 6466 aTimerList->Count(&n);
michael@0 6467
michael@0 6468 while (n) {
michael@0 6469 nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
michael@0 6470
michael@0 6471 aTimerList->RemoveElementAt(n); // bye bye owning timer ref
michael@0 6472
michael@0 6473 if (timer)
michael@0 6474 timer->Cancel();
michael@0 6475 }
michael@0 6476 }
michael@0 6477
michael@0 6478 NS_IMETHODIMP
michael@0 6479 nsDocShell::CancelRefreshURITimers()
michael@0 6480 {
michael@0 6481 DoCancelRefreshURITimers(mRefreshURIList);
michael@0 6482 DoCancelRefreshURITimers(mSavedRefreshURIList);
michael@0 6483 mRefreshURIList = nullptr;
michael@0 6484 mSavedRefreshURIList = nullptr;
michael@0 6485
michael@0 6486 return NS_OK;
michael@0 6487 }
michael@0 6488
michael@0 6489 NS_IMETHODIMP
michael@0 6490 nsDocShell::GetRefreshPending(bool* _retval)
michael@0 6491 {
michael@0 6492 if (!mRefreshURIList) {
michael@0 6493 *_retval = false;
michael@0 6494 return NS_OK;
michael@0 6495 }
michael@0 6496
michael@0 6497 uint32_t count;
michael@0 6498 nsresult rv = mRefreshURIList->Count(&count);
michael@0 6499 if (NS_SUCCEEDED(rv))
michael@0 6500 *_retval = (count != 0);
michael@0 6501 return rv;
michael@0 6502 }
michael@0 6503
michael@0 6504 NS_IMETHODIMP
michael@0 6505 nsDocShell::SuspendRefreshURIs()
michael@0 6506 {
michael@0 6507 if (mRefreshURIList) {
michael@0 6508 uint32_t n = 0;
michael@0 6509 mRefreshURIList->Count(&n);
michael@0 6510
michael@0 6511 for (uint32_t i = 0; i < n; ++i) {
michael@0 6512 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
michael@0 6513 if (!timer)
michael@0 6514 continue; // this must be a nsRefreshURI already
michael@0 6515
michael@0 6516 // Replace this timer object with a nsRefreshTimer object.
michael@0 6517 nsCOMPtr<nsITimerCallback> callback;
michael@0 6518 timer->GetCallback(getter_AddRefs(callback));
michael@0 6519
michael@0 6520 timer->Cancel();
michael@0 6521
michael@0 6522 nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
michael@0 6523 NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects");
michael@0 6524
michael@0 6525 mRefreshURIList->ReplaceElementAt(rt, i);
michael@0 6526 }
michael@0 6527 }
michael@0 6528
michael@0 6529 // Suspend refresh URIs for our child shells as well.
michael@0 6530 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 6531 while (iter.HasMore()) {
michael@0 6532 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
michael@0 6533 if (shell)
michael@0 6534 shell->SuspendRefreshURIs();
michael@0 6535 }
michael@0 6536
michael@0 6537 return NS_OK;
michael@0 6538 }
michael@0 6539
michael@0 6540 NS_IMETHODIMP
michael@0 6541 nsDocShell::ResumeRefreshURIs()
michael@0 6542 {
michael@0 6543 RefreshURIFromQueue();
michael@0 6544
michael@0 6545 // Resume refresh URIs for our child shells as well.
michael@0 6546 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 6547 while (iter.HasMore()) {
michael@0 6548 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
michael@0 6549 if (shell)
michael@0 6550 shell->ResumeRefreshURIs();
michael@0 6551 }
michael@0 6552
michael@0 6553 return NS_OK;
michael@0 6554 }
michael@0 6555
michael@0 6556 nsresult
michael@0 6557 nsDocShell::RefreshURIFromQueue()
michael@0 6558 {
michael@0 6559 if (!mRefreshURIList)
michael@0 6560 return NS_OK;
michael@0 6561 uint32_t n = 0;
michael@0 6562 mRefreshURIList->Count(&n);
michael@0 6563
michael@0 6564 while (n) {
michael@0 6565 nsCOMPtr<nsISupports> element;
michael@0 6566 mRefreshURIList->GetElementAt(--n, getter_AddRefs(element));
michael@0 6567 nsCOMPtr<nsITimerCallback> refreshInfo(do_QueryInterface(element));
michael@0 6568
michael@0 6569 if (refreshInfo) {
michael@0 6570 // This is the nsRefreshTimer object, waiting to be
michael@0 6571 // setup in a timer object and fired.
michael@0 6572 // Create the timer and trigger it.
michael@0 6573 uint32_t delay = static_cast<nsRefreshTimer*>(static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
michael@0 6574 nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 6575 if (timer) {
michael@0 6576 // Replace the nsRefreshTimer element in the queue with
michael@0 6577 // its corresponding timer object, so that in case another
michael@0 6578 // load comes through before the timer can go off, the timer will
michael@0 6579 // get cancelled in CancelRefreshURITimer()
michael@0 6580 mRefreshURIList->ReplaceElementAt(timer, n);
michael@0 6581 timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
michael@0 6582 }
michael@0 6583 }
michael@0 6584 } // while
michael@0 6585
michael@0 6586 return NS_OK;
michael@0 6587 }
michael@0 6588
michael@0 6589 //*****************************************************************************
michael@0 6590 // nsDocShell::nsIContentViewerContainer
michael@0 6591 //*****************************************************************************
michael@0 6592
michael@0 6593 NS_IMETHODIMP
michael@0 6594 nsDocShell::Embed(nsIContentViewer * aContentViewer,
michael@0 6595 const char *aCommand, nsISupports * aExtraInfo)
michael@0 6596 {
michael@0 6597 // Save the LayoutHistoryState of the previous document, before
michael@0 6598 // setting up new document
michael@0 6599 PersistLayoutHistoryState();
michael@0 6600
michael@0 6601 nsresult rv = SetupNewViewer(aContentViewer);
michael@0 6602
michael@0 6603 // If we are loading a wyciwyg url from history, change the base URI for
michael@0 6604 // the document to the original http url that created the document.write().
michael@0 6605 // This makes sure that all relative urls in a document.written page loaded
michael@0 6606 // via history work properly.
michael@0 6607 if (mCurrentURI &&
michael@0 6608 (mLoadType & LOAD_CMD_HISTORY ||
michael@0 6609 mLoadType == LOAD_RELOAD_NORMAL ||
michael@0 6610 mLoadType == LOAD_RELOAD_CHARSET_CHANGE)){
michael@0 6611 bool isWyciwyg = false;
michael@0 6612 // Check if the url is wyciwyg
michael@0 6613 rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
michael@0 6614 if (isWyciwyg && NS_SUCCEEDED(rv))
michael@0 6615 SetBaseUrlForWyciwyg(aContentViewer);
michael@0 6616 }
michael@0 6617 // XXX What if SetupNewViewer fails?
michael@0 6618 if (mLSHE) {
michael@0 6619 // Restore the editing state, if it's stored in session history.
michael@0 6620 if (mLSHE->HasDetachedEditor()) {
michael@0 6621 ReattachEditorToWindow(mLSHE);
michael@0 6622 }
michael@0 6623 // Set history.state
michael@0 6624 SetDocCurrentStateObj(mLSHE);
michael@0 6625
michael@0 6626 SetHistoryEntry(&mOSHE, mLSHE);
michael@0 6627 }
michael@0 6628
michael@0 6629 bool updateHistory = true;
michael@0 6630
michael@0 6631 // Determine if this type of load should update history
michael@0 6632 switch (mLoadType) {
michael@0 6633 case LOAD_NORMAL_REPLACE:
michael@0 6634 case LOAD_STOP_CONTENT_AND_REPLACE:
michael@0 6635 case LOAD_RELOAD_BYPASS_CACHE:
michael@0 6636 case LOAD_RELOAD_BYPASS_PROXY:
michael@0 6637 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
michael@0 6638 case LOAD_REPLACE_BYPASS_CACHE:
michael@0 6639 updateHistory = false;
michael@0 6640 break;
michael@0 6641 default:
michael@0 6642 break;
michael@0 6643 }
michael@0 6644
michael@0 6645 if (!updateHistory)
michael@0 6646 SetLayoutHistoryState(nullptr);
michael@0 6647
michael@0 6648 return NS_OK;
michael@0 6649 }
michael@0 6650
michael@0 6651 /* void setIsPrinting (in boolean aIsPrinting); */
michael@0 6652 NS_IMETHODIMP
michael@0 6653 nsDocShell::SetIsPrinting(bool aIsPrinting)
michael@0 6654 {
michael@0 6655 mIsPrintingOrPP = aIsPrinting;
michael@0 6656 return NS_OK;
michael@0 6657 }
michael@0 6658
michael@0 6659 //*****************************************************************************
michael@0 6660 // nsDocShell::nsIWebProgressListener
michael@0 6661 //*****************************************************************************
michael@0 6662
michael@0 6663 NS_IMETHODIMP
michael@0 6664 nsDocShell::OnProgressChange(nsIWebProgress * aProgress,
michael@0 6665 nsIRequest * aRequest,
michael@0 6666 int32_t aCurSelfProgress,
michael@0 6667 int32_t aMaxSelfProgress,
michael@0 6668 int32_t aCurTotalProgress,
michael@0 6669 int32_t aMaxTotalProgress)
michael@0 6670 {
michael@0 6671 return NS_OK;
michael@0 6672 }
michael@0 6673
michael@0 6674 NS_IMETHODIMP
michael@0 6675 nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
michael@0 6676 uint32_t aStateFlags, nsresult aStatus)
michael@0 6677 {
michael@0 6678 if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
michael@0 6679 // Save timing statistics.
michael@0 6680 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
michael@0 6681 nsCOMPtr<nsIURI> uri;
michael@0 6682 channel->GetURI(getter_AddRefs(uri));
michael@0 6683 nsAutoCString aURI;
michael@0 6684 uri->GetAsciiSpec(aURI);
michael@0 6685
michael@0 6686 nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
michael@0 6687 nsCOMPtr<nsIWebProgress> webProgress =
michael@0 6688 do_QueryInterface(GetAsSupports(this));
michael@0 6689
michael@0 6690 // We don't update navigation timing for wyciwyg channels
michael@0 6691 if (this == aProgress && !wcwgChannel){
michael@0 6692 MaybeInitTiming();
michael@0 6693 mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType));
michael@0 6694 }
michael@0 6695
michael@0 6696 // Was the wyciwyg document loaded on this docshell?
michael@0 6697 if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
michael@0 6698 bool equalUri = true;
michael@0 6699 // Store the wyciwyg url in session history, only if it is
michael@0 6700 // being loaded fresh for the first time. We don't want
michael@0 6701 // multiple entries for successive loads
michael@0 6702 if (mCurrentURI &&
michael@0 6703 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
michael@0 6704 !equalUri) {
michael@0 6705
michael@0 6706 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
michael@0 6707 GetSameTypeParent(getter_AddRefs(parentAsItem));
michael@0 6708 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
michael@0 6709 bool inOnLoadHandler = false;
michael@0 6710 if (parentDS) {
michael@0 6711 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
michael@0 6712 }
michael@0 6713 if (inOnLoadHandler) {
michael@0 6714 // We're handling parent's load event listener, which causes
michael@0 6715 // document.write in a subdocument.
michael@0 6716 // Need to clear the session history for all child
michael@0 6717 // docshells so that we can handle them like they would
michael@0 6718 // all be added dynamically.
michael@0 6719 nsCOMPtr<nsIDocShell> parent =
michael@0 6720 do_QueryInterface(parentAsItem);
michael@0 6721 if (parent) {
michael@0 6722 bool oshe = false;
michael@0 6723 nsCOMPtr<nsISHEntry> entry;
michael@0 6724 parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
michael@0 6725 static_cast<nsDocShell*>(parent.get())->
michael@0 6726 ClearFrameHistory(entry);
michael@0 6727 }
michael@0 6728 }
michael@0 6729
michael@0 6730 // This is a document.write(). Get the made-up url
michael@0 6731 // from the channel and store it in session history.
michael@0 6732 // Pass false for aCloneChildren, since we're creating
michael@0 6733 // a new DOM here.
michael@0 6734 AddToSessionHistory(uri, wcwgChannel, nullptr, false,
michael@0 6735 getter_AddRefs(mLSHE));
michael@0 6736 SetCurrentURI(uri, aRequest, true, 0);
michael@0 6737 // Save history state of the previous page
michael@0 6738 PersistLayoutHistoryState();
michael@0 6739 // We'll never get an Embed() for this load, so just go ahead
michael@0 6740 // and SetHistoryEntry now.
michael@0 6741 SetHistoryEntry(&mOSHE, mLSHE);
michael@0 6742 }
michael@0 6743
michael@0 6744 }
michael@0 6745 // Page has begun to load
michael@0 6746 mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
michael@0 6747
michael@0 6748 if ((aStateFlags & STATE_RESTORING) == 0) {
michael@0 6749 // Show the progress cursor if the pref is set
michael@0 6750 if (Preferences::GetBool("ui.use_activity_cursor", false)) {
michael@0 6751 nsCOMPtr<nsIWidget> mainWidget;
michael@0 6752 GetMainWidget(getter_AddRefs(mainWidget));
michael@0 6753 if (mainWidget) {
michael@0 6754 mainWidget->SetCursor(eCursor_spinning);
michael@0 6755 }
michael@0 6756 }
michael@0 6757 }
michael@0 6758 }
michael@0 6759 else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
michael@0 6760 // Page is loading
michael@0 6761 mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
michael@0 6762 }
michael@0 6763 else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
michael@0 6764 // Page has finished loading
michael@0 6765 mBusyFlags = BUSY_FLAGS_NONE;
michael@0 6766
michael@0 6767 // Hide the progress cursor if the pref is set
michael@0 6768 if (Preferences::GetBool("ui.use_activity_cursor", false)) {
michael@0 6769 nsCOMPtr<nsIWidget> mainWidget;
michael@0 6770 GetMainWidget(getter_AddRefs(mainWidget));
michael@0 6771 if (mainWidget) {
michael@0 6772 mainWidget->SetCursor(eCursor_standard);
michael@0 6773 }
michael@0 6774 }
michael@0 6775 }
michael@0 6776 if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
michael@0 6777 nsCOMPtr<nsIWebProgress> webProgress =
michael@0 6778 do_QueryInterface(GetAsSupports(this));
michael@0 6779 // Is the document stop notification for this document?
michael@0 6780 if (aProgress == webProgress.get()) {
michael@0 6781 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
michael@0 6782 EndPageLoad(aProgress, channel, aStatus);
michael@0 6783 }
michael@0 6784 }
michael@0 6785 // note that redirect state changes will go through here as well, but it
michael@0 6786 // is better to handle those in OnRedirectStateChange where more
michael@0 6787 // information is available.
michael@0 6788 return NS_OK;
michael@0 6789 }
michael@0 6790
michael@0 6791 NS_IMETHODIMP
michael@0 6792 nsDocShell::OnLocationChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
michael@0 6793 nsIURI * aURI, uint32_t aFlags)
michael@0 6794 {
michael@0 6795 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 6796 return NS_OK;
michael@0 6797 }
michael@0 6798
michael@0 6799 void
michael@0 6800 nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
michael@0 6801 nsIChannel* aNewChannel,
michael@0 6802 uint32_t aRedirectFlags,
michael@0 6803 uint32_t aStateFlags)
michael@0 6804 {
michael@0 6805 NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
michael@0 6806 "Calling OnRedirectStateChange when there is no redirect");
michael@0 6807 if (!(aStateFlags & STATE_IS_DOCUMENT))
michael@0 6808 return; // not a toplevel document
michael@0 6809
michael@0 6810 nsCOMPtr<nsIURI> oldURI, newURI;
michael@0 6811 aOldChannel->GetURI(getter_AddRefs(oldURI));
michael@0 6812 aNewChannel->GetURI(getter_AddRefs(newURI));
michael@0 6813 if (!oldURI || !newURI) {
michael@0 6814 return;
michael@0 6815 }
michael@0 6816
michael@0 6817 // Check if we have a redirect registered for this url.
michael@0 6818 uint32_t appId;
michael@0 6819 nsresult rv = GetAppId(&appId);
michael@0 6820 if (NS_FAILED(rv)) {
michael@0 6821 return;
michael@0 6822 }
michael@0 6823
michael@0 6824 if (appId != nsIScriptSecurityManager::NO_APP_ID &&
michael@0 6825 appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
michael@0 6826 nsCOMPtr<nsIAppsService> appsService =
michael@0 6827 do_GetService(APPS_SERVICE_CONTRACTID);
michael@0 6828 NS_ASSERTION(appsService, "No AppsService available");
michael@0 6829 nsCOMPtr<nsIURI> redirect;
michael@0 6830 rv = appsService->GetRedirect(appId, newURI, getter_AddRefs(redirect));
michael@0 6831 if (NS_SUCCEEDED(rv) && redirect) {
michael@0 6832 aNewChannel->Cancel(NS_BINDING_ABORTED);
michael@0 6833 rv = LoadURI(redirect, nullptr, 0, false);
michael@0 6834 if (NS_SUCCEEDED(rv)) {
michael@0 6835 return;
michael@0 6836 }
michael@0 6837 }
michael@0 6838 }
michael@0 6839
michael@0 6840 // Below a URI visit is saved (see AddURIVisit method doc).
michael@0 6841 // The visit chain looks something like:
michael@0 6842 // ...
michael@0 6843 // Site N - 1
michael@0 6844 // => Site N
michael@0 6845 // (redirect to =>) Site N + 1 (we are here!)
michael@0 6846
michael@0 6847 // Get N - 1 and transition type
michael@0 6848 nsCOMPtr<nsIURI> previousURI;
michael@0 6849 uint32_t previousFlags = 0;
michael@0 6850 ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
michael@0 6851
michael@0 6852 if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
michael@0 6853 ChannelIsPost(aOldChannel)) {
michael@0 6854 // 1. Internal redirects are ignored because they are specific to the
michael@0 6855 // channel implementation.
michael@0 6856 // 2. POSTs are not saved by global history.
michael@0 6857 //
michael@0 6858 // Regardless, we need to propagate the previous visit to the new
michael@0 6859 // channel.
michael@0 6860 SaveLastVisit(aNewChannel, previousURI, previousFlags);
michael@0 6861 }
michael@0 6862 else {
michael@0 6863 nsCOMPtr<nsIURI> referrer;
michael@0 6864 // Treat referrer as null if there is an error getting it.
michael@0 6865 (void)NS_GetReferrerFromChannel(aOldChannel,
michael@0 6866 getter_AddRefs(referrer));
michael@0 6867
michael@0 6868 // Get the HTTP response code, if available.
michael@0 6869 uint32_t responseStatus = 0;
michael@0 6870 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
michael@0 6871 if (httpChannel) {
michael@0 6872 (void)httpChannel->GetResponseStatus(&responseStatus);
michael@0 6873 }
michael@0 6874
michael@0 6875 // Add visit N -1 => N
michael@0 6876 AddURIVisit(oldURI, referrer, previousURI, previousFlags,
michael@0 6877 responseStatus);
michael@0 6878
michael@0 6879 // Since N + 1 could be the final destination, we will not save N => N + 1
michael@0 6880 // here. OnNewURI will do that, so we will cache it.
michael@0 6881 SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
michael@0 6882 }
michael@0 6883
michael@0 6884 // check if the new load should go through the application cache.
michael@0 6885 nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
michael@0 6886 do_QueryInterface(aNewChannel);
michael@0 6887 if (appCacheChannel) {
michael@0 6888 if (GeckoProcessType_Default != XRE_GetProcessType()) {
michael@0 6889 // Permission will be checked in the parent process.
michael@0 6890 appCacheChannel->SetChooseApplicationCache(true);
michael@0 6891 } else {
michael@0 6892 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 6893 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 6894
michael@0 6895 if (secMan) {
michael@0 6896 nsCOMPtr<nsIPrincipal> principal;
michael@0 6897 secMan->GetDocShellCodebasePrincipal(newURI, this, getter_AddRefs(principal));
michael@0 6898 appCacheChannel->SetChooseApplicationCache(NS_ShouldCheckAppCache(principal,
michael@0 6899 mInPrivateBrowsing));
michael@0 6900 }
michael@0 6901 }
michael@0 6902 }
michael@0 6903
michael@0 6904 if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
michael@0 6905 mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
michael@0 6906 mLoadType = LOAD_NORMAL_REPLACE;
michael@0 6907 SetHistoryEntry(&mLSHE, nullptr);
michael@0 6908 }
michael@0 6909 }
michael@0 6910
michael@0 6911 NS_IMETHODIMP
michael@0 6912 nsDocShell::OnStatusChange(nsIWebProgress * aWebProgress,
michael@0 6913 nsIRequest * aRequest,
michael@0 6914 nsresult aStatus, const char16_t * aMessage)
michael@0 6915 {
michael@0 6916 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 6917 return NS_OK;
michael@0 6918 }
michael@0 6919
michael@0 6920 NS_IMETHODIMP
michael@0 6921 nsDocShell::OnSecurityChange(nsIWebProgress * aWebProgress,
michael@0 6922 nsIRequest * aRequest, uint32_t state)
michael@0 6923 {
michael@0 6924 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 6925 return NS_OK;
michael@0 6926 }
michael@0 6927
michael@0 6928
michael@0 6929 nsresult
michael@0 6930 nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
michael@0 6931 nsIChannel * aChannel, nsresult aStatus)
michael@0 6932 {
michael@0 6933 if(!aChannel)
michael@0 6934 return NS_ERROR_NULL_POINTER;
michael@0 6935
michael@0 6936 MOZ_EVENT_TRACER_DONE(this, "docshell::pageload");
michael@0 6937
michael@0 6938 nsCOMPtr<nsIURI> url;
michael@0 6939 nsresult rv = aChannel->GetURI(getter_AddRefs(url));
michael@0 6940 if (NS_FAILED(rv)) return rv;
michael@0 6941
michael@0 6942 nsCOMPtr<nsITimedChannel> timingChannel =
michael@0 6943 do_QueryInterface(aChannel);
michael@0 6944 if (timingChannel) {
michael@0 6945 TimeStamp channelCreationTime;
michael@0 6946 rv = timingChannel->GetChannelCreation(&channelCreationTime);
michael@0 6947 if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
michael@0 6948 Telemetry::AccumulateTimeDelta(
michael@0 6949 Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
michael@0 6950 channelCreationTime);
michael@0 6951 nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup =
michael@0 6952 do_QueryInterface(mLoadGroup);
michael@0 6953 if (internalLoadGroup)
michael@0 6954 internalLoadGroup->OnEndPageLoad(aChannel);
michael@0 6955 }
michael@0 6956 }
michael@0 6957
michael@0 6958 // Timing is picked up by the window, we don't need it anymore
michael@0 6959 mTiming = nullptr;
michael@0 6960
michael@0 6961 // clean up reload state for meta charset
michael@0 6962 if (eCharsetReloadRequested == mCharsetReloadState)
michael@0 6963 mCharsetReloadState = eCharsetReloadStopOrigional;
michael@0 6964 else
michael@0 6965 mCharsetReloadState = eCharsetReloadInit;
michael@0 6966
michael@0 6967 // Save a pointer to the currently-loading history entry.
michael@0 6968 // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
michael@0 6969 // entry further down in this method.
michael@0 6970 nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
michael@0 6971
michael@0 6972 //
michael@0 6973 // one of many safeguards that prevent death and destruction if
michael@0 6974 // someone is so very very rude as to bring this window down
michael@0 6975 // during this load handler.
michael@0 6976 //
michael@0 6977 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
michael@0 6978
michael@0 6979 // Notify the ContentViewer that the Document has finished loading. This
michael@0 6980 // will cause any OnLoad(...) and PopState(...) handlers to fire.
michael@0 6981 if (!mEODForCurrentDocument && mContentViewer) {
michael@0 6982 mIsExecutingOnLoadHandler = true;
michael@0 6983 mContentViewer->LoadComplete(aStatus);
michael@0 6984 mIsExecutingOnLoadHandler = false;
michael@0 6985
michael@0 6986 mEODForCurrentDocument = true;
michael@0 6987
michael@0 6988 // If all documents have completed their loading
michael@0 6989 // favor native event dispatch priorities
michael@0 6990 // over performance
michael@0 6991 if (--gNumberOfDocumentsLoading == 0) {
michael@0 6992 // Hint to use normal native event dispatch priorities
michael@0 6993 FavorPerformanceHint(false);
michael@0 6994 }
michael@0 6995 }
michael@0 6996 /* Check if the httpChannel has any cache-control related response headers,
michael@0 6997 * like no-store, no-cache. If so, update SHEntry so that
michael@0 6998 * when a user goes back/forward to this page, we appropriately do
michael@0 6999 * form value restoration or load from server.
michael@0 7000 */
michael@0 7001 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
michael@0 7002 if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel.
michael@0 7003 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
michael@0 7004
michael@0 7005 if (httpChannel) {
michael@0 7006 // figure out if SH should be saving layout state.
michael@0 7007 bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
michael@0 7008 if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
michael@0 7009 (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE))
michael@0 7010 mLSHE->SetSaveLayoutStateFlag(false);
michael@0 7011 }
michael@0 7012
michael@0 7013 // Clear mLSHE after calling the onLoadHandlers. This way, if the
michael@0 7014 // onLoadHandler tries to load something different in
michael@0 7015 // itself or one of its children, we can deal with it appropriately.
michael@0 7016 if (mLSHE) {
michael@0 7017 mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
michael@0 7018
michael@0 7019 // Clear the mLSHE reference to indicate document loading is done one
michael@0 7020 // way or another.
michael@0 7021 SetHistoryEntry(&mLSHE, nullptr);
michael@0 7022 }
michael@0 7023 // if there's a refresh header in the channel, this method
michael@0 7024 // will set it up for us.
michael@0 7025 RefreshURIFromQueue();
michael@0 7026
michael@0 7027 // Test whether this is the top frame or a subframe
michael@0 7028 bool isTopFrame = true;
michael@0 7029 nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
michael@0 7030 rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
michael@0 7031 if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
michael@0 7032 isTopFrame = false;
michael@0 7033 }
michael@0 7034
michael@0 7035 //
michael@0 7036 // If the page load failed, then deal with the error condition...
michael@0 7037 // Errors are handled as follows:
michael@0 7038 // 1. Check to see if it's a file not found error or bad content
michael@0 7039 // encoding error.
michael@0 7040 // 2. Send the URI to a keyword server (if enabled)
michael@0 7041 // 3. If the error was DNS failure, then add www and .com to the URI
michael@0 7042 // (if appropriate).
michael@0 7043 // 4. Throw an error dialog box...
michael@0 7044 //
michael@0 7045 if (url && NS_FAILED(aStatus)) {
michael@0 7046 if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
michael@0 7047 aStatus == NS_ERROR_CORRUPTED_CONTENT ||
michael@0 7048 aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
michael@0 7049 DisplayLoadError(aStatus, url, nullptr, aChannel);
michael@0 7050 return NS_OK;
michael@0 7051 }
michael@0 7052
michael@0 7053 if (sURIFixup) {
michael@0 7054 //
michael@0 7055 // Try and make an alternative URI from the old one
michael@0 7056 //
michael@0 7057 nsCOMPtr<nsIURI> newURI;
michael@0 7058 nsCOMPtr<nsIInputStream> newPostData;
michael@0 7059
michael@0 7060 nsAutoCString oldSpec;
michael@0 7061 url->GetSpec(oldSpec);
michael@0 7062
michael@0 7063 //
michael@0 7064 // First try keyword fixup
michael@0 7065 //
michael@0 7066 if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
michael@0 7067 bool keywordsEnabled =
michael@0 7068 Preferences::GetBool("keyword.enabled", false);
michael@0 7069
michael@0 7070 nsAutoCString host;
michael@0 7071 url->GetHost(host);
michael@0 7072
michael@0 7073 nsAutoCString scheme;
michael@0 7074 url->GetScheme(scheme);
michael@0 7075
michael@0 7076 int32_t dotLoc = host.FindChar('.');
michael@0 7077
michael@0 7078 // we should only perform a keyword search under the following
michael@0 7079 // conditions:
michael@0 7080 // (0) Pref keyword.enabled is true
michael@0 7081 // (1) the url scheme is http (or https)
michael@0 7082 // (2) the url does not have a protocol scheme
michael@0 7083 // If we don't enforce such a policy, then we end up doing
michael@0 7084 // keyword searchs on urls we don't intend like imap, file,
michael@0 7085 // mailbox, etc. This could lead to a security problem where we
michael@0 7086 // send data to the keyword server that we shouldn't be.
michael@0 7087 // Someone needs to clean up keywords in general so we can
michael@0 7088 // determine on a per url basis if we want keywords
michael@0 7089 // enabled...this is just a bandaid...
michael@0 7090 if (keywordsEnabled && !scheme.IsEmpty() &&
michael@0 7091 (scheme.Find("http") != 0)) {
michael@0 7092 keywordsEnabled = false;
michael@0 7093 }
michael@0 7094
michael@0 7095 if (keywordsEnabled && (kNotFound == dotLoc)) {
michael@0 7096 // only send non-qualified hosts to the keyword server
michael@0 7097 if (!mOriginalUriString.IsEmpty()) {
michael@0 7098 sURIFixup->KeywordToURI(mOriginalUriString,
michael@0 7099 getter_AddRefs(newPostData),
michael@0 7100 getter_AddRefs(newURI));
michael@0 7101 }
michael@0 7102 else {
michael@0 7103 //
michael@0 7104 // If this string was passed through nsStandardURL by
michael@0 7105 // chance, then it may have been converted from UTF-8 to
michael@0 7106 // ACE, which would result in a completely bogus keyword
michael@0 7107 // query. Here we try to recover the original Unicode
michael@0 7108 // value, but this is not 100% correct since the value may
michael@0 7109 // have been normalized per the IDN normalization rules.
michael@0 7110 //
michael@0 7111 // Since we don't have access to the exact original string
michael@0 7112 // that was entered by the user, this will just have to do.
michael@0 7113 bool isACE;
michael@0 7114 nsAutoCString utf8Host;
michael@0 7115 nsCOMPtr<nsIIDNService> idnSrv =
michael@0 7116 do_GetService(NS_IDNSERVICE_CONTRACTID);
michael@0 7117 if (idnSrv &&
michael@0 7118 NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
michael@0 7119 NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
michael@0 7120 sURIFixup->KeywordToURI(utf8Host,
michael@0 7121 getter_AddRefs(newPostData),
michael@0 7122 getter_AddRefs(newURI));
michael@0 7123 } else {
michael@0 7124 sURIFixup->KeywordToURI(host,
michael@0 7125 getter_AddRefs(newPostData),
michael@0 7126 getter_AddRefs(newURI));
michael@0 7127 }
michael@0 7128 }
michael@0 7129 } // end keywordsEnabled
michael@0 7130 }
michael@0 7131
michael@0 7132 //
michael@0 7133 // Now try change the address, e.g. turn http://foo into
michael@0 7134 // http://www.foo.com
michael@0 7135 //
michael@0 7136 if (aStatus == NS_ERROR_UNKNOWN_HOST ||
michael@0 7137 aStatus == NS_ERROR_NET_RESET) {
michael@0 7138 bool doCreateAlternate = true;
michael@0 7139
michael@0 7140 // Skip fixup for anything except a normal document load
michael@0 7141 // operation on the topframe.
michael@0 7142
michael@0 7143 if (mLoadType != LOAD_NORMAL || !isTopFrame) {
michael@0 7144 doCreateAlternate = false;
michael@0 7145 }
michael@0 7146 else {
michael@0 7147 // Test if keyword lookup produced a new URI or not
michael@0 7148 if (newURI) {
michael@0 7149 bool sameURI = false;
michael@0 7150 url->Equals(newURI, &sameURI);
michael@0 7151 if (!sameURI) {
michael@0 7152 // Keyword lookup made a new URI so no need to try
michael@0 7153 // an alternate one.
michael@0 7154 doCreateAlternate = false;
michael@0 7155 }
michael@0 7156 }
michael@0 7157 }
michael@0 7158 if (doCreateAlternate) {
michael@0 7159 newURI = nullptr;
michael@0 7160 newPostData = nullptr;
michael@0 7161 sURIFixup->CreateFixupURI(oldSpec,
michael@0 7162 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
michael@0 7163 getter_AddRefs(newPostData),
michael@0 7164 getter_AddRefs(newURI));
michael@0 7165 }
michael@0 7166 }
michael@0 7167
michael@0 7168 // Did we make a new URI that is different to the old one? If so
michael@0 7169 // load it.
michael@0 7170 //
michael@0 7171 if (newURI) {
michael@0 7172 // Make sure the new URI is different from the old one,
michael@0 7173 // otherwise there's little point trying to load it again.
michael@0 7174 bool sameURI = false;
michael@0 7175 url->Equals(newURI, &sameURI);
michael@0 7176 if (!sameURI) {
michael@0 7177 nsAutoCString newSpec;
michael@0 7178 newURI->GetSpec(newSpec);
michael@0 7179 NS_ConvertUTF8toUTF16 newSpecW(newSpec);
michael@0 7180
michael@0 7181 return LoadURI(newSpecW.get(), // URI string
michael@0 7182 LOAD_FLAGS_NONE, // Load flags
michael@0 7183 nullptr, // Referring URI
michael@0 7184 newPostData, // Post data stream
michael@0 7185 nullptr); // Headers stream
michael@0 7186 }
michael@0 7187 }
michael@0 7188 }
michael@0 7189
michael@0 7190 // Well, fixup didn't work :-(
michael@0 7191 // It is time to throw an error dialog box, and be done with it...
michael@0 7192
michael@0 7193 // Errors to be shown only on top-level frames
michael@0 7194 if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
michael@0 7195 aStatus == NS_ERROR_CONNECTION_REFUSED ||
michael@0 7196 aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
michael@0 7197 aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
michael@0 7198 (isTopFrame || UseErrorPages())) {
michael@0 7199 DisplayLoadError(aStatus, url, nullptr, aChannel);
michael@0 7200 }
michael@0 7201 // Errors to be shown for any frame
michael@0 7202 else if (aStatus == NS_ERROR_NET_TIMEOUT ||
michael@0 7203 aStatus == NS_ERROR_REDIRECT_LOOP ||
michael@0 7204 aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
michael@0 7205 aStatus == NS_ERROR_NET_INTERRUPT ||
michael@0 7206 aStatus == NS_ERROR_NET_RESET ||
michael@0 7207 aStatus == NS_ERROR_OFFLINE ||
michael@0 7208 aStatus == NS_ERROR_MALWARE_URI ||
michael@0 7209 aStatus == NS_ERROR_PHISHING_URI ||
michael@0 7210 aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
michael@0 7211 aStatus == NS_ERROR_REMOTE_XUL ||
michael@0 7212 aStatus == NS_ERROR_OFFLINE ||
michael@0 7213 NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
michael@0 7214 DisplayLoadError(aStatus, url, nullptr, aChannel);
michael@0 7215 }
michael@0 7216 else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
michael@0 7217 // Non-caching channels will simply return NS_ERROR_OFFLINE.
michael@0 7218 // Caching channels would have to look at their flags to work
michael@0 7219 // out which error to return. Or we can fix up the error here.
michael@0 7220 if (!(mLoadType & LOAD_CMD_HISTORY))
michael@0 7221 aStatus = NS_ERROR_OFFLINE;
michael@0 7222 DisplayLoadError(aStatus, url, nullptr, aChannel);
michael@0 7223 }
michael@0 7224 } // if we have a host
michael@0 7225 else if (url && NS_SUCCEEDED(aStatus)) {
michael@0 7226 mozilla::net::SeerLearnRedirect(url, aChannel, this);
michael@0 7227 }
michael@0 7228
michael@0 7229 return NS_OK;
michael@0 7230 }
michael@0 7231
michael@0 7232
michael@0 7233 //*****************************************************************************
michael@0 7234 // nsDocShell: Content Viewer Management
michael@0 7235 //*****************************************************************************
michael@0 7236
michael@0 7237 NS_IMETHODIMP
michael@0 7238 nsDocShell::EnsureContentViewer()
michael@0 7239 {
michael@0 7240 if (mContentViewer)
michael@0 7241 return NS_OK;
michael@0 7242 if (mIsBeingDestroyed)
michael@0 7243 return NS_ERROR_FAILURE;
michael@0 7244
michael@0 7245 nsCOMPtr<nsIURI> baseURI;
michael@0 7246 nsIPrincipal* principal = GetInheritedPrincipal(false);
michael@0 7247 nsCOMPtr<nsIDocShellTreeItem> parentItem;
michael@0 7248 GetSameTypeParent(getter_AddRefs(parentItem));
michael@0 7249 if (parentItem) {
michael@0 7250 nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
michael@0 7251 if (domWin) {
michael@0 7252 nsCOMPtr<nsIContent> parentContent =
michael@0 7253 do_QueryInterface(domWin->GetFrameElementInternal());
michael@0 7254 if (parentContent) {
michael@0 7255 baseURI = parentContent->GetBaseURI();
michael@0 7256 }
michael@0 7257 }
michael@0 7258 }
michael@0 7259
michael@0 7260 nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
michael@0 7261
michael@0 7262 if (NS_SUCCEEDED(rv)) {
michael@0 7263 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
michael@0 7264 NS_ASSERTION(doc,
michael@0 7265 "Should have doc if CreateAboutBlankContentViewer "
michael@0 7266 "succeeded!");
michael@0 7267
michael@0 7268 doc->SetIsInitialDocument(true);
michael@0 7269 }
michael@0 7270
michael@0 7271 return rv;
michael@0 7272 }
michael@0 7273
michael@0 7274 nsresult
michael@0 7275 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
michael@0 7276 nsIURI* aBaseURI,
michael@0 7277 bool aTryToSaveOldPresentation)
michael@0 7278 {
michael@0 7279 nsCOMPtr<nsIDocument> blankDoc;
michael@0 7280 nsCOMPtr<nsIContentViewer> viewer;
michael@0 7281 nsresult rv = NS_ERROR_FAILURE;
michael@0 7282
michael@0 7283 /* mCreatingDocument should never be true at this point. However, it's
michael@0 7284 a theoretical possibility. We want to know about it and make it stop,
michael@0 7285 and this sounds like a job for an assertion. */
michael@0 7286 NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted");
michael@0 7287 if (mCreatingDocument)
michael@0 7288 return NS_ERROR_FAILURE;
michael@0 7289
michael@0 7290 mCreatingDocument = true;
michael@0 7291
michael@0 7292 // mContentViewer->PermitUnload may release |this| docshell.
michael@0 7293 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
michael@0 7294
michael@0 7295 // Make sure timing is created. But first record whether we had it
michael@0 7296 // already, so we don't clobber the timing for an in-progress load.
michael@0 7297 bool hadTiming = mTiming;
michael@0 7298 MaybeInitTiming();
michael@0 7299 if (mContentViewer) {
michael@0 7300 // We've got a content viewer already. Make sure the user
michael@0 7301 // permits us to discard the current document and replace it
michael@0 7302 // with about:blank. And also ensure we fire the unload events
michael@0 7303 // in the current document.
michael@0 7304
michael@0 7305 // Unload gets fired first for
michael@0 7306 // document loaded from the session history.
michael@0 7307 mTiming->NotifyBeforeUnload();
michael@0 7308
michael@0 7309 bool okToUnload;
michael@0 7310 rv = mContentViewer->PermitUnload(false, &okToUnload);
michael@0 7311
michael@0 7312 if (NS_SUCCEEDED(rv) && !okToUnload) {
michael@0 7313 // The user chose not to unload the page, interrupt the load.
michael@0 7314 return NS_ERROR_FAILURE;
michael@0 7315 }
michael@0 7316
michael@0 7317 mSavingOldViewer = aTryToSaveOldPresentation &&
michael@0 7318 CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
michael@0 7319
michael@0 7320 if (mTiming) {
michael@0 7321 mTiming->NotifyUnloadAccepted(mCurrentURI);
michael@0 7322 }
michael@0 7323
michael@0 7324 // Make sure to blow away our mLoadingURI just in case. No loads
michael@0 7325 // from inside this pagehide.
michael@0 7326 mLoadingURI = nullptr;
michael@0 7327
michael@0 7328 // Stop any in-progress loading, so that we don't accidentally trigger any
michael@0 7329 // PageShow notifications from Embed() interrupting our loading below.
michael@0 7330 Stop();
michael@0 7331
michael@0 7332 // Notify the current document that it is about to be unloaded!!
michael@0 7333 //
michael@0 7334 // It is important to fire the unload() notification *before* any state
michael@0 7335 // is changed within the DocShell - otherwise, javascript will get the
michael@0 7336 // wrong information :-(
michael@0 7337 //
michael@0 7338 (void) FirePageHideNotification(!mSavingOldViewer);
michael@0 7339 }
michael@0 7340
michael@0 7341 // Now make sure we don't think we're in the middle of firing unload after
michael@0 7342 // this point. This will make us fire unload when the about:blank document
michael@0 7343 // unloads... but that's ok, more or less. Would be nice if it fired load
michael@0 7344 // too, of course.
michael@0 7345 mFiredUnloadEvent = false;
michael@0 7346
michael@0 7347 nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
michael@0 7348 nsContentUtils::FindInternalContentViewer("text/html");
michael@0 7349
michael@0 7350 if (docFactory) {
michael@0 7351 nsCOMPtr<nsIPrincipal> principal;
michael@0 7352 if (mSandboxFlags & SANDBOXED_ORIGIN) {
michael@0 7353 principal = do_CreateInstance("@mozilla.org/nullprincipal;1");
michael@0 7354 } else {
michael@0 7355 principal = aPrincipal;
michael@0 7356 }
michael@0 7357 // generate (about:blank) document to load
michael@0 7358 docFactory->CreateBlankDocument(mLoadGroup, principal,
michael@0 7359 getter_AddRefs(blankDoc));
michael@0 7360 if (blankDoc) {
michael@0 7361 // Hack: set the base URI manually, since this document never
michael@0 7362 // got Reset() with a channel.
michael@0 7363 blankDoc->SetBaseURI(aBaseURI);
michael@0 7364
michael@0 7365 blankDoc->SetContainer(this);
michael@0 7366
michael@0 7367 // Copy our sandbox flags to the document. These are immutable
michael@0 7368 // after being set here.
michael@0 7369 blankDoc->SetSandboxFlags(mSandboxFlags);
michael@0 7370
michael@0 7371 // create a content viewer for us and the new document
michael@0 7372 docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
michael@0 7373 blankDoc, "view", getter_AddRefs(viewer));
michael@0 7374
michael@0 7375 // hook 'em up
michael@0 7376 if (viewer) {
michael@0 7377 viewer->SetContainer(this);
michael@0 7378 Embed(viewer, "", 0);
michael@0 7379
michael@0 7380 SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
michael@0 7381 rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
michael@0 7382 }
michael@0 7383 }
michael@0 7384 }
michael@0 7385 mCreatingDocument = false;
michael@0 7386
michael@0 7387 // The transient about:blank viewer doesn't have a session history entry.
michael@0 7388 SetHistoryEntry(&mOSHE, nullptr);
michael@0 7389
michael@0 7390 // Clear out our mTiming like we would in EndPageLoad, if we didn't
michael@0 7391 // have one before entering this function.
michael@0 7392 if (!hadTiming) {
michael@0 7393 mTiming = nullptr;
michael@0 7394 }
michael@0 7395
michael@0 7396 return rv;
michael@0 7397 }
michael@0 7398
michael@0 7399 NS_IMETHODIMP
michael@0 7400 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal)
michael@0 7401 {
michael@0 7402 return CreateAboutBlankContentViewer(aPrincipal, nullptr);
michael@0 7403 }
michael@0 7404
michael@0 7405 bool
michael@0 7406 nsDocShell::CanSavePresentation(uint32_t aLoadType,
michael@0 7407 nsIRequest *aNewRequest,
michael@0 7408 nsIDocument *aNewDocument)
michael@0 7409 {
michael@0 7410 if (!mOSHE)
michael@0 7411 return false; // no entry to save into
michael@0 7412
michael@0 7413 nsCOMPtr<nsIContentViewer> viewer;
michael@0 7414 mOSHE->GetContentViewer(getter_AddRefs(viewer));
michael@0 7415 if (viewer) {
michael@0 7416 NS_WARNING("mOSHE already has a content viewer!");
michael@0 7417 return false;
michael@0 7418 }
michael@0 7419
michael@0 7420 // Only save presentation for "normal" loads and link loads. Anything else
michael@0 7421 // probably wants to refetch the page, so caching the old presentation
michael@0 7422 // would be incorrect.
michael@0 7423 if (aLoadType != LOAD_NORMAL &&
michael@0 7424 aLoadType != LOAD_HISTORY &&
michael@0 7425 aLoadType != LOAD_LINK &&
michael@0 7426 aLoadType != LOAD_STOP_CONTENT &&
michael@0 7427 aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
michael@0 7428 aLoadType != LOAD_ERROR_PAGE)
michael@0 7429 return false;
michael@0 7430
michael@0 7431 // If the session history entry has the saveLayoutState flag set to false,
michael@0 7432 // then we should not cache the presentation.
michael@0 7433 bool canSaveState;
michael@0 7434 mOSHE->GetSaveLayoutStateFlag(&canSaveState);
michael@0 7435 if (!canSaveState)
michael@0 7436 return false;
michael@0 7437
michael@0 7438 // If the document is not done loading, don't cache it.
michael@0 7439 if (!mScriptGlobal || mScriptGlobal->IsLoading())
michael@0 7440 return false;
michael@0 7441
michael@0 7442 if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument))
michael@0 7443 return false;
michael@0 7444
michael@0 7445 // Avoid doing the work of saving the presentation state in the case where
michael@0 7446 // the content viewer cache is disabled.
michael@0 7447 if (nsSHistory::GetMaxTotalViewers() == 0)
michael@0 7448 return false;
michael@0 7449
michael@0 7450 // Don't cache the content viewer if we're in a subframe and the subframe
michael@0 7451 // pref is disabled.
michael@0 7452 bool cacheFrames =
michael@0 7453 Preferences::GetBool("browser.sessionhistory.cache_subframes",
michael@0 7454 false);
michael@0 7455 if (!cacheFrames) {
michael@0 7456 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 7457 GetSameTypeParent(getter_AddRefs(root));
michael@0 7458 if (root && root != this) {
michael@0 7459 return false; // this is a subframe load
michael@0 7460 }
michael@0 7461 }
michael@0 7462
michael@0 7463 // If the document does not want its presentation cached, then don't.
michael@0 7464 nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
michael@0 7465 return doc && doc->CanSavePresentation(aNewRequest);
michael@0 7466 }
michael@0 7467
michael@0 7468 void
michael@0 7469 nsDocShell::ReattachEditorToWindow(nsISHEntry *aSHEntry)
michael@0 7470 {
michael@0 7471 NS_ASSERTION(!mEditorData,
michael@0 7472 "Why reattach an editor when we already have one?");
michael@0 7473 NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
michael@0 7474 "Reattaching when there's not a detached editor.");
michael@0 7475
michael@0 7476 if (mEditorData || !aSHEntry)
michael@0 7477 return;
michael@0 7478
michael@0 7479 mEditorData = aSHEntry->ForgetEditorData();
michael@0 7480 if (mEditorData) {
michael@0 7481 #ifdef DEBUG
michael@0 7482 nsresult rv =
michael@0 7483 #endif
michael@0 7484 mEditorData->ReattachToWindow(this);
michael@0 7485 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
michael@0 7486 }
michael@0 7487 }
michael@0 7488
michael@0 7489 void
michael@0 7490 nsDocShell::DetachEditorFromWindow()
michael@0 7491 {
michael@0 7492 if (!mEditorData || mEditorData->WaitingForLoad()) {
michael@0 7493 // If there's nothing to detach, or if the editor data is actually set
michael@0 7494 // up for the _new_ page that's coming in, don't detach.
michael@0 7495 return;
michael@0 7496 }
michael@0 7497
michael@0 7498 NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
michael@0 7499 "Detaching editor when it's already detached.");
michael@0 7500
michael@0 7501 nsresult res = mEditorData->DetachFromWindow();
michael@0 7502 NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
michael@0 7503
michael@0 7504 if (NS_SUCCEEDED(res)) {
michael@0 7505 // Make mOSHE hold the owning ref to the editor data.
michael@0 7506 if (mOSHE)
michael@0 7507 mOSHE->SetEditorData(mEditorData.forget());
michael@0 7508 else
michael@0 7509 mEditorData = nullptr;
michael@0 7510 }
michael@0 7511
michael@0 7512 #ifdef DEBUG
michael@0 7513 {
michael@0 7514 bool isEditable;
michael@0 7515 GetEditable(&isEditable);
michael@0 7516 NS_ASSERTION(!isEditable,
michael@0 7517 "Window is still editable after detaching editor.");
michael@0 7518 }
michael@0 7519 #endif // DEBUG
michael@0 7520 }
michael@0 7521
michael@0 7522 nsresult
michael@0 7523 nsDocShell::CaptureState()
michael@0 7524 {
michael@0 7525 if (!mOSHE || mOSHE == mLSHE) {
michael@0 7526 // No entry to save into, or we're replacing the existing entry.
michael@0 7527 return NS_ERROR_FAILURE;
michael@0 7528 }
michael@0 7529
michael@0 7530 if (!mScriptGlobal)
michael@0 7531 return NS_ERROR_FAILURE;
michael@0 7532
michael@0 7533 nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState();
michael@0 7534 NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE);
michael@0 7535
michael@0 7536 #ifdef DEBUG_PAGE_CACHE
michael@0 7537 nsCOMPtr<nsIURI> uri;
michael@0 7538 mOSHE->GetURI(getter_AddRefs(uri));
michael@0 7539 nsAutoCString spec;
michael@0 7540 if (uri)
michael@0 7541 uri->GetSpec(spec);
michael@0 7542 printf("Saving presentation into session history\n");
michael@0 7543 printf(" SH URI: %s\n", spec.get());
michael@0 7544 #endif
michael@0 7545
michael@0 7546 nsresult rv = mOSHE->SetWindowState(windowState);
michael@0 7547 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7548
michael@0 7549 // Suspend refresh URIs and save off the timer queue
michael@0 7550 rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
michael@0 7551 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7552
michael@0 7553 // Capture the current content viewer bounds.
michael@0 7554 if (mContentViewer) {
michael@0 7555 nsIntRect bounds;
michael@0 7556 mContentViewer->GetBounds(bounds);
michael@0 7557 rv = mOSHE->SetViewerBounds(bounds);
michael@0 7558 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7559 }
michael@0 7560
michael@0 7561 // Capture the docshell hierarchy.
michael@0 7562 mOSHE->ClearChildShells();
michael@0 7563
michael@0 7564 uint32_t childCount = mChildList.Length();
michael@0 7565 for (uint32_t i = 0; i < childCount; ++i) {
michael@0 7566 nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
michael@0 7567 NS_ASSERTION(childShell, "null child shell");
michael@0 7568
michael@0 7569 mOSHE->AddChildShell(childShell);
michael@0 7570 }
michael@0 7571
michael@0 7572 return NS_OK;
michael@0 7573 }
michael@0 7574
michael@0 7575 NS_IMETHODIMP
michael@0 7576 nsDocShell::RestorePresentationEvent::Run()
michael@0 7577 {
michael@0 7578 if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory()))
michael@0 7579 NS_WARNING("RestoreFromHistory failed");
michael@0 7580 return NS_OK;
michael@0 7581 }
michael@0 7582
michael@0 7583 NS_IMETHODIMP
michael@0 7584 nsDocShell::BeginRestore(nsIContentViewer *aContentViewer, bool aTop)
michael@0 7585 {
michael@0 7586 nsresult rv;
michael@0 7587 if (!aContentViewer) {
michael@0 7588 rv = EnsureContentViewer();
michael@0 7589 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7590
michael@0 7591 aContentViewer = mContentViewer;
michael@0 7592 }
michael@0 7593
michael@0 7594 // Dispatch events for restoring the presentation. We try to simulate
michael@0 7595 // the progress notifications loading the document would cause, so we add
michael@0 7596 // the document's channel to the loadgroup to initiate stateChange
michael@0 7597 // notifications.
michael@0 7598
michael@0 7599 nsCOMPtr<nsIDOMDocument> domDoc;
michael@0 7600 aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
michael@0 7601 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
michael@0 7602 if (doc) {
michael@0 7603 nsIChannel *channel = doc->GetChannel();
michael@0 7604 if (channel) {
michael@0 7605 mEODForCurrentDocument = false;
michael@0 7606 mIsRestoringDocument = true;
michael@0 7607 mLoadGroup->AddRequest(channel, nullptr);
michael@0 7608 mIsRestoringDocument = false;
michael@0 7609 }
michael@0 7610 }
michael@0 7611
michael@0 7612 if (!aTop) {
michael@0 7613 // This point corresponds to us having gotten OnStartRequest or
michael@0 7614 // STATE_START, so do the same thing that CreateContentViewer does at
michael@0 7615 // this point to ensure that unload/pagehide events for this document
michael@0 7616 // will fire when it's unloaded again.
michael@0 7617 mFiredUnloadEvent = false;
michael@0 7618
michael@0 7619 // For non-top frames, there is no notion of making sure that the
michael@0 7620 // previous document is in the domwindow when STATE_START notifications
michael@0 7621 // happen. We can just call BeginRestore for all of the child shells
michael@0 7622 // now.
michael@0 7623 rv = BeginRestoreChildren();
michael@0 7624 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7625 }
michael@0 7626
michael@0 7627 return NS_OK;
michael@0 7628 }
michael@0 7629
michael@0 7630 nsresult
michael@0 7631 nsDocShell::BeginRestoreChildren()
michael@0 7632 {
michael@0 7633 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 7634 while (iter.HasMore()) {
michael@0 7635 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
michael@0 7636 if (child) {
michael@0 7637 nsresult rv = child->BeginRestore(nullptr, false);
michael@0 7638 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7639 }
michael@0 7640 }
michael@0 7641 return NS_OK;
michael@0 7642 }
michael@0 7643
michael@0 7644 NS_IMETHODIMP
michael@0 7645 nsDocShell::FinishRestore()
michael@0 7646 {
michael@0 7647 // First we call finishRestore() on our children. In the simulated load,
michael@0 7648 // all of the child frames finish loading before the main document.
michael@0 7649
michael@0 7650 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 7651 while (iter.HasMore()) {
michael@0 7652 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
michael@0 7653 if (child) {
michael@0 7654 child->FinishRestore();
michael@0 7655 }
michael@0 7656 }
michael@0 7657
michael@0 7658 if (mOSHE && mOSHE->HasDetachedEditor()) {
michael@0 7659 ReattachEditorToWindow(mOSHE);
michael@0 7660 }
michael@0 7661
michael@0 7662 nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
michael@0 7663 if (doc) {
michael@0 7664 // Finally, we remove the request from the loadgroup. This will
michael@0 7665 // cause onStateChange(STATE_STOP) to fire, which will fire the
michael@0 7666 // pageshow event to the chrome.
michael@0 7667
michael@0 7668 nsIChannel *channel = doc->GetChannel();
michael@0 7669 if (channel) {
michael@0 7670 mIsRestoringDocument = true;
michael@0 7671 mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
michael@0 7672 mIsRestoringDocument = false;
michael@0 7673 }
michael@0 7674 }
michael@0 7675
michael@0 7676 return NS_OK;
michael@0 7677 }
michael@0 7678
michael@0 7679 NS_IMETHODIMP
michael@0 7680 nsDocShell::GetRestoringDocument(bool *aRestoring)
michael@0 7681 {
michael@0 7682 *aRestoring = mIsRestoringDocument;
michael@0 7683 return NS_OK;
michael@0 7684 }
michael@0 7685
michael@0 7686 nsresult
michael@0 7687 nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, bool *aRestoring)
michael@0 7688 {
michael@0 7689 NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
michael@0 7690 "RestorePresentation should only be called for history loads");
michael@0 7691
michael@0 7692 nsCOMPtr<nsIContentViewer> viewer;
michael@0 7693 aSHEntry->GetContentViewer(getter_AddRefs(viewer));
michael@0 7694
michael@0 7695 #ifdef DEBUG_PAGE_CACHE
michael@0 7696 nsCOMPtr<nsIURI> uri;
michael@0 7697 aSHEntry->GetURI(getter_AddRefs(uri));
michael@0 7698
michael@0 7699 nsAutoCString spec;
michael@0 7700 if (uri)
michael@0 7701 uri->GetSpec(spec);
michael@0 7702 #endif
michael@0 7703
michael@0 7704 *aRestoring = false;
michael@0 7705
michael@0 7706 if (!viewer) {
michael@0 7707 #ifdef DEBUG_PAGE_CACHE
michael@0 7708 printf("no saved presentation for uri: %s\n", spec.get());
michael@0 7709 #endif
michael@0 7710 return NS_OK;
michael@0 7711 }
michael@0 7712
michael@0 7713 // We need to make sure the content viewer's container is this docshell.
michael@0 7714 // In subframe navigation, it's possible for the docshell that the
michael@0 7715 // content viewer was originally loaded into to be replaced with a
michael@0 7716 // different one. We don't currently support restoring the presentation
michael@0 7717 // in that case.
michael@0 7718
michael@0 7719 nsCOMPtr<nsIDocShell> container;
michael@0 7720 viewer->GetContainer(getter_AddRefs(container));
michael@0 7721 if (!::SameCOMIdentity(container, GetAsSupports(this))) {
michael@0 7722 #ifdef DEBUG_PAGE_CACHE
michael@0 7723 printf("No valid container, clearing presentation\n");
michael@0 7724 #endif
michael@0 7725 aSHEntry->SetContentViewer(nullptr);
michael@0 7726 return NS_ERROR_FAILURE;
michael@0 7727 }
michael@0 7728
michael@0 7729 NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
michael@0 7730
michael@0 7731 #ifdef DEBUG_PAGE_CACHE
michael@0 7732 printf("restoring presentation from session history: %s\n", spec.get());
michael@0 7733 #endif
michael@0 7734
michael@0 7735 SetHistoryEntry(&mLSHE, aSHEntry);
michael@0 7736
michael@0 7737 // Add the request to our load group. We do this before swapping out
michael@0 7738 // the content viewers so that consumers of STATE_START can access
michael@0 7739 // the old document. We only deal with the toplevel load at this time --
michael@0 7740 // to be consistent with normal document loading, subframes cannot start
michael@0 7741 // loading until after data arrives, which is after STATE_START completes.
michael@0 7742
michael@0 7743 BeginRestore(viewer, true);
michael@0 7744
michael@0 7745 // Post an event that will remove the request after we've returned
michael@0 7746 // to the event loop. This mimics the way it is called by nsIChannel
michael@0 7747 // implementations.
michael@0 7748
michael@0 7749 // Revoke any pending restore (just in case)
michael@0 7750 NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
michael@0 7751 "should only have one RestorePresentationEvent");
michael@0 7752 mRestorePresentationEvent.Revoke();
michael@0 7753
michael@0 7754 nsRefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
michael@0 7755 nsresult rv = NS_DispatchToCurrentThread(evt);
michael@0 7756 if (NS_SUCCEEDED(rv)) {
michael@0 7757 mRestorePresentationEvent = evt.get();
michael@0 7758 // The rest of the restore processing will happen on our event
michael@0 7759 // callback.
michael@0 7760 *aRestoring = true;
michael@0 7761 }
michael@0 7762
michael@0 7763 return rv;
michael@0 7764 }
michael@0 7765
michael@0 7766 nsresult
michael@0 7767 nsDocShell::RestoreFromHistory()
michael@0 7768 {
michael@0 7769 mRestorePresentationEvent.Forget();
michael@0 7770
michael@0 7771 // This section of code follows the same ordering as CreateContentViewer.
michael@0 7772 if (!mLSHE)
michael@0 7773 return NS_ERROR_FAILURE;
michael@0 7774
michael@0 7775 nsCOMPtr<nsIContentViewer> viewer;
michael@0 7776 mLSHE->GetContentViewer(getter_AddRefs(viewer));
michael@0 7777 if (!viewer)
michael@0 7778 return NS_ERROR_FAILURE;
michael@0 7779
michael@0 7780 if (mSavingOldViewer) {
michael@0 7781 // We determined that it was safe to cache the document presentation
michael@0 7782 // at the time we initiated the new load. We need to check whether
michael@0 7783 // it's still safe to do so, since there may have been DOM mutations
michael@0 7784 // or new requests initiated.
michael@0 7785 nsCOMPtr<nsIDOMDocument> domDoc;
michael@0 7786 viewer->GetDOMDocument(getter_AddRefs(domDoc));
michael@0 7787 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
michael@0 7788 nsIRequest *request = nullptr;
michael@0 7789 if (doc)
michael@0 7790 request = doc->GetChannel();
michael@0 7791 mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
michael@0 7792 }
michael@0 7793
michael@0 7794 nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV(
michael@0 7795 do_QueryInterface(mContentViewer));
michael@0 7796 nsCOMPtr<nsIMarkupDocumentViewer> newMUDV(
michael@0 7797 do_QueryInterface(viewer));
michael@0 7798 int32_t minFontSize = 0;
michael@0 7799 float textZoom = 1.0f;
michael@0 7800 float pageZoom = 1.0f;
michael@0 7801 bool styleDisabled = false;
michael@0 7802 if (oldMUDV && newMUDV) {
michael@0 7803 oldMUDV->GetMinFontSize(&minFontSize);
michael@0 7804 oldMUDV->GetTextZoom(&textZoom);
michael@0 7805 oldMUDV->GetFullZoom(&pageZoom);
michael@0 7806 oldMUDV->GetAuthorStyleDisabled(&styleDisabled);
michael@0 7807 }
michael@0 7808
michael@0 7809 // Protect against mLSHE going away via a load triggered from
michael@0 7810 // pagehide or unload.
michael@0 7811 nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
michael@0 7812
michael@0 7813 // Make sure to blow away our mLoadingURI just in case. No loads
michael@0 7814 // from inside this pagehide.
michael@0 7815 mLoadingURI = nullptr;
michael@0 7816
michael@0 7817 // Notify the old content viewer that it's being hidden.
michael@0 7818 FirePageHideNotification(!mSavingOldViewer);
michael@0 7819
michael@0 7820 // If mLSHE was changed as a result of the pagehide event, then
michael@0 7821 // something else was loaded. Don't finish restoring.
michael@0 7822 if (mLSHE != origLSHE)
michael@0 7823 return NS_OK;
michael@0 7824
michael@0 7825 // Set mFiredUnloadEvent = false so that the unload handler for the
michael@0 7826 // *new* document will fire.
michael@0 7827 mFiredUnloadEvent = false;
michael@0 7828
michael@0 7829 mURIResultedInDocument = true;
michael@0 7830 nsCOMPtr<nsISHistory> rootSH;
michael@0 7831 GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 7832 if (rootSH) {
michael@0 7833 nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
michael@0 7834 rootSH->GetIndex(&mPreviousTransIndex);
michael@0 7835 hist->UpdateIndex();
michael@0 7836 rootSH->GetIndex(&mLoadedTransIndex);
michael@0 7837 #ifdef DEBUG_PAGE_CACHE
michael@0 7838 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
michael@0 7839 mLoadedTransIndex);
michael@0 7840 #endif
michael@0 7841 }
michael@0 7842
michael@0 7843 // Rather than call Embed(), we will retrieve the viewer from the session
michael@0 7844 // history entry and swap it in.
michael@0 7845 // XXX can we refactor this so that we can just call Embed()?
michael@0 7846 PersistLayoutHistoryState();
michael@0 7847 nsresult rv;
michael@0 7848 if (mContentViewer) {
michael@0 7849 if (mSavingOldViewer && NS_FAILED(CaptureState())) {
michael@0 7850 if (mOSHE) {
michael@0 7851 mOSHE->SyncPresentationState();
michael@0 7852 }
michael@0 7853 mSavingOldViewer = false;
michael@0 7854 }
michael@0 7855 }
michael@0 7856
michael@0 7857 mSavedRefreshURIList = nullptr;
michael@0 7858
michael@0 7859 // In cases where we use a transient about:blank viewer between loads,
michael@0 7860 // we never show the transient viewer, so _its_ previous viewer is never
michael@0 7861 // unhooked from the view hierarchy. Destroy any such previous viewer now,
michael@0 7862 // before we grab the root view sibling, so that we don't grab a view
michael@0 7863 // that's about to go away.
michael@0 7864
michael@0 7865 if (mContentViewer) {
michael@0 7866 nsCOMPtr<nsIContentViewer> previousViewer;
michael@0 7867 mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
michael@0 7868 if (previousViewer) {
michael@0 7869 mContentViewer->SetPreviousViewer(nullptr);
michael@0 7870 previousViewer->Destroy();
michael@0 7871 }
michael@0 7872 }
michael@0 7873
michael@0 7874 // Save off the root view's parent and sibling so that we can insert the
michael@0 7875 // new content viewer's root view at the same position. Also save the
michael@0 7876 // bounds of the root view's widget.
michael@0 7877
michael@0 7878 nsView *rootViewSibling = nullptr, *rootViewParent = nullptr;
michael@0 7879 nsIntRect newBounds(0, 0, 0, 0);
michael@0 7880
michael@0 7881 nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell();
michael@0 7882 if (oldPresShell) {
michael@0 7883 nsViewManager *vm = oldPresShell->GetViewManager();
michael@0 7884 if (vm) {
michael@0 7885 nsView *oldRootView = vm->GetRootView();
michael@0 7886
michael@0 7887 if (oldRootView) {
michael@0 7888 rootViewSibling = oldRootView->GetNextSibling();
michael@0 7889 rootViewParent = oldRootView->GetParent();
michael@0 7890
michael@0 7891 mContentViewer->GetBounds(newBounds);
michael@0 7892 }
michael@0 7893 }
michael@0 7894 }
michael@0 7895
michael@0 7896 nsCOMPtr<nsIContent> container;
michael@0 7897 nsCOMPtr<nsIDocument> sibling;
michael@0 7898 if (rootViewParent && rootViewParent->GetParent()) {
michael@0 7899 nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
michael@0 7900 container = frame ? frame->GetContent() : nullptr;
michael@0 7901 }
michael@0 7902 if (rootViewSibling) {
michael@0 7903 nsIFrame *frame = rootViewSibling->GetFrame();
michael@0 7904 sibling = frame ? frame->PresContext()->PresShell()->GetDocument() : nullptr;
michael@0 7905 }
michael@0 7906
michael@0 7907 // Transfer ownership to mContentViewer. By ensuring that either the
michael@0 7908 // docshell or the session history, but not both, have references to the
michael@0 7909 // content viewer, we prevent the viewer from being torn down after
michael@0 7910 // Destroy() is called.
michael@0 7911
michael@0 7912 if (mContentViewer) {
michael@0 7913 mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
michael@0 7914 viewer->SetPreviousViewer(mContentViewer);
michael@0 7915 }
michael@0 7916 if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
michael@0 7917 // We don't plan to save a viewer in mOSHE; tell it to drop
michael@0 7918 // any other state it's holding.
michael@0 7919 mOSHE->SyncPresentationState();
michael@0 7920 }
michael@0 7921
michael@0 7922 // Order the mContentViewer setup just like Embed does.
michael@0 7923 mContentViewer = nullptr;
michael@0 7924
michael@0 7925 // Now that we're about to switch documents, forget all of our children.
michael@0 7926 // Note that we cached them as needed up in CaptureState above.
michael@0 7927 DestroyChildren();
michael@0 7928
michael@0 7929 mContentViewer.swap(viewer);
michael@0 7930
michael@0 7931 // Grab all of the related presentation from the SHEntry now.
michael@0 7932 // Clearing the viewer from the SHEntry will clear all of this state.
michael@0 7933 nsCOMPtr<nsISupports> windowState;
michael@0 7934 mLSHE->GetWindowState(getter_AddRefs(windowState));
michael@0 7935 mLSHE->SetWindowState(nullptr);
michael@0 7936
michael@0 7937 bool sticky;
michael@0 7938 mLSHE->GetSticky(&sticky);
michael@0 7939
michael@0 7940 nsCOMPtr<nsIDOMDocument> domDoc;
michael@0 7941 mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
michael@0 7942
michael@0 7943 nsCOMArray<nsIDocShellTreeItem> childShells;
michael@0 7944 int32_t i = 0;
michael@0 7945 nsCOMPtr<nsIDocShellTreeItem> child;
michael@0 7946 while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
michael@0 7947 child) {
michael@0 7948 childShells.AppendObject(child);
michael@0 7949 }
michael@0 7950
michael@0 7951 // get the previous content viewer size
michael@0 7952 nsIntRect oldBounds(0, 0, 0, 0);
michael@0 7953 mLSHE->GetViewerBounds(oldBounds);
michael@0 7954
michael@0 7955 // Restore the refresh URI list. The refresh timers will be restarted
michael@0 7956 // when EndPageLoad() is called.
michael@0 7957 nsCOMPtr<nsISupportsArray> refreshURIList;
michael@0 7958 mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
michael@0 7959
michael@0 7960 // Reattach to the window object.
michael@0 7961 mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive
michael@0 7962 rv = mContentViewer->Open(windowState, mLSHE);
michael@0 7963 mIsRestoringDocument = false;
michael@0 7964
michael@0 7965 // Hack to keep nsDocShellEditorData alive across the
michael@0 7966 // SetContentViewer(nullptr) call below.
michael@0 7967 nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
michael@0 7968
michael@0 7969 // Now remove it from the cached presentation.
michael@0 7970 mLSHE->SetContentViewer(nullptr);
michael@0 7971 mEODForCurrentDocument = false;
michael@0 7972
michael@0 7973 mLSHE->SetEditorData(data.forget());
michael@0 7974
michael@0 7975 #ifdef DEBUG
michael@0 7976 {
michael@0 7977 nsCOMPtr<nsISupportsArray> refreshURIs;
michael@0 7978 mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
michael@0 7979 nsCOMPtr<nsIDocShellTreeItem> childShell;
michael@0 7980 mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
michael@0 7981 NS_ASSERTION(!refreshURIs && !childShell,
michael@0 7982 "SHEntry should have cleared presentation state");
michael@0 7983 }
michael@0 7984 #endif
michael@0 7985
michael@0 7986 // Restore the sticky state of the viewer. The viewer has set this state
michael@0 7987 // on the history entry in Destroy() just before marking itself non-sticky,
michael@0 7988 // to avoid teardown of the presentation.
michael@0 7989 mContentViewer->SetSticky(sticky);
michael@0 7990
michael@0 7991 NS_ENSURE_SUCCESS(rv, rv);
michael@0 7992
michael@0 7993 // mLSHE is now our currently-loaded document.
michael@0 7994 SetHistoryEntry(&mOSHE, mLSHE);
michael@0 7995
michael@0 7996 // XXX special wyciwyg handling in Embed()?
michael@0 7997
michael@0 7998 // We aren't going to restore any items from the LayoutHistoryState,
michael@0 7999 // but we don't want them to stay around in case the page is reloaded.
michael@0 8000 SetLayoutHistoryState(nullptr);
michael@0 8001
michael@0 8002 // This is the end of our Embed() replacement
michael@0 8003
michael@0 8004 mSavingOldViewer = false;
michael@0 8005 mEODForCurrentDocument = false;
michael@0 8006
michael@0 8007 // Tell the event loop to favor plevents over user events, see comments
michael@0 8008 // in CreateContentViewer.
michael@0 8009 if (++gNumberOfDocumentsLoading == 1)
michael@0 8010 FavorPerformanceHint(true);
michael@0 8011
michael@0 8012
michael@0 8013 if (oldMUDV && newMUDV) {
michael@0 8014 newMUDV->SetMinFontSize(minFontSize);
michael@0 8015 newMUDV->SetTextZoom(textZoom);
michael@0 8016 newMUDV->SetFullZoom(pageZoom);
michael@0 8017 newMUDV->SetAuthorStyleDisabled(styleDisabled);
michael@0 8018 }
michael@0 8019
michael@0 8020 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
michael@0 8021 uint32_t parentSuspendCount = 0;
michael@0 8022 if (document) {
michael@0 8023 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 8024 GetParent(getter_AddRefs(parent));
michael@0 8025 nsCOMPtr<nsIDocument> d = do_GetInterface(parent);
michael@0 8026 if (d) {
michael@0 8027 if (d->EventHandlingSuppressed()) {
michael@0 8028 document->SuppressEventHandling(nsIDocument::eEvents,
michael@0 8029 d->EventHandlingSuppressed());
michael@0 8030 }
michael@0 8031
michael@0 8032 // Ick, it'd be nicer to not rewalk all of the subdocs here.
michael@0 8033 if (d->AnimationsPaused()) {
michael@0 8034 document->SuppressEventHandling(nsIDocument::eAnimationsOnly,
michael@0 8035 d->AnimationsPaused());
michael@0 8036 }
michael@0 8037
michael@0 8038 nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
michael@0 8039 if (parentWindow) {
michael@0 8040 parentSuspendCount = parentWindow->TimeoutSuspendCount();
michael@0 8041 }
michael@0 8042 }
michael@0 8043
michael@0 8044 // Use the uri from the mLSHE we had when we entered this function
michael@0 8045 // (which need not match the document's URI if anchors are involved),
michael@0 8046 // since that's the history entry we're loading. Note that if we use
michael@0 8047 // origLSHE we don't have to worry about whether the entry in question
michael@0 8048 // is still mLSHE or whether it's now mOSHE.
michael@0 8049 nsCOMPtr<nsIURI> uri;
michael@0 8050 origLSHE->GetURI(getter_AddRefs(uri));
michael@0 8051 SetCurrentURI(uri, document->GetChannel(), true, 0);
michael@0 8052 }
michael@0 8053
michael@0 8054 // This is the end of our CreateContentViewer() replacement.
michael@0 8055 // Now we simulate a load. First, we restore the state of the javascript
michael@0 8056 // window object.
michael@0 8057 nsCOMPtr<nsPIDOMWindow> privWin =
michael@0 8058 do_GetInterface(static_cast<nsIInterfaceRequestor*>(this));
michael@0 8059 NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
michael@0 8060
michael@0 8061 rv = privWin->RestoreWindowState(windowState);
michael@0 8062 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8063
michael@0 8064 // Now, dispatch a title change event which would happen as the
michael@0 8065 // <head> is parsed.
michael@0 8066 document->NotifyPossibleTitleChange(false);
michael@0 8067
michael@0 8068 // Now we simulate appending child docshells for subframes.
michael@0 8069 for (i = 0; i < childShells.Count(); ++i) {
michael@0 8070 nsIDocShellTreeItem *childItem = childShells.ObjectAt(i);
michael@0 8071 nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
michael@0 8072
michael@0 8073 // Make sure to not clobber the state of the child. Since AddChild
michael@0 8074 // always clobbers it, save it off first.
michael@0 8075 bool allowPlugins;
michael@0 8076 childShell->GetAllowPlugins(&allowPlugins);
michael@0 8077
michael@0 8078 bool allowJavascript;
michael@0 8079 childShell->GetAllowJavascript(&allowJavascript);
michael@0 8080
michael@0 8081 bool allowRedirects;
michael@0 8082 childShell->GetAllowMetaRedirects(&allowRedirects);
michael@0 8083
michael@0 8084 bool allowSubframes;
michael@0 8085 childShell->GetAllowSubframes(&allowSubframes);
michael@0 8086
michael@0 8087 bool allowImages;
michael@0 8088 childShell->GetAllowImages(&allowImages);
michael@0 8089
michael@0 8090 bool allowMedia = childShell->GetAllowMedia();
michael@0 8091
michael@0 8092 bool allowDNSPrefetch;
michael@0 8093 childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
michael@0 8094
michael@0 8095 bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
michael@0 8096
michael@0 8097 uint32_t defaultLoadFlags;
michael@0 8098 childShell->GetDefaultLoadFlags(&defaultLoadFlags);
michael@0 8099
michael@0 8100 // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
michael@0 8101 // that the child inherits our state. Among other things, this means
michael@0 8102 // that the child inherits our mIsActive and mInPrivateBrowsing, which
michael@0 8103 // is what we want.
michael@0 8104 AddChild(childItem);
michael@0 8105
michael@0 8106 childShell->SetAllowPlugins(allowPlugins);
michael@0 8107 childShell->SetAllowJavascript(allowJavascript);
michael@0 8108 childShell->SetAllowMetaRedirects(allowRedirects);
michael@0 8109 childShell->SetAllowSubframes(allowSubframes);
michael@0 8110 childShell->SetAllowImages(allowImages);
michael@0 8111 childShell->SetAllowMedia(allowMedia);
michael@0 8112 childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
michael@0 8113 childShell->SetAllowContentRetargeting(allowContentRetargeting);
michael@0 8114 childShell->SetDefaultLoadFlags(defaultLoadFlags);
michael@0 8115
michael@0 8116 rv = childShell->BeginRestore(nullptr, false);
michael@0 8117 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8118 }
michael@0 8119
michael@0 8120 nsCOMPtr<nsIPresShell> shell = GetPresShell();
michael@0 8121
michael@0 8122 // We may be displayed on a different monitor (or in a different
michael@0 8123 // HiDPI mode) than when we got into the history list. So we need
michael@0 8124 // to check if this has happened. See bug 838239.
michael@0 8125
michael@0 8126 // Because the prescontext normally handles resolution changes via
michael@0 8127 // a runnable (see nsPresContext::UIResolutionChanged), its device
michael@0 8128 // context won't be -immediately- updated as a result of calling
michael@0 8129 // shell->BackingScaleFactorChanged().
michael@0 8130
michael@0 8131 // But we depend on that device context when adjusting the view size
michael@0 8132 // via mContentViewer->SetBounds(newBounds) below. So we need to
michael@0 8133 // explicitly tell it to check for changed resolution here.
michael@0 8134 if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) {
michael@0 8135 shell->BackingScaleFactorChanged();
michael@0 8136 }
michael@0 8137
michael@0 8138 nsViewManager *newVM = shell ? shell->GetViewManager() : nullptr;
michael@0 8139 nsView *newRootView = newVM ? newVM->GetRootView() : nullptr;
michael@0 8140
michael@0 8141 // Insert the new root view at the correct location in the view tree.
michael@0 8142 if (container) {
michael@0 8143 nsSubDocumentFrame* subDocFrame = do_QueryFrame(container->GetPrimaryFrame());
michael@0 8144 rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr;
michael@0 8145 }
michael@0 8146 if (sibling &&
michael@0 8147 sibling->GetShell() &&
michael@0 8148 sibling->GetShell()->GetViewManager()) {
michael@0 8149 rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView();
michael@0 8150 } else {
michael@0 8151 rootViewSibling = nullptr;
michael@0 8152 }
michael@0 8153 if (rootViewParent && newRootView && newRootView->GetParent() != rootViewParent) {
michael@0 8154 nsViewManager *parentVM = rootViewParent->GetViewManager();
michael@0 8155 if (parentVM) {
michael@0 8156 // InsertChild(parent, child, sib, true) inserts the child after
michael@0 8157 // sib in content order, which is before sib in view order. BUT
michael@0 8158 // when sib is null it inserts at the end of the the document
michael@0 8159 // order, i.e., first in view order. But when oldRootSibling is
michael@0 8160 // null, the old root as at the end of the view list --- last in
michael@0 8161 // content order --- and we want to call InsertChild(parent, child,
michael@0 8162 // nullptr, false) in that case.
michael@0 8163 parentVM->InsertChild(rootViewParent, newRootView,
michael@0 8164 rootViewSibling,
michael@0 8165 rootViewSibling ? true : false);
michael@0 8166
michael@0 8167 NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
michael@0 8168 "error in InsertChild");
michael@0 8169 }
michael@0 8170 }
michael@0 8171
michael@0 8172 // If parent is suspended, increase suspension count.
michael@0 8173 // This can't be done as early as event suppression since this
michael@0 8174 // depends on docshell tree.
michael@0 8175 if (parentSuspendCount) {
michael@0 8176 privWin->SuspendTimeouts(parentSuspendCount, false);
michael@0 8177 }
michael@0 8178
michael@0 8179 // Now that all of the child docshells have been put into place, we can
michael@0 8180 // restart the timers for the window and all of the child frames.
michael@0 8181 privWin->ResumeTimeouts();
michael@0 8182
michael@0 8183 // Restore the refresh URI list. The refresh timers will be restarted
michael@0 8184 // when EndPageLoad() is called.
michael@0 8185 mRefreshURIList = refreshURIList;
michael@0 8186
michael@0 8187 // Meta-refresh timers have been restarted for this shell, but not
michael@0 8188 // for our children. Walk the child shells and restart their timers.
michael@0 8189 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
michael@0 8190 while (iter.HasMore()) {
michael@0 8191 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
michael@0 8192 if (child)
michael@0 8193 child->ResumeRefreshURIs();
michael@0 8194 }
michael@0 8195
michael@0 8196 // Make sure this presentation is the same size as the previous
michael@0 8197 // presentation. If this is not the same size we showed it at last time,
michael@0 8198 // then we need to resize the widget.
michael@0 8199
michael@0 8200 // XXXbryner This interacts poorly with Firefox's infobar. If the old
michael@0 8201 // presentation had the infobar visible, then we will resize the new
michael@0 8202 // presentation to that smaller size. However, firing the locationchanged
michael@0 8203 // event will hide the infobar, which will immediately resize the window
michael@0 8204 // back to the larger size. A future optimization might be to restore
michael@0 8205 // the presentation at the "wrong" size, then fire the locationchanged
michael@0 8206 // event and check whether the docshell's new size is the same as the
michael@0 8207 // cached viewer size (skipping the resize if they are equal).
michael@0 8208
michael@0 8209 if (newRootView) {
michael@0 8210 if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
michael@0 8211 #ifdef DEBUG_PAGE_CACHE
michael@0 8212 printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
michael@0 8213 newBounds.y, newBounds.width, newBounds.height);
michael@0 8214 #endif
michael@0 8215 mContentViewer->SetBounds(newBounds);
michael@0 8216 } else {
michael@0 8217 nsIScrollableFrame *rootScrollFrame =
michael@0 8218 shell->GetRootScrollFrameAsScrollableExternal();
michael@0 8219 if (rootScrollFrame) {
michael@0 8220 rootScrollFrame->PostScrolledAreaEventForCurrentArea();
michael@0 8221 }
michael@0 8222 }
michael@0 8223 }
michael@0 8224
michael@0 8225 // The FinishRestore call below can kill these, null them out so we don't
michael@0 8226 // have invalid pointer lying around.
michael@0 8227 newRootView = rootViewSibling = rootViewParent = nullptr;
michael@0 8228 newVM = nullptr;
michael@0 8229
michael@0 8230 // Simulate the completion of the load.
michael@0 8231 nsDocShell::FinishRestore();
michael@0 8232
michael@0 8233 // Restart plugins, and paint the content.
michael@0 8234 if (shell) {
michael@0 8235 shell->Thaw();
michael@0 8236 }
michael@0 8237
michael@0 8238 return privWin->FireDelayedDOMEvents();
michael@0 8239 }
michael@0 8240
michael@0 8241 NS_IMETHODIMP
michael@0 8242 nsDocShell::CreateContentViewer(const char *aContentType,
michael@0 8243 nsIRequest * request,
michael@0 8244 nsIStreamListener ** aContentHandler)
michael@0 8245 {
michael@0 8246 *aContentHandler = nullptr;
michael@0 8247
michael@0 8248 // Can we check the content type of the current content viewer
michael@0 8249 // and reuse it without destroying it and re-creating it?
michael@0 8250
michael@0 8251 NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
michael@0 8252
michael@0 8253 // Instantiate the content viewer object
michael@0 8254 nsCOMPtr<nsIContentViewer> viewer;
michael@0 8255 nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup,
michael@0 8256 aContentHandler, getter_AddRefs(viewer));
michael@0 8257
michael@0 8258 if (NS_FAILED(rv))
michael@0 8259 return rv;
michael@0 8260
michael@0 8261 // Notify the current document that it is about to be unloaded!!
michael@0 8262 //
michael@0 8263 // It is important to fire the unload() notification *before* any state
michael@0 8264 // is changed within the DocShell - otherwise, javascript will get the
michael@0 8265 // wrong information :-(
michael@0 8266 //
michael@0 8267
michael@0 8268 if (mSavingOldViewer) {
michael@0 8269 // We determined that it was safe to cache the document presentation
michael@0 8270 // at the time we initiated the new load. We need to check whether
michael@0 8271 // it's still safe to do so, since there may have been DOM mutations
michael@0 8272 // or new requests initiated.
michael@0 8273 nsCOMPtr<nsIDOMDocument> domDoc;
michael@0 8274 viewer->GetDOMDocument(getter_AddRefs(domDoc));
michael@0 8275 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
michael@0 8276 mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
michael@0 8277 }
michael@0 8278
michael@0 8279 NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
michael@0 8280
michael@0 8281 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
michael@0 8282 if (aOpenedChannel) {
michael@0 8283 aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
michael@0 8284 }
michael@0 8285 FirePageHideNotification(!mSavingOldViewer);
michael@0 8286 mLoadingURI = nullptr;
michael@0 8287
michael@0 8288 // Set mFiredUnloadEvent = false so that the unload handler for the
michael@0 8289 // *new* document will fire.
michael@0 8290 mFiredUnloadEvent = false;
michael@0 8291
michael@0 8292 // we've created a new document so go ahead and call
michael@0 8293 // OnLoadingSite(), but don't fire OnLocationChange()
michael@0 8294 // notifications before we've called Embed(). See bug 284993.
michael@0 8295 mURIResultedInDocument = true;
michael@0 8296
michael@0 8297 if (mLoadType == LOAD_ERROR_PAGE) {
michael@0 8298 // We need to set the SH entry and our current URI here and not
michael@0 8299 // at the moment we load the page. We want the same behavior
michael@0 8300 // of Stop() as for a normal page load. See bug 514232 for details.
michael@0 8301
michael@0 8302 // Revert mLoadType to load type to state the page load failed,
michael@0 8303 // following function calls need it.
michael@0 8304 mLoadType = mFailedLoadType;
michael@0 8305
michael@0 8306 nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
michael@0 8307
michael@0 8308 // Make sure we have a URI to set currentURI.
michael@0 8309 nsCOMPtr<nsIURI> failedURI;
michael@0 8310 if (failedChannel) {
michael@0 8311 NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
michael@0 8312 }
michael@0 8313
michael@0 8314 if (!failedURI) {
michael@0 8315 failedURI = mFailedURI;
michael@0 8316 }
michael@0 8317 if (!failedURI) {
michael@0 8318 // We need a URI object to store a session history entry, so make up a URI
michael@0 8319 NS_NewURI(getter_AddRefs(failedURI), "about:blank");
michael@0 8320 }
michael@0 8321
michael@0 8322 // When we don't have failedURI, something wrong will happen. See
michael@0 8323 // bug 291876.
michael@0 8324 MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
michael@0 8325
michael@0 8326 mFailedChannel = nullptr;
michael@0 8327 mFailedURI = nullptr;
michael@0 8328
michael@0 8329 // Create an shistory entry for the old load.
michael@0 8330 if (failedURI) {
michael@0 8331 bool errorOnLocationChangeNeeded =
michael@0 8332 OnNewURI(failedURI, failedChannel, nullptr, mLoadType, false,
michael@0 8333 false, false);
michael@0 8334
michael@0 8335 if (errorOnLocationChangeNeeded) {
michael@0 8336 FireOnLocationChange(this, failedChannel, failedURI,
michael@0 8337 LOCATION_CHANGE_ERROR_PAGE);
michael@0 8338 }
michael@0 8339 }
michael@0 8340
michael@0 8341 // Be sure to have a correct mLSHE, it may have been cleared by
michael@0 8342 // EndPageLoad. See bug 302115.
michael@0 8343 if (mSessionHistory && !mLSHE) {
michael@0 8344 int32_t idx;
michael@0 8345 mSessionHistory->GetRequestedIndex(&idx);
michael@0 8346 if (idx == -1)
michael@0 8347 mSessionHistory->GetIndex(&idx);
michael@0 8348 mSessionHistory->GetEntryAtIndex(idx, false,
michael@0 8349 getter_AddRefs(mLSHE));
michael@0 8350 }
michael@0 8351
michael@0 8352 mLoadType = LOAD_ERROR_PAGE;
michael@0 8353 }
michael@0 8354
michael@0 8355 bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
michael@0 8356
michael@0 8357 // let's try resetting the load group if we need to...
michael@0 8358 nsCOMPtr<nsILoadGroup> currentLoadGroup;
michael@0 8359 NS_ENSURE_SUCCESS(aOpenedChannel->
michael@0 8360 GetLoadGroup(getter_AddRefs(currentLoadGroup)),
michael@0 8361 NS_ERROR_FAILURE);
michael@0 8362
michael@0 8363 if (currentLoadGroup != mLoadGroup) {
michael@0 8364 nsLoadFlags loadFlags = 0;
michael@0 8365
michael@0 8366 //Cancel any URIs that are currently loading...
michael@0 8367 /// XXX: Need to do this eventually Stop();
michael@0 8368 //
michael@0 8369 // Retarget the document to this loadgroup...
michael@0 8370 //
michael@0 8371 /* First attach the channel to the right loadgroup
michael@0 8372 * and then remove from the old loadgroup. This
michael@0 8373 * puts the notifications in the right order and
michael@0 8374 * we don't null-out mLSHE in OnStateChange() for
michael@0 8375 * all redirected urls
michael@0 8376 */
michael@0 8377 aOpenedChannel->SetLoadGroup(mLoadGroup);
michael@0 8378
michael@0 8379 // Mark the channel as being a document URI...
michael@0 8380 aOpenedChannel->GetLoadFlags(&loadFlags);
michael@0 8381 loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
michael@0 8382
michael@0 8383 aOpenedChannel->SetLoadFlags(loadFlags);
michael@0 8384
michael@0 8385 mLoadGroup->AddRequest(request, nullptr);
michael@0 8386 if (currentLoadGroup)
michael@0 8387 currentLoadGroup->RemoveRequest(request, nullptr,
michael@0 8388 NS_BINDING_RETARGETED);
michael@0 8389
michael@0 8390 // Update the notification callbacks, so that progress and
michael@0 8391 // status information are sent to the right docshell...
michael@0 8392 aOpenedChannel->SetNotificationCallbacks(this);
michael@0 8393 }
michael@0 8394
michael@0 8395 NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nullptr),
michael@0 8396 NS_ERROR_FAILURE);
michael@0 8397
michael@0 8398 mSavedRefreshURIList = nullptr;
michael@0 8399 mSavingOldViewer = false;
michael@0 8400 mEODForCurrentDocument = false;
michael@0 8401
michael@0 8402 // if this document is part of a multipart document,
michael@0 8403 // the ID can be used to distinguish it from the other parts.
michael@0 8404 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(request));
michael@0 8405 if (multiPartChannel) {
michael@0 8406 nsCOMPtr<nsIPresShell> shell = GetPresShell();
michael@0 8407 if (NS_SUCCEEDED(rv) && shell) {
michael@0 8408 nsIDocument *doc = shell->GetDocument();
michael@0 8409 if (doc) {
michael@0 8410 uint32_t partID;
michael@0 8411 multiPartChannel->GetPartID(&partID);
michael@0 8412 doc->SetPartID(partID);
michael@0 8413 }
michael@0 8414 }
michael@0 8415 }
michael@0 8416
michael@0 8417 // Give hint to native plevent dispatch mechanism. If a document
michael@0 8418 // is loading the native plevent dispatch mechanism should favor
michael@0 8419 // performance over normal native event dispatch priorities.
michael@0 8420 if (++gNumberOfDocumentsLoading == 1) {
michael@0 8421 // Hint to favor performance for the plevent notification mechanism.
michael@0 8422 // We want the pages to load as fast as possible even if its means
michael@0 8423 // native messages might be starved.
michael@0 8424 FavorPerformanceHint(true);
michael@0 8425 }
michael@0 8426
michael@0 8427 if (onLocationChangeNeeded) {
michael@0 8428 FireOnLocationChange(this, request, mCurrentURI, 0);
michael@0 8429 }
michael@0 8430
michael@0 8431 return NS_OK;
michael@0 8432 }
michael@0 8433
michael@0 8434 nsresult
michael@0 8435 nsDocShell::NewContentViewerObj(const char *aContentType,
michael@0 8436 nsIRequest * request, nsILoadGroup * aLoadGroup,
michael@0 8437 nsIStreamListener ** aContentHandler,
michael@0 8438 nsIContentViewer ** aViewer)
michael@0 8439 {
michael@0 8440 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
michael@0 8441
michael@0 8442 nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
michael@0 8443 nsContentUtils::FindInternalContentViewer(aContentType);
michael@0 8444 if (!docLoaderFactory) {
michael@0 8445 return NS_ERROR_FAILURE;
michael@0 8446 }
michael@0 8447
michael@0 8448 // Now create an instance of the content viewer
michael@0 8449 // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
michael@0 8450 nsresult rv = docLoaderFactory->CreateInstance("view",
michael@0 8451 aOpenedChannel,
michael@0 8452 aLoadGroup, aContentType,
michael@0 8453 this,
michael@0 8454 nullptr,
michael@0 8455 aContentHandler,
michael@0 8456 aViewer);
michael@0 8457 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8458
michael@0 8459 (*aViewer)->SetContainer(this);
michael@0 8460 return NS_OK;
michael@0 8461 }
michael@0 8462
michael@0 8463 NS_IMETHODIMP
michael@0 8464 nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
michael@0 8465 {
michael@0 8466 //
michael@0 8467 // Copy content viewer state from previous or parent content viewer.
michael@0 8468 //
michael@0 8469 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
michael@0 8470 //
michael@0 8471 // Do NOT to maintain a reference to the old content viewer outside
michael@0 8472 // of this "copying" block, or it will not be destroyed until the end of
michael@0 8473 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
michael@0 8474 //
michael@0 8475 // In this block of code, if we get an error result, we return it
michael@0 8476 // but if we get a null pointer, that's perfectly legal for parent
michael@0 8477 // and parentContentViewer.
michael@0 8478 //
michael@0 8479
michael@0 8480 int32_t x = 0;
michael@0 8481 int32_t y = 0;
michael@0 8482 int32_t cx = 0;
michael@0 8483 int32_t cy = 0;
michael@0 8484
michael@0 8485 // This will get the size from the current content viewer or from the
michael@0 8486 // Init settings
michael@0 8487 DoGetPositionAndSize(&x, &y, &cx, &cy);
michael@0 8488
michael@0 8489 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
michael@0 8490 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
michael@0 8491 NS_ERROR_FAILURE);
michael@0 8492 nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
michael@0 8493
michael@0 8494 nsAutoCString forceCharset;
michael@0 8495 nsAutoCString hintCharset;
michael@0 8496 int32_t hintCharsetSource;
michael@0 8497 int32_t minFontSize;
michael@0 8498 float textZoom;
michael@0 8499 float pageZoom;
michael@0 8500 bool styleDisabled;
michael@0 8501 // |newMUDV| also serves as a flag to set the data from the above vars
michael@0 8502 nsCOMPtr<nsIMarkupDocumentViewer> newMUDV;
michael@0 8503
michael@0 8504 if (mContentViewer || parent) {
michael@0 8505 nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV;
michael@0 8506 if (mContentViewer) {
michael@0 8507 // Get any interesting state from old content viewer
michael@0 8508 // XXX: it would be far better to just reuse the document viewer ,
michael@0 8509 // since we know we're just displaying the same document as before
michael@0 8510 oldMUDV = do_QueryInterface(mContentViewer);
michael@0 8511
michael@0 8512 // Tell the old content viewer to hibernate in session history when
michael@0 8513 // it is destroyed.
michael@0 8514
michael@0 8515 if (mSavingOldViewer && NS_FAILED(CaptureState())) {
michael@0 8516 if (mOSHE) {
michael@0 8517 mOSHE->SyncPresentationState();
michael@0 8518 }
michael@0 8519 mSavingOldViewer = false;
michael@0 8520 }
michael@0 8521 }
michael@0 8522 else {
michael@0 8523 // No old content viewer, so get state from parent's content viewer
michael@0 8524 nsCOMPtr<nsIContentViewer> parentContentViewer;
michael@0 8525 parent->GetContentViewer(getter_AddRefs(parentContentViewer));
michael@0 8526 oldMUDV = do_QueryInterface(parentContentViewer);
michael@0 8527 }
michael@0 8528
michael@0 8529 if (oldMUDV) {
michael@0 8530 nsresult rv;
michael@0 8531
michael@0 8532 newMUDV = do_QueryInterface(aNewViewer,&rv);
michael@0 8533 if (newMUDV) {
michael@0 8534 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8535 GetForceCharacterSet(forceCharset),
michael@0 8536 NS_ERROR_FAILURE);
michael@0 8537 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8538 GetHintCharacterSet(hintCharset),
michael@0 8539 NS_ERROR_FAILURE);
michael@0 8540 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8541 GetHintCharacterSetSource(&hintCharsetSource),
michael@0 8542 NS_ERROR_FAILURE);
michael@0 8543 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8544 GetMinFontSize(&minFontSize),
michael@0 8545 NS_ERROR_FAILURE);
michael@0 8546 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8547 GetTextZoom(&textZoom),
michael@0 8548 NS_ERROR_FAILURE);
michael@0 8549 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8550 GetFullZoom(&pageZoom),
michael@0 8551 NS_ERROR_FAILURE);
michael@0 8552 NS_ENSURE_SUCCESS(oldMUDV->
michael@0 8553 GetAuthorStyleDisabled(&styleDisabled),
michael@0 8554 NS_ERROR_FAILURE);
michael@0 8555 }
michael@0 8556 }
michael@0 8557 }
michael@0 8558
michael@0 8559 nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
michael@0 8560 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
michael@0 8561 nsCOMPtr<nsIContentViewer> kungfuDeathGrip = mContentViewer;
michael@0 8562 if (mContentViewer) {
michael@0 8563 // Stop any activity that may be happening in the old document before
michael@0 8564 // releasing it...
michael@0 8565 mContentViewer->Stop();
michael@0 8566
michael@0 8567 // Try to extract the canvas background color from the old
michael@0 8568 // presentation shell, so we can use it for the next document.
michael@0 8569 nsCOMPtr<nsIPresShell> shell;
michael@0 8570 mContentViewer->GetPresShell(getter_AddRefs(shell));
michael@0 8571
michael@0 8572 if (shell) {
michael@0 8573 bgcolor = shell->GetCanvasBackground();
michael@0 8574 }
michael@0 8575
michael@0 8576 mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
michael@0 8577 aNewViewer->SetPreviousViewer(mContentViewer);
michael@0 8578 }
michael@0 8579 if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
michael@0 8580 // We don't plan to save a viewer in mOSHE; tell it to drop
michael@0 8581 // any other state it's holding.
michael@0 8582 mOSHE->SyncPresentationState();
michael@0 8583 }
michael@0 8584
michael@0 8585 mContentViewer = nullptr;
michael@0 8586
michael@0 8587 // Now that we're about to switch documents, forget all of our children.
michael@0 8588 // Note that we cached them as needed up in CaptureState above.
michael@0 8589 DestroyChildren();
michael@0 8590
michael@0 8591 mContentViewer = aNewViewer;
michael@0 8592
michael@0 8593 nsCOMPtr<nsIWidget> widget;
michael@0 8594 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
michael@0 8595
michael@0 8596 nsIntRect bounds(x, y, cx, cy);
michael@0 8597
michael@0 8598 mContentViewer->SetNavigationTiming(mTiming);
michael@0 8599
michael@0 8600 if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
michael@0 8601 mContentViewer = nullptr;
michael@0 8602 NS_ERROR("ContentViewer Initialization failed");
michael@0 8603 return NS_ERROR_FAILURE;
michael@0 8604 }
michael@0 8605
michael@0 8606 // If we have old state to copy, set the old state onto the new content
michael@0 8607 // viewer
michael@0 8608 if (newMUDV) {
michael@0 8609 NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
michael@0 8610 NS_ERROR_FAILURE);
michael@0 8611 NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset),
michael@0 8612 NS_ERROR_FAILURE);
michael@0 8613 NS_ENSURE_SUCCESS(newMUDV->
michael@0 8614 SetHintCharacterSetSource(hintCharsetSource),
michael@0 8615 NS_ERROR_FAILURE);
michael@0 8616 NS_ENSURE_SUCCESS(newMUDV->SetMinFontSize(minFontSize),
michael@0 8617 NS_ERROR_FAILURE);
michael@0 8618 NS_ENSURE_SUCCESS(newMUDV->SetTextZoom(textZoom),
michael@0 8619 NS_ERROR_FAILURE);
michael@0 8620 NS_ENSURE_SUCCESS(newMUDV->SetFullZoom(pageZoom),
michael@0 8621 NS_ERROR_FAILURE);
michael@0 8622 NS_ENSURE_SUCCESS(newMUDV->SetAuthorStyleDisabled(styleDisabled),
michael@0 8623 NS_ERROR_FAILURE);
michael@0 8624 }
michael@0 8625
michael@0 8626 // Stuff the bgcolor from the old pres shell into the new
michael@0 8627 // pres shell. This improves page load continuity.
michael@0 8628 nsCOMPtr<nsIPresShell> shell;
michael@0 8629 mContentViewer->GetPresShell(getter_AddRefs(shell));
michael@0 8630
michael@0 8631 if (shell) {
michael@0 8632 shell->SetCanvasBackground(bgcolor);
michael@0 8633 }
michael@0 8634
michael@0 8635 // XXX: It looks like the LayoutState gets restored again in Embed()
michael@0 8636 // right after the call to SetupNewViewer(...)
michael@0 8637
michael@0 8638 // We don't show the mContentViewer yet, since we want to draw the old page
michael@0 8639 // until we have enough of the new page to show. Just return with the new
michael@0 8640 // viewer still set to hidden.
michael@0 8641
michael@0 8642 return NS_OK;
michael@0 8643 }
michael@0 8644
michael@0 8645 nsresult
michael@0 8646 nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry)
michael@0 8647 {
michael@0 8648 nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
michael@0 8649 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
michael@0 8650
michael@0 8651 nsCOMPtr<nsIStructuredCloneContainer> scContainer;
michael@0 8652 if (shEntry) {
michael@0 8653 nsresult rv = shEntry->GetStateData(getter_AddRefs(scContainer));
michael@0 8654 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8655
michael@0 8656 // If shEntry is null, just set the document's state object to null.
michael@0 8657 }
michael@0 8658
michael@0 8659 // It's OK for scContainer too be null here; that just means there's no
michael@0 8660 // state data associated with this history entry.
michael@0 8661 document->SetStateObject(scContainer);
michael@0 8662
michael@0 8663 return NS_OK;
michael@0 8664 }
michael@0 8665
michael@0 8666 nsresult
michael@0 8667 nsDocShell::CheckLoadingPermissions()
michael@0 8668 {
michael@0 8669 // This method checks whether the caller may load content into
michael@0 8670 // this docshell. Even though we've done our best to hide windows
michael@0 8671 // from code that doesn't have the right to access them, it's
michael@0 8672 // still possible for an evil site to open a window and access
michael@0 8673 // frames in the new window through window.frames[] (which is
michael@0 8674 // allAccess for historic reasons), so we still need to do this
michael@0 8675 // check on load.
michael@0 8676 nsresult rv = NS_OK, sameOrigin = NS_OK;
michael@0 8677
michael@0 8678 if (!gValidateOrigin || !IsFrame()) {
michael@0 8679 // Origin validation was turned off, or we're not a frame.
michael@0 8680 // Permit all loads.
michael@0 8681
michael@0 8682 return rv;
michael@0 8683 }
michael@0 8684
michael@0 8685 nsCOMPtr<nsIScriptSecurityManager> securityManager =
michael@0 8686 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 8687 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8688
michael@0 8689 // We're a frame. Check that the caller has write permission to
michael@0 8690 // the parent before allowing it to load anything into this
michael@0 8691 // docshell.
michael@0 8692 nsCOMPtr<nsIPrincipal> subjPrincipal;
michael@0 8693 rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal));
michael@0 8694 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv);
michael@0 8695
michael@0 8696 // Check if the caller is from the same origin as this docshell,
michael@0 8697 // or any of its ancestors.
michael@0 8698 nsCOMPtr<nsIDocShellTreeItem> item(this);
michael@0 8699 do {
michael@0 8700 nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item));
michael@0 8701 nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
michael@0 8702
michael@0 8703 nsIPrincipal *p;
michael@0 8704 if (!sop || !(p = sop->GetPrincipal())) {
michael@0 8705 return NS_ERROR_UNEXPECTED;
michael@0 8706 }
michael@0 8707
michael@0 8708 // Compare origins
michael@0 8709 bool subsumes;
michael@0 8710 sameOrigin = subjPrincipal->Subsumes(p, &subsumes);
michael@0 8711 if (NS_SUCCEEDED(sameOrigin)) {
michael@0 8712 if (subsumes) {
michael@0 8713 // Same origin, permit load
michael@0 8714
michael@0 8715 return sameOrigin;
michael@0 8716 }
michael@0 8717
michael@0 8718 sameOrigin = NS_ERROR_DOM_PROP_ACCESS_DENIED;
michael@0 8719 }
michael@0 8720
michael@0 8721 nsCOMPtr<nsIDocShellTreeItem> tmp;
michael@0 8722 item->GetSameTypeParent(getter_AddRefs(tmp));
michael@0 8723 item.swap(tmp);
michael@0 8724 } while (item);
michael@0 8725
michael@0 8726 return sameOrigin;
michael@0 8727 }
michael@0 8728
michael@0 8729 //*****************************************************************************
michael@0 8730 // nsDocShell: Site Loading
michael@0 8731 //*****************************************************************************
michael@0 8732 namespace
michael@0 8733 {
michael@0 8734
michael@0 8735 #ifdef MOZ_PLACES
michael@0 8736 // Callback used by CopyFavicon to inform the favicon service that one URI
michael@0 8737 // (mNewURI) has the same favicon URI (OnComplete's aFaviconURI) as another.
michael@0 8738 class nsCopyFaviconCallback MOZ_FINAL : public nsIFaviconDataCallback
michael@0 8739 {
michael@0 8740 public:
michael@0 8741 NS_DECL_ISUPPORTS
michael@0 8742
michael@0 8743 nsCopyFaviconCallback(nsIURI *aNewURI, bool aInPrivateBrowsing)
michael@0 8744 : mNewURI(aNewURI)
michael@0 8745 , mInPrivateBrowsing(aInPrivateBrowsing)
michael@0 8746 {
michael@0 8747 }
michael@0 8748
michael@0 8749 NS_IMETHODIMP
michael@0 8750 OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen,
michael@0 8751 const uint8_t *aData, const nsACString &aMimeType)
michael@0 8752 {
michael@0 8753 // Continue only if there is an associated favicon.
michael@0 8754 if (!aFaviconURI) {
michael@0 8755 return NS_OK;
michael@0 8756 }
michael@0 8757
michael@0 8758 NS_ASSERTION(aDataLen == 0,
michael@0 8759 "We weren't expecting the callback to deliver data.");
michael@0 8760 nsCOMPtr<mozIAsyncFavicons> favSvc =
michael@0 8761 do_GetService("@mozilla.org/browser/favicon-service;1");
michael@0 8762 NS_ENSURE_STATE(favSvc);
michael@0 8763
michael@0 8764 return favSvc->SetAndFetchFaviconForPage(mNewURI, aFaviconURI,
michael@0 8765 false,
michael@0 8766 mInPrivateBrowsing ?
michael@0 8767 nsIFaviconService::FAVICON_LOAD_PRIVATE :
michael@0 8768 nsIFaviconService::FAVICON_LOAD_NON_PRIVATE,
michael@0 8769 nullptr);
michael@0 8770 }
michael@0 8771
michael@0 8772 private:
michael@0 8773 nsCOMPtr<nsIURI> mNewURI;
michael@0 8774 bool mInPrivateBrowsing;
michael@0 8775 };
michael@0 8776
michael@0 8777 NS_IMPL_ISUPPORTS(nsCopyFaviconCallback, nsIFaviconDataCallback)
michael@0 8778 #endif
michael@0 8779
michael@0 8780 // Tell the favicon service that aNewURI has the same favicon as aOldURI.
michael@0 8781 void CopyFavicon(nsIURI *aOldURI, nsIURI *aNewURI, bool inPrivateBrowsing)
michael@0 8782 {
michael@0 8783 #ifdef MOZ_PLACES
michael@0 8784 nsCOMPtr<mozIAsyncFavicons> favSvc =
michael@0 8785 do_GetService("@mozilla.org/browser/favicon-service;1");
michael@0 8786 if (favSvc) {
michael@0 8787 nsCOMPtr<nsIFaviconDataCallback> callback =
michael@0 8788 new nsCopyFaviconCallback(aNewURI, inPrivateBrowsing);
michael@0 8789 favSvc->GetFaviconURLForPage(aOldURI, callback);
michael@0 8790 }
michael@0 8791 #endif
michael@0 8792 }
michael@0 8793
michael@0 8794 } // anonymous namespace
michael@0 8795
michael@0 8796 class InternalLoadEvent : public nsRunnable
michael@0 8797 {
michael@0 8798 public:
michael@0 8799 InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
michael@0 8800 nsISupports * aOwner, uint32_t aFlags,
michael@0 8801 const char* aTypeHint, nsIInputStream * aPostData,
michael@0 8802 nsIInputStream * aHeadersData, uint32_t aLoadType,
michael@0 8803 nsISHEntry * aSHEntry, bool aFirstParty,
michael@0 8804 const nsAString &aSrcdoc, nsIDocShell* aSourceDocShell,
michael@0 8805 nsIURI * aBaseURI) :
michael@0 8806 mSrcdoc(aSrcdoc),
michael@0 8807 mDocShell(aDocShell),
michael@0 8808 mURI(aURI),
michael@0 8809 mReferrer(aReferrer),
michael@0 8810 mOwner(aOwner),
michael@0 8811 mPostData(aPostData),
michael@0 8812 mHeadersData(aHeadersData),
michael@0 8813 mSHEntry(aSHEntry),
michael@0 8814 mFlags(aFlags),
michael@0 8815 mLoadType(aLoadType),
michael@0 8816 mFirstParty(aFirstParty),
michael@0 8817 mSourceDocShell(aSourceDocShell),
michael@0 8818 mBaseURI(aBaseURI)
michael@0 8819 {
michael@0 8820 // Make sure to keep null things null as needed
michael@0 8821 if (aTypeHint) {
michael@0 8822 mTypeHint = aTypeHint;
michael@0 8823 }
michael@0 8824 }
michael@0 8825
michael@0 8826 NS_IMETHOD Run() {
michael@0 8827 return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
michael@0 8828 nullptr, mTypeHint.get(),
michael@0 8829 NullString(), mPostData, mHeadersData,
michael@0 8830 mLoadType, mSHEntry, mFirstParty,
michael@0 8831 mSrcdoc, mSourceDocShell, mBaseURI,
michael@0 8832 nullptr, nullptr);
michael@0 8833 }
michael@0 8834
michael@0 8835 private:
michael@0 8836
michael@0 8837 // Use IDL strings so .get() returns null by default
michael@0 8838 nsXPIDLString mWindowTarget;
michael@0 8839 nsXPIDLCString mTypeHint;
michael@0 8840 nsString mSrcdoc;
michael@0 8841
michael@0 8842 nsRefPtr<nsDocShell> mDocShell;
michael@0 8843 nsCOMPtr<nsIURI> mURI;
michael@0 8844 nsCOMPtr<nsIURI> mReferrer;
michael@0 8845 nsCOMPtr<nsISupports> mOwner;
michael@0 8846 nsCOMPtr<nsIInputStream> mPostData;
michael@0 8847 nsCOMPtr<nsIInputStream> mHeadersData;
michael@0 8848 nsCOMPtr<nsISHEntry> mSHEntry;
michael@0 8849 uint32_t mFlags;
michael@0 8850 uint32_t mLoadType;
michael@0 8851 bool mFirstParty;
michael@0 8852 nsCOMPtr<nsIDocShell> mSourceDocShell;
michael@0 8853 nsCOMPtr<nsIURI> mBaseURI;
michael@0 8854 };
michael@0 8855
michael@0 8856 /**
michael@0 8857 * Returns true if we started an asynchronous load (i.e., from the network), but
michael@0 8858 * the document we're loading there hasn't yet become this docshell's active
michael@0 8859 * document.
michael@0 8860 *
michael@0 8861 * When JustStartedNetworkLoad is true, you should be careful about modifying
michael@0 8862 * mLoadType and mLSHE. These are both set when the asynchronous load first
michael@0 8863 * starts, and the load expects that, when it eventually runs InternalLoad,
michael@0 8864 * mLoadType and mLSHE will have their original values.
michael@0 8865 */
michael@0 8866 bool
michael@0 8867 nsDocShell::JustStartedNetworkLoad()
michael@0 8868 {
michael@0 8869 return mDocumentRequest &&
michael@0 8870 mDocumentRequest != GetCurrentDocChannel();
michael@0 8871 }
michael@0 8872
michael@0 8873 NS_IMETHODIMP
michael@0 8874 nsDocShell::InternalLoad(nsIURI * aURI,
michael@0 8875 nsIURI * aReferrer,
michael@0 8876 nsISupports * aOwner,
michael@0 8877 uint32_t aFlags,
michael@0 8878 const char16_t *aWindowTarget,
michael@0 8879 const char* aTypeHint,
michael@0 8880 const nsAString& aFileName,
michael@0 8881 nsIInputStream * aPostData,
michael@0 8882 nsIInputStream * aHeadersData,
michael@0 8883 uint32_t aLoadType,
michael@0 8884 nsISHEntry * aSHEntry,
michael@0 8885 bool aFirstParty,
michael@0 8886 const nsAString &aSrcdoc,
michael@0 8887 nsIDocShell* aSourceDocShell,
michael@0 8888 nsIURI* aBaseURI,
michael@0 8889 nsIDocShell** aDocShell,
michael@0 8890 nsIRequest** aRequest)
michael@0 8891 {
michael@0 8892 nsresult rv = NS_OK;
michael@0 8893 mOriginalUriString.Truncate();
michael@0 8894
michael@0 8895 #ifdef PR_LOGGING
michael@0 8896 if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
michael@0 8897 nsAutoCString spec;
michael@0 8898 if (aURI)
michael@0 8899 aURI->GetSpec(spec);
michael@0 8900 PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
michael@0 8901 }
michael@0 8902 #endif
michael@0 8903 // Initialize aDocShell/aRequest
michael@0 8904 if (aDocShell) {
michael@0 8905 *aDocShell = nullptr;
michael@0 8906 }
michael@0 8907 if (aRequest) {
michael@0 8908 *aRequest = nullptr;
michael@0 8909 }
michael@0 8910
michael@0 8911 if (!aURI) {
michael@0 8912 return NS_ERROR_NULL_POINTER;
michael@0 8913 }
michael@0 8914
michael@0 8915 NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
michael@0 8916
michael@0 8917 NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
michael@0 8918
michael@0 8919 // wyciwyg urls can only be loaded through history. Any normal load of
michael@0 8920 // wyciwyg through docshell is illegal. Disallow such loads.
michael@0 8921 if (aLoadType & LOAD_CMD_NORMAL) {
michael@0 8922 bool isWyciwyg = false;
michael@0 8923 rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
michael@0 8924 if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv))
michael@0 8925 return NS_ERROR_FAILURE;
michael@0 8926 }
michael@0 8927
michael@0 8928 bool bIsJavascript = false;
michael@0 8929 if (NS_FAILED(aURI->SchemeIs("javascript", &bIsJavascript))) {
michael@0 8930 bIsJavascript = false;
michael@0 8931 }
michael@0 8932
michael@0 8933 //
michael@0 8934 // First, notify any nsIContentPolicy listeners about the document load.
michael@0 8935 // Only abort the load if a content policy listener explicitly vetos it!
michael@0 8936 //
michael@0 8937 nsCOMPtr<Element> requestingElement;
michael@0 8938 // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
michael@0 8939 if (mScriptGlobal)
michael@0 8940 requestingElement = mScriptGlobal->GetFrameElementInternal();
michael@0 8941
michael@0 8942 nsRefPtr<nsGlobalWindow> MMADeathGrip = mScriptGlobal;
michael@0 8943
michael@0 8944 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
michael@0 8945 uint32_t contentType;
michael@0 8946 bool isNewDocShell = false;
michael@0 8947 bool isTargetTopLevelDocShell = false;
michael@0 8948 nsCOMPtr<nsIDocShell> targetDocShell;
michael@0 8949 if (aWindowTarget && *aWindowTarget) {
michael@0 8950 // Locate the target DocShell.
michael@0 8951 nsCOMPtr<nsIDocShellTreeItem> targetItem;
michael@0 8952 rv = FindItemWithName(aWindowTarget, nullptr, this,
michael@0 8953 getter_AddRefs(targetItem));
michael@0 8954 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8955
michael@0 8956 targetDocShell = do_QueryInterface(targetItem);
michael@0 8957 // If the targetDocShell doesn't exist, then this is a new docShell
michael@0 8958 // and we should consider this a TYPE_DOCUMENT load
michael@0 8959 isNewDocShell = !targetDocShell;
michael@0 8960
michael@0 8961 // If the targetDocShell and the rootDocShell are the same, then the
michael@0 8962 // targetDocShell is the top level document and hence we should
michael@0 8963 // consider this TYPE_DOCUMENT
michael@0 8964 if (targetDocShell) {
michael@0 8965 nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
michael@0 8966 targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
michael@0 8967 NS_ASSERTION(sameTypeRoot, "No document shell root tree item from targetDocShell!");
michael@0 8968 nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
michael@0 8969 NS_ASSERTION(rootShell, "No root docshell from document shell root tree item.");
michael@0 8970
michael@0 8971 if (targetDocShell == rootShell) {
michael@0 8972 isTargetTopLevelDocShell = true;
michael@0 8973 }
michael@0 8974 }
michael@0 8975 }
michael@0 8976 if (IsFrame() && !isNewDocShell && !isTargetTopLevelDocShell) {
michael@0 8977 NS_ASSERTION(requestingElement, "A frame but no DOM element!?");
michael@0 8978 contentType = nsIContentPolicy::TYPE_SUBDOCUMENT;
michael@0 8979 } else {
michael@0 8980 contentType = nsIContentPolicy::TYPE_DOCUMENT;
michael@0 8981 }
michael@0 8982
michael@0 8983 nsISupports* context = requestingElement;
michael@0 8984 if (!context) {
michael@0 8985 context = ToSupports(mScriptGlobal);
michael@0 8986 }
michael@0 8987
michael@0 8988 // XXXbz would be nice to know the loading principal here... but we don't
michael@0 8989 nsCOMPtr<nsIPrincipal> loadingPrincipal = do_QueryInterface(aOwner);
michael@0 8990 if (!loadingPrincipal && aReferrer) {
michael@0 8991 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 8992 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 8993 NS_ENSURE_SUCCESS(rv, rv);
michael@0 8994
michael@0 8995 rv = secMan->GetSimpleCodebasePrincipal(aReferrer,
michael@0 8996 getter_AddRefs(loadingPrincipal));
michael@0 8997 }
michael@0 8998
michael@0 8999 rv = NS_CheckContentLoadPolicy(contentType,
michael@0 9000 aURI,
michael@0 9001 loadingPrincipal,
michael@0 9002 context,
michael@0 9003 EmptyCString(), //mime guess
michael@0 9004 nullptr, //extra
michael@0 9005 &shouldLoad);
michael@0 9006
michael@0 9007 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
michael@0 9008 if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
michael@0 9009 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
michael@0 9010 }
michael@0 9011
michael@0 9012 return NS_ERROR_CONTENT_BLOCKED;
michael@0 9013 }
michael@0 9014
michael@0 9015 nsCOMPtr<nsISupports> owner(aOwner);
michael@0 9016 //
michael@0 9017 // Get an owner from the current document if necessary. Note that we only
michael@0 9018 // do this for URIs that inherit a security context and local file URIs;
michael@0 9019 // in particular we do NOT do this for about:blank. This way, random
michael@0 9020 // about:blank loads that have no owner (which basically means they were
michael@0 9021 // done by someone from chrome manually messing with our nsIWebNavigation
michael@0 9022 // or by C++ setting document.location) don't get a funky principal. If
michael@0 9023 // callers want something interesting to happen with the about:blank
michael@0 9024 // principal in this case, they should pass an owner in.
michael@0 9025 //
michael@0 9026 {
michael@0 9027 bool inherits;
michael@0 9028 // One more twist: Don't inherit the owner for external loads.
michael@0 9029 if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
michael@0 9030 (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) &&
michael@0 9031 NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
michael@0 9032 &inherits)) &&
michael@0 9033 inherits) {
michael@0 9034
michael@0 9035 owner = GetInheritedPrincipal(true);
michael@0 9036 }
michael@0 9037 }
michael@0 9038
michael@0 9039 // Don't allow loads that would inherit our security context
michael@0 9040 // if this document came from an unsafe channel.
michael@0 9041 {
michael@0 9042 bool willInherit;
michael@0 9043 // This condition needs to match the one in
michael@0 9044 // nsContentUtils::SetUpChannelOwner.
michael@0 9045 // Except we reverse the rv check to be safe in case
michael@0 9046 // nsContentUtils::URIInheritsSecurityContext fails here and
michael@0 9047 // succeeds there.
michael@0 9048 rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
michael@0 9049 if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
michael@0 9050 nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
michael@0 9051 do {
michael@0 9052 nsCOMPtr<nsIDocShell> itemDocShell =
michael@0 9053 do_QueryInterface(treeItem);
michael@0 9054 bool isUnsafe;
michael@0 9055 if (itemDocShell &&
michael@0 9056 NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
michael@0 9057 isUnsafe) {
michael@0 9058 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 9059 }
michael@0 9060
michael@0 9061 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 9062 treeItem->GetSameTypeParent(getter_AddRefs(parent));
michael@0 9063 parent.swap(treeItem);
michael@0 9064 } while (treeItem);
michael@0 9065 }
michael@0 9066 }
michael@0 9067
michael@0 9068 //
michael@0 9069 // Resolve the window target before going any further...
michael@0 9070 // If the load has been targeted to another DocShell, then transfer the
michael@0 9071 // load to it...
michael@0 9072 //
michael@0 9073 if (aWindowTarget && *aWindowTarget) {
michael@0 9074 // We've already done our owner-inheriting. Mask out that bit, so we
michael@0 9075 // don't try inheriting an owner from the target window if we came up
michael@0 9076 // with a null owner above.
michael@0 9077 aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
michael@0 9078
michael@0 9079 bool isNewWindow = false;
michael@0 9080 if (!targetDocShell) {
michael@0 9081 // If the docshell's document is sandboxed, only open a new window
michael@0 9082 // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
michael@0 9083 // (i.e. if allow-popups is specified)
michael@0 9084 NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
michael@0 9085 nsIDocument* doc = mContentViewer->GetDocument();
michael@0 9086 uint32_t sandboxFlags = 0;
michael@0 9087
michael@0 9088 if (doc) {
michael@0 9089 sandboxFlags = doc->GetSandboxFlags();
michael@0 9090 if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
michael@0 9091 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
michael@0 9092 }
michael@0 9093 }
michael@0 9094
michael@0 9095 nsCOMPtr<nsPIDOMWindow> win =
michael@0 9096 do_GetInterface(GetAsSupports(this));
michael@0 9097 NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
michael@0 9098
michael@0 9099 nsDependentString name(aWindowTarget);
michael@0 9100 nsCOMPtr<nsIDOMWindow> newWin;
michael@0 9101 nsAutoCString spec;
michael@0 9102 if (aURI)
michael@0 9103 aURI->GetSpec(spec);
michael@0 9104 rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
michael@0 9105 name, // window name
michael@0 9106 EmptyString(), // Features
michael@0 9107 getter_AddRefs(newWin));
michael@0 9108
michael@0 9109 // In some cases the Open call doesn't actually result in a new
michael@0 9110 // window being opened. We can detect these cases by examining the
michael@0 9111 // document in |newWin|, if any.
michael@0 9112 nsCOMPtr<nsPIDOMWindow> piNewWin = do_QueryInterface(newWin);
michael@0 9113 if (piNewWin) {
michael@0 9114 nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
michael@0 9115 if (!newDoc || newDoc->IsInitialDocument()) {
michael@0 9116 isNewWindow = true;
michael@0 9117 aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
michael@0 9118 }
michael@0 9119 }
michael@0 9120
michael@0 9121 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
michael@0 9122 targetDocShell = do_QueryInterface(webNav);
michael@0 9123 }
michael@0 9124
michael@0 9125 //
michael@0 9126 // Transfer the load to the target DocShell... Pass nullptr as the
michael@0 9127 // window target name from to prevent recursive retargeting!
michael@0 9128 //
michael@0 9129 if (NS_SUCCEEDED(rv) && targetDocShell) {
michael@0 9130 rv = targetDocShell->InternalLoad(aURI,
michael@0 9131 aReferrer,
michael@0 9132 owner,
michael@0 9133 aFlags,
michael@0 9134 nullptr, // No window target
michael@0 9135 aTypeHint,
michael@0 9136 NullString(), // No forced download
michael@0 9137 aPostData,
michael@0 9138 aHeadersData,
michael@0 9139 aLoadType,
michael@0 9140 aSHEntry,
michael@0 9141 aFirstParty,
michael@0 9142 aSrcdoc,
michael@0 9143 aSourceDocShell,
michael@0 9144 aBaseURI,
michael@0 9145 aDocShell,
michael@0 9146 aRequest);
michael@0 9147 if (rv == NS_ERROR_NO_CONTENT) {
michael@0 9148 // XXXbz except we never reach this code!
michael@0 9149 if (isNewWindow) {
michael@0 9150 //
michael@0 9151 // At this point, a new window has been created, but the
michael@0 9152 // URI did not have any data associated with it...
michael@0 9153 //
michael@0 9154 // So, the best we can do, is to tear down the new window
michael@0 9155 // that was just created!
michael@0 9156 //
michael@0 9157 nsCOMPtr<nsIDOMWindow> domWin =
michael@0 9158 do_GetInterface(targetDocShell);
michael@0 9159 if (domWin) {
michael@0 9160 domWin->Close();
michael@0 9161 }
michael@0 9162 }
michael@0 9163 //
michael@0 9164 // NS_ERROR_NO_CONTENT should not be returned to the
michael@0 9165 // caller... This is an internal error code indicating that
michael@0 9166 // the URI had no data associated with it - probably a
michael@0 9167 // helper-app style protocol (ie. mailto://)
michael@0 9168 //
michael@0 9169 rv = NS_OK;
michael@0 9170 }
michael@0 9171 else if (isNewWindow) {
michael@0 9172 // XXX: Once new windows are created hidden, the new
michael@0 9173 // window will need to be made visible... For now,
michael@0 9174 // do nothing.
michael@0 9175 }
michael@0 9176 }
michael@0 9177
michael@0 9178 // Else we ran out of memory, or were a popup and got blocked,
michael@0 9179 // or something.
michael@0 9180
michael@0 9181 return rv;
michael@0 9182 }
michael@0 9183
michael@0 9184 //
michael@0 9185 // Load is being targetted at this docshell so return an error if the
michael@0 9186 // docshell is in the process of being destroyed.
michael@0 9187 //
michael@0 9188 if (mIsBeingDestroyed) {
michael@0 9189 return NS_ERROR_FAILURE;
michael@0 9190 }
michael@0 9191
michael@0 9192 NS_ENSURE_STATE(!HasUnloadedParent());
michael@0 9193
michael@0 9194 rv = CheckLoadingPermissions();
michael@0 9195 if (NS_FAILED(rv)) {
michael@0 9196 return rv;
michael@0 9197 }
michael@0 9198
michael@0 9199 if (mFiredUnloadEvent) {
michael@0 9200 if (IsOKToLoadURI(aURI)) {
michael@0 9201 NS_PRECONDITION(!aWindowTarget || !*aWindowTarget,
michael@0 9202 "Shouldn't have a window target here!");
michael@0 9203
michael@0 9204 // If this is a replace load, make whatever load triggered
michael@0 9205 // the unload event also a replace load, so we don't
michael@0 9206 // create extra history entries.
michael@0 9207 if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
michael@0 9208 mLoadType = LOAD_NORMAL_REPLACE;
michael@0 9209 }
michael@0 9210
michael@0 9211 // Do this asynchronously
michael@0 9212 nsCOMPtr<nsIRunnable> ev =
michael@0 9213 new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
michael@0 9214 aTypeHint, aPostData, aHeadersData,
michael@0 9215 aLoadType, aSHEntry, aFirstParty, aSrcdoc,
michael@0 9216 aSourceDocShell, aBaseURI);
michael@0 9217 return NS_DispatchToCurrentThread(ev);
michael@0 9218 }
michael@0 9219
michael@0 9220 // Just ignore this load attempt
michael@0 9221 return NS_OK;
michael@0 9222 }
michael@0 9223
michael@0 9224 // If a source docshell has been passed, check to see if we are sandboxed
michael@0 9225 // from it as the result of an iframe or CSP sandbox.
michael@0 9226 if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
michael@0 9227 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
michael@0 9228 }
michael@0 9229
michael@0 9230 // If this docshell is owned by a frameloader, make sure to cancel
michael@0 9231 // possible frameloader initialization before loading a new page.
michael@0 9232 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 9233 GetParent(getter_AddRefs(parent));
michael@0 9234 if (parent) {
michael@0 9235 nsCOMPtr<nsIDocument> doc = do_GetInterface(parent);
michael@0 9236 if (doc) {
michael@0 9237 doc->TryCancelFrameLoaderInitialization(this);
michael@0 9238 }
michael@0 9239 }
michael@0 9240
michael@0 9241 // Before going any further vet loads initiated by external programs.
michael@0 9242 if (aLoadType == LOAD_NORMAL_EXTERNAL) {
michael@0 9243 // Disallow external chrome: loads targetted at content windows
michael@0 9244 bool isChrome = false;
michael@0 9245 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
michael@0 9246 NS_WARNING("blocked external chrome: url -- use '-chrome' option");
michael@0 9247 return NS_ERROR_FAILURE;
michael@0 9248 }
michael@0 9249
michael@0 9250 // clear the decks to prevent context bleed-through (bug 298255)
michael@0 9251 rv = CreateAboutBlankContentViewer(nullptr, nullptr);
michael@0 9252 if (NS_FAILED(rv))
michael@0 9253 return NS_ERROR_FAILURE;
michael@0 9254
michael@0 9255 // reset loadType so we don't have to add lots of tests for
michael@0 9256 // LOAD_NORMAL_EXTERNAL after this point
michael@0 9257 aLoadType = LOAD_NORMAL;
michael@0 9258 }
michael@0 9259
michael@0 9260 mAllowKeywordFixup =
michael@0 9261 (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
michael@0 9262 mURIResultedInDocument = false; // reset the clock...
michael@0 9263
michael@0 9264 if (aLoadType == LOAD_NORMAL ||
michael@0 9265 aLoadType == LOAD_STOP_CONTENT ||
michael@0 9266 LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
michael@0 9267 aLoadType == LOAD_HISTORY ||
michael@0 9268 aLoadType == LOAD_LINK) {
michael@0 9269
michael@0 9270 nsCOMPtr<nsIURI> currentURI = mCurrentURI;
michael@0 9271 // Split currentURI and aURI on the '#' character. Make sure we read
michael@0 9272 // the return values of SplitURIAtHash; if it fails, we don't want to
michael@0 9273 // allow a short-circuited navigation.
michael@0 9274 nsAutoCString curBeforeHash, curHash, newBeforeHash, newHash;
michael@0 9275 nsresult splitRv1, splitRv2;
michael@0 9276 splitRv1 = currentURI ?
michael@0 9277 nsContentUtils::SplitURIAtHash(currentURI,
michael@0 9278 curBeforeHash, curHash) :
michael@0 9279 NS_ERROR_FAILURE;
michael@0 9280 splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash);
michael@0 9281
michael@0 9282 bool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
michael@0 9283 NS_SUCCEEDED(splitRv2) &&
michael@0 9284 curBeforeHash.Equals(newBeforeHash);
michael@0 9285
michael@0 9286 if (!sameExceptHashes && sURIFixup && currentURI &&
michael@0 9287 NS_SUCCEEDED(splitRv2)) {
michael@0 9288 // Maybe aURI came from the exposable form of currentURI?
michael@0 9289 nsCOMPtr<nsIURI> currentExposableURI;
michael@0 9290 rv = sURIFixup->CreateExposableURI(currentURI,
michael@0 9291 getter_AddRefs(currentExposableURI));
michael@0 9292 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9293 splitRv1 = nsContentUtils::SplitURIAtHash(currentExposableURI,
michael@0 9294 curBeforeHash, curHash);
michael@0 9295 sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
michael@0 9296 curBeforeHash.Equals(newBeforeHash);
michael@0 9297 }
michael@0 9298
michael@0 9299 bool historyNavBetweenSameDoc = false;
michael@0 9300 if (mOSHE && aSHEntry) {
michael@0 9301 // We're doing a history load.
michael@0 9302
michael@0 9303 mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
michael@0 9304
michael@0 9305 #ifdef DEBUG
michael@0 9306 if (historyNavBetweenSameDoc) {
michael@0 9307 nsCOMPtr<nsIInputStream> currentPostData;
michael@0 9308 mOSHE->GetPostData(getter_AddRefs(currentPostData));
michael@0 9309 NS_ASSERTION(currentPostData == aPostData,
michael@0 9310 "Different POST data for entries for the same page?");
michael@0 9311 }
michael@0 9312 #endif
michael@0 9313 }
michael@0 9314
michael@0 9315 // A short-circuited load happens when we navigate between two SHEntries
michael@0 9316 // for the same document. We do a short-circuited load under two
michael@0 9317 // circumstances. Either
michael@0 9318 //
michael@0 9319 // a) we're navigating between two different SHEntries which share a
michael@0 9320 // document, or
michael@0 9321 //
michael@0 9322 // b) we're navigating to a new shentry whose URI differs from the
michael@0 9323 // current URI only in its hash, the new hash is non-empty, and
michael@0 9324 // we're not doing a POST.
michael@0 9325 //
michael@0 9326 // The restriction tha the SHEntries in (a) must be different ensures
michael@0 9327 // that history.go(0) and the like trigger full refreshes, rather than
michael@0 9328 // short-circuited loads.
michael@0 9329 bool doShortCircuitedLoad =
michael@0 9330 (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
michael@0 9331 (!aSHEntry && aPostData == nullptr &&
michael@0 9332 sameExceptHashes && !newHash.IsEmpty());
michael@0 9333
michael@0 9334 if (doShortCircuitedLoad) {
michael@0 9335 // Save the position of the scrollers.
michael@0 9336 nscoord cx = 0, cy = 0;
michael@0 9337 GetCurScrollPos(ScrollOrientation_X, &cx);
michael@0 9338 GetCurScrollPos(ScrollOrientation_Y, &cy);
michael@0 9339
michael@0 9340 // ScrollToAnchor doesn't necessarily cause us to scroll the window;
michael@0 9341 // the function decides whether a scroll is appropriate based on the
michael@0 9342 // arguments it receives. But even if we don't end up scrolling,
michael@0 9343 // ScrollToAnchor performs other important tasks, such as informing
michael@0 9344 // the presShell that we have a new hash. See bug 680257.
michael@0 9345 rv = ScrollToAnchor(curHash, newHash, aLoadType);
michael@0 9346 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9347
michael@0 9348 // Reset mLoadType to its original value once we exit this block,
michael@0 9349 // because this short-circuited load might have started after a
michael@0 9350 // normal, network load, and we don't want to clobber its load type.
michael@0 9351 // See bug 737307.
michael@0 9352 AutoRestore<uint32_t> loadTypeResetter(mLoadType);
michael@0 9353
michael@0 9354 // If a non-short-circuit load (i.e., a network load) is pending,
michael@0 9355 // make this a replacement load, so that we don't add a SHEntry here
michael@0 9356 // and the network load goes into the SHEntry it expects to.
michael@0 9357 if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
michael@0 9358 mLoadType = LOAD_NORMAL_REPLACE;
michael@0 9359 }
michael@0 9360 else {
michael@0 9361 mLoadType = aLoadType;
michael@0 9362 }
michael@0 9363
michael@0 9364 mURIResultedInDocument = true;
michael@0 9365
michael@0 9366 nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
michael@0 9367
michael@0 9368 /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
michael@0 9369 * SetCurrentURI() called from OnNewURI() will send proper
michael@0 9370 * onLocationChange() notifications to the browser to update
michael@0 9371 * back/forward buttons.
michael@0 9372 */
michael@0 9373 SetHistoryEntry(&mLSHE, aSHEntry);
michael@0 9374
michael@0 9375 /* This is a anchor traversal with in the same page.
michael@0 9376 * call OnNewURI() so that, this traversal will be
michael@0 9377 * recorded in session and global history.
michael@0 9378 */
michael@0 9379 nsCOMPtr<nsISupports> owner;
michael@0 9380 if (mOSHE) {
michael@0 9381 mOSHE->GetOwner(getter_AddRefs(owner));
michael@0 9382 }
michael@0 9383 // Pass true for aCloneSHChildren, since we're not
michael@0 9384 // changing documents here, so all of our subframes are
michael@0 9385 // still relevant to the new session history entry.
michael@0 9386 //
michael@0 9387 // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
michael@0 9388 // flag on firing onLocationChange(...).
michael@0 9389 // Anyway, aCloneSHChildren param is simply reflecting
michael@0 9390 // doShortCircuitedLoad in this scope.
michael@0 9391 OnNewURI(aURI, nullptr, owner, mLoadType, true, true, true);
michael@0 9392
michael@0 9393 nsCOMPtr<nsIInputStream> postData;
michael@0 9394 nsCOMPtr<nsISupports> cacheKey;
michael@0 9395
michael@0 9396 if (mOSHE) {
michael@0 9397 /* save current position of scroller(s) (bug 59774) */
michael@0 9398 mOSHE->SetScrollPosition(cx, cy);
michael@0 9399 // Get the postdata and page ident from the current page, if
michael@0 9400 // the new load is being done via normal means. Note that
michael@0 9401 // "normal means" can be checked for just by checking for
michael@0 9402 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
michael@0 9403 // above -- it filters out some LOAD_CMD_NORMAL cases that we
michael@0 9404 // wouldn't want here.
michael@0 9405 if (aLoadType & LOAD_CMD_NORMAL) {
michael@0 9406 mOSHE->GetPostData(getter_AddRefs(postData));
michael@0 9407 mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
michael@0 9408
michael@0 9409 // Link our new SHEntry to the old SHEntry's back/forward
michael@0 9410 // cache data, since the two SHEntries correspond to the
michael@0 9411 // same document.
michael@0 9412 if (mLSHE)
michael@0 9413 mLSHE->AdoptBFCacheEntry(mOSHE);
michael@0 9414 }
michael@0 9415 }
michael@0 9416
michael@0 9417 /* Assign mOSHE to mLSHE. This will either be a new entry created
michael@0 9418 * by OnNewURI() for normal loads or aSHEntry for history loads.
michael@0 9419 */
michael@0 9420 if (mLSHE) {
michael@0 9421 SetHistoryEntry(&mOSHE, mLSHE);
michael@0 9422 // Save the postData obtained from the previous page
michael@0 9423 // in to the session history entry created for the
michael@0 9424 // anchor page, so that any history load of the anchor
michael@0 9425 // page will restore the appropriate postData.
michael@0 9426 if (postData)
michael@0 9427 mOSHE->SetPostData(postData);
michael@0 9428
michael@0 9429 // Make sure we won't just repost without hitting the
michael@0 9430 // cache first
michael@0 9431 if (cacheKey)
michael@0 9432 mOSHE->SetCacheKey(cacheKey);
michael@0 9433 }
michael@0 9434
michael@0 9435 /* restore previous position of scroller(s), if we're moving
michael@0 9436 * back in history (bug 59774)
michael@0 9437 */
michael@0 9438 if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL))
michael@0 9439 {
michael@0 9440 nscoord bx, by;
michael@0 9441 mOSHE->GetScrollPosition(&bx, &by);
michael@0 9442 SetCurScrollPosEx(bx, by);
michael@0 9443 }
michael@0 9444
michael@0 9445 /* Restore the original LSHE if we were loading something
michael@0 9446 * while short-circuited load was initiated.
michael@0 9447 */
michael@0 9448 SetHistoryEntry(&mLSHE, oldLSHE);
michael@0 9449 /* Set the title for the SH entry for this target url. so that
michael@0 9450 * SH menus in go/back/forward buttons won't be empty for this.
michael@0 9451 */
michael@0 9452 if (mSessionHistory) {
michael@0 9453 int32_t index = -1;
michael@0 9454 mSessionHistory->GetIndex(&index);
michael@0 9455 nsCOMPtr<nsISHEntry> shEntry;
michael@0 9456 mSessionHistory->GetEntryAtIndex(index, false,
michael@0 9457 getter_AddRefs(shEntry));
michael@0 9458 NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
michael@0 9459 shEntry->SetTitle(mTitle);
michael@0 9460 }
michael@0 9461
michael@0 9462 /* Set the title for the Global History entry for this anchor url.
michael@0 9463 */
michael@0 9464 if (mUseGlobalHistory && !mInPrivateBrowsing) {
michael@0 9465 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 9466 if (history) {
michael@0 9467 history->SetURITitle(aURI, mTitle);
michael@0 9468 }
michael@0 9469 else if (mGlobalHistory) {
michael@0 9470 mGlobalHistory->SetPageTitle(aURI, mTitle);
michael@0 9471 }
michael@0 9472 }
michael@0 9473
michael@0 9474 // Set the doc's URI according to the new history entry's URI.
michael@0 9475 nsCOMPtr<nsIDocument> doc =
michael@0 9476 do_GetInterface(GetAsSupports(this));
michael@0 9477 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
michael@0 9478 doc->SetDocumentURI(aURI);
michael@0 9479
michael@0 9480 SetDocCurrentStateObj(mOSHE);
michael@0 9481
michael@0 9482 // Dispatch the popstate and hashchange events, as appropriate.
michael@0 9483 //
michael@0 9484 // The event dispatch below can cause us to re-enter script and
michael@0 9485 // destroy the docshell, nulling out mScriptGlobal. Hold a stack
michael@0 9486 // reference to avoid null derefs. See bug 914521.
michael@0 9487 nsRefPtr<nsGlobalWindow> win = mScriptGlobal;
michael@0 9488 if (win) {
michael@0 9489 // Fire a hashchange event URIs differ, and only in their hashes.
michael@0 9490 bool doHashchange = sameExceptHashes && !curHash.Equals(newHash);
michael@0 9491
michael@0 9492 if (historyNavBetweenSameDoc || doHashchange) {
michael@0 9493 win->DispatchSyncPopState();
michael@0 9494 }
michael@0 9495
michael@0 9496 if (doHashchange) {
michael@0 9497 // Note that currentURI hasn't changed because it's on the
michael@0 9498 // stack, so we can just use it directly as the old URI.
michael@0 9499 win->DispatchAsyncHashchange(currentURI, aURI);
michael@0 9500 }
michael@0 9501 }
michael@0 9502
michael@0 9503 // Inform the favicon service that the favicon for oldURI also
michael@0 9504 // applies to aURI.
michael@0 9505 CopyFavicon(currentURI, aURI, mInPrivateBrowsing);
michael@0 9506
michael@0 9507 return NS_OK;
michael@0 9508 }
michael@0 9509 }
michael@0 9510
michael@0 9511 // mContentViewer->PermitUnload can destroy |this| docShell, which
michael@0 9512 // causes the next call of CanSavePresentation to crash.
michael@0 9513 // Hold onto |this| until we return, to prevent a crash from happening.
michael@0 9514 // (bug#331040)
michael@0 9515 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
michael@0 9516
michael@0 9517 // Don't init timing for javascript:, since it generally doesn't
michael@0 9518 // actually start a load or anything. If it does, we'll init
michael@0 9519 // timing then, from OnStateChange.
michael@0 9520
michael@0 9521 // XXXbz mTiming should know what channel it's for, so we don't
michael@0 9522 // need this hackery. Note that this is still broken in cases
michael@0 9523 // when we're loading something that's not javascript: and the
michael@0 9524 // beforeunload handler denies the load. That will screw up
michael@0 9525 // timing for the next load!
michael@0 9526 if (!bIsJavascript) {
michael@0 9527 MaybeInitTiming();
michael@0 9528 }
michael@0 9529 bool timeBeforeUnload = aFileName.IsVoid();
michael@0 9530 if (mTiming && timeBeforeUnload) {
michael@0 9531 mTiming->NotifyBeforeUnload();
michael@0 9532 }
michael@0 9533 // Check if the page doesn't want to be unloaded. The javascript:
michael@0 9534 // protocol handler deals with this for javascript: URLs.
michael@0 9535 if (!bIsJavascript && aFileName.IsVoid() && mContentViewer) {
michael@0 9536 bool okToUnload;
michael@0 9537 rv = mContentViewer->PermitUnload(false, &okToUnload);
michael@0 9538
michael@0 9539 if (NS_SUCCEEDED(rv) && !okToUnload) {
michael@0 9540 // The user chose not to unload the page, interrupt the
michael@0 9541 // load.
michael@0 9542 return NS_OK;
michael@0 9543 }
michael@0 9544 }
michael@0 9545
michael@0 9546 if (mTiming && timeBeforeUnload) {
michael@0 9547 mTiming->NotifyUnloadAccepted(mCurrentURI);
michael@0 9548 }
michael@0 9549
michael@0 9550 // Check for saving the presentation here, before calling Stop().
michael@0 9551 // This is necessary so that we can catch any pending requests.
michael@0 9552 // Since the new request has not been created yet, we pass null for the
michael@0 9553 // new request parameter.
michael@0 9554 // Also pass nullptr for the document, since it doesn't affect the return
michael@0 9555 // value for our purposes here.
michael@0 9556 bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
michael@0 9557
michael@0 9558 // Don't stop current network activity for javascript: URL's since
michael@0 9559 // they might not result in any data, and thus nothing should be
michael@0 9560 // stopped in those cases. In the case where they do result in
michael@0 9561 // data, the javascript: URL channel takes care of stopping
michael@0 9562 // current network activity.
michael@0 9563 if (!bIsJavascript && aFileName.IsVoid()) {
michael@0 9564 // Stop any current network activity.
michael@0 9565 // Also stop content if this is a zombie doc. otherwise
michael@0 9566 // the onload will be delayed by other loads initiated in the
michael@0 9567 // background by the first document that
michael@0 9568 // didn't fully load before the next load was initiated.
michael@0 9569 // If not a zombie, don't stop content until data
michael@0 9570 // starts arriving from the new URI...
michael@0 9571
michael@0 9572 nsCOMPtr<nsIContentViewer> zombieViewer;
michael@0 9573 if (mContentViewer) {
michael@0 9574 mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
michael@0 9575 }
michael@0 9576
michael@0 9577 if (zombieViewer ||
michael@0 9578 LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
michael@0 9579 rv = Stop(nsIWebNavigation::STOP_ALL);
michael@0 9580 } else {
michael@0 9581 rv = Stop(nsIWebNavigation::STOP_NETWORK);
michael@0 9582 }
michael@0 9583
michael@0 9584 if (NS_FAILED(rv))
michael@0 9585 return rv;
michael@0 9586 }
michael@0 9587
michael@0 9588 mLoadType = aLoadType;
michael@0 9589
michael@0 9590 // mLSHE should be assigned to aSHEntry, only after Stop() has
michael@0 9591 // been called. But when loading an error page, do not clear the
michael@0 9592 // mLSHE for the real page.
michael@0 9593 if (mLoadType != LOAD_ERROR_PAGE)
michael@0 9594 SetHistoryEntry(&mLSHE, aSHEntry);
michael@0 9595
michael@0 9596 mSavingOldViewer = savePresentation;
michael@0 9597
michael@0 9598 // If we have a saved content viewer in history, restore and show it now.
michael@0 9599 if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
michael@0 9600 // Make sure our history ID points to the same ID as
michael@0 9601 // SHEntry's docshell ID.
michael@0 9602 aSHEntry->GetDocshellID(&mHistoryID);
michael@0 9603
michael@0 9604 // It's possible that the previous viewer of mContentViewer is the
michael@0 9605 // viewer that will end up in aSHEntry when it gets closed. If that's
michael@0 9606 // the case, we need to go ahead and force it into its shentry so we
michael@0 9607 // can restore it.
michael@0 9608 if (mContentViewer) {
michael@0 9609 nsCOMPtr<nsIContentViewer> prevViewer;
michael@0 9610 mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
michael@0 9611 if (prevViewer) {
michael@0 9612 #ifdef DEBUG
michael@0 9613 nsCOMPtr<nsIContentViewer> prevPrevViewer;
michael@0 9614 prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
michael@0 9615 NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
michael@0 9616 #endif
michael@0 9617 nsCOMPtr<nsISHEntry> viewerEntry;
michael@0 9618 prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
michael@0 9619 if (viewerEntry == aSHEntry) {
michael@0 9620 // Make sure this viewer ends up in the right place
michael@0 9621 mContentViewer->SetPreviousViewer(nullptr);
michael@0 9622 prevViewer->Destroy();
michael@0 9623 }
michael@0 9624 }
michael@0 9625 }
michael@0 9626 nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
michael@0 9627 bool restoring;
michael@0 9628 rv = RestorePresentation(aSHEntry, &restoring);
michael@0 9629 if (restoring)
michael@0 9630 return rv;
michael@0 9631
michael@0 9632 // We failed to restore the presentation, so clean up.
michael@0 9633 // Both the old and new history entries could potentially be in
michael@0 9634 // an inconsistent state.
michael@0 9635 if (NS_FAILED(rv)) {
michael@0 9636 if (oldEntry)
michael@0 9637 oldEntry->SyncPresentationState();
michael@0 9638
michael@0 9639 aSHEntry->SyncPresentationState();
michael@0 9640 }
michael@0 9641 }
michael@0 9642
michael@0 9643 nsAutoString srcdoc;
michael@0 9644 if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC)
michael@0 9645 srcdoc = aSrcdoc;
michael@0 9646 else
michael@0 9647 srcdoc = NullString();
michael@0 9648
michael@0 9649 mozilla::net::SeerPredict(aURI, nullptr, nsINetworkSeer::PREDICT_LOAD,
michael@0 9650 this, nullptr);
michael@0 9651
michael@0 9652 nsCOMPtr<nsIRequest> req;
michael@0 9653 rv = DoURILoad(aURI, aReferrer,
michael@0 9654 !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
michael@0 9655 owner, aTypeHint, aFileName, aPostData, aHeadersData,
michael@0 9656 aFirstParty, aDocShell, getter_AddRefs(req),
michael@0 9657 (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
michael@0 9658 (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
michael@0 9659 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
michael@0 9660 srcdoc, aBaseURI);
michael@0 9661 if (req && aRequest)
michael@0 9662 NS_ADDREF(*aRequest = req);
michael@0 9663
michael@0 9664 if (NS_FAILED(rv)) {
michael@0 9665 nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
michael@0 9666 DisplayLoadError(rv, aURI, nullptr, chan);
michael@0 9667 }
michael@0 9668
michael@0 9669 return rv;
michael@0 9670 }
michael@0 9671
michael@0 9672 nsIPrincipal*
michael@0 9673 nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
michael@0 9674 {
michael@0 9675 nsCOMPtr<nsIDocument> document;
michael@0 9676 bool inheritedFromCurrent = false;
michael@0 9677
michael@0 9678 if (aConsiderCurrentDocument && mContentViewer) {
michael@0 9679 document = mContentViewer->GetDocument();
michael@0 9680 inheritedFromCurrent = true;
michael@0 9681 }
michael@0 9682
michael@0 9683 if (!document) {
michael@0 9684 nsCOMPtr<nsIDocShellTreeItem> parentItem;
michael@0 9685 GetSameTypeParent(getter_AddRefs(parentItem));
michael@0 9686 if (parentItem) {
michael@0 9687 document = do_GetInterface(parentItem);
michael@0 9688 }
michael@0 9689 }
michael@0 9690
michael@0 9691 if (!document) {
michael@0 9692 if (!aConsiderCurrentDocument) {
michael@0 9693 return nullptr;
michael@0 9694 }
michael@0 9695
michael@0 9696 // Make sure we end up with _something_ as the principal no matter
michael@0 9697 // what.
michael@0 9698 EnsureContentViewer(); // If this fails, we'll just get a null
michael@0 9699 // docViewer and bail.
michael@0 9700
michael@0 9701 if (!mContentViewer)
michael@0 9702 return nullptr;
michael@0 9703 document = mContentViewer->GetDocument();
michael@0 9704 }
michael@0 9705
michael@0 9706 //-- Get the document's principal
michael@0 9707 if (document) {
michael@0 9708 nsIPrincipal *docPrincipal = document->NodePrincipal();
michael@0 9709
michael@0 9710 // Don't allow loads in typeContent docShells to inherit the system
michael@0 9711 // principal from existing documents.
michael@0 9712 if (inheritedFromCurrent &&
michael@0 9713 mItemType == typeContent &&
michael@0 9714 nsContentUtils::IsSystemPrincipal(docPrincipal)) {
michael@0 9715 return nullptr;
michael@0 9716 }
michael@0 9717
michael@0 9718 return docPrincipal;
michael@0 9719 }
michael@0 9720
michael@0 9721 return nullptr;
michael@0 9722 }
michael@0 9723
michael@0 9724 nsresult
michael@0 9725 nsDocShell::DoURILoad(nsIURI * aURI,
michael@0 9726 nsIURI * aReferrerURI,
michael@0 9727 bool aSendReferrer,
michael@0 9728 nsISupports * aOwner,
michael@0 9729 const char * aTypeHint,
michael@0 9730 const nsAString & aFileName,
michael@0 9731 nsIInputStream * aPostData,
michael@0 9732 nsIInputStream * aHeadersData,
michael@0 9733 bool aFirstParty,
michael@0 9734 nsIDocShell ** aDocShell,
michael@0 9735 nsIRequest ** aRequest,
michael@0 9736 bool aIsNewWindowTarget,
michael@0 9737 bool aBypassClassifier,
michael@0 9738 bool aForceAllowCookies,
michael@0 9739 const nsAString &aSrcdoc,
michael@0 9740 nsIURI * aBaseURI)
michael@0 9741 {
michael@0 9742 #ifdef MOZ_VISUAL_EVENT_TRACER
michael@0 9743 nsAutoCString urlSpec;
michael@0 9744 aURI->GetAsciiSpec(urlSpec);
michael@0 9745 MOZ_EVENT_TRACER_NAME_OBJECT(this, urlSpec.BeginReading());
michael@0 9746 MOZ_EVENT_TRACER_EXEC(this, "docshell::pageload");
michael@0 9747 #endif
michael@0 9748
michael@0 9749 nsresult rv;
michael@0 9750 nsCOMPtr<nsIURILoader> uriLoader;
michael@0 9751
michael@0 9752 uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
michael@0 9753 if (NS_FAILED(rv)) return rv;
michael@0 9754
michael@0 9755 nsLoadFlags loadFlags = mDefaultLoadFlags;
michael@0 9756 if (aFirstParty) {
michael@0 9757 // tag first party URL loads
michael@0 9758 loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
michael@0 9759 }
michael@0 9760
michael@0 9761 if (mLoadType == LOAD_ERROR_PAGE) {
michael@0 9762 // Error pages are LOAD_BACKGROUND
michael@0 9763 loadFlags |= nsIChannel::LOAD_BACKGROUND;
michael@0 9764 }
michael@0 9765
michael@0 9766 // check for Content Security Policy to pass along with the
michael@0 9767 // new channel we are creating
michael@0 9768 nsCOMPtr<nsIChannelPolicy> channelPolicy;
michael@0 9769 if (IsFrame()) {
michael@0 9770 // check the parent docshell for a CSP
michael@0 9771 nsCOMPtr<nsIContentSecurityPolicy> csp;
michael@0 9772 nsCOMPtr<nsIDocShellTreeItem> parentItem;
michael@0 9773 GetSameTypeParent(getter_AddRefs(parentItem));
michael@0 9774 nsCOMPtr<nsIDocument> doc = do_GetInterface(parentItem);
michael@0 9775 if (doc) {
michael@0 9776 rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
michael@0 9777 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9778 if (csp) {
michael@0 9779 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
michael@0 9780 channelPolicy->SetContentSecurityPolicy(csp);
michael@0 9781 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
michael@0 9782 }
michael@0 9783 }
michael@0 9784
michael@0 9785 // Only allow view-source scheme in top-level docshells. view-source is
michael@0 9786 // the only scheme to which this applies at the moment due to potential
michael@0 9787 // timing attacks to read data from cross-origin iframes. If this widens
michael@0 9788 // we should add a protocol flag for whether the scheme is allowed in
michael@0 9789 // frames and use something like nsNetUtil::NS_URIChainHasFlags.
michael@0 9790 nsCOMPtr<nsIURI> tempURI = aURI;
michael@0 9791 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
michael@0 9792 while (nestedURI) {
michael@0 9793 // view-source should always be an nsINestedURI, loop and check the
michael@0 9794 // scheme on this and all inner URIs that are also nested URIs.
michael@0 9795 bool isViewSource = false;
michael@0 9796 rv = tempURI->SchemeIs("view-source", &isViewSource);
michael@0 9797 if (NS_FAILED(rv) || isViewSource) {
michael@0 9798 return NS_ERROR_UNKNOWN_PROTOCOL;
michael@0 9799 }
michael@0 9800 nestedURI->GetInnerURI(getter_AddRefs(tempURI));
michael@0 9801 nestedURI = do_QueryInterface(tempURI);
michael@0 9802 }
michael@0 9803 }
michael@0 9804
michael@0 9805 // open a channel for the url
michael@0 9806 nsCOMPtr<nsIChannel> channel;
michael@0 9807
michael@0 9808 bool isSrcdoc = !aSrcdoc.IsVoid();
michael@0 9809 if (!isSrcdoc) {
michael@0 9810 rv = NS_NewChannel(getter_AddRefs(channel),
michael@0 9811 aURI,
michael@0 9812 nullptr,
michael@0 9813 nullptr,
michael@0 9814 static_cast<nsIInterfaceRequestor *>(this),
michael@0 9815 loadFlags,
michael@0 9816 channelPolicy);
michael@0 9817 if (NS_FAILED(rv)) {
michael@0 9818 if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
michael@0 9819 // This is a uri with a protocol scheme we don't know how
michael@0 9820 // to handle. Embedders might still be interested in
michael@0 9821 // handling the load, though, so we fire a notification
michael@0 9822 // before throwing the load away.
michael@0 9823 bool abort = false;
michael@0 9824 nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
michael@0 9825 if (NS_SUCCEEDED(rv2) && abort) {
michael@0 9826 // Hey, they're handling the load for us! How convenient!
michael@0 9827 return NS_OK;
michael@0 9828 }
michael@0 9829 }
michael@0 9830 return rv;
michael@0 9831 }
michael@0 9832 if (aBaseURI) {
michael@0 9833 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
michael@0 9834 if (vsc) {
michael@0 9835 vsc->SetBaseURI(aBaseURI);
michael@0 9836 }
michael@0 9837 }
michael@0 9838 }
michael@0 9839 else {
michael@0 9840 nsAutoCString scheme;
michael@0 9841 rv = aURI->GetScheme(scheme);
michael@0 9842 NS_ENSURE_SUCCESS(rv,rv);
michael@0 9843 bool isViewSource;
michael@0 9844 aURI->SchemeIs("view-source",&isViewSource);
michael@0 9845
michael@0 9846 if (isViewSource) {
michael@0 9847 nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance();
michael@0 9848 NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE);
michael@0 9849
michael@0 9850 rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, aBaseURI,
michael@0 9851 getter_AddRefs(channel));
michael@0 9852 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9853 }
michael@0 9854 else {
michael@0 9855 rv = NS_NewInputStreamChannel(getter_AddRefs(channel),aURI,
michael@0 9856 aSrcdoc,
michael@0 9857 NS_LITERAL_CSTRING("text/html"),
michael@0 9858 true);
michael@0 9859 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9860 nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
michael@0 9861 MOZ_ASSERT(isc);
michael@0 9862 isc->SetBaseURI(aBaseURI);
michael@0 9863 }
michael@0 9864 }
michael@0 9865
michael@0 9866 nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
michael@0 9867 do_QueryInterface(channel);
michael@0 9868 if (appCacheChannel) {
michael@0 9869 // Any document load should not inherit application cache.
michael@0 9870 appCacheChannel->SetInheritApplicationCache(false);
michael@0 9871
michael@0 9872 // Loads with the correct permissions should check for a matching
michael@0 9873 // application cache.
michael@0 9874 if (GeckoProcessType_Default != XRE_GetProcessType()) {
michael@0 9875 // Permission will be checked in the parent process
michael@0 9876 appCacheChannel->SetChooseApplicationCache(true);
michael@0 9877 } else {
michael@0 9878 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 9879 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 9880
michael@0 9881 if (secMan) {
michael@0 9882 nsCOMPtr<nsIPrincipal> principal;
michael@0 9883 secMan->GetDocShellCodebasePrincipal(aURI, this, getter_AddRefs(principal));
michael@0 9884 appCacheChannel->SetChooseApplicationCache(
michael@0 9885 NS_ShouldCheckAppCache(principal, mInPrivateBrowsing));
michael@0 9886 }
michael@0 9887 }
michael@0 9888 }
michael@0 9889
michael@0 9890 // Make sure to give the caller a channel if we managed to create one
michael@0 9891 // This is important for correct error page/session history interaction
michael@0 9892 if (aRequest)
michael@0 9893 NS_ADDREF(*aRequest = channel);
michael@0 9894
michael@0 9895 channel->SetOriginalURI(aURI);
michael@0 9896 if (aTypeHint && *aTypeHint) {
michael@0 9897 channel->SetContentType(nsDependentCString(aTypeHint));
michael@0 9898 mContentTypeHint = aTypeHint;
michael@0 9899 } else {
michael@0 9900 mContentTypeHint.Truncate();
michael@0 9901 }
michael@0 9902
michael@0 9903 if (!aFileName.IsVoid()) {
michael@0 9904 rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
michael@0 9905 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9906 if (!aFileName.IsEmpty()) {
michael@0 9907 rv = channel->SetContentDispositionFilename(aFileName);
michael@0 9908 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9909 }
michael@0 9910 }
michael@0 9911
michael@0 9912 if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
michael@0 9913 mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
michael@0 9914 rv = SetMixedContentChannel(channel);
michael@0 9915 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9916 } else if (mMixedContentChannel) {
michael@0 9917 /*
michael@0 9918 * If the user "Disables Protection on This Page", we call
michael@0 9919 * SetMixedContentChannel for the first time, otherwise
michael@0 9920 * mMixedContentChannel is still null.
michael@0 9921 * Later, if the new channel passes a same orign check, we remember the
michael@0 9922 * users decision by calling SetMixedContentChannel using the new channel.
michael@0 9923 * This way, the user does not have to click the disable protection button
michael@0 9924 * over and over for browsing the same site.
michael@0 9925 */
michael@0 9926 rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel);
michael@0 9927 if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) {
michael@0 9928 SetMixedContentChannel(nullptr);
michael@0 9929 }
michael@0 9930 }
michael@0 9931
michael@0 9932 //hack
michael@0 9933 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
michael@0 9934 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
michael@0 9935 if (httpChannelInternal) {
michael@0 9936 if (aForceAllowCookies) {
michael@0 9937 httpChannelInternal->SetForceAllowThirdPartyCookie(true);
michael@0 9938 }
michael@0 9939 if (aFirstParty) {
michael@0 9940 httpChannelInternal->SetDocumentURI(aURI);
michael@0 9941 } else {
michael@0 9942 httpChannelInternal->SetDocumentURI(aReferrerURI);
michael@0 9943 }
michael@0 9944 }
michael@0 9945
michael@0 9946 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
michael@0 9947 if (props)
michael@0 9948 {
michael@0 9949 // save true referrer for those who need it (e.g. xpinstall whitelisting)
michael@0 9950 // Currently only http and ftp channels support this.
michael@0 9951 props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
michael@0 9952 aReferrerURI);
michael@0 9953 }
michael@0 9954
michael@0 9955 //
michael@0 9956 // If this is a HTTP channel, then set up the HTTP specific information
michael@0 9957 // (ie. POST data, referrer, ...)
michael@0 9958 //
michael@0 9959 if (httpChannel) {
michael@0 9960 nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(httpChannel));
michael@0 9961 /* Get the cache Key from SH */
michael@0 9962 nsCOMPtr<nsISupports> cacheKey;
michael@0 9963 if (mLSHE) {
michael@0 9964 mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
michael@0 9965 }
michael@0 9966 else if (mOSHE) // for reload cases
michael@0 9967 mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
michael@0 9968
michael@0 9969 // figure out if we need to set the post data stream on the channel...
michael@0 9970 // right now, this is only done for http channels.....
michael@0 9971 if (aPostData) {
michael@0 9972 // XXX it's a bit of a hack to rewind the postdata stream here but
michael@0 9973 // it has to be done in case the post data is being reused multiple
michael@0 9974 // times.
michael@0 9975 nsCOMPtr<nsISeekableStream>
michael@0 9976 postDataSeekable(do_QueryInterface(aPostData));
michael@0 9977 if (postDataSeekable) {
michael@0 9978 rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
michael@0 9979 NS_ENSURE_SUCCESS(rv, rv);
michael@0 9980 }
michael@0 9981
michael@0 9982 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
michael@0 9983 NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
michael@0 9984
michael@0 9985 // we really need to have a content type associated with this stream!!
michael@0 9986 uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1);
michael@0 9987 /* If there is a valid postdata *and* it is a History Load,
michael@0 9988 * set up the cache key on the channel, to retrieve the
michael@0 9989 * data *only* from the cache. If it is a normal reload, the
michael@0 9990 * cache is free to go to the server for updated postdata.
michael@0 9991 */
michael@0 9992 if (cacheChannel && cacheKey) {
michael@0 9993 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
michael@0 9994 cacheChannel->SetCacheKey(cacheKey);
michael@0 9995 uint32_t loadFlags;
michael@0 9996 if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags)))
michael@0 9997 channel->SetLoadFlags(loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
michael@0 9998 }
michael@0 9999 else if (mLoadType == LOAD_RELOAD_NORMAL)
michael@0 10000 cacheChannel->SetCacheKey(cacheKey);
michael@0 10001 }
michael@0 10002 }
michael@0 10003 else {
michael@0 10004 /* If there is no postdata, set the cache key on the channel, and
michael@0 10005 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
michael@0 10006 * will be free to get it from net if it is not found in cache.
michael@0 10007 * New cache may use it creatively on CGI pages with GET
michael@0 10008 * method and even on those that say "no-cache"
michael@0 10009 */
michael@0 10010 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL
michael@0 10011 || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
michael@0 10012 if (cacheChannel && cacheKey)
michael@0 10013 cacheChannel->SetCacheKey(cacheKey);
michael@0 10014 }
michael@0 10015 }
michael@0 10016 if (aHeadersData) {
michael@0 10017 rv = AddHeadersToChannel(aHeadersData, httpChannel);
michael@0 10018 }
michael@0 10019 // Set the referrer explicitly
michael@0 10020 if (aReferrerURI && aSendReferrer) {
michael@0 10021 // Referrer is currenly only set for link clicks here.
michael@0 10022 httpChannel->SetReferrer(aReferrerURI);
michael@0 10023 }
michael@0 10024 }
michael@0 10025
michael@0 10026 nsCOMPtr<nsIPrincipal> ownerPrincipal;
michael@0 10027
michael@0 10028 // If the content being loaded should be sandboxed with respect to origin
michael@0 10029 // we need to create a new null principal here, and then tell
michael@0 10030 // nsContentUtils::SetUpChannelOwner to force it to be set as the
michael@0 10031 // channel owner.
michael@0 10032 if (mSandboxFlags & SANDBOXED_ORIGIN) {
michael@0 10033 ownerPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
michael@0 10034 } else {
michael@0 10035 // Not sandboxed - we allow the content to assume its natural owner.
michael@0 10036 ownerPrincipal = do_QueryInterface(aOwner);
michael@0 10037 }
michael@0 10038
michael@0 10039 nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true,
michael@0 10040 (mSandboxFlags & SANDBOXED_ORIGIN) ||
michael@0 10041 isSrcdoc);
michael@0 10042
michael@0 10043 nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
michael@0 10044 if (scriptChannel) {
michael@0 10045 // Allow execution against our context if the principals match
michael@0 10046 scriptChannel->
michael@0 10047 SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
michael@0 10048 }
michael@0 10049
michael@0 10050 if (aIsNewWindowTarget) {
michael@0 10051 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
michael@0 10052 if (props) {
michael@0 10053 props->SetPropertyAsBool(
michael@0 10054 NS_LITERAL_STRING("docshell.newWindowTarget"),
michael@0 10055 true);
michael@0 10056 }
michael@0 10057 }
michael@0 10058
michael@0 10059 nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
michael@0 10060 if (timedChannel) {
michael@0 10061 timedChannel->SetTimingEnabled(true);
michael@0 10062 if (IsFrame()) {
michael@0 10063 timedChannel->SetInitiatorType(NS_LITERAL_STRING("subdocument"));
michael@0 10064 }
michael@0 10065 }
michael@0 10066
michael@0 10067 rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
michael@0 10068
michael@0 10069 //
michael@0 10070 // If the channel load failed, we failed and nsIWebProgress just ain't
michael@0 10071 // gonna happen.
michael@0 10072 //
michael@0 10073 if (NS_SUCCEEDED(rv)) {
michael@0 10074 if (aDocShell) {
michael@0 10075 *aDocShell = this;
michael@0 10076 NS_ADDREF(*aDocShell);
michael@0 10077 }
michael@0 10078 }
michael@0 10079
michael@0 10080 return rv;
michael@0 10081 }
michael@0 10082
michael@0 10083 static NS_METHOD
michael@0 10084 AppendSegmentToString(nsIInputStream *in,
michael@0 10085 void *closure,
michael@0 10086 const char *fromRawSegment,
michael@0 10087 uint32_t toOffset,
michael@0 10088 uint32_t count,
michael@0 10089 uint32_t *writeCount)
michael@0 10090 {
michael@0 10091 // aFromSegment now contains aCount bytes of data.
michael@0 10092
michael@0 10093 nsAutoCString *buf = static_cast<nsAutoCString *>(closure);
michael@0 10094 buf->Append(fromRawSegment, count);
michael@0 10095
michael@0 10096 // Indicate that we have consumed all of aFromSegment
michael@0 10097 *writeCount = count;
michael@0 10098 return NS_OK;
michael@0 10099 }
michael@0 10100
michael@0 10101 NS_IMETHODIMP
michael@0 10102 nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData,
michael@0 10103 nsIChannel *aGenericChannel)
michael@0 10104 {
michael@0 10105 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
michael@0 10106 NS_ENSURE_STATE(httpChannel);
michael@0 10107
michael@0 10108 uint32_t numRead;
michael@0 10109 nsAutoCString headersString;
michael@0 10110 nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
michael@0 10111 &headersString,
michael@0 10112 UINT32_MAX,
michael@0 10113 &numRead);
michael@0 10114 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10115
michael@0 10116 // used during the manipulation of the String from the InputStream
michael@0 10117 nsAutoCString headerName;
michael@0 10118 nsAutoCString headerValue;
michael@0 10119 int32_t crlf;
michael@0 10120 int32_t colon;
michael@0 10121
michael@0 10122 //
michael@0 10123 // Iterate over the headersString: for each "\r\n" delimited chunk,
michael@0 10124 // add the value as a header to the nsIHttpChannel
michael@0 10125 //
michael@0 10126
michael@0 10127 static const char kWhitespace[] = "\b\t\r\n ";
michael@0 10128 while (true) {
michael@0 10129 crlf = headersString.Find("\r\n");
michael@0 10130 if (crlf == kNotFound)
michael@0 10131 return NS_OK;
michael@0 10132
michael@0 10133 const nsCSubstring &oneHeader = StringHead(headersString, crlf);
michael@0 10134
michael@0 10135 colon = oneHeader.FindChar(':');
michael@0 10136 if (colon == kNotFound)
michael@0 10137 return NS_ERROR_UNEXPECTED;
michael@0 10138
michael@0 10139 headerName = StringHead(oneHeader, colon);
michael@0 10140 headerValue = Substring(oneHeader, colon + 1);
michael@0 10141
michael@0 10142 headerName.Trim(kWhitespace);
michael@0 10143 headerValue.Trim(kWhitespace);
michael@0 10144
michael@0 10145 headersString.Cut(0, crlf + 2);
michael@0 10146
michael@0 10147 //
michael@0 10148 // FINALLY: we can set the header!
michael@0 10149 //
michael@0 10150
michael@0 10151 rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
michael@0 10152 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10153 }
michael@0 10154
michael@0 10155 NS_NOTREACHED("oops");
michael@0 10156 return NS_ERROR_UNEXPECTED;
michael@0 10157 }
michael@0 10158
michael@0 10159 nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
michael@0 10160 nsIURILoader * aURILoader,
michael@0 10161 bool aBypassClassifier)
michael@0 10162 {
michael@0 10163 nsresult rv;
michael@0 10164 // Mark the channel as being a document URI and allow content sniffing...
michael@0 10165 nsLoadFlags loadFlags = 0;
michael@0 10166 (void) aChannel->GetLoadFlags(&loadFlags);
michael@0 10167 loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
michael@0 10168 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
michael@0 10169
michael@0 10170 // Load attributes depend on load type...
michael@0 10171 switch (mLoadType) {
michael@0 10172 case LOAD_HISTORY:
michael@0 10173 {
michael@0 10174 // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
michael@0 10175 // push/replaceState (bug 669671).
michael@0 10176 bool uriModified = false;
michael@0 10177 if (mLSHE) {
michael@0 10178 mLSHE->GetURIWasModified(&uriModified);
michael@0 10179 }
michael@0 10180
michael@0 10181 if (!uriModified)
michael@0 10182 loadFlags |= nsIRequest::VALIDATE_NEVER;
michael@0 10183 }
michael@0 10184 break;
michael@0 10185
michael@0 10186 case LOAD_RELOAD_CHARSET_CHANGE:
michael@0 10187 loadFlags |= nsIRequest::LOAD_FROM_CACHE;
michael@0 10188 break;
michael@0 10189
michael@0 10190 case LOAD_RELOAD_NORMAL:
michael@0 10191 case LOAD_REFRESH:
michael@0 10192 loadFlags |= nsIRequest::VALIDATE_ALWAYS;
michael@0 10193 break;
michael@0 10194
michael@0 10195 case LOAD_NORMAL_BYPASS_CACHE:
michael@0 10196 case LOAD_NORMAL_BYPASS_PROXY:
michael@0 10197 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
michael@0 10198 case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
michael@0 10199 case LOAD_RELOAD_BYPASS_CACHE:
michael@0 10200 case LOAD_RELOAD_BYPASS_PROXY:
michael@0 10201 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
michael@0 10202 case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
michael@0 10203 case LOAD_REPLACE_BYPASS_CACHE:
michael@0 10204 loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
michael@0 10205 nsIRequest::LOAD_FRESH_CONNECTION;
michael@0 10206 break;
michael@0 10207
michael@0 10208 case LOAD_NORMAL:
michael@0 10209 case LOAD_LINK:
michael@0 10210 // Set cache checking flags
michael@0 10211 switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
michael@0 10212 case 0:
michael@0 10213 loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
michael@0 10214 break;
michael@0 10215 case 1:
michael@0 10216 loadFlags |= nsIRequest::VALIDATE_ALWAYS;
michael@0 10217 break;
michael@0 10218 case 2:
michael@0 10219 loadFlags |= nsIRequest::VALIDATE_NEVER;
michael@0 10220 break;
michael@0 10221 }
michael@0 10222 break;
michael@0 10223 }
michael@0 10224
michael@0 10225 if (!aBypassClassifier) {
michael@0 10226 loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
michael@0 10227 }
michael@0 10228
michael@0 10229 (void) aChannel->SetLoadFlags(loadFlags);
michael@0 10230
michael@0 10231 uint32_t openFlags = 0;
michael@0 10232 if (mLoadType == LOAD_LINK) {
michael@0 10233 openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
michael@0 10234 }
michael@0 10235 if (!mAllowContentRetargeting) {
michael@0 10236 openFlags |= nsIURILoader::DONT_RETARGET;
michael@0 10237 }
michael@0 10238 rv = aURILoader->OpenURI(aChannel, openFlags, this);
michael@0 10239 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10240
michael@0 10241 return NS_OK;
michael@0 10242 }
michael@0 10243
michael@0 10244 nsresult
michael@0 10245 nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
michael@0 10246 uint32_t aLoadType)
michael@0 10247 {
michael@0 10248 if (!mCurrentURI) {
michael@0 10249 return NS_OK;
michael@0 10250 }
michael@0 10251
michael@0 10252 nsCOMPtr<nsIPresShell> shell = GetPresShell();
michael@0 10253 if (!shell) {
michael@0 10254 // If we failed to get the shell, or if there is no shell,
michael@0 10255 // nothing left to do here.
michael@0 10256 return NS_OK;
michael@0 10257 }
michael@0 10258
michael@0 10259 nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
michael@0 10260 if (rootScroll) {
michael@0 10261 rootScroll->ClearDidHistoryRestore();
michael@0 10262 }
michael@0 10263
michael@0 10264 // If we have no new anchor, we do not want to scroll, unless there is a
michael@0 10265 // current anchor and we are doing a history load. So return if we have no
michael@0 10266 // new anchor, and there is no current anchor or the load is not a history
michael@0 10267 // load.
michael@0 10268 if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) &&
michael@0 10269 aNewHash.IsEmpty()) {
michael@0 10270 return NS_OK;
michael@0 10271 }
michael@0 10272
michael@0 10273 // Take the '#' off aNewHash to get the ref name. (aNewHash might be empty,
michael@0 10274 // but that's fine.)
michael@0 10275 nsDependentCSubstring newHashName(aNewHash, 1);
michael@0 10276
michael@0 10277 // Both the new and current URIs refer to the same page. We can now
michael@0 10278 // browse to the hash stored in the new URI.
michael@0 10279
michael@0 10280 if (!newHashName.IsEmpty()) {
michael@0 10281 // anchor is there, but if it's a load from history,
michael@0 10282 // we don't have any anchor jumping to do
michael@0 10283 bool scroll = aLoadType != LOAD_HISTORY &&
michael@0 10284 aLoadType != LOAD_RELOAD_NORMAL;
michael@0 10285
michael@0 10286 char *str = ToNewCString(newHashName);
michael@0 10287 if (!str) {
michael@0 10288 return NS_ERROR_OUT_OF_MEMORY;
michael@0 10289 }
michael@0 10290
michael@0 10291 // nsUnescape modifies the string that is passed into it.
michael@0 10292 nsUnescape(str);
michael@0 10293
michael@0 10294 // We assume that the bytes are in UTF-8, as it says in the
michael@0 10295 // spec:
michael@0 10296 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
michael@0 10297
michael@0 10298 // We try the UTF-8 string first, and then try the document's
michael@0 10299 // charset (see below). If the string is not UTF-8,
michael@0 10300 // conversion will fail and give us an empty Unicode string.
michael@0 10301 // In that case, we should just fall through to using the
michael@0 10302 // page's charset.
michael@0 10303 nsresult rv = NS_ERROR_FAILURE;
michael@0 10304 NS_ConvertUTF8toUTF16 uStr(str);
michael@0 10305 if (!uStr.IsEmpty()) {
michael@0 10306 rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll);
michael@0 10307 }
michael@0 10308 nsMemory::Free(str);
michael@0 10309
michael@0 10310 // Above will fail if the anchor name is not UTF-8. Need to
michael@0 10311 // convert from document charset to unicode.
michael@0 10312 if (NS_FAILED(rv)) {
michael@0 10313
michael@0 10314 // Get a document charset
michael@0 10315 NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
michael@0 10316 nsIDocument* doc = mContentViewer->GetDocument();
michael@0 10317 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
michael@0 10318 const nsACString &aCharset = doc->GetDocumentCharacterSet();
michael@0 10319
michael@0 10320 nsCOMPtr<nsITextToSubURI> textToSubURI =
michael@0 10321 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
michael@0 10322 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10323
michael@0 10324 // Unescape and convert to unicode
michael@0 10325 nsXPIDLString uStr;
michael@0 10326
michael@0 10327 rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
michael@0 10328 PromiseFlatCString(newHashName).get(),
michael@0 10329 getter_Copies(uStr));
michael@0 10330 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10331
michael@0 10332 // Ignore return value of GoToAnchor, since it will return an error
michael@0 10333 // if there is no such anchor in the document, which is actually a
michael@0 10334 // success condition for us (we want to update the session history
michael@0 10335 // with the new URI no matter whether we actually scrolled
michael@0 10336 // somewhere).
michael@0 10337 //
michael@0 10338 // When newHashName contains "%00", unescaped string may be empty.
michael@0 10339 // And GoToAnchor asserts if we ask it to scroll to an empty ref.
michael@0 10340 shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty());
michael@0 10341 }
michael@0 10342 }
michael@0 10343 else {
michael@0 10344
michael@0 10345 // Tell the shell it's at an anchor, without scrolling.
michael@0 10346 shell->GoToAnchor(EmptyString(), false);
michael@0 10347
michael@0 10348 // An empty anchor was found, but if it's a load from history,
michael@0 10349 // we don't have to jump to the top of the page. Scrollbar
michael@0 10350 // position will be restored by the caller, based on positions
michael@0 10351 // stored in session history.
michael@0 10352 if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
michael@0 10353 return NS_OK;
michael@0 10354 // An empty anchor. Scroll to the top of the page. Ignore the
michael@0 10355 // return value; failure to scroll here (e.g. if there is no
michael@0 10356 // root scrollframe) is not grounds for canceling the load!
michael@0 10357 SetCurScrollPosEx(0, 0);
michael@0 10358 }
michael@0 10359
michael@0 10360 return NS_OK;
michael@0 10361 }
michael@0 10362
michael@0 10363 void
michael@0 10364 nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
michael@0 10365 {
michael@0 10366 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
michael@0 10367 if (httpChannel) {
michael@0 10368 nsCOMPtr<nsIURI> referrer;
michael@0 10369 nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
michael@0 10370 if (NS_SUCCEEDED(rv)) {
michael@0 10371 SetReferrerURI(referrer);
michael@0 10372 }
michael@0 10373 }
michael@0 10374 }
michael@0 10375
michael@0 10376 bool
michael@0 10377 nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
michael@0 10378 uint32_t aLoadType, bool aFireOnLocationChange,
michael@0 10379 bool aAddToGlobalHistory, bool aCloneSHChildren)
michael@0 10380 {
michael@0 10381 NS_PRECONDITION(aURI, "uri is null");
michael@0 10382 NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
michael@0 10383
michael@0 10384 #if defined(PR_LOGGING) && defined(DEBUG)
michael@0 10385 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
michael@0 10386 nsAutoCString spec;
michael@0 10387 aURI->GetSpec(spec);
michael@0 10388
michael@0 10389 nsAutoCString chanName;
michael@0 10390 if (aChannel)
michael@0 10391 aChannel->GetName(chanName);
michael@0 10392 else
michael@0 10393 chanName.AssignLiteral("<no channel>");
michael@0 10394
michael@0 10395 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 10396 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
michael@0 10397 chanName.get(), aLoadType));
michael@0 10398 }
michael@0 10399 #endif
michael@0 10400
michael@0 10401 bool equalUri = false;
michael@0 10402
michael@0 10403 // Get the post data and the HTTP response code from the channel.
michael@0 10404 uint32_t responseStatus = 0;
michael@0 10405 nsCOMPtr<nsIInputStream> inputStream;
michael@0 10406 if (aChannel) {
michael@0 10407 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
michael@0 10408
michael@0 10409 // Check if the HTTPChannel is hiding under a multiPartChannel
michael@0 10410 if (!httpChannel) {
michael@0 10411 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
michael@0 10412 }
michael@0 10413
michael@0 10414 if (httpChannel) {
michael@0 10415 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
michael@0 10416 if (uploadChannel) {
michael@0 10417 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
michael@0 10418 }
michael@0 10419
michael@0 10420 // If the response status indicates an error, unlink this session
michael@0 10421 // history entry from any entries sharing its document.
michael@0 10422 nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
michael@0 10423 if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
michael@0 10424 mLSHE->AbandonBFCacheEntry();
michael@0 10425 }
michael@0 10426 }
michael@0 10427 }
michael@0 10428
michael@0 10429 // Determine if this type of load should update history.
michael@0 10430 bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY ||
michael@0 10431 aLoadType == LOAD_ERROR_PAGE ||
michael@0 10432 aLoadType & LOAD_CMD_HISTORY);
michael@0 10433
michael@0 10434 // We don't update session history on reload.
michael@0 10435 bool updateSHistory = updateGHistory && (!(aLoadType & LOAD_CMD_RELOAD));
michael@0 10436
michael@0 10437 /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
michael@0 10438 * the current frame or in the root docshell
michael@0 10439 */
michael@0 10440 nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
michael@0 10441 if (!rootSH) {
michael@0 10442 // Get the handle to SH from the root docshell
michael@0 10443 GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 10444 if (!rootSH) {
michael@0 10445 updateSHistory = false;
michael@0 10446 updateGHistory = false; // XXX Why global history too?
michael@0 10447 }
michael@0 10448 } // rootSH
michael@0 10449
michael@0 10450 // Check if the url to be loaded is the same as the one already loaded.
michael@0 10451 if (mCurrentURI)
michael@0 10452 aURI->Equals(mCurrentURI, &equalUri);
michael@0 10453
michael@0 10454 #ifdef DEBUG
michael@0 10455 bool shAvailable = (rootSH != nullptr);
michael@0 10456
michael@0 10457 // XXX This log message is almost useless because |updateSHistory|
michael@0 10458 // and |updateGHistory| are not correct at this point.
michael@0 10459
michael@0 10460 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 10461 (" shAvailable=%i updateSHistory=%i updateGHistory=%i"
michael@0 10462 " equalURI=%i\n",
michael@0 10463 shAvailable, updateSHistory, updateGHistory, equalUri));
michael@0 10464
michael@0 10465 if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
michael@0 10466 NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?");
michael@0 10467 }
michael@0 10468 #endif
michael@0 10469
michael@0 10470 /* If the url to be loaded is the same as the one already there,
michael@0 10471 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
michael@0 10472 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
michael@0 10473 * AddToSessionHistory() won't mess with the current SHEntry and
michael@0 10474 * if this page has any frame children, it also will be handled
michael@0 10475 * properly. see bug 83684
michael@0 10476 *
michael@0 10477 * NB: If mOSHE is null but we have a current URI, then it means
michael@0 10478 * that we must be at the transient about:blank content viewer
michael@0 10479 * (asserted above) and we should let the normal load continue,
michael@0 10480 * since there's nothing to replace.
michael@0 10481 *
michael@0 10482 * XXX Hopefully changing the loadType at this time will not hurt
michael@0 10483 * anywhere. The other way to take care of sequentially repeating
michael@0 10484 * frameset pages is to add new methods to nsIDocShellTreeItem.
michael@0 10485 * Hopefully I don't have to do that.
michael@0 10486 */
michael@0 10487 if (equalUri &&
michael@0 10488 mOSHE &&
michael@0 10489 (mLoadType == LOAD_NORMAL ||
michael@0 10490 mLoadType == LOAD_LINK ||
michael@0 10491 mLoadType == LOAD_STOP_CONTENT) &&
michael@0 10492 !inputStream)
michael@0 10493 {
michael@0 10494 mLoadType = LOAD_NORMAL_REPLACE;
michael@0 10495 }
michael@0 10496
michael@0 10497 // If this is a refresh to the currently loaded url, we don't
michael@0 10498 // have to update session or global history.
michael@0 10499 if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
michael@0 10500 SetHistoryEntry(&mLSHE, mOSHE);
michael@0 10501 }
michael@0 10502
michael@0 10503 /* If the user pressed shift-reload, cache will create a new cache key
michael@0 10504 * for the page. Save the new cacheKey in Session History.
michael@0 10505 * see bug 90098
michael@0 10506 */
michael@0 10507 if (aChannel &&
michael@0 10508 (aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
michael@0 10509 aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
michael@0 10510 aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE ||
michael@0 10511 aLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT)) {
michael@0 10512 NS_ASSERTION(!updateSHistory,
michael@0 10513 "We shouldn't be updating session history for forced"
michael@0 10514 " reloads!");
michael@0 10515
michael@0 10516 nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
michael@0 10517 nsCOMPtr<nsISupports> cacheKey;
michael@0 10518 // Get the Cache Key and store it in SH.
michael@0 10519 if (cacheChannel)
michael@0 10520 cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
michael@0 10521 // If we already have a loading history entry, store the new cache key
michael@0 10522 // in it. Otherwise, since we're doing a reload and won't be updating
michael@0 10523 // our history entry, store the cache key in our current history entry.
michael@0 10524 if (mLSHE)
michael@0 10525 mLSHE->SetCacheKey(cacheKey);
michael@0 10526 else if (mOSHE)
michael@0 10527 mOSHE->SetCacheKey(cacheKey);
michael@0 10528
michael@0 10529 // Since we're force-reloading, clear all the sub frame history.
michael@0 10530 ClearFrameHistory(mLSHE);
michael@0 10531 ClearFrameHistory(mOSHE);
michael@0 10532 }
michael@0 10533
michael@0 10534 if (aLoadType == LOAD_RELOAD_NORMAL) {
michael@0 10535 nsCOMPtr<nsISHEntry> currentSH;
michael@0 10536 bool oshe = false;
michael@0 10537 GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
michael@0 10538 bool dynamicallyAddedChild = false;
michael@0 10539 if (currentSH) {
michael@0 10540 currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
michael@0 10541 }
michael@0 10542 if (dynamicallyAddedChild) {
michael@0 10543 ClearFrameHistory(currentSH);
michael@0 10544 }
michael@0 10545 }
michael@0 10546
michael@0 10547 if (aLoadType == LOAD_REFRESH) {
michael@0 10548 ClearFrameHistory(mLSHE);
michael@0 10549 ClearFrameHistory(mOSHE);
michael@0 10550 }
michael@0 10551
michael@0 10552 if (updateSHistory) {
michael@0 10553 // Update session history if necessary...
michael@0 10554 if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
michael@0 10555 /* This is a fresh page getting loaded for the first time
michael@0 10556 *.Create a Entry for it and add it to SH, if this is the
michael@0 10557 * rootDocShell
michael@0 10558 */
michael@0 10559 (void) AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren,
michael@0 10560 getter_AddRefs(mLSHE));
michael@0 10561 }
michael@0 10562 }
michael@0 10563
michael@0 10564 // If this is a POST request, we do not want to include this in global
michael@0 10565 // history.
michael@0 10566 if (updateGHistory &&
michael@0 10567 aAddToGlobalHistory &&
michael@0 10568 !ChannelIsPost(aChannel)) {
michael@0 10569 nsCOMPtr<nsIURI> previousURI;
michael@0 10570 uint32_t previousFlags = 0;
michael@0 10571
michael@0 10572 if (aLoadType & LOAD_CMD_RELOAD) {
michael@0 10573 // On a reload request, we don't set redirecting flags.
michael@0 10574 previousURI = aURI;
michael@0 10575 } else {
michael@0 10576 ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
michael@0 10577 &previousFlags);
michael@0 10578 }
michael@0 10579
michael@0 10580 // Note: We don't use |referrer| when our global history is
michael@0 10581 // based on IHistory.
michael@0 10582 nsCOMPtr<nsIURI> referrer;
michael@0 10583 // Treat referrer as null if there is an error getting it.
michael@0 10584 (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
michael@0 10585
michael@0 10586 AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
michael@0 10587 }
michael@0 10588
michael@0 10589 // If this was a history load or a refresh,
michael@0 10590 // update the index in SH.
michael@0 10591 if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) {
michael@0 10592 nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
michael@0 10593 if (shInternal) {
michael@0 10594 rootSH->GetIndex(&mPreviousTransIndex);
michael@0 10595 shInternal->UpdateIndex();
michael@0 10596 rootSH->GetIndex(&mLoadedTransIndex);
michael@0 10597 #ifdef DEBUG_PAGE_CACHE
michael@0 10598 printf("Previous index: %d, Loaded index: %d\n\n",
michael@0 10599 mPreviousTransIndex, mLoadedTransIndex);
michael@0 10600 #endif
michael@0 10601 }
michael@0 10602 }
michael@0 10603
michael@0 10604 // aCloneSHChildren exactly means "we are not loading a new document".
michael@0 10605 uint32_t locationFlags = aCloneSHChildren?
michael@0 10606 uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
michael@0 10607
michael@0 10608 bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
michael@0 10609 aFireOnLocationChange,
michael@0 10610 locationFlags);
michael@0 10611 // Make sure to store the referrer from the channel, if any
michael@0 10612 SetupReferrerFromChannel(aChannel);
michael@0 10613 return onLocationChangeNeeded;
michael@0 10614 }
michael@0 10615
michael@0 10616 bool
michael@0 10617 nsDocShell::OnLoadingSite(nsIChannel * aChannel, bool aFireOnLocationChange,
michael@0 10618 bool aAddToGlobalHistory)
michael@0 10619 {
michael@0 10620 nsCOMPtr<nsIURI> uri;
michael@0 10621 // If this a redirect, use the final url (uri)
michael@0 10622 // else use the original url
michael@0 10623 //
michael@0 10624 // Note that this should match what documents do (see nsDocument::Reset).
michael@0 10625 NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
michael@0 10626 NS_ENSURE_TRUE(uri, false);
michael@0 10627
michael@0 10628 // Pass false for aCloneSHChildren, since we're loading a new page here.
michael@0 10629 return OnNewURI(uri, aChannel, nullptr, mLoadType, aFireOnLocationChange,
michael@0 10630 aAddToGlobalHistory, false);
michael@0 10631
michael@0 10632 }
michael@0 10633
michael@0 10634 void
michael@0 10635 nsDocShell::SetReferrerURI(nsIURI * aURI)
michael@0 10636 {
michael@0 10637 mReferrerURI = aURI; // This assigment addrefs
michael@0 10638 }
michael@0 10639
michael@0 10640 //*****************************************************************************
michael@0 10641 // nsDocShell: Session History
michael@0 10642 //*****************************************************************************
michael@0 10643
michael@0 10644 NS_IMETHODIMP
michael@0 10645 nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
michael@0 10646 const nsAString& aURL, bool aReplace, JSContext* aCx)
michael@0 10647 {
michael@0 10648 // Implements History.pushState and History.replaceState
michael@0 10649
michael@0 10650 // Here's what we do, roughly in the order specified by HTML5:
michael@0 10651 // 1. Serialize aData using structured clone.
michael@0 10652 // 2. If the third argument is present,
michael@0 10653 // a. Resolve the url, relative to the first script's base URL
michael@0 10654 // b. If (a) fails, raise a SECURITY_ERR
michael@0 10655 // c. Compare the resulting absolute URL to the document's address. If
michael@0 10656 // any part of the URLs difer other than the <path>, <query>, and
michael@0 10657 // <fragment> components, raise a SECURITY_ERR and abort.
michael@0 10658 // 3. If !aReplace:
michael@0 10659 // Remove from the session history all entries after the current entry,
michael@0 10660 // as we would after a regular navigation, and save the current
michael@0 10661 // entry's scroll position (bug 590573).
michael@0 10662 // 4. As apropriate, either add a state object entry to the session history
michael@0 10663 // after the current entry with the following properties, or modify the
michael@0 10664 // current session history entry to set
michael@0 10665 // a. cloned data as the state object,
michael@0 10666 // b. if the third argument was present, the absolute URL found in
michael@0 10667 // step 2
michael@0 10668 // Also clear the new history entry's POST data (see bug 580069).
michael@0 10669 // 5. If aReplace is false (i.e. we're doing a pushState instead of a
michael@0 10670 // replaceState), notify bfcache that we've navigated to a new page.
michael@0 10671 // 6. If the third argument is present, set the document's current address
michael@0 10672 // to the absolute URL found in step 2.
michael@0 10673 //
michael@0 10674 // It's important that this function not run arbitrary scripts after step 1
michael@0 10675 // and before completing step 5. For example, if a script called
michael@0 10676 // history.back() before we completed step 5, bfcache might destroy an
michael@0 10677 // active content viewer. Since EvictOutOfRangeContentViewers at the end of
michael@0 10678 // step 5 might run script, we can't just put a script blocker around the
michael@0 10679 // critical section.
michael@0 10680 //
michael@0 10681 // Note that we completely ignore the aTitle parameter.
michael@0 10682
michael@0 10683 nsresult rv;
michael@0 10684
michael@0 10685 // Don't clobber the load type of an existing network load.
michael@0 10686 AutoRestore<uint32_t> loadTypeResetter(mLoadType);
michael@0 10687
michael@0 10688 // pushState effectively becomes replaceState when we've started a network
michael@0 10689 // load but haven't adopted its document yet. This mirrors what we do with
michael@0 10690 // changes to the hash at this stage of the game.
michael@0 10691 if (JustStartedNetworkLoad()) {
michael@0 10692 aReplace = true;
michael@0 10693 }
michael@0 10694
michael@0 10695 nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
michael@0 10696 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
michael@0 10697
michael@0 10698 // Step 1: Serialize aData using structured clone.
michael@0 10699 nsCOMPtr<nsIStructuredCloneContainer> scContainer;
michael@0 10700
michael@0 10701 // scContainer->Init might cause arbitrary JS to run, and this code might
michael@0 10702 // navigate the page we're on, potentially to a different origin! (bug
michael@0 10703 // 634834) To protect against this, we abort if our principal changes due
michael@0 10704 // to the InitFromJSVal() call.
michael@0 10705 {
michael@0 10706 nsCOMPtr<nsIDocument> origDocument =
michael@0 10707 do_GetInterface(GetAsSupports(this));
michael@0 10708 if (!origDocument)
michael@0 10709 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 10710 nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
michael@0 10711
michael@0 10712 scContainer = new nsStructuredCloneContainer();
michael@0 10713 JSContext *cx = aCx;
michael@0 10714 nsCxPusher pusher;
michael@0 10715 if (!cx) {
michael@0 10716 cx = nsContentUtils::GetContextFromDocument(document);
michael@0 10717 pusher.Push(cx);
michael@0 10718 }
michael@0 10719 rv = scContainer->InitFromJSVal(aData, cx);
michael@0 10720
michael@0 10721 // If we're running in the document's context and the structured clone
michael@0 10722 // failed, clear the context's pending exception. See bug 637116.
michael@0 10723 if (NS_FAILED(rv) && !aCx) {
michael@0 10724 JS_ClearPendingException(aCx);
michael@0 10725 }
michael@0 10726 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10727
michael@0 10728 nsCOMPtr<nsIDocument> newDocument =
michael@0 10729 do_GetInterface(GetAsSupports(this));
michael@0 10730 if (!newDocument)
michael@0 10731 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 10732 nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
michael@0 10733
michael@0 10734 bool principalsEqual = false;
michael@0 10735 origPrincipal->Equals(newPrincipal, &principalsEqual);
michael@0 10736 NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
michael@0 10737 }
michael@0 10738
michael@0 10739 // Check that the state object isn't too long.
michael@0 10740 // Default max length: 640k bytes.
michael@0 10741 int32_t maxStateObjSize =
michael@0 10742 Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
michael@0 10743 if (maxStateObjSize < 0) {
michael@0 10744 maxStateObjSize = 0;
michael@0 10745 }
michael@0 10746
michael@0 10747 uint64_t scSize;
michael@0 10748 rv = scContainer->GetSerializedNBytes(&scSize);
michael@0 10749 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10750
michael@0 10751 NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize,
michael@0 10752 NS_ERROR_ILLEGAL_VALUE);
michael@0 10753
michael@0 10754 // Step 2: Resolve aURL
michael@0 10755 bool equalURIs = true;
michael@0 10756 nsCOMPtr<nsIURI> currentURI;
michael@0 10757 if (sURIFixup && mCurrentURI) {
michael@0 10758 rv = sURIFixup->CreateExposableURI(mCurrentURI,
michael@0 10759 getter_AddRefs(currentURI));
michael@0 10760 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10761 } else {
michael@0 10762 currentURI = mCurrentURI;
michael@0 10763 }
michael@0 10764 nsCOMPtr<nsIURI> oldURI = currentURI;
michael@0 10765 nsCOMPtr<nsIURI> newURI;
michael@0 10766 if (aURL.Length() == 0) {
michael@0 10767 newURI = currentURI;
michael@0 10768 }
michael@0 10769 else {
michael@0 10770 // 2a: Resolve aURL relative to mURI
michael@0 10771
michael@0 10772 nsIURI* docBaseURI = document->GetDocBaseURI();
michael@0 10773 if (!docBaseURI)
michael@0 10774 return NS_ERROR_FAILURE;
michael@0 10775
michael@0 10776 nsAutoCString spec;
michael@0 10777 docBaseURI->GetSpec(spec);
michael@0 10778
michael@0 10779 nsAutoCString charset;
michael@0 10780 rv = docBaseURI->GetOriginCharset(charset);
michael@0 10781 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
michael@0 10782
michael@0 10783 rv = NS_NewURI(getter_AddRefs(newURI), aURL,
michael@0 10784 charset.get(), docBaseURI);
michael@0 10785
michael@0 10786 // 2b: If 2a fails, raise a SECURITY_ERR
michael@0 10787 if (NS_FAILED(rv)) {
michael@0 10788 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 10789 }
michael@0 10790
michael@0 10791 // 2c: Same-origin check.
michael@0 10792 if (!nsContentUtils::URIIsLocalFile(newURI)) {
michael@0 10793 // In addition to checking that the security manager says that
michael@0 10794 // the new URI has the same origin as our current URI, we also
michael@0 10795 // check that the two URIs have the same userpass. (The
michael@0 10796 // security manager says that |http://foo.com| and
michael@0 10797 // |http://me@foo.com| have the same origin.) currentURI
michael@0 10798 // won't contain the password part of the userpass, so this
michael@0 10799 // means that it's never valid to specify a password in a
michael@0 10800 // pushState or replaceState URI.
michael@0 10801
michael@0 10802 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 10803 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 10804 NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
michael@0 10805
michael@0 10806 // It's very important that we check that newURI is of the same
michael@0 10807 // origin as currentURI, not docBaseURI, because a page can
michael@0 10808 // set docBaseURI arbitrarily to any domain.
michael@0 10809 nsAutoCString currentUserPass, newUserPass;
michael@0 10810 NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
michael@0 10811 NS_ERROR_FAILURE);
michael@0 10812 NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass),
michael@0 10813 NS_ERROR_FAILURE);
michael@0 10814 if (NS_FAILED(secMan->CheckSameOriginURI(currentURI,
michael@0 10815 newURI, true)) ||
michael@0 10816 !currentUserPass.Equals(newUserPass)) {
michael@0 10817
michael@0 10818 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 10819 }
michael@0 10820 }
michael@0 10821 else {
michael@0 10822 // It's a file:// URI
michael@0 10823 nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
michael@0 10824 do_QueryInterface(document);
michael@0 10825
michael@0 10826 if (!docScriptObj) {
michael@0 10827 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 10828 }
michael@0 10829
michael@0 10830 nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
michael@0 10831
michael@0 10832 if (!principal ||
michael@0 10833 NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
michael@0 10834
michael@0 10835 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 10836 }
michael@0 10837 }
michael@0 10838
michael@0 10839 if (currentURI) {
michael@0 10840 currentURI->Equals(newURI, &equalURIs);
michael@0 10841 }
michael@0 10842 else {
michael@0 10843 equalURIs = false;
michael@0 10844 }
michael@0 10845
michael@0 10846 } // end of same-origin check
michael@0 10847
michael@0 10848 // Step 3: Create a new entry in the session history. This will erase
michael@0 10849 // all SHEntries after the new entry and make this entry the current
michael@0 10850 // one. This operation may modify mOSHE, which we need later, so we
michael@0 10851 // keep a reference here.
michael@0 10852 NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
michael@0 10853 nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
michael@0 10854
michael@0 10855 mLoadType = LOAD_PUSHSTATE;
michael@0 10856
michael@0 10857 nsCOMPtr<nsISHEntry> newSHEntry;
michael@0 10858 if (!aReplace) {
michael@0 10859 // Save the current scroll position (bug 590573).
michael@0 10860 nscoord cx = 0, cy = 0;
michael@0 10861 GetCurScrollPos(ScrollOrientation_X, &cx);
michael@0 10862 GetCurScrollPos(ScrollOrientation_Y, &cy);
michael@0 10863 mOSHE->SetScrollPosition(cx, cy);
michael@0 10864
michael@0 10865 // Since we're not changing which page we have loaded, pass
michael@0 10866 // true for aCloneChildren.
michael@0 10867 rv = AddToSessionHistory(newURI, nullptr, nullptr, true,
michael@0 10868 getter_AddRefs(newSHEntry));
michael@0 10869 NS_ENSURE_SUCCESS(rv, rv);
michael@0 10870
michael@0 10871 NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
michael@0 10872
michael@0 10873 // Link the new SHEntry to the old SHEntry's BFCache entry, since the
michael@0 10874 // two entries correspond to the same document.
michael@0 10875 NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE),
michael@0 10876 NS_ERROR_FAILURE);
michael@0 10877
michael@0 10878 // Set the new SHEntry's title (bug 655273).
michael@0 10879 nsString title;
michael@0 10880 mOSHE->GetTitle(getter_Copies(title));
michael@0 10881 newSHEntry->SetTitle(title);
michael@0 10882
michael@0 10883 // AddToSessionHistory may not modify mOSHE. In case it doesn't,
michael@0 10884 // we'll just set mOSHE here.
michael@0 10885 mOSHE = newSHEntry;
michael@0 10886
michael@0 10887 } else {
michael@0 10888 newSHEntry = mOSHE;
michael@0 10889 newSHEntry->SetURI(newURI);
michael@0 10890 }
michael@0 10891
michael@0 10892 // Step 4: Modify new/original session history entry and clear its POST
michael@0 10893 // data, if there is any.
michael@0 10894 newSHEntry->SetStateData(scContainer);
michael@0 10895 newSHEntry->SetPostData(nullptr);
michael@0 10896
michael@0 10897 // If this push/replaceState changed the document's current URI and the new
michael@0 10898 // URI differs from the old URI in more than the hash, or if the old
michael@0 10899 // SHEntry's URI was modified in this way by a push/replaceState call
michael@0 10900 // set URIWasModified to true for the current SHEntry (bug 669671).
michael@0 10901 bool sameExceptHashes = true, oldURIWasModified = false;
michael@0 10902 newURI->EqualsExceptRef(currentURI, &sameExceptHashes);
michael@0 10903 oldOSHE->GetURIWasModified(&oldURIWasModified);
michael@0 10904 newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
michael@0 10905
michael@0 10906 // Step 5: If aReplace is false, indicating that we're doing a pushState
michael@0 10907 // rather than a replaceState, notify bfcache that we've added a page to
michael@0 10908 // the history so it can evict content viewers if appropriate. Otherwise
michael@0 10909 // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
michael@0 10910 // was replaced.
michael@0 10911 nsCOMPtr<nsISHistory> rootSH;
michael@0 10912 GetRootSessionHistory(getter_AddRefs(rootSH));
michael@0 10913 NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
michael@0 10914
michael@0 10915 nsCOMPtr<nsISHistoryInternal> internalSH =
michael@0 10916 do_QueryInterface(rootSH);
michael@0 10917 NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
michael@0 10918
michael@0 10919 if (!aReplace) {
michael@0 10920 int32_t curIndex = -1;
michael@0 10921 rv = rootSH->GetIndex(&curIndex);
michael@0 10922 if (NS_SUCCEEDED(rv) && curIndex > -1) {
michael@0 10923 internalSH->EvictOutOfRangeContentViewers(curIndex);
michael@0 10924 }
michael@0 10925 } else {
michael@0 10926 nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry);
michael@0 10927
michael@0 10928 int32_t index = -1;
michael@0 10929 rv = rootSH->GetIndexOfEntry(rootSHEntry, &index);
michael@0 10930 if (NS_SUCCEEDED(rv) && index > -1) {
michael@0 10931 internalSH->ReplaceEntry(index, rootSHEntry);
michael@0 10932 }
michael@0 10933 }
michael@0 10934
michael@0 10935 // Step 6: If the document's URI changed, update document's URI and update
michael@0 10936 // global history.
michael@0 10937 //
michael@0 10938 // We need to call FireOnLocationChange so that the browser's address bar
michael@0 10939 // gets updated and the back button is enabled, but we only need to
michael@0 10940 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
michael@0 10941 // since SetCurrentURI will call FireOnLocationChange for us.
michael@0 10942 //
michael@0 10943 // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
michael@0 10944 // nullptr for aRequest param to FireOnLocationChange(...). Such an update
michael@0 10945 // notification is allowed only when we know docshell is not loading a new
michael@0 10946 // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
michael@0 10947 // FireOnLocationChange(...) breaks security UI.
michael@0 10948 if (!equalURIs) {
michael@0 10949 SetCurrentURI(newURI, nullptr, true, LOCATION_CHANGE_SAME_DOCUMENT);
michael@0 10950 document->SetDocumentURI(newURI);
michael@0 10951
michael@0 10952 AddURIVisit(newURI, oldURI, oldURI, 0);
michael@0 10953
michael@0 10954 // AddURIVisit doesn't set the title for the new URI in global history,
michael@0 10955 // so do that here.
michael@0 10956 if (mUseGlobalHistory && !mInPrivateBrowsing) {
michael@0 10957 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 10958 if (history) {
michael@0 10959 history->SetURITitle(newURI, mTitle);
michael@0 10960 }
michael@0 10961 else if (mGlobalHistory) {
michael@0 10962 mGlobalHistory->SetPageTitle(newURI, mTitle);
michael@0 10963 }
michael@0 10964 }
michael@0 10965
michael@0 10966 // Inform the favicon service that our old favicon applies to this new
michael@0 10967 // URI.
michael@0 10968 CopyFavicon(oldURI, newURI, mInPrivateBrowsing);
michael@0 10969 }
michael@0 10970 else {
michael@0 10971 FireDummyOnLocationChange();
michael@0 10972 }
michael@0 10973 document->SetStateObject(scContainer);
michael@0 10974
michael@0 10975 return NS_OK;
michael@0 10976 }
michael@0 10977
michael@0 10978 bool
michael@0 10979 nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
michael@0 10980 {
michael@0 10981 // I believe none of the about: urls should go in the history. But then
michael@0 10982 // that could just be me... If the intent is only deny about:blank then we
michael@0 10983 // should just do a spec compare, rather than two gets of the scheme and
michael@0 10984 // then the path. -Gagan
michael@0 10985 nsresult rv;
michael@0 10986 nsAutoCString buf, pref;
michael@0 10987
michael@0 10988 rv = aURI->GetScheme(buf);
michael@0 10989 if (NS_FAILED(rv))
michael@0 10990 return false;
michael@0 10991
michael@0 10992 if (buf.Equals("about")) {
michael@0 10993 rv = aURI->GetPath(buf);
michael@0 10994 if (NS_FAILED(rv))
michael@0 10995 return false;
michael@0 10996
michael@0 10997 if (buf.Equals("blank")) {
michael@0 10998 return false;
michael@0 10999 }
michael@0 11000 }
michael@0 11001
michael@0 11002 rv = Preferences::GetDefaultCString("browser.newtab.url", &pref);
michael@0 11003
michael@0 11004 if (NS_FAILED(rv)) {
michael@0 11005 return true;
michael@0 11006 }
michael@0 11007
michael@0 11008 rv = aURI->GetSpec(buf);
michael@0 11009 NS_ENSURE_SUCCESS(rv, true);
michael@0 11010
michael@0 11011 return !buf.Equals(pref);
michael@0 11012 }
michael@0 11013
michael@0 11014 nsresult
michael@0 11015 nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
michael@0 11016 nsISupports* aOwner, bool aCloneChildren,
michael@0 11017 nsISHEntry ** aNewEntry)
michael@0 11018 {
michael@0 11019 NS_PRECONDITION(aURI, "uri is null");
michael@0 11020 NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
michael@0 11021
michael@0 11022 #if defined(PR_LOGGING) && defined(DEBUG)
michael@0 11023 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
michael@0 11024 nsAutoCString spec;
michael@0 11025 aURI->GetSpec(spec);
michael@0 11026
michael@0 11027 nsAutoCString chanName;
michael@0 11028 if (aChannel)
michael@0 11029 aChannel->GetName(chanName);
michael@0 11030 else
michael@0 11031 chanName.AssignLiteral("<no channel>");
michael@0 11032
michael@0 11033 PR_LOG(gDocShellLog, PR_LOG_DEBUG,
michael@0 11034 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(),
michael@0 11035 chanName.get()));
michael@0 11036 }
michael@0 11037 #endif
michael@0 11038
michael@0 11039 nsresult rv = NS_OK;
michael@0 11040 nsCOMPtr<nsISHEntry> entry;
michael@0 11041 bool shouldPersist;
michael@0 11042
michael@0 11043 shouldPersist = ShouldAddToSessionHistory(aURI);
michael@0 11044
michael@0 11045 // Get a handle to the root docshell
michael@0 11046 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 11047 GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 11048 /*
michael@0 11049 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
michael@0 11050 * the existing SH entry in the page and replace the url and
michael@0 11051 * other vitalities.
michael@0 11052 */
michael@0 11053 if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
michael@0 11054 root != static_cast<nsIDocShellTreeItem *>(this)) {
michael@0 11055 // This is a subframe
michael@0 11056 entry = mOSHE;
michael@0 11057 nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
michael@0 11058 if (shContainer) {
michael@0 11059 int32_t childCount = 0;
michael@0 11060 shContainer->GetChildCount(&childCount);
michael@0 11061 // Remove all children of this entry
michael@0 11062 for (int32_t i = childCount - 1; i >= 0; i--) {
michael@0 11063 nsCOMPtr<nsISHEntry> child;
michael@0 11064 shContainer->GetChildAt(i, getter_AddRefs(child));
michael@0 11065 shContainer->RemoveChild(child);
michael@0 11066 } // for
michael@0 11067 entry->AbandonBFCacheEntry();
michael@0 11068 } // shContainer
michael@0 11069 }
michael@0 11070
michael@0 11071 // Create a new entry if necessary.
michael@0 11072 if (!entry) {
michael@0 11073 entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
michael@0 11074
michael@0 11075 if (!entry) {
michael@0 11076 return NS_ERROR_OUT_OF_MEMORY;
michael@0 11077 }
michael@0 11078 }
michael@0 11079
michael@0 11080 // Get the post data & referrer
michael@0 11081 nsCOMPtr<nsIInputStream> inputStream;
michael@0 11082 nsCOMPtr<nsIURI> referrerURI;
michael@0 11083 nsCOMPtr<nsISupports> cacheKey;
michael@0 11084 nsCOMPtr<nsISupports> owner = aOwner;
michael@0 11085 bool expired = false;
michael@0 11086 bool discardLayoutState = false;
michael@0 11087 nsCOMPtr<nsICachingChannel> cacheChannel;
michael@0 11088 if (aChannel) {
michael@0 11089 cacheChannel = do_QueryInterface(aChannel);
michael@0 11090
michael@0 11091 /* If there is a caching channel, get the Cache Key and store it
michael@0 11092 * in SH.
michael@0 11093 */
michael@0 11094 if (cacheChannel) {
michael@0 11095 cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
michael@0 11096 }
michael@0 11097 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
michael@0 11098
michael@0 11099 // Check if the httpChannel is hiding under a multipartChannel
michael@0 11100 if (!httpChannel) {
michael@0 11101 GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
michael@0 11102 }
michael@0 11103 if (httpChannel) {
michael@0 11104 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
michael@0 11105 if (uploadChannel) {
michael@0 11106 uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
michael@0 11107 }
michael@0 11108 httpChannel->GetReferrer(getter_AddRefs(referrerURI));
michael@0 11109
michael@0 11110 discardLayoutState = ShouldDiscardLayoutState(httpChannel);
michael@0 11111 }
michael@0 11112 aChannel->GetOwner(getter_AddRefs(owner));
michael@0 11113 }
michael@0 11114
michael@0 11115 //Title is set in nsDocShell::SetTitle()
michael@0 11116 entry->Create(aURI, // uri
michael@0 11117 EmptyString(), // Title
michael@0 11118 inputStream, // Post data stream
michael@0 11119 nullptr, // LayoutHistory state
michael@0 11120 cacheKey, // CacheKey
michael@0 11121 mContentTypeHint, // Content-type
michael@0 11122 owner, // Channel or provided owner
michael@0 11123 mHistoryID,
michael@0 11124 mDynamicallyCreated);
michael@0 11125 entry->SetReferrerURI(referrerURI);
michael@0 11126 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
michael@0 11127 if (inStrmChan) {
michael@0 11128 bool isSrcdocChannel;
michael@0 11129 inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
michael@0 11130 if (isSrcdocChannel) {
michael@0 11131 nsAutoString srcdoc;
michael@0 11132 inStrmChan->GetSrcdocData(srcdoc);
michael@0 11133 entry->SetSrcdocData(srcdoc);
michael@0 11134 nsCOMPtr<nsIURI> baseURI;
michael@0 11135 inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
michael@0 11136 entry->SetBaseURI(baseURI);
michael@0 11137 }
michael@0 11138 }
michael@0 11139 /* If cache got a 'no-store', ask SH not to store
michael@0 11140 * HistoryLayoutState. By default, SH will set this
michael@0 11141 * flag to true and save HistoryLayoutState.
michael@0 11142 */
michael@0 11143 if (discardLayoutState) {
michael@0 11144 entry->SetSaveLayoutStateFlag(false);
michael@0 11145 }
michael@0 11146 if (cacheChannel) {
michael@0 11147 // Check if the page has expired from cache
michael@0 11148 uint32_t expTime = 0;
michael@0 11149 cacheChannel->GetCacheTokenExpirationTime(&expTime);
michael@0 11150 uint32_t now = PRTimeToSeconds(PR_Now());
michael@0 11151 if (expTime <= now)
michael@0 11152 expired = true;
michael@0 11153 }
michael@0 11154 if (expired)
michael@0 11155 entry->SetExpirationStatus(true);
michael@0 11156
michael@0 11157
michael@0 11158 if (root == static_cast<nsIDocShellTreeItem *>(this) && mSessionHistory) {
michael@0 11159 // If we need to clone our children onto the new session
michael@0 11160 // history entry, do so now.
michael@0 11161 if (aCloneChildren && mOSHE) {
michael@0 11162 uint32_t cloneID;
michael@0 11163 mOSHE->GetID(&cloneID);
michael@0 11164 nsCOMPtr<nsISHEntry> newEntry;
michael@0 11165 CloneAndReplace(mOSHE, this, cloneID, entry, true, getter_AddRefs(newEntry));
michael@0 11166 NS_ASSERTION(entry == newEntry, "The new session history should be in the new entry");
michael@0 11167 }
michael@0 11168
michael@0 11169 // This is the root docshell
michael@0 11170 if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
michael@0 11171 // Replace current entry in session history.
michael@0 11172 int32_t index = 0;
michael@0 11173 mSessionHistory->GetIndex(&index);
michael@0 11174 nsCOMPtr<nsISHistoryInternal> shPrivate(do_QueryInterface(mSessionHistory));
michael@0 11175 // Replace the current entry with the new entry
michael@0 11176 if (shPrivate)
michael@0 11177 rv = shPrivate->ReplaceEntry(index, entry);
michael@0 11178 }
michael@0 11179 else {
michael@0 11180 // Add to session history
michael@0 11181 nsCOMPtr<nsISHistoryInternal>
michael@0 11182 shPrivate(do_QueryInterface(mSessionHistory));
michael@0 11183 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
michael@0 11184 mSessionHistory->GetIndex(&mPreviousTransIndex);
michael@0 11185 rv = shPrivate->AddEntry(entry, shouldPersist);
michael@0 11186 mSessionHistory->GetIndex(&mLoadedTransIndex);
michael@0 11187 #ifdef DEBUG_PAGE_CACHE
michael@0 11188 printf("Previous index: %d, Loaded index: %d\n\n",
michael@0 11189 mPreviousTransIndex, mLoadedTransIndex);
michael@0 11190 #endif
michael@0 11191 }
michael@0 11192 }
michael@0 11193 else {
michael@0 11194 // This is a subframe.
michael@0 11195 if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
michael@0 11196 LOAD_FLAGS_REPLACE_HISTORY))
michael@0 11197 rv = DoAddChildSHEntry(entry, mChildOffset, aCloneChildren);
michael@0 11198 }
michael@0 11199
michael@0 11200 // Return the new SH entry...
michael@0 11201 if (aNewEntry) {
michael@0 11202 *aNewEntry = nullptr;
michael@0 11203 if (NS_SUCCEEDED(rv)) {
michael@0 11204 *aNewEntry = entry;
michael@0 11205 NS_ADDREF(*aNewEntry);
michael@0 11206 }
michael@0 11207 }
michael@0 11208
michael@0 11209 return rv;
michael@0 11210 }
michael@0 11211
michael@0 11212
michael@0 11213 NS_IMETHODIMP
michael@0 11214 nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType)
michael@0 11215 {
michael@0 11216 if (!IsNavigationAllowed()) {
michael@0 11217 return NS_OK;
michael@0 11218 }
michael@0 11219
michael@0 11220 nsCOMPtr<nsIURI> uri;
michael@0 11221 nsCOMPtr<nsIInputStream> postData;
michael@0 11222 nsCOMPtr<nsIURI> referrerURI;
michael@0 11223 nsAutoCString contentType;
michael@0 11224 nsCOMPtr<nsISupports> owner;
michael@0 11225
michael@0 11226 NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
michael@0 11227
michael@0 11228 NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
michael@0 11229 NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
michael@0 11230 NS_ERROR_FAILURE);
michael@0 11231 NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
michael@0 11232 NS_ERROR_FAILURE);
michael@0 11233 NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
michael@0 11234 NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)),
michael@0 11235 NS_ERROR_FAILURE);
michael@0 11236
michael@0 11237 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
michael@0 11238 // that's the only thing holding a ref to aEntry that will cause aEntry to
michael@0 11239 // die while we're loading it. So hold a strong ref to aEntry here, just
michael@0 11240 // in case.
michael@0 11241 nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
michael@0 11242 bool isJS;
michael@0 11243 nsresult rv = uri->SchemeIs("javascript", &isJS);
michael@0 11244 if (NS_FAILED(rv) || isJS) {
michael@0 11245 // We're loading a URL that will execute script from inside asyncOpen.
michael@0 11246 // Replace the current document with about:blank now to prevent
michael@0 11247 // anything from the current document from leaking into any JavaScript
michael@0 11248 // code in the URL.
michael@0 11249 nsCOMPtr<nsIPrincipal> prin = do_QueryInterface(owner);
michael@0 11250 // Don't cache the presentation if we're going to just reload the
michael@0 11251 // current entry. Caching would lead to trying to save the different
michael@0 11252 // content viewers in the same nsISHEntry object.
michael@0 11253 rv = CreateAboutBlankContentViewer(prin, nullptr, aEntry != mOSHE);
michael@0 11254
michael@0 11255 if (NS_FAILED(rv)) {
michael@0 11256 // The creation of the intermittent about:blank content
michael@0 11257 // viewer failed for some reason (potentially because the
michael@0 11258 // user prevented it). Interrupt the history load.
michael@0 11259 return NS_OK;
michael@0 11260 }
michael@0 11261
michael@0 11262 if (!owner) {
michael@0 11263 // Ensure that we have an owner. Otherwise javascript: URIs will
michael@0 11264 // pick it up from the about:blank page we just loaded, and we
michael@0 11265 // don't really want even that in this case.
michael@0 11266 owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
michael@0 11267 NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY);
michael@0 11268 }
michael@0 11269 }
michael@0 11270
michael@0 11271 /* If there is a valid postdata *and* the user pressed
michael@0 11272 * reload or shift-reload, take user's permission before we
michael@0 11273 * repost the data to the server.
michael@0 11274 */
michael@0 11275 if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
michael@0 11276 bool repost;
michael@0 11277 rv = ConfirmRepost(&repost);
michael@0 11278 if (NS_FAILED(rv)) return rv;
michael@0 11279
michael@0 11280 // If the user pressed cancel in the dialog, return. We're done here.
michael@0 11281 if (!repost)
michael@0 11282 return NS_BINDING_ABORTED;
michael@0 11283 }
michael@0 11284
michael@0 11285 // Do not inherit owner from document (security-critical!);
michael@0 11286 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
michael@0 11287
michael@0 11288 nsAutoString srcdoc;
michael@0 11289 bool isSrcdoc;
michael@0 11290 nsCOMPtr<nsIURI> baseURI;
michael@0 11291 aEntry->GetIsSrcdocEntry(&isSrcdoc);
michael@0 11292 if (isSrcdoc) {
michael@0 11293 aEntry->GetSrcdocData(srcdoc);
michael@0 11294 aEntry->GetBaseURI(getter_AddRefs(baseURI));
michael@0 11295 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
michael@0 11296 }
michael@0 11297 else {
michael@0 11298 srcdoc = NullString();
michael@0 11299 }
michael@0 11300
michael@0 11301 // Passing nullptr as aSourceDocShell gives the same behaviour as before
michael@0 11302 // aSourceDocShell was introduced. According to spec we should be passing
michael@0 11303 // the source browsing context that was used when the history entry was
michael@0 11304 // first created. bug 947716 has been created to address this issue.
michael@0 11305 rv = InternalLoad(uri,
michael@0 11306 referrerURI,
michael@0 11307 owner,
michael@0 11308 flags,
michael@0 11309 nullptr, // No window target
michael@0 11310 contentType.get(), // Type hint
michael@0 11311 NullString(), // No forced file download
michael@0 11312 postData, // Post data stream
michael@0 11313 nullptr, // No headers stream
michael@0 11314 aLoadType, // Load type
michael@0 11315 aEntry, // SHEntry
michael@0 11316 true,
michael@0 11317 srcdoc,
michael@0 11318 nullptr, // Source docshell, see comment above
michael@0 11319 baseURI,
michael@0 11320 nullptr, // No nsIDocShell
michael@0 11321 nullptr); // No nsIRequest
michael@0 11322 return rv;
michael@0 11323 }
michael@0 11324
michael@0 11325 NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(bool* aShould)
michael@0 11326 {
michael@0 11327 *aShould = false;
michael@0 11328 if (mOSHE) {
michael@0 11329 // Don't capture historystate and save it in history
michael@0 11330 // if the page asked not to do so.
michael@0 11331 mOSHE->GetSaveLayoutStateFlag(aShould);
michael@0 11332 }
michael@0 11333
michael@0 11334 return NS_OK;
michael@0 11335 }
michael@0 11336
michael@0 11337 NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState()
michael@0 11338 {
michael@0 11339 nsresult rv = NS_OK;
michael@0 11340
michael@0 11341 if (mOSHE) {
michael@0 11342 nsCOMPtr<nsIPresShell> shell = GetPresShell();
michael@0 11343 if (shell) {
michael@0 11344 nsCOMPtr<nsILayoutHistoryState> layoutState;
michael@0 11345 rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
michael@0 11346 }
michael@0 11347 }
michael@0 11348
michael@0 11349 return rv;
michael@0 11350 }
michael@0 11351
michael@0 11352 /* static */ nsresult
michael@0 11353 nsDocShell::WalkHistoryEntries(nsISHEntry *aRootEntry,
michael@0 11354 nsDocShell *aRootShell,
michael@0 11355 WalkHistoryEntriesFunc aCallback,
michael@0 11356 void *aData)
michael@0 11357 {
michael@0 11358 NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
michael@0 11359
michael@0 11360 nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
michael@0 11361 if (!container)
michael@0 11362 return NS_ERROR_FAILURE;
michael@0 11363
michael@0 11364 int32_t childCount;
michael@0 11365 container->GetChildCount(&childCount);
michael@0 11366 for (int32_t i = 0; i < childCount; i++) {
michael@0 11367 nsCOMPtr<nsISHEntry> childEntry;
michael@0 11368 container->GetChildAt(i, getter_AddRefs(childEntry));
michael@0 11369 if (!childEntry) {
michael@0 11370 // childEntry can be null for valid reasons, for example if the
michael@0 11371 // docshell at index i never loaded anything useful.
michael@0 11372 // Remember to clone also nulls in the child array (bug 464064).
michael@0 11373 aCallback(nullptr, nullptr, i, aData);
michael@0 11374 continue;
michael@0 11375 }
michael@0 11376
michael@0 11377 nsDocShell *childShell = nullptr;
michael@0 11378 if (aRootShell) {
michael@0 11379 // Walk the children of aRootShell and see if one of them
michael@0 11380 // has srcChild as a SHEntry.
michael@0 11381
michael@0 11382 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(aRootShell->mChildList);
michael@0 11383 while (iter.HasMore()) {
michael@0 11384 nsDocShell *child = static_cast<nsDocShell*>(iter.GetNext());
michael@0 11385
michael@0 11386 if (child->HasHistoryEntry(childEntry)) {
michael@0 11387 childShell = child;
michael@0 11388 break;
michael@0 11389 }
michael@0 11390 }
michael@0 11391 }
michael@0 11392 nsresult rv = aCallback(childEntry, childShell, i, aData);
michael@0 11393 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11394 }
michael@0 11395
michael@0 11396 return NS_OK;
michael@0 11397 }
michael@0 11398
michael@0 11399 // callback data for WalkHistoryEntries
michael@0 11400 struct MOZ_STACK_CLASS CloneAndReplaceData
michael@0 11401 {
michael@0 11402 CloneAndReplaceData(uint32_t aCloneID, nsISHEntry *aReplaceEntry,
michael@0 11403 bool aCloneChildren, nsISHEntry *aDestTreeParent)
michael@0 11404 : cloneID(aCloneID),
michael@0 11405 cloneChildren(aCloneChildren),
michael@0 11406 replaceEntry(aReplaceEntry),
michael@0 11407 destTreeParent(aDestTreeParent) { }
michael@0 11408
michael@0 11409 uint32_t cloneID;
michael@0 11410 bool cloneChildren;
michael@0 11411 nsISHEntry *replaceEntry;
michael@0 11412 nsISHEntry *destTreeParent;
michael@0 11413 nsCOMPtr<nsISHEntry> resultEntry;
michael@0 11414 };
michael@0 11415
michael@0 11416 /* static */ nsresult
michael@0 11417 nsDocShell::CloneAndReplaceChild(nsISHEntry *aEntry, nsDocShell *aShell,
michael@0 11418 int32_t aEntryIndex, void *aData)
michael@0 11419 {
michael@0 11420 nsCOMPtr<nsISHEntry> dest;
michael@0 11421
michael@0 11422 CloneAndReplaceData *data = static_cast<CloneAndReplaceData*>(aData);
michael@0 11423 uint32_t cloneID = data->cloneID;
michael@0 11424 nsISHEntry *replaceEntry = data->replaceEntry;
michael@0 11425
michael@0 11426 nsCOMPtr<nsISHContainer> container =
michael@0 11427 do_QueryInterface(data->destTreeParent);
michael@0 11428 if (!aEntry) {
michael@0 11429 if (container) {
michael@0 11430 container->AddChild(nullptr, aEntryIndex);
michael@0 11431 }
michael@0 11432 return NS_OK;
michael@0 11433 }
michael@0 11434
michael@0 11435 uint32_t srcID;
michael@0 11436 aEntry->GetID(&srcID);
michael@0 11437
michael@0 11438 nsresult rv = NS_OK;
michael@0 11439 if (srcID == cloneID) {
michael@0 11440 // Replace the entry
michael@0 11441 dest = replaceEntry;
michael@0 11442 } else {
michael@0 11443 // Clone the SHEntry...
michael@0 11444 rv = aEntry->Clone(getter_AddRefs(dest));
michael@0 11445 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11446 }
michael@0 11447 dest->SetIsSubFrame(true);
michael@0 11448
michael@0 11449 if (srcID != cloneID || data->cloneChildren) {
michael@0 11450 // Walk the children
michael@0 11451 CloneAndReplaceData childData(cloneID, replaceEntry,
michael@0 11452 data->cloneChildren, dest);
michael@0 11453 rv = WalkHistoryEntries(aEntry, aShell,
michael@0 11454 CloneAndReplaceChild, &childData);
michael@0 11455 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11456 }
michael@0 11457
michael@0 11458 if (srcID != cloneID && aShell) {
michael@0 11459 aShell->SwapHistoryEntries(aEntry, dest);
michael@0 11460 }
michael@0 11461
michael@0 11462 if (container)
michael@0 11463 container->AddChild(dest, aEntryIndex);
michael@0 11464
michael@0 11465 data->resultEntry = dest;
michael@0 11466 return rv;
michael@0 11467 }
michael@0 11468
michael@0 11469 /* static */ nsresult
michael@0 11470 nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
michael@0 11471 nsDocShell *aSrcShell,
michael@0 11472 uint32_t aCloneID,
michael@0 11473 nsISHEntry *aReplaceEntry,
michael@0 11474 bool aCloneChildren,
michael@0 11475 nsISHEntry **aResultEntry)
michael@0 11476 {
michael@0 11477 NS_ENSURE_ARG_POINTER(aResultEntry);
michael@0 11478 NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
michael@0 11479
michael@0 11480 CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr);
michael@0 11481 nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
michael@0 11482
michael@0 11483 data.resultEntry.swap(*aResultEntry);
michael@0 11484 return rv;
michael@0 11485 }
michael@0 11486
michael@0 11487 void
michael@0 11488 nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
michael@0 11489 {
michael@0 11490 if (aOldEntry == mOSHE)
michael@0 11491 mOSHE = aNewEntry;
michael@0 11492
michael@0 11493 if (aOldEntry == mLSHE)
michael@0 11494 mLSHE = aNewEntry;
michael@0 11495 }
michael@0 11496
michael@0 11497
michael@0 11498 struct SwapEntriesData
michael@0 11499 {
michael@0 11500 nsDocShell *ignoreShell; // constant; the shell to ignore
michael@0 11501 nsISHEntry *destTreeRoot; // constant; the root of the dest tree
michael@0 11502 nsISHEntry *destTreeParent; // constant; the node under destTreeRoot
michael@0 11503 // whose children will correspond to aEntry
michael@0 11504 };
michael@0 11505
michael@0 11506
michael@0 11507 nsresult
michael@0 11508 nsDocShell::SetChildHistoryEntry(nsISHEntry *aEntry, nsDocShell *aShell,
michael@0 11509 int32_t aEntryIndex, void *aData)
michael@0 11510 {
michael@0 11511 SwapEntriesData *data = static_cast<SwapEntriesData*>(aData);
michael@0 11512 nsDocShell *ignoreShell = data->ignoreShell;
michael@0 11513
michael@0 11514 if (!aShell || aShell == ignoreShell)
michael@0 11515 return NS_OK;
michael@0 11516
michael@0 11517 nsISHEntry *destTreeRoot = data->destTreeRoot;
michael@0 11518
michael@0 11519 nsCOMPtr<nsISHEntry> destEntry;
michael@0 11520 nsCOMPtr<nsISHContainer> container =
michael@0 11521 do_QueryInterface(data->destTreeParent);
michael@0 11522
michael@0 11523 if (container) {
michael@0 11524 // aEntry is a clone of some child of destTreeParent, but since the
michael@0 11525 // trees aren't necessarily in sync, we'll have to locate it.
michael@0 11526 // Note that we could set aShell's entry to null if we don't find a
michael@0 11527 // corresponding entry under destTreeParent.
michael@0 11528
michael@0 11529 uint32_t targetID, id;
michael@0 11530 aEntry->GetID(&targetID);
michael@0 11531
michael@0 11532 // First look at the given index, since this is the common case.
michael@0 11533 nsCOMPtr<nsISHEntry> entry;
michael@0 11534 container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
michael@0 11535 if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
michael@0 11536 destEntry.swap(entry);
michael@0 11537 } else {
michael@0 11538 int32_t childCount;
michael@0 11539 container->GetChildCount(&childCount);
michael@0 11540 for (int32_t i = 0; i < childCount; ++i) {
michael@0 11541 container->GetChildAt(i, getter_AddRefs(entry));
michael@0 11542 if (!entry)
michael@0 11543 continue;
michael@0 11544
michael@0 11545 entry->GetID(&id);
michael@0 11546 if (id == targetID) {
michael@0 11547 destEntry.swap(entry);
michael@0 11548 break;
michael@0 11549 }
michael@0 11550 }
michael@0 11551 }
michael@0 11552 } else {
michael@0 11553 destEntry = destTreeRoot;
michael@0 11554 }
michael@0 11555
michael@0 11556 aShell->SwapHistoryEntries(aEntry, destEntry);
michael@0 11557
michael@0 11558 // Now handle the children of aEntry.
michael@0 11559 SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
michael@0 11560 return WalkHistoryEntries(aEntry, aShell,
michael@0 11561 SetChildHistoryEntry, &childData);
michael@0 11562 }
michael@0 11563
michael@0 11564
michael@0 11565 static nsISHEntry*
michael@0 11566 GetRootSHEntry(nsISHEntry *aEntry)
michael@0 11567 {
michael@0 11568 nsCOMPtr<nsISHEntry> rootEntry = aEntry;
michael@0 11569 nsISHEntry *result = nullptr;
michael@0 11570 while (rootEntry) {
michael@0 11571 result = rootEntry;
michael@0 11572 result->GetParent(getter_AddRefs(rootEntry));
michael@0 11573 }
michael@0 11574
michael@0 11575 return result;
michael@0 11576 }
michael@0 11577
michael@0 11578
michael@0 11579 void
michael@0 11580 nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry> *aPtr, nsISHEntry *aEntry)
michael@0 11581 {
michael@0 11582 // We need to sync up the docshell and session history trees for
michael@0 11583 // subframe navigation. If the load was in a subframe, we forward up to
michael@0 11584 // the root docshell, which will then recursively sync up all docshells
michael@0 11585 // to their corresponding entries in the new session history tree.
michael@0 11586 // If we don't do this, then we can cache a content viewer on the wrong
michael@0 11587 // cloned entry, and subsequently restore it at the wrong time.
michael@0 11588
michael@0 11589 nsISHEntry *newRootEntry = GetRootSHEntry(aEntry);
michael@0 11590 if (newRootEntry) {
michael@0 11591 // newRootEntry is now the new root entry.
michael@0 11592 // Find the old root entry as well.
michael@0 11593
michael@0 11594 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
michael@0 11595 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
michael@0 11596 nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
michael@0 11597 if (oldRootEntry) {
michael@0 11598 nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
michael@0 11599 GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
michael@0 11600 nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
michael@0 11601 if (rootShell) { // if we're the root just set it, nothing to swap
michael@0 11602 SwapEntriesData data = { this, newRootEntry };
michael@0 11603 nsIDocShell *rootIDocShell =
michael@0 11604 static_cast<nsIDocShell*>(rootShell);
michael@0 11605 nsDocShell *rootDocShell = static_cast<nsDocShell*>
michael@0 11606 (rootIDocShell);
michael@0 11607
michael@0 11608 #ifdef DEBUG
michael@0 11609 nsresult rv =
michael@0 11610 #endif
michael@0 11611 SetChildHistoryEntry(oldRootEntry, rootDocShell,
michael@0 11612 0, &data);
michael@0 11613 NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
michael@0 11614 }
michael@0 11615 }
michael@0 11616 }
michael@0 11617
michael@0 11618 *aPtr = aEntry;
michael@0 11619 }
michael@0 11620
michael@0 11621
michael@0 11622 nsresult
michael@0 11623 nsDocShell::GetRootSessionHistory(nsISHistory ** aReturn)
michael@0 11624 {
michael@0 11625 nsresult rv;
michael@0 11626
michael@0 11627 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 11628 //Get the root docshell
michael@0 11629 rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 11630 // QI to nsIWebNavigation
michael@0 11631 nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
michael@0 11632 if (rootAsWebnav) {
michael@0 11633 // Get the handle to SH from the root docshell
michael@0 11634 rv = rootAsWebnav->GetSessionHistory(aReturn);
michael@0 11635 }
michael@0 11636 return rv;
michael@0 11637 }
michael@0 11638
michael@0 11639 nsresult
michael@0 11640 nsDocShell::GetHttpChannel(nsIChannel * aChannel, nsIHttpChannel ** aReturn)
michael@0 11641 {
michael@0 11642 NS_ENSURE_ARG_POINTER(aReturn);
michael@0 11643 if (!aChannel)
michael@0 11644 return NS_ERROR_FAILURE;
michael@0 11645
michael@0 11646 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
michael@0 11647 if (multiPartChannel) {
michael@0 11648 nsCOMPtr<nsIChannel> baseChannel;
michael@0 11649 multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
michael@0 11650 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
michael@0 11651 *aReturn = httpChannel;
michael@0 11652 NS_IF_ADDREF(*aReturn);
michael@0 11653 }
michael@0 11654 return NS_OK;
michael@0 11655 }
michael@0 11656
michael@0 11657 bool
michael@0 11658 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel)
michael@0 11659 {
michael@0 11660 // By default layout State will be saved.
michael@0 11661 if (!aChannel)
michael@0 11662 return false;
michael@0 11663
michael@0 11664 // figure out if SH should be saving layout state
michael@0 11665 nsCOMPtr<nsISupports> securityInfo;
michael@0 11666 bool noStore = false, noCache = false;
michael@0 11667 aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
michael@0 11668 aChannel->IsNoStoreResponse(&noStore);
michael@0 11669 aChannel->IsNoCacheResponse(&noCache);
michael@0 11670
michael@0 11671 return (noStore || (noCache && securityInfo));
michael@0 11672 }
michael@0 11673
michael@0 11674 NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
michael@0 11675 {
michael@0 11676 NS_ENSURE_ARG_POINTER(aEditor);
michael@0 11677
michael@0 11678 if (!mEditorData) {
michael@0 11679 *aEditor = nullptr;
michael@0 11680 return NS_OK;
michael@0 11681 }
michael@0 11682
michael@0 11683 return mEditorData->GetEditor(aEditor);
michael@0 11684 }
michael@0 11685
michael@0 11686 NS_IMETHODIMP nsDocShell::SetEditor(nsIEditor * aEditor)
michael@0 11687 {
michael@0 11688 nsresult rv = EnsureEditorData();
michael@0 11689 if (NS_FAILED(rv)) return rv;
michael@0 11690
michael@0 11691 return mEditorData->SetEditor(aEditor);
michael@0 11692 }
michael@0 11693
michael@0 11694
michael@0 11695 NS_IMETHODIMP nsDocShell::GetEditable(bool *aEditable)
michael@0 11696 {
michael@0 11697 NS_ENSURE_ARG_POINTER(aEditable);
michael@0 11698 *aEditable = mEditorData && mEditorData->GetEditable();
michael@0 11699 return NS_OK;
michael@0 11700 }
michael@0 11701
michael@0 11702
michael@0 11703 NS_IMETHODIMP nsDocShell::GetHasEditingSession(bool *aHasEditingSession)
michael@0 11704 {
michael@0 11705 NS_ENSURE_ARG_POINTER(aHasEditingSession);
michael@0 11706
michael@0 11707 if (mEditorData)
michael@0 11708 {
michael@0 11709 nsCOMPtr<nsIEditingSession> editingSession;
michael@0 11710 mEditorData->GetEditingSession(getter_AddRefs(editingSession));
michael@0 11711 *aHasEditingSession = (editingSession.get() != nullptr);
michael@0 11712 }
michael@0 11713 else
michael@0 11714 {
michael@0 11715 *aHasEditingSession = false;
michael@0 11716 }
michael@0 11717
michael@0 11718 return NS_OK;
michael@0 11719 }
michael@0 11720
michael@0 11721 NS_IMETHODIMP nsDocShell::MakeEditable(bool inWaitForUriLoad)
michael@0 11722 {
michael@0 11723 nsresult rv = EnsureEditorData();
michael@0 11724 if (NS_FAILED(rv)) return rv;
michael@0 11725
michael@0 11726 return mEditorData->MakeEditable(inWaitForUriLoad);
michael@0 11727 }
michael@0 11728
michael@0 11729 bool
michael@0 11730 nsDocShell::ChannelIsPost(nsIChannel* aChannel)
michael@0 11731 {
michael@0 11732 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
michael@0 11733 if (!httpChannel) {
michael@0 11734 return false;
michael@0 11735 }
michael@0 11736
michael@0 11737 nsAutoCString method;
michael@0 11738 httpChannel->GetRequestMethod(method);
michael@0 11739 return method.Equals("POST");
michael@0 11740 }
michael@0 11741
michael@0 11742 void
michael@0 11743 nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
michael@0 11744 nsIURI** aURI,
michael@0 11745 uint32_t* aChannelRedirectFlags)
michael@0 11746 {
michael@0 11747 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
michael@0 11748 if (!props) {
michael@0 11749 return;
michael@0 11750 }
michael@0 11751
michael@0 11752 nsresult rv = props->GetPropertyAsInterface(
michael@0 11753 NS_LITERAL_STRING("docshell.previousURI"),
michael@0 11754 NS_GET_IID(nsIURI),
michael@0 11755 reinterpret_cast<void**>(aURI)
michael@0 11756 );
michael@0 11757
michael@0 11758 if (NS_FAILED(rv)) {
michael@0 11759 // There is no last visit for this channel, so this must be the first
michael@0 11760 // link. Link the visit to the referrer of this request, if any.
michael@0 11761 // Treat referrer as null if there is an error getting it.
michael@0 11762 (void)NS_GetReferrerFromChannel(aChannel, aURI);
michael@0 11763 }
michael@0 11764 else {
michael@0 11765 rv = props->GetPropertyAsUint32(
michael@0 11766 NS_LITERAL_STRING("docshell.previousFlags"),
michael@0 11767 aChannelRedirectFlags
michael@0 11768 );
michael@0 11769
michael@0 11770 NS_WARN_IF_FALSE(
michael@0 11771 NS_SUCCEEDED(rv),
michael@0 11772 "Could not fetch previous flags, URI will be treated like referrer"
michael@0 11773 );
michael@0 11774 }
michael@0 11775 }
michael@0 11776
michael@0 11777 void
michael@0 11778 nsDocShell::SaveLastVisit(nsIChannel* aChannel,
michael@0 11779 nsIURI* aURI,
michael@0 11780 uint32_t aChannelRedirectFlags)
michael@0 11781 {
michael@0 11782 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
michael@0 11783 if (!props || !aURI) {
michael@0 11784 return;
michael@0 11785 }
michael@0 11786
michael@0 11787 props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
michael@0 11788 aURI);
michael@0 11789 props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
michael@0 11790 aChannelRedirectFlags);
michael@0 11791 }
michael@0 11792
michael@0 11793 void
michael@0 11794 nsDocShell::AddURIVisit(nsIURI* aURI,
michael@0 11795 nsIURI* aReferrerURI,
michael@0 11796 nsIURI* aPreviousURI,
michael@0 11797 uint32_t aChannelRedirectFlags,
michael@0 11798 uint32_t aResponseStatus)
michael@0 11799 {
michael@0 11800 MOZ_ASSERT(aURI, "Visited URI is null!");
michael@0 11801 MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE &&
michael@0 11802 mLoadType != LOAD_BYPASS_HISTORY,
michael@0 11803 "Do not add error or bypass pages to global history");
michael@0 11804
michael@0 11805 // Only content-type docshells save URI visits. Also don't do
michael@0 11806 // anything here if we're not supposed to use global history.
michael@0 11807 if (mItemType != typeContent || !mUseGlobalHistory || mInPrivateBrowsing) {
michael@0 11808 return;
michael@0 11809 }
michael@0 11810
michael@0 11811 nsCOMPtr<IHistory> history = services::GetHistoryService();
michael@0 11812
michael@0 11813 if (history) {
michael@0 11814 uint32_t visitURIFlags = 0;
michael@0 11815
michael@0 11816 if (!IsFrame()) {
michael@0 11817 visitURIFlags |= IHistory::TOP_LEVEL;
michael@0 11818 }
michael@0 11819
michael@0 11820 if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
michael@0 11821 visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
michael@0 11822 }
michael@0 11823 else if (aChannelRedirectFlags &
michael@0 11824 nsIChannelEventSink::REDIRECT_PERMANENT) {
michael@0 11825 visitURIFlags |= IHistory::REDIRECT_PERMANENT;
michael@0 11826 }
michael@0 11827
michael@0 11828 if (aResponseStatus >= 300 && aResponseStatus < 400) {
michael@0 11829 visitURIFlags |= IHistory::REDIRECT_SOURCE;
michael@0 11830 }
michael@0 11831 // Errors 400-501 and 505 are considered unrecoverable, in the sense a
michael@0 11832 // simple retry attempt by the user is unlikely to solve them.
michael@0 11833 // 408 is special cased, since may actually indicate a temporary
michael@0 11834 // connection problem.
michael@0 11835 else if (aResponseStatus != 408 &&
michael@0 11836 ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
michael@0 11837 aResponseStatus == 505)) {
michael@0 11838 visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
michael@0 11839 }
michael@0 11840
michael@0 11841 (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
michael@0 11842 }
michael@0 11843 else if (mGlobalHistory) {
michael@0 11844 // Falls back to sync global history interface.
michael@0 11845 (void)mGlobalHistory->AddURI(aURI,
michael@0 11846 !!aChannelRedirectFlags,
michael@0 11847 !IsFrame(),
michael@0 11848 aReferrerURI);
michael@0 11849 }
michael@0 11850 }
michael@0 11851
michael@0 11852 //*****************************************************************************
michael@0 11853 // nsDocShell: Helper Routines
michael@0 11854 //*****************************************************************************
michael@0 11855
michael@0 11856 NS_IMETHODIMP
michael@0 11857 nsDocShell::SetLoadType(uint32_t aLoadType)
michael@0 11858 {
michael@0 11859 mLoadType = aLoadType;
michael@0 11860 return NS_OK;
michael@0 11861 }
michael@0 11862
michael@0 11863 NS_IMETHODIMP
michael@0 11864 nsDocShell::GetLoadType(uint32_t * aLoadType)
michael@0 11865 {
michael@0 11866 *aLoadType = mLoadType;
michael@0 11867 return NS_OK;
michael@0 11868 }
michael@0 11869
michael@0 11870 nsresult
michael@0 11871 nsDocShell::ConfirmRepost(bool * aRepost)
michael@0 11872 {
michael@0 11873 nsCOMPtr<nsIPrompt> prompter;
michael@0 11874 CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
michael@0 11875 if (!prompter) {
michael@0 11876 return NS_ERROR_NOT_AVAILABLE;
michael@0 11877 }
michael@0 11878
michael@0 11879 nsCOMPtr<nsIStringBundleService> stringBundleService =
michael@0 11880 mozilla::services::GetStringBundleService();
michael@0 11881 if (!stringBundleService)
michael@0 11882 return NS_ERROR_FAILURE;
michael@0 11883
michael@0 11884 nsCOMPtr<nsIStringBundle> appBundle;
michael@0 11885 nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
michael@0 11886 getter_AddRefs(appBundle));
michael@0 11887 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11888
michael@0 11889 nsCOMPtr<nsIStringBundle> brandBundle;
michael@0 11890 rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle));
michael@0 11891 NS_ENSURE_SUCCESS(rv, rv);
michael@0 11892
michael@0 11893 NS_ASSERTION(prompter && brandBundle && appBundle,
michael@0 11894 "Unable to set up repost prompter.");
michael@0 11895
michael@0 11896 nsXPIDLString brandName;
michael@0 11897 rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"),
michael@0 11898 getter_Copies(brandName));
michael@0 11899
michael@0 11900 nsXPIDLString msgString, button0Title;
michael@0 11901 if (NS_FAILED(rv)) { // No brand, use the generic version.
michael@0 11902 rv = appBundle->GetStringFromName(MOZ_UTF16("confirmRepostPrompt"),
michael@0 11903 getter_Copies(msgString));
michael@0 11904 }
michael@0 11905 else {
michael@0 11906 // Brand available - if the app has an override file with formatting, the app name will
michael@0 11907 // be included. Without an override, the prompt will look like the generic version.
michael@0 11908 const char16_t *formatStrings[] = { brandName.get() };
michael@0 11909 rv = appBundle->FormatStringFromName(MOZ_UTF16("confirmRepostPrompt"),
michael@0 11910 formatStrings, ArrayLength(formatStrings),
michael@0 11911 getter_Copies(msgString));
michael@0 11912 }
michael@0 11913 if (NS_FAILED(rv)) return rv;
michael@0 11914
michael@0 11915 rv = appBundle->GetStringFromName(MOZ_UTF16("resendButton.label"),
michael@0 11916 getter_Copies(button0Title));
michael@0 11917 if (NS_FAILED(rv)) return rv;
michael@0 11918
michael@0 11919 int32_t buttonPressed;
michael@0 11920 // The actual value here is irrelevant, but we can't pass an invalid
michael@0 11921 // bool through XPConnect.
michael@0 11922 bool checkState = false;
michael@0 11923 rv = prompter->
michael@0 11924 ConfirmEx(nullptr, msgString.get(),
michael@0 11925 (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
michael@0 11926 (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
michael@0 11927 button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed);
michael@0 11928 if (NS_FAILED(rv)) return rv;
michael@0 11929
michael@0 11930 *aRepost = (buttonPressed == 0);
michael@0 11931 return NS_OK;
michael@0 11932 }
michael@0 11933
michael@0 11934 NS_IMETHODIMP
michael@0 11935 nsDocShell::GetPromptAndStringBundle(nsIPrompt ** aPrompt,
michael@0 11936 nsIStringBundle ** aStringBundle)
michael@0 11937 {
michael@0 11938 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void **) aPrompt),
michael@0 11939 NS_ERROR_FAILURE);
michael@0 11940
michael@0 11941 nsCOMPtr<nsIStringBundleService> stringBundleService =
michael@0 11942 mozilla::services::GetStringBundleService();
michael@0 11943 NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
michael@0 11944
michael@0 11945 NS_ENSURE_SUCCESS(stringBundleService->
michael@0 11946 CreateBundle(kAppstringsBundleURL,
michael@0 11947 aStringBundle),
michael@0 11948 NS_ERROR_FAILURE);
michael@0 11949
michael@0 11950 return NS_OK;
michael@0 11951 }
michael@0 11952
michael@0 11953 NS_IMETHODIMP
michael@0 11954 nsDocShell::GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent,
michael@0 11955 int32_t * aOffset)
michael@0 11956 {
michael@0 11957 NS_ENSURE_ARG_POINTER(aChild || aParent);
michael@0 11958
michael@0 11959 nsCOMPtr<nsIDOMNodeList> childNodes;
michael@0 11960 NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
michael@0 11961 NS_ERROR_FAILURE);
michael@0 11962 NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
michael@0 11963
michael@0 11964 int32_t i = 0;
michael@0 11965
michael@0 11966 for (; true; i++) {
michael@0 11967 nsCOMPtr<nsIDOMNode> childNode;
michael@0 11968 NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
michael@0 11969 NS_ERROR_FAILURE);
michael@0 11970 NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
michael@0 11971
michael@0 11972 if (childNode.get() == aChild) {
michael@0 11973 *aOffset = i;
michael@0 11974 return NS_OK;
michael@0 11975 }
michael@0 11976 }
michael@0 11977
michael@0 11978 return NS_ERROR_FAILURE;
michael@0 11979 }
michael@0 11980
michael@0 11981 nsIScrollableFrame *
michael@0 11982 nsDocShell::GetRootScrollFrame()
michael@0 11983 {
michael@0 11984 nsCOMPtr<nsIPresShell> shell = GetPresShell();
michael@0 11985 NS_ENSURE_TRUE(shell, nullptr);
michael@0 11986
michael@0 11987 return shell->GetRootScrollFrameAsScrollableExternal();
michael@0 11988 }
michael@0 11989
michael@0 11990 NS_IMETHODIMP
michael@0 11991 nsDocShell::EnsureScriptEnvironment()
michael@0 11992 {
michael@0 11993 if (mScriptGlobal)
michael@0 11994 return NS_OK;
michael@0 11995
michael@0 11996 if (mIsBeingDestroyed) {
michael@0 11997 return NS_ERROR_NOT_AVAILABLE;
michael@0 11998 }
michael@0 11999
michael@0 12000 #ifdef DEBUG
michael@0 12001 NS_ASSERTION(!mInEnsureScriptEnv,
michael@0 12002 "Infinite loop! Calling EnsureScriptEnvironment() from "
michael@0 12003 "within EnsureScriptEnvironment()!");
michael@0 12004
michael@0 12005 // Yeah, this isn't re-entrant safe, but that's ok since if we
michael@0 12006 // re-enter this method, we'll infinitely loop...
michael@0 12007 AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
michael@0 12008 mInEnsureScriptEnv = true;
michael@0 12009 #endif
michael@0 12010
michael@0 12011 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
michael@0 12012 NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
michael@0 12013
michael@0 12014 uint32_t chromeFlags;
michael@0 12015 browserChrome->GetChromeFlags(&chromeFlags);
michael@0 12016
michael@0 12017 bool isModalContentWindow = (mItemType == typeContent) &&
michael@0 12018 (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW);
michael@0 12019 // There can be various other content docshells associated with the
michael@0 12020 // top-level window, like sidebars. Make sure that we only create an
michael@0 12021 // nsGlobalModalWindow for the primary content shell.
michael@0 12022 if (isModalContentWindow) {
michael@0 12023 nsCOMPtr<nsIDocShellTreeItem> primaryItem;
michael@0 12024 nsresult rv = mTreeOwner->GetPrimaryContentShell(getter_AddRefs(primaryItem));
michael@0 12025 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12026 isModalContentWindow = (primaryItem == this);
michael@0 12027 }
michael@0 12028
michael@0 12029 // If our window is modal and we're not opened as chrome, make
michael@0 12030 // this window a modal content window.
michael@0 12031 mScriptGlobal =
michael@0 12032 NS_NewScriptGlobalObject(mItemType == typeChrome, isModalContentWindow);
michael@0 12033 MOZ_ASSERT(mScriptGlobal);
michael@0 12034
michael@0 12035 mScriptGlobal->SetDocShell(this);
michael@0 12036
michael@0 12037 // Ensure the script object is set up to run script.
michael@0 12038 return mScriptGlobal->EnsureScriptEnvironment();
michael@0 12039 }
michael@0 12040
michael@0 12041
michael@0 12042 NS_IMETHODIMP
michael@0 12043 nsDocShell::EnsureEditorData()
michael@0 12044 {
michael@0 12045 bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
michael@0 12046 if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
michael@0 12047 // We shouldn't recreate the editor data if it already exists, or
michael@0 12048 // we're shutting down, or we already have a detached editor data
michael@0 12049 // stored in the session history. We should only have one editordata
michael@0 12050 // per docshell.
michael@0 12051 mEditorData = new nsDocShellEditorData(this);
michael@0 12052 }
michael@0 12053
michael@0 12054 return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
michael@0 12055 }
michael@0 12056
michael@0 12057 nsresult
michael@0 12058 nsDocShell::EnsureTransferableHookData()
michael@0 12059 {
michael@0 12060 if (!mTransferableHookData) {
michael@0 12061 mTransferableHookData = new nsTransferableHookData();
michael@0 12062 if (!mTransferableHookData) return NS_ERROR_OUT_OF_MEMORY;
michael@0 12063 }
michael@0 12064
michael@0 12065 return NS_OK;
michael@0 12066 }
michael@0 12067
michael@0 12068
michael@0 12069 NS_IMETHODIMP nsDocShell::EnsureFind()
michael@0 12070 {
michael@0 12071 nsresult rv;
michael@0 12072 if (!mFind)
michael@0 12073 {
michael@0 12074 mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
michael@0 12075 if (NS_FAILED(rv)) return rv;
michael@0 12076 }
michael@0 12077
michael@0 12078 // we promise that the nsIWebBrowserFind that we return has been set
michael@0 12079 // up to point to the focused, or content window, so we have to
michael@0 12080 // set that up each time.
michael@0 12081
michael@0 12082 nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
michael@0 12083 NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
michael@0 12084
michael@0 12085 // default to our window
michael@0 12086 nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(scriptGO);
michael@0 12087 nsCOMPtr<nsPIDOMWindow> windowToSearch;
michael@0 12088 nsFocusManager::GetFocusedDescendant(ourWindow, true, getter_AddRefs(windowToSearch));
michael@0 12089
michael@0 12090 nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
michael@0 12091 if (!findInFrames) return NS_ERROR_NO_INTERFACE;
michael@0 12092
michael@0 12093 rv = findInFrames->SetRootSearchFrame(ourWindow);
michael@0 12094 if (NS_FAILED(rv)) return rv;
michael@0 12095 rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
michael@0 12096 if (NS_FAILED(rv)) return rv;
michael@0 12097
michael@0 12098 return NS_OK;
michael@0 12099 }
michael@0 12100
michael@0 12101 bool
michael@0 12102 nsDocShell::IsFrame()
michael@0 12103 {
michael@0 12104 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 12105 GetSameTypeParent(getter_AddRefs(parent));
michael@0 12106 return !!parent;
michael@0 12107 }
michael@0 12108
michael@0 12109 /* boolean IsBeingDestroyed (); */
michael@0 12110 NS_IMETHODIMP
michael@0 12111 nsDocShell::IsBeingDestroyed(bool *aDoomed)
michael@0 12112 {
michael@0 12113 NS_ENSURE_ARG(aDoomed);
michael@0 12114 *aDoomed = mIsBeingDestroyed;
michael@0 12115 return NS_OK;
michael@0 12116 }
michael@0 12117
michael@0 12118
michael@0 12119 NS_IMETHODIMP
michael@0 12120 nsDocShell::GetIsExecutingOnLoadHandler(bool *aResult)
michael@0 12121 {
michael@0 12122 NS_ENSURE_ARG(aResult);
michael@0 12123 *aResult = mIsExecutingOnLoadHandler;
michael@0 12124 return NS_OK;
michael@0 12125 }
michael@0 12126
michael@0 12127 NS_IMETHODIMP
michael@0 12128 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState **aLayoutHistoryState)
michael@0 12129 {
michael@0 12130 if (mOSHE)
michael@0 12131 mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
michael@0 12132 return NS_OK;
michael@0 12133 }
michael@0 12134
michael@0 12135 NS_IMETHODIMP
michael@0 12136 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState)
michael@0 12137 {
michael@0 12138 if (mOSHE)
michael@0 12139 mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
michael@0 12140 return NS_OK;
michael@0 12141 }
michael@0 12142
michael@0 12143 //*****************************************************************************
michael@0 12144 //*** nsRefreshTimer: Object Management
michael@0 12145 //*****************************************************************************
michael@0 12146
michael@0 12147 nsRefreshTimer::nsRefreshTimer()
michael@0 12148 : mDelay(0), mRepeat(false), mMetaRefresh(false)
michael@0 12149 {
michael@0 12150 }
michael@0 12151
michael@0 12152 nsRefreshTimer::~nsRefreshTimer()
michael@0 12153 {
michael@0 12154 }
michael@0 12155
michael@0 12156 //*****************************************************************************
michael@0 12157 // nsRefreshTimer::nsISupports
michael@0 12158 //*****************************************************************************
michael@0 12159
michael@0 12160 NS_IMPL_ADDREF(nsRefreshTimer)
michael@0 12161 NS_IMPL_RELEASE(nsRefreshTimer)
michael@0 12162
michael@0 12163 NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
michael@0 12164 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
michael@0 12165 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
michael@0 12166 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 12167
michael@0 12168 ///*****************************************************************************
michael@0 12169 // nsRefreshTimer::nsITimerCallback
michael@0 12170 //******************************************************************************
michael@0 12171 NS_IMETHODIMP
michael@0 12172 nsRefreshTimer::Notify(nsITimer * aTimer)
michael@0 12173 {
michael@0 12174 NS_ASSERTION(mDocShell, "DocShell is somehow null");
michael@0 12175
michael@0 12176 if (mDocShell && aTimer) {
michael@0 12177 // Get the delay count to determine load type
michael@0 12178 uint32_t delay = 0;
michael@0 12179 aTimer->GetDelay(&delay);
michael@0 12180 mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer);
michael@0 12181 }
michael@0 12182 return NS_OK;
michael@0 12183 }
michael@0 12184
michael@0 12185 //*****************************************************************************
michael@0 12186 // nsDocShell::InterfaceRequestorProxy
michael@0 12187 //*****************************************************************************
michael@0 12188 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor* p)
michael@0 12189 {
michael@0 12190 if (p) {
michael@0 12191 mWeakPtr = do_GetWeakReference(p);
michael@0 12192 }
michael@0 12193 }
michael@0 12194
michael@0 12195 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
michael@0 12196 {
michael@0 12197 mWeakPtr = nullptr;
michael@0 12198 }
michael@0 12199
michael@0 12200 NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)
michael@0 12201
michael@0 12202 NS_IMETHODIMP
michael@0 12203 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID & aIID, void **aSink)
michael@0 12204 {
michael@0 12205 NS_ENSURE_ARG_POINTER(aSink);
michael@0 12206 nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
michael@0 12207 if (ifReq) {
michael@0 12208 return ifReq->GetInterface(aIID, aSink);
michael@0 12209 }
michael@0 12210 *aSink = nullptr;
michael@0 12211 return NS_NOINTERFACE;
michael@0 12212 }
michael@0 12213
michael@0 12214 nsresult
michael@0 12215 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer)
michael@0 12216 {
michael@0 12217 if (!aContentViewer)
michael@0 12218 return NS_ERROR_FAILURE;
michael@0 12219
michael@0 12220 nsCOMPtr<nsIURI> baseURI;
michael@0 12221 nsresult rv = NS_ERROR_NOT_AVAILABLE;
michael@0 12222
michael@0 12223 if (sURIFixup)
michael@0 12224 rv = sURIFixup->CreateExposableURI(mCurrentURI,
michael@0 12225 getter_AddRefs(baseURI));
michael@0 12226
michael@0 12227 // Get the current document and set the base uri
michael@0 12228 if (baseURI) {
michael@0 12229 nsIDocument* document = aContentViewer->GetDocument();
michael@0 12230 if (document) {
michael@0 12231 rv = document->SetBaseURI(baseURI);
michael@0 12232 }
michael@0 12233 }
michael@0 12234 return rv;
michael@0 12235 }
michael@0 12236
michael@0 12237 //*****************************************************************************
michael@0 12238 // nsDocShell::nsIAuthPromptProvider
michael@0 12239 //*****************************************************************************
michael@0 12240
michael@0 12241 NS_IMETHODIMP
michael@0 12242 nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
michael@0 12243 void** aResult)
michael@0 12244 {
michael@0 12245 // a priority prompt request will override a false mAllowAuth setting
michael@0 12246 bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
michael@0 12247
michael@0 12248 if (!mAllowAuth && !priorityPrompt)
michael@0 12249 return NS_ERROR_NOT_AVAILABLE;
michael@0 12250
michael@0 12251 // we're either allowing auth, or it's a proxy request
michael@0 12252 nsresult rv;
michael@0 12253 nsCOMPtr<nsIPromptFactory> wwatch =
michael@0 12254 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
michael@0 12255 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12256
michael@0 12257 rv = EnsureScriptEnvironment();
michael@0 12258 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12259
michael@0 12260 // Get the an auth prompter for our window so that the parenting
michael@0 12261 // of the dialogs works as it should when using tabs.
michael@0 12262
michael@0 12263 return wwatch->GetPrompt(mScriptGlobal, iid,
michael@0 12264 reinterpret_cast<void**>(aResult));
michael@0 12265 }
michael@0 12266
michael@0 12267 //*****************************************************************************
michael@0 12268 // nsDocShell::nsILoadContext
michael@0 12269 //*****************************************************************************
michael@0 12270 NS_IMETHODIMP
michael@0 12271 nsDocShell::GetAssociatedWindow(nsIDOMWindow** aWindow)
michael@0 12272 {
michael@0 12273 CallGetInterface(this, aWindow);
michael@0 12274 return NS_OK;
michael@0 12275 }
michael@0 12276
michael@0 12277 NS_IMETHODIMP
michael@0 12278 nsDocShell::GetTopWindow(nsIDOMWindow** aWindow)
michael@0 12279 {
michael@0 12280 nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this));
michael@0 12281 if (win) {
michael@0 12282 win->GetTop(aWindow);
michael@0 12283 }
michael@0 12284 return NS_OK;
michael@0 12285 }
michael@0 12286
michael@0 12287 NS_IMETHODIMP
michael@0 12288 nsDocShell::GetTopFrameElement(nsIDOMElement** aElement)
michael@0 12289 {
michael@0 12290 *aElement = nullptr;
michael@0 12291 nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this));
michael@0 12292 if (!win) {
michael@0 12293 return NS_OK;
michael@0 12294 }
michael@0 12295
michael@0 12296 nsCOMPtr<nsIDOMWindow> top;
michael@0 12297 win->GetScriptableTop(getter_AddRefs(top));
michael@0 12298 NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
michael@0 12299
michael@0 12300 // GetFrameElement, /not/ GetScriptableFrameElement -- if |top| is inside
michael@0 12301 // <iframe mozbrowser>, we want to return the iframe, not null.
michael@0 12302 return top->GetFrameElement(aElement);
michael@0 12303 }
michael@0 12304
michael@0 12305 NS_IMETHODIMP
michael@0 12306 nsDocShell::IsAppOfType(uint32_t aAppType, bool *aIsOfType)
michael@0 12307 {
michael@0 12308 nsCOMPtr<nsIDocShell> shell = this;
michael@0 12309 while (shell) {
michael@0 12310 uint32_t type;
michael@0 12311 shell->GetAppType(&type);
michael@0 12312 if (type == aAppType) {
michael@0 12313 *aIsOfType = true;
michael@0 12314 return NS_OK;
michael@0 12315 }
michael@0 12316 nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(shell);
michael@0 12317 nsCOMPtr<nsIDocShellTreeItem> parent;
michael@0 12318 item->GetParent(getter_AddRefs(parent));
michael@0 12319 shell = do_QueryInterface(parent);
michael@0 12320 }
michael@0 12321
michael@0 12322 *aIsOfType = false;
michael@0 12323 return NS_OK;
michael@0 12324 }
michael@0 12325
michael@0 12326 NS_IMETHODIMP
michael@0 12327 nsDocShell::GetIsContent(bool *aIsContent)
michael@0 12328 {
michael@0 12329 *aIsContent = (mItemType == typeContent);
michael@0 12330 return NS_OK;
michael@0 12331 }
michael@0 12332
michael@0 12333 bool
michael@0 12334 nsDocShell::IsOKToLoadURI(nsIURI* aURI)
michael@0 12335 {
michael@0 12336 NS_PRECONDITION(aURI, "Must have a URI!");
michael@0 12337
michael@0 12338 if (!mFiredUnloadEvent) {
michael@0 12339 return true;
michael@0 12340 }
michael@0 12341
michael@0 12342 if (!mLoadingURI) {
michael@0 12343 return false;
michael@0 12344 }
michael@0 12345
michael@0 12346 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 12347 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 12348 return
michael@0 12349 secMan &&
michael@0 12350 NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
michael@0 12351 }
michael@0 12352
michael@0 12353 //
michael@0 12354 // Routines for selection and clipboard
michael@0 12355 //
michael@0 12356 nsresult
michael@0 12357 nsDocShell::GetControllerForCommand(const char * inCommand,
michael@0 12358 nsIController** outController)
michael@0 12359 {
michael@0 12360 NS_ENSURE_ARG_POINTER(outController);
michael@0 12361 *outController = nullptr;
michael@0 12362
michael@0 12363 NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
michael@0 12364
michael@0 12365 nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
michael@0 12366 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
michael@0 12367
michael@0 12368 return root->GetControllerForCommand(inCommand, outController);
michael@0 12369 }
michael@0 12370
michael@0 12371 NS_IMETHODIMP
michael@0 12372 nsDocShell::IsCommandEnabled(const char * inCommand, bool* outEnabled)
michael@0 12373 {
michael@0 12374 NS_ENSURE_ARG_POINTER(outEnabled);
michael@0 12375 *outEnabled = false;
michael@0 12376
michael@0 12377 nsresult rv = NS_ERROR_FAILURE;
michael@0 12378
michael@0 12379 nsCOMPtr<nsIController> controller;
michael@0 12380 rv = GetControllerForCommand (inCommand, getter_AddRefs(controller));
michael@0 12381 if (controller)
michael@0 12382 rv = controller->IsCommandEnabled(inCommand, outEnabled);
michael@0 12383
michael@0 12384 return rv;
michael@0 12385 }
michael@0 12386
michael@0 12387 NS_IMETHODIMP
michael@0 12388 nsDocShell::DoCommand(const char * inCommand)
michael@0 12389 {
michael@0 12390 nsresult rv = NS_ERROR_FAILURE;
michael@0 12391
michael@0 12392 nsCOMPtr<nsIController> controller;
michael@0 12393 rv = GetControllerForCommand(inCommand, getter_AddRefs(controller));
michael@0 12394 if (controller)
michael@0 12395 rv = controller->DoCommand(inCommand);
michael@0 12396
michael@0 12397 return rv;
michael@0 12398 }
michael@0 12399
michael@0 12400 nsresult
michael@0 12401 nsDocShell::EnsureCommandHandler()
michael@0 12402 {
michael@0 12403 if (!mCommandManager)
michael@0 12404 {
michael@0 12405 nsCOMPtr<nsPICommandUpdater> commandUpdater =
michael@0 12406 do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
michael@0 12407 if (!commandUpdater) return NS_ERROR_OUT_OF_MEMORY;
michael@0 12408
michael@0 12409 nsCOMPtr<nsIDOMWindow> domWindow =
michael@0 12410 do_GetInterface(static_cast<nsIInterfaceRequestor *>(this));
michael@0 12411
michael@0 12412 nsresult rv = commandUpdater->Init(domWindow);
michael@0 12413 if (NS_SUCCEEDED(rv))
michael@0 12414 mCommandManager = do_QueryInterface(commandUpdater);
michael@0 12415 }
michael@0 12416
michael@0 12417 return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
michael@0 12418 }
michael@0 12419
michael@0 12420 NS_IMETHODIMP
michael@0 12421 nsDocShell::CanCutSelection(bool* aResult)
michael@0 12422 {
michael@0 12423 return IsCommandEnabled("cmd_cut", aResult);
michael@0 12424 }
michael@0 12425
michael@0 12426 NS_IMETHODIMP
michael@0 12427 nsDocShell::CanCopySelection(bool* aResult)
michael@0 12428 {
michael@0 12429 return IsCommandEnabled("cmd_copy", aResult);
michael@0 12430 }
michael@0 12431
michael@0 12432 NS_IMETHODIMP
michael@0 12433 nsDocShell::CanCopyLinkLocation(bool* aResult)
michael@0 12434 {
michael@0 12435 return IsCommandEnabled("cmd_copyLink", aResult);
michael@0 12436 }
michael@0 12437
michael@0 12438 NS_IMETHODIMP
michael@0 12439 nsDocShell::CanCopyImageLocation(bool* aResult)
michael@0 12440 {
michael@0 12441 return IsCommandEnabled("cmd_copyImageLocation",
michael@0 12442 aResult);
michael@0 12443 }
michael@0 12444
michael@0 12445 NS_IMETHODIMP
michael@0 12446 nsDocShell::CanCopyImageContents(bool* aResult)
michael@0 12447 {
michael@0 12448 return IsCommandEnabled("cmd_copyImageContents",
michael@0 12449 aResult);
michael@0 12450 }
michael@0 12451
michael@0 12452 NS_IMETHODIMP
michael@0 12453 nsDocShell::CanPaste(bool* aResult)
michael@0 12454 {
michael@0 12455 return IsCommandEnabled("cmd_paste", aResult);
michael@0 12456 }
michael@0 12457
michael@0 12458 NS_IMETHODIMP
michael@0 12459 nsDocShell::CutSelection(void)
michael@0 12460 {
michael@0 12461 return DoCommand ( "cmd_cut" );
michael@0 12462 }
michael@0 12463
michael@0 12464 NS_IMETHODIMP
michael@0 12465 nsDocShell::CopySelection(void)
michael@0 12466 {
michael@0 12467 return DoCommand ( "cmd_copy" );
michael@0 12468 }
michael@0 12469
michael@0 12470 NS_IMETHODIMP
michael@0 12471 nsDocShell::CopyLinkLocation(void)
michael@0 12472 {
michael@0 12473 return DoCommand ( "cmd_copyLink" );
michael@0 12474 }
michael@0 12475
michael@0 12476 NS_IMETHODIMP
michael@0 12477 nsDocShell::CopyImageLocation(void)
michael@0 12478 {
michael@0 12479 return DoCommand ( "cmd_copyImageLocation" );
michael@0 12480 }
michael@0 12481
michael@0 12482 NS_IMETHODIMP
michael@0 12483 nsDocShell::CopyImageContents(void)
michael@0 12484 {
michael@0 12485 return DoCommand ( "cmd_copyImageContents" );
michael@0 12486 }
michael@0 12487
michael@0 12488 NS_IMETHODIMP
michael@0 12489 nsDocShell::Paste(void)
michael@0 12490 {
michael@0 12491 return DoCommand ( "cmd_paste" );
michael@0 12492 }
michael@0 12493
michael@0 12494 NS_IMETHODIMP
michael@0 12495 nsDocShell::SelectAll(void)
michael@0 12496 {
michael@0 12497 return DoCommand ( "cmd_selectAll" );
michael@0 12498 }
michael@0 12499
michael@0 12500 //
michael@0 12501 // SelectNone
michael@0 12502 //
michael@0 12503 // Collapses the current selection, insertion point ends up at beginning
michael@0 12504 // of previous selection.
michael@0 12505 //
michael@0 12506 NS_IMETHODIMP
michael@0 12507 nsDocShell::SelectNone(void)
michael@0 12508 {
michael@0 12509 return DoCommand ( "cmd_selectNone" );
michael@0 12510 }
michael@0 12511
michael@0 12512 //----------------------------------------------------------------------
michael@0 12513
michael@0 12514 // link handling
michael@0 12515
michael@0 12516 class OnLinkClickEvent : public nsRunnable {
michael@0 12517 public:
michael@0 12518 OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
michael@0 12519 nsIURI* aURI,
michael@0 12520 const char16_t* aTargetSpec,
michael@0 12521 const nsAString& aFileName,
michael@0 12522 nsIInputStream* aPostDataStream,
michael@0 12523 nsIInputStream* aHeadersDataStream,
michael@0 12524 bool aIsTrusted);
michael@0 12525
michael@0 12526 NS_IMETHOD Run() {
michael@0 12527 nsAutoPopupStatePusher popupStatePusher(mPopupState);
michael@0 12528
michael@0 12529 nsCxPusher pusher;
michael@0 12530 if (mIsTrusted || pusher.Push(mContent)) {
michael@0 12531 mHandler->OnLinkClickSync(mContent, mURI,
michael@0 12532 mTargetSpec.get(), mFileName,
michael@0 12533 mPostDataStream, mHeadersDataStream,
michael@0 12534 nullptr, nullptr);
michael@0 12535 }
michael@0 12536 return NS_OK;
michael@0 12537 }
michael@0 12538
michael@0 12539 private:
michael@0 12540 nsRefPtr<nsDocShell> mHandler;
michael@0 12541 nsCOMPtr<nsIURI> mURI;
michael@0 12542 nsString mTargetSpec;
michael@0 12543 nsString mFileName;
michael@0 12544 nsCOMPtr<nsIInputStream> mPostDataStream;
michael@0 12545 nsCOMPtr<nsIInputStream> mHeadersDataStream;
michael@0 12546 nsCOMPtr<nsIContent> mContent;
michael@0 12547 PopupControlState mPopupState;
michael@0 12548 bool mIsTrusted;
michael@0 12549 };
michael@0 12550
michael@0 12551 OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
michael@0 12552 nsIContent *aContent,
michael@0 12553 nsIURI* aURI,
michael@0 12554 const char16_t* aTargetSpec,
michael@0 12555 const nsAString& aFileName,
michael@0 12556 nsIInputStream* aPostDataStream,
michael@0 12557 nsIInputStream* aHeadersDataStream,
michael@0 12558 bool aIsTrusted)
michael@0 12559 : mHandler(aHandler)
michael@0 12560 , mURI(aURI)
michael@0 12561 , mTargetSpec(aTargetSpec)
michael@0 12562 , mFileName(aFileName)
michael@0 12563 , mPostDataStream(aPostDataStream)
michael@0 12564 , mHeadersDataStream(aHeadersDataStream)
michael@0 12565 , mContent(aContent)
michael@0 12566 , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
michael@0 12567 , mIsTrusted(aIsTrusted)
michael@0 12568 {
michael@0 12569 }
michael@0 12570
michael@0 12571 //----------------------------------------
michael@0 12572
michael@0 12573 NS_IMETHODIMP
michael@0 12574 nsDocShell::OnLinkClick(nsIContent* aContent,
michael@0 12575 nsIURI* aURI,
michael@0 12576 const char16_t* aTargetSpec,
michael@0 12577 const nsAString& aFileName,
michael@0 12578 nsIInputStream* aPostDataStream,
michael@0 12579 nsIInputStream* aHeadersDataStream,
michael@0 12580 bool aIsTrusted)
michael@0 12581 {
michael@0 12582 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
michael@0 12583
michael@0 12584 if (!IsOKToLoadURI(aURI)) {
michael@0 12585 return NS_OK;
michael@0 12586 }
michael@0 12587
michael@0 12588 // On history navigation through Back/Forward buttons, don't execute
michael@0 12589 // automatic JavaScript redirection such as |anchorElement.click()| or
michael@0 12590 // |formElement.submit()|.
michael@0 12591 //
michael@0 12592 // XXX |formElement.submit()| bypasses this checkpoint because it calls
michael@0 12593 // nsDocShell::OnLinkClickSync(...) instead.
michael@0 12594 if (ShouldBlockLoadingForBackButton()) {
michael@0 12595 return NS_OK;
michael@0 12596 }
michael@0 12597
michael@0 12598 if (aContent->IsEditable()) {
michael@0 12599 return NS_OK;
michael@0 12600 }
michael@0 12601
michael@0 12602 nsresult rv = NS_ERROR_FAILURE;
michael@0 12603 nsAutoString target;
michael@0 12604
michael@0 12605 nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
michael@0 12606 if (browserChrome3) {
michael@0 12607 nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
michael@0 12608 nsAutoString oldTarget(aTargetSpec);
michael@0 12609 rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
michael@0 12610 linkNode, mIsAppTab, target);
michael@0 12611 }
michael@0 12612
michael@0 12613 if (NS_FAILED(rv))
michael@0 12614 target = aTargetSpec;
michael@0 12615
michael@0 12616 nsCOMPtr<nsIRunnable> ev =
michael@0 12617 new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
michael@0 12618 aPostDataStream, aHeadersDataStream, aIsTrusted);
michael@0 12619 return NS_DispatchToCurrentThread(ev);
michael@0 12620 }
michael@0 12621
michael@0 12622 NS_IMETHODIMP
michael@0 12623 nsDocShell::OnLinkClickSync(nsIContent *aContent,
michael@0 12624 nsIURI* aURI,
michael@0 12625 const char16_t* aTargetSpec,
michael@0 12626 const nsAString& aFileName,
michael@0 12627 nsIInputStream* aPostDataStream,
michael@0 12628 nsIInputStream* aHeadersDataStream,
michael@0 12629 nsIDocShell** aDocShell,
michael@0 12630 nsIRequest** aRequest)
michael@0 12631 {
michael@0 12632 // Initialize the DocShell / Request
michael@0 12633 if (aDocShell) {
michael@0 12634 *aDocShell = nullptr;
michael@0 12635 }
michael@0 12636 if (aRequest) {
michael@0 12637 *aRequest = nullptr;
michael@0 12638 }
michael@0 12639
michael@0 12640 if (!IsOKToLoadURI(aURI)) {
michael@0 12641 return NS_OK;
michael@0 12642 }
michael@0 12643
michael@0 12644 // XXX When the linking node was HTMLFormElement, it is synchronous event.
michael@0 12645 // That is, the caller of this method is not |OnLinkClickEvent::Run()|
michael@0 12646 // but |HTMLFormElement::SubmitSubmission(...)|.
michael@0 12647 if (nsGkAtoms::form == aContent->Tag() && ShouldBlockLoadingForBackButton()) {
michael@0 12648 return NS_OK;
michael@0 12649 }
michael@0 12650
michael@0 12651 if (aContent->IsEditable()) {
michael@0 12652 return NS_OK;
michael@0 12653 }
michael@0 12654
michael@0 12655 {
michael@0 12656 // defer to an external protocol handler if necessary...
michael@0 12657 nsCOMPtr<nsIExternalProtocolService> extProtService =
michael@0 12658 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
michael@0 12659 if (extProtService) {
michael@0 12660 nsAutoCString scheme;
michael@0 12661 aURI->GetScheme(scheme);
michael@0 12662 if (!scheme.IsEmpty()) {
michael@0 12663 // if the URL scheme does not correspond to an exposed protocol, then we
michael@0 12664 // need to hand this link click over to the external protocol handler.
michael@0 12665 bool isExposed;
michael@0 12666 nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
michael@0 12667 if (NS_SUCCEEDED(rv) && !isExposed) {
michael@0 12668 return extProtService->LoadURI(aURI, this);
michael@0 12669 }
michael@0 12670 }
michael@0 12671 }
michael@0 12672 }
michael@0 12673
michael@0 12674 // Get the owner document of the link that was clicked, this will be
michael@0 12675 // the document that the link is in, or the last document that the
michael@0 12676 // link was in. From that document, we'll get the URI to use as the
michael@0 12677 // referer, since the current URI in this docshell may be a
michael@0 12678 // new document that we're in the process of loading.
michael@0 12679 nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
michael@0 12680 NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
michael@0 12681
michael@0 12682 // Now check that the refererDoc's inner window is the current inner
michael@0 12683 // window for mScriptGlobal. If it's not, then we don't want to
michael@0 12684 // follow this link.
michael@0 12685 nsPIDOMWindow* refererInner = refererDoc->GetInnerWindow();
michael@0 12686 NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
michael@0 12687 if (!mScriptGlobal ||
michael@0 12688 mScriptGlobal->GetCurrentInnerWindow() != refererInner) {
michael@0 12689 // We're no longer the current inner window
michael@0 12690 return NS_OK;
michael@0 12691 }
michael@0 12692
michael@0 12693 nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
michael@0 12694
michael@0 12695 // referer could be null here in some odd cases, but that's ok,
michael@0 12696 // we'll just load the link w/o sending a referer in those cases.
michael@0 12697
michael@0 12698 nsAutoString target(aTargetSpec);
michael@0 12699
michael@0 12700 // If this is an anchor element, grab its type property to use as a hint
michael@0 12701 nsAutoString typeHint;
michael@0 12702 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent));
michael@0 12703 if (anchor) {
michael@0 12704 anchor->GetType(typeHint);
michael@0 12705 NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
michael@0 12706 nsAutoCString type, dummy;
michael@0 12707 NS_ParseContentType(utf8Hint, type, dummy);
michael@0 12708 CopyUTF8toUTF16(type, typeHint);
michael@0 12709 }
michael@0 12710
michael@0 12711 // Clone the URI now, in case a content policy or something messes
michael@0 12712 // with it under InternalLoad; we do _not_ want to change the URI
michael@0 12713 // our caller passed in.
michael@0 12714 nsCOMPtr<nsIURI> clonedURI;
michael@0 12715 aURI->Clone(getter_AddRefs(clonedURI));
michael@0 12716 if (!clonedURI) {
michael@0 12717 return NS_ERROR_OUT_OF_MEMORY;
michael@0 12718 }
michael@0 12719
michael@0 12720 nsresult rv = InternalLoad(clonedURI, // New URI
michael@0 12721 referer, // Referer URI
michael@0 12722 aContent->NodePrincipal(), // Owner is our node's
michael@0 12723 // principal
michael@0 12724 INTERNAL_LOAD_FLAGS_NONE,
michael@0 12725 target.get(), // Window target
michael@0 12726 NS_LossyConvertUTF16toASCII(typeHint).get(),
michael@0 12727 aFileName, // Download as file
michael@0 12728 aPostDataStream, // Post data stream
michael@0 12729 aHeadersDataStream, // Headers stream
michael@0 12730 LOAD_LINK, // Load type
michael@0 12731 nullptr, // No SHEntry
michael@0 12732 true, // first party site
michael@0 12733 NullString(), // No srcdoc
michael@0 12734 this, // We are the source
michael@0 12735 nullptr, // baseURI not needed
michael@0 12736 aDocShell, // DocShell out-param
michael@0 12737 aRequest); // Request out-param
michael@0 12738 if (NS_SUCCEEDED(rv)) {
michael@0 12739 DispatchPings(aContent, aURI, referer);
michael@0 12740 }
michael@0 12741 return rv;
michael@0 12742 }
michael@0 12743
michael@0 12744 NS_IMETHODIMP
michael@0 12745 nsDocShell::OnOverLink(nsIContent* aContent,
michael@0 12746 nsIURI* aURI,
michael@0 12747 const char16_t* aTargetSpec)
michael@0 12748 {
michael@0 12749 if (aContent->IsEditable()) {
michael@0 12750 return NS_OK;
michael@0 12751 }
michael@0 12752
michael@0 12753 nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
michael@0 12754 nsresult rv = NS_ERROR_FAILURE;
michael@0 12755
michael@0 12756 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
michael@0 12757 if (!browserChrome2) {
michael@0 12758 browserChrome = do_GetInterface(mTreeOwner);
michael@0 12759 if (!browserChrome)
michael@0 12760 return rv;
michael@0 12761 }
michael@0 12762
michael@0 12763 nsCOMPtr<nsITextToSubURI> textToSubURI =
michael@0 12764 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
michael@0 12765 if (NS_FAILED(rv))
michael@0 12766 return rv;
michael@0 12767
michael@0 12768 // use url origin charset to unescape the URL
michael@0 12769 nsAutoCString charset;
michael@0 12770 rv = aURI->GetOriginCharset(charset);
michael@0 12771 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12772
michael@0 12773 nsAutoCString spec;
michael@0 12774 rv = aURI->GetSpec(spec);
michael@0 12775 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12776
michael@0 12777 nsAutoString uStr;
michael@0 12778 rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr);
michael@0 12779 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12780
michael@0 12781 mozilla::net::SeerPredict(aURI, mCurrentURI, nsINetworkSeer::PREDICT_LINK,
michael@0 12782 this, nullptr);
michael@0 12783
michael@0 12784 if (browserChrome2) {
michael@0 12785 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
michael@0 12786 rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
michael@0 12787 uStr, element);
michael@0 12788 } else {
michael@0 12789 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
michael@0 12790 }
michael@0 12791 return rv;
michael@0 12792 }
michael@0 12793
michael@0 12794 NS_IMETHODIMP
michael@0 12795 nsDocShell::OnLeaveLink()
michael@0 12796 {
michael@0 12797 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
michael@0 12798 nsresult rv = NS_ERROR_FAILURE;
michael@0 12799
michael@0 12800 if (browserChrome) {
michael@0 12801 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
michael@0 12802 EmptyString().get());
michael@0 12803 }
michael@0 12804 return rv;
michael@0 12805 }
michael@0 12806
michael@0 12807 bool
michael@0 12808 nsDocShell::ShouldBlockLoadingForBackButton()
michael@0 12809 {
michael@0 12810 if (!(mLoadType & LOAD_CMD_HISTORY) ||
michael@0 12811 EventStateManager::IsHandlingUserInput() ||
michael@0 12812 !Preferences::GetBool("accessibility.blockjsredirection")) {
michael@0 12813 return false;
michael@0 12814 }
michael@0 12815
michael@0 12816 bool canGoForward = false;
michael@0 12817 GetCanGoForward(&canGoForward);
michael@0 12818 return canGoForward;
michael@0 12819 }
michael@0 12820
michael@0 12821 bool
michael@0 12822 nsDocShell::PluginsAllowedInCurrentDoc()
michael@0 12823 {
michael@0 12824 bool pluginsAllowed = false;
michael@0 12825
michael@0 12826 if (!mContentViewer) {
michael@0 12827 return false;
michael@0 12828 }
michael@0 12829
michael@0 12830 nsIDocument* doc = mContentViewer->GetDocument();
michael@0 12831 if (!doc) {
michael@0 12832 return false;
michael@0 12833 }
michael@0 12834
michael@0 12835 doc->GetAllowPlugins(&pluginsAllowed);
michael@0 12836 return pluginsAllowed;
michael@0 12837 }
michael@0 12838
michael@0 12839 //----------------------------------------------------------------------
michael@0 12840 // Web Shell Services API
michael@0 12841
michael@0 12842 //This functions is only called when a new charset is detected in loading a document.
michael@0 12843 //Its name should be changed to "CharsetReloadDocument"
michael@0 12844 NS_IMETHODIMP
michael@0 12845 nsDocShell::ReloadDocument(const char* aCharset,
michael@0 12846 int32_t aSource)
michael@0 12847 {
michael@0 12848
michael@0 12849 // XXX hack. keep the aCharset and aSource wait to pick it up
michael@0 12850 nsCOMPtr<nsIContentViewer> cv;
michael@0 12851 NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
michael@0 12852 if (cv)
michael@0 12853 {
michael@0 12854 nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);
michael@0 12855 if (muDV)
michael@0 12856 {
michael@0 12857 int32_t hint;
michael@0 12858 muDV->GetHintCharacterSetSource(&hint);
michael@0 12859 if (aSource > hint)
michael@0 12860 {
michael@0 12861 nsCString charset(aCharset);
michael@0 12862 muDV->SetHintCharacterSet(charset);
michael@0 12863 muDV->SetHintCharacterSetSource(aSource);
michael@0 12864 if(eCharsetReloadRequested != mCharsetReloadState)
michael@0 12865 {
michael@0 12866 mCharsetReloadState = eCharsetReloadRequested;
michael@0 12867 return Reload(LOAD_FLAGS_CHARSET_CHANGE);
michael@0 12868 }
michael@0 12869 }
michael@0 12870 }
michael@0 12871 }
michael@0 12872 //return failure if this request is not accepted due to mCharsetReloadState
michael@0 12873 return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
michael@0 12874 }
michael@0 12875
michael@0 12876
michael@0 12877 NS_IMETHODIMP
michael@0 12878 nsDocShell::StopDocumentLoad(void)
michael@0 12879 {
michael@0 12880 if(eCharsetReloadRequested != mCharsetReloadState)
michael@0 12881 {
michael@0 12882 Stop(nsIWebNavigation::STOP_ALL);
michael@0 12883 return NS_OK;
michael@0 12884 }
michael@0 12885 //return failer if this request is not accepted due to mCharsetReloadState
michael@0 12886 return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
michael@0 12887 }
michael@0 12888
michael@0 12889 NS_IMETHODIMP
michael@0 12890 nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
michael@0 12891 {
michael@0 12892 *aPrintPreview = nullptr;
michael@0 12893 #if NS_PRINT_PREVIEW
michael@0 12894 nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
michael@0 12895 if (!print || !print->IsInitializedForPrintPreview()) {
michael@0 12896 Stop(nsIWebNavigation::STOP_ALL);
michael@0 12897 nsCOMPtr<nsIPrincipal> principal =
michael@0 12898 do_CreateInstance("@mozilla.org/nullprincipal;1");
michael@0 12899 NS_ENSURE_STATE(principal);
michael@0 12900 nsresult rv = CreateAboutBlankContentViewer(principal, nullptr);
michael@0 12901 NS_ENSURE_SUCCESS(rv, rv);
michael@0 12902 print = do_QueryInterface(mContentViewer);
michael@0 12903 NS_ENSURE_STATE(print);
michael@0 12904 print->InitializeForPrintPreview();
michael@0 12905 }
michael@0 12906 nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
michael@0 12907 result.forget(aPrintPreview);
michael@0 12908 return NS_OK;
michael@0 12909 #else
michael@0 12910 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 12911 #endif
michael@0 12912 }
michael@0 12913
michael@0 12914
michael@0 12915 #ifdef DEBUG
michael@0 12916 unsigned long nsDocShell::gNumberOfDocShells = 0;
michael@0 12917 #endif
michael@0 12918
michael@0 12919 NS_IMETHODIMP
michael@0 12920 nsDocShell::GetCanExecuteScripts(bool *aResult)
michael@0 12921 {
michael@0 12922 *aResult = mCanExecuteScripts;
michael@0 12923 return NS_OK;
michael@0 12924 }
michael@0 12925
michael@0 12926 NS_IMETHODIMP
michael@0 12927 nsDocShell::SetIsApp(uint32_t aOwnAppId)
michael@0 12928 {
michael@0 12929 mOwnOrContainingAppId = aOwnAppId;
michael@0 12930 if (aOwnAppId != nsIScriptSecurityManager::NO_APP_ID &&
michael@0 12931 aOwnAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
michael@0 12932 mFrameType = eFrameTypeApp;
michael@0 12933 } else {
michael@0 12934 mFrameType = eFrameTypeRegular;
michael@0 12935 }
michael@0 12936
michael@0 12937 return NS_OK;
michael@0 12938 }
michael@0 12939
michael@0 12940 NS_IMETHODIMP
michael@0 12941 nsDocShell::SetIsBrowserInsideApp(uint32_t aContainingAppId)
michael@0 12942 {
michael@0 12943 mOwnOrContainingAppId = aContainingAppId;
michael@0 12944 mFrameType = eFrameTypeBrowser;
michael@0 12945 return NS_OK;
michael@0 12946 }
michael@0 12947
michael@0 12948 /* [infallible] */ NS_IMETHODIMP
michael@0 12949 nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
michael@0 12950 {
michael@0 12951 *aIsBrowser = (mFrameType == eFrameTypeBrowser);
michael@0 12952 return NS_OK;
michael@0 12953 }
michael@0 12954
michael@0 12955 /* [infallible] */ NS_IMETHODIMP
michael@0 12956 nsDocShell::GetIsApp(bool* aIsApp)
michael@0 12957 {
michael@0 12958 *aIsApp = (mFrameType == eFrameTypeApp);
michael@0 12959 return NS_OK;
michael@0 12960 }
michael@0 12961
michael@0 12962 /* [infallible] */ NS_IMETHODIMP
michael@0 12963 nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp)
michael@0 12964 {
michael@0 12965 switch (mFrameType) {
michael@0 12966 case eFrameTypeRegular:
michael@0 12967 *aIsBrowserOrApp = false;
michael@0 12968 break;
michael@0 12969 case eFrameTypeBrowser:
michael@0 12970 case eFrameTypeApp:
michael@0 12971 *aIsBrowserOrApp = true;
michael@0 12972 break;
michael@0 12973 }
michael@0 12974
michael@0 12975 return NS_OK;
michael@0 12976 }
michael@0 12977
michael@0 12978 nsDocShell::FrameType
michael@0 12979 nsDocShell::GetInheritedFrameType()
michael@0 12980 {
michael@0 12981 if (mFrameType != eFrameTypeRegular) {
michael@0 12982 return mFrameType;
michael@0 12983 }
michael@0 12984
michael@0 12985 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
michael@0 12986 GetSameTypeParent(getter_AddRefs(parentAsItem));
michael@0 12987
michael@0 12988 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
michael@0 12989 if (!parent) {
michael@0 12990 return eFrameTypeRegular;
michael@0 12991 }
michael@0 12992
michael@0 12993 return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
michael@0 12994 }
michael@0 12995
michael@0 12996 /* [infallible] */ NS_IMETHODIMP
michael@0 12997 nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
michael@0 12998 {
michael@0 12999 *aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser);
michael@0 13000 return NS_OK;
michael@0 13001 }
michael@0 13002
michael@0 13003 /* [infallible] */ NS_IMETHODIMP
michael@0 13004 nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp)
michael@0 13005 {
michael@0 13006 switch (GetInheritedFrameType()) {
michael@0 13007 case eFrameTypeRegular:
michael@0 13008 *aIsInBrowserOrApp = false;
michael@0 13009 break;
michael@0 13010 case eFrameTypeBrowser:
michael@0 13011 case eFrameTypeApp:
michael@0 13012 *aIsInBrowserOrApp = true;
michael@0 13013 break;
michael@0 13014 }
michael@0 13015
michael@0 13016 return NS_OK;
michael@0 13017 }
michael@0 13018
michael@0 13019 /* [infallible] */ NS_IMETHODIMP
michael@0 13020 nsDocShell::GetAppId(uint32_t* aAppId)
michael@0 13021 {
michael@0 13022 if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
michael@0 13023 *aAppId = mOwnOrContainingAppId;
michael@0 13024 return NS_OK;
michael@0 13025 }
michael@0 13026
michael@0 13027 nsCOMPtr<nsIDocShell> parent;
michael@0 13028 GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
michael@0 13029
michael@0 13030 if (!parent) {
michael@0 13031 *aAppId = nsIScriptSecurityManager::NO_APP_ID;
michael@0 13032 return NS_OK;
michael@0 13033 }
michael@0 13034
michael@0 13035 return parent->GetAppId(aAppId);
michael@0 13036 }
michael@0 13037
michael@0 13038 NS_IMETHODIMP
michael@0 13039 nsDocShell::GetAppManifestURL(nsAString& aAppManifestURL)
michael@0 13040 {
michael@0 13041 uint32_t appId;
michael@0 13042 GetAppId(&appId);
michael@0 13043
michael@0 13044 if (appId != nsIScriptSecurityManager::NO_APP_ID &&
michael@0 13045 appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
michael@0 13046 nsCOMPtr<nsIAppsService> appsService =
michael@0 13047 do_GetService(APPS_SERVICE_CONTRACTID);
michael@0 13048 NS_ASSERTION(appsService, "No AppsService available");
michael@0 13049 appsService->GetManifestURLByLocalId(appId, aAppManifestURL);
michael@0 13050 } else {
michael@0 13051 aAppManifestURL.SetLength(0);
michael@0 13052 }
michael@0 13053
michael@0 13054 return NS_OK;
michael@0 13055 }
michael@0 13056
michael@0 13057 NS_IMETHODIMP
michael@0 13058 nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
michael@0 13059 {
michael@0 13060 if (TabChild* tabChild = TabChild::GetFrom(this)) {
michael@0 13061 *aOut = tabChild->IsAsyncPanZoomEnabled();
michael@0 13062 return NS_OK;
michael@0 13063 }
michael@0 13064 *aOut = false;
michael@0 13065 return NS_OK;
michael@0 13066 }
michael@0 13067
michael@0 13068 bool
michael@0 13069 nsDocShell::HasUnloadedParent()
michael@0 13070 {
michael@0 13071 nsCOMPtr<nsIDocShellTreeItem> currentTreeItem = this;
michael@0 13072 while (currentTreeItem) {
michael@0 13073 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
michael@0 13074 currentTreeItem->GetParent(getter_AddRefs(parentTreeItem));
michael@0 13075 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem);
michael@0 13076 if (parent) {
michael@0 13077 bool inUnload = false;
michael@0 13078 parent->GetIsInUnload(&inUnload);
michael@0 13079 if (inUnload) {
michael@0 13080 return true;
michael@0 13081 }
michael@0 13082 }
michael@0 13083 currentTreeItem.swap(parentTreeItem);
michael@0 13084 }
michael@0 13085 return false;
michael@0 13086 }
michael@0 13087
michael@0 13088 bool
michael@0 13089 nsDocShell::IsInvisible()
michael@0 13090 {
michael@0 13091 return mInvisible;
michael@0 13092 }
michael@0 13093
michael@0 13094 void
michael@0 13095 nsDocShell::SetInvisible(bool aInvisible)
michael@0 13096 {
michael@0 13097 mInvisible = aInvisible;
michael@0 13098 }

mercurial