Wed, 31 Dec 2014 06:09:35 +0100
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(<); |
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(<); |
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 | } |