/src/mozilla-central/docshell/base/nsDocShell.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsDocShell.h" |
8 | | |
9 | | #include <algorithm> |
10 | | |
11 | | #ifdef XP_WIN |
12 | | #include <process.h> |
13 | | #define getpid _getpid |
14 | | #else |
15 | | #include <unistd.h> // for getpid() |
16 | | #endif |
17 | | |
18 | | #include "mozilla/ArrayUtils.h" |
19 | | #include "mozilla/Attributes.h" |
20 | | #include "mozilla/AutoRestore.h" |
21 | | #include "mozilla/BasePrincipal.h" |
22 | | #include "mozilla/Casting.h" |
23 | | #include "mozilla/Encoding.h" |
24 | | #include "mozilla/EventStateManager.h" |
25 | | #include "mozilla/HTMLEditor.h" |
26 | | #include "mozilla/LoadInfo.h" |
27 | | #include "mozilla/Logging.h" |
28 | | #include "mozilla/MediaFeatureChange.h" |
29 | | #include "mozilla/Preferences.h" |
30 | | #include "mozilla/ResultExtensions.h" |
31 | | #include "mozilla/Services.h" |
32 | | #include "mozilla/StaticPrefs.h" |
33 | | #include "mozilla/StartupTimeline.h" |
34 | | #include "mozilla/Telemetry.h" |
35 | | #include "mozilla/Unused.h" |
36 | | |
37 | | #include "mozilla/dom/ClientChannelHelper.h" |
38 | | #include "mozilla/dom/ClientHandle.h" |
39 | | #include "mozilla/dom/ClientInfo.h" |
40 | | #include "mozilla/dom/ClientManager.h" |
41 | | #include "mozilla/dom/ClientSource.h" |
42 | | #include "mozilla/dom/ContentChild.h" |
43 | | #include "mozilla/dom/ContentFrameMessageManager.h" |
44 | | #include "mozilla/dom/DocGroup.h" |
45 | | #include "mozilla/dom/Element.h" |
46 | | #include "mozilla/dom/HTMLAnchorElement.h" |
47 | | #include "mozilla/dom/PerformanceNavigation.h" |
48 | | #include "mozilla/dom/PermissionMessageUtils.h" |
49 | | #include "mozilla/dom/ProfileTimelineMarkerBinding.h" |
50 | | #include "mozilla/dom/ScreenOrientation.h" |
51 | | #include "mozilla/dom/ScriptSettings.h" |
52 | | #include "mozilla/dom/ServiceWorkerInterceptController.h" |
53 | | #include "mozilla/dom/ServiceWorkerUtils.h" |
54 | | #include "mozilla/dom/SessionStorageManager.h" |
55 | | #include "mozilla/dom/TabChild.h" |
56 | | #include "mozilla/dom/TabGroup.h" |
57 | | #include "mozilla/dom/ToJSValue.h" |
58 | | #include "mozilla/dom/ChildSHistory.h" |
59 | | |
60 | | |
61 | | #include "mozilla/net/ReferrerPolicy.h" |
62 | | |
63 | | #include "nsIApplicationCacheChannel.h" |
64 | | #include "nsIApplicationCacheContainer.h" |
65 | | #include "nsIAppShell.h" |
66 | | #include "nsIAsyncVerifyRedirectCallback.h" |
67 | | #include "nsIAuthPrompt.h" |
68 | | #include "nsIAuthPrompt2.h" |
69 | | #include "nsICachingChannel.h" |
70 | | #include "nsICaptivePortalService.h" |
71 | | #include "nsIChannel.h" |
72 | | #include "nsIChannelEventSink.h" |
73 | | #include "nsIClassOfService.h" |
74 | | #include "nsICommandManager.h" |
75 | | #include "nsIConsoleReportCollector.h" |
76 | | #include "nsIContent.h" |
77 | | #include "nsIContentInlines.h" |
78 | | #include "nsIContentSecurityPolicy.h" |
79 | | #include "nsIContentViewer.h" |
80 | | #include "nsIController.h" |
81 | | #include "nsICookieService.h" |
82 | | #include "nsIDocShellTreeItem.h" |
83 | | #include "nsIDocShellTreeOwner.h" |
84 | | #include "nsIDocument.h" |
85 | | #include "nsIDocumentLoaderFactory.h" |
86 | | #include "nsIDOMWindow.h" |
87 | | #include "nsIEditingSession.h" |
88 | | #include "nsIExternalProtocolService.h" |
89 | | #include "nsIFormPOSTActionChannel.h" |
90 | | #include "nsIFrame.h" |
91 | | #include "nsIGlobalObject.h" |
92 | | #include "nsIHttpChannel.h" |
93 | | #include "nsIHttpChannelInternal.h" |
94 | | #include "nsIIDNService.h" |
95 | | #include "nsIInputStreamChannel.h" |
96 | | #include "nsIInterfaceRequestorUtils.h" |
97 | | #include "nsIJARChannel.h" |
98 | | #include "nsILayoutHistoryState.h" |
99 | | #include "nsILoadInfo.h" |
100 | | #include "nsIMultiPartChannel.h" |
101 | | #include "nsINestedURI.h" |
102 | | #include "nsINetworkPredictor.h" |
103 | | #include "nsINode.h" |
104 | | #include "nsINSSErrorsService.h" |
105 | | #include "nsIObserverService.h" |
106 | | #include "nsIOService.h" |
107 | | #include "nsIPrincipal.h" |
108 | | #include "nsIPrivacyTransitionObserver.h" |
109 | | #include "nsIPrompt.h" |
110 | | #include "nsIPromptFactory.h" |
111 | | #include "nsIReflowObserver.h" |
112 | | #include "nsIScriptChannel.h" |
113 | | #include "nsIScriptObjectPrincipal.h" |
114 | | #include "nsIScriptSecurityManager.h" |
115 | | #include "nsIScrollableFrame.h" |
116 | | #include "nsIScrollObserver.h" |
117 | | #include "nsISecureBrowserUI.h" |
118 | | #include "nsISecurityUITelemetry.h" |
119 | | #include "nsISeekableStream.h" |
120 | | #include "nsISelectionDisplay.h" |
121 | | #include "nsISHEntry.h" |
122 | | #include "nsISHistory.h" |
123 | | #include "nsISiteSecurityService.h" |
124 | | #include "nsISocketProvider.h" |
125 | | #include "nsIStringBundle.h" |
126 | | #include "nsIStructuredCloneContainer.h" |
127 | | #include "nsISupportsPrimitives.h" |
128 | | #include "nsITabChild.h" |
129 | | #include "nsITextToSubURI.h" |
130 | | #include "nsITimedChannel.h" |
131 | | #include "nsITimer.h" |
132 | | #include "nsITransportSecurityInfo.h" |
133 | | #include "nsIUploadChannel.h" |
134 | | #include "nsIURIFixup.h" |
135 | | #include "nsIURILoader.h" |
136 | | #include "nsIURIMutator.h" |
137 | | #include "nsIURL.h" |
138 | | #include "nsIViewSourceChannel.h" |
139 | | #include "nsIWebBrowserChrome.h" |
140 | | #include "nsIWebBrowserChrome3.h" |
141 | | #include "nsIWebBrowserChromeFocus.h" |
142 | | #include "nsIWebBrowserFind.h" |
143 | | #include "nsIWebProgress.h" |
144 | | #include "nsIWidget.h" |
145 | | #include "nsIWindowWatcher.h" |
146 | | #include "nsIWritablePropertyBag2.h" |
147 | | #include "nsIWyciwygChannel.h" |
148 | | |
149 | | #include "nsCommandManager.h" |
150 | | #include "nsPIDOMWindow.h" |
151 | | #include "nsPILoadGroupInternal.h" |
152 | | #include "nsPIWindowRoot.h" |
153 | | |
154 | | #include "IHistory.h" |
155 | | #include "IUrlClassifierUITelemetry.h" |
156 | | |
157 | | #include "mozIThirdPartyUtil.h" |
158 | | |
159 | | #include "nsArray.h" |
160 | | #include "nsArrayUtils.h" |
161 | | #include "nsAutoPtr.h" |
162 | | #include "nsCDefaultURIFixup.h" |
163 | | #include "nsCExternalHandlerService.h" |
164 | | #include "nsContentDLF.h" |
165 | | #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...) |
166 | | #include "nsContentSecurityManager.h" |
167 | | #include "nsContentUtils.h" |
168 | | #include "nsCURILoader.h" |
169 | | #include "nsDocShellCID.h" |
170 | | #include "nsDocShellEditorData.h" |
171 | | #include "nsDocShellEnumerator.h" |
172 | | #include "nsDocShellLoadInfo.h" |
173 | | #include "nsDocShellLoadTypes.h" |
174 | | #include "nsDOMCID.h" |
175 | | #include "nsDOMNavigationTiming.h" |
176 | | #include "nsDSURIContentListener.h" |
177 | | #include "nsError.h" |
178 | | #include "nsEscape.h" |
179 | | #include "nsFocusManager.h" |
180 | | #include "nsGlobalWindow.h" |
181 | | #include "nsJSEnvironment.h" |
182 | | #include "nsNetCID.h" |
183 | | #include "nsNetUtil.h" |
184 | | #include "nsObjectLoadingContent.h" |
185 | | #include "nsPingListener.h" |
186 | | #include "nsPoint.h" |
187 | | #include "nsQueryObject.h" |
188 | | #include "nsRect.h" |
189 | | #include "nsRefreshTimer.h" |
190 | | #include "nsSandboxFlags.h" |
191 | | #include "nsSHistory.h" |
192 | | #include "nsStructuredCloneContainer.h" |
193 | | #include "nsSubDocumentFrame.h" |
194 | | #include "nsView.h" |
195 | | #include "nsViewManager.h" |
196 | | #include "nsViewSourceHandler.h" |
197 | | #include "nsWebBrowserFind.h" |
198 | | #include "nsWhitespaceTokenizer.h" |
199 | | #include "nsWidgetsCID.h" |
200 | | #include "nsXULAppAPI.h" |
201 | | |
202 | | #include "GeckoProfiler.h" |
203 | | #include "mozilla/NullPrincipal.h" |
204 | | #include "Navigator.h" |
205 | | #include "prenv.h" |
206 | | #include "URIUtils.h" |
207 | | |
208 | | #include "timeline/JavascriptTimelineMarker.h" |
209 | | |
210 | | #ifdef MOZ_PLACES |
211 | | #include "nsIFaviconService.h" |
212 | | #include "mozIPlacesPendingOperation.h" |
213 | | #endif |
214 | | |
215 | | #if NS_PRINT_PREVIEW |
216 | | #include "nsIDocumentViewerPrint.h" |
217 | | #include "nsIWebBrowserPrint.h" |
218 | | #endif |
219 | | |
220 | | #ifdef MOZ_TOOLKIT_SEARCH |
221 | | #include "nsIBrowserSearchService.h" |
222 | | #endif |
223 | | |
224 | | using namespace mozilla; |
225 | | using namespace mozilla::dom; |
226 | | using namespace mozilla::net; |
227 | | |
228 | | // Threshold value in ms for META refresh based redirects |
229 | 0 | #define REFRESH_REDIRECT_TIMER 15000 |
230 | | |
231 | | // Hint for native dispatch of events on how long to delay after |
232 | | // all documents have loaded in milliseconds before favoring normal |
233 | | // native event dispatch priorites over performance |
234 | | // Can be overridden with docshell.event_starvation_delay_hint pref. |
235 | 0 | #define NS_EVENT_STARVATION_DELAY_HINT 2000 |
236 | | |
237 | | static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); |
238 | | |
239 | | // True means sUseErrorPages has been added to |
240 | | // preferences var cache. |
241 | | static bool gAddedPreferencesVarCache = false; |
242 | | |
243 | | // Number of documents currently loading |
244 | | static int32_t gNumberOfDocumentsLoading = 0; |
245 | | |
246 | | // Global count of existing docshells. |
247 | | static int32_t gDocShellCount = 0; |
248 | | |
249 | | // Global count of docshells with the private attribute set |
250 | | static uint32_t gNumberOfPrivateDocShells = 0; |
251 | | |
252 | | // True means we validate window targets to prevent frameset |
253 | | // spoofing. Initialize this to a non-bolean value so we know to check |
254 | | // the pref on the creation of the first docshell. |
255 | | static uint32_t gValidateOrigin = 0xffffffff; |
256 | | |
257 | | #ifdef DEBUG |
258 | | static mozilla::LazyLogModule gDocShellLog("nsDocShell"); |
259 | | #endif |
260 | | static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");; |
261 | | |
262 | | const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties"; |
263 | | const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties"; |
264 | | |
265 | | bool nsDocShell::sUseErrorPages = false; |
266 | | |
267 | | // Global reference to the URI fixup service. |
268 | | nsIURIFixup* nsDocShell::sURIFixup = nullptr; |
269 | | |
270 | | static void |
271 | | FavorPerformanceHint(bool aPerfOverStarvation) |
272 | 0 | { |
273 | 0 | nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID); |
274 | 0 | if (appShell) { |
275 | 0 | appShell->FavorPerformanceHint( |
276 | 0 | aPerfOverStarvation, |
277 | 0 | Preferences::GetUint("docshell.event_starvation_delay_hint", |
278 | 0 | NS_EVENT_STARVATION_DELAY_HINT)); |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | | static void |
283 | | IncreasePrivateDocShellCount() |
284 | 0 | { |
285 | 0 | gNumberOfPrivateDocShells++; |
286 | 0 | if (gNumberOfPrivateDocShells > 1 || |
287 | 0 | !XRE_IsContentProcess()) { |
288 | 0 | return; |
289 | 0 | } |
290 | 0 | |
291 | 0 | mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); |
292 | 0 | cc->SendPrivateDocShellsExist(true); |
293 | 0 | } |
294 | | |
295 | | static void |
296 | | DecreasePrivateDocShellCount() |
297 | 0 | { |
298 | 0 | MOZ_ASSERT(gNumberOfPrivateDocShells > 0); |
299 | 0 | gNumberOfPrivateDocShells--; |
300 | 0 | if (!gNumberOfPrivateDocShells) { |
301 | 0 | if (XRE_IsContentProcess()) { |
302 | 0 | dom::ContentChild* cc = dom::ContentChild::GetSingleton(); |
303 | 0 | cc->SendPrivateDocShellsExist(false); |
304 | 0 | return; |
305 | 0 | } |
306 | 0 | |
307 | 0 | nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService(); |
308 | 0 | if (obsvc) { |
309 | 0 | obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr); |
310 | 0 | } |
311 | 0 | } |
312 | 0 | } |
313 | | |
314 | | nsDocShell::nsDocShell() |
315 | | : nsDocLoader() |
316 | | , mForcedCharset(nullptr) |
317 | | , mParentCharset(nullptr) |
318 | | , mTreeOwner(nullptr) |
319 | | , mChromeEventHandler(nullptr) |
320 | | , mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto) |
321 | | , mCharsetReloadState(eCharsetReloadInit) |
322 | | , mOrientationLock(hal::eScreenOrientation_None) |
323 | | , mParentCharsetSource(0) |
324 | | , mMarginWidth(-1) |
325 | | , mMarginHeight(-1) |
326 | | , mItemType(typeContent) |
327 | | , mPreviousEntryIndex(-1) |
328 | | , mLoadedEntryIndex(-1) |
329 | | , mChildOffset(0) |
330 | | , mSandboxFlags(0) |
331 | | , mBusyFlags(BUSY_FLAGS_NONE) |
332 | | , mAppType(nsIDocShell::APP_TYPE_UNKNOWN) |
333 | | , mLoadType(0) |
334 | | , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL) |
335 | | , mReferrerPolicy(0) |
336 | | , mFailedLoadType(0) |
337 | | , mFrameType(FRAME_TYPE_REGULAR) |
338 | | , mPrivateBrowsingId(0) |
339 | | , mDisplayMode(nsIDocShell::DISPLAY_MODE_BROWSER) |
340 | | , mJSRunToCompletionDepth(0) |
341 | | , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE) |
342 | | , mFullscreenAllowed(CHECK_ATTRIBUTES) |
343 | | , mCreatingDocument(false) |
344 | | #ifdef DEBUG |
345 | | , mInEnsureScriptEnv(false) |
346 | | #endif |
347 | | , mCreated(false) |
348 | | , mAllowSubframes(true) |
349 | | , mAllowPlugins(true) |
350 | | , mAllowJavascript(true) |
351 | | , mAllowMetaRedirects(true) |
352 | | , mAllowImages(true) |
353 | | , mAllowMedia(true) |
354 | | , mAllowDNSPrefetch(true) |
355 | | , mAllowWindowControl(true) |
356 | | , mAllowContentRetargeting(true) |
357 | | , mAllowContentRetargetingOnChildren(true) |
358 | | , mUseErrorPages(false) |
359 | | , mObserveErrorPages(true) |
360 | | , mCSSErrorReportingEnabled(false) |
361 | | , mAllowAuth(true) |
362 | | , mAllowKeywordFixup(false) |
363 | | , mIsOffScreenBrowser(false) |
364 | | , mIsActive(true) |
365 | | , mDisableMetaRefreshWhenInactive(false) |
366 | | , mIsAppTab(false) |
367 | | , mUseGlobalHistory(false) |
368 | | , mUseRemoteTabs(false) |
369 | | , mUseTrackingProtection(false) |
370 | | , mDeviceSizeIsPageSize(false) |
371 | | , mWindowDraggingAllowed(false) |
372 | | , mInFrameSwap(false) |
373 | | , mInheritPrivateBrowsingId(true) |
374 | | , mCanExecuteScripts(false) |
375 | | , mFiredUnloadEvent(false) |
376 | | , mEODForCurrentDocument(false) |
377 | | , mURIResultedInDocument(false) |
378 | | , mIsBeingDestroyed(false) |
379 | | , mIsExecutingOnLoadHandler(false) |
380 | | , mIsPrintingOrPP(false) |
381 | | , mSavingOldViewer(false) |
382 | | , mDynamicallyCreated(false) |
383 | | , mAffectPrivateSessionLifetime(true) |
384 | | , mInvisible(false) |
385 | | , mHasLoadedNonBlankURI(false) |
386 | | , mBlankTiming(false) |
387 | 0 | { |
388 | 0 | mHistoryID.m0 = 0; |
389 | 0 | mHistoryID.m1 = 0; |
390 | 0 | mHistoryID.m2 = 0; |
391 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
392 | 0 |
|
393 | 0 | nsContentUtils::GenerateUUIDInPlace(mHistoryID); |
394 | 0 |
|
395 | 0 | if (gDocShellCount++ == 0) { |
396 | 0 | NS_ASSERTION(sURIFixup == nullptr, |
397 | 0 | "Huh, sURIFixup not null in first nsDocShell ctor!"); |
398 | 0 |
|
399 | 0 | CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup); |
400 | 0 | } |
401 | 0 |
|
402 | 0 | MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this)); |
403 | 0 |
|
404 | | #ifdef DEBUG |
405 | | // We're counting the number of |nsDocShells| to help find leaks |
406 | | ++gNumberOfDocShells; |
407 | | if (!PR_GetEnv("MOZ_QUIET")) { |
408 | | printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %s]\n", |
409 | | (void*)this, |
410 | | gNumberOfDocShells, |
411 | | getpid(), |
412 | | nsIDToCString(mHistoryID).get()); |
413 | | } |
414 | | #endif |
415 | | } |
416 | | |
417 | | nsDocShell::~nsDocShell() |
418 | 0 | { |
419 | 0 | MOZ_ASSERT(!mObserved); |
420 | 0 |
|
421 | 0 | // Avoid notifying observers while we're in the dtor. |
422 | 0 | mIsBeingDestroyed = true; |
423 | 0 |
|
424 | 0 | Destroy(); |
425 | 0 |
|
426 | 0 | if (mSessionHistory) { |
427 | 0 | mSessionHistory->LegacySHistory()->SetRootDocShell(nullptr); |
428 | 0 | } |
429 | 0 |
|
430 | 0 | if (--gDocShellCount == 0) { |
431 | 0 | NS_IF_RELEASE(sURIFixup); |
432 | 0 | } |
433 | 0 |
|
434 | 0 | MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this)); |
435 | 0 |
|
436 | | #ifdef DEBUG |
437 | | // We're counting the number of |nsDocShells| to help find leaks |
438 | | --gNumberOfDocShells; |
439 | | if (!PR_GetEnv("MOZ_QUIET")) { |
440 | | printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %s]\n", |
441 | | (void*)this, |
442 | | gNumberOfDocShells, |
443 | | getpid(), |
444 | | nsIDToCString(mHistoryID).get()); |
445 | | } |
446 | | #endif |
447 | | } |
448 | | |
449 | | nsresult |
450 | | nsDocShell::Init() |
451 | 0 | { |
452 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
453 | 0 |
|
454 | 0 | nsresult rv = nsDocLoader::Init(); |
455 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
456 | 0 |
|
457 | 0 | NS_ASSERTION(mLoadGroup, "Something went wrong!"); |
458 | 0 |
|
459 | 0 | mContentListener = new nsDSURIContentListener(this); |
460 | 0 | rv = mContentListener->Init(); |
461 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
462 | 0 |
|
463 | 0 | // If parent intercept is not enabled then we must forward to |
464 | 0 | // the network controller from docshell. We also enable if we're |
465 | 0 | // in the parent process in order to support non-e10s configurations. |
466 | 0 | if (!ServiceWorkerParentInterceptEnabled() || XRE_IsParentProcess()) { |
467 | 0 | mInterceptController = new ServiceWorkerInterceptController(); |
468 | 0 | } |
469 | 0 |
|
470 | 0 | // We want to hold a strong ref to the loadgroup, so it better hold a weak |
471 | 0 | // ref to us... use an InterfaceRequestorProxy to do this. |
472 | 0 | nsCOMPtr<nsIInterfaceRequestor> proxy = |
473 | 0 | new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this)); |
474 | 0 | mLoadGroup->SetNotificationCallbacks(proxy); |
475 | 0 |
|
476 | 0 | rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this); |
477 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
478 | 0 |
|
479 | 0 | mBrowsingContext = BrowsingContext::Create(this); |
480 | 0 |
|
481 | 0 | // Add as |this| a progress listener to itself. A little weird, but |
482 | 0 | // simpler than reproducing all the listener-notification logic in |
483 | 0 | // overrides of the various methods via which nsDocLoader can be |
484 | 0 | // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok. |
485 | 0 | return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT | |
486 | 0 | nsIWebProgress::NOTIFY_STATE_NETWORK); |
487 | 0 | } |
488 | | |
489 | | void |
490 | | nsDocShell::DestroyChildren() |
491 | 0 | { |
492 | 0 | nsCOMPtr<nsIDocShellTreeItem> shell; |
493 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
494 | 0 | while (iter.HasMore()) { |
495 | 0 | shell = do_QueryObject(iter.GetNext()); |
496 | 0 | NS_ASSERTION(shell, "docshell has null child"); |
497 | 0 |
|
498 | 0 | if (shell) { |
499 | 0 | shell->SetTreeOwner(nullptr); |
500 | 0 | } |
501 | 0 | } |
502 | 0 |
|
503 | 0 | nsDocLoader::DestroyChildren(); |
504 | 0 | } |
505 | | |
506 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDocShell, |
507 | | nsDocLoader, |
508 | | mSessionStorageManager, |
509 | | mScriptGlobal, |
510 | | mInitialClientSource, |
511 | | mSessionHistory, |
512 | | mBrowsingContext) |
513 | | |
514 | | NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader) |
515 | | NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader) |
516 | | |
517 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell) |
518 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDocShell) |
519 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem) |
520 | 0 | NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) |
521 | 0 | NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) |
522 | 0 | NS_INTERFACE_MAP_ENTRY(nsIScrollable) |
523 | 0 | NS_INTERFACE_MAP_ENTRY(nsIRefreshURI) |
524 | 0 | NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) |
525 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
526 | 0 | NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor) |
527 | 0 | NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider) |
528 | 0 | NS_INTERFACE_MAP_ENTRY(nsILoadContext) |
529 | 0 | NS_INTERFACE_MAP_ENTRY(nsILinkHandler) |
530 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager) |
531 | 0 | NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController, |
532 | 0 | mInterceptController) |
533 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner) |
534 | 0 | NS_INTERFACE_MAP_END_INHERITING(nsDocLoader) |
535 | | |
536 | | NS_IMETHODIMP |
537 | | nsDocShell::GetInterface(const nsIID& aIID, void** aSink) |
538 | 0 | { |
539 | 0 | MOZ_ASSERT(aSink, "null out param"); |
540 | 0 |
|
541 | 0 | *aSink = nullptr; |
542 | 0 |
|
543 | 0 | if (aIID.Equals(NS_GET_IID(nsICommandManager))) { |
544 | 0 | NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE); |
545 | 0 | *aSink = mCommandManager; |
546 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) { |
547 | 0 | *aSink = mContentListener; |
548 | 0 | } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) || |
549 | 0 | aIID.Equals(NS_GET_IID(nsIGlobalObject)) || |
550 | 0 | aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) || |
551 | 0 | aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) || |
552 | 0 | aIID.Equals(NS_GET_IID(nsIDOMWindow))) && |
553 | 0 | NS_SUCCEEDED(EnsureScriptEnvironment())) { |
554 | 0 | return mScriptGlobal->QueryInterface(aIID, aSink); |
555 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIDocument)) && |
556 | 0 | NS_SUCCEEDED(EnsureContentViewer())) { |
557 | 0 | nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument(); |
558 | 0 | doc.forget(aSink); |
559 | 0 | return *aSink ? NS_OK : NS_NOINTERFACE; |
560 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) { |
561 | 0 | *aSink = nullptr; |
562 | 0 |
|
563 | 0 | // Return application cache associated with this docshell, if any |
564 | 0 |
|
565 | 0 | nsCOMPtr<nsIContentViewer> contentViewer; |
566 | 0 | GetContentViewer(getter_AddRefs(contentViewer)); |
567 | 0 | if (!contentViewer) { |
568 | 0 | return NS_ERROR_NO_INTERFACE; |
569 | 0 | } |
570 | 0 | |
571 | 0 | nsCOMPtr<nsIDocument> doc = contentViewer->GetDocument(); |
572 | 0 | NS_ASSERTION(doc, "Should have a document."); |
573 | 0 | if (!doc) { |
574 | 0 | return NS_ERROR_NO_INTERFACE; |
575 | 0 | } |
576 | 0 | |
577 | | #if defined(DEBUG) |
578 | | MOZ_LOG(gDocShellLog, LogLevel::Debug, |
579 | | ("nsDocShell[%p]: returning app cache container %p", |
580 | | this, doc.get())); |
581 | | #endif |
582 | 0 | return doc->QueryInterface(aIID, aSink); |
583 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) && |
584 | 0 | NS_SUCCEEDED(EnsureScriptEnvironment())) { |
585 | 0 | nsresult rv; |
586 | 0 | nsCOMPtr<nsIWindowWatcher> wwatch = |
587 | 0 | do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); |
588 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
589 | 0 |
|
590 | 0 | // Get the an auth prompter for our window so that the parenting |
591 | 0 | // of the dialogs works as it should when using tabs. |
592 | 0 | nsIPrompt* prompt; |
593 | 0 | rv = wwatch->GetNewPrompter(mScriptGlobal->AsOuter(), &prompt); |
594 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
595 | 0 |
|
596 | 0 | *aSink = prompt; |
597 | 0 | return NS_OK; |
598 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || |
599 | 0 | aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { |
600 | 0 | return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ? |
601 | 0 | NS_OK : NS_NOINTERFACE; |
602 | 0 | } else if (aIID.Equals(NS_GET_IID(nsISHistory))) { |
603 | 0 | RefPtr<ChildSHistory> shistory = GetSessionHistory(); |
604 | 0 | if (shistory) { |
605 | 0 | // XXX(nika): Stop exposing nsISHistory through GetInterface. |
606 | 0 | nsCOMPtr<nsISHistory> legacy = shistory->LegacySHistory(); |
607 | 0 | legacy.forget(aSink); |
608 | 0 | return NS_OK; |
609 | 0 | } |
610 | 0 | return NS_NOINTERFACE; |
611 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) { |
612 | 0 | nsresult rv = EnsureFind(); |
613 | 0 | if (NS_FAILED(rv)) { |
614 | 0 | return rv; |
615 | 0 | } |
616 | 0 | |
617 | 0 | *aSink = mFind; |
618 | 0 | NS_ADDREF((nsISupports*)*aSink); |
619 | 0 | return NS_OK; |
620 | 0 | } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) { |
621 | 0 | nsIPresShell* shell = GetPresShell(); |
622 | 0 | if (shell) { |
623 | 0 | return shell->QueryInterface(aIID, aSink); |
624 | 0 | } |
625 | 0 | } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) { |
626 | 0 | nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
627 | 0 | nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner)); |
628 | 0 | if (NS_SUCCEEDED(rv) && treeOwner) { |
629 | 0 | return treeOwner->QueryInterface(aIID, aSink); |
630 | 0 | } |
631 | 0 | } else if (aIID.Equals(NS_GET_IID(nsITabChild))) { |
632 | 0 | *aSink = GetTabChild().take(); |
633 | 0 | return *aSink ? NS_OK : NS_ERROR_FAILURE; |
634 | 0 | } else { |
635 | 0 | return nsDocLoader::GetInterface(aIID, aSink); |
636 | 0 | } |
637 | 0 | |
638 | 0 | NS_IF_ADDREF(((nsISupports*)*aSink)); |
639 | 0 | return *aSink ? NS_OK : NS_NOINTERFACE; |
640 | 0 | } |
641 | | |
642 | | NS_IMETHODIMP |
643 | | nsDocShell::LoadURI(nsIURI* aURI, |
644 | | nsDocShellLoadInfo* aLoadInfo, |
645 | | uint32_t aLoadFlags, |
646 | | bool aFirstParty) |
647 | 0 | { |
648 | 0 | MOZ_ASSERT(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0, |
649 | 0 | "Unexpected flags"); |
650 | 0 | MOZ_ASSERT((aLoadFlags & 0xf) == 0, "Should not have these flags set"); |
651 | 0 |
|
652 | 0 | // Note: we allow loads to get through here even if mFiredUnloadEvent is |
653 | 0 | // true; that case will get handled in LoadInternal or LoadHistoryEntry, |
654 | 0 | // so we pass false as the second parameter to IsNavigationAllowed. |
655 | 0 | // However, we don't allow the page to change location *in the middle of* |
656 | 0 | // firing beforeunload, so we do need to check if *beforeunload* is currently |
657 | 0 | // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP. |
658 | 0 | if (!IsNavigationAllowed(true, false)) { |
659 | 0 | return NS_OK; // JS may not handle returning of an error code |
660 | 0 | } |
661 | 0 | |
662 | 0 | nsCOMPtr<nsIURI> referrer; |
663 | 0 | nsCOMPtr<nsIURI> originalURI; |
664 | 0 | Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI; |
665 | 0 | bool keepResultPrincipalURIIfSet = false; |
666 | 0 | bool loadReplace = false; |
667 | 0 | nsCOMPtr<nsIInputStream> postStream; |
668 | 0 | nsCOMPtr<nsIInputStream> headersStream; |
669 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal; |
670 | 0 | bool inheritPrincipal = false; |
671 | 0 | bool principalIsExplicit = false; |
672 | 0 | bool sendReferrer = true; |
673 | 0 | uint32_t referrerPolicy = RP_Unset; |
674 | 0 | bool isSrcdoc = false; |
675 | 0 | nsCOMPtr<nsISHEntry> shEntry; |
676 | 0 | nsString target; |
677 | 0 | nsAutoString srcdoc; |
678 | 0 | bool forceAllowDataURI = false; |
679 | 0 | bool originalFrameSrc = false; |
680 | 0 | nsCOMPtr<nsIDocShell> sourceDocShell; |
681 | 0 | nsCOMPtr<nsIURI> baseURI; |
682 | 0 |
|
683 | 0 | uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); |
684 | 0 |
|
685 | 0 | NS_ENSURE_ARG(aURI); |
686 | 0 |
|
687 | 0 | if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) && |
688 | 0 | mItemType == typeContent && !NS_IsAboutBlank(aURI)) { |
689 | 0 | StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI); |
690 | 0 | } |
691 | 0 |
|
692 | 0 | // Extract the info from the DocShellLoadInfo struct... |
693 | 0 | if (aLoadInfo) { |
694 | 0 | referrer = aLoadInfo->Referrer(); |
695 | 0 | originalURI = aLoadInfo->OriginalURI(); |
696 | 0 | aLoadInfo->GetMaybeResultPrincipalURI(resultPrincipalURI); |
697 | 0 | keepResultPrincipalURIIfSet = aLoadInfo->KeepResultPrincipalURIIfSet(); |
698 | 0 | loadReplace = aLoadInfo->LoadReplace(); |
699 | 0 | // Get the appropriate loadType from nsIDocShellLoadInfo type |
700 | 0 | loadType = aLoadInfo->LoadType(); |
701 | 0 |
|
702 | 0 | triggeringPrincipal = aLoadInfo->TriggeringPrincipal(); |
703 | 0 | inheritPrincipal = aLoadInfo->InheritPrincipal(); |
704 | 0 | principalIsExplicit = aLoadInfo->PrincipalIsExplicit(); |
705 | 0 | shEntry = aLoadInfo->SHEntry(); |
706 | 0 | aLoadInfo->GetTarget(target); |
707 | 0 | postStream = aLoadInfo->PostDataStream(); |
708 | 0 | headersStream = aLoadInfo->HeadersStream(); |
709 | 0 | sendReferrer = aLoadInfo->SendReferrer(); |
710 | 0 | referrerPolicy = aLoadInfo->ReferrerPolicy(); |
711 | 0 | isSrcdoc = aLoadInfo->IsSrcdocLoad(); |
712 | 0 | aLoadInfo->GetSrcdocData(srcdoc); |
713 | 0 | sourceDocShell = aLoadInfo->SourceDocShell(); |
714 | 0 | baseURI = aLoadInfo->BaseURI(); |
715 | 0 | forceAllowDataURI = aLoadInfo->ForceAllowDataURI(); |
716 | 0 | originalFrameSrc = aLoadInfo->OriginalFrameSrc(); |
717 | 0 | } |
718 | 0 |
|
719 | 0 | MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, |
720 | 0 | ("nsDocShell[%p]: loading %s with flags 0x%08x", |
721 | 0 | this, aURI->GetSpecOrDefault().get(), aLoadFlags)); |
722 | 0 |
|
723 | 0 | if (!shEntry && |
724 | 0 | !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) { |
725 | 0 | // First verify if this is a subframe. |
726 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
727 | 0 | GetSameTypeParent(getter_AddRefs(parentAsItem)); |
728 | 0 | nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem)); |
729 | 0 | uint32_t parentLoadType; |
730 | 0 |
|
731 | 0 | if (parentDS && parentDS != static_cast<nsIDocShell*>(this)) { |
732 | 0 | /* OK. It is a subframe. Checkout the |
733 | 0 | * parent's loadtype. If the parent was loaded thro' a history |
734 | 0 | * mechanism, then get the SH entry for the child from the parent. |
735 | 0 | * This is done to restore frameset navigation while going back/forward. |
736 | 0 | * If the parent was loaded through any other loadType, set the |
737 | 0 | * child's loadType too accordingly, so that session history does not |
738 | 0 | * get confused. |
739 | 0 | */ |
740 | 0 |
|
741 | 0 | // Get the parent's load type |
742 | 0 | parentDS->GetLoadType(&parentLoadType); |
743 | 0 |
|
744 | 0 | // Get the ShEntry for the child from the parent |
745 | 0 | nsCOMPtr<nsISHEntry> currentSH; |
746 | 0 | bool oshe = false; |
747 | 0 | parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe); |
748 | 0 | bool dynamicallyAddedChild = mDynamicallyCreated; |
749 | 0 | if (!dynamicallyAddedChild && !oshe && currentSH) { |
750 | 0 | currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild); |
751 | 0 | } |
752 | 0 | if (!dynamicallyAddedChild) { |
753 | 0 | // Only use the old SHEntry, if we're sure enough that |
754 | 0 | // it wasn't originally for some other frame. |
755 | 0 | parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry)); |
756 | 0 | } |
757 | 0 |
|
758 | 0 | // Make some decisions on the child frame's loadType based on the |
759 | 0 | // parent's loadType, if the subframe hasn't loaded anything into it. |
760 | 0 | // |
761 | 0 | // In some cases privileged scripts may try to get the DOMWindow |
762 | 0 | // reference of this docshell before the loading starts, causing the |
763 | 0 | // initial about:blank content viewer being created and mCurrentURI being |
764 | 0 | // set. To handle this case we check if mCurrentURI is about:blank and |
765 | 0 | // currentSHEntry is null. |
766 | 0 | nsCOMPtr<nsISHEntry> currentChildEntry; |
767 | 0 | GetCurrentSHEntry(getter_AddRefs(currentChildEntry), &oshe); |
768 | 0 | if (!mCurrentURI || (NS_IsAboutBlank(mCurrentURI) && !currentChildEntry)) { |
769 | 0 | // This is a newly created frame. Check for exception cases first. |
770 | 0 | // By default the subframe will inherit the parent's loadType. |
771 | 0 | if (shEntry && (parentLoadType == LOAD_NORMAL || |
772 | 0 | parentLoadType == LOAD_LINK || |
773 | 0 | parentLoadType == LOAD_NORMAL_EXTERNAL)) { |
774 | 0 | // The parent was loaded normally. In this case, this *brand new* |
775 | 0 | // child really shouldn't have a SHEntry. If it does, it could be |
776 | 0 | // because the parent is replacing an existing frame with a new frame, |
777 | 0 | // in the onLoadHandler. We don't want this url to get into session |
778 | 0 | // history. Clear off shEntry, and set load type to |
779 | 0 | // LOAD_BYPASS_HISTORY. |
780 | 0 | bool inOnLoadHandler = false; |
781 | 0 | parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
782 | 0 | if (inOnLoadHandler) { |
783 | 0 | loadType = LOAD_NORMAL_REPLACE; |
784 | 0 | shEntry = nullptr; |
785 | 0 | } |
786 | 0 | } else if (parentLoadType == LOAD_REFRESH) { |
787 | 0 | // Clear shEntry. For refresh loads, we have to load |
788 | 0 | // what comes thro' the pipe, not what's in history. |
789 | 0 | shEntry = nullptr; |
790 | 0 | } else if ((parentLoadType == LOAD_BYPASS_HISTORY) || |
791 | 0 | (shEntry && |
792 | 0 | ((parentLoadType & LOAD_CMD_HISTORY) || |
793 | 0 | (parentLoadType == LOAD_RELOAD_NORMAL) || |
794 | 0 | (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) || |
795 | 0 | (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE) || |
796 | 0 | (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)))) { |
797 | 0 | // If the parent url, bypassed history or was loaded from |
798 | 0 | // history, pass on the parent's loadType to the new child |
799 | 0 | // frame too, so that the child frame will also |
800 | 0 | // avoid getting into history. |
801 | 0 | loadType = parentLoadType; |
802 | 0 | } else if (parentLoadType == LOAD_ERROR_PAGE) { |
803 | 0 | // If the parent document is an error page, we don't |
804 | 0 | // want to update global/session history. However, |
805 | 0 | // this child frame is not an error page. |
806 | 0 | loadType = LOAD_BYPASS_HISTORY; |
807 | 0 | } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) || |
808 | 0 | (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) || |
809 | 0 | (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) { |
810 | 0 | // the new frame should inherit the parent's load type so that it also |
811 | 0 | // bypasses the cache and/or proxy |
812 | 0 | loadType = parentLoadType; |
813 | 0 | } |
814 | 0 | } else { |
815 | 0 | // This is a pre-existing subframe. If |
816 | 0 | // 1. The load of this frame was not originally initiated by session |
817 | 0 | // history directly (i.e. (!shEntry) condition succeeded, but it can |
818 | 0 | // still be a history load on parent which causes this frame being |
819 | 0 | // loaded), and |
820 | 0 | // 2. mCurrentURI is not null, nor the initial about:blank, |
821 | 0 | // it is possible that a parent's onLoadHandler or even self's |
822 | 0 | // onLoadHandler is loading a new page in this child. Check parent's and |
823 | 0 | // self's busy flag and if it is set, we don't want this onLoadHandler |
824 | 0 | // load to get in to session history. |
825 | 0 | uint32_t parentBusy = BUSY_FLAGS_NONE; |
826 | 0 | uint32_t selfBusy = BUSY_FLAGS_NONE; |
827 | 0 | parentDS->GetBusyFlags(&parentBusy); |
828 | 0 | GetBusyFlags(&selfBusy); |
829 | 0 | if (parentBusy & BUSY_FLAGS_BUSY || |
830 | 0 | selfBusy & BUSY_FLAGS_BUSY) { |
831 | 0 | loadType = LOAD_NORMAL_REPLACE; |
832 | 0 | shEntry = nullptr; |
833 | 0 | } |
834 | 0 | } |
835 | 0 | } // parentDS |
836 | 0 | else { |
837 | 0 | // This is the root docshell. If we got here while |
838 | 0 | // executing an onLoad Handler,this load will not go |
839 | 0 | // into session history. |
840 | 0 | bool inOnLoadHandler = false; |
841 | 0 | GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
842 | 0 | if (inOnLoadHandler) { |
843 | 0 | loadType = LOAD_NORMAL_REPLACE; |
844 | 0 | } |
845 | 0 | } |
846 | 0 | } // !shEntry |
847 | 0 |
|
848 | 0 | if (shEntry) { |
849 | | #ifdef DEBUG |
850 | | MOZ_LOG(gDocShellLog, LogLevel::Debug, |
851 | | ("nsDocShell[%p]: loading from session history", this)); |
852 | | #endif |
853 | |
|
854 | 0 | return LoadHistoryEntry(shEntry, loadType); |
855 | 0 | } |
856 | 0 |
|
857 | 0 | // On history navigation via Back/Forward buttons, don't execute |
858 | 0 | // automatic JavaScript redirection such as |location.href = ...| or |
859 | 0 | // |window.open()| |
860 | 0 | // |
861 | 0 | // LOAD_NORMAL: window.open(...) etc. |
862 | 0 | // LOAD_STOP_CONTENT: location.href = ..., location.assign(...) |
863 | 0 | if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) && |
864 | 0 | ShouldBlockLoadingForBackButton()) { |
865 | 0 | return NS_OK; |
866 | 0 | } |
867 | 0 | |
868 | 0 | // Perform the load... |
869 | 0 | |
870 | 0 | // We need a principalToInherit. |
871 | 0 | // |
872 | 0 | // If principalIsExplicit is not set there are 4 possibilities: |
873 | 0 | // (1) If the system principal or an expanded principal was passed |
874 | 0 | // in and we're a typeContent docshell, inherit the principal |
875 | 0 | // from the current document instead. |
876 | 0 | // (2) In all other cases when the principal passed in is not null, |
877 | 0 | // use that principal. |
878 | 0 | // (3) If the caller has allowed inheriting from the current document, |
879 | 0 | // or if we're being called from system code (eg chrome JS or pure |
880 | 0 | // C++) then inheritPrincipal should be true and InternalLoad will get |
881 | 0 | // a principal from the current document. If none of these things are |
882 | 0 | // true, then |
883 | 0 | // (4) we don't pass a principal into the channel, and a principal will be |
884 | 0 | // created later from the channel's internal data. |
885 | 0 | // |
886 | 0 | // If principalIsExplicit *is* set, there are 4 possibilities |
887 | 0 | // (1) If the system principal or an expanded principal was passed in |
888 | 0 | // and we're a typeContent docshell, return an error. |
889 | 0 | // (2) In all other cases when the principal passed in is not null, |
890 | 0 | // use that principal. |
891 | 0 | // (3) If the caller has allowed inheriting from the current document, |
892 | 0 | // then inheritPrincipal should be true and InternalLoad will get |
893 | 0 | // a principal from the current document. If none of these things are |
894 | 0 | // true, then |
895 | 0 | // (4) we dont' pass a principal into the channel, and a principal will be |
896 | 0 | // created later from the channel's internal data. |
897 | 0 | nsCOMPtr<nsIPrincipal> principalToInherit = triggeringPrincipal; |
898 | 0 | if (principalToInherit && mItemType != typeChrome) { |
899 | 0 | if (nsContentUtils::IsSystemPrincipal(principalToInherit)) { |
900 | 0 | if (principalIsExplicit) { |
901 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
902 | 0 | } |
903 | 0 | principalToInherit = nullptr; |
904 | 0 | inheritPrincipal = true; |
905 | 0 | } else if (nsContentUtils::IsExpandedPrincipal(principalToInherit)) { |
906 | 0 | if (principalIsExplicit) { |
907 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
908 | 0 | } |
909 | 0 | // Don't inherit from the current page. Just do the safe thing |
910 | 0 | // and pretend that we were loaded by a nullprincipal. |
911 | 0 | // |
912 | 0 | // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't |
913 | 0 | // have origin attributes. |
914 | 0 | principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this); |
915 | 0 | inheritPrincipal = false; |
916 | 0 | } |
917 | 0 | } |
918 | 0 | if (!principalToInherit && !inheritPrincipal && !principalIsExplicit) { |
919 | 0 | // See if there's system or chrome JS code running |
920 | 0 | inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode(); |
921 | 0 | } |
922 | 0 |
|
923 | 0 | if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) { |
924 | 0 | inheritPrincipal = false; |
925 | 0 | // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is |
926 | 0 | // enabled, we will set firstPartyDomain on the origin attributes. |
927 | 0 | principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty); |
928 | 0 | } |
929 | 0 |
|
930 | 0 | // If the triggeringPrincipal is not passed explicitly, we first try to create |
931 | 0 | // a principal from the referrer, since the referrer URI reflects the web origin |
932 | 0 | // that triggered the load. If there is no referrer URI, we fall back to using |
933 | 0 | // the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal |
934 | 0 | // and no referrer simulate a load that was triggered by the system. |
935 | 0 | // It's important to note that this block of code needs to appear *after* the block |
936 | 0 | // where we munge the principalToInherit, because otherwise we would never enter |
937 | 0 | // code blocks checking if the principalToInherit is null and we will end up with |
938 | 0 | // a wrong inheritPrincipal flag. |
939 | 0 | if (!triggeringPrincipal) { |
940 | 0 | if (referrer) { |
941 | 0 | nsresult rv = CreatePrincipalFromReferrer(referrer, |
942 | 0 | getter_AddRefs(triggeringPrincipal)); |
943 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
944 | 0 | } |
945 | 0 | else { |
946 | 0 | triggeringPrincipal = nsContentUtils::GetSystemPrincipal(); |
947 | 0 | } |
948 | 0 | } |
949 | 0 |
|
950 | 0 | uint32_t flags = 0; |
951 | 0 |
|
952 | 0 | if (inheritPrincipal) { |
953 | 0 | MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(principalToInherit), "Should not inherit SystemPrincipal"); |
954 | 0 | flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL; |
955 | 0 | } |
956 | 0 |
|
957 | 0 | if (!sendReferrer) { |
958 | 0 | flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; |
959 | 0 | } |
960 | 0 |
|
961 | 0 | if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { |
962 | 0 | flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; |
963 | 0 | } |
964 | 0 |
|
965 | 0 | if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) { |
966 | 0 | flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; |
967 | 0 | } |
968 | 0 |
|
969 | 0 | if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) { |
970 | 0 | flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; |
971 | 0 | } |
972 | 0 |
|
973 | 0 | if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) { |
974 | 0 | flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES; |
975 | 0 | } |
976 | 0 |
|
977 | 0 | if (isSrcdoc) { |
978 | 0 | flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; |
979 | 0 | } |
980 | 0 |
|
981 | 0 | if (forceAllowDataURI) { |
982 | 0 | flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI; |
983 | 0 | } |
984 | 0 |
|
985 | 0 | if (originalFrameSrc) { |
986 | 0 | flags |= INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC; |
987 | 0 | } |
988 | 0 |
|
989 | 0 | return InternalLoad(aURI, |
990 | 0 | originalURI, |
991 | 0 | resultPrincipalURI, |
992 | 0 | keepResultPrincipalURIIfSet, |
993 | 0 | loadReplace, |
994 | 0 | referrer, |
995 | 0 | referrerPolicy, |
996 | 0 | triggeringPrincipal, |
997 | 0 | principalToInherit, |
998 | 0 | flags, |
999 | 0 | target, |
1000 | 0 | nullptr, // No type hint |
1001 | 0 | VoidString(), // No forced download |
1002 | 0 | postStream, |
1003 | 0 | headersStream, |
1004 | 0 | loadType, |
1005 | 0 | nullptr, // No SHEntry |
1006 | 0 | aFirstParty, |
1007 | 0 | srcdoc, |
1008 | 0 | sourceDocShell, |
1009 | 0 | baseURI, |
1010 | 0 | nullptr, // No nsIDocShell |
1011 | 0 | nullptr); // No nsIRequest |
1012 | 0 | } |
1013 | | |
1014 | | /* |
1015 | | * Reset state to a new content model within the current document and the |
1016 | | * document viewer. Called by the document before initiating an out of band |
1017 | | * document.write(). |
1018 | | */ |
1019 | | NS_IMETHODIMP |
1020 | | nsDocShell::PrepareForNewContentModel() |
1021 | 0 | { |
1022 | 0 | mEODForCurrentDocument = false; |
1023 | 0 | return NS_OK; |
1024 | 0 | } |
1025 | | |
1026 | | NS_IMETHODIMP |
1027 | | nsDocShell::FirePageHideNotification(bool aIsUnload) |
1028 | 0 | { |
1029 | 0 | FirePageHideNotificationInternal(aIsUnload, false); |
1030 | 0 | return NS_OK; |
1031 | 0 | } |
1032 | | |
1033 | | void |
1034 | | nsDocShell::FirePageHideNotificationInternal(bool aIsUnload, |
1035 | | bool aSkipCheckingDynEntries) |
1036 | 0 | { |
1037 | 0 | if (mContentViewer && !mFiredUnloadEvent) { |
1038 | 0 | // Keep an explicit reference since calling PageHide could release |
1039 | 0 | // mContentViewer |
1040 | 0 | nsCOMPtr<nsIContentViewer> contentViewer(mContentViewer); |
1041 | 0 | mFiredUnloadEvent = true; |
1042 | 0 |
|
1043 | 0 | if (mTiming) { |
1044 | 0 | mTiming->NotifyUnloadEventStart(); |
1045 | 0 | } |
1046 | 0 |
|
1047 | 0 | contentViewer->PageHide(aIsUnload); |
1048 | 0 |
|
1049 | 0 | if (mTiming) { |
1050 | 0 | mTiming->NotifyUnloadEventEnd(); |
1051 | 0 | } |
1052 | 0 |
|
1053 | 0 | AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids; |
1054 | 0 | uint32_t n = mChildList.Length(); |
1055 | 0 | kids.SetCapacity(n); |
1056 | 0 | for (uint32_t i = 0; i < n; i++) { |
1057 | 0 | kids.AppendElement(do_QueryInterface(ChildAt(i))); |
1058 | 0 | } |
1059 | 0 |
|
1060 | 0 | n = kids.Length(); |
1061 | 0 | for (uint32_t i = 0; i < n; ++i) { |
1062 | 0 | RefPtr<nsDocShell> child = static_cast<nsDocShell*>(kids[i].get()); |
1063 | 0 | if (child) { |
1064 | 0 | // Skip checking dynamic subframe entries in our children. |
1065 | 0 | child->FirePageHideNotificationInternal(aIsUnload, true); |
1066 | 0 | } |
1067 | 0 | } |
1068 | 0 |
|
1069 | 0 | // If the document is unloading, remove all dynamic subframe entries. |
1070 | 0 | if (aIsUnload && !aSkipCheckingDynEntries) { |
1071 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
1072 | 0 | if (rootSH && mOSHE) { |
1073 | 0 | int32_t index = rootSH->Index(); |
1074 | 0 | rootSH->LegacySHistory()->RemoveDynEntries(index, mOSHE); |
1075 | 0 | } |
1076 | 0 | } |
1077 | 0 |
|
1078 | 0 | // Now make sure our editor, if any, is detached before we go |
1079 | 0 | // any farther. |
1080 | 0 | DetachEditorFromWindow(); |
1081 | 0 | } |
1082 | 0 | } |
1083 | | |
1084 | | nsresult |
1085 | | nsDocShell::DispatchToTabGroup(TaskCategory aCategory, |
1086 | | already_AddRefed<nsIRunnable>&& aRunnable) |
1087 | 0 | { |
1088 | 0 | // Hold the ref so we won't forget to release it. |
1089 | 0 | nsCOMPtr<nsIRunnable> runnable(aRunnable); |
1090 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
1091 | 0 | if (!win) { |
1092 | 0 | // Window should only be unavailable after destroyed. |
1093 | 0 | MOZ_ASSERT(mIsBeingDestroyed); |
1094 | 0 | return NS_ERROR_FAILURE; |
1095 | 0 | } |
1096 | 0 |
|
1097 | 0 | if (win->GetDocGroup()) { |
1098 | 0 | return win->GetDocGroup()->Dispatch(aCategory, runnable.forget()); |
1099 | 0 | } |
1100 | 0 | RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup(); |
1101 | 0 | return tabGroup->Dispatch(aCategory, runnable.forget()); |
1102 | 0 | } |
1103 | | |
1104 | | NS_IMETHODIMP |
1105 | | nsDocShell::DispatchLocationChangeEvent() |
1106 | 0 | { |
1107 | 0 | return DispatchToTabGroup( |
1108 | 0 | TaskCategory::Other, |
1109 | 0 | NewRunnableMethod("nsDocShell::FireDummyOnLocationChange", |
1110 | 0 | this, |
1111 | 0 | &nsDocShell::FireDummyOnLocationChange)); |
1112 | 0 | } |
1113 | | |
1114 | | bool |
1115 | | nsDocShell::MaybeInitTiming() |
1116 | 0 | { |
1117 | 0 | if (mTiming && !mBlankTiming) { |
1118 | 0 | return false; |
1119 | 0 | } |
1120 | 0 | |
1121 | 0 | bool canBeReset = false; |
1122 | 0 |
|
1123 | 0 | if (mScriptGlobal && mBlankTiming) { |
1124 | 0 | nsPIDOMWindowInner* innerWin = |
1125 | 0 | mScriptGlobal->AsOuter()->GetCurrentInnerWindow(); |
1126 | 0 | if (innerWin && innerWin->GetPerformance()) { |
1127 | 0 | mTiming = innerWin->GetPerformance()->GetDOMTiming(); |
1128 | 0 | mBlankTiming = false; |
1129 | 0 | } |
1130 | 0 | } |
1131 | 0 |
|
1132 | 0 | if (!mTiming) { |
1133 | 0 | mTiming = new nsDOMNavigationTiming(this); |
1134 | 0 | canBeReset = true; |
1135 | 0 | } |
1136 | 0 |
|
1137 | 0 | mTiming->NotifyNavigationStart( |
1138 | 0 | mIsActive ? nsDOMNavigationTiming::DocShellState::eActive |
1139 | 0 | : nsDOMNavigationTiming::DocShellState::eInactive); |
1140 | 0 |
|
1141 | 0 | return canBeReset; |
1142 | 0 | } |
1143 | | |
1144 | | void |
1145 | | nsDocShell::MaybeResetInitTiming(bool aReset) |
1146 | 0 | { |
1147 | 0 | if (aReset) { |
1148 | 0 | mTiming = nullptr; |
1149 | 0 | } |
1150 | 0 | } |
1151 | | |
1152 | | nsDOMNavigationTiming* |
1153 | | nsDocShell::GetNavigationTiming() const |
1154 | 0 | { |
1155 | 0 | return mTiming; |
1156 | 0 | } |
1157 | | |
1158 | | // |
1159 | | // Bug 13871: Prevent frameset spoofing |
1160 | | // |
1161 | | // This routine answers: 'Is origin's document from same domain as |
1162 | | // target's document?' |
1163 | | // |
1164 | | // file: uris are considered the same domain for the purpose of |
1165 | | // frame navigation regardless of script accessibility (bug 420425) |
1166 | | // |
1167 | | /* static */ bool |
1168 | | nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem, |
1169 | | nsIDocShellTreeItem* aTargetTreeItem) |
1170 | 0 | { |
1171 | 0 | // We want to bypass this check for chrome callers, but only if there's |
1172 | 0 | // JS on the stack. System callers still need to do it. |
1173 | 0 | if (nsContentUtils::GetCurrentJSContext() && |
1174 | 0 | nsContentUtils::IsCallerChrome()) { |
1175 | 0 | return true; |
1176 | 0 | } |
1177 | 0 | |
1178 | 0 | MOZ_ASSERT(aOriginTreeItem && aTargetTreeItem, "need two docshells"); |
1179 | 0 |
|
1180 | 0 | // Get origin document principal |
1181 | 0 | nsCOMPtr<nsIDocument> originDocument = aOriginTreeItem->GetDocument(); |
1182 | 0 | NS_ENSURE_TRUE(originDocument, false); |
1183 | 0 |
|
1184 | 0 | // Get target principal |
1185 | 0 | nsCOMPtr<nsIDocument> targetDocument = aTargetTreeItem->GetDocument(); |
1186 | 0 | NS_ENSURE_TRUE(targetDocument, false); |
1187 | 0 |
|
1188 | 0 | bool equal; |
1189 | 0 | nsresult rv = originDocument->NodePrincipal()->Equals( |
1190 | 0 | targetDocument->NodePrincipal(), &equal); |
1191 | 0 | if (NS_SUCCEEDED(rv) && equal) { |
1192 | 0 | return true; |
1193 | 0 | } |
1194 | 0 | |
1195 | 0 | // Not strictly equal, special case if both are file: uris |
1196 | 0 | bool originIsFile = false; |
1197 | 0 | bool targetIsFile = false; |
1198 | 0 | nsCOMPtr<nsIURI> originURI; |
1199 | 0 | nsCOMPtr<nsIURI> targetURI; |
1200 | 0 | nsCOMPtr<nsIURI> innerOriginURI; |
1201 | 0 | nsCOMPtr<nsIURI> innerTargetURI; |
1202 | 0 |
|
1203 | 0 | rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI)); |
1204 | 0 | if (NS_SUCCEEDED(rv) && originURI) { |
1205 | 0 | innerOriginURI = NS_GetInnermostURI(originURI); |
1206 | 0 | } |
1207 | 0 |
|
1208 | 0 | rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI)); |
1209 | 0 | if (NS_SUCCEEDED(rv) && targetURI) { |
1210 | 0 | innerTargetURI = NS_GetInnermostURI(targetURI); |
1211 | 0 | } |
1212 | 0 |
|
1213 | 0 | return innerOriginURI && innerTargetURI && |
1214 | 0 | NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) && |
1215 | 0 | NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) && |
1216 | 0 | originIsFile && targetIsFile; |
1217 | 0 | } |
1218 | | |
1219 | | nsresult |
1220 | | nsDocShell::GetEldestPresContext(nsPresContext** aPresContext) |
1221 | 0 | { |
1222 | 0 | NS_ENSURE_ARG_POINTER(aPresContext); |
1223 | 0 | *aPresContext = nullptr; |
1224 | 0 |
|
1225 | 0 | nsCOMPtr<nsIContentViewer> viewer = mContentViewer; |
1226 | 0 | while (viewer) { |
1227 | 0 | nsCOMPtr<nsIContentViewer> prevViewer; |
1228 | 0 | viewer->GetPreviousViewer(getter_AddRefs(prevViewer)); |
1229 | 0 | if (!prevViewer) { |
1230 | 0 | return viewer->GetPresContext(aPresContext); |
1231 | 0 | } |
1232 | 0 | viewer = prevViewer; |
1233 | 0 | } |
1234 | 0 |
|
1235 | 0 | return NS_OK; |
1236 | 0 | } |
1237 | | |
1238 | | NS_IMETHODIMP |
1239 | | nsDocShell::GetPresContext(nsPresContext** aPresContext) |
1240 | 0 | { |
1241 | 0 | NS_ENSURE_ARG_POINTER(aPresContext); |
1242 | 0 | *aPresContext = nullptr; |
1243 | 0 |
|
1244 | 0 | if (!mContentViewer) { |
1245 | 0 | return NS_OK; |
1246 | 0 | } |
1247 | 0 | |
1248 | 0 | return mContentViewer->GetPresContext(aPresContext); |
1249 | 0 | } |
1250 | | |
1251 | | NS_IMETHODIMP_(nsIPresShell*) |
1252 | | nsDocShell::GetPresShell() |
1253 | 0 | { |
1254 | 0 | RefPtr<nsPresContext> presContext; |
1255 | 0 | (void)GetPresContext(getter_AddRefs(presContext)); |
1256 | 0 | return presContext ? presContext->GetPresShell() : nullptr; |
1257 | 0 | } |
1258 | | |
1259 | | NS_IMETHODIMP |
1260 | | nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell) |
1261 | 0 | { |
1262 | 0 | nsresult rv = NS_OK; |
1263 | 0 |
|
1264 | 0 | NS_ENSURE_ARG_POINTER(aPresShell); |
1265 | 0 | *aPresShell = nullptr; |
1266 | 0 |
|
1267 | 0 | RefPtr<nsPresContext> presContext; |
1268 | 0 | (void)GetEldestPresContext(getter_AddRefs(presContext)); |
1269 | 0 |
|
1270 | 0 | if (presContext) { |
1271 | 0 | NS_IF_ADDREF(*aPresShell = presContext->GetPresShell()); |
1272 | 0 | } |
1273 | 0 |
|
1274 | 0 | return rv; |
1275 | 0 | } |
1276 | | |
1277 | | NS_IMETHODIMP |
1278 | | nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer) |
1279 | 0 | { |
1280 | 0 | NS_ENSURE_ARG_POINTER(aContentViewer); |
1281 | 0 |
|
1282 | 0 | *aContentViewer = mContentViewer; |
1283 | 0 | NS_IF_ADDREF(*aContentViewer); |
1284 | 0 | return NS_OK; |
1285 | 0 | } |
1286 | | |
1287 | | NS_IMETHODIMP |
1288 | | nsDocShell::SetChromeEventHandler(EventTarget* aChromeEventHandler) |
1289 | 0 | { |
1290 | 0 | // Weak reference. Don't addref. |
1291 | 0 | mChromeEventHandler = aChromeEventHandler; |
1292 | 0 |
|
1293 | 0 | if (mScriptGlobal) { |
1294 | 0 | mScriptGlobal->SetChromeEventHandler(mChromeEventHandler); |
1295 | 0 | } |
1296 | 0 |
|
1297 | 0 | return NS_OK; |
1298 | 0 | } |
1299 | | |
1300 | | NS_IMETHODIMP |
1301 | | nsDocShell::GetChromeEventHandler(EventTarget** aChromeEventHandler) |
1302 | 0 | { |
1303 | 0 | NS_ENSURE_ARG_POINTER(aChromeEventHandler); |
1304 | 0 | nsCOMPtr<EventTarget> handler = mChromeEventHandler; |
1305 | 0 | handler.forget(aChromeEventHandler); |
1306 | 0 | return NS_OK; |
1307 | 0 | } |
1308 | | |
1309 | | NS_IMETHODIMP |
1310 | | nsDocShell::SetCurrentURI(nsIURI* aURI) |
1311 | 0 | { |
1312 | 0 | // Note that securityUI will set STATE_IS_INSECURE, even if |
1313 | 0 | // the scheme of |aURI| is "https". |
1314 | 0 | SetCurrentURI(aURI, nullptr, true, 0); |
1315 | 0 | return NS_OK; |
1316 | 0 | } |
1317 | | |
1318 | | bool |
1319 | | nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest, |
1320 | | bool aFireOnLocationChange, uint32_t aLocationFlags) |
1321 | 0 | { |
1322 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
1323 | 0 |
|
1324 | 0 | MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, |
1325 | 0 | ("DOCSHELL %p SetCurrentURI %s\n", |
1326 | 0 | this, aURI ? aURI->GetSpecOrDefault().get() : "")); |
1327 | 0 |
|
1328 | 0 | // We don't want to send a location change when we're displaying an error |
1329 | 0 | // page, and we don't want to change our idea of "current URI" either |
1330 | 0 | if (mLoadType == LOAD_ERROR_PAGE) { |
1331 | 0 | return false; |
1332 | 0 | } |
1333 | 0 | |
1334 | 0 | mCurrentURI = aURI; |
1335 | 0 |
|
1336 | 0 | if (!NS_IsAboutBlank(mCurrentURI)) { |
1337 | 0 | mHasLoadedNonBlankURI = true; |
1338 | 0 | } |
1339 | 0 |
|
1340 | 0 | bool isRoot = false; // Is this the root docshell |
1341 | 0 | bool isSubFrame = false; // Is this a subframe navigation? |
1342 | 0 |
|
1343 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
1344 | 0 |
|
1345 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(root)); |
1346 | 0 | if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) { |
1347 | 0 | // This is the root docshell |
1348 | 0 | isRoot = true; |
1349 | 0 | } |
1350 | 0 | if (mLSHE) { |
1351 | 0 | isSubFrame = mLSHE->GetIsSubFrame(); |
1352 | 0 | } |
1353 | 0 |
|
1354 | 0 | if (!isSubFrame && !isRoot) { |
1355 | 0 | /* |
1356 | 0 | * We don't want to send OnLocationChange notifications when |
1357 | 0 | * a subframe is being loaded for the first time, while |
1358 | 0 | * visiting a frameset page |
1359 | 0 | */ |
1360 | 0 | return false; |
1361 | 0 | } |
1362 | 0 | |
1363 | 0 | if (aFireOnLocationChange) { |
1364 | 0 | FireOnLocationChange(this, aRequest, aURI, aLocationFlags); |
1365 | 0 | } |
1366 | 0 | return !aFireOnLocationChange; |
1367 | 0 | } |
1368 | | |
1369 | | NS_IMETHODIMP |
1370 | | nsDocShell::GetCharset(nsACString& aCharset) |
1371 | 0 | { |
1372 | 0 | aCharset.Truncate(); |
1373 | 0 |
|
1374 | 0 | nsIPresShell* presShell = GetPresShell(); |
1375 | 0 | NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); |
1376 | 0 | nsIDocument* doc = presShell->GetDocument(); |
1377 | 0 | NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
1378 | 0 | doc->GetDocumentCharacterSet()->Name(aCharset); |
1379 | 0 | return NS_OK; |
1380 | 0 | } |
1381 | | |
1382 | | NS_IMETHODIMP |
1383 | | nsDocShell::GatherCharsetMenuTelemetry() |
1384 | 0 | { |
1385 | 0 | nsCOMPtr<nsIContentViewer> viewer; |
1386 | 0 | GetContentViewer(getter_AddRefs(viewer)); |
1387 | 0 | if (!viewer) { |
1388 | 0 | return NS_OK; |
1389 | 0 | } |
1390 | 0 | |
1391 | 0 | nsIDocument* doc = viewer->GetDocument(); |
1392 | 0 | if (!doc || doc->WillIgnoreCharsetOverride()) { |
1393 | 0 | return NS_OK; |
1394 | 0 | } |
1395 | 0 | |
1396 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true); |
1397 | 0 |
|
1398 | 0 | bool isFileURL = false; |
1399 | 0 | nsIURI* url = doc->GetOriginalURI(); |
1400 | 0 | if (url) { |
1401 | 0 | url->SchemeIs("file", &isFileURL); |
1402 | 0 | } |
1403 | 0 |
|
1404 | 0 | int32_t charsetSource = doc->GetDocumentCharacterSetSource(); |
1405 | 0 | switch (charsetSource) { |
1406 | 0 | case kCharsetFromTopLevelDomain: |
1407 | 0 | // Unlabeled doc on a domain that we map to a fallback encoding |
1408 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7); |
1409 | 0 | break; |
1410 | 0 | case kCharsetFromFallback: |
1411 | 0 | case kCharsetFromDocTypeDefault: |
1412 | 0 | case kCharsetFromCache: |
1413 | 0 | case kCharsetFromParentFrame: |
1414 | 0 | case kCharsetFromHintPrevDoc: |
1415 | 0 | // Changing charset on an unlabeled doc. |
1416 | 0 | if (isFileURL) { |
1417 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0); |
1418 | 0 | } else { |
1419 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1); |
1420 | 0 | } |
1421 | 0 | break; |
1422 | 0 | case kCharsetFromAutoDetection: |
1423 | 0 | // Changing charset on unlabeled doc where chardet fired |
1424 | 0 | if (isFileURL) { |
1425 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2); |
1426 | 0 | } else { |
1427 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3); |
1428 | 0 | } |
1429 | 0 | break; |
1430 | 0 | case kCharsetFromMetaPrescan: |
1431 | 0 | case kCharsetFromMetaTag: |
1432 | 0 | case kCharsetFromChannel: |
1433 | 0 | // Changing charset on a doc that had a charset label. |
1434 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4); |
1435 | 0 | break; |
1436 | 0 | case kCharsetFromParentForced: |
1437 | 0 | case kCharsetFromUserForced: |
1438 | 0 | // Changing charset on a document that already had an override. |
1439 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5); |
1440 | 0 | break; |
1441 | 0 | case kCharsetFromIrreversibleAutoDetection: |
1442 | 0 | case kCharsetFromOtherComponent: |
1443 | 0 | case kCharsetFromByteOrderMark: |
1444 | 0 | case kCharsetUninitialized: |
1445 | 0 | default: |
1446 | 0 | // Bug. This isn't supposed to happen. |
1447 | 0 | Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6); |
1448 | 0 | break; |
1449 | 0 | } |
1450 | 0 | return NS_OK; |
1451 | 0 | } |
1452 | | |
1453 | | NS_IMETHODIMP |
1454 | | nsDocShell::SetCharset(const nsACString& aCharset) |
1455 | 0 | { |
1456 | 0 | // set the charset override |
1457 | 0 | return SetForcedCharset(aCharset); |
1458 | 0 | } |
1459 | | |
1460 | | NS_IMETHODIMP |
1461 | | nsDocShell::SetForcedCharset(const nsACString& aCharset) |
1462 | 0 | { |
1463 | 0 | if (aCharset.IsEmpty()) { |
1464 | 0 | mForcedCharset = nullptr; |
1465 | 0 | return NS_OK; |
1466 | 0 | } |
1467 | 0 | const Encoding* encoding = Encoding::ForLabel(aCharset); |
1468 | 0 | if (!encoding) { |
1469 | 0 | // Reject unknown labels |
1470 | 0 | return NS_ERROR_INVALID_ARG; |
1471 | 0 | } |
1472 | 0 | if (!encoding->IsAsciiCompatible() && encoding != ISO_2022_JP_ENCODING) { |
1473 | 0 | // Reject XSS hazards |
1474 | 0 | return NS_ERROR_INVALID_ARG; |
1475 | 0 | } |
1476 | 0 | mForcedCharset = encoding; |
1477 | 0 | return NS_OK; |
1478 | 0 | } |
1479 | | |
1480 | | NS_IMETHODIMP |
1481 | | nsDocShell::GetForcedCharset(nsACString& aResult) |
1482 | 0 | { |
1483 | 0 | if (mForcedCharset) { |
1484 | 0 | mForcedCharset->Name(aResult); |
1485 | 0 | } else { |
1486 | 0 | aResult.Truncate(); |
1487 | 0 | } |
1488 | 0 | return NS_OK; |
1489 | 0 | } |
1490 | | |
1491 | | void |
1492 | | nsDocShell::SetParentCharset(const Encoding*& aCharset, |
1493 | | int32_t aCharsetSource, |
1494 | | nsIPrincipal* aPrincipal) |
1495 | 0 | { |
1496 | 0 | mParentCharset = aCharset; |
1497 | 0 | mParentCharsetSource = aCharsetSource; |
1498 | 0 | mParentCharsetPrincipal = aPrincipal; |
1499 | 0 | } |
1500 | | |
1501 | | void |
1502 | | nsDocShell::GetParentCharset(const Encoding*& aCharset, |
1503 | | int32_t* aCharsetSource, |
1504 | | nsIPrincipal** aPrincipal) |
1505 | 0 | { |
1506 | 0 | aCharset = mParentCharset; |
1507 | 0 | *aCharsetSource = mParentCharsetSource; |
1508 | 0 | NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal); |
1509 | 0 | } |
1510 | | |
1511 | | NS_IMETHODIMP |
1512 | | nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded) |
1513 | 0 | { |
1514 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1515 | 0 | *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded(); |
1516 | 0 | return NS_OK; |
1517 | 0 | } |
1518 | | |
1519 | | NS_IMETHODIMP |
1520 | | nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked) |
1521 | 0 | { |
1522 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1523 | 0 | *aHasMixedActiveContentBlocked = |
1524 | 0 | doc && doc->GetHasMixedActiveContentBlocked(); |
1525 | 0 | return NS_OK; |
1526 | 0 | } |
1527 | | |
1528 | | NS_IMETHODIMP |
1529 | | nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded) |
1530 | 0 | { |
1531 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1532 | 0 | *aHasMixedDisplayContentLoaded = |
1533 | 0 | doc && doc->GetHasMixedDisplayContentLoaded(); |
1534 | 0 | return NS_OK; |
1535 | 0 | } |
1536 | | |
1537 | | NS_IMETHODIMP |
1538 | | nsDocShell::GetHasMixedDisplayContentBlocked( |
1539 | | bool* aHasMixedDisplayContentBlocked) |
1540 | 0 | { |
1541 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1542 | 0 | *aHasMixedDisplayContentBlocked = |
1543 | 0 | doc && doc->GetHasMixedDisplayContentBlocked(); |
1544 | 0 | return NS_OK; |
1545 | 0 | } |
1546 | | |
1547 | | NS_IMETHODIMP |
1548 | | nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked) |
1549 | 0 | { |
1550 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1551 | 0 | *aHasTrackingContentBlocked = doc && doc->GetHasTrackingContentBlocked(); |
1552 | 0 | return NS_OK; |
1553 | 0 | } |
1554 | | |
1555 | | NS_IMETHODIMP |
1556 | | nsDocShell::GetHasSlowTrackingContentBlocked(bool* aHasSlowTrackingContentBlocked) |
1557 | 0 | { |
1558 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1559 | 0 | *aHasSlowTrackingContentBlocked = doc && doc->GetHasSlowTrackingContentBlocked(); |
1560 | 0 | return NS_OK; |
1561 | 0 | } |
1562 | | |
1563 | | NS_IMETHODIMP |
1564 | | nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded) |
1565 | 0 | { |
1566 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1567 | 0 | *aHasTrackingContentLoaded = doc && doc->GetHasTrackingContentLoaded(); |
1568 | 0 | return NS_OK; |
1569 | 0 | } |
1570 | | |
1571 | | NS_IMETHODIMP |
1572 | | nsDocShell::GetHasCookiesBlockedByPermission(bool* aHasCookiesBlockedByPermission) |
1573 | 0 | { |
1574 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1575 | 0 | *aHasCookiesBlockedByPermission = doc && doc->GetHasCookiesBlockedByPermission(); |
1576 | 0 | return NS_OK; |
1577 | 0 | } |
1578 | | |
1579 | | NS_IMETHODIMP |
1580 | | nsDocShell::GetHasCookiesBlockedDueToTrackers(bool* aHasCookiesBlockedDueToTrackers) |
1581 | 0 | { |
1582 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1583 | 0 | *aHasCookiesBlockedDueToTrackers = doc && doc->GetHasTrackingCookiesBlocked(); |
1584 | 0 | return NS_OK; |
1585 | 0 | } |
1586 | | |
1587 | | NS_IMETHODIMP |
1588 | | nsDocShell::GetHasAllCookiesBeenBlocked(bool* aHasAllCookiesBeenBlocked) |
1589 | 0 | { |
1590 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1591 | 0 | *aHasAllCookiesBeenBlocked = doc && doc->GetHasAllCookiesBlocked(); |
1592 | 0 | return NS_OK; |
1593 | 0 | } |
1594 | | |
1595 | | NS_IMETHODIMP |
1596 | | nsDocShell::GetHasForeignCookiesBeenBlocked(bool* aHasForeignCookiesBeenBlocked) |
1597 | 0 | { |
1598 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
1599 | 0 | *aHasForeignCookiesBeenBlocked = doc && doc->GetHasForeignCookiesBlocked(); |
1600 | 0 | return NS_OK; |
1601 | 0 | } |
1602 | | |
1603 | | NS_IMETHODIMP |
1604 | | nsDocShell::GetAllowPlugins(bool* aAllowPlugins) |
1605 | 0 | { |
1606 | 0 | NS_ENSURE_ARG_POINTER(aAllowPlugins); |
1607 | 0 |
|
1608 | 0 | *aAllowPlugins = mAllowPlugins; |
1609 | 0 | return NS_OK; |
1610 | 0 | } |
1611 | | |
1612 | | NS_IMETHODIMP |
1613 | | nsDocShell::SetAllowPlugins(bool aAllowPlugins) |
1614 | 0 | { |
1615 | 0 | mAllowPlugins = aAllowPlugins; |
1616 | 0 | // XXX should enable or disable a plugin host |
1617 | 0 | return NS_OK; |
1618 | 0 | } |
1619 | | |
1620 | | NS_IMETHODIMP |
1621 | | nsDocShell::GetAllowJavascript(bool* aAllowJavascript) |
1622 | 0 | { |
1623 | 0 | NS_ENSURE_ARG_POINTER(aAllowJavascript); |
1624 | 0 |
|
1625 | 0 | *aAllowJavascript = mAllowJavascript; |
1626 | 0 | return NS_OK; |
1627 | 0 | } |
1628 | | |
1629 | | NS_IMETHODIMP |
1630 | | nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled) |
1631 | 0 | { |
1632 | 0 | MOZ_ASSERT(aEnabled); |
1633 | 0 | *aEnabled = mCSSErrorReportingEnabled; |
1634 | 0 | return NS_OK; |
1635 | 0 | } |
1636 | | |
1637 | | NS_IMETHODIMP |
1638 | | nsDocShell::SetCssErrorReportingEnabled(bool aEnabled) |
1639 | 0 | { |
1640 | 0 | mCSSErrorReportingEnabled = aEnabled; |
1641 | 0 | return NS_OK; |
1642 | 0 | } |
1643 | | |
1644 | | NS_IMETHODIMP |
1645 | | nsDocShell::SetAllowJavascript(bool aAllowJavascript) |
1646 | 0 | { |
1647 | 0 | mAllowJavascript = aAllowJavascript; |
1648 | 0 | RecomputeCanExecuteScripts(); |
1649 | 0 | return NS_OK; |
1650 | 0 | } |
1651 | | |
1652 | | NS_IMETHODIMP |
1653 | | nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) |
1654 | 0 | { |
1655 | 0 | NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing); |
1656 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
1657 | 0 | *aUsePrivateBrowsing = mPrivateBrowsingId > 0; |
1658 | 0 | return NS_OK; |
1659 | 0 | } |
1660 | | |
1661 | | NS_IMETHODIMP |
1662 | | nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) |
1663 | 0 | { |
1664 | 0 | if (!CanSetOriginAttributes()) { |
1665 | 0 | bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0); |
1666 | 0 |
|
1667 | 0 | return changed ? NS_ERROR_FAILURE : NS_OK; |
1668 | 0 | } |
1669 | 0 |
|
1670 | 0 | return SetPrivateBrowsing(aUsePrivateBrowsing); |
1671 | 0 | } |
1672 | | |
1673 | | NS_IMETHODIMP |
1674 | | nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing) |
1675 | 0 | { |
1676 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
1677 | 0 |
|
1678 | 0 | bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0); |
1679 | 0 | if (changed) { |
1680 | 0 | mPrivateBrowsingId = aUsePrivateBrowsing ? 1 : 0; |
1681 | 0 |
|
1682 | 0 | if (mItemType != typeChrome) { |
1683 | 0 | mOriginAttributes.SyncAttributesWithPrivateBrowsing(aUsePrivateBrowsing); |
1684 | 0 | } |
1685 | 0 |
|
1686 | 0 | if (mAffectPrivateSessionLifetime) { |
1687 | 0 | if (aUsePrivateBrowsing) { |
1688 | 0 | IncreasePrivateDocShellCount(); |
1689 | 0 | } else { |
1690 | 0 | DecreasePrivateDocShellCount(); |
1691 | 0 | } |
1692 | 0 | } |
1693 | 0 | } |
1694 | 0 |
|
1695 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
1696 | 0 | while (iter.HasMore()) { |
1697 | 0 | nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext()); |
1698 | 0 | if (shell) { |
1699 | 0 | shell->SetPrivateBrowsing(aUsePrivateBrowsing); |
1700 | 0 | } |
1701 | 0 | } |
1702 | 0 |
|
1703 | 0 | if (changed) { |
1704 | 0 | nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers); |
1705 | 0 | while (iter.HasMore()) { |
1706 | 0 | nsWeakPtr ref = iter.GetNext(); |
1707 | 0 | nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref); |
1708 | 0 | if (!obs) { |
1709 | 0 | mPrivacyObservers.RemoveElement(ref); |
1710 | 0 | } else { |
1711 | 0 | obs->PrivateModeChanged(aUsePrivateBrowsing); |
1712 | 0 | } |
1713 | 0 | } |
1714 | 0 | } |
1715 | 0 |
|
1716 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
1717 | 0 | return NS_OK; |
1718 | 0 | } |
1719 | | |
1720 | | NS_IMETHODIMP |
1721 | | nsDocShell::GetHasLoadedNonBlankURI(bool* aResult) |
1722 | 0 | { |
1723 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
1724 | 0 |
|
1725 | 0 | *aResult = mHasLoadedNonBlankURI; |
1726 | 0 | return NS_OK; |
1727 | 0 | } |
1728 | | |
1729 | | NS_IMETHODIMP |
1730 | | nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs) |
1731 | 0 | { |
1732 | 0 | NS_ENSURE_ARG_POINTER(aUseRemoteTabs); |
1733 | 0 |
|
1734 | 0 | *aUseRemoteTabs = mUseRemoteTabs; |
1735 | 0 | return NS_OK; |
1736 | 0 | } |
1737 | | |
1738 | | NS_IMETHODIMP |
1739 | | nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) |
1740 | 0 | { |
1741 | 0 | if (aUseRemoteTabs) { |
1742 | 0 | CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::DOMIPCEnabled, |
1743 | 0 | true); |
1744 | 0 | } |
1745 | 0 |
|
1746 | 0 | mUseRemoteTabs = aUseRemoteTabs; |
1747 | 0 | return NS_OK; |
1748 | 0 | } |
1749 | | |
1750 | | NS_IMETHODIMP |
1751 | | nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime) |
1752 | 0 | { |
1753 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
1754 | 0 |
|
1755 | 0 | bool change = aAffectLifetime != mAffectPrivateSessionLifetime; |
1756 | 0 | if (change && UsePrivateBrowsing()) { |
1757 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
1758 | 0 | if (aAffectLifetime) { |
1759 | 0 | IncreasePrivateDocShellCount(); |
1760 | 0 | } else { |
1761 | 0 | DecreasePrivateDocShellCount(); |
1762 | 0 | } |
1763 | 0 | } |
1764 | 0 | mAffectPrivateSessionLifetime = aAffectLifetime; |
1765 | 0 |
|
1766 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
1767 | 0 | while (iter.HasMore()) { |
1768 | 0 | nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
1769 | 0 | if (shell) { |
1770 | 0 | shell->SetAffectPrivateSessionLifetime(aAffectLifetime); |
1771 | 0 | } |
1772 | 0 | } |
1773 | 0 | return NS_OK; |
1774 | 0 | } |
1775 | | |
1776 | | NS_IMETHODIMP |
1777 | | nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime) |
1778 | 0 | { |
1779 | 0 | *aAffectLifetime = mAffectPrivateSessionLifetime; |
1780 | 0 | return NS_OK; |
1781 | 0 | } |
1782 | | |
1783 | | NS_IMETHODIMP |
1784 | | nsDocShell::AddWeakPrivacyTransitionObserver( |
1785 | | nsIPrivacyTransitionObserver* aObserver) |
1786 | 0 | { |
1787 | 0 | nsWeakPtr weakObs = do_GetWeakReference(aObserver); |
1788 | 0 | if (!weakObs) { |
1789 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1790 | 0 | } |
1791 | 0 | return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; |
1792 | 0 | } |
1793 | | |
1794 | | NS_IMETHODIMP |
1795 | | nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver) |
1796 | 0 | { |
1797 | 0 | nsWeakPtr weakObs = do_GetWeakReference(aObserver); |
1798 | 0 | if (!weakObs) { |
1799 | 0 | return NS_ERROR_FAILURE; |
1800 | 0 | } |
1801 | 0 | return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; |
1802 | 0 | } |
1803 | | |
1804 | | NS_IMETHODIMP |
1805 | | nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver) |
1806 | 0 | { |
1807 | 0 | nsWeakPtr obs = do_GetWeakReference(aObserver); |
1808 | 0 | return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE; |
1809 | 0 | } |
1810 | | |
1811 | | NS_IMETHODIMP |
1812 | | nsDocShell::NotifyReflowObservers(bool aInterruptible, |
1813 | | DOMHighResTimeStamp aStart, |
1814 | | DOMHighResTimeStamp aEnd) |
1815 | 0 | { |
1816 | 0 | nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers); |
1817 | 0 | while (iter.HasMore()) { |
1818 | 0 | nsWeakPtr ref = iter.GetNext(); |
1819 | 0 | nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref); |
1820 | 0 | if (!obs) { |
1821 | 0 | mReflowObservers.RemoveElement(ref); |
1822 | 0 | } else if (aInterruptible) { |
1823 | 0 | obs->ReflowInterruptible(aStart, aEnd); |
1824 | 0 | } else { |
1825 | 0 | obs->Reflow(aStart, aEnd); |
1826 | 0 | } |
1827 | 0 | } |
1828 | 0 | return NS_OK; |
1829 | 0 | } |
1830 | | |
1831 | | NS_IMETHODIMP |
1832 | | nsDocShell::GetAllowMetaRedirects(bool* aReturn) |
1833 | 0 | { |
1834 | 0 | NS_ENSURE_ARG_POINTER(aReturn); |
1835 | 0 |
|
1836 | 0 | *aReturn = mAllowMetaRedirects; |
1837 | 0 | return NS_OK; |
1838 | 0 | } |
1839 | | |
1840 | | NS_IMETHODIMP |
1841 | | nsDocShell::SetAllowMetaRedirects(bool aValue) |
1842 | 0 | { |
1843 | 0 | mAllowMetaRedirects = aValue; |
1844 | 0 | return NS_OK; |
1845 | 0 | } |
1846 | | |
1847 | | NS_IMETHODIMP |
1848 | | nsDocShell::GetAllowSubframes(bool* aAllowSubframes) |
1849 | 0 | { |
1850 | 0 | NS_ENSURE_ARG_POINTER(aAllowSubframes); |
1851 | 0 |
|
1852 | 0 | *aAllowSubframes = mAllowSubframes; |
1853 | 0 | return NS_OK; |
1854 | 0 | } |
1855 | | |
1856 | | NS_IMETHODIMP |
1857 | | nsDocShell::SetAllowSubframes(bool aAllowSubframes) |
1858 | 0 | { |
1859 | 0 | mAllowSubframes = aAllowSubframes; |
1860 | 0 | return NS_OK; |
1861 | 0 | } |
1862 | | |
1863 | | NS_IMETHODIMP |
1864 | | nsDocShell::GetAllowImages(bool* aAllowImages) |
1865 | 0 | { |
1866 | 0 | NS_ENSURE_ARG_POINTER(aAllowImages); |
1867 | 0 |
|
1868 | 0 | *aAllowImages = mAllowImages; |
1869 | 0 | return NS_OK; |
1870 | 0 | } |
1871 | | |
1872 | | NS_IMETHODIMP |
1873 | | nsDocShell::SetAllowImages(bool aAllowImages) |
1874 | 0 | { |
1875 | 0 | mAllowImages = aAllowImages; |
1876 | 0 | return NS_OK; |
1877 | 0 | } |
1878 | | |
1879 | | NS_IMETHODIMP |
1880 | | nsDocShell::GetAllowMedia(bool* aAllowMedia) |
1881 | 0 | { |
1882 | 0 | *aAllowMedia = mAllowMedia; |
1883 | 0 | return NS_OK; |
1884 | 0 | } |
1885 | | |
1886 | | NS_IMETHODIMP |
1887 | | nsDocShell::SetAllowMedia(bool aAllowMedia) |
1888 | 0 | { |
1889 | 0 | mAllowMedia = aAllowMedia; |
1890 | 0 |
|
1891 | 0 | // Mute or unmute audio contexts attached to the inner window. |
1892 | 0 | if (mScriptGlobal) { |
1893 | 0 | if (nsPIDOMWindowInner* innerWin = |
1894 | 0 | mScriptGlobal->AsOuter()->GetCurrentInnerWindow()) { |
1895 | 0 | if (aAllowMedia) { |
1896 | 0 | innerWin->UnmuteAudioContexts(); |
1897 | 0 | } else { |
1898 | 0 | innerWin->MuteAudioContexts(); |
1899 | 0 | } |
1900 | 0 | } |
1901 | 0 | } |
1902 | 0 |
|
1903 | 0 | return NS_OK; |
1904 | 0 | } |
1905 | | |
1906 | | NS_IMETHODIMP |
1907 | | nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch) |
1908 | 0 | { |
1909 | 0 | *aAllowDNSPrefetch = mAllowDNSPrefetch; |
1910 | 0 | return NS_OK; |
1911 | 0 | } |
1912 | | |
1913 | | NS_IMETHODIMP |
1914 | | nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch) |
1915 | 0 | { |
1916 | 0 | mAllowDNSPrefetch = aAllowDNSPrefetch; |
1917 | 0 | return NS_OK; |
1918 | 0 | } |
1919 | | |
1920 | | NS_IMETHODIMP |
1921 | | nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl) |
1922 | 0 | { |
1923 | 0 | *aAllowWindowControl = mAllowWindowControl; |
1924 | 0 | return NS_OK; |
1925 | 0 | } |
1926 | | |
1927 | | NS_IMETHODIMP |
1928 | | nsDocShell::SetAllowWindowControl(bool aAllowWindowControl) |
1929 | 0 | { |
1930 | 0 | mAllowWindowControl = aAllowWindowControl; |
1931 | 0 | return NS_OK; |
1932 | 0 | } |
1933 | | |
1934 | | NS_IMETHODIMP |
1935 | | nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting) |
1936 | 0 | { |
1937 | 0 | *aAllowContentRetargeting = mAllowContentRetargeting; |
1938 | 0 | return NS_OK; |
1939 | 0 | } |
1940 | | |
1941 | | NS_IMETHODIMP |
1942 | | nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting) |
1943 | 0 | { |
1944 | 0 | mAllowContentRetargetingOnChildren = aAllowContentRetargeting; |
1945 | 0 | mAllowContentRetargeting = aAllowContentRetargeting; |
1946 | 0 | return NS_OK; |
1947 | 0 | } |
1948 | | |
1949 | | NS_IMETHODIMP |
1950 | | nsDocShell::GetAllowContentRetargetingOnChildren( |
1951 | | bool* aAllowContentRetargetingOnChildren) |
1952 | 0 | { |
1953 | 0 | *aAllowContentRetargetingOnChildren = mAllowContentRetargetingOnChildren; |
1954 | 0 | return NS_OK; |
1955 | 0 | } |
1956 | | |
1957 | | NS_IMETHODIMP |
1958 | | nsDocShell::SetAllowContentRetargetingOnChildren( |
1959 | | bool aAllowContentRetargetingOnChildren) |
1960 | 0 | { |
1961 | 0 | mAllowContentRetargetingOnChildren = aAllowContentRetargetingOnChildren; |
1962 | 0 | return NS_OK; |
1963 | 0 | } |
1964 | | |
1965 | | NS_IMETHODIMP |
1966 | | nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId) |
1967 | 0 | { |
1968 | 0 | *aInheritPrivateBrowsingId = mInheritPrivateBrowsingId; |
1969 | 0 | return NS_OK; |
1970 | 0 | } |
1971 | | |
1972 | | NS_IMETHODIMP |
1973 | | nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId) |
1974 | 0 | { |
1975 | 0 | mInheritPrivateBrowsingId = aInheritPrivateBrowsingId; |
1976 | 0 | return NS_OK; |
1977 | 0 | } |
1978 | | |
1979 | | NS_IMETHODIMP |
1980 | | nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed) |
1981 | 0 | { |
1982 | 0 | NS_ENSURE_ARG_POINTER(aFullscreenAllowed); |
1983 | 0 |
|
1984 | 0 | // Browsers and apps have their mFullscreenAllowed retrieved from their |
1985 | 0 | // corresponding iframe in their parent upon creation. |
1986 | 0 | if (mFullscreenAllowed != CHECK_ATTRIBUTES) { |
1987 | 0 | *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS); |
1988 | 0 | return NS_OK; |
1989 | 0 | } |
1990 | 0 | |
1991 | 0 | // Assume false until we determine otherwise... |
1992 | 0 | *aFullscreenAllowed = false; |
1993 | 0 |
|
1994 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
1995 | 0 | if (!win) { |
1996 | 0 | return NS_OK; |
1997 | 0 | } |
1998 | 0 | if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) { |
1999 | 0 | if (frameElement->IsXULElement()) { |
2000 | 0 | if (frameElement->HasAttr(kNameSpaceID_None, |
2001 | 0 | nsGkAtoms::disablefullscreen)) { |
2002 | 0 | // Document inside this frame is explicitly disabled. |
2003 | 0 | return NS_OK; |
2004 | 0 | } |
2005 | 0 | } else { |
2006 | 0 | // We do not allow document inside any containing element other |
2007 | 0 | // than iframe to enter fullscreen. |
2008 | 0 | if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) { |
2009 | 0 | // If any ancestor iframe does not have allowfullscreen attribute |
2010 | 0 | // set, then fullscreen is not allowed. |
2011 | 0 | if (!frameElement->HasAttr(kNameSpaceID_None, |
2012 | 0 | nsGkAtoms::allowfullscreen) && |
2013 | 0 | !frameElement->HasAttr(kNameSpaceID_None, |
2014 | 0 | nsGkAtoms::mozallowfullscreen)) { |
2015 | 0 | return NS_OK; |
2016 | 0 | } |
2017 | 0 | } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) { |
2018 | 0 | // Respect allowfullscreen only if this is a rewritten YouTube embed. |
2019 | 0 | nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent = |
2020 | 0 | do_QueryInterface(frameElement); |
2021 | 0 | if (!objectLoadingContent) { |
2022 | 0 | return NS_OK; |
2023 | 0 | } |
2024 | 0 | nsObjectLoadingContent* olc = |
2025 | 0 | static_cast<nsObjectLoadingContent*>(objectLoadingContent.get()); |
2026 | 0 | if (!olc->IsRewrittenYoutubeEmbed()) { |
2027 | 0 | return NS_OK; |
2028 | 0 | } |
2029 | 0 | // We don't have to check prefixed attributes because Flash does not |
2030 | 0 | // support them. |
2031 | 0 | if (!frameElement->HasAttr(kNameSpaceID_None, |
2032 | 0 | nsGkAtoms::allowfullscreen)) { |
2033 | 0 | return NS_OK; |
2034 | 0 | } |
2035 | 0 | } else { |
2036 | 0 | // neither iframe nor embed |
2037 | 0 | return NS_OK; |
2038 | 0 | } |
2039 | 0 | } |
2040 | 0 | } |
2041 | 0 | |
2042 | 0 | // If we have no parent then we're the root docshell; no ancestor of the |
2043 | 0 | // original docshell doesn't have a allowfullscreen attribute, so |
2044 | 0 | // report fullscreen as allowed. |
2045 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
2046 | 0 | if (!parent) { |
2047 | 0 | *aFullscreenAllowed = true; |
2048 | 0 | return NS_OK; |
2049 | 0 | } |
2050 | 0 | |
2051 | 0 | // Otherwise, we have a parent, continue the checking for |
2052 | 0 | // mozFullscreenAllowed in the parent docshell's ancestors. |
2053 | 0 | return parent->GetFullscreenAllowed(aFullscreenAllowed); |
2054 | 0 | } |
2055 | | |
2056 | | NS_IMETHODIMP |
2057 | | nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed) |
2058 | 0 | { |
2059 | 0 | if (!nsIDocShell::GetIsMozBrowser()) { |
2060 | 0 | // Only allow setting of fullscreenAllowed on content/process boundaries. |
2061 | 0 | // At non-boundaries the fullscreenAllowed attribute is calculated based on |
2062 | 0 | // whether all enclosing frames have the "mozFullscreenAllowed" attribute |
2063 | 0 | // set to "true". fullscreenAllowed is set at the process boundaries to |
2064 | 0 | // propagate the value of the parent's "mozFullscreenAllowed" attribute |
2065 | 0 | // across process boundaries. |
2066 | 0 | return NS_ERROR_UNEXPECTED; |
2067 | 0 | } |
2068 | 0 | mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS); |
2069 | 0 | return NS_OK; |
2070 | 0 | } |
2071 | | |
2072 | | hal::ScreenOrientation |
2073 | | nsDocShell::OrientationLock() |
2074 | 0 | { |
2075 | 0 | return mOrientationLock; |
2076 | 0 | } |
2077 | | |
2078 | | void |
2079 | | nsDocShell::SetOrientationLock(hal::ScreenOrientation aOrientationLock) |
2080 | 0 | { |
2081 | 0 | mOrientationLock = aOrientationLock; |
2082 | 0 | } |
2083 | | |
2084 | | NS_IMETHODIMP |
2085 | | nsDocShell::GetMayEnableCharacterEncodingMenu( |
2086 | | bool* aMayEnableCharacterEncodingMenu) |
2087 | 0 | { |
2088 | 0 | *aMayEnableCharacterEncodingMenu = false; |
2089 | 0 | if (!mContentViewer) { |
2090 | 0 | return NS_OK; |
2091 | 0 | } |
2092 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
2093 | 0 | if (!doc) { |
2094 | 0 | return NS_OK; |
2095 | 0 | } |
2096 | 0 | if (doc->WillIgnoreCharsetOverride()) { |
2097 | 0 | return NS_OK; |
2098 | 0 | } |
2099 | 0 | |
2100 | 0 | *aMayEnableCharacterEncodingMenu = true; |
2101 | 0 | return NS_OK; |
2102 | 0 | } |
2103 | | |
2104 | | NS_IMETHODIMP |
2105 | | nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection, |
2106 | | nsISimpleEnumerator** aResult) |
2107 | 0 | { |
2108 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
2109 | 0 | *aResult = nullptr; |
2110 | 0 |
|
2111 | 0 | RefPtr<nsDocShellEnumerator> docShellEnum; |
2112 | 0 | if (aDirection == ENUMERATE_FORWARDS) { |
2113 | 0 | docShellEnum = new nsDocShellForwardsEnumerator; |
2114 | 0 | } else { |
2115 | 0 | docShellEnum = new nsDocShellBackwardsEnumerator; |
2116 | 0 | } |
2117 | 0 |
|
2118 | 0 | nsresult rv = docShellEnum->SetEnumDocShellType(aItemType); |
2119 | 0 | if (NS_FAILED(rv)) { |
2120 | 0 | return rv; |
2121 | 0 | } |
2122 | 0 | |
2123 | 0 | rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this); |
2124 | 0 | if (NS_FAILED(rv)) { |
2125 | 0 | return rv; |
2126 | 0 | } |
2127 | 0 | |
2128 | 0 | rv = docShellEnum->First(); |
2129 | 0 | if (NS_FAILED(rv)) { |
2130 | 0 | return rv; |
2131 | 0 | } |
2132 | 0 | |
2133 | 0 | rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), |
2134 | 0 | (void**)aResult); |
2135 | 0 |
|
2136 | 0 | return rv; |
2137 | 0 | } |
2138 | | |
2139 | | NS_IMETHODIMP |
2140 | | nsDocShell::GetAppType(uint32_t* aAppType) |
2141 | 0 | { |
2142 | 0 | *aAppType = mAppType; |
2143 | 0 | return NS_OK; |
2144 | 0 | } |
2145 | | |
2146 | | NS_IMETHODIMP |
2147 | | nsDocShell::SetAppType(uint32_t aAppType) |
2148 | 0 | { |
2149 | 0 | mAppType = aAppType; |
2150 | 0 | return NS_OK; |
2151 | 0 | } |
2152 | | |
2153 | | NS_IMETHODIMP |
2154 | | nsDocShell::GetAllowAuth(bool* aAllowAuth) |
2155 | 0 | { |
2156 | 0 | *aAllowAuth = mAllowAuth; |
2157 | 0 | return NS_OK; |
2158 | 0 | } |
2159 | | |
2160 | | NS_IMETHODIMP |
2161 | | nsDocShell::SetAllowAuth(bool aAllowAuth) |
2162 | 0 | { |
2163 | 0 | mAllowAuth = aAllowAuth; |
2164 | 0 | return NS_OK; |
2165 | 0 | } |
2166 | | |
2167 | | NS_IMETHODIMP |
2168 | | nsDocShell::GetZoom(float* aZoom) |
2169 | 0 | { |
2170 | 0 | NS_ENSURE_ARG_POINTER(aZoom); |
2171 | 0 | *aZoom = 1.0f; |
2172 | 0 | return NS_OK; |
2173 | 0 | } |
2174 | | |
2175 | | NS_IMETHODIMP |
2176 | | nsDocShell::SetZoom(float aZoom) |
2177 | 0 | { |
2178 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
2179 | 0 | } |
2180 | | |
2181 | | NS_IMETHODIMP |
2182 | | nsDocShell::GetMarginWidth(int32_t* aWidth) |
2183 | 0 | { |
2184 | 0 | NS_ENSURE_ARG_POINTER(aWidth); |
2185 | 0 |
|
2186 | 0 | *aWidth = mMarginWidth; |
2187 | 0 | return NS_OK; |
2188 | 0 | } |
2189 | | |
2190 | | NS_IMETHODIMP |
2191 | | nsDocShell::SetMarginWidth(int32_t aWidth) |
2192 | 0 | { |
2193 | 0 | mMarginWidth = aWidth; |
2194 | 0 | return NS_OK; |
2195 | 0 | } |
2196 | | |
2197 | | NS_IMETHODIMP |
2198 | | nsDocShell::GetMarginHeight(int32_t* aHeight) |
2199 | 0 | { |
2200 | 0 | NS_ENSURE_ARG_POINTER(aHeight); |
2201 | 0 |
|
2202 | 0 | *aHeight = mMarginHeight; |
2203 | 0 | return NS_OK; |
2204 | 0 | } |
2205 | | |
2206 | | NS_IMETHODIMP |
2207 | | nsDocShell::SetMarginHeight(int32_t aHeight) |
2208 | 0 | { |
2209 | 0 | mMarginHeight = aHeight; |
2210 | 0 | return NS_OK; |
2211 | 0 | } |
2212 | | |
2213 | | NS_IMETHODIMP |
2214 | | nsDocShell::GetBusyFlags(uint32_t* aBusyFlags) |
2215 | 0 | { |
2216 | 0 | NS_ENSURE_ARG_POINTER(aBusyFlags); |
2217 | 0 |
|
2218 | 0 | *aBusyFlags = mBusyFlags; |
2219 | 0 | return NS_OK; |
2220 | 0 | } |
2221 | | |
2222 | | NS_IMETHODIMP |
2223 | | nsDocShell::TabToTreeOwner(bool aForward, bool aForDocumentNavigation, bool* aTookFocus) |
2224 | 0 | { |
2225 | 0 | NS_ENSURE_ARG_POINTER(aTookFocus); |
2226 | 0 |
|
2227 | 0 | nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner); |
2228 | 0 | if (chromeFocus) { |
2229 | 0 | if (aForward) { |
2230 | 0 | *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement(aForDocumentNavigation)); |
2231 | 0 | } else { |
2232 | 0 | *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement(aForDocumentNavigation)); |
2233 | 0 | } |
2234 | 0 | } else { |
2235 | 0 | *aTookFocus = false; |
2236 | 0 | } |
2237 | 0 |
|
2238 | 0 | return NS_OK; |
2239 | 0 | } |
2240 | | |
2241 | | NS_IMETHODIMP |
2242 | | nsDocShell::GetSecurityUI(nsISecureBrowserUI** aSecurityUI) |
2243 | 0 | { |
2244 | 0 | NS_IF_ADDREF(*aSecurityUI = mSecurityUI); |
2245 | 0 | return NS_OK; |
2246 | 0 | } |
2247 | | |
2248 | | NS_IMETHODIMP |
2249 | | nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI) |
2250 | 0 | { |
2251 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
2252 | 0 |
|
2253 | 0 | mSecurityUI = aSecurityUI; |
2254 | 0 | mSecurityUI->SetDocShell(this); |
2255 | 0 | return NS_OK; |
2256 | 0 | } |
2257 | | |
2258 | | NS_IMETHODIMP |
2259 | | nsDocShell::GetLoadURIDelegate(nsILoadURIDelegate** aLoadURIDelegate) |
2260 | 0 | { |
2261 | 0 | NS_IF_ADDREF(*aLoadURIDelegate = mLoadURIDelegate); |
2262 | 0 | return NS_OK; |
2263 | 0 | } |
2264 | | |
2265 | | NS_IMETHODIMP |
2266 | | nsDocShell::SetLoadURIDelegate(nsILoadURIDelegate* aLoadURIDelegate) |
2267 | 0 | { |
2268 | 0 | mLoadURIDelegate = aLoadURIDelegate; |
2269 | 0 | return NS_OK; |
2270 | 0 | } |
2271 | | |
2272 | | NS_IMETHODIMP |
2273 | | nsDocShell::GetUseErrorPages(bool* aUseErrorPages) |
2274 | 0 | { |
2275 | 0 | *aUseErrorPages = UseErrorPages(); |
2276 | 0 | return NS_OK; |
2277 | 0 | } |
2278 | | |
2279 | | NS_IMETHODIMP |
2280 | | nsDocShell::SetUseErrorPages(bool aUseErrorPages) |
2281 | 0 | { |
2282 | 0 | // If mUseErrorPages is set explicitly, stop using sUseErrorPages. |
2283 | 0 | if (mObserveErrorPages) { |
2284 | 0 | mObserveErrorPages = false; |
2285 | 0 | } |
2286 | 0 | mUseErrorPages = aUseErrorPages; |
2287 | 0 | return NS_OK; |
2288 | 0 | } |
2289 | | |
2290 | | NS_IMETHODIMP |
2291 | | nsDocShell::GetPreviousEntryIndex(int32_t* aPreviousEntryIndex) |
2292 | 0 | { |
2293 | 0 | *aPreviousEntryIndex = mPreviousEntryIndex; |
2294 | 0 | return NS_OK; |
2295 | 0 | } |
2296 | | |
2297 | | NS_IMETHODIMP |
2298 | | nsDocShell::GetLoadedEntryIndex(int32_t* aLoadedEntryIndex) |
2299 | 0 | { |
2300 | 0 | *aLoadedEntryIndex = mLoadedEntryIndex; |
2301 | 0 | return NS_OK; |
2302 | 0 | } |
2303 | | |
2304 | | NS_IMETHODIMP |
2305 | | nsDocShell::HistoryPurged(int32_t aNumEntries) |
2306 | 0 | { |
2307 | 0 | // These indices are used for fastback cache eviction, to determine |
2308 | 0 | // which session history entries are candidates for content viewer |
2309 | 0 | // eviction. We need to adjust by the number of entries that we |
2310 | 0 | // just purged from history, so that we look at the right session history |
2311 | 0 | // entries during eviction. |
2312 | 0 | mPreviousEntryIndex = std::max(-1, mPreviousEntryIndex - aNumEntries); |
2313 | 0 | mLoadedEntryIndex = std::max(0, mLoadedEntryIndex - aNumEntries); |
2314 | 0 |
|
2315 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
2316 | 0 | while (iter.HasMore()) { |
2317 | 0 | nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
2318 | 0 | if (shell) { |
2319 | 0 | shell->HistoryPurged(aNumEntries); |
2320 | 0 | } |
2321 | 0 | } |
2322 | 0 |
|
2323 | 0 | return NS_OK; |
2324 | 0 | } |
2325 | | |
2326 | | nsresult |
2327 | | nsDocShell::HistoryEntryRemoved(int32_t aIndex) |
2328 | 0 | { |
2329 | 0 | // These indices are used for fastback cache eviction, to determine |
2330 | 0 | // which session history entries are candidates for content viewer |
2331 | 0 | // eviction. We need to adjust by the number of entries that we |
2332 | 0 | // just purged from history, so that we look at the right session history |
2333 | 0 | // entries during eviction. |
2334 | 0 | if (aIndex == mPreviousEntryIndex) { |
2335 | 0 | mPreviousEntryIndex = -1; |
2336 | 0 | } else if (aIndex < mPreviousEntryIndex) { |
2337 | 0 | --mPreviousEntryIndex; |
2338 | 0 | } |
2339 | 0 | if (mLoadedEntryIndex == aIndex) { |
2340 | 0 | mLoadedEntryIndex = 0; |
2341 | 0 | } else if (aIndex < mLoadedEntryIndex) { |
2342 | 0 | --mLoadedEntryIndex; |
2343 | 0 | } |
2344 | 0 |
|
2345 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
2346 | 0 | while (iter.HasMore()) { |
2347 | 0 | nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
2348 | 0 | if (shell) { |
2349 | 0 | static_cast<nsDocShell*>(shell.get())->HistoryEntryRemoved(aIndex); |
2350 | 0 | } |
2351 | 0 | } |
2352 | 0 |
|
2353 | 0 | return NS_OK; |
2354 | 0 | } |
2355 | | |
2356 | | NS_IMETHODIMP |
2357 | | nsDocShell::SetRecordProfileTimelineMarkers(bool aValue) |
2358 | 0 | { |
2359 | 0 | bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers(); |
2360 | 0 | if (currentValue == aValue) { |
2361 | 0 | return NS_OK; |
2362 | 0 | } |
2363 | 0 | |
2364 | 0 | RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); |
2365 | 0 | if (!timelines) { |
2366 | 0 | return NS_OK; |
2367 | 0 | } |
2368 | 0 | |
2369 | 0 | if (aValue) { |
2370 | 0 | MOZ_ASSERT(!timelines->HasConsumer(this)); |
2371 | 0 | timelines->AddConsumer(this); |
2372 | 0 | MOZ_ASSERT(timelines->HasConsumer(this)); |
2373 | 0 | UseEntryScriptProfiling(); |
2374 | 0 | } else { |
2375 | 0 | MOZ_ASSERT(timelines->HasConsumer(this)); |
2376 | 0 | timelines->RemoveConsumer(this); |
2377 | 0 | MOZ_ASSERT(!timelines->HasConsumer(this)); |
2378 | 0 | UnuseEntryScriptProfiling(); |
2379 | 0 | } |
2380 | 0 |
|
2381 | 0 | return NS_OK; |
2382 | 0 | } |
2383 | | |
2384 | | NS_IMETHODIMP |
2385 | | nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue) |
2386 | 0 | { |
2387 | 0 | *aValue = !!mObserved; |
2388 | 0 | return NS_OK; |
2389 | 0 | } |
2390 | | |
2391 | | nsresult |
2392 | | nsDocShell::PopProfileTimelineMarkers( |
2393 | | JSContext* aCx, |
2394 | | JS::MutableHandle<JS::Value> aOut) |
2395 | 0 | { |
2396 | 0 | RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); |
2397 | 0 | if (!timelines) { |
2398 | 0 | return NS_OK; |
2399 | 0 | } |
2400 | 0 | |
2401 | 0 | nsTArray<dom::ProfileTimelineMarker> store; |
2402 | 0 | SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store); |
2403 | 0 |
|
2404 | 0 | timelines->PopMarkers(this, aCx, store); |
2405 | 0 |
|
2406 | 0 | if (!ToJSValue(aCx, store, aOut)) { |
2407 | 0 | JS_ClearPendingException(aCx); |
2408 | 0 | return NS_ERROR_UNEXPECTED; |
2409 | 0 | } |
2410 | 0 | |
2411 | 0 | return NS_OK; |
2412 | 0 | } |
2413 | | |
2414 | | nsresult |
2415 | | nsDocShell::Now(DOMHighResTimeStamp* aWhen) |
2416 | 0 | { |
2417 | 0 | *aWhen = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds(); |
2418 | 0 | return NS_OK; |
2419 | 0 | } |
2420 | | |
2421 | | NS_IMETHODIMP |
2422 | | nsDocShell::SetWindowDraggingAllowed(bool aValue) |
2423 | 0 | { |
2424 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
2425 | 0 | if (!aValue && mItemType == typeChrome && !parent) { |
2426 | 0 | // Window dragging is always allowed for top level |
2427 | 0 | // chrome docshells. |
2428 | 0 | return NS_ERROR_FAILURE; |
2429 | 0 | } |
2430 | 0 | mWindowDraggingAllowed = aValue; |
2431 | 0 | return NS_OK; |
2432 | 0 | } |
2433 | | |
2434 | | NS_IMETHODIMP |
2435 | | nsDocShell::GetWindowDraggingAllowed(bool* aValue) |
2436 | 0 | { |
2437 | 0 | // window dragging regions in CSS (-moz-window-drag:drag) |
2438 | 0 | // can be slow. Default behavior is to only allow it for |
2439 | 0 | // chrome top level windows. |
2440 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
2441 | 0 | if (mItemType == typeChrome && !parent) { |
2442 | 0 | // Top level chrome window |
2443 | 0 | *aValue = true; |
2444 | 0 | } else { |
2445 | 0 | *aValue = mWindowDraggingAllowed; |
2446 | 0 | } |
2447 | 0 | return NS_OK; |
2448 | 0 | } |
2449 | | |
2450 | | nsIDOMStorageManager* |
2451 | | nsDocShell::TopSessionStorageManager() |
2452 | 0 | { |
2453 | 0 | nsresult rv; |
2454 | 0 |
|
2455 | 0 | nsCOMPtr<nsIDocShellTreeItem> topItem; |
2456 | 0 | rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem)); |
2457 | 0 | if (NS_FAILED(rv)) { |
2458 | 0 | return nullptr; |
2459 | 0 | } |
2460 | 0 | |
2461 | 0 | if (!topItem) { |
2462 | 0 | return nullptr; |
2463 | 0 | } |
2464 | 0 | |
2465 | 0 | nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get()); |
2466 | 0 | if (topDocShell != this) { |
2467 | 0 | return topDocShell->TopSessionStorageManager(); |
2468 | 0 | } |
2469 | 0 | |
2470 | 0 | if (!mSessionStorageManager) { |
2471 | 0 | mSessionStorageManager = new SessionStorageManager(); |
2472 | 0 | } |
2473 | 0 |
|
2474 | 0 | return mSessionStorageManager; |
2475 | 0 | } |
2476 | | |
2477 | | NS_IMETHODIMP |
2478 | | nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult) |
2479 | 0 | { |
2480 | 0 | NS_IF_ADDREF(*aResult = GetCurrentDocChannel()); |
2481 | 0 | return NS_OK; |
2482 | 0 | } |
2483 | | |
2484 | | nsIChannel* |
2485 | | nsDocShell::GetCurrentDocChannel() |
2486 | 0 | { |
2487 | 0 | if (mContentViewer) { |
2488 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
2489 | 0 | if (doc) { |
2490 | 0 | return doc->GetChannel(); |
2491 | 0 | } |
2492 | 0 | } |
2493 | 0 | return nullptr; |
2494 | 0 | } |
2495 | | |
2496 | | NS_IMETHODIMP |
2497 | | nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver) |
2498 | 0 | { |
2499 | 0 | nsWeakPtr weakObs = do_GetWeakReference(aObserver); |
2500 | 0 | if (!weakObs) { |
2501 | 0 | return NS_ERROR_FAILURE; |
2502 | 0 | } |
2503 | 0 | return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; |
2504 | 0 | } |
2505 | | |
2506 | | NS_IMETHODIMP |
2507 | | nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver) |
2508 | 0 | { |
2509 | 0 | nsWeakPtr obs = do_GetWeakReference(aObserver); |
2510 | 0 | return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE; |
2511 | 0 | } |
2512 | | |
2513 | | void |
2514 | | nsDocShell::NotifyAsyncPanZoomStarted() |
2515 | 0 | { |
2516 | 0 | nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers); |
2517 | 0 | while (iter.HasMore()) { |
2518 | 0 | nsWeakPtr ref = iter.GetNext(); |
2519 | 0 | nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref); |
2520 | 0 | if (obs) { |
2521 | 0 | obs->AsyncPanZoomStarted(); |
2522 | 0 | } else { |
2523 | 0 | mScrollObservers.RemoveElement(ref); |
2524 | 0 | } |
2525 | 0 | } |
2526 | 0 | } |
2527 | | |
2528 | | void |
2529 | | nsDocShell::NotifyAsyncPanZoomStopped() |
2530 | 0 | { |
2531 | 0 | nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers); |
2532 | 0 | while (iter.HasMore()) { |
2533 | 0 | nsWeakPtr ref = iter.GetNext(); |
2534 | 0 | nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref); |
2535 | 0 | if (obs) { |
2536 | 0 | obs->AsyncPanZoomStopped(); |
2537 | 0 | } else { |
2538 | 0 | mScrollObservers.RemoveElement(ref); |
2539 | 0 | } |
2540 | 0 | } |
2541 | 0 | } |
2542 | | |
2543 | | NS_IMETHODIMP |
2544 | | nsDocShell::NotifyScrollObservers() |
2545 | 0 | { |
2546 | 0 | nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers); |
2547 | 0 | while (iter.HasMore()) { |
2548 | 0 | nsWeakPtr ref = iter.GetNext(); |
2549 | 0 | nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref); |
2550 | 0 | if (obs) { |
2551 | 0 | obs->ScrollPositionChanged(); |
2552 | 0 | } else { |
2553 | 0 | mScrollObservers.RemoveElement(ref); |
2554 | 0 | } |
2555 | 0 | } |
2556 | 0 | return NS_OK; |
2557 | 0 | } |
2558 | | |
2559 | | //***************************************************************************** |
2560 | | // nsDocShell::nsIDocShellTreeItem |
2561 | | //***************************************************************************** |
2562 | | |
2563 | | NS_IMETHODIMP |
2564 | | nsDocShell::GetName(nsAString& aName) |
2565 | 0 | { |
2566 | 0 | mBrowsingContext->GetName(aName); |
2567 | 0 | return NS_OK; |
2568 | 0 | } |
2569 | | |
2570 | | NS_IMETHODIMP |
2571 | | nsDocShell::SetName(const nsAString& aName) |
2572 | 0 | { |
2573 | 0 | mBrowsingContext->SetName(aName); |
2574 | 0 | return NS_OK; |
2575 | 0 | } |
2576 | | |
2577 | | NS_IMETHODIMP |
2578 | | nsDocShell::NameEquals(const nsAString& aName, bool* aResult) |
2579 | 0 | { |
2580 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
2581 | 0 | *aResult = mBrowsingContext->NameEquals(aName); |
2582 | 0 | return NS_OK; |
2583 | 0 | } |
2584 | | |
2585 | | NS_IMETHODIMP |
2586 | | nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent) |
2587 | 0 | { |
2588 | 0 | aCustomUserAgent = mCustomUserAgent; |
2589 | 0 | return NS_OK; |
2590 | 0 | } |
2591 | | |
2592 | | NS_IMETHODIMP |
2593 | | nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent) |
2594 | 0 | { |
2595 | 0 | mCustomUserAgent = aCustomUserAgent; |
2596 | 0 | RefPtr<nsGlobalWindowInner> win = mScriptGlobal ? |
2597 | 0 | mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr; |
2598 | 0 | if (win) { |
2599 | 0 | Navigator* navigator = win->Navigator(); |
2600 | 0 | if (navigator) { |
2601 | 0 | navigator->ClearUserAgentCache(); |
2602 | 0 | } |
2603 | 0 | } |
2604 | 0 |
|
2605 | 0 | uint32_t childCount = mChildList.Length(); |
2606 | 0 | for (uint32_t i = 0; i < childCount; ++i) { |
2607 | 0 | nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i)); |
2608 | 0 | if (childShell) { |
2609 | 0 | childShell->SetCustomUserAgent(aCustomUserAgent); |
2610 | 0 | } |
2611 | 0 | } |
2612 | 0 | return NS_OK; |
2613 | 0 | } |
2614 | | |
2615 | | NS_IMETHODIMP |
2616 | | nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride) |
2617 | 0 | { |
2618 | 0 | NS_ENSURE_ARG_POINTER(aTouchEventsOverride); |
2619 | 0 |
|
2620 | 0 | *aTouchEventsOverride = mTouchEventsOverride; |
2621 | 0 | return NS_OK; |
2622 | 0 | } |
2623 | | |
2624 | | NS_IMETHODIMP |
2625 | | nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride) |
2626 | 0 | { |
2627 | 0 | if (!(aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE || |
2628 | 0 | aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED || |
2629 | 0 | aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED)) { |
2630 | 0 | return NS_ERROR_INVALID_ARG; |
2631 | 0 | } |
2632 | 0 | |
2633 | 0 | mTouchEventsOverride = aTouchEventsOverride; |
2634 | 0 |
|
2635 | 0 | uint32_t childCount = mChildList.Length(); |
2636 | 0 | for (uint32_t i = 0; i < childCount; ++i) { |
2637 | 0 | nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i)); |
2638 | 0 | if (childShell) { |
2639 | 0 | childShell->SetTouchEventsOverride(aTouchEventsOverride); |
2640 | 0 | } |
2641 | 0 | } |
2642 | 0 | return NS_OK; |
2643 | 0 | } |
2644 | | |
2645 | | /* virtual */ int32_t |
2646 | | nsDocShell::ItemType() |
2647 | 0 | { |
2648 | 0 | return mItemType; |
2649 | 0 | } |
2650 | | |
2651 | | NS_IMETHODIMP |
2652 | | nsDocShell::GetItemType(int32_t* aItemType) |
2653 | 0 | { |
2654 | 0 | NS_ENSURE_ARG_POINTER(aItemType); |
2655 | 0 |
|
2656 | 0 | *aItemType = ItemType(); |
2657 | 0 | return NS_OK; |
2658 | 0 | } |
2659 | | |
2660 | | NS_IMETHODIMP |
2661 | | nsDocShell::SetItemType(int32_t aItemType) |
2662 | 0 | { |
2663 | 0 | NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType)); |
2664 | 0 |
|
2665 | 0 | // Only allow setting the type on root docshells. Those would be the ones |
2666 | 0 | // that have the docloader service as mParent or have no mParent at all. |
2667 | 0 | nsCOMPtr<nsIDocumentLoader> docLoaderService = |
2668 | 0 | do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); |
2669 | 0 | NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED); |
2670 | 0 |
|
2671 | 0 | NS_ENSURE_STATE(!mParent || mParent == docLoaderService); |
2672 | 0 |
|
2673 | 0 | mItemType = aItemType; |
2674 | 0 |
|
2675 | 0 | // disable auth prompting for anything but content |
2676 | 0 | mAllowAuth = mItemType == typeContent; |
2677 | 0 |
|
2678 | 0 | RefPtr<nsPresContext> presContext = nullptr; |
2679 | 0 | GetPresContext(getter_AddRefs(presContext)); |
2680 | 0 | if (presContext) { |
2681 | 0 | presContext->UpdateIsChrome(); |
2682 | 0 | } |
2683 | 0 |
|
2684 | 0 | return NS_OK; |
2685 | 0 | } |
2686 | | |
2687 | | NS_IMETHODIMP |
2688 | | nsDocShell::GetParent(nsIDocShellTreeItem** aParent) |
2689 | 0 | { |
2690 | 0 | if (!mParent) { |
2691 | 0 | *aParent = nullptr; |
2692 | 0 | } else { |
2693 | 0 | CallQueryInterface(mParent, aParent); |
2694 | 0 | } |
2695 | 0 | // Note that in the case when the parent is not an nsIDocShellTreeItem we |
2696 | 0 | // don't want to throw; we just want to return null. |
2697 | 0 | return NS_OK; |
2698 | 0 | } |
2699 | | |
2700 | | already_AddRefed<nsDocShell> |
2701 | | nsDocShell::GetParentDocshell() |
2702 | 0 | { |
2703 | 0 | nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent)); |
2704 | 0 | return docshell.forget().downcast<nsDocShell>(); |
2705 | 0 | } |
2706 | | |
2707 | | void |
2708 | | nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal) |
2709 | 0 | { |
2710 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
2711 | 0 |
|
2712 | 0 | // If there is an existing document then there is no need to create |
2713 | 0 | // a client for a future initial about:blank document. |
2714 | 0 | if (mScriptGlobal && mScriptGlobal->GetCurrentInnerWindowInternal() && |
2715 | 0 | mScriptGlobal->GetCurrentInnerWindowInternal()->GetExtantDoc()) { |
2716 | 0 | MOZ_DIAGNOSTIC_ASSERT( |
2717 | 0 | mScriptGlobal->GetCurrentInnerWindowInternal()->GetClientInfo().isSome()); |
2718 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mInitialClientSource); |
2719 | 0 | return; |
2720 | 0 | } |
2721 | 0 | |
2722 | 0 | // Don't recreate the initial client source. We call this multiple times |
2723 | 0 | // when DoChannelLoad() is called before CreateAboutBlankContentViewer. |
2724 | 0 | if (mInitialClientSource) { |
2725 | 0 | return; |
2726 | 0 | } |
2727 | 0 | |
2728 | 0 | // Don't pre-allocate the client when we are sandboxed. The inherited |
2729 | 0 | // principal does not take sandboxing into account. |
2730 | 0 | // TODO: Refactor sandboxing principal code out so we can use it here. |
2731 | 0 | if (!aPrincipal && mSandboxFlags) { |
2732 | 0 | return; |
2733 | 0 | } |
2734 | 0 | |
2735 | 0 | nsIPrincipal* principal = aPrincipal ? aPrincipal |
2736 | 0 | : GetInheritedPrincipal(false); |
2737 | 0 |
|
2738 | 0 | // Sometimes there is no principal available when we are called from |
2739 | 0 | // CreateAboutBlankContentViewer. For example, sometimes the principal |
2740 | 0 | // is only extracted from the load context after the document is created |
2741 | 0 | // in nsDocument::ResetToURI(). Ideally we would do something similar |
2742 | 0 | // here, but for now lets just avoid the issue by not preallocating the |
2743 | 0 | // client. |
2744 | 0 | if (!principal) { |
2745 | 0 | return; |
2746 | 0 | } |
2747 | 0 | |
2748 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
2749 | 0 | if (!win) { |
2750 | 0 | return; |
2751 | 0 | } |
2752 | 0 | |
2753 | 0 | mInitialClientSource = |
2754 | 0 | ClientManager::CreateSource(ClientType::Window, |
2755 | 0 | win->EventTargetFor(TaskCategory::Other), |
2756 | 0 | principal); |
2757 | 0 | MOZ_DIAGNOSTIC_ASSERT(mInitialClientSource); |
2758 | 0 |
|
2759 | 0 | // Mark the initial client as execution ready, but owned by the docshell. |
2760 | 0 | // If the client is actually used this will cause ClientSource to force |
2761 | 0 | // the creation of the initial about:blank by calling nsDocShell::GetDocument(). |
2762 | 0 | mInitialClientSource->DocShellExecutionReady(this); |
2763 | 0 |
|
2764 | 0 | // Next, check to see if the parent is controlled. |
2765 | 0 | nsCOMPtr<nsIDocShell> parent = GetParentDocshell(); |
2766 | 0 | nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr; |
2767 | 0 | nsPIDOMWindowInner* parentInner = |
2768 | 0 | parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr; |
2769 | 0 | if (!parentInner) { |
2770 | 0 | return; |
2771 | 0 | } |
2772 | 0 | |
2773 | 0 | nsCOMPtr<nsIURI> uri; |
2774 | 0 | MOZ_ALWAYS_SUCCEEDS( |
2775 | 0 | NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank"))); |
2776 | 0 |
|
2777 | 0 | // We're done if there is no parent controller or if this docshell |
2778 | 0 | // is not permitted to control for some reason. |
2779 | 0 | Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController()); |
2780 | 0 | if (controller.isNothing() || !ServiceWorkerAllowedToControlWindow(principal, uri)) { |
2781 | 0 | return; |
2782 | 0 | } |
2783 | 0 | |
2784 | 0 | mInitialClientSource->InheritController(controller.ref()); |
2785 | 0 | } |
2786 | | |
2787 | | Maybe<ClientInfo> |
2788 | | nsDocShell::GetInitialClientInfo() const |
2789 | 0 | { |
2790 | 0 | if (mInitialClientSource) { |
2791 | 0 | Maybe<ClientInfo> result; |
2792 | 0 | result.emplace(mInitialClientSource->Info()); |
2793 | 0 | return result; |
2794 | 0 | } |
2795 | 0 | |
2796 | 0 | nsGlobalWindowInner* innerWindow = |
2797 | 0 | mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr; |
2798 | 0 | nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr; |
2799 | 0 |
|
2800 | 0 | if (!doc || !doc->IsInitialDocument()) { |
2801 | 0 | return Maybe<ClientInfo>(); |
2802 | 0 | } |
2803 | 0 | |
2804 | 0 | return innerWindow->GetClientInfo(); |
2805 | 0 | } |
2806 | | |
2807 | | void |
2808 | | nsDocShell::RecomputeCanExecuteScripts() |
2809 | 0 | { |
2810 | 0 | bool old = mCanExecuteScripts; |
2811 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
2812 | 0 |
|
2813 | 0 | // If we have no tree owner, that means that we've been detached from the |
2814 | 0 | // docshell tree (this is distinct from having no parent dochshell, which |
2815 | 0 | // is the case for root docshells). It would be nice to simply disallow |
2816 | 0 | // script in detached docshells, but bug 986542 demonstrates that this |
2817 | 0 | // behavior breaks at least one website. |
2818 | 0 | // |
2819 | 0 | // So instead, we use our previous value, unless mAllowJavascript has been |
2820 | 0 | // explicitly set to false. |
2821 | 0 | if (!mTreeOwner) { |
2822 | 0 | mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript; |
2823 | 0 | // If scripting has been explicitly disabled on our docshell, we're done. |
2824 | 0 | } else if (!mAllowJavascript) { |
2825 | 0 | mCanExecuteScripts = false; |
2826 | 0 | // If we have a parent, inherit. |
2827 | 0 | } else if (parent) { |
2828 | 0 | mCanExecuteScripts = parent->mCanExecuteScripts; |
2829 | 0 | // Otherwise, we're the root of the tree, and we haven't explicitly disabled |
2830 | 0 | // script. Allow. |
2831 | 0 | } else { |
2832 | 0 | mCanExecuteScripts = true; |
2833 | 0 | } |
2834 | 0 |
|
2835 | 0 | // Inform our active DOM window. |
2836 | 0 | // |
2837 | 0 | // This will pass the outer, which will be in the scope of the active inner. |
2838 | 0 | if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) { |
2839 | 0 | xpc::Scriptability& scriptability = |
2840 | 0 | xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject()); |
2841 | 0 | scriptability.SetDocShellAllowsScript(mCanExecuteScripts); |
2842 | 0 | } |
2843 | 0 |
|
2844 | 0 | // If our value has changed, our children might be affected. Recompute their |
2845 | 0 | // value as well. |
2846 | 0 | if (old != mCanExecuteScripts) { |
2847 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
2848 | 0 | while (iter.HasMore()) { |
2849 | 0 | static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts(); |
2850 | 0 | } |
2851 | 0 | } |
2852 | 0 | } |
2853 | | |
2854 | | nsresult |
2855 | | nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) |
2856 | 0 | { |
2857 | 0 | bool wasFrame = IsFrame(); |
2858 | | #ifdef DEBUG |
2859 | | bool wasPrivate = UsePrivateBrowsing(); |
2860 | | #endif |
2861 | |
|
2862 | 0 | nsresult rv = nsDocLoader::SetDocLoaderParent(aParent); |
2863 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
2864 | 0 |
|
2865 | 0 | nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup); |
2866 | 0 | if (wasFrame != IsFrame() && priorityGroup) { |
2867 | 0 | priorityGroup->AdjustPriority(wasFrame ? -1 : 1); |
2868 | 0 | } |
2869 | 0 |
|
2870 | 0 | // Curse ambiguous nsISupports inheritance! |
2871 | 0 | nsISupports* parent = GetAsSupports(aParent); |
2872 | 0 |
|
2873 | 0 | // If parent is another docshell, we inherit all their flags for |
2874 | 0 | // allowing plugins, scripting etc. |
2875 | 0 | bool value; |
2876 | 0 | nsString customUserAgent; |
2877 | 0 | nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent)); |
2878 | 0 |
|
2879 | 0 | if (parentAsDocShell) { |
2880 | 0 | if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) { |
2881 | 0 | SetAllowPlugins(value); |
2882 | 0 | } |
2883 | 0 | if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) { |
2884 | 0 | SetAllowJavascript(value); |
2885 | 0 | } |
2886 | 0 | if (mAllowMetaRedirects && NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) { |
2887 | 0 | SetAllowMetaRedirects(value); |
2888 | 0 | } |
2889 | 0 | if (mAllowSubframes && NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) { |
2890 | 0 | SetAllowSubframes(value); |
2891 | 0 | } |
2892 | 0 | if (mAllowImages && NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) { |
2893 | 0 | SetAllowImages(value); |
2894 | 0 | } |
2895 | 0 | SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia); |
2896 | 0 | if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) { |
2897 | 0 | SetAllowWindowControl(value); |
2898 | 0 | } |
2899 | 0 | SetAllowContentRetargeting(mAllowContentRetargeting && |
2900 | 0 | parentAsDocShell->GetAllowContentRetargetingOnChildren()); |
2901 | 0 | if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) { |
2902 | 0 | SetIsActive(value); |
2903 | 0 | } |
2904 | 0 | if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) && |
2905 | 0 | !customUserAgent.IsEmpty()) { |
2906 | 0 | SetCustomUserAgent(customUserAgent); |
2907 | 0 | } |
2908 | 0 | if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) { |
2909 | 0 | value = false; |
2910 | 0 | } |
2911 | 0 | SetAllowDNSPrefetch(mAllowDNSPrefetch && value); |
2912 | 0 | if (mInheritPrivateBrowsingId) { |
2913 | 0 | value = parentAsDocShell->GetAffectPrivateSessionLifetime(); |
2914 | 0 | SetAffectPrivateSessionLifetime(value); |
2915 | 0 | } |
2916 | 0 | uint32_t flags; |
2917 | 0 | if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) { |
2918 | 0 | SetDefaultLoadFlags(flags); |
2919 | 0 | } |
2920 | 0 | uint32_t touchEventsOverride; |
2921 | 0 | if (NS_SUCCEEDED(parentAsDocShell->GetTouchEventsOverride(&touchEventsOverride))) { |
2922 | 0 | SetTouchEventsOverride(touchEventsOverride); |
2923 | 0 | } |
2924 | 0 | } |
2925 | 0 |
|
2926 | 0 | nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent)); |
2927 | 0 | if (parentAsLoadContext && mInheritPrivateBrowsingId && |
2928 | 0 | NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) { |
2929 | 0 | SetPrivateBrowsing(value); |
2930 | 0 | } |
2931 | 0 |
|
2932 | 0 | nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent)); |
2933 | 0 | if (parentURIListener) { |
2934 | 0 | mContentListener->SetParentContentListener(parentURIListener); |
2935 | 0 | } |
2936 | 0 |
|
2937 | 0 | // Our parent has changed. Recompute scriptability. |
2938 | 0 | RecomputeCanExecuteScripts(); |
2939 | 0 |
|
2940 | 0 | NS_ASSERTION(mInheritPrivateBrowsingId || wasPrivate == UsePrivateBrowsing(), |
2941 | 0 | "Private browsing state changed while inheritance was disabled"); |
2942 | 0 |
|
2943 | 0 | return NS_OK; |
2944 | 0 | } |
2945 | | |
2946 | | NS_IMETHODIMP |
2947 | | nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent) |
2948 | 0 | { |
2949 | 0 | NS_ENSURE_ARG_POINTER(aParent); |
2950 | 0 | *aParent = nullptr; |
2951 | 0 |
|
2952 | 0 | if (nsIDocShell::GetIsMozBrowser()) { |
2953 | 0 | return NS_OK; |
2954 | 0 | } |
2955 | 0 | |
2956 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent = |
2957 | 0 | do_QueryInterface(GetAsSupports(mParent)); |
2958 | 0 | if (!parent) { |
2959 | 0 | return NS_OK; |
2960 | 0 | } |
2961 | 0 | |
2962 | 0 | if (parent->ItemType() == mItemType) { |
2963 | 0 | parent.swap(*aParent); |
2964 | 0 | } |
2965 | 0 | return NS_OK; |
2966 | 0 | } |
2967 | | |
2968 | | NS_IMETHODIMP |
2969 | | nsDocShell::GetSameTypeParentIgnoreBrowserBoundaries(nsIDocShell** aParent) |
2970 | 0 | { |
2971 | 0 | NS_ENSURE_ARG_POINTER(aParent); |
2972 | 0 | *aParent = nullptr; |
2973 | 0 |
|
2974 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent = |
2975 | 0 | do_QueryInterface(GetAsSupports(mParent)); |
2976 | 0 | if (!parent) { |
2977 | 0 | return NS_OK; |
2978 | 0 | } |
2979 | 0 | |
2980 | 0 | if (parent->ItemType() == mItemType) { |
2981 | 0 | nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent); |
2982 | 0 | parentDS.forget(aParent); |
2983 | 0 | } |
2984 | 0 | return NS_OK; |
2985 | 0 | } |
2986 | | |
2987 | | NS_IMETHODIMP |
2988 | | nsDocShell::GetRootTreeItem(nsIDocShellTreeItem** aRootTreeItem) |
2989 | 0 | { |
2990 | 0 | NS_ENSURE_ARG_POINTER(aRootTreeItem); |
2991 | 0 |
|
2992 | 0 | RefPtr<nsDocShell> root = this; |
2993 | 0 | RefPtr<nsDocShell> parent = root->GetParentDocshell(); |
2994 | 0 | while (parent) { |
2995 | 0 | root = parent; |
2996 | 0 | parent = root->GetParentDocshell(); |
2997 | 0 | } |
2998 | 0 |
|
2999 | 0 | root.forget(aRootTreeItem); |
3000 | 0 | return NS_OK; |
3001 | 0 | } |
3002 | | |
3003 | | NS_IMETHODIMP |
3004 | | nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootTreeItem) |
3005 | 0 | { |
3006 | 0 | NS_ENSURE_ARG_POINTER(aRootTreeItem); |
3007 | 0 | *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this); |
3008 | 0 |
|
3009 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
3010 | 0 | NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)), |
3011 | 0 | NS_ERROR_FAILURE); |
3012 | 0 | while (parent) { |
3013 | 0 | *aRootTreeItem = parent; |
3014 | 0 | NS_ENSURE_SUCCESS( |
3015 | 0 | (*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)), |
3016 | 0 | NS_ERROR_FAILURE); |
3017 | 0 | } |
3018 | 0 | NS_ADDREF(*aRootTreeItem); |
3019 | 0 | return NS_OK; |
3020 | 0 | } |
3021 | | |
3022 | | NS_IMETHODIMP |
3023 | | nsDocShell::GetSameTypeRootTreeItemIgnoreBrowserBoundaries(nsIDocShell** aRootTreeItem) |
3024 | 0 | { |
3025 | 0 | NS_ENSURE_ARG_POINTER(aRootTreeItem); |
3026 | 0 | *aRootTreeItem = static_cast<nsIDocShell *>(this); |
3027 | 0 |
|
3028 | 0 | nsCOMPtr<nsIDocShell> parent; |
3029 | 0 | NS_ENSURE_SUCCESS(GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)), |
3030 | 0 | NS_ERROR_FAILURE); |
3031 | 0 | while (parent) { |
3032 | 0 | *aRootTreeItem = parent; |
3033 | 0 | NS_ENSURE_SUCCESS((*aRootTreeItem)-> |
3034 | 0 | GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent)), |
3035 | 0 | NS_ERROR_FAILURE); |
3036 | 0 | } |
3037 | 0 | NS_ADDREF(*aRootTreeItem); |
3038 | 0 | return NS_OK; |
3039 | 0 | } |
3040 | | |
3041 | | /* static */ |
3042 | | bool |
3043 | | nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem, |
3044 | | nsIDocShellTreeItem* aAccessingItem, |
3045 | | bool aConsiderOpener) |
3046 | 0 | { |
3047 | 0 | MOZ_ASSERT(aTargetItem, "Must have target item!"); |
3048 | 0 |
|
3049 | 0 | if (!gValidateOrigin || !aAccessingItem) { |
3050 | 0 | // Good to go |
3051 | 0 | return true; |
3052 | 0 | } |
3053 | 0 | |
3054 | 0 | // XXXbz should we care if aAccessingItem or the document therein is |
3055 | 0 | // chrome? Should those get extra privileges? |
3056 | 0 | |
3057 | 0 | // For historical context, see: |
3058 | 0 | // |
3059 | 0 | // Bug 13871: Prevent frameset spoofing |
3060 | 0 | // Bug 103638: Targets with same name in different windows open in wrong |
3061 | 0 | // window with javascript |
3062 | 0 | // Bug 408052: Adopt "ancestor" frame navigation policy |
3063 | 0 | |
3064 | 0 | // Now do a security check. |
3065 | 0 | // |
3066 | 0 | // Disallow navigation if the two frames are not part of the same app, or if |
3067 | 0 | // they have different is-in-browser-element states. |
3068 | 0 | // |
3069 | 0 | // Allow navigation if |
3070 | 0 | // 1) aAccessingItem can script aTargetItem or one of its ancestors in |
3071 | 0 | // the frame hierarchy or |
3072 | 0 | // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant |
3073 | 0 | // 3) aTargetItem is a top-level frame and aAccessingItem can target |
3074 | 0 | // its opener per rule (1) or (2). |
3075 | 0 | |
3076 | 0 | if (aTargetItem == aAccessingItem) { |
3077 | 0 | // A frame is allowed to navigate itself. |
3078 | 0 | return true; |
3079 | 0 | } |
3080 | 0 | |
3081 | 0 | nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem); |
3082 | 0 | nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem); |
3083 | 0 | if (!targetDS || !accessingDS) { |
3084 | 0 | // We must be able to convert both to nsIDocShell. |
3085 | 0 | return false; |
3086 | 0 | } |
3087 | 0 | |
3088 | 0 | if (targetDS->GetIsInIsolatedMozBrowserElement() != |
3089 | 0 | accessingDS->GetIsInIsolatedMozBrowserElement()) { |
3090 | 0 | return false; |
3091 | 0 | } |
3092 | 0 | |
3093 | 0 | nsCOMPtr<nsIDocShellTreeItem> accessingRoot; |
3094 | 0 | aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot)); |
3095 | 0 | nsCOMPtr<nsIDocShell> accessingRootDS = do_QueryInterface(accessingRoot); |
3096 | 0 |
|
3097 | 0 | nsCOMPtr<nsIDocShellTreeItem> targetRoot; |
3098 | 0 | aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot)); |
3099 | 0 | nsCOMPtr<nsIDocShell> targetRootDS = do_QueryInterface(targetRoot); |
3100 | 0 |
|
3101 | 0 | OriginAttributes targetOA = |
3102 | 0 | static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes(); |
3103 | 0 | OriginAttributes accessingOA = |
3104 | 0 | static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes(); |
3105 | 0 |
|
3106 | 0 | // When the first party isolation is on, the top-level docShell may not have |
3107 | 0 | // the firstPartyDomain in its originAttributes, but its document will have |
3108 | 0 | // it. So we get the firstPartyDomain from the nodePrincipal of the document |
3109 | 0 | // before we compare the originAttributes. |
3110 | 0 | if (OriginAttributes::IsFirstPartyEnabled()) { |
3111 | 0 | if (aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent && |
3112 | 0 | (accessingDS == accessingRootDS || accessingDS->GetIsMozBrowser())) { |
3113 | 0 |
|
3114 | 0 | nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument(); |
3115 | 0 |
|
3116 | 0 | if (accessingDoc) { |
3117 | 0 | nsCOMPtr<nsIPrincipal> accessingPrincipal = accessingDoc->NodePrincipal(); |
3118 | 0 |
|
3119 | 0 | accessingOA.mFirstPartyDomain = |
3120 | 0 | accessingPrincipal->OriginAttributesRef().mFirstPartyDomain; |
3121 | 0 | } |
3122 | 0 | } |
3123 | 0 |
|
3124 | 0 | if (aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent && |
3125 | 0 | (targetDS == targetRootDS || targetDS->GetIsMozBrowser())) { |
3126 | 0 |
|
3127 | 0 | nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument(); |
3128 | 0 |
|
3129 | 0 | if (targetDoc) { |
3130 | 0 | nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal(); |
3131 | 0 |
|
3132 | 0 | targetOA.mFirstPartyDomain = |
3133 | 0 | targetPrincipal->OriginAttributesRef().mFirstPartyDomain; |
3134 | 0 | } |
3135 | 0 | } |
3136 | 0 | } |
3137 | 0 |
|
3138 | 0 | if (targetOA != accessingOA) { |
3139 | 0 | return false; |
3140 | 0 | } |
3141 | 0 | |
3142 | 0 | // A private document can't access a non-private one, and vice versa. |
3143 | 0 | if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() != |
3144 | 0 | static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) { |
3145 | 0 | return false; |
3146 | 0 | } |
3147 | 0 | |
3148 | 0 | if (aTargetItem == accessingRoot) { |
3149 | 0 | // A frame can navigate its root. |
3150 | 0 | return true; |
3151 | 0 | } |
3152 | 0 | |
3153 | 0 | // Check if aAccessingItem can navigate one of aTargetItem's ancestors. |
3154 | 0 | nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem; |
3155 | 0 | do { |
3156 | 0 | if (ValidateOrigin(aAccessingItem, target)) { |
3157 | 0 | return true; |
3158 | 0 | } |
3159 | 0 | |
3160 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
3161 | 0 | target->GetSameTypeParent(getter_AddRefs(parent)); |
3162 | 0 | parent.swap(target); |
3163 | 0 | } while (target); |
3164 | 0 |
|
3165 | 0 | if (aTargetItem != targetRoot) { |
3166 | 0 | // target is a subframe, not in accessor's frame hierarchy, and all its |
3167 | 0 | // ancestors have origins different from that of the accessor. Don't |
3168 | 0 | // allow access. |
3169 | 0 | return false; |
3170 | 0 | } |
3171 | 0 | |
3172 | 0 | if (!aConsiderOpener) { |
3173 | 0 | // All done here |
3174 | 0 | return false; |
3175 | 0 | } |
3176 | 0 | |
3177 | 0 | nsCOMPtr<nsPIDOMWindowOuter> targetWindow = aTargetItem->GetWindow(); |
3178 | 0 | if (!targetWindow) { |
3179 | 0 | NS_ERROR("This should not happen, really"); |
3180 | 0 | return false; |
3181 | 0 | } |
3182 | 0 |
|
3183 | 0 | nsCOMPtr<mozIDOMWindowProxy> targetOpener = targetWindow->GetOpener(); |
3184 | 0 | nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener)); |
3185 | 0 | nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav)); |
3186 | 0 |
|
3187 | 0 | if (!openerItem) { |
3188 | 0 | return false; |
3189 | 0 | } |
3190 | 0 | |
3191 | 0 | return CanAccessItem(openerItem, aAccessingItem, false); |
3192 | 0 | } |
3193 | | |
3194 | | static bool |
3195 | | ItemIsActive(nsIDocShellTreeItem* aItem) |
3196 | 0 | { |
3197 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> window = aItem->GetWindow()) { |
3198 | 0 | auto* win = nsGlobalWindowOuter::Cast(window); |
3199 | 0 | if (!win->GetClosedOuter()) { |
3200 | 0 | return true; |
3201 | 0 | } |
3202 | 0 | } |
3203 | 0 | |
3204 | 0 | return false; |
3205 | 0 | } |
3206 | | |
3207 | | NS_IMETHODIMP |
3208 | | nsDocShell::FindItemWithName(const nsAString& aName, |
3209 | | nsIDocShellTreeItem* aRequestor, |
3210 | | nsIDocShellTreeItem* aOriginalRequestor, |
3211 | | bool aSkipTabGroup, |
3212 | | nsIDocShellTreeItem** aResult) |
3213 | 0 | { |
3214 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
3215 | 0 |
|
3216 | 0 | // If we don't find one, we return NS_OK and a null result |
3217 | 0 | *aResult = nullptr; |
3218 | 0 |
|
3219 | 0 | if (aName.IsEmpty()) { |
3220 | 0 | return NS_OK; |
3221 | 0 | } |
3222 | 0 | |
3223 | 0 | if (aRequestor) { |
3224 | 0 | // If aRequestor is not null we don't need to check special names, so |
3225 | 0 | // just hand straight off to the search by actual name function. |
3226 | 0 | return DoFindItemWithName(aName, aRequestor, aOriginalRequestor, |
3227 | 0 | aSkipTabGroup, aResult); |
3228 | 0 | } else { |
3229 | 0 | // This is the entry point into the target-finding algorithm. Check |
3230 | 0 | // for special names. This should only be done once, hence the check |
3231 | 0 | // for a null aRequestor. |
3232 | 0 |
|
3233 | 0 | nsCOMPtr<nsIDocShellTreeItem> foundItem; |
3234 | 0 | if (aName.LowerCaseEqualsLiteral("_self")) { |
3235 | 0 | foundItem = this; |
3236 | 0 | } else if (aName.LowerCaseEqualsLiteral("_blank")) { |
3237 | 0 | // Just return null. Caller must handle creating a new window with |
3238 | 0 | // a blank name himself. |
3239 | 0 | return NS_OK; |
3240 | 0 | } else if (aName.LowerCaseEqualsLiteral("_parent")) { |
3241 | 0 | GetSameTypeParent(getter_AddRefs(foundItem)); |
3242 | 0 | if (!foundItem) { |
3243 | 0 | foundItem = this; |
3244 | 0 | } |
3245 | 0 | } else if (aName.LowerCaseEqualsLiteral("_top")) { |
3246 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(foundItem)); |
3247 | 0 | NS_ASSERTION(foundItem, "Must have this; worst case it's us!"); |
3248 | 0 | } else { |
3249 | 0 | // Do the search for item by an actual name. |
3250 | 0 | DoFindItemWithName(aName, aRequestor, aOriginalRequestor, |
3251 | 0 | aSkipTabGroup, getter_AddRefs(foundItem)); |
3252 | 0 | } |
3253 | 0 |
|
3254 | 0 | if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) { |
3255 | 0 | foundItem = nullptr; |
3256 | 0 | } |
3257 | 0 |
|
3258 | 0 | // DoFindItemWithName only returns active items and we don't check if |
3259 | 0 | // the item is active for the special cases. |
3260 | 0 | if (foundItem) { |
3261 | 0 | foundItem.swap(*aResult); |
3262 | 0 | } |
3263 | 0 | return NS_OK; |
3264 | 0 | } |
3265 | 0 | } |
3266 | | |
3267 | | void |
3268 | 0 | nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() { |
3269 | 0 | // Chrome docshells must not have a private browsing OriginAttribute |
3270 | 0 | // Content docshells must maintain the equality: |
3271 | 0 | // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId |
3272 | 0 | if (mItemType == typeChrome) { |
3273 | 0 | MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0); |
3274 | 0 | } else { |
3275 | 0 | MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId); |
3276 | 0 | } |
3277 | 0 | } |
3278 | | |
3279 | | nsresult |
3280 | | nsDocShell::DoFindItemWithName(const nsAString& aName, |
3281 | | nsIDocShellTreeItem* aRequestor, |
3282 | | nsIDocShellTreeItem* aOriginalRequestor, |
3283 | | bool aSkipTabGroup, |
3284 | | nsIDocShellTreeItem** aResult) |
3285 | 0 | { |
3286 | 0 | // First we check our name. |
3287 | 0 | if (mBrowsingContext->NameEquals(aName) && ItemIsActive(this) && |
3288 | 0 | CanAccessItem(this, aOriginalRequestor)) { |
3289 | 0 | NS_ADDREF(*aResult = this); |
3290 | 0 | return NS_OK; |
3291 | 0 | } |
3292 | 0 |
|
3293 | 0 | // Second we check our children making sure not to ask a child if |
3294 | 0 | // it is the aRequestor. |
3295 | | #ifdef DEBUG |
3296 | | nsresult rv = |
3297 | | #endif |
3298 | 0 | FindChildWithName(aName, true, true, aRequestor, aOriginalRequestor, |
3299 | 0 | aResult); |
3300 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), |
3301 | 0 | "FindChildWithName should not be failing here."); |
3302 | 0 | if (*aResult) { |
3303 | 0 | return NS_OK; |
3304 | 0 | } |
3305 | 0 | |
3306 | 0 | // Third if we have a parent and it isn't the requestor then we |
3307 | 0 | // should ask it to do the search. If it is the requestor we |
3308 | 0 | // should just stop here and let the parent do the rest. If we |
3309 | 0 | // don't have a parent, then we should ask the |
3310 | 0 | // docShellTreeOwner to do the search. |
3311 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem = |
3312 | 0 | do_QueryInterface(GetAsSupports(mParent)); |
3313 | 0 | if (parentAsTreeItem) { |
3314 | 0 | if (parentAsTreeItem == aRequestor) { |
3315 | 0 | return NS_OK; |
3316 | 0 | } |
3317 | 0 | |
3318 | 0 | // If we have a same-type parent, respecting browser and app boundaries. |
3319 | 0 | // NOTE: Could use GetSameTypeParent if the issues described in bug 1310344 are fixed. |
3320 | 0 | if (!GetIsMozBrowser() && parentAsTreeItem->ItemType() == mItemType) { |
3321 | 0 | return parentAsTreeItem->FindItemWithName( |
3322 | 0 | aName, |
3323 | 0 | static_cast<nsIDocShellTreeItem*>(this), |
3324 | 0 | aOriginalRequestor, |
3325 | 0 | /* aSkipTabGroup = */ false, |
3326 | 0 | aResult); |
3327 | 0 | } |
3328 | 0 | } |
3329 | 0 | |
3330 | 0 | // If we have a null parent or the parent is not of the same type, we need to |
3331 | 0 | // give up on finding it in our tree, and start looking in our TabGroup. |
3332 | 0 | nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow(); |
3333 | 0 | if (window && !aSkipTabGroup) { |
3334 | 0 | RefPtr<mozilla::dom::TabGroup> tabGroup = window->TabGroup(); |
3335 | 0 | tabGroup->FindItemWithName(aName, aRequestor, aOriginalRequestor, aResult); |
3336 | 0 | } |
3337 | 0 |
|
3338 | 0 | return NS_OK; |
3339 | 0 | } |
3340 | | |
3341 | | bool |
3342 | | nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell) |
3343 | 0 | { |
3344 | 0 | // If no target then not sandboxed. |
3345 | 0 | if (!aTargetDocShell) { |
3346 | 0 | return false; |
3347 | 0 | } |
3348 | 0 | |
3349 | 0 | // We cannot be sandboxed from ourselves. |
3350 | 0 | if (aTargetDocShell == this) { |
3351 | 0 | return false; |
3352 | 0 | } |
3353 | 0 | |
3354 | 0 | // Default the sandbox flags to our flags, so that if we can't retrieve the |
3355 | 0 | // active document, we will still enforce our own. |
3356 | 0 | uint32_t sandboxFlags = mSandboxFlags; |
3357 | 0 | if (mContentViewer) { |
3358 | 0 | nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument(); |
3359 | 0 | if (doc) { |
3360 | 0 | sandboxFlags = doc->GetSandboxFlags(); |
3361 | 0 | } |
3362 | 0 | } |
3363 | 0 |
|
3364 | 0 | // If no flags, we are not sandboxed at all. |
3365 | 0 | if (!sandboxFlags) { |
3366 | 0 | return false; |
3367 | 0 | } |
3368 | 0 | |
3369 | 0 | // If aTargetDocShell has an ancestor, it is not top level. |
3370 | 0 | nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget; |
3371 | 0 | aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget)); |
3372 | 0 | if (ancestorOfTarget) { |
3373 | 0 | do { |
3374 | 0 | // We are not sandboxed if we are an ancestor of target. |
3375 | 0 | if (ancestorOfTarget == this) { |
3376 | 0 | return false; |
3377 | 0 | } |
3378 | 0 | nsCOMPtr<nsIDocShellTreeItem> tempTreeItem; |
3379 | 0 | ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem)); |
3380 | 0 | tempTreeItem.swap(ancestorOfTarget); |
3381 | 0 | } while (ancestorOfTarget); |
3382 | 0 |
|
3383 | 0 | // Otherwise, we are sandboxed from aTargetDocShell. |
3384 | 0 | return true; |
3385 | 0 | } |
3386 | 0 | |
3387 | 0 | // aTargetDocShell is top level, are we the "one permitted sandboxed |
3388 | 0 | // navigator", i.e. did we open aTargetDocShell? |
3389 | 0 | nsCOMPtr<nsIDocShell> permittedNavigator; |
3390 | 0 | aTargetDocShell->GetOnePermittedSandboxedNavigator( |
3391 | 0 | getter_AddRefs(permittedNavigator)); |
3392 | 0 | if (permittedNavigator == this) { |
3393 | 0 | return false; |
3394 | 0 | } |
3395 | 0 | |
3396 | 0 | // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed |
3397 | 0 | // from our top. |
3398 | 0 | if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) { |
3399 | 0 | nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; |
3400 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem)); |
3401 | 0 | if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) { |
3402 | 0 | return false; |
3403 | 0 | } |
3404 | 0 | } |
3405 | 0 | |
3406 | 0 | // Otherwise, we are sandboxed from aTargetDocShell. |
3407 | 0 | return true; |
3408 | 0 | } |
3409 | | |
3410 | | NS_IMETHODIMP |
3411 | | nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner) |
3412 | 0 | { |
3413 | 0 | NS_ENSURE_ARG_POINTER(aTreeOwner); |
3414 | 0 |
|
3415 | 0 | *aTreeOwner = mTreeOwner; |
3416 | 0 | NS_IF_ADDREF(*aTreeOwner); |
3417 | 0 | return NS_OK; |
3418 | 0 | } |
3419 | | |
3420 | | NS_IMETHODIMP |
3421 | | nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) |
3422 | 0 | { |
3423 | 0 | if (mIsBeingDestroyed && aTreeOwner) { |
3424 | 0 | return NS_ERROR_FAILURE; |
3425 | 0 | } |
3426 | 0 | |
3427 | 0 | // Don't automatically set the progress based on the tree owner for frames |
3428 | 0 | if (!IsFrame()) { |
3429 | 0 | nsCOMPtr<nsIWebProgress> webProgress = |
3430 | 0 | do_QueryInterface(GetAsSupports(this)); |
3431 | 0 |
|
3432 | 0 | if (webProgress) { |
3433 | 0 | nsCOMPtr<nsIWebProgressListener> oldListener = |
3434 | 0 | do_QueryInterface(mTreeOwner); |
3435 | 0 | nsCOMPtr<nsIWebProgressListener> newListener = |
3436 | 0 | do_QueryInterface(aTreeOwner); |
3437 | 0 |
|
3438 | 0 | if (oldListener) { |
3439 | 0 | webProgress->RemoveProgressListener(oldListener); |
3440 | 0 | } |
3441 | 0 |
|
3442 | 0 | if (newListener) { |
3443 | 0 | webProgress->AddProgressListener(newListener, |
3444 | 0 | nsIWebProgress::NOTIFY_ALL); |
3445 | 0 | } |
3446 | 0 | } |
3447 | 0 | } |
3448 | 0 |
|
3449 | 0 | mTreeOwner = aTreeOwner; // Weak reference per API |
3450 | 0 |
|
3451 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
3452 | 0 | while (iter.HasMore()) { |
3453 | 0 | nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext()); |
3454 | 0 | NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); |
3455 | 0 |
|
3456 | 0 | if (child->ItemType() == mItemType) { |
3457 | 0 | child->SetTreeOwner(aTreeOwner); |
3458 | 0 | } |
3459 | 0 | } |
3460 | 0 |
|
3461 | 0 | // Our tree owner has changed. Recompute scriptability. |
3462 | 0 | // |
3463 | 0 | // Note that this is near-redundant with the recomputation in |
3464 | 0 | // SetDocLoaderParent(), but not so for the root DocShell, where the call to |
3465 | 0 | // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(), |
3466 | 0 | // and we never set another parent. Given that this is neither expensive nor |
3467 | 0 | // performance-critical, let's be safe and unconditionally recompute this |
3468 | 0 | // state whenever dependent state changes. |
3469 | 0 | RecomputeCanExecuteScripts(); |
3470 | 0 |
|
3471 | 0 | return NS_OK; |
3472 | 0 | } |
3473 | | |
3474 | | NS_IMETHODIMP |
3475 | | nsDocShell::SetChildOffset(int32_t aChildOffset) |
3476 | 0 | { |
3477 | 0 | mChildOffset = aChildOffset; |
3478 | 0 | return NS_OK; |
3479 | 0 | } |
3480 | | |
3481 | | NS_IMETHODIMP |
3482 | | nsDocShell::GetChildOffset(int32_t* aChildOffset) |
3483 | 0 | { |
3484 | 0 | *aChildOffset = mChildOffset; |
3485 | 0 | return NS_OK; |
3486 | 0 | } |
3487 | | |
3488 | | NS_IMETHODIMP |
3489 | | nsDocShell::GetHistoryID(nsID** aID) |
3490 | 0 | { |
3491 | 0 | *aID = mHistoryID.Clone(); |
3492 | 0 | return NS_OK; |
3493 | 0 | } |
3494 | | |
3495 | | const nsID |
3496 | | nsDocShell::HistoryID() |
3497 | 0 | { |
3498 | 0 | return mHistoryID; |
3499 | 0 | } |
3500 | | |
3501 | | NS_IMETHODIMP |
3502 | | nsDocShell::GetIsInUnload(bool* aIsInUnload) |
3503 | 0 | { |
3504 | 0 | *aIsInUnload = mFiredUnloadEvent; |
3505 | 0 | return NS_OK; |
3506 | 0 | } |
3507 | | |
3508 | | NS_IMETHODIMP |
3509 | | nsDocShell::GetChildCount(int32_t* aChildCount) |
3510 | 0 | { |
3511 | 0 | NS_ENSURE_ARG_POINTER(aChildCount); |
3512 | 0 | *aChildCount = mChildList.Length(); |
3513 | 0 | return NS_OK; |
3514 | 0 | } |
3515 | | |
3516 | | NS_IMETHODIMP |
3517 | | nsDocShell::AddChild(nsIDocShellTreeItem* aChild) |
3518 | 0 | { |
3519 | 0 | NS_ENSURE_ARG_POINTER(aChild); |
3520 | 0 |
|
3521 | 0 | RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild); |
3522 | 0 | NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED); |
3523 | 0 |
|
3524 | 0 | // Make sure we're not creating a loop in the docshell tree |
3525 | 0 | nsDocLoader* ancestor = this; |
3526 | 0 | do { |
3527 | 0 | if (childAsDocLoader == ancestor) { |
3528 | 0 | return NS_ERROR_ILLEGAL_VALUE; |
3529 | 0 | } |
3530 | 0 | ancestor = ancestor->GetParent(); |
3531 | 0 | } while (ancestor); |
3532 | 0 |
|
3533 | 0 | // Make sure to remove the child from its current parent. |
3534 | 0 | nsDocLoader* childsParent = childAsDocLoader->GetParent(); |
3535 | 0 | if (childsParent) { |
3536 | 0 | nsresult rv = childsParent->RemoveChildLoader(childAsDocLoader); |
3537 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3538 | 0 | } |
3539 | 0 |
|
3540 | 0 | // Make sure to clear the treeowner in case this child is a different type |
3541 | 0 | // from us. |
3542 | 0 | aChild->SetTreeOwner(nullptr); |
3543 | 0 |
|
3544 | 0 | nsresult res = AddChildLoader(childAsDocLoader); |
3545 | 0 | NS_ENSURE_SUCCESS(res, res); |
3546 | 0 | NS_ASSERTION(!mChildList.IsEmpty(), |
3547 | 0 | "child list must not be empty after a successful add"); |
3548 | 0 |
|
3549 | 0 | nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild); |
3550 | 0 | bool dynamic = false; |
3551 | 0 | childDocShell->GetCreatedDynamically(&dynamic); |
3552 | 0 | if (!dynamic) { |
3553 | 0 | nsCOMPtr<nsISHEntry> currentSH; |
3554 | 0 | bool oshe = false; |
3555 | 0 | GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe); |
3556 | 0 | if (currentSH) { |
3557 | 0 | currentSH->HasDynamicallyAddedChild(&dynamic); |
3558 | 0 | } |
3559 | 0 | } |
3560 | 0 | childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1); |
3561 | 0 |
|
3562 | 0 | /* Set the child's global history if the parent has one */ |
3563 | 0 | if (mUseGlobalHistory) { |
3564 | 0 | childDocShell->SetUseGlobalHistory(true); |
3565 | 0 | } |
3566 | 0 |
|
3567 | 0 | if (aChild->ItemType() != mItemType) { |
3568 | 0 | return NS_OK; |
3569 | 0 | } |
3570 | 0 | |
3571 | 0 | aChild->SetTreeOwner(mTreeOwner); |
3572 | 0 |
|
3573 | 0 | nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild)); |
3574 | 0 | if (!childAsDocShell) { |
3575 | 0 | return NS_OK; |
3576 | 0 | } |
3577 | 0 | |
3578 | 0 | childAsDocShell->AttachBrowsingContext(this); |
3579 | 0 |
|
3580 | 0 | // charset, style-disabling, and zoom will be inherited in SetupNewViewer() |
3581 | 0 |
|
3582 | 0 | // Now take this document's charset and set the child's parentCharset field |
3583 | 0 | // to it. We'll later use that field, in the loading process, for the |
3584 | 0 | // charset choosing algorithm. |
3585 | 0 | // If we fail, at any point, we just return NS_OK. |
3586 | 0 | // This code has some performance impact. But this will be reduced when |
3587 | 0 | // the current charset will finally be stored as an Atom, avoiding the |
3588 | 0 | // alias resolution extra look-up. |
3589 | 0 |
|
3590 | 0 | // we are NOT going to propagate the charset is this Chrome's docshell |
3591 | 0 | if (mItemType == nsIDocShellTreeItem::typeChrome) { |
3592 | 0 | return NS_OK; |
3593 | 0 | } |
3594 | 0 | |
3595 | 0 | // get the parent's current charset |
3596 | 0 | if (!mContentViewer) { |
3597 | 0 | return NS_OK; |
3598 | 0 | } |
3599 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
3600 | 0 | if (!doc) { |
3601 | 0 | return NS_OK; |
3602 | 0 | } |
3603 | 0 | |
3604 | 0 | bool isWyciwyg = false; |
3605 | 0 |
|
3606 | 0 | if (mCurrentURI) { |
3607 | 0 | // Check if the url is wyciwyg |
3608 | 0 | mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg); |
3609 | 0 | } |
3610 | 0 |
|
3611 | 0 | if (!isWyciwyg) { |
3612 | 0 | // If this docshell is loaded from a wyciwyg: URI, don't |
3613 | 0 | // advertise our charset since it does not in any way reflect |
3614 | 0 | // the actual source charset, which is what we're trying to |
3615 | 0 | // expose here. |
3616 | 0 |
|
3617 | 0 | const Encoding* parentCS = doc->GetDocumentCharacterSet(); |
3618 | 0 | int32_t charsetSource = doc->GetDocumentCharacterSetSource(); |
3619 | 0 | // set the child's parentCharset |
3620 | 0 | childAsDocShell->SetParentCharset(parentCS, |
3621 | 0 | charsetSource, |
3622 | 0 | doc->NodePrincipal()); |
3623 | 0 | } |
3624 | 0 |
|
3625 | 0 | // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", |
3626 | 0 | // NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType); |
3627 | 0 |
|
3628 | 0 | return NS_OK; |
3629 | 0 | } |
3630 | | |
3631 | | NS_IMETHODIMP |
3632 | | nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild) |
3633 | 0 | { |
3634 | 0 | NS_ENSURE_ARG_POINTER(aChild); |
3635 | 0 |
|
3636 | 0 | RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild); |
3637 | 0 | NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED); |
3638 | 0 |
|
3639 | 0 | nsresult rv = RemoveChildLoader(childAsDocLoader); |
3640 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3641 | 0 |
|
3642 | 0 | nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild)); |
3643 | 0 | if (childAsDocShell) { |
3644 | 0 | childAsDocShell->DetachBrowsingContext(); |
3645 | 0 | } |
3646 | 0 |
|
3647 | 0 | aChild->SetTreeOwner(nullptr); |
3648 | 0 |
|
3649 | 0 | return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader); |
3650 | 0 | } |
3651 | | |
3652 | | NS_IMETHODIMP |
3653 | | nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild) |
3654 | 0 | { |
3655 | 0 | NS_ENSURE_ARG_POINTER(aChild); |
3656 | 0 |
|
3657 | | #ifdef DEBUG |
3658 | | if (aIndex < 0) { |
3659 | | NS_WARNING("Negative index passed to GetChildAt"); |
3660 | | } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) { |
3661 | | NS_WARNING("Too large an index passed to GetChildAt"); |
3662 | | } |
3663 | | #endif |
3664 | |
|
3665 | 0 | nsIDocumentLoader* child = ChildAt(aIndex); |
3666 | 0 | NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED); |
3667 | 0 |
|
3668 | 0 | return CallQueryInterface(child, aChild); |
3669 | 0 | } |
3670 | | |
3671 | | NS_IMETHODIMP |
3672 | | nsDocShell::FindChildWithName(const nsAString& aName, |
3673 | | bool aRecurse, bool aSameType, |
3674 | | nsIDocShellTreeItem* aRequestor, |
3675 | | nsIDocShellTreeItem* aOriginalRequestor, |
3676 | | nsIDocShellTreeItem** aResult) |
3677 | 0 | { |
3678 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
3679 | 0 |
|
3680 | 0 | // if we don't find one, we return NS_OK and a null result |
3681 | 0 | *aResult = nullptr; |
3682 | 0 |
|
3683 | 0 | if (aName.IsEmpty()) { |
3684 | 0 | return NS_OK; |
3685 | 0 | } |
3686 | 0 | |
3687 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
3688 | 0 | while (iter.HasMore()) { |
3689 | 0 | nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext()); |
3690 | 0 | NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); |
3691 | 0 | int32_t childType = child->ItemType(); |
3692 | 0 |
|
3693 | 0 | if (aSameType && (childType != mItemType)) { |
3694 | 0 | continue; |
3695 | 0 | } |
3696 | 0 | |
3697 | 0 | bool childNameEquals = false; |
3698 | 0 | child->NameEquals(aName, &childNameEquals); |
3699 | 0 | if (childNameEquals && ItemIsActive(child) && |
3700 | 0 | CanAccessItem(child, aOriginalRequestor)) { |
3701 | 0 | child.swap(*aResult); |
3702 | 0 | break; |
3703 | 0 | } |
3704 | 0 | |
3705 | 0 | // Only ask it to check children if it is same type |
3706 | 0 | if (childType != mItemType) { |
3707 | 0 | continue; |
3708 | 0 | } |
3709 | 0 | |
3710 | 0 | // Only ask the child if it isn't the requestor |
3711 | 0 | if (aRecurse && (aRequestor != child)) { |
3712 | 0 | // See if child contains the shell with the given name |
3713 | | #ifdef DEBUG |
3714 | | nsresult rv = |
3715 | | #endif |
3716 | | child->FindChildWithName(aName, true, aSameType, |
3717 | 0 | static_cast<nsIDocShellTreeItem*>(this), |
3718 | 0 | aOriginalRequestor, aResult); |
3719 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), "FindChildWithName should not fail here"); |
3720 | 0 | if (*aResult) { |
3721 | 0 | // found it |
3722 | 0 | return NS_OK; |
3723 | 0 | } |
3724 | 0 | } |
3725 | 0 | } |
3726 | 0 | return NS_OK; |
3727 | 0 | } |
3728 | | |
3729 | | NS_IMETHODIMP |
3730 | | nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry** aResult) |
3731 | 0 | { |
3732 | 0 | nsresult rv = NS_OK; |
3733 | 0 |
|
3734 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
3735 | 0 | *aResult = nullptr; |
3736 | 0 |
|
3737 | 0 | // A nsISHEntry for a child is *only* available when the parent is in |
3738 | 0 | // the progress of loading a document too... |
3739 | 0 |
|
3740 | 0 | if (mLSHE) { |
3741 | 0 | /* Before looking for the subframe's url, check |
3742 | 0 | * the expiration status of the parent. If the parent |
3743 | 0 | * has expired from cache, then subframes will not be |
3744 | 0 | * loaded from history in certain situations. |
3745 | 0 | */ |
3746 | 0 | bool parentExpired = mLSHE->GetExpirationStatus(); |
3747 | 0 |
|
3748 | 0 | /* Get the parent's Load Type so that it can be set on the child too. |
3749 | 0 | * By default give a loadHistory value |
3750 | 0 | */ |
3751 | 0 | uint32_t loadType = mLSHE->GetLoadType(); |
3752 | 0 | // If the user did a shift-reload on this frameset page, |
3753 | 0 | // we don't want to load the subframes from history. |
3754 | 0 | if (IsForceReloadType(loadType) || |
3755 | 0 | loadType == LOAD_REFRESH) { |
3756 | 0 | return rv; |
3757 | 0 | } |
3758 | 0 | |
3759 | 0 | /* If the user pressed reload and the parent frame has expired |
3760 | 0 | * from cache, we do not want to load the child frame from history. |
3761 | 0 | */ |
3762 | 0 | if (parentExpired && (loadType == LOAD_RELOAD_NORMAL)) { |
3763 | 0 | // The parent has expired. Return null. |
3764 | 0 | *aResult = nullptr; |
3765 | 0 | return rv; |
3766 | 0 | } |
3767 | 0 | |
3768 | 0 | // Get the child subframe from session history. |
3769 | 0 | rv = mLSHE->GetChildAt(aChildOffset, aResult); |
3770 | 0 | if (*aResult) { |
3771 | 0 | (*aResult)->SetLoadType(loadType); |
3772 | 0 | } |
3773 | 0 | } |
3774 | 0 | return rv; |
3775 | 0 | } |
3776 | | |
3777 | | NS_IMETHODIMP |
3778 | | nsDocShell::AddChildSHEntry(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry, |
3779 | | int32_t aChildOffset, uint32_t aLoadType, |
3780 | | bool aCloneChildren) |
3781 | 0 | { |
3782 | 0 | nsresult rv = NS_OK; |
3783 | 0 |
|
3784 | 0 | if (mLSHE && aLoadType != LOAD_PUSHSTATE) { |
3785 | 0 | /* You get here if you are currently building a |
3786 | 0 | * hierarchy ie.,you just visited a frameset page |
3787 | 0 | */ |
3788 | 0 | if (NS_FAILED(mLSHE->ReplaceChild(aNewEntry))) { |
3789 | 0 | rv = mLSHE->AddChild(aNewEntry, aChildOffset); |
3790 | 0 | } |
3791 | 0 | } else if (!aCloneRef) { |
3792 | 0 | /* This is an initial load in some subframe. Just append it if we can */ |
3793 | 0 | if (mOSHE) { |
3794 | 0 | rv = mOSHE->AddChild(aNewEntry, aChildOffset); |
3795 | 0 | } |
3796 | 0 | } else { |
3797 | 0 | rv = AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset, |
3798 | 0 | aLoadType, aCloneChildren); |
3799 | 0 | } |
3800 | 0 | return rv; |
3801 | 0 | } |
3802 | | |
3803 | | nsresult |
3804 | | nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef, |
3805 | | nsISHEntry* aNewEntry, |
3806 | | int32_t aChildOffset, |
3807 | | uint32_t aLoadType, |
3808 | | bool aCloneChildren) |
3809 | 0 | { |
3810 | 0 | nsresult rv = NS_OK; |
3811 | 0 | if (mSessionHistory) { |
3812 | 0 | /* You are currently in the rootDocShell. |
3813 | 0 | * You will get here when a subframe has a new url |
3814 | 0 | * to load and you have walked up the tree all the |
3815 | 0 | * way to the top to clone the current SHEntry hierarchy |
3816 | 0 | * and replace the subframe where a new url was loaded with |
3817 | 0 | * a new entry. |
3818 | 0 | */ |
3819 | 0 | nsCOMPtr<nsISHEntry> currentHE; |
3820 | 0 | int32_t index = mSessionHistory->Index(); |
3821 | 0 | if (index < 0) { |
3822 | 0 | return NS_ERROR_FAILURE; |
3823 | 0 | } |
3824 | 0 | |
3825 | 0 | rv = mSessionHistory->LegacySHistory()->GetEntryAtIndex( |
3826 | 0 | index, getter_AddRefs(currentHE)); |
3827 | 0 | NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE); |
3828 | 0 |
|
3829 | 0 | nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE)); |
3830 | 0 | if (currentEntry) { |
3831 | 0 | nsCOMPtr<nsISHEntry> nextEntry; |
3832 | 0 | uint32_t cloneID = aCloneRef->GetID(); |
3833 | 0 | rv = nsSHistory::CloneAndReplace(currentEntry, this, cloneID, |
3834 | 0 | aNewEntry, aCloneChildren, getter_AddRefs(nextEntry)); |
3835 | 0 |
|
3836 | 0 | if (NS_SUCCEEDED(rv)) { |
3837 | 0 | rv = mSessionHistory->LegacySHistory()->AddEntry(nextEntry, true); |
3838 | 0 | } |
3839 | 0 | } |
3840 | 0 | } else { |
3841 | 0 | /* Just pass this along */ |
3842 | 0 | nsCOMPtr<nsIDocShell> parent = |
3843 | 0 | do_QueryInterface(GetAsSupports(mParent), &rv); |
3844 | 0 | if (parent) { |
3845 | 0 | rv = static_cast<nsDocShell*>(parent.get())->AddChildSHEntryInternal( |
3846 | 0 | aCloneRef, aNewEntry, aChildOffset, aLoadType, aCloneChildren); |
3847 | 0 | } |
3848 | 0 | } |
3849 | 0 | return rv; |
3850 | 0 | } |
3851 | | |
3852 | | nsresult |
3853 | | nsDocShell::AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset, |
3854 | | bool aCloneChildren) |
3855 | 0 | { |
3856 | 0 | /* You will get here when you are in a subframe and |
3857 | 0 | * a new url has been loaded on you. |
3858 | 0 | * The mOSHE in this subframe will be the previous url's |
3859 | 0 | * mOSHE. This mOSHE will be used as the identification |
3860 | 0 | * for this subframe in the CloneAndReplace function. |
3861 | 0 | */ |
3862 | 0 |
|
3863 | 0 | // In this case, we will end up calling AddEntry, which increases the |
3864 | 0 | // current index by 1 |
3865 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
3866 | 0 | if (rootSH) { |
3867 | 0 | mPreviousEntryIndex = rootSH->Index(); |
3868 | 0 | } |
3869 | 0 |
|
3870 | 0 | nsresult rv; |
3871 | 0 | nsCOMPtr<nsIDocShell> parent = do_QueryInterface(GetAsSupports(mParent), &rv); |
3872 | 0 | if (parent) { |
3873 | 0 | rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType, |
3874 | 0 | aCloneChildren); |
3875 | 0 | } |
3876 | 0 |
|
3877 | 0 | if (rootSH) { |
3878 | 0 | mLoadedEntryIndex = rootSH->Index(); |
3879 | | #ifdef DEBUG_PAGE_CACHE |
3880 | | printf("Previous index: %d, Loaded index: %d\n\n", mPreviousEntryIndex, |
3881 | | mLoadedEntryIndex); |
3882 | | #endif |
3883 | | } |
3884 | 0 |
|
3885 | 0 | return rv; |
3886 | 0 | } |
3887 | | |
3888 | | NS_IMETHODIMP |
3889 | | nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory) |
3890 | 0 | { |
3891 | 0 | mUseGlobalHistory = aUseGlobalHistory; |
3892 | 0 | if (!aUseGlobalHistory) { |
3893 | 0 | return NS_OK; |
3894 | 0 | } |
3895 | 0 | |
3896 | 0 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
3897 | 0 | return history ? NS_OK : NS_ERROR_FAILURE; |
3898 | 0 | } |
3899 | | |
3900 | | NS_IMETHODIMP |
3901 | | nsDocShell::GetUseGlobalHistory(bool* aUseGlobalHistory) |
3902 | 0 | { |
3903 | 0 | *aUseGlobalHistory = mUseGlobalHistory; |
3904 | 0 | return NS_OK; |
3905 | 0 | } |
3906 | | |
3907 | | NS_IMETHODIMP |
3908 | | nsDocShell::RemoveFromSessionHistory() |
3909 | 0 | { |
3910 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
3911 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(root)); |
3912 | 0 | nsCOMPtr<nsIWebNavigation> rootAsWebnav = do_QueryInterface(root); |
3913 | 0 | if (!rootAsWebnav) { |
3914 | 0 | return NS_OK; |
3915 | 0 | } |
3916 | 0 | RefPtr<ChildSHistory> sessionHistory = rootAsWebnav->GetSessionHistory(); |
3917 | 0 | if (!sessionHistory) { |
3918 | 0 | return NS_OK; |
3919 | 0 | } |
3920 | 0 | int32_t index = sessionHistory->Index(); |
3921 | 0 | AutoTArray<nsID, 16> ids({mHistoryID}); |
3922 | 0 | sessionHistory->LegacySHistory()->RemoveEntries(ids, index); |
3923 | 0 | return NS_OK; |
3924 | 0 | } |
3925 | | |
3926 | | NS_IMETHODIMP |
3927 | | nsDocShell::SetCreatedDynamically(bool aDynamic) |
3928 | 0 | { |
3929 | 0 | mDynamicallyCreated = aDynamic; |
3930 | 0 | return NS_OK; |
3931 | 0 | } |
3932 | | |
3933 | | NS_IMETHODIMP |
3934 | | nsDocShell::GetCreatedDynamically(bool* aDynamic) |
3935 | 0 | { |
3936 | 0 | *aDynamic = mDynamicallyCreated; |
3937 | 0 | return NS_OK; |
3938 | 0 | } |
3939 | | |
3940 | | NS_IMETHODIMP |
3941 | | nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE) |
3942 | 0 | { |
3943 | 0 | *aOSHE = false; |
3944 | 0 | *aEntry = nullptr; |
3945 | 0 | if (mLSHE) { |
3946 | 0 | NS_ADDREF(*aEntry = mLSHE); |
3947 | 0 | } else if (mOSHE) { |
3948 | 0 | NS_ADDREF(*aEntry = mOSHE); |
3949 | 0 | *aOSHE = true; |
3950 | 0 | } |
3951 | 0 | return NS_OK; |
3952 | 0 | } |
3953 | | |
3954 | | nsIScriptGlobalObject* |
3955 | | nsDocShell::GetScriptGlobalObject() |
3956 | 0 | { |
3957 | 0 | NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr); |
3958 | 0 | return mScriptGlobal; |
3959 | 0 | } |
3960 | | |
3961 | | nsIDocument* |
3962 | | nsDocShell::GetDocument() |
3963 | 0 | { |
3964 | 0 | NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr); |
3965 | 0 | return mContentViewer->GetDocument(); |
3966 | 0 | } |
3967 | | |
3968 | | nsPIDOMWindowOuter* |
3969 | | nsDocShell::GetWindow() |
3970 | 0 | { |
3971 | 0 | if (NS_FAILED(EnsureScriptEnvironment())) { |
3972 | 0 | return nullptr; |
3973 | 0 | } |
3974 | 0 | return mScriptGlobal->AsOuter(); |
3975 | 0 | } |
3976 | | |
3977 | | NS_IMETHODIMP |
3978 | | nsDocShell::GetDomWindow(mozIDOMWindowProxy** aWindow) |
3979 | 0 | { |
3980 | 0 | NS_ENSURE_ARG_POINTER(aWindow); |
3981 | 0 |
|
3982 | 0 | nsresult rv = EnsureScriptEnvironment(); |
3983 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
3984 | 0 |
|
3985 | 0 | nsCOMPtr<nsPIDOMWindowOuter> window = mScriptGlobal->AsOuter(); |
3986 | 0 | window.forget(aWindow); |
3987 | 0 | return NS_OK; |
3988 | 0 | } |
3989 | | |
3990 | | NS_IMETHODIMP |
3991 | | nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) |
3992 | 0 | { |
3993 | 0 | RefPtr<ContentFrameMessageManager> mm; |
3994 | 0 | if (RefPtr<TabChild> tabChild = TabChild::GetFrom(this)) { |
3995 | 0 | mm = tabChild->GetMessageManager(); |
3996 | 0 | } else if (nsPIDOMWindowOuter* win = GetWindow()) { |
3997 | 0 | mm = win->GetMessageManager(); |
3998 | 0 | } |
3999 | 0 | mm.forget(aMessageManager); |
4000 | 0 | return NS_OK; |
4001 | 0 | } |
4002 | | |
4003 | | NS_IMETHODIMP |
4004 | | nsDocShell::SetDeviceSizeIsPageSize(bool aValue) |
4005 | 0 | { |
4006 | 0 | if (mDeviceSizeIsPageSize != aValue) { |
4007 | 0 | mDeviceSizeIsPageSize = aValue; |
4008 | 0 | RefPtr<nsPresContext> presContext; |
4009 | 0 | GetPresContext(getter_AddRefs(presContext)); |
4010 | 0 | if (presContext) { |
4011 | 0 | presContext->MediaFeatureValuesChanged({ |
4012 | 0 | MediaFeatureChangeReason::DeviceSizeIsPageSizeChange }); |
4013 | 0 | } |
4014 | 0 | } |
4015 | 0 | return NS_OK; |
4016 | 0 | } |
4017 | | |
4018 | | NS_IMETHODIMP |
4019 | | nsDocShell::GetDeviceSizeIsPageSize(bool* aValue) |
4020 | 0 | { |
4021 | 0 | *aValue = mDeviceSizeIsPageSize; |
4022 | 0 | return NS_OK; |
4023 | 0 | } |
4024 | | |
4025 | | void |
4026 | | nsDocShell::ClearFrameHistory(nsISHEntry* aEntry) |
4027 | 0 | { |
4028 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4029 | 0 | if (!rootSH || !aEntry) { |
4030 | 0 | return; |
4031 | 0 | } |
4032 | 0 | |
4033 | 0 | int32_t count = aEntry->GetChildCount(); |
4034 | 0 | AutoTArray<nsID, 16> ids; |
4035 | 0 | for (int32_t i = 0; i < count; ++i) { |
4036 | 0 | nsCOMPtr<nsISHEntry> child; |
4037 | 0 | aEntry->GetChildAt(i, getter_AddRefs(child)); |
4038 | 0 | if (child) { |
4039 | 0 | ids.AppendElement(child->DocshellID()); |
4040 | 0 | } |
4041 | 0 | } |
4042 | 0 | int32_t index = rootSH->Index(); |
4043 | 0 | rootSH->LegacySHistory()->RemoveEntries(ids, index); |
4044 | 0 | } |
4045 | | |
4046 | | //------------------------------------- |
4047 | | //-- Helper Method for Print discovery |
4048 | | //------------------------------------- |
4049 | | bool |
4050 | | nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog) |
4051 | 0 | { |
4052 | 0 | if (mIsPrintingOrPP && aDisplayErrorDialog) { |
4053 | 0 | DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr); |
4054 | 0 | } |
4055 | 0 |
|
4056 | 0 | return mIsPrintingOrPP; |
4057 | 0 | } |
4058 | | |
4059 | | bool |
4060 | | nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog, |
4061 | | bool aCheckIfUnloadFired) |
4062 | 0 | { |
4063 | 0 | bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) && |
4064 | 0 | (!aCheckIfUnloadFired || !mFiredUnloadEvent); |
4065 | 0 | if (!isAllowed) { |
4066 | 0 | return false; |
4067 | 0 | } |
4068 | 0 | if (!mContentViewer) { |
4069 | 0 | return true; |
4070 | 0 | } |
4071 | 0 | bool firingBeforeUnload; |
4072 | 0 | mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload); |
4073 | 0 | return !firingBeforeUnload; |
4074 | 0 | } |
4075 | | |
4076 | | //***************************************************************************** |
4077 | | // nsDocShell::nsIWebNavigation |
4078 | | //***************************************************************************** |
4079 | | |
4080 | | NS_IMETHODIMP |
4081 | | nsDocShell::GetCanGoBack(bool* aCanGoBack) |
4082 | 0 | { |
4083 | 0 | *aCanGoBack = false; |
4084 | 0 | if (!IsNavigationAllowed(false)) { |
4085 | 0 | return NS_OK; // JS may not handle returning of an error code |
4086 | 0 | } |
4087 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4088 | 0 | if (rootSH) { |
4089 | 0 | *aCanGoBack = rootSH->CanGo(-1); |
4090 | 0 | return NS_OK; |
4091 | 0 | } |
4092 | 0 | return NS_ERROR_FAILURE; |
4093 | 0 | } |
4094 | | |
4095 | | NS_IMETHODIMP |
4096 | | nsDocShell::GetCanGoForward(bool* aCanGoForward) |
4097 | 0 | { |
4098 | 0 | *aCanGoForward = false; |
4099 | 0 | if (!IsNavigationAllowed(false)) { |
4100 | 0 | return NS_OK; // JS may not handle returning of an error code |
4101 | 0 | } |
4102 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4103 | 0 | if (rootSH) { |
4104 | 0 | *aCanGoForward = rootSH->CanGo(1); |
4105 | 0 | return NS_OK; |
4106 | 0 | } |
4107 | 0 | return NS_ERROR_FAILURE; |
4108 | 0 | } |
4109 | | |
4110 | | NS_IMETHODIMP |
4111 | | nsDocShell::GoBack() |
4112 | 0 | { |
4113 | 0 | if (!IsNavigationAllowed()) { |
4114 | 0 | return NS_OK; // JS may not handle returning of an error code |
4115 | 0 | } |
4116 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4117 | 0 | NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); |
4118 | 0 | ErrorResult rv; |
4119 | 0 | rootSH->Go(-1, rv); |
4120 | 0 | return rv.StealNSResult(); |
4121 | 0 | } |
4122 | | |
4123 | | NS_IMETHODIMP |
4124 | | nsDocShell::GoForward() |
4125 | 0 | { |
4126 | 0 | if (!IsNavigationAllowed()) { |
4127 | 0 | return NS_OK; // JS may not handle returning of an error code |
4128 | 0 | } |
4129 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4130 | 0 | NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); |
4131 | 0 | ErrorResult rv; |
4132 | 0 | rootSH->Go(1, rv); |
4133 | 0 | return rv.StealNSResult(); |
4134 | 0 | } |
4135 | | |
4136 | | // XXX(nika): We may want to stop exposing this API in the child process? Going |
4137 | | // to a specific index from multiple different processes could definitely race. |
4138 | | NS_IMETHODIMP |
4139 | | nsDocShell::GotoIndex(int32_t aIndex) |
4140 | 0 | { |
4141 | 0 | if (!IsNavigationAllowed()) { |
4142 | 0 | return NS_OK; // JS may not handle returning of an error code |
4143 | 0 | } |
4144 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4145 | 0 | NS_ENSURE_TRUE(rootSH, NS_ERROR_FAILURE); |
4146 | 0 | return rootSH->LegacySHistory()->GotoIndex(aIndex); |
4147 | 0 | } |
4148 | | |
4149 | | NS_IMETHODIMP |
4150 | | nsDocShell::LoadURI(const nsAString& aURI, |
4151 | | uint32_t aLoadFlags, |
4152 | | nsIURI* aReferringURI, |
4153 | | nsIInputStream* aPostStream, |
4154 | | nsIInputStream* aHeaderStream, |
4155 | | nsIPrincipal* aTriggeringPrincipal) |
4156 | 0 | { |
4157 | 0 | return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI, |
4158 | 0 | RP_Unset, aPostStream, |
4159 | 0 | aHeaderStream, nullptr, aTriggeringPrincipal); |
4160 | 0 | } |
4161 | | |
4162 | | NS_IMETHODIMP |
4163 | | nsDocShell::LoadURIWithOptions(const nsAString& aURI, |
4164 | | uint32_t aLoadFlags, |
4165 | | nsIURI* aReferringURI, |
4166 | | uint32_t aReferrerPolicy, |
4167 | | nsIInputStream* aPostStream, |
4168 | | nsIInputStream* aHeaderStream, |
4169 | | nsIURI* aBaseURI, |
4170 | | nsIPrincipal* aTriggeringPrincipal) |
4171 | 0 | { |
4172 | 0 | NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags"); |
4173 | 0 |
|
4174 | 0 | if (!IsNavigationAllowed()) { |
4175 | 0 | return NS_OK; // JS may not handle returning of an error code |
4176 | 0 | } |
4177 | 0 | nsCOMPtr<nsIURI> uri; |
4178 | 0 | nsCOMPtr<nsIInputStream> postStream(aPostStream); |
4179 | 0 | nsresult rv = NS_OK; |
4180 | 0 |
|
4181 | 0 | // Create a URI from our string; if that succeeds, we want to |
4182 | 0 | // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP |
4183 | 0 | // flag. |
4184 | 0 |
|
4185 | 0 | NS_ConvertUTF16toUTF8 uriString(aURI); |
4186 | 0 | // Cleanup the empty spaces that might be on each end. |
4187 | 0 | uriString.Trim(" "); |
4188 | 0 | // Eliminate embedded newlines, which single-line text fields now allow: |
4189 | 0 | uriString.StripCRLF(); |
4190 | 0 | NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE); |
4191 | 0 |
|
4192 | 0 | rv = NS_NewURI(getter_AddRefs(uri), uriString); |
4193 | 0 | if (uri) { |
4194 | 0 | aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; |
4195 | 0 | } |
4196 | 0 |
|
4197 | 0 | nsCOMPtr<nsIURIFixupInfo> fixupInfo; |
4198 | 0 | if (sURIFixup) { |
4199 | 0 | // Call the fixup object. This will clobber the rv from NS_NewURI |
4200 | 0 | // above, but that's fine with us. Note that we need to do this even |
4201 | 0 | // if NS_NewURI returned a URI, because fixup handles nested URIs, etc |
4202 | 0 | // (things like view-source:mozilla.org for example). |
4203 | 0 | uint32_t fixupFlags = 0; |
4204 | 0 | if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { |
4205 | 0 | fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; |
4206 | 0 | } |
4207 | 0 | if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) { |
4208 | 0 | fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS; |
4209 | 0 | } |
4210 | 0 | nsCOMPtr<nsIInputStream> fixupStream; |
4211 | 0 | rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags, |
4212 | 0 | getter_AddRefs(fixupStream), |
4213 | 0 | getter_AddRefs(fixupInfo)); |
4214 | 0 |
|
4215 | 0 | if (NS_SUCCEEDED(rv)) { |
4216 | 0 | fixupInfo->GetPreferredURI(getter_AddRefs(uri)); |
4217 | 0 | fixupInfo->SetConsumer(GetAsSupports(this)); |
4218 | 0 | } |
4219 | 0 |
|
4220 | 0 | if (fixupStream) { |
4221 | 0 | // GetFixupURIInfo only returns a post data stream if it succeeded |
4222 | 0 | // and changed the URI, in which case we should override the |
4223 | 0 | // passed-in post data. |
4224 | 0 | postStream = fixupStream; |
4225 | 0 | } |
4226 | 0 |
|
4227 | 0 | if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { |
4228 | 0 | nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); |
4229 | 0 | if (serv) { |
4230 | 0 | serv->NotifyObservers(fixupInfo, "keyword-uri-fixup", |
4231 | 0 | PromiseFlatString(aURI).get()); |
4232 | 0 | } |
4233 | 0 | } |
4234 | 0 | } |
4235 | 0 | // else no fixup service so just use the URI we created and see |
4236 | 0 | // what happens |
4237 | 0 |
|
4238 | 0 | if (NS_ERROR_MALFORMED_URI == rv) { |
4239 | 0 | if (DisplayLoadError(rv, uri, PromiseFlatString(aURI).get(), nullptr) && |
4240 | 0 | (aLoadFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) { |
4241 | 0 | return NS_ERROR_LOAD_SHOWED_ERRORPAGE; |
4242 | 0 | } |
4243 | 0 | } |
4244 | 0 | |
4245 | 0 | if (NS_FAILED(rv) || !uri) { |
4246 | 0 | return NS_ERROR_FAILURE; |
4247 | 0 | } |
4248 | 0 | |
4249 | 0 | PopupControlState popupState; |
4250 | 0 | if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) { |
4251 | 0 | popupState = openAllowed; |
4252 | 0 | aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS; |
4253 | 0 | } else { |
4254 | 0 | popupState = openOverridden; |
4255 | 0 | } |
4256 | 0 | nsAutoPopupStatePusher statePusher(popupState); |
4257 | 0 |
|
4258 | 0 | bool forceAllowDataURI = |
4259 | 0 | aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI; |
4260 | 0 |
|
4261 | 0 | // Don't pass certain flags that aren't needed and end up confusing |
4262 | 0 | // ConvertLoadTypeToDocShellInfoLoadType. We do need to ensure that they are |
4263 | 0 | // passed to LoadURI though, since it uses them. |
4264 | 0 | uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS); |
4265 | 0 | aLoadFlags &= ~EXTRA_LOAD_FLAGS; |
4266 | 0 |
|
4267 | 0 | RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo(); |
4268 | 0 |
|
4269 | 0 | /* |
4270 | 0 | * If the user "Disables Protection on This Page", we have to make sure to |
4271 | 0 | * remember the users decision when opening links in child tabs [Bug 906190] |
4272 | 0 | */ |
4273 | 0 | uint32_t loadType; |
4274 | 0 | if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) { |
4275 | 0 | loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags); |
4276 | 0 | } else { |
4277 | 0 | loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); |
4278 | 0 | } |
4279 | 0 |
|
4280 | 0 | loadInfo->SetLoadType(loadType); |
4281 | 0 | loadInfo->SetPostDataStream(postStream); |
4282 | 0 | loadInfo->SetReferrer(aReferringURI); |
4283 | 0 | loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy); |
4284 | 0 | loadInfo->SetHeadersStream(aHeaderStream); |
4285 | 0 | loadInfo->SetBaseURI(aBaseURI); |
4286 | 0 | loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal); |
4287 | 0 | loadInfo->SetForceAllowDataURI(forceAllowDataURI); |
4288 | 0 |
|
4289 | 0 | if (fixupInfo) { |
4290 | 0 | nsAutoString searchProvider, keyword; |
4291 | 0 | fixupInfo->GetKeywordProviderName(searchProvider); |
4292 | 0 | fixupInfo->GetKeywordAsSent(keyword); |
4293 | 0 | MaybeNotifyKeywordSearchLoading(searchProvider, keyword); |
4294 | 0 | } |
4295 | 0 |
|
4296 | 0 | rv = LoadURI(uri, loadInfo, extraFlags, true); |
4297 | 0 |
|
4298 | 0 | // Save URI string in case it's needed later when |
4299 | 0 | // sending to search engine service in EndPageLoad() |
4300 | 0 | mOriginalUriString = uriString; |
4301 | 0 |
|
4302 | 0 | return rv; |
4303 | 0 | } |
4304 | | |
4305 | | NS_IMETHODIMP |
4306 | | nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, |
4307 | | const char16_t* aURL, |
4308 | | nsIChannel* aFailedChannel, |
4309 | | bool* aDisplayedErrorPage) |
4310 | 0 | { |
4311 | 0 | *aDisplayedErrorPage = false; |
4312 | 0 | // Get prompt and string bundle services |
4313 | 0 | nsCOMPtr<nsIPrompt> prompter; |
4314 | 0 | nsCOMPtr<nsIStringBundle> stringBundle; |
4315 | 0 | GetPromptAndStringBundle(getter_AddRefs(prompter), |
4316 | 0 | getter_AddRefs(stringBundle)); |
4317 | 0 |
|
4318 | 0 | NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE); |
4319 | 0 | NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE); |
4320 | 0 |
|
4321 | 0 | const char* error = nullptr; |
4322 | 0 | // The key used to select the appropriate error message from the properties file. |
4323 | 0 | const char* errorDescriptionID = nullptr; |
4324 | 0 | const uint32_t kMaxFormatStrArgs = 3; |
4325 | 0 | nsAutoString formatStrs[kMaxFormatStrArgs]; |
4326 | 0 | uint32_t formatStrCount = 0; |
4327 | 0 | bool addHostPort = false; |
4328 | 0 | nsresult rv = NS_OK; |
4329 | 0 | nsAutoString messageStr; |
4330 | 0 | nsAutoCString cssClass; |
4331 | 0 | nsAutoCString errorPage; |
4332 | 0 |
|
4333 | 0 | if (mLoadURIDelegate) { |
4334 | 0 | nsCOMPtr<nsIURI> errorPageURI; |
4335 | 0 | rv = mLoadURIDelegate->HandleLoadError(aURI, aError, |
4336 | 0 | NS_ERROR_GET_MODULE(aError), |
4337 | 0 | getter_AddRefs(errorPageURI)); |
4338 | 0 | if (NS_FAILED(rv)) { |
4339 | 0 | *aDisplayedErrorPage = false; |
4340 | 0 | return NS_OK; |
4341 | 0 | } |
4342 | 0 | |
4343 | 0 | if (errorPageURI) { |
4344 | 0 | *aDisplayedErrorPage = NS_SUCCEEDED(LoadErrorPage(errorPageURI, aURI, aFailedChannel)); |
4345 | 0 | return NS_OK; |
4346 | 0 | } |
4347 | 0 | } |
4348 | 0 |
|
4349 | 0 | errorPage.AssignLiteral("neterror"); |
4350 | 0 |
|
4351 | 0 | // Turn the error code into a human readable error message. |
4352 | 0 | if (NS_ERROR_UNKNOWN_PROTOCOL == aError) { |
4353 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4354 | 0 |
|
4355 | 0 | // Extract the schemes into a comma delimited list. |
4356 | 0 | nsAutoCString scheme; |
4357 | 0 | aURI->GetScheme(scheme); |
4358 | 0 | CopyASCIItoUTF16(scheme, formatStrs[0]); |
4359 | 0 | nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI); |
4360 | 0 | while (nestedURI) { |
4361 | 0 | nsCOMPtr<nsIURI> tempURI; |
4362 | 0 | nsresult rv2; |
4363 | 0 | rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI)); |
4364 | 0 | if (NS_SUCCEEDED(rv2) && tempURI) { |
4365 | 0 | tempURI->GetScheme(scheme); |
4366 | 0 | formatStrs[0].AppendLiteral(", "); |
4367 | 0 | AppendASCIItoUTF16(scheme, formatStrs[0]); |
4368 | 0 | } |
4369 | 0 | nestedURI = do_QueryInterface(tempURI); |
4370 | 0 | } |
4371 | 0 | formatStrCount = 1; |
4372 | 0 | error = "unknownProtocolFound"; |
4373 | 0 | } else if (NS_ERROR_FILE_NOT_FOUND == aError) { |
4374 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4375 | 0 | error = "fileNotFound"; |
4376 | 0 | } else if (NS_ERROR_FILE_ACCESS_DENIED == aError) { |
4377 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4378 | 0 | error = "fileAccessDenied"; |
4379 | 0 | } else if (NS_ERROR_UNKNOWN_HOST == aError) { |
4380 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4381 | 0 | // Get the host |
4382 | 0 | nsAutoCString host; |
4383 | 0 | nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI); |
4384 | 0 | innermostURI->GetHost(host); |
4385 | 0 | CopyUTF8toUTF16(host, formatStrs[0]); |
4386 | 0 | formatStrCount = 1; |
4387 | 0 | errorDescriptionID = "dnsNotFound2"; |
4388 | 0 | error = "dnsNotFound"; |
4389 | 0 | } else if (NS_ERROR_CONNECTION_REFUSED == aError) { |
4390 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4391 | 0 | addHostPort = true; |
4392 | 0 | error = "connectionFailure"; |
4393 | 0 | } else if (NS_ERROR_NET_INTERRUPT == aError) { |
4394 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4395 | 0 | addHostPort = true; |
4396 | 0 | error = "netInterrupt"; |
4397 | 0 | } else if (NS_ERROR_NET_TIMEOUT == aError) { |
4398 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
4399 | 0 | // Get the host |
4400 | 0 | nsAutoCString host; |
4401 | 0 | aURI->GetHost(host); |
4402 | 0 | CopyUTF8toUTF16(host, formatStrs[0]); |
4403 | 0 | formatStrCount = 1; |
4404 | 0 | error = "netTimeout"; |
4405 | 0 | } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError || |
4406 | 0 | NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) { |
4407 | 0 | // CSP error |
4408 | 0 | cssClass.AssignLiteral("neterror"); |
4409 | 0 | error = "cspBlocked"; |
4410 | 0 | } else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) { |
4411 | 0 | nsCOMPtr<nsINSSErrorsService> nsserr = |
4412 | 0 | do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID); |
4413 | 0 |
|
4414 | 0 | uint32_t errorClass; |
4415 | 0 | if (!nsserr || NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) { |
4416 | 0 | errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL; |
4417 | 0 | } |
4418 | 0 |
|
4419 | 0 | nsCOMPtr<nsISupports> securityInfo; |
4420 | 0 | nsCOMPtr<nsITransportSecurityInfo> tsi; |
4421 | 0 | if (aFailedChannel) { |
4422 | 0 | aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo)); |
4423 | 0 | } |
4424 | 0 | tsi = do_QueryInterface(securityInfo); |
4425 | 0 | if (tsi) { |
4426 | 0 | uint32_t securityState; |
4427 | 0 | tsi->GetSecurityState(&securityState); |
4428 | 0 | if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) { |
4429 | 0 | error = "sslv3Used"; |
4430 | 0 | addHostPort = true; |
4431 | 0 | } else if (securityState & nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) { |
4432 | 0 | error = "weakCryptoUsed"; |
4433 | 0 | addHostPort = true; |
4434 | 0 | } |
4435 | 0 | } else { |
4436 | 0 | // No channel, let's obtain the generic error message |
4437 | 0 | if (nsserr) { |
4438 | 0 | nsserr->GetErrorMessage(aError, messageStr); |
4439 | 0 | } |
4440 | 0 | } |
4441 | 0 | // We don't have a message string here anymore but DisplayLoadError |
4442 | 0 | // requires a non-empty messageStr. |
4443 | 0 | messageStr.Truncate(); |
4444 | 0 | messageStr.AssignLiteral(u" "); |
4445 | 0 | if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) { |
4446 | 0 | error = "nssBadCert"; |
4447 | 0 |
|
4448 | 0 | // If this is an HTTP Strict Transport Security host or a pinned host |
4449 | 0 | // and the certificate is bad, don't allow overrides (RFC 6797 section |
4450 | 0 | // 12.1, HPKP draft spec section 2.6). |
4451 | 0 | uint32_t flags = |
4452 | 0 | UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0; |
4453 | 0 | bool isStsHost = false; |
4454 | 0 | bool isPinnedHost = false; |
4455 | 0 | if (XRE_IsParentProcess()) { |
4456 | 0 | nsCOMPtr<nsISiteSecurityService> sss = |
4457 | 0 | do_GetService(NS_SSSERVICE_CONTRACTID, &rv); |
4458 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4459 | 0 | rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, |
4460 | 0 | flags, mOriginAttributes, nullptr, nullptr, |
4461 | 0 | &isStsHost); |
4462 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4463 | 0 | rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI, |
4464 | 0 | flags, mOriginAttributes, nullptr, nullptr, |
4465 | 0 | &isPinnedHost); |
4466 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4467 | 0 | } else { |
4468 | 0 | mozilla::dom::ContentChild* cc = |
4469 | 0 | mozilla::dom::ContentChild::GetSingleton(); |
4470 | 0 | mozilla::ipc::URIParams uri; |
4471 | 0 | SerializeURI(aURI, uri); |
4472 | 0 | cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags, |
4473 | 0 | mOriginAttributes, &isStsHost); |
4474 | 0 | cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags, |
4475 | 0 | mOriginAttributes, &isPinnedHost); |
4476 | 0 | } |
4477 | 0 |
|
4478 | 0 | if (Preferences::GetBool( |
4479 | 0 | "browser.xul.error_pages.expert_bad_cert", false)) { |
4480 | 0 | cssClass.AssignLiteral("expertBadCert"); |
4481 | 0 | } |
4482 | 0 |
|
4483 | 0 | // HSTS/pinning takes precedence over the expert bad cert pref. We |
4484 | 0 | // never want to show the "Add Exception" button for these sites. |
4485 | 0 | // In the future we should differentiate between an HSTS host and a |
4486 | 0 | // pinned host and display a more informative message to the user. |
4487 | 0 | if (isStsHost || isPinnedHost) { |
4488 | 0 | cssClass.AssignLiteral("badStsCert"); |
4489 | 0 | } |
4490 | 0 |
|
4491 | 0 | uint32_t bucketId; |
4492 | 0 | if (isStsHost) { |
4493 | 0 | // measuring STS separately allows us to measure click through |
4494 | 0 | // rates easily |
4495 | 0 | bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS; |
4496 | 0 | } else { |
4497 | 0 | bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP; |
4498 | 0 | } |
4499 | 0 |
|
4500 | 0 | // See if an alternate cert error page is registered |
4501 | 0 | nsAutoCString alternateErrorPage; |
4502 | 0 | nsresult rv = |
4503 | 0 | Preferences::GetCString("security.alternate_certificate_error_page", |
4504 | 0 | alternateErrorPage); |
4505 | 0 | if (NS_SUCCEEDED(rv)) { |
4506 | 0 | errorPage.Assign(alternateErrorPage); |
4507 | 0 | } |
4508 | 0 |
|
4509 | 0 | if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) { |
4510 | 0 | Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId); |
4511 | 0 | } |
4512 | 0 | } else { |
4513 | 0 | error = "nssFailure2"; |
4514 | 0 | } |
4515 | 0 | } else if (NS_ERROR_PHISHING_URI == aError || |
4516 | 0 | NS_ERROR_MALWARE_URI == aError || |
4517 | 0 | NS_ERROR_UNWANTED_URI == aError || |
4518 | 0 | NS_ERROR_HARMFUL_URI == aError) { |
4519 | 0 | nsAutoCString host; |
4520 | 0 | aURI->GetHost(host); |
4521 | 0 | CopyUTF8toUTF16(host, formatStrs[0]); |
4522 | 0 | formatStrCount = 1; |
4523 | 0 |
|
4524 | 0 | // Malware and phishing detectors may want to use an alternate error |
4525 | 0 | // page, but if the pref's not set, we'll fall back on the standard page |
4526 | 0 | nsAutoCString alternateErrorPage; |
4527 | 0 | nsresult rv = Preferences::GetCString("urlclassifier.alternate_error_page", |
4528 | 0 | alternateErrorPage); |
4529 | 0 | if (NS_SUCCEEDED(rv)) { |
4530 | 0 | errorPage.Assign(alternateErrorPage); |
4531 | 0 | } |
4532 | 0 |
|
4533 | 0 | uint32_t bucketId; |
4534 | 0 | bool sendTelemetry = false; |
4535 | 0 | if (NS_ERROR_PHISHING_URI == aError) { |
4536 | 0 | sendTelemetry = true; |
4537 | 0 | error = "deceptiveBlocked"; |
4538 | 0 | bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_FRAME |
4539 | 0 | : IUrlClassifierUITelemetry::WARNING_PHISHING_PAGE_TOP; |
4540 | 0 | } else if (NS_ERROR_MALWARE_URI == aError) { |
4541 | 0 | sendTelemetry = true; |
4542 | 0 | error = "malwareBlocked"; |
4543 | 0 | bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_FRAME |
4544 | 0 | : IUrlClassifierUITelemetry::WARNING_MALWARE_PAGE_TOP; |
4545 | 0 | } else if (NS_ERROR_UNWANTED_URI == aError) { |
4546 | 0 | sendTelemetry = true; |
4547 | 0 | error = "unwantedBlocked"; |
4548 | 0 | bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_FRAME |
4549 | 0 | : IUrlClassifierUITelemetry::WARNING_UNWANTED_PAGE_TOP; |
4550 | 0 | } else if (NS_ERROR_HARMFUL_URI == aError) { |
4551 | 0 | sendTelemetry = true; |
4552 | 0 | error = "harmfulBlocked"; |
4553 | 0 | bucketId = IsFrame() ? IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_FRAME |
4554 | 0 | : IUrlClassifierUITelemetry::WARNING_HARMFUL_PAGE_TOP; |
4555 | 0 | } |
4556 | 0 |
|
4557 | 0 | if (sendTelemetry && errorPage.EqualsIgnoreCase("blocked")) { |
4558 | 0 | Telemetry::Accumulate(Telemetry::URLCLASSIFIER_UI_EVENTS, bucketId); |
4559 | 0 | } |
4560 | 0 |
|
4561 | 0 | cssClass.AssignLiteral("blacklist"); |
4562 | 0 | } else if (NS_ERROR_CONTENT_CRASHED == aError) { |
4563 | 0 | errorPage.AssignLiteral("tabcrashed"); |
4564 | 0 | error = "tabcrashed"; |
4565 | 0 |
|
4566 | 0 | nsCOMPtr<EventTarget> handler = mChromeEventHandler; |
4567 | 0 | if (handler) { |
4568 | 0 | nsCOMPtr<Element> element = do_QueryInterface(handler); |
4569 | 0 | element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr); |
4570 | 0 | } |
4571 | 0 |
|
4572 | 0 | // DisplayLoadError requires a non-empty messageStr to proceed and call |
4573 | 0 | // LoadErrorPage. If the page doesn't have a title, we will use a blank |
4574 | 0 | // space which will be trimmed and thus treated as empty by the front-end. |
4575 | 0 | if (messageStr.IsEmpty()) { |
4576 | 0 | messageStr.AssignLiteral(u" "); |
4577 | 0 | } |
4578 | 0 | } else if (NS_ERROR_BUILDID_MISMATCH == aError) { |
4579 | 0 | errorPage.AssignLiteral("restartrequired"); |
4580 | 0 | error = "restartrequired"; |
4581 | 0 |
|
4582 | 0 | // DisplayLoadError requires a non-empty messageStr to proceed and call |
4583 | 0 | // LoadErrorPage. If the page doesn't have a title, we will use a blank |
4584 | 0 | // space which will be trimmed and thus treated as empty by the front-end. |
4585 | 0 | if (messageStr.IsEmpty()) { |
4586 | 0 | messageStr.AssignLiteral(u" "); |
4587 | 0 | } |
4588 | 0 | } else { |
4589 | 0 | // Errors requiring simple formatting |
4590 | 0 | switch (aError) { |
4591 | 0 | case NS_ERROR_MALFORMED_URI: |
4592 | 0 | // URI is malformed |
4593 | 0 | error = "malformedURI"; |
4594 | 0 | errorDescriptionID = "malformedURI2"; |
4595 | 0 | break; |
4596 | 0 | case NS_ERROR_REDIRECT_LOOP: |
4597 | 0 | // Doc failed to load because the server generated too many redirects |
4598 | 0 | error = "redirectLoop"; |
4599 | 0 | break; |
4600 | 0 | case NS_ERROR_UNKNOWN_SOCKET_TYPE: |
4601 | 0 | // Doc failed to load because PSM is not installed |
4602 | 0 | error = "unknownSocketType"; |
4603 | 0 | break; |
4604 | 0 | case NS_ERROR_NET_RESET: |
4605 | 0 | // Doc failed to load because the server kept reseting the connection |
4606 | 0 | // before we could read any data from it |
4607 | 0 | error = "netReset"; |
4608 | 0 | break; |
4609 | 0 | case NS_ERROR_DOCUMENT_NOT_CACHED: |
4610 | 0 | // Doc failed to load because the cache does not contain a copy of |
4611 | 0 | // the document. |
4612 | 0 | error = "notCached"; |
4613 | 0 | break; |
4614 | 0 | case NS_ERROR_OFFLINE: |
4615 | 0 | // Doc failed to load because we are offline. |
4616 | 0 | error = "netOffline"; |
4617 | 0 | break; |
4618 | 0 | case NS_ERROR_DOCUMENT_IS_PRINTMODE: |
4619 | 0 | // Doc navigation attempted while Printing or Print Preview |
4620 | 0 | error = "isprinting"; |
4621 | 0 | break; |
4622 | 0 | case NS_ERROR_PORT_ACCESS_NOT_ALLOWED: |
4623 | 0 | // Port blocked for security reasons |
4624 | 0 | addHostPort = true; |
4625 | 0 | error = "deniedPortAccess"; |
4626 | 0 | break; |
4627 | 0 | case NS_ERROR_UNKNOWN_PROXY_HOST: |
4628 | 0 | // Proxy hostname could not be resolved. |
4629 | 0 | error = "proxyResolveFailure"; |
4630 | 0 | break; |
4631 | 0 | case NS_ERROR_PROXY_CONNECTION_REFUSED: |
4632 | 0 | // Proxy connection was refused. |
4633 | 0 | error = "proxyConnectFailure"; |
4634 | 0 | break; |
4635 | 0 | case NS_ERROR_INVALID_CONTENT_ENCODING: |
4636 | 0 | // Bad Content Encoding. |
4637 | 0 | error = "contentEncodingError"; |
4638 | 0 | break; |
4639 | 0 | case NS_ERROR_REMOTE_XUL: |
4640 | 0 | error = "remoteXUL"; |
4641 | 0 | break; |
4642 | 0 | case NS_ERROR_UNSAFE_CONTENT_TYPE: |
4643 | 0 | // Channel refused to load from an unrecognized content type. |
4644 | 0 | error = "unsafeContentType"; |
4645 | 0 | break; |
4646 | 0 | case NS_ERROR_CORRUPTED_CONTENT: |
4647 | 0 | // Broken Content Detected. e.g. Content-MD5 check failure. |
4648 | 0 | error = "corruptedContentErrorv2"; |
4649 | 0 | break; |
4650 | 0 | case NS_ERROR_INTERCEPTION_FAILED: |
4651 | 0 | // ServiceWorker intercepted request, but something went wrong. |
4652 | 0 | error = "corruptedContentErrorv2"; |
4653 | 0 | break; |
4654 | 0 | case NS_ERROR_NET_INADEQUATE_SECURITY: |
4655 | 0 | // Server negotiated bad TLS for HTTP/2. |
4656 | 0 | error = "inadequateSecurityError"; |
4657 | 0 | addHostPort = true; |
4658 | 0 | break; |
4659 | 0 | case NS_ERROR_BLOCKED_BY_POLICY: |
4660 | 0 | // Page blocked by policy |
4661 | 0 | error = "blockedByPolicy"; |
4662 | 0 | break; |
4663 | 0 | default: |
4664 | 0 | break; |
4665 | 0 | } |
4666 | 0 | } |
4667 | 0 | |
4668 | 0 | // Test if the error should be displayed |
4669 | 0 | if (!error) { |
4670 | 0 | return NS_OK; |
4671 | 0 | } |
4672 | 0 | |
4673 | 0 | if (!errorDescriptionID) { |
4674 | 0 | errorDescriptionID = error; |
4675 | 0 | } |
4676 | 0 |
|
4677 | 0 | // Test if the error needs to be formatted |
4678 | 0 | if (!messageStr.IsEmpty()) { |
4679 | 0 | // already obtained message |
4680 | 0 | } else { |
4681 | 0 | if (addHostPort) { |
4682 | 0 | // Build up the host:port string. |
4683 | 0 | nsAutoCString hostport; |
4684 | 0 | if (aURI) { |
4685 | 0 | aURI->GetHostPort(hostport); |
4686 | 0 | } else { |
4687 | 0 | hostport.Assign('?'); |
4688 | 0 | } |
4689 | 0 | CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]); |
4690 | 0 | } |
4691 | 0 |
|
4692 | 0 | nsAutoCString spec; |
4693 | 0 | rv = NS_ERROR_NOT_AVAILABLE; |
4694 | 0 | if (aURI) { |
4695 | 0 | // displaying "file://" is aesthetically unpleasing and could even be |
4696 | 0 | // confusing to the user |
4697 | 0 | bool isFileURI = false; |
4698 | 0 | rv = aURI->SchemeIs("file", &isFileURI); |
4699 | 0 | if (NS_SUCCEEDED(rv) && isFileURI) { |
4700 | 0 | aURI->GetPathQueryRef(spec); |
4701 | 0 | } else { |
4702 | 0 | aURI->GetSpec(spec); |
4703 | 0 | } |
4704 | 0 |
|
4705 | 0 | nsCOMPtr<nsITextToSubURI> textToSubURI( |
4706 | 0 | do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv)); |
4707 | 0 | if (NS_SUCCEEDED(rv)) { |
4708 | 0 | rv = textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), spec, |
4709 | 0 | formatStrs[formatStrCount]); |
4710 | 0 | } |
4711 | 0 | } else { |
4712 | 0 | spec.Assign('?'); |
4713 | 0 | } |
4714 | 0 | if (NS_FAILED(rv)) { |
4715 | 0 | CopyUTF8toUTF16(spec, formatStrs[formatStrCount]); |
4716 | 0 | } |
4717 | 0 | rv = NS_OK; |
4718 | 0 | ++formatStrCount; |
4719 | 0 |
|
4720 | 0 | const char16_t* strs[kMaxFormatStrArgs]; |
4721 | 0 | for (uint32_t i = 0; i < formatStrCount; i++) { |
4722 | 0 | strs[i] = formatStrs[i].get(); |
4723 | 0 | } |
4724 | 0 | nsAutoString str; |
4725 | 0 | rv = stringBundle->FormatStringFromName(errorDescriptionID, strs, formatStrCount, str); |
4726 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4727 | 0 | messageStr.Assign(str.get()); |
4728 | 0 | } |
4729 | 0 |
|
4730 | 0 | // Display the error as a page or an alert prompt |
4731 | 0 | NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE); |
4732 | 0 |
|
4733 | 0 | if (NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) { |
4734 | 0 | bool isSecureURI = false; |
4735 | 0 | rv = aURI->SchemeIs("https", &isSecureURI); |
4736 | 0 | if (NS_SUCCEEDED(rv) && isSecureURI) { |
4737 | 0 | // Maybe TLS intolerant. Treat this as an SSL error. |
4738 | 0 | error = "nssFailure2"; |
4739 | 0 | } |
4740 | 0 | } |
4741 | 0 |
|
4742 | 0 | if (UseErrorPages()) { |
4743 | 0 | // Display an error page |
4744 | 0 | nsresult loadedPage = LoadErrorPage(aURI, aURL, errorPage.get(), |
4745 | 0 | error, messageStr.get(), |
4746 | 0 | cssClass.get(), aFailedChannel); |
4747 | 0 | *aDisplayedErrorPage = NS_SUCCEEDED(loadedPage); |
4748 | 0 | } else { |
4749 | 0 | // The prompter reqires that our private window has a document (or it |
4750 | 0 | // asserts). Satisfy that assertion now since GetDoc will force |
4751 | 0 | // creation of one if it hasn't already been created. |
4752 | 0 | if (mScriptGlobal) { |
4753 | 0 | Unused << mScriptGlobal->GetDoc(); |
4754 | 0 | } |
4755 | 0 |
|
4756 | 0 | // Display a message box |
4757 | 0 | prompter->Alert(nullptr, messageStr.get()); |
4758 | 0 | } |
4759 | 0 |
|
4760 | 0 | return NS_OK; |
4761 | 0 | } |
4762 | | |
4763 | 0 | #define PREF_SAFEBROWSING_ALLOWOVERRIDE "browser.safebrowsing.allowOverride" |
4764 | | |
4765 | | nsresult |
4766 | | nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL, |
4767 | | const char* aErrorPage, |
4768 | | const char* aErrorType, |
4769 | | const char16_t* aDescription, |
4770 | | const char* aCSSClass, |
4771 | | nsIChannel* aFailedChannel) |
4772 | 0 | { |
4773 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
4774 | 0 |
|
4775 | | #if defined(DEBUG) |
4776 | | if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) { |
4777 | | nsAutoCString chanName; |
4778 | | if (aFailedChannel) { |
4779 | | aFailedChannel->GetName(chanName); |
4780 | | } else { |
4781 | | chanName.AssignLiteral("<no channel>"); |
4782 | | } |
4783 | | |
4784 | | MOZ_LOG(gDocShellLog, LogLevel::Debug, |
4785 | | ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this, |
4786 | | aURI ? aURI->GetSpecOrDefault().get() : "", |
4787 | | NS_ConvertUTF16toUTF8(aURL).get(), |
4788 | | chanName.get())); |
4789 | | } |
4790 | | #endif |
4791 | |
|
4792 | 0 | nsAutoCString url; |
4793 | 0 | if (aURI) { |
4794 | 0 | nsresult rv = aURI->GetSpec(url); |
4795 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4796 | 0 | } else if (aURL) { |
4797 | 0 | CopyUTF16toUTF8(MakeStringSpan(aURL), url); |
4798 | 0 | } else { |
4799 | 0 | return NS_ERROR_INVALID_POINTER; |
4800 | 0 | } |
4801 | 0 | |
4802 | 0 | // Create a URL to pass all the error information through to the page. |
4803 | 0 | |
4804 | 0 | #undef SAFE_ESCAPE |
4805 | 0 | #define SAFE_ESCAPE(output, input, params) \ |
4806 | 0 | if (NS_WARN_IF(!NS_Escape(input, output, params))) { \ |
4807 | 0 | return NS_ERROR_OUT_OF_MEMORY; \ |
4808 | 0 | } |
4809 | 0 | |
4810 | 0 | nsCString escapedUrl, escapedError, escapedDescription, |
4811 | 0 | escapedCSSClass; |
4812 | 0 | SAFE_ESCAPE(escapedUrl, url, url_Path); |
4813 | 0 | SAFE_ESCAPE(escapedError, nsDependentCString(aErrorType), url_Path); |
4814 | 0 | SAFE_ESCAPE(escapedDescription, |
4815 | 0 | NS_ConvertUTF16toUTF8(aDescription), url_Path); |
4816 | 0 | if (aCSSClass) { |
4817 | 0 | nsCString cssClass(aCSSClass); |
4818 | 0 | SAFE_ESCAPE(escapedCSSClass, cssClass, url_Path); |
4819 | 0 | } |
4820 | 0 | nsCString errorPageUrl("about:"); |
4821 | 0 | errorPageUrl.AppendASCII(aErrorPage); |
4822 | 0 | errorPageUrl.AppendLiteral("?e="); |
4823 | 0 |
|
4824 | 0 | errorPageUrl.AppendASCII(escapedError.get()); |
4825 | 0 | errorPageUrl.AppendLiteral("&u="); |
4826 | 0 | errorPageUrl.AppendASCII(escapedUrl.get()); |
4827 | 0 | if ((strcmp(aErrorPage, "blocked") == 0) && |
4828 | 0 | Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE, true)) { |
4829 | 0 | errorPageUrl.AppendLiteral("&o=1"); |
4830 | 0 | } |
4831 | 0 | if (!escapedCSSClass.IsEmpty()) { |
4832 | 0 | errorPageUrl.AppendLiteral("&s="); |
4833 | 0 | errorPageUrl.AppendASCII(escapedCSSClass.get()); |
4834 | 0 | } |
4835 | 0 | errorPageUrl.AppendLiteral("&c=UTF-8"); |
4836 | 0 |
|
4837 | 0 | nsAutoCString frameType(FrameTypeToString(mFrameType)); |
4838 | 0 | errorPageUrl.AppendLiteral("&f="); |
4839 | 0 | errorPageUrl.AppendASCII(frameType.get()); |
4840 | 0 |
|
4841 | 0 | nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID); |
4842 | 0 | int32_t cpsState; |
4843 | 0 | if (cps && NS_SUCCEEDED(cps->GetState(&cpsState)) && |
4844 | 0 | cpsState == nsICaptivePortalService::LOCKED_PORTAL) { |
4845 | 0 | errorPageUrl.AppendLiteral("&captive=true"); |
4846 | 0 | } |
4847 | 0 |
|
4848 | 0 | // netError.xhtml's getDescription only handles the "d" parameter at the |
4849 | 0 | // end of the URL, so append it last. |
4850 | 0 | errorPageUrl.AppendLiteral("&d="); |
4851 | 0 | errorPageUrl.AppendASCII(escapedDescription.get()); |
4852 | 0 |
|
4853 | 0 | nsCOMPtr<nsIURI> errorPageURI; |
4854 | 0 | nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl); |
4855 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4856 | 0 |
|
4857 | 0 | return LoadErrorPage(errorPageURI, aURI, aFailedChannel); |
4858 | 0 | } |
4859 | | |
4860 | | nsresult |
4861 | | nsDocShell::LoadErrorPage(nsIURI* aErrorURI, nsIURI* aFailedURI, nsIChannel* aFailedChannel) |
4862 | 0 | { |
4863 | 0 | mFailedChannel = aFailedChannel; |
4864 | 0 | mFailedURI = aFailedURI; |
4865 | 0 | mFailedLoadType = mLoadType; |
4866 | 0 |
|
4867 | 0 | if (mLSHE) { |
4868 | 0 | // Abandon mLSHE's BFCache entry and create a new one. This way, if |
4869 | 0 | // we go back or forward to another SHEntry with the same doc |
4870 | 0 | // identifier, the error page won't persist. |
4871 | 0 | mLSHE->AbandonBFCacheEntry(); |
4872 | 0 | } |
4873 | 0 |
|
4874 | 0 | return InternalLoad(aErrorURI, nullptr, Nothing(), false, false, nullptr, RP_Unset, |
4875 | 0 | nsContentUtils::GetSystemPrincipal(), nullptr, |
4876 | 0 | INTERNAL_LOAD_FLAGS_NONE, EmptyString(), |
4877 | 0 | nullptr, VoidString(), nullptr, nullptr, |
4878 | 0 | LOAD_ERROR_PAGE, nullptr, true, VoidString(), this, |
4879 | 0 | nullptr, nullptr, nullptr); |
4880 | 0 | } |
4881 | | |
4882 | | NS_IMETHODIMP |
4883 | | nsDocShell::Reload(uint32_t aReloadFlags) |
4884 | 0 | { |
4885 | 0 | if (!IsNavigationAllowed()) { |
4886 | 0 | return NS_OK; // JS may not handle returning of an error code |
4887 | 0 | } |
4888 | 0 | nsresult rv; |
4889 | 0 | NS_ASSERTION(((aReloadFlags & 0xf) == 0), |
4890 | 0 | "Reload command not updated to use load flags!"); |
4891 | 0 | NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0, |
4892 | 0 | "Don't pass these flags to Reload"); |
4893 | 0 |
|
4894 | 0 | uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags); |
4895 | 0 | NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG); |
4896 | 0 |
|
4897 | 0 | // Send notifications to the HistoryListener if any, about the impending |
4898 | 0 | // reload |
4899 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
4900 | 0 | bool canReload = true; |
4901 | 0 | if (rootSH) { |
4902 | 0 | rootSH->LegacySHistory() |
4903 | 0 | ->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload); |
4904 | 0 | } |
4905 | 0 |
|
4906 | 0 | if (!canReload) { |
4907 | 0 | return NS_OK; |
4908 | 0 | } |
4909 | 0 | |
4910 | 0 | /* If you change this part of code, make sure bug 45297 does not re-occur */ |
4911 | 0 | if (mOSHE) { |
4912 | 0 | rv = LoadHistoryEntry(mOSHE, loadType); |
4913 | 0 | } else if (mLSHE) { // In case a reload happened before the current load is done |
4914 | 0 | rv = LoadHistoryEntry(mLSHE, loadType); |
4915 | 0 | } else { |
4916 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
4917 | 0 |
|
4918 | 0 | if (!doc) { |
4919 | 0 | return NS_OK; |
4920 | 0 | } |
4921 | 0 | |
4922 | 0 | // Do not inherit owner from document |
4923 | 0 | uint32_t flags = INTERNAL_LOAD_FLAGS_NONE; |
4924 | 0 | nsAutoString srcdoc; |
4925 | 0 | nsCOMPtr<nsIURI> baseURI; |
4926 | 0 | nsCOMPtr<nsIURI> originalURI; |
4927 | 0 | nsCOMPtr<nsIURI> resultPrincipalURI; |
4928 | 0 | bool loadReplace = false; |
4929 | 0 |
|
4930 | 0 | nsIPrincipal* triggeringPrincipal = doc->NodePrincipal(); |
4931 | 0 | nsAutoString contentTypeHint; |
4932 | 0 | doc->GetContentType(contentTypeHint); |
4933 | 0 |
|
4934 | 0 | if (doc->IsSrcdocDocument()) { |
4935 | 0 | doc->GetSrcdocData(srcdoc); |
4936 | 0 | flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; |
4937 | 0 | baseURI = doc->GetBaseURI(); |
4938 | 0 | } |
4939 | 0 | nsCOMPtr<nsIChannel> chan = doc->GetChannel(); |
4940 | 0 | if (chan) { |
4941 | 0 | uint32_t loadFlags; |
4942 | 0 | chan->GetLoadFlags(&loadFlags); |
4943 | 0 | loadReplace = loadFlags & nsIChannel::LOAD_REPLACE; |
4944 | 0 | nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan)); |
4945 | 0 | if (httpChan) { |
4946 | 0 | httpChan->GetOriginalURI(getter_AddRefs(originalURI)); |
4947 | 0 | } |
4948 | 0 |
|
4949 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo(); |
4950 | 0 | if (loadInfo) { |
4951 | 0 | loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); |
4952 | 0 | } |
4953 | 0 | } |
4954 | 0 |
|
4955 | 0 | MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal"); |
4956 | 0 |
|
4957 | 0 | // Stack variables to ensure changes to the member variables don't affect to |
4958 | 0 | // the call. |
4959 | 0 | nsCOMPtr<nsIURI> currentURI = mCurrentURI; |
4960 | 0 | nsCOMPtr<nsIURI> referrerURI = mReferrerURI; |
4961 | 0 | uint32_t referrerPolicy = mReferrerPolicy; |
4962 | 0 |
|
4963 | 0 | // Reload always rewrites result principal URI. |
4964 | 0 | Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI; |
4965 | 0 | emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI)); |
4966 | 0 | rv = InternalLoad(currentURI, |
4967 | 0 | originalURI, |
4968 | 0 | emplacedResultPrincipalURI, |
4969 | 0 | false, |
4970 | 0 | loadReplace, |
4971 | 0 | referrerURI, |
4972 | 0 | referrerPolicy, |
4973 | 0 | triggeringPrincipal, |
4974 | 0 | triggeringPrincipal, |
4975 | 0 | flags, |
4976 | 0 | EmptyString(), // No window target |
4977 | 0 | NS_LossyConvertUTF16toASCII(contentTypeHint).get(), |
4978 | 0 | VoidString(), // No forced download |
4979 | 0 | nullptr, // No post data |
4980 | 0 | nullptr, // No headers data |
4981 | 0 | loadType, // Load type |
4982 | 0 | nullptr, // No SHEntry |
4983 | 0 | true, |
4984 | 0 | srcdoc, // srcdoc argument for iframe |
4985 | 0 | this, // For reloads we are the source |
4986 | 0 | baseURI, |
4987 | 0 | nullptr, // No nsIDocShell |
4988 | 0 | nullptr); // No nsIRequest |
4989 | 0 | } |
4990 | 0 |
|
4991 | 0 | return rv; |
4992 | 0 | } |
4993 | | |
4994 | | NS_IMETHODIMP |
4995 | | nsDocShell::Stop(uint32_t aStopFlags) |
4996 | 0 | { |
4997 | 0 | // Revoke any pending event related to content viewer restoration |
4998 | 0 | mRestorePresentationEvent.Revoke(); |
4999 | 0 |
|
5000 | 0 | if (mLoadType == LOAD_ERROR_PAGE) { |
5001 | 0 | if (mLSHE) { |
5002 | 0 | // Since error page loads never unset mLSHE, do so now |
5003 | 0 | SetHistoryEntry(&mOSHE, mLSHE); |
5004 | 0 | SetHistoryEntry(&mLSHE, nullptr); |
5005 | 0 | } |
5006 | 0 |
|
5007 | 0 | mFailedChannel = nullptr; |
5008 | 0 | mFailedURI = nullptr; |
5009 | 0 | } |
5010 | 0 |
|
5011 | 0 | if (nsIWebNavigation::STOP_CONTENT & aStopFlags) { |
5012 | 0 | // Stop the document loading |
5013 | 0 | if (mContentViewer) { |
5014 | 0 | nsCOMPtr<nsIContentViewer> cv = mContentViewer; |
5015 | 0 | cv->Stop(); |
5016 | 0 | } |
5017 | 0 | } |
5018 | 0 |
|
5019 | 0 | if (nsIWebNavigation::STOP_NETWORK & aStopFlags) { |
5020 | 0 | // Suspend any timers that were set for this loader. We'll clear |
5021 | 0 | // them out for good in CreateContentViewer. |
5022 | 0 | if (mRefreshURIList) { |
5023 | 0 | SuspendRefreshURIs(); |
5024 | 0 | mSavedRefreshURIList.swap(mRefreshURIList); |
5025 | 0 | mRefreshURIList = nullptr; |
5026 | 0 | } |
5027 | 0 |
|
5028 | 0 | // XXXbz We could also pass |this| to nsIURILoader::Stop. That will |
5029 | 0 | // just call Stop() on us as an nsIDocumentLoader... We need fewer |
5030 | 0 | // redundant apis! |
5031 | 0 | Stop(); |
5032 | 0 | } |
5033 | 0 |
|
5034 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
5035 | 0 | while (iter.HasMore()) { |
5036 | 0 | nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext())); |
5037 | 0 | if (shellAsNav) { |
5038 | 0 | shellAsNav->Stop(aStopFlags); |
5039 | 0 | } |
5040 | 0 | } |
5041 | 0 |
|
5042 | 0 | return NS_OK; |
5043 | 0 | } |
5044 | | |
5045 | | NS_IMETHODIMP |
5046 | | nsDocShell::GetDocument(nsIDocument** aDocument) |
5047 | 0 | { |
5048 | 0 | NS_ENSURE_ARG_POINTER(aDocument); |
5049 | 0 | NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE); |
5050 | 0 |
|
5051 | 0 | nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument(); |
5052 | 0 | if (!doc) { |
5053 | 0 | return NS_ERROR_NOT_AVAILABLE; |
5054 | 0 | } |
5055 | 0 | |
5056 | 0 | doc.forget(aDocument); |
5057 | 0 | return NS_OK; |
5058 | 0 | } |
5059 | | |
5060 | | NS_IMETHODIMP |
5061 | | nsDocShell::GetCurrentURI(nsIURI** aURI) |
5062 | 0 | { |
5063 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
5064 | 0 |
|
5065 | 0 | nsCOMPtr<nsIURI> uri = mCurrentURI; |
5066 | 0 | uri.forget(aURI); |
5067 | 0 | return NS_OK; |
5068 | 0 | } |
5069 | | |
5070 | | NS_IMETHODIMP |
5071 | | nsDocShell::GetReferringURI(nsIURI** aURI) |
5072 | 0 | { |
5073 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
5074 | 0 |
|
5075 | 0 | *aURI = mReferrerURI; |
5076 | 0 | NS_IF_ADDREF(*aURI); |
5077 | 0 |
|
5078 | 0 | return NS_OK; |
5079 | 0 | } |
5080 | | |
5081 | | NS_IMETHODIMP |
5082 | | nsDocShell::InitSessionHistory() |
5083 | 0 | { |
5084 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
5085 | 0 |
|
5086 | 0 | // Make sure that we are the root DocShell, and set a handle to root docshell |
5087 | 0 | // in the session history. |
5088 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
5089 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(root)); |
5090 | 0 | if (root != this) { |
5091 | 0 | return NS_ERROR_FAILURE; |
5092 | 0 | } |
5093 | 0 | |
5094 | 0 | mSessionHistory = new ChildSHistory(this); |
5095 | 0 | return NS_OK; |
5096 | 0 | } |
5097 | | |
5098 | | NS_IMETHODIMP |
5099 | | nsDocShell::GetSessionHistoryXPCOM(nsISupports** aSessionHistory) |
5100 | 0 | { |
5101 | 0 | NS_ENSURE_ARG_POINTER(aSessionHistory); |
5102 | 0 | RefPtr<ChildSHistory> shistory = mSessionHistory; |
5103 | 0 | shistory.forget(aSessionHistory); |
5104 | 0 | return NS_OK; |
5105 | 0 | } |
5106 | | |
5107 | | //***************************************************************************** |
5108 | | // nsDocShell::nsIWebPageDescriptor |
5109 | | //***************************************************************************** |
5110 | | |
5111 | | NS_IMETHODIMP |
5112 | | nsDocShell::LoadPage(nsISupports* aPageDescriptor, uint32_t aDisplayType) |
5113 | 0 | { |
5114 | 0 | nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor)); |
5115 | 0 |
|
5116 | 0 | // Currently, the opaque 'page descriptor' is an nsISHEntry... |
5117 | 0 | if (!shEntryIn) { |
5118 | 0 | return NS_ERROR_INVALID_POINTER; |
5119 | 0 | } |
5120 | 0 | |
5121 | 0 | // Now clone shEntryIn, since we might end up modifying it later on, and we |
5122 | 0 | // want a page descriptor to be reusable. |
5123 | 0 | nsCOMPtr<nsISHEntry> shEntry; |
5124 | 0 | nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry)); |
5125 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5126 | 0 |
|
5127 | 0 | // Give our cloned shEntry a new bfcache entry so this load is independent |
5128 | 0 | // of all other loads. (This is important, in particular, for bugs 582795 |
5129 | 0 | // and 585298.) |
5130 | 0 | rv = shEntry->AbandonBFCacheEntry(); |
5131 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5132 | 0 |
|
5133 | 0 | // |
5134 | 0 | // load the page as view-source |
5135 | 0 | // |
5136 | 0 | if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) { |
5137 | 0 | nsCString spec, newSpec; |
5138 | 0 |
|
5139 | 0 | // Create a new view-source URI and replace the original. |
5140 | 0 | nsCOMPtr<nsIURI> oldUri = shEntry->GetURI(); |
5141 | 0 |
|
5142 | 0 | oldUri->GetSpec(spec); |
5143 | 0 | newSpec.AppendLiteral("view-source:"); |
5144 | 0 | newSpec.Append(spec); |
5145 | 0 |
|
5146 | 0 | nsCOMPtr<nsIURI> newUri; |
5147 | 0 | rv = NS_NewURI(getter_AddRefs(newUri), newSpec); |
5148 | 0 | if (NS_FAILED(rv)) { |
5149 | 0 | return rv; |
5150 | 0 | } |
5151 | 0 | shEntry->SetURI(newUri); |
5152 | 0 | shEntry->SetOriginalURI(nullptr); |
5153 | 0 | shEntry->SetResultPrincipalURI(nullptr); |
5154 | 0 | // shEntry's current triggering principal is whoever loaded that page initially. |
5155 | 0 | // But now we're doing another load of the page, via an API that is only exposed |
5156 | 0 | // to system code. The triggering principal for this load should be the system |
5157 | 0 | // principal. |
5158 | 0 | shEntry->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal()); |
5159 | 0 | } |
5160 | 0 |
|
5161 | 0 | rv = LoadHistoryEntry(shEntry, LOAD_HISTORY); |
5162 | 0 | return rv; |
5163 | 0 | } |
5164 | | |
5165 | | NS_IMETHODIMP |
5166 | | nsDocShell::GetCurrentDescriptor(nsISupports** aPageDescriptor) |
5167 | 0 | { |
5168 | 0 | MOZ_ASSERT(aPageDescriptor, "Null out param?"); |
5169 | 0 |
|
5170 | 0 | *aPageDescriptor = nullptr; |
5171 | 0 |
|
5172 | 0 | nsISHEntry* src = mOSHE ? mOSHE : mLSHE; |
5173 | 0 | if (src) { |
5174 | 0 | nsCOMPtr<nsISHEntry> dest; |
5175 | 0 |
|
5176 | 0 | nsresult rv = src->Clone(getter_AddRefs(dest)); |
5177 | 0 | if (NS_FAILED(rv)) { |
5178 | 0 | return rv; |
5179 | 0 | } |
5180 | 0 | |
5181 | 0 | // null out inappropriate cloned attributes... |
5182 | 0 | dest->SetParent(nullptr); |
5183 | 0 | dest->SetIsSubFrame(false); |
5184 | 0 |
|
5185 | 0 | return CallQueryInterface(dest, aPageDescriptor); |
5186 | 0 | } |
5187 | 0 | |
5188 | 0 | return NS_ERROR_NOT_AVAILABLE; |
5189 | 0 | } |
5190 | | |
5191 | | //***************************************************************************** |
5192 | | // nsDocShell::nsIBaseWindow |
5193 | | //***************************************************************************** |
5194 | | |
5195 | | NS_IMETHODIMP |
5196 | | nsDocShell::InitWindow(nativeWindow aParentNativeWindow, |
5197 | | nsIWidget* aParentWidget, int32_t aX, int32_t aY, |
5198 | | int32_t aWidth, int32_t aHeight) |
5199 | 0 | { |
5200 | 0 | SetParentWidget(aParentWidget); |
5201 | 0 | SetPositionAndSize(aX, aY, aWidth, aHeight, 0); |
5202 | 0 |
|
5203 | 0 | return NS_OK; |
5204 | 0 | } |
5205 | | |
5206 | | NS_IMETHODIMP |
5207 | | nsDocShell::Create() |
5208 | 0 | { |
5209 | 0 | if (mCreated) { |
5210 | 0 | // We've already been created |
5211 | 0 | return NS_OK; |
5212 | 0 | } |
5213 | 0 | |
5214 | 0 | NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome, |
5215 | 0 | "Unexpected item type in docshell"); |
5216 | 0 |
|
5217 | 0 | NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); |
5218 | 0 | mCreated = true; |
5219 | 0 |
|
5220 | 0 | if (gValidateOrigin == 0xffffffff) { |
5221 | 0 | // Check pref to see if we should prevent frameset spoofing |
5222 | 0 | gValidateOrigin = |
5223 | 0 | Preferences::GetBool("browser.frame.validate_origin", true); |
5224 | 0 | } |
5225 | 0 |
|
5226 | 0 | // Should we use XUL error pages instead of alerts if possible? |
5227 | 0 | mUseErrorPages = |
5228 | 0 | Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages); |
5229 | 0 |
|
5230 | 0 | if (!gAddedPreferencesVarCache) { |
5231 | 0 | Preferences::AddBoolVarCache(&sUseErrorPages, |
5232 | 0 | "browser.xul.error_pages.enabled", |
5233 | 0 | mUseErrorPages); |
5234 | 0 | gAddedPreferencesVarCache = true; |
5235 | 0 | } |
5236 | 0 |
|
5237 | 0 | mDisableMetaRefreshWhenInactive = |
5238 | 0 | Preferences::GetBool("browser.meta_refresh_when_inactive.disabled", |
5239 | 0 | mDisableMetaRefreshWhenInactive); |
5240 | 0 |
|
5241 | 0 | mDeviceSizeIsPageSize = |
5242 | 0 | Preferences::GetBool("docshell.device_size_is_page_size", |
5243 | 0 | mDeviceSizeIsPageSize); |
5244 | 0 |
|
5245 | 0 | nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); |
5246 | 0 | if (serv) { |
5247 | 0 | const char* msg = mItemType == typeContent ? |
5248 | 0 | NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE; |
5249 | 0 | serv->NotifyObservers(GetAsSupports(this), msg, nullptr); |
5250 | 0 | } |
5251 | 0 |
|
5252 | 0 | return NS_OK; |
5253 | 0 | } |
5254 | | |
5255 | | NS_IMETHODIMP |
5256 | | nsDocShell::Destroy() |
5257 | 0 | { |
5258 | 0 | // XXX: We allow this function to be called just once. If you are going to |
5259 | 0 | // reset new variables in this function, please make sure the variables will |
5260 | 0 | // never be re-initialized. Adding assertions to check |mIsBeingDestroyed| |
5261 | 0 | // in the setter functions for the variables would be enough. |
5262 | 0 | if (mIsBeingDestroyed) { |
5263 | 0 | return NS_ERROR_DOCSHELL_DYING; |
5264 | 0 | } |
5265 | 0 | |
5266 | 0 | NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome, |
5267 | 0 | "Unexpected item type in docshell"); |
5268 | 0 |
|
5269 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
5270 | 0 |
|
5271 | 0 | nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); |
5272 | 0 | if (serv) { |
5273 | 0 | const char* msg = mItemType == typeContent ? |
5274 | 0 | NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY; |
5275 | 0 | serv->NotifyObservers(GetAsSupports(this), msg, nullptr); |
5276 | 0 | } |
5277 | 0 |
|
5278 | 0 | mIsBeingDestroyed = true; |
5279 | 0 |
|
5280 | 0 | // Brak the cycle with the initial client, if present. |
5281 | 0 | mInitialClientSource.reset(); |
5282 | 0 |
|
5283 | 0 | // Make sure we don't record profile timeline markers anymore |
5284 | 0 | SetRecordProfileTimelineMarkers(false); |
5285 | 0 |
|
5286 | 0 | // Remove our pref observers |
5287 | 0 | if (mObserveErrorPages) { |
5288 | 0 | mObserveErrorPages = false; |
5289 | 0 | } |
5290 | 0 |
|
5291 | 0 | // Make sure to blow away our mLoadingURI just in case. No loads |
5292 | 0 | // from inside this pagehide. |
5293 | 0 | mLoadingURI = nullptr; |
5294 | 0 |
|
5295 | 0 | // Fire unload event before we blow anything away. |
5296 | 0 | (void)FirePageHideNotification(true); |
5297 | 0 |
|
5298 | 0 | // Clear pointers to any detached nsEditorData that's lying |
5299 | 0 | // around in shistory entries. Breaks cycle. See bug 430921. |
5300 | 0 | if (mOSHE) { |
5301 | 0 | mOSHE->SetEditorData(nullptr); |
5302 | 0 | } |
5303 | 0 | if (mLSHE) { |
5304 | 0 | mLSHE->SetEditorData(nullptr); |
5305 | 0 | } |
5306 | 0 |
|
5307 | 0 | // Note: mContentListener can be null if Init() failed and we're being |
5308 | 0 | // called from the destructor. |
5309 | 0 | if (mContentListener) { |
5310 | 0 | mContentListener->DropDocShellReference(); |
5311 | 0 | mContentListener->SetParentContentListener(nullptr); |
5312 | 0 | // Note that we do NOT set mContentListener to null here; that |
5313 | 0 | // way if someone tries to do a load in us after this point |
5314 | 0 | // the nsDSURIContentListener will block it. All of which |
5315 | 0 | // means that we should do this before calling Stop(), of |
5316 | 0 | // course. |
5317 | 0 | } |
5318 | 0 |
|
5319 | 0 | // Stop any URLs that are currently being loaded... |
5320 | 0 | Stop(nsIWebNavigation::STOP_ALL); |
5321 | 0 |
|
5322 | 0 | mEditorData = nullptr; |
5323 | 0 |
|
5324 | 0 | // Save the state of the current document, before destroying the window. |
5325 | 0 | // This is needed to capture the state of a frameset when the new document |
5326 | 0 | // causes the frameset to be destroyed... |
5327 | 0 | PersistLayoutHistoryState(); |
5328 | 0 |
|
5329 | 0 | // Remove this docshell from its parent's child list |
5330 | 0 | nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem = |
5331 | 0 | do_QueryInterface(GetAsSupports(mParent)); |
5332 | 0 | if (docShellParentAsItem) { |
5333 | 0 | docShellParentAsItem->RemoveChild(this); |
5334 | 0 | } |
5335 | 0 |
|
5336 | 0 | if (mContentViewer) { |
5337 | 0 | mContentViewer->Close(nullptr); |
5338 | 0 | mContentViewer->Destroy(); |
5339 | 0 | mContentViewer = nullptr; |
5340 | 0 | } |
5341 | 0 |
|
5342 | 0 | nsDocLoader::Destroy(); |
5343 | 0 |
|
5344 | 0 | mParentWidget = nullptr; |
5345 | 0 | mCurrentURI = nullptr; |
5346 | 0 |
|
5347 | 0 | if (mScriptGlobal) { |
5348 | 0 | mScriptGlobal->DetachFromDocShell(); |
5349 | 0 | mScriptGlobal = nullptr; |
5350 | 0 | } |
5351 | 0 |
|
5352 | 0 | if (mSessionHistory) { |
5353 | 0 | // We want to destroy these content viewers now rather than |
5354 | 0 | // letting their destruction wait for the session history |
5355 | 0 | // entries to get garbage collected. (Bug 488394) |
5356 | 0 | mSessionHistory->EvictLocalContentViewers(); |
5357 | 0 | mSessionHistory = nullptr; |
5358 | 0 | } |
5359 | 0 |
|
5360 | 0 | mBrowsingContext->Detach(); |
5361 | 0 |
|
5362 | 0 | SetTreeOwner(nullptr); |
5363 | 0 |
|
5364 | 0 | mOnePermittedSandboxedNavigator = nullptr; |
5365 | 0 |
|
5366 | 0 | // required to break ref cycle |
5367 | 0 | mSecurityUI = nullptr; |
5368 | 0 |
|
5369 | 0 | // Cancel any timers that were set for this docshell; this is needed |
5370 | 0 | // to break the cycle between us and the timers. |
5371 | 0 | CancelRefreshURITimers(); |
5372 | 0 |
|
5373 | 0 | if (UsePrivateBrowsing()) { |
5374 | 0 | mPrivateBrowsingId = 0; |
5375 | 0 | mOriginAttributes.SyncAttributesWithPrivateBrowsing(false); |
5376 | 0 | if (mAffectPrivateSessionLifetime) { |
5377 | 0 | DecreasePrivateDocShellCount(); |
5378 | 0 | } |
5379 | 0 | } |
5380 | 0 |
|
5381 | 0 | return NS_OK; |
5382 | 0 | } |
5383 | | |
5384 | | NS_IMETHODIMP |
5385 | | nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double* aScale) |
5386 | 0 | { |
5387 | 0 | if (mParentWidget) { |
5388 | 0 | *aScale = mParentWidget->GetDefaultScale().scale; |
5389 | 0 | return NS_OK; |
5390 | 0 | } |
5391 | 0 | |
5392 | 0 | nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner)); |
5393 | 0 | if (ownerWindow) { |
5394 | 0 | return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale); |
5395 | 0 | } |
5396 | 0 | |
5397 | 0 | *aScale = 1.0; |
5398 | 0 | return NS_OK; |
5399 | 0 | } |
5400 | | |
5401 | | NS_IMETHODIMP |
5402 | | nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale) |
5403 | 0 | { |
5404 | 0 | if (mParentWidget) { |
5405 | 0 | *aScale = mParentWidget->GetDesktopToDeviceScale().scale; |
5406 | 0 | return NS_OK; |
5407 | 0 | } |
5408 | 0 | |
5409 | 0 | nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner)); |
5410 | 0 | if (ownerWindow) { |
5411 | 0 | return ownerWindow->GetDevicePixelsPerDesktopPixel(aScale); |
5412 | 0 | } |
5413 | 0 | |
5414 | 0 | *aScale = 1.0; |
5415 | 0 | return NS_OK; |
5416 | 0 | } |
5417 | | |
5418 | | NS_IMETHODIMP |
5419 | | nsDocShell::SetPosition(int32_t aX, int32_t aY) |
5420 | 0 | { |
5421 | 0 | mBounds.MoveTo(aX, aY); |
5422 | 0 |
|
5423 | 0 | if (mContentViewer) { |
5424 | 0 | NS_ENSURE_SUCCESS(mContentViewer->Move(aX, aY), NS_ERROR_FAILURE); |
5425 | 0 | } |
5426 | 0 |
|
5427 | 0 | return NS_OK; |
5428 | 0 | } |
5429 | | |
5430 | | NS_IMETHODIMP |
5431 | | nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY) |
5432 | 0 | { |
5433 | 0 | nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner)); |
5434 | 0 | if (ownerWindow) { |
5435 | 0 | return ownerWindow->SetPositionDesktopPix(aX, aY); |
5436 | 0 | } |
5437 | 0 | |
5438 | 0 | double scale = 1.0; |
5439 | 0 | GetDevicePixelsPerDesktopPixel(&scale); |
5440 | 0 | return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale)); |
5441 | 0 | } |
5442 | | |
5443 | | NS_IMETHODIMP |
5444 | | nsDocShell::GetPosition(int32_t* aX, int32_t* aY) |
5445 | 0 | { |
5446 | 0 | return GetPositionAndSize(aX, aY, nullptr, nullptr); |
5447 | 0 | } |
5448 | | |
5449 | | NS_IMETHODIMP |
5450 | | nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint) |
5451 | 0 | { |
5452 | 0 | int32_t x = 0, y = 0; |
5453 | 0 | GetPosition(&x, &y); |
5454 | 0 | return SetPositionAndSize(x, y, aWidth, aHeight, |
5455 | 0 | aRepaint ? nsIBaseWindow::eRepaint : 0); |
5456 | 0 | } |
5457 | | |
5458 | | NS_IMETHODIMP |
5459 | | nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight) |
5460 | 0 | { |
5461 | 0 | return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight); |
5462 | 0 | } |
5463 | | |
5464 | | NS_IMETHODIMP |
5465 | | nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth, |
5466 | | int32_t aHeight, uint32_t aFlags) |
5467 | 0 | { |
5468 | 0 | mBounds.SetRect(aX, aY, aWidth, aHeight); |
5469 | 0 |
|
5470 | 0 | // Hold strong ref, since SetBounds can make us null out mContentViewer |
5471 | 0 | nsCOMPtr<nsIContentViewer> viewer = mContentViewer; |
5472 | 0 | if (viewer) { |
5473 | 0 | uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize) ? |
5474 | 0 | nsIContentViewer::eDelayResize : 0; |
5475 | 0 | // XXX Border figured in here or is that handled elsewhere? |
5476 | 0 | nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags); |
5477 | 0 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
5478 | 0 | } |
5479 | 0 |
|
5480 | 0 | return NS_OK; |
5481 | 0 | } |
5482 | | |
5483 | | NS_IMETHODIMP |
5484 | | nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth, |
5485 | | int32_t* aHeight) |
5486 | 0 | { |
5487 | 0 | if (mParentWidget) { |
5488 | 0 | // ensure size is up-to-date if window has changed resolution |
5489 | 0 | LayoutDeviceIntRect r = mParentWidget->GetClientBounds(); |
5490 | 0 | SetPositionAndSize(mBounds.X(), mBounds.Y(), r.Width(), r.Height(), 0); |
5491 | 0 | } |
5492 | 0 |
|
5493 | 0 | // We should really consider just getting this information from |
5494 | 0 | // our window instead of duplicating the storage and code... |
5495 | 0 | if (aWidth || aHeight) { |
5496 | 0 | // Caller wants to know our size; make sure to give them up to |
5497 | 0 | // date information. |
5498 | 0 | nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent))); |
5499 | 0 | if (doc) { |
5500 | 0 | doc->FlushPendingNotifications(FlushType::Layout); |
5501 | 0 | } |
5502 | 0 | } |
5503 | 0 |
|
5504 | 0 | DoGetPositionAndSize(aX, aY, aWidth, aHeight); |
5505 | 0 | return NS_OK; |
5506 | 0 | } |
5507 | | |
5508 | | void |
5509 | | nsDocShell::DoGetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth, |
5510 | | int32_t* aHeight) |
5511 | 0 | { |
5512 | 0 | if (aX) { |
5513 | 0 | *aX = mBounds.X(); |
5514 | 0 | } |
5515 | 0 | if (aY) { |
5516 | 0 | *aY = mBounds.Y(); |
5517 | 0 | } |
5518 | 0 | if (aWidth) { |
5519 | 0 | *aWidth = mBounds.Width(); |
5520 | 0 | } |
5521 | 0 | if (aHeight) { |
5522 | 0 | *aHeight = mBounds.Height(); |
5523 | 0 | } |
5524 | 0 | } |
5525 | | |
5526 | | NS_IMETHODIMP |
5527 | | nsDocShell::Repaint(bool aForce) |
5528 | 0 | { |
5529 | 0 | nsCOMPtr<nsIPresShell> presShell = GetPresShell(); |
5530 | 0 | NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); |
5531 | 0 |
|
5532 | 0 | nsViewManager* viewManager = presShell->GetViewManager(); |
5533 | 0 | NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE); |
5534 | 0 |
|
5535 | 0 | viewManager->InvalidateAllViews(); |
5536 | 0 | return NS_OK; |
5537 | 0 | } |
5538 | | |
5539 | | NS_IMETHODIMP |
5540 | | nsDocShell::GetParentWidget(nsIWidget** aParentWidget) |
5541 | 0 | { |
5542 | 0 | NS_ENSURE_ARG_POINTER(aParentWidget); |
5543 | 0 |
|
5544 | 0 | *aParentWidget = mParentWidget; |
5545 | 0 | NS_IF_ADDREF(*aParentWidget); |
5546 | 0 |
|
5547 | 0 | return NS_OK; |
5548 | 0 | } |
5549 | | |
5550 | | NS_IMETHODIMP |
5551 | | nsDocShell::SetParentWidget(nsIWidget* aParentWidget) |
5552 | 0 | { |
5553 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
5554 | 0 | mParentWidget = aParentWidget; |
5555 | 0 |
|
5556 | 0 | return NS_OK; |
5557 | 0 | } |
5558 | | |
5559 | | NS_IMETHODIMP |
5560 | | nsDocShell::GetParentNativeWindow(nativeWindow* aParentNativeWindow) |
5561 | 0 | { |
5562 | 0 | NS_ENSURE_ARG_POINTER(aParentNativeWindow); |
5563 | 0 |
|
5564 | 0 | if (mParentWidget) { |
5565 | 0 | *aParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET); |
5566 | 0 | } else { |
5567 | 0 | *aParentNativeWindow = nullptr; |
5568 | 0 | } |
5569 | 0 |
|
5570 | 0 | return NS_OK; |
5571 | 0 | } |
5572 | | |
5573 | | NS_IMETHODIMP |
5574 | | nsDocShell::SetParentNativeWindow(nativeWindow aParentNativeWindow) |
5575 | 0 | { |
5576 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
5577 | 0 | } |
5578 | | |
5579 | | NS_IMETHODIMP |
5580 | | nsDocShell::GetNativeHandle(nsAString& aNativeHandle) |
5581 | 0 | { |
5582 | 0 | // the nativeHandle should be accessed from nsIXULWindow |
5583 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
5584 | 0 | } |
5585 | | |
5586 | | NS_IMETHODIMP |
5587 | | nsDocShell::GetVisibility(bool* aVisibility) |
5588 | 0 | { |
5589 | 0 | NS_ENSURE_ARG_POINTER(aVisibility); |
5590 | 0 |
|
5591 | 0 | *aVisibility = false; |
5592 | 0 |
|
5593 | 0 | if (!mContentViewer) { |
5594 | 0 | return NS_OK; |
5595 | 0 | } |
5596 | 0 | |
5597 | 0 | nsCOMPtr<nsIPresShell> presShell = GetPresShell(); |
5598 | 0 | if (!presShell) { |
5599 | 0 | return NS_OK; |
5600 | 0 | } |
5601 | 0 | |
5602 | 0 | // get the view manager |
5603 | 0 | nsViewManager* vm = presShell->GetViewManager(); |
5604 | 0 | NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE); |
5605 | 0 |
|
5606 | 0 | // get the root view |
5607 | 0 | nsView* view = vm->GetRootView(); // views are not ref counted |
5608 | 0 | NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); |
5609 | 0 |
|
5610 | 0 | // if our root view is hidden, we are not visible |
5611 | 0 | if (view->GetVisibility() == nsViewVisibility_kHide) { |
5612 | 0 | return NS_OK; |
5613 | 0 | } |
5614 | 0 | |
5615 | 0 | // otherwise, we must walk up the document and view trees checking |
5616 | 0 | // for a hidden view, unless we're an off screen browser, which |
5617 | 0 | // would make this test meaningless. |
5618 | 0 | |
5619 | 0 | RefPtr<nsDocShell> docShell = this; |
5620 | 0 | RefPtr<nsDocShell> parentItem = docShell->GetParentDocshell(); |
5621 | 0 | while (parentItem) { |
5622 | 0 | presShell = docShell->GetPresShell(); |
5623 | 0 |
|
5624 | 0 | nsCOMPtr<nsIPresShell> pPresShell = parentItem->GetPresShell(); |
5625 | 0 |
|
5626 | 0 | // Null-check for crash in bug 267804 |
5627 | 0 | if (!pPresShell) { |
5628 | 0 | MOZ_ASSERT_UNREACHABLE("parent docshell has null pres shell"); |
5629 | 0 | return NS_OK; |
5630 | 0 | } |
5631 | 0 |
|
5632 | 0 | vm = presShell->GetViewManager(); |
5633 | 0 | if (vm) { |
5634 | 0 | view = vm->GetRootView(); |
5635 | 0 | } |
5636 | 0 |
|
5637 | 0 | if (view) { |
5638 | 0 | view = view->GetParent(); // anonymous inner view |
5639 | 0 | if (view) { |
5640 | 0 | view = view->GetParent(); // subdocumentframe's view |
5641 | 0 | } |
5642 | 0 | } |
5643 | 0 |
|
5644 | 0 | nsIFrame* frame = view ? view->GetFrame() : nullptr; |
5645 | 0 | bool isDocShellOffScreen = false; |
5646 | 0 | docShell->GetIsOffScreenBrowser(&isDocShellOffScreen); |
5647 | 0 | if (frame && |
5648 | 0 | !frame->IsVisibleConsideringAncestors( |
5649 | 0 | nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) && |
5650 | 0 | !isDocShellOffScreen) { |
5651 | 0 | return NS_OK; |
5652 | 0 | } |
5653 | 0 | |
5654 | 0 | docShell = parentItem; |
5655 | 0 | parentItem = docShell->GetParentDocshell(); |
5656 | 0 | } |
5657 | 0 |
|
5658 | 0 | nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner)); |
5659 | 0 | if (!treeOwnerAsWin) { |
5660 | 0 | *aVisibility = true; |
5661 | 0 | return NS_OK; |
5662 | 0 | } |
5663 | 0 | |
5664 | 0 | // Check with the tree owner as well to give embedders a chance to |
5665 | 0 | // expose visibility as well. |
5666 | 0 | return treeOwnerAsWin->GetVisibility(aVisibility); |
5667 | 0 | } |
5668 | | |
5669 | | NS_IMETHODIMP |
5670 | | nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen) |
5671 | 0 | { |
5672 | 0 | mIsOffScreenBrowser = aIsOffScreen; |
5673 | 0 | return NS_OK; |
5674 | 0 | } |
5675 | | |
5676 | | NS_IMETHODIMP |
5677 | | nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen) |
5678 | 0 | { |
5679 | 0 | *aIsOffScreen = mIsOffScreenBrowser; |
5680 | 0 | return NS_OK; |
5681 | 0 | } |
5682 | | |
5683 | | NS_IMETHODIMP |
5684 | | nsDocShell::SetIsActive(bool aIsActive) |
5685 | 0 | { |
5686 | 0 | // We disallow setting active on chrome docshells. |
5687 | 0 | if (mItemType == nsIDocShellTreeItem::typeChrome) { |
5688 | 0 | return NS_ERROR_INVALID_ARG; |
5689 | 0 | } |
5690 | 0 | |
5691 | 0 | // Keep track ourselves. |
5692 | 0 | mIsActive = aIsActive; |
5693 | 0 |
|
5694 | 0 | // Tell the PresShell about it. |
5695 | 0 | nsCOMPtr<nsIPresShell> pshell = GetPresShell(); |
5696 | 0 | if (pshell) { |
5697 | 0 | pshell->SetIsActive(aIsActive); |
5698 | 0 | } |
5699 | 0 |
|
5700 | 0 | // Tell the window about it |
5701 | 0 | if (mScriptGlobal) { |
5702 | 0 | mScriptGlobal->SetIsBackground(!aIsActive); |
5703 | 0 | if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) { |
5704 | 0 | // Update orientation when the top-level browsing context becomes active. |
5705 | 0 | if (aIsActive) { |
5706 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
5707 | 0 | GetSameTypeParent(getter_AddRefs(parent)); |
5708 | 0 | if (!parent) { |
5709 | 0 | // We only care about the top-level browsing context. |
5710 | 0 | uint16_t orientation = OrientationLock(); |
5711 | 0 | ScreenOrientation::UpdateActiveOrientationLock(orientation); |
5712 | 0 | } |
5713 | 0 | } |
5714 | 0 |
|
5715 | 0 | doc->PostVisibilityUpdateEvent(); |
5716 | 0 | } |
5717 | 0 | } |
5718 | 0 |
|
5719 | 0 | // Tell the nsDOMNavigationTiming about it |
5720 | 0 | RefPtr<nsDOMNavigationTiming> timing = mTiming; |
5721 | 0 | if (!timing && mContentViewer) { |
5722 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
5723 | 0 | if (doc) { |
5724 | 0 | timing = doc->GetNavigationTiming(); |
5725 | 0 | } |
5726 | 0 | } |
5727 | 0 | if (timing) { |
5728 | 0 | timing->NotifyDocShellStateChanged( |
5729 | 0 | aIsActive ? nsDOMNavigationTiming::DocShellState::eActive |
5730 | 0 | : nsDOMNavigationTiming::DocShellState::eInactive); |
5731 | 0 | } |
5732 | 0 |
|
5733 | 0 | // Recursively tell all of our children, but don't tell <iframe mozbrowser> |
5734 | 0 | // children; they handle their state separately. |
5735 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
5736 | 0 | while (iter.HasMore()) { |
5737 | 0 | nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext()); |
5738 | 0 | if (!docshell) { |
5739 | 0 | continue; |
5740 | 0 | } |
5741 | 0 | |
5742 | 0 | if (!docshell->GetIsMozBrowser()) { |
5743 | 0 | docshell->SetIsActive(aIsActive); |
5744 | 0 | } |
5745 | 0 | } |
5746 | 0 |
|
5747 | 0 | // Restart or stop meta refresh timers if necessary |
5748 | 0 | if (mDisableMetaRefreshWhenInactive) { |
5749 | 0 | if (mIsActive) { |
5750 | 0 | ResumeRefreshURIs(); |
5751 | 0 | } else { |
5752 | 0 | SuspendRefreshURIs(); |
5753 | 0 | } |
5754 | 0 | } |
5755 | 0 |
|
5756 | 0 | return NS_OK; |
5757 | 0 | } |
5758 | | |
5759 | | NS_IMETHODIMP |
5760 | | nsDocShell::GetIsActive(bool* aIsActive) |
5761 | 0 | { |
5762 | 0 | *aIsActive = mIsActive; |
5763 | 0 | return NS_OK; |
5764 | 0 | } |
5765 | | |
5766 | | NS_IMETHODIMP |
5767 | | nsDocShell::SetIsAppTab(bool aIsAppTab) |
5768 | 0 | { |
5769 | 0 | mIsAppTab = aIsAppTab; |
5770 | 0 | return NS_OK; |
5771 | 0 | } |
5772 | | |
5773 | | NS_IMETHODIMP |
5774 | | nsDocShell::GetIsAppTab(bool* aIsAppTab) |
5775 | 0 | { |
5776 | 0 | *aIsAppTab = mIsAppTab; |
5777 | 0 | return NS_OK; |
5778 | 0 | } |
5779 | | |
5780 | | NS_IMETHODIMP |
5781 | | nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags) |
5782 | 0 | { |
5783 | 0 | mSandboxFlags = aSandboxFlags; |
5784 | 0 | return NS_OK; |
5785 | 0 | } |
5786 | | |
5787 | | NS_IMETHODIMP |
5788 | | nsDocShell::GetSandboxFlags(uint32_t* aSandboxFlags) |
5789 | 0 | { |
5790 | 0 | *aSandboxFlags = mSandboxFlags; |
5791 | 0 | return NS_OK; |
5792 | 0 | } |
5793 | | |
5794 | | NS_IMETHODIMP |
5795 | | nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator) |
5796 | 0 | { |
5797 | 0 | if (mOnePermittedSandboxedNavigator) { |
5798 | 0 | NS_ERROR("One Permitted Sandboxed Navigator should only be set once."); |
5799 | 0 | return NS_OK; |
5800 | 0 | } |
5801 | 0 |
|
5802 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
5803 | 0 |
|
5804 | 0 | mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator); |
5805 | 0 | NS_ASSERTION(mOnePermittedSandboxedNavigator, |
5806 | 0 | "One Permitted Sandboxed Navigator must support weak references."); |
5807 | 0 |
|
5808 | 0 | return NS_OK; |
5809 | 0 | } |
5810 | | |
5811 | | NS_IMETHODIMP |
5812 | | nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator) |
5813 | 0 | { |
5814 | 0 | NS_ENSURE_ARG_POINTER(aSandboxedNavigator); |
5815 | 0 | nsCOMPtr<nsIDocShell> permittedNavigator = |
5816 | 0 | do_QueryReferent(mOnePermittedSandboxedNavigator); |
5817 | 0 | permittedNavigator.forget(aSandboxedNavigator); |
5818 | 0 | return NS_OK; |
5819 | 0 | } |
5820 | | |
5821 | | NS_IMETHODIMP |
5822 | | nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags) |
5823 | 0 | { |
5824 | 0 | mDefaultLoadFlags = aDefaultLoadFlags; |
5825 | 0 |
|
5826 | 0 | // Tell the load group to set these flags all requests in the group |
5827 | 0 | if (mLoadGroup) { |
5828 | 0 | mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags); |
5829 | 0 | } else { |
5830 | 0 | NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to"); |
5831 | 0 | } |
5832 | 0 |
|
5833 | 0 | // Recursively tell all of our children. We *do not* skip |
5834 | 0 | // <iframe mozbrowser> children - if someone sticks custom flags in this |
5835 | 0 | // docShell then they too get the same flags. |
5836 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
5837 | 0 | while (iter.HasMore()) { |
5838 | 0 | nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext()); |
5839 | 0 | if (!docshell) { |
5840 | 0 | continue; |
5841 | 0 | } |
5842 | 0 | docshell->SetDefaultLoadFlags(aDefaultLoadFlags); |
5843 | 0 | } |
5844 | 0 | return NS_OK; |
5845 | 0 | } |
5846 | | |
5847 | | NS_IMETHODIMP |
5848 | | nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags) |
5849 | 0 | { |
5850 | 0 | *aDefaultLoadFlags = mDefaultLoadFlags; |
5851 | 0 | return NS_OK; |
5852 | 0 | } |
5853 | | |
5854 | | NS_IMETHODIMP |
5855 | | nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel) |
5856 | 0 | { |
5857 | | #ifdef DEBUG |
5858 | | // if the channel is non-null |
5859 | | if (aMixedContentChannel) { |
5860 | | // Get the root docshell. |
5861 | | nsCOMPtr<nsIDocShellTreeItem> root; |
5862 | | GetSameTypeRootTreeItem(getter_AddRefs(root)); |
5863 | | NS_WARNING_ASSERTION(root.get() == static_cast<nsIDocShellTreeItem*>(this), |
5864 | | "Setting mMixedContentChannel on a docshell that is " |
5865 | | "not the root docshell"); |
5866 | | } |
5867 | | #endif |
5868 | | mMixedContentChannel = aMixedContentChannel; |
5869 | 0 | return NS_OK; |
5870 | 0 | } |
5871 | | |
5872 | | NS_IMETHODIMP |
5873 | | nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel) |
5874 | 0 | { |
5875 | 0 | NS_ENSURE_ARG_POINTER(aFailedChannel); |
5876 | 0 | nsIDocument* doc = GetDocument(); |
5877 | 0 | if (!doc) { |
5878 | 0 | *aFailedChannel = nullptr; |
5879 | 0 | return NS_OK; |
5880 | 0 | } |
5881 | 0 | NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel()); |
5882 | 0 | return NS_OK; |
5883 | 0 | } |
5884 | | |
5885 | | NS_IMETHODIMP |
5886 | | nsDocShell::GetMixedContentChannel(nsIChannel** aMixedContentChannel) |
5887 | 0 | { |
5888 | 0 | NS_ENSURE_ARG_POINTER(aMixedContentChannel); |
5889 | 0 | NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel); |
5890 | 0 | return NS_OK; |
5891 | 0 | } |
5892 | | |
5893 | | NS_IMETHODIMP |
5894 | | nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection, |
5895 | | bool* aAllowMixedContent, |
5896 | | bool* aIsRootDocShell) |
5897 | 0 | { |
5898 | 0 | *aRootHasSecureConnection = true; |
5899 | 0 | *aAllowMixedContent = false; |
5900 | 0 | *aIsRootDocShell = false; |
5901 | 0 |
|
5902 | 0 | nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot; |
5903 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); |
5904 | 0 | NS_ASSERTION(sameTypeRoot, |
5905 | 0 | "No document shell root tree item from document shell tree item!"); |
5906 | 0 | *aIsRootDocShell = |
5907 | 0 | sameTypeRoot.get() == static_cast<nsIDocShellTreeItem*>(this); |
5908 | 0 |
|
5909 | 0 | // now get the document from sameTypeRoot |
5910 | 0 | nsCOMPtr<nsIDocument> rootDoc = sameTypeRoot->GetDocument(); |
5911 | 0 | if (rootDoc) { |
5912 | 0 | nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal(); |
5913 | 0 |
|
5914 | 0 | // For things with system principal (e.g. scratchpad) there is no uri |
5915 | 0 | // aRootHasSecureConnection should be false. |
5916 | 0 | nsCOMPtr<nsIURI> rootUri; |
5917 | 0 | if (nsContentUtils::IsSystemPrincipal(rootPrincipal) || |
5918 | 0 | NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri || |
5919 | 0 | NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) { |
5920 | 0 | *aRootHasSecureConnection = false; |
5921 | 0 | } |
5922 | 0 |
|
5923 | 0 | // Check the root doc's channel against the root docShell's |
5924 | 0 | // mMixedContentChannel to see if they are the same. If they are the same, |
5925 | 0 | // the user has overriden the block. |
5926 | 0 | nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot); |
5927 | 0 | nsCOMPtr<nsIChannel> mixedChannel; |
5928 | 0 | rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel)); |
5929 | 0 | *aAllowMixedContent = |
5930 | 0 | mixedChannel && (mixedChannel == rootDoc->GetChannel()); |
5931 | 0 | } |
5932 | 0 |
|
5933 | 0 | return NS_OK; |
5934 | 0 | } |
5935 | | |
5936 | | NS_IMETHODIMP |
5937 | | nsDocShell::SetVisibility(bool aVisibility) |
5938 | 0 | { |
5939 | 0 | // Show()/Hide() may change mContentViewer. |
5940 | 0 | nsCOMPtr<nsIContentViewer> cv = mContentViewer; |
5941 | 0 | if (!cv) { |
5942 | 0 | return NS_OK; |
5943 | 0 | } |
5944 | 0 | if (aVisibility) { |
5945 | 0 | cv->Show(); |
5946 | 0 | } else { |
5947 | 0 | cv->Hide(); |
5948 | 0 | } |
5949 | 0 |
|
5950 | 0 | return NS_OK; |
5951 | 0 | } |
5952 | | |
5953 | | NS_IMETHODIMP |
5954 | | nsDocShell::GetEnabled(bool* aEnabled) |
5955 | 0 | { |
5956 | 0 | NS_ENSURE_ARG_POINTER(aEnabled); |
5957 | 0 | *aEnabled = true; |
5958 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
5959 | 0 | } |
5960 | | |
5961 | | NS_IMETHODIMP |
5962 | | nsDocShell::SetEnabled(bool aEnabled) |
5963 | 0 | { |
5964 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
5965 | 0 | } |
5966 | | |
5967 | | NS_IMETHODIMP |
5968 | | nsDocShell::SetFocus() |
5969 | 0 | { |
5970 | 0 | return NS_OK; |
5971 | 0 | } |
5972 | | |
5973 | | NS_IMETHODIMP |
5974 | | nsDocShell::GetMainWidget(nsIWidget** aMainWidget) |
5975 | 0 | { |
5976 | 0 | // We don't create our own widget, so simply return the parent one. |
5977 | 0 | return GetParentWidget(aMainWidget); |
5978 | 0 | } |
5979 | | |
5980 | | NS_IMETHODIMP |
5981 | | nsDocShell::GetTitle(nsAString& aTitle) |
5982 | 0 | { |
5983 | 0 | aTitle = mTitle; |
5984 | 0 | return NS_OK; |
5985 | 0 | } |
5986 | | |
5987 | | NS_IMETHODIMP |
5988 | | nsDocShell::SetTitle(const nsAString& aTitle) |
5989 | 0 | { |
5990 | 0 | // Store local title |
5991 | 0 | mTitle = aTitle; |
5992 | 0 |
|
5993 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
5994 | 0 | GetSameTypeParent(getter_AddRefs(parent)); |
5995 | 0 |
|
5996 | 0 | // When title is set on the top object it should then be passed to the |
5997 | 0 | // tree owner. |
5998 | 0 | if (!parent) { |
5999 | 0 | nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner)); |
6000 | 0 | if (treeOwnerAsWin) { |
6001 | 0 | treeOwnerAsWin->SetTitle(aTitle); |
6002 | 0 | } |
6003 | 0 | } |
6004 | 0 |
|
6005 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
6006 | 0 | if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) { |
6007 | 0 | UpdateGlobalHistoryTitle(mCurrentURI); |
6008 | 0 | } |
6009 | 0 |
|
6010 | 0 | // Update SessionHistory with the document's title. |
6011 | 0 | if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY && |
6012 | 0 | mLoadType != LOAD_ERROR_PAGE) { |
6013 | 0 | mOSHE->SetTitle(mTitle); |
6014 | 0 | } |
6015 | 0 |
|
6016 | 0 | return NS_OK; |
6017 | 0 | } |
6018 | | |
6019 | | nsresult |
6020 | | nsDocShell::GetCurScrollPos(int32_t aScrollOrientation, int32_t* aCurPos) |
6021 | 0 | { |
6022 | 0 | NS_ENSURE_ARG_POINTER(aCurPos); |
6023 | 0 |
|
6024 | 0 | nsIScrollableFrame* sf = GetRootScrollFrame(); |
6025 | 0 | if (!sf) { |
6026 | 0 | return NS_ERROR_FAILURE; |
6027 | 0 | } |
6028 | 0 | |
6029 | 0 | nsPoint pt = sf->GetScrollPosition(); |
6030 | 0 |
|
6031 | 0 | switch (aScrollOrientation) { |
6032 | 0 | case ScrollOrientation_X: |
6033 | 0 | *aCurPos = pt.x; |
6034 | 0 | return NS_OK; |
6035 | 0 |
|
6036 | 0 | case ScrollOrientation_Y: |
6037 | 0 | *aCurPos = pt.y; |
6038 | 0 | return NS_OK; |
6039 | 0 |
|
6040 | 0 | default: |
6041 | 0 | NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG); |
6042 | 0 | } |
6043 | 0 | } |
6044 | | |
6045 | | nsresult |
6046 | | nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos, |
6047 | | int32_t aCurVerticalPos) |
6048 | 0 | { |
6049 | 0 | nsIScrollableFrame* sf = GetRootScrollFrame(); |
6050 | 0 | NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
6051 | 0 |
|
6052 | 0 | nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT; |
6053 | 0 | if (sf->GetScrollStyles().mScrollBehavior == |
6054 | 0 | NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) { |
6055 | 0 | scrollMode = nsIScrollableFrame::SMOOTH_MSD; |
6056 | 0 | } |
6057 | 0 |
|
6058 | 0 | sf->ScrollTo(nsPoint(aCurHorizontalPos, aCurVerticalPos), scrollMode); |
6059 | 0 | return NS_OK; |
6060 | 0 | } |
6061 | | |
6062 | | //***************************************************************************** |
6063 | | // nsDocShell::nsIScrollable |
6064 | | //***************************************************************************** |
6065 | | |
6066 | | NS_IMETHODIMP |
6067 | | nsDocShell::GetDefaultScrollbarPreferences(int32_t aScrollOrientation, |
6068 | | int32_t* aScrollbarPref) |
6069 | 0 | { |
6070 | 0 | NS_ENSURE_ARG_POINTER(aScrollbarPref); |
6071 | 0 | switch (aScrollOrientation) { |
6072 | 0 | case ScrollOrientation_X: |
6073 | 0 | *aScrollbarPref = mDefaultScrollbarPref.x; |
6074 | 0 | return NS_OK; |
6075 | 0 |
|
6076 | 0 | case ScrollOrientation_Y: |
6077 | 0 | *aScrollbarPref = mDefaultScrollbarPref.y; |
6078 | 0 | return NS_OK; |
6079 | 0 |
|
6080 | 0 | default: |
6081 | 0 | NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG); |
6082 | 0 | } |
6083 | 0 | return NS_ERROR_FAILURE; |
6084 | 0 | } |
6085 | | |
6086 | | NS_IMETHODIMP |
6087 | | nsDocShell::SetDefaultScrollbarPreferences(int32_t aScrollOrientation, |
6088 | | int32_t aScrollbarPref) |
6089 | 0 | { |
6090 | 0 | switch (aScrollOrientation) { |
6091 | 0 | case ScrollOrientation_X: |
6092 | 0 | mDefaultScrollbarPref.x = aScrollbarPref; |
6093 | 0 | return NS_OK; |
6094 | 0 |
|
6095 | 0 | case ScrollOrientation_Y: |
6096 | 0 | mDefaultScrollbarPref.y = aScrollbarPref; |
6097 | 0 | return NS_OK; |
6098 | 0 |
|
6099 | 0 | default: |
6100 | 0 | NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG); |
6101 | 0 | } |
6102 | 0 | return NS_ERROR_FAILURE; |
6103 | 0 | } |
6104 | | |
6105 | | NS_IMETHODIMP |
6106 | | nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible, |
6107 | | bool* aHorizontalVisible) |
6108 | 0 | { |
6109 | 0 | nsIScrollableFrame* sf = GetRootScrollFrame(); |
6110 | 0 | NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
6111 | 0 |
|
6112 | 0 | uint32_t scrollbarVisibility = sf->GetScrollbarVisibility(); |
6113 | 0 | if (aVerticalVisible) { |
6114 | 0 | *aVerticalVisible = |
6115 | 0 | (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0; |
6116 | 0 | } |
6117 | 0 | if (aHorizontalVisible) { |
6118 | 0 | *aHorizontalVisible = |
6119 | 0 | (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0; |
6120 | 0 | } |
6121 | 0 |
|
6122 | 0 | return NS_OK; |
6123 | 0 | } |
6124 | | |
6125 | | //***************************************************************************** |
6126 | | // nsDocShell::nsIRefreshURI |
6127 | | //***************************************************************************** |
6128 | | |
6129 | | NS_IMETHODIMP |
6130 | | nsDocShell::RefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, |
6131 | | int32_t aDelay, bool aRepeat, |
6132 | | bool aMetaRefresh) |
6133 | 0 | { |
6134 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
6135 | 0 |
|
6136 | 0 | NS_ENSURE_ARG(aURI); |
6137 | 0 |
|
6138 | 0 | /* Check if Meta refresh/redirects are permitted. Some |
6139 | 0 | * embedded applications may not want to do this. |
6140 | 0 | * Must do this before sending out NOTIFY_REFRESH events |
6141 | 0 | * because listeners may have side effects (e.g. displaying a |
6142 | 0 | * button to manually trigger the refresh later). |
6143 | 0 | */ |
6144 | 0 | bool allowRedirects = true; |
6145 | 0 | GetAllowMetaRedirects(&allowRedirects); |
6146 | 0 | if (!allowRedirects) { |
6147 | 0 | return NS_OK; |
6148 | 0 | } |
6149 | 0 | |
6150 | 0 | // If any web progress listeners are listening for NOTIFY_REFRESH events, |
6151 | 0 | // give them a chance to block this refresh. |
6152 | 0 | bool sameURI; |
6153 | 0 | nsresult rv = aURI->Equals(mCurrentURI, &sameURI); |
6154 | 0 | if (NS_FAILED(rv)) { |
6155 | 0 | sameURI = false; |
6156 | 0 | } |
6157 | 0 | if (!RefreshAttempted(this, aURI, aDelay, sameURI)) { |
6158 | 0 | return NS_OK; |
6159 | 0 | } |
6160 | 0 | |
6161 | 0 | nsCOMPtr<nsITimerCallback> refreshTimer = |
6162 | 0 | new nsRefreshTimer(this, aURI, aPrincipal, aDelay, aRepeat, aMetaRefresh); |
6163 | 0 |
|
6164 | 0 | uint32_t busyFlags = 0; |
6165 | 0 | GetBusyFlags(&busyFlags); |
6166 | 0 |
|
6167 | 0 | if (!mRefreshURIList) { |
6168 | 0 | mRefreshURIList = nsArray::Create(); |
6169 | 0 | } |
6170 | 0 |
|
6171 | 0 | if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) { |
6172 | 0 | // We don't want to create the timer right now. Instead queue up the request |
6173 | 0 | // and trigger the timer in EndPageLoad() or whenever we become active. |
6174 | 0 | mRefreshURIList->AppendElement(refreshTimer); |
6175 | 0 | } else { |
6176 | 0 | // There is no page loading going on right now. Create the |
6177 | 0 | // timer and fire it right away. |
6178 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
6179 | 0 | NS_ENSURE_TRUE(win, NS_ERROR_FAILURE); |
6180 | 0 |
|
6181 | 0 | nsCOMPtr<nsITimer> timer; |
6182 | 0 | MOZ_TRY_VAR(timer, |
6183 | 0 | NS_NewTimerWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT, |
6184 | 0 | win->TabGroup()->EventTargetFor(TaskCategory::Network))); |
6185 | 0 |
|
6186 | 0 | mRefreshURIList->AppendElement(timer); // owning timer ref |
6187 | 0 | } |
6188 | 0 | return NS_OK; |
6189 | 0 | } |
6190 | | |
6191 | | nsresult |
6192 | | nsDocShell::ForceRefreshURIFromTimer(nsIURI* aURI, |
6193 | | nsIPrincipal* aPrincipal, |
6194 | | int32_t aDelay, |
6195 | | bool aMetaRefresh, |
6196 | | nsITimer* aTimer) |
6197 | 0 | { |
6198 | 0 | MOZ_ASSERT(aTimer, "Must have a timer here"); |
6199 | 0 |
|
6200 | 0 | // Remove aTimer from mRefreshURIList if needed |
6201 | 0 | if (mRefreshURIList) { |
6202 | 0 | uint32_t n = 0; |
6203 | 0 | mRefreshURIList->GetLength(&n); |
6204 | 0 |
|
6205 | 0 | for (uint32_t i = 0; i < n; ++i) { |
6206 | 0 | nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i); |
6207 | 0 | if (timer == aTimer) { |
6208 | 0 | mRefreshURIList->RemoveElementAt(i); |
6209 | 0 | break; |
6210 | 0 | } |
6211 | 0 | } |
6212 | 0 | } |
6213 | 0 |
|
6214 | 0 | return ForceRefreshURI(aURI, aPrincipal, aDelay, aMetaRefresh); |
6215 | 0 | } |
6216 | | |
6217 | | NS_IMETHODIMP |
6218 | | nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal, int32_t aDelay, bool aMetaRefresh) |
6219 | 0 | { |
6220 | 0 | NS_ENSURE_ARG(aURI); |
6221 | 0 |
|
6222 | 0 | RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo(); |
6223 | 0 |
|
6224 | 0 | /* We do need to pass in a referrer, but we don't want it to |
6225 | 0 | * be sent to the server. |
6226 | 0 | */ |
6227 | 0 | loadInfo->SetSendReferrer(false); |
6228 | 0 |
|
6229 | 0 | /* for most refreshes the current URI is an appropriate |
6230 | 0 | * internal referrer |
6231 | 0 | */ |
6232 | 0 | loadInfo->SetReferrer(mCurrentURI); |
6233 | 0 |
|
6234 | 0 | loadInfo->SetOriginalURI(mCurrentURI); |
6235 | 0 | loadInfo->SetResultPrincipalURI(aURI); |
6236 | 0 | loadInfo->SetResultPrincipalURIIsSome(true); |
6237 | 0 | loadInfo->SetKeepResultPrincipalURIIfSet(true); |
6238 | 0 |
|
6239 | 0 | // Set the triggering pricipal to aPrincipal if available, or current |
6240 | 0 | // document's principal otherwise. |
6241 | 0 | nsCOMPtr<nsIPrincipal> principal = aPrincipal; |
6242 | 0 | if (!principal) { |
6243 | 0 | nsCOMPtr<nsIDocument> doc = GetDocument(); |
6244 | 0 | if (!doc) { |
6245 | 0 | return NS_ERROR_FAILURE; |
6246 | 0 | } |
6247 | 0 | principal = doc->NodePrincipal(); |
6248 | 0 | } |
6249 | 0 | loadInfo->SetTriggeringPrincipal(principal); |
6250 | 0 | loadInfo->SetPrincipalIsExplicit(true); |
6251 | 0 |
|
6252 | 0 | /* Check if this META refresh causes a redirection |
6253 | 0 | * to another site. |
6254 | 0 | */ |
6255 | 0 | bool equalUri = false; |
6256 | 0 | nsresult rv = aURI->Equals(mCurrentURI, &equalUri); |
6257 | 0 | if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh && |
6258 | 0 | aDelay <= REFRESH_REDIRECT_TIMER) { |
6259 | 0 | /* It is a META refresh based redirection within the threshold time |
6260 | 0 | * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER). |
6261 | 0 | * Pass a REPLACE flag to LoadURI(). |
6262 | 0 | */ |
6263 | 0 | loadInfo->SetLoadType(LOAD_NORMAL_REPLACE); |
6264 | 0 |
|
6265 | 0 | /* for redirects we mimic HTTP, which passes the |
6266 | 0 | * original referrer |
6267 | 0 | */ |
6268 | 0 | nsCOMPtr<nsIURI> internalReferrer; |
6269 | 0 | GetReferringURI(getter_AddRefs(internalReferrer)); |
6270 | 0 | if (internalReferrer) { |
6271 | 0 | loadInfo->SetReferrer(internalReferrer); |
6272 | 0 | } |
6273 | 0 | } else { |
6274 | 0 | loadInfo->SetLoadType(LOAD_REFRESH); |
6275 | 0 | } |
6276 | 0 |
|
6277 | 0 | /* |
6278 | 0 | * LoadURI(...) will cancel all refresh timers... This causes the |
6279 | 0 | * Timer and its refreshData instance to be released... |
6280 | 0 | */ |
6281 | 0 | LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, true); |
6282 | 0 |
|
6283 | 0 | return NS_OK; |
6284 | 0 | } |
6285 | | |
6286 | | nsresult |
6287 | | nsDocShell::SetupRefreshURIFromHeader(nsIURI* aBaseURI, |
6288 | | nsIPrincipal* aPrincipal, |
6289 | | const nsACString& aHeader) |
6290 | 0 | { |
6291 | 0 | // Refresh headers are parsed with the following format in mind |
6292 | 0 | // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri"> |
6293 | 0 | // By the time we are here, the following is true: |
6294 | 0 | // header = "REFRESH" |
6295 | 0 | // content = "5; URL=http://uri" // note the URL attribute is |
6296 | 0 | // optional, if it is absent, the currently loaded url is used. |
6297 | 0 | // Also note that the seconds and URL separator can be either |
6298 | 0 | // a ';' or a ','. The ',' separator should be illegal but CNN |
6299 | 0 | // is using it. |
6300 | 0 | // |
6301 | 0 | // We need to handle the following strings, where |
6302 | 0 | // - X is a set of digits |
6303 | 0 | // - URI is either a relative or absolute URI |
6304 | 0 | // |
6305 | 0 | // Note that URI should start with "url=" but we allow omission |
6306 | 0 | // |
6307 | 0 | // "" || ";" || "," |
6308 | 0 | // empty string. use the currently loaded URI |
6309 | 0 | // and refresh immediately. |
6310 | 0 | // "X" || "X;" || "X," |
6311 | 0 | // Refresh the currently loaded URI in X seconds. |
6312 | 0 | // "X; URI" || "X, URI" |
6313 | 0 | // Refresh using URI as the destination in X seconds. |
6314 | 0 | // "URI" || "; URI" || ", URI" |
6315 | 0 | // Refresh immediately using URI as the destination. |
6316 | 0 | // |
6317 | 0 | // Currently, anything immediately following the URI, if |
6318 | 0 | // separated by any char in the set "'\"\t\r\n " will be |
6319 | 0 | // ignored. So "10; url=go.html ; foo=bar" will work, |
6320 | 0 | // and so will "10; url='go.html'; foo=bar". However, |
6321 | 0 | // "10; url=go.html; foo=bar" will result in the uri |
6322 | 0 | // "go.html;" since ';' and ',' are valid uri characters. |
6323 | 0 | // |
6324 | 0 | // Note that we need to remove any tokens wrapping the URI. |
6325 | 0 | // These tokens currently include spaces, double and single |
6326 | 0 | // quotes. |
6327 | 0 |
|
6328 | 0 | // when done, seconds is 0 or the given number of seconds |
6329 | 0 | // uriAttrib is empty or the URI specified |
6330 | 0 | MOZ_ASSERT(aPrincipal); |
6331 | 0 |
|
6332 | 0 | nsAutoCString uriAttrib; |
6333 | 0 | int32_t seconds = 0; |
6334 | 0 | bool specifiesSeconds = false; |
6335 | 0 |
|
6336 | 0 | nsACString::const_iterator iter, tokenStart, doneIterating; |
6337 | 0 |
|
6338 | 0 | aHeader.BeginReading(iter); |
6339 | 0 | aHeader.EndReading(doneIterating); |
6340 | 0 |
|
6341 | 0 | // skip leading whitespace |
6342 | 0 | while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) { |
6343 | 0 | ++iter; |
6344 | 0 | } |
6345 | 0 |
|
6346 | 0 | tokenStart = iter; |
6347 | 0 |
|
6348 | 0 | // skip leading + and - |
6349 | 0 | if (iter != doneIterating && (*iter == '-' || *iter == '+')) { |
6350 | 0 | ++iter; |
6351 | 0 | } |
6352 | 0 |
|
6353 | 0 | // parse number |
6354 | 0 | while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) { |
6355 | 0 | seconds = seconds * 10 + (*iter - '0'); |
6356 | 0 | specifiesSeconds = true; |
6357 | 0 | ++iter; |
6358 | 0 | } |
6359 | 0 |
|
6360 | 0 | if (iter != doneIterating) { |
6361 | 0 | // if we started with a '-', number is negative |
6362 | 0 | if (*tokenStart == '-') { |
6363 | 0 | seconds = -seconds; |
6364 | 0 | } |
6365 | 0 |
|
6366 | 0 | // skip to next ';' or ',' |
6367 | 0 | nsACString::const_iterator iterAfterDigit = iter; |
6368 | 0 | while (iter != doneIterating && !(*iter == ';' || *iter == ',')) { |
6369 | 0 | if (specifiesSeconds) { |
6370 | 0 | // Non-whitespace characters here mean that the string is |
6371 | 0 | // malformed but tolerate sites that specify a decimal point, |
6372 | 0 | // even though meta refresh only works on whole seconds. |
6373 | 0 | if (iter == iterAfterDigit && |
6374 | 0 | !nsCRT::IsAsciiSpace(*iter) && *iter != '.') { |
6375 | 0 | // The characters between the seconds and the next |
6376 | 0 | // section are just garbage! |
6377 | 0 | // e.g. content="2a0z+,URL=http://www.mozilla.org/" |
6378 | 0 | // Just ignore this redirect. |
6379 | 0 | return NS_ERROR_FAILURE; |
6380 | 0 | } else if (nsCRT::IsAsciiSpace(*iter)) { |
6381 | 0 | // We've had at least one whitespace so tolerate the mistake |
6382 | 0 | // and drop through. |
6383 | 0 | // e.g. content="10 foo" |
6384 | 0 | ++iter; |
6385 | 0 | break; |
6386 | 0 | } |
6387 | 0 | } |
6388 | 0 | ++iter; |
6389 | 0 | } |
6390 | 0 |
|
6391 | 0 | // skip any remaining whitespace |
6392 | 0 | while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) { |
6393 | 0 | ++iter; |
6394 | 0 | } |
6395 | 0 |
|
6396 | 0 | // skip ';' or ',' |
6397 | 0 | if (iter != doneIterating && (*iter == ';' || *iter == ',')) { |
6398 | 0 | ++iter; |
6399 | 0 | } |
6400 | 0 |
|
6401 | 0 | // skip whitespace |
6402 | 0 | while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) { |
6403 | 0 | ++iter; |
6404 | 0 | } |
6405 | 0 | } |
6406 | 0 |
|
6407 | 0 | // possible start of URI |
6408 | 0 | tokenStart = iter; |
6409 | 0 |
|
6410 | 0 | // skip "url = " to real start of URI |
6411 | 0 | if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) { |
6412 | 0 | ++iter; |
6413 | 0 | if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) { |
6414 | 0 | ++iter; |
6415 | 0 | if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) { |
6416 | 0 | ++iter; |
6417 | 0 |
|
6418 | 0 | // skip whitespace |
6419 | 0 | while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) { |
6420 | 0 | ++iter; |
6421 | 0 | } |
6422 | 0 |
|
6423 | 0 | if (iter != doneIterating && *iter == '=') { |
6424 | 0 | ++iter; |
6425 | 0 |
|
6426 | 0 | // skip whitespace |
6427 | 0 | while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) { |
6428 | 0 | ++iter; |
6429 | 0 | } |
6430 | 0 |
|
6431 | 0 | // found real start of URI |
6432 | 0 | tokenStart = iter; |
6433 | 0 | } |
6434 | 0 | } |
6435 | 0 | } |
6436 | 0 | } |
6437 | 0 |
|
6438 | 0 | // skip a leading '"' or '\''. |
6439 | 0 |
|
6440 | 0 | bool isQuotedURI = false; |
6441 | 0 | if (tokenStart != doneIterating && |
6442 | 0 | (*tokenStart == '"' || *tokenStart == '\'')) { |
6443 | 0 | isQuotedURI = true; |
6444 | 0 | ++tokenStart; |
6445 | 0 | } |
6446 | 0 |
|
6447 | 0 | // set iter to start of URI |
6448 | 0 | iter = tokenStart; |
6449 | 0 |
|
6450 | 0 | // tokenStart here points to the beginning of URI |
6451 | 0 |
|
6452 | 0 | // grab the rest of the URI |
6453 | 0 | while (iter != doneIterating) { |
6454 | 0 | if (isQuotedURI && (*iter == '"' || *iter == '\'')) { |
6455 | 0 | break; |
6456 | 0 | } |
6457 | 0 | ++iter; |
6458 | 0 | } |
6459 | 0 |
|
6460 | 0 | // move iter one back if the last character is a '"' or '\'' |
6461 | 0 | if (iter != tokenStart && isQuotedURI) { |
6462 | 0 | --iter; |
6463 | 0 | if (!(*iter == '"' || *iter == '\'')) { |
6464 | 0 | ++iter; |
6465 | 0 | } |
6466 | 0 | } |
6467 | 0 |
|
6468 | 0 | // URI is whatever's contained from tokenStart to iter. |
6469 | 0 | // note: if tokenStart == doneIterating, so is iter. |
6470 | 0 |
|
6471 | 0 | nsresult rv = NS_OK; |
6472 | 0 |
|
6473 | 0 | nsCOMPtr<nsIURI> uri; |
6474 | 0 | bool specifiesURI = false; |
6475 | 0 | if (tokenStart == iter) { |
6476 | 0 | uri = aBaseURI; |
6477 | 0 | } else { |
6478 | 0 | uriAttrib = Substring(tokenStart, iter); |
6479 | 0 | // NS_NewURI takes care of any whitespace surrounding the URL |
6480 | 0 | rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI); |
6481 | 0 | specifiesURI = true; |
6482 | 0 | } |
6483 | 0 |
|
6484 | 0 | // No URI or seconds were specified |
6485 | 0 | if (!specifiesSeconds && !specifiesURI) { |
6486 | 0 | // Do nothing because the alternative is to spin around in a refresh |
6487 | 0 | // loop forever! |
6488 | 0 | return NS_ERROR_FAILURE; |
6489 | 0 | } |
6490 | 0 | |
6491 | 0 | if (NS_SUCCEEDED(rv)) { |
6492 | 0 | nsCOMPtr<nsIScriptSecurityManager> securityManager( |
6493 | 0 | do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); |
6494 | 0 | if (NS_SUCCEEDED(rv)) { |
6495 | 0 | rv = securityManager->CheckLoadURIWithPrincipal( |
6496 | 0 | aPrincipal, uri, |
6497 | 0 | nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT); |
6498 | 0 |
|
6499 | 0 | if (NS_SUCCEEDED(rv)) { |
6500 | 0 | bool isjs = true; |
6501 | 0 | rv = NS_URIChainHasFlags( |
6502 | 0 | uri, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs); |
6503 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6504 | 0 |
|
6505 | 0 | if (isjs) { |
6506 | 0 | return NS_ERROR_FAILURE; |
6507 | 0 | } |
6508 | 0 | } |
6509 | 0 | |
6510 | 0 | if (NS_SUCCEEDED(rv)) { |
6511 | 0 | // Since we can't travel back in time yet, just pretend |
6512 | 0 | // negative numbers do nothing at all. |
6513 | 0 | if (seconds < 0) { |
6514 | 0 | return NS_ERROR_FAILURE; |
6515 | 0 | } |
6516 | 0 | |
6517 | 0 | rv = RefreshURI(uri, aPrincipal, seconds * 1000, false, true); |
6518 | 0 | } |
6519 | 0 | } |
6520 | 0 | } |
6521 | 0 | return rv; |
6522 | 0 | } |
6523 | | |
6524 | | NS_IMETHODIMP |
6525 | | nsDocShell::SetupRefreshURI(nsIChannel* aChannel) |
6526 | 0 | { |
6527 | 0 | nsresult rv; |
6528 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv)); |
6529 | 0 | if (NS_SUCCEEDED(rv)) { |
6530 | 0 | nsAutoCString refreshHeader; |
6531 | 0 | rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"), |
6532 | 0 | refreshHeader); |
6533 | 0 |
|
6534 | 0 | if (!refreshHeader.IsEmpty()) { |
6535 | 0 | nsCOMPtr<nsIScriptSecurityManager> secMan = |
6536 | 0 | do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); |
6537 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6538 | 0 |
|
6539 | 0 | nsCOMPtr<nsIPrincipal> principal; |
6540 | 0 | rv = secMan->GetChannelResultPrincipal(aChannel, |
6541 | 0 | getter_AddRefs(principal)); |
6542 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6543 | 0 |
|
6544 | 0 | SetupReferrerFromChannel(aChannel); |
6545 | 0 | rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader); |
6546 | 0 | if (NS_SUCCEEDED(rv)) { |
6547 | 0 | return NS_REFRESHURI_HEADER_FOUND; |
6548 | 0 | } |
6549 | 0 | } |
6550 | 0 | } |
6551 | 0 | return rv; |
6552 | 0 | } |
6553 | | |
6554 | | static void |
6555 | | DoCancelRefreshURITimers(nsIMutableArray* aTimerList) |
6556 | 0 | { |
6557 | 0 | if (!aTimerList) { |
6558 | 0 | return; |
6559 | 0 | } |
6560 | 0 | |
6561 | 0 | uint32_t n = 0; |
6562 | 0 | aTimerList->GetLength(&n); |
6563 | 0 |
|
6564 | 0 | while (n) { |
6565 | 0 | nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n)); |
6566 | 0 |
|
6567 | 0 | aTimerList->RemoveElementAt(n); // bye bye owning timer ref |
6568 | 0 |
|
6569 | 0 | if (timer) { |
6570 | 0 | timer->Cancel(); |
6571 | 0 | } |
6572 | 0 | } |
6573 | 0 | } |
6574 | | |
6575 | | NS_IMETHODIMP |
6576 | | nsDocShell::CancelRefreshURITimers() |
6577 | 0 | { |
6578 | 0 | DoCancelRefreshURITimers(mRefreshURIList); |
6579 | 0 | DoCancelRefreshURITimers(mSavedRefreshURIList); |
6580 | 0 | mRefreshURIList = nullptr; |
6581 | 0 | mSavedRefreshURIList = nullptr; |
6582 | 0 |
|
6583 | 0 | return NS_OK; |
6584 | 0 | } |
6585 | | |
6586 | | NS_IMETHODIMP |
6587 | | nsDocShell::GetRefreshPending(bool* aResult) |
6588 | 0 | { |
6589 | 0 | if (!mRefreshURIList) { |
6590 | 0 | *aResult = false; |
6591 | 0 | return NS_OK; |
6592 | 0 | } |
6593 | 0 | |
6594 | 0 | uint32_t count; |
6595 | 0 | nsresult rv = mRefreshURIList->GetLength(&count); |
6596 | 0 | if (NS_SUCCEEDED(rv)) { |
6597 | 0 | *aResult = (count != 0); |
6598 | 0 | } |
6599 | 0 | return rv; |
6600 | 0 | } |
6601 | | |
6602 | | NS_IMETHODIMP |
6603 | | nsDocShell::SuspendRefreshURIs() |
6604 | 0 | { |
6605 | 0 | if (mRefreshURIList) { |
6606 | 0 | uint32_t n = 0; |
6607 | 0 | mRefreshURIList->GetLength(&n); |
6608 | 0 |
|
6609 | 0 | for (uint32_t i = 0; i < n; ++i) { |
6610 | 0 | nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i); |
6611 | 0 | if (!timer) { |
6612 | 0 | continue; // this must be a nsRefreshURI already |
6613 | 0 | } |
6614 | 0 | |
6615 | 0 | // Replace this timer object with a nsRefreshTimer object. |
6616 | 0 | nsCOMPtr<nsITimerCallback> callback; |
6617 | 0 | timer->GetCallback(getter_AddRefs(callback)); |
6618 | 0 |
|
6619 | 0 | timer->Cancel(); |
6620 | 0 |
|
6621 | 0 | nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback); |
6622 | 0 | NS_ASSERTION(rt, |
6623 | 0 | "RefreshURIList timer callbacks should only be RefreshTimer objects"); |
6624 | 0 |
|
6625 | 0 | mRefreshURIList->ReplaceElementAt(rt, i); |
6626 | 0 | } |
6627 | 0 | } |
6628 | 0 |
|
6629 | 0 | // Suspend refresh URIs for our child shells as well. |
6630 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
6631 | 0 | while (iter.HasMore()) { |
6632 | 0 | nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
6633 | 0 | if (shell) { |
6634 | 0 | shell->SuspendRefreshURIs(); |
6635 | 0 | } |
6636 | 0 | } |
6637 | 0 |
|
6638 | 0 | return NS_OK; |
6639 | 0 | } |
6640 | | |
6641 | | NS_IMETHODIMP |
6642 | | nsDocShell::ResumeRefreshURIs() |
6643 | 0 | { |
6644 | 0 | RefreshURIFromQueue(); |
6645 | 0 |
|
6646 | 0 | // Resume refresh URIs for our child shells as well. |
6647 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
6648 | 0 | while (iter.HasMore()) { |
6649 | 0 | nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
6650 | 0 | if (shell) { |
6651 | 0 | shell->ResumeRefreshURIs(); |
6652 | 0 | } |
6653 | 0 | } |
6654 | 0 |
|
6655 | 0 | return NS_OK; |
6656 | 0 | } |
6657 | | |
6658 | | nsresult |
6659 | | nsDocShell::RefreshURIFromQueue() |
6660 | 0 | { |
6661 | 0 | if (!mRefreshURIList) { |
6662 | 0 | return NS_OK; |
6663 | 0 | } |
6664 | 0 | uint32_t n = 0; |
6665 | 0 | mRefreshURIList->GetLength(&n); |
6666 | 0 |
|
6667 | 0 | while (n) { |
6668 | 0 | nsCOMPtr<nsITimerCallback> refreshInfo = |
6669 | 0 | do_QueryElementAt(mRefreshURIList, --n); |
6670 | 0 |
|
6671 | 0 | if (refreshInfo) { |
6672 | 0 | // This is the nsRefreshTimer object, waiting to be |
6673 | 0 | // setup in a timer object and fired. |
6674 | 0 | // Create the timer and trigger it. |
6675 | 0 | uint32_t delay = |
6676 | 0 | static_cast<nsRefreshTimer*>( |
6677 | 0 | static_cast<nsITimerCallback*>(refreshInfo))->GetDelay(); |
6678 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
6679 | 0 | if (win) { |
6680 | 0 | nsCOMPtr<nsITimer> timer; |
6681 | 0 | NS_NewTimerWithCallback(getter_AddRefs(timer), |
6682 | 0 | refreshInfo, delay, nsITimer::TYPE_ONE_SHOT, |
6683 | 0 | win->TabGroup()->EventTargetFor(TaskCategory::Network)); |
6684 | 0 |
|
6685 | 0 | if (timer) { |
6686 | 0 | // Replace the nsRefreshTimer element in the queue with |
6687 | 0 | // its corresponding timer object, so that in case another |
6688 | 0 | // load comes through before the timer can go off, the timer will |
6689 | 0 | // get cancelled in CancelRefreshURITimer() |
6690 | 0 | mRefreshURIList->ReplaceElementAt(timer, n); |
6691 | 0 | } |
6692 | 0 | } |
6693 | 0 | } |
6694 | 0 | } |
6695 | 0 |
|
6696 | 0 | return NS_OK; |
6697 | 0 | } |
6698 | | |
6699 | | nsresult |
6700 | | nsDocShell::Embed(nsIContentViewer* aContentViewer, |
6701 | | const char* aCommand, nsISupports* aExtraInfo) |
6702 | 0 | { |
6703 | 0 | // Save the LayoutHistoryState of the previous document, before |
6704 | 0 | // setting up new document |
6705 | 0 | PersistLayoutHistoryState(); |
6706 | 0 |
|
6707 | 0 | nsresult rv = SetupNewViewer(aContentViewer); |
6708 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
6709 | 0 |
|
6710 | 0 | // If we are loading a wyciwyg url from history, change the base URI for |
6711 | 0 | // the document to the original http url that created the document.write(). |
6712 | 0 | // This makes sure that all relative urls in a document.written page loaded |
6713 | 0 | // via history work properly. |
6714 | 0 | if (mCurrentURI && |
6715 | 0 | (mLoadType & LOAD_CMD_HISTORY || |
6716 | 0 | mLoadType == LOAD_RELOAD_NORMAL || |
6717 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE || |
6718 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE || |
6719 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE)) { |
6720 | 0 | bool isWyciwyg = false; |
6721 | 0 | // Check if the url is wyciwyg |
6722 | 0 | rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg); |
6723 | 0 | if (isWyciwyg && NS_SUCCEEDED(rv)) { |
6724 | 0 | SetBaseUrlForWyciwyg(aContentViewer); |
6725 | 0 | } |
6726 | 0 | } |
6727 | 0 | // XXX What if SetupNewViewer fails? |
6728 | 0 | if (mLSHE) { |
6729 | 0 | // Restore the editing state, if it's stored in session history. |
6730 | 0 | if (mLSHE->HasDetachedEditor()) { |
6731 | 0 | ReattachEditorToWindow(mLSHE); |
6732 | 0 | } |
6733 | 0 | // Set history.state |
6734 | 0 | SetDocCurrentStateObj(mLSHE); |
6735 | 0 |
|
6736 | 0 | SetHistoryEntry(&mOSHE, mLSHE); |
6737 | 0 | } |
6738 | 0 |
|
6739 | 0 | bool updateHistory = true; |
6740 | 0 |
|
6741 | 0 | // Determine if this type of load should update history |
6742 | 0 | switch (mLoadType) { |
6743 | 0 | case LOAD_NORMAL_REPLACE: |
6744 | 0 | case LOAD_STOP_CONTENT_AND_REPLACE: |
6745 | 0 | case LOAD_RELOAD_BYPASS_CACHE: |
6746 | 0 | case LOAD_RELOAD_BYPASS_PROXY: |
6747 | 0 | case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
6748 | 0 | case LOAD_REPLACE_BYPASS_CACHE: |
6749 | 0 | updateHistory = false; |
6750 | 0 | break; |
6751 | 0 | default: |
6752 | 0 | break; |
6753 | 0 | } |
6754 | 0 | |
6755 | 0 | if (!updateHistory) { |
6756 | 0 | SetLayoutHistoryState(nullptr); |
6757 | 0 | } |
6758 | 0 |
|
6759 | 0 | return NS_OK; |
6760 | 0 | } |
6761 | | |
6762 | | |
6763 | | //***************************************************************************** |
6764 | | // nsDocShell::nsIWebProgressListener |
6765 | | //***************************************************************************** |
6766 | | |
6767 | | NS_IMETHODIMP |
6768 | | nsDocShell::OnProgressChange(nsIWebProgress* aProgress, |
6769 | | nsIRequest* aRequest, |
6770 | | int32_t aCurSelfProgress, |
6771 | | int32_t aMaxSelfProgress, |
6772 | | int32_t aCurTotalProgress, |
6773 | | int32_t aMaxTotalProgress) |
6774 | 0 | { |
6775 | 0 | return NS_OK; |
6776 | 0 | } |
6777 | | |
6778 | | NS_IMETHODIMP |
6779 | | nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest, |
6780 | | uint32_t aStateFlags, nsresult aStatus) |
6781 | 0 | { |
6782 | 0 | if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) { |
6783 | 0 | // Save timing statistics. |
6784 | 0 | nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
6785 | 0 | nsCOMPtr<nsIURI> uri; |
6786 | 0 | channel->GetURI(getter_AddRefs(uri)); |
6787 | 0 | nsAutoCString aURI; |
6788 | 0 | uri->GetAsciiSpec(aURI); |
6789 | 0 |
|
6790 | 0 | nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest)); |
6791 | 0 | nsCOMPtr<nsIWebProgress> webProgress = |
6792 | 0 | do_QueryInterface(GetAsSupports(this)); |
6793 | 0 |
|
6794 | 0 | // We don't update navigation timing for wyciwyg channels |
6795 | 0 | if (this == aProgress && !wcwgChannel) { |
6796 | 0 | mozilla::Unused << MaybeInitTiming(); |
6797 | 0 | mTiming->NotifyFetchStart(uri, |
6798 | 0 | ConvertLoadTypeToNavigationType(mLoadType)); |
6799 | 0 | } |
6800 | 0 |
|
6801 | 0 | // Was the wyciwyg document loaded on this docshell? |
6802 | 0 | if (wcwgChannel && !mLSHE && (mItemType == typeContent) && |
6803 | 0 | aProgress == webProgress.get()) { |
6804 | 0 | bool equalUri = true; |
6805 | 0 | // Store the wyciwyg url in session history, only if it is |
6806 | 0 | // being loaded fresh for the first time. We don't want |
6807 | 0 | // multiple entries for successive loads |
6808 | 0 | if (mCurrentURI && |
6809 | 0 | NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) && |
6810 | 0 | !equalUri) { |
6811 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
6812 | 0 | GetSameTypeParent(getter_AddRefs(parentAsItem)); |
6813 | 0 | nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem)); |
6814 | 0 | bool inOnLoadHandler = false; |
6815 | 0 | if (parentDS) { |
6816 | 0 | parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
6817 | 0 | } |
6818 | 0 | if (inOnLoadHandler) { |
6819 | 0 | // We're handling parent's load event listener, which causes |
6820 | 0 | // document.write in a subdocument. |
6821 | 0 | // Need to clear the session history for all child |
6822 | 0 | // docshells so that we can handle them like they would |
6823 | 0 | // all be added dynamically. |
6824 | 0 | nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem); |
6825 | 0 | if (parent) { |
6826 | 0 | bool oshe = false; |
6827 | 0 | nsCOMPtr<nsISHEntry> entry; |
6828 | 0 | parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe); |
6829 | 0 | static_cast<nsDocShell*>(parent.get())->ClearFrameHistory(entry); |
6830 | 0 | } |
6831 | 0 | } |
6832 | 0 |
|
6833 | 0 | // This is a document.write(). Get the made-up url |
6834 | 0 | // from the channel and store it in session history. |
6835 | 0 | // Pass false for aCloneChildren, since we're creating |
6836 | 0 | // a new DOM here. |
6837 | 0 | AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, false, |
6838 | 0 | getter_AddRefs(mLSHE)); |
6839 | 0 | SetCurrentURI(uri, aRequest, true, 0); |
6840 | 0 | // Save history state of the previous page |
6841 | 0 | PersistLayoutHistoryState(); |
6842 | 0 | // We'll never get an Embed() for this load, so just go ahead |
6843 | 0 | // and SetHistoryEntry now. |
6844 | 0 | SetHistoryEntry(&mOSHE, mLSHE); |
6845 | 0 | } |
6846 | 0 | } |
6847 | 0 | // Page has begun to load |
6848 | 0 | mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD; |
6849 | 0 |
|
6850 | 0 | if ((aStateFlags & STATE_RESTORING) == 0) { |
6851 | 0 | // Show the progress cursor if the pref is set |
6852 | 0 | if (nsContentUtils::UseActivityCursor()) { |
6853 | 0 | nsCOMPtr<nsIWidget> mainWidget; |
6854 | 0 | GetMainWidget(getter_AddRefs(mainWidget)); |
6855 | 0 | if (mainWidget) { |
6856 | 0 | mainWidget->SetCursor(eCursor_spinning); |
6857 | 0 | } |
6858 | 0 | } |
6859 | 0 | } |
6860 | 0 | } else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) { |
6861 | 0 | // Page is loading |
6862 | 0 | mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING; |
6863 | 0 | } else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) { |
6864 | 0 | // Page has finished loading |
6865 | 0 | mBusyFlags = BUSY_FLAGS_NONE; |
6866 | 0 |
|
6867 | 0 | // Hide the progress cursor if the pref is set |
6868 | 0 | if (nsContentUtils::UseActivityCursor()) { |
6869 | 0 | nsCOMPtr<nsIWidget> mainWidget; |
6870 | 0 | GetMainWidget(getter_AddRefs(mainWidget)); |
6871 | 0 | if (mainWidget) { |
6872 | 0 | mainWidget->SetCursor(eCursor_standard); |
6873 | 0 | } |
6874 | 0 | } |
6875 | 0 | } |
6876 | 0 | if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) { |
6877 | 0 | nsCOMPtr<nsIWebProgress> webProgress = |
6878 | 0 | do_QueryInterface(GetAsSupports(this)); |
6879 | 0 | // Is the document stop notification for this document? |
6880 | 0 | if (aProgress == webProgress.get()) { |
6881 | 0 | nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
6882 | 0 | EndPageLoad(aProgress, channel, aStatus); |
6883 | 0 | } |
6884 | 0 | } |
6885 | 0 | // note that redirect state changes will go through here as well, but it |
6886 | 0 | // is better to handle those in OnRedirectStateChange where more |
6887 | 0 | // information is available. |
6888 | 0 | return NS_OK; |
6889 | 0 | } |
6890 | | |
6891 | | NS_IMETHODIMP |
6892 | | nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest, |
6893 | | nsIURI* aURI, uint32_t aFlags) |
6894 | 0 | { |
6895 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
6896 | 0 | return NS_OK; |
6897 | 0 | } |
6898 | | |
6899 | | void |
6900 | | nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, |
6901 | | nsIChannel* aNewChannel, |
6902 | | uint32_t aRedirectFlags, |
6903 | | uint32_t aStateFlags) |
6904 | 0 | { |
6905 | 0 | NS_ASSERTION(aStateFlags & STATE_REDIRECTING, |
6906 | 0 | "Calling OnRedirectStateChange when there is no redirect"); |
6907 | 0 |
|
6908 | 0 | // If mixed content is allowed for the old channel, we forward |
6909 | 0 | // the permission to the new channel if it has the same origin |
6910 | 0 | // as the old one. |
6911 | 0 | if (mMixedContentChannel && mMixedContentChannel == aOldChannel) { |
6912 | 0 | nsresult rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, aNewChannel); |
6913 | 0 | if (NS_SUCCEEDED(rv)) { |
6914 | 0 | SetMixedContentChannel(aNewChannel); // Same origin: forward permission. |
6915 | 0 | } else { |
6916 | 0 | SetMixedContentChannel(nullptr); // Different origin: clear mMixedContentChannel. |
6917 | 0 | } |
6918 | 0 | } |
6919 | 0 |
|
6920 | 0 | if (!(aStateFlags & STATE_IS_DOCUMENT)) { |
6921 | 0 | return; // not a toplevel document |
6922 | 0 | } |
6923 | 0 | |
6924 | 0 | nsCOMPtr<nsIURI> oldURI, newURI; |
6925 | 0 | aOldChannel->GetURI(getter_AddRefs(oldURI)); |
6926 | 0 | aNewChannel->GetURI(getter_AddRefs(newURI)); |
6927 | 0 | if (!oldURI || !newURI) { |
6928 | 0 | return; |
6929 | 0 | } |
6930 | 0 | |
6931 | 0 | // Below a URI visit is saved (see AddURIVisit method doc). |
6932 | 0 | // The visit chain looks something like: |
6933 | 0 | // ... |
6934 | 0 | // Site N - 1 |
6935 | 0 | // => Site N |
6936 | 0 | // (redirect to =>) Site N + 1 (we are here!) |
6937 | 0 | |
6938 | 0 | // Get N - 1 and transition type |
6939 | 0 | nsCOMPtr<nsIURI> previousURI; |
6940 | 0 | uint32_t previousFlags = 0; |
6941 | 0 | ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags); |
6942 | 0 |
|
6943 | 0 | if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL || |
6944 | 0 | ChannelIsPost(aOldChannel)) { |
6945 | 0 | // 1. Internal redirects are ignored because they are specific to the |
6946 | 0 | // channel implementation. |
6947 | 0 | // 2. POSTs are not saved by global history. |
6948 | 0 | // |
6949 | 0 | // Regardless, we need to propagate the previous visit to the new |
6950 | 0 | // channel. |
6951 | 0 | SaveLastVisit(aNewChannel, previousURI, previousFlags); |
6952 | 0 | } else { |
6953 | 0 | nsCOMPtr<nsIURI> referrer; |
6954 | 0 | // Treat referrer as null if there is an error getting it. |
6955 | 0 | (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer)); |
6956 | 0 |
|
6957 | 0 | // Get the HTTP response code, if available. |
6958 | 0 | uint32_t responseStatus = 0; |
6959 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel); |
6960 | 0 | if (httpChannel) { |
6961 | 0 | Unused << httpChannel->GetResponseStatus(&responseStatus); |
6962 | 0 | } |
6963 | 0 |
|
6964 | 0 | // Add visit N -1 => N |
6965 | 0 | AddURIVisit(oldURI, referrer, previousURI, previousFlags, responseStatus); |
6966 | 0 |
|
6967 | 0 | // Since N + 1 could be the final destination, we will not save N => N + 1 |
6968 | 0 | // here. OnNewURI will do that, so we will cache it. |
6969 | 0 | SaveLastVisit(aNewChannel, oldURI, aRedirectFlags); |
6970 | 0 | } |
6971 | 0 |
|
6972 | 0 | // check if the new load should go through the application cache. |
6973 | 0 | nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
6974 | 0 | do_QueryInterface(aNewChannel); |
6975 | 0 | if (appCacheChannel) { |
6976 | 0 | if (GeckoProcessType_Default != XRE_GetProcessType()) { |
6977 | 0 | // Permission will be checked in the parent process. |
6978 | 0 | appCacheChannel->SetChooseApplicationCache(true); |
6979 | 0 | } else { |
6980 | 0 | nsCOMPtr<nsIScriptSecurityManager> secMan = |
6981 | 0 | do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
6982 | 0 |
|
6983 | 0 | if (secMan) { |
6984 | 0 | nsCOMPtr<nsIPrincipal> principal; |
6985 | 0 | secMan->GetDocShellCodebasePrincipal(newURI, this, |
6986 | 0 | getter_AddRefs(principal)); |
6987 | 0 | appCacheChannel->SetChooseApplicationCache( |
6988 | 0 | NS_ShouldCheckAppCache(principal)); |
6989 | 0 | } |
6990 | 0 | } |
6991 | 0 | } |
6992 | 0 |
|
6993 | 0 | if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && |
6994 | 0 | mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) { |
6995 | 0 | mLoadType = LOAD_NORMAL_REPLACE; |
6996 | 0 | SetHistoryEntry(&mLSHE, nullptr); |
6997 | 0 | } |
6998 | 0 | } |
6999 | | |
7000 | | NS_IMETHODIMP |
7001 | | nsDocShell::OnStatusChange(nsIWebProgress* aWebProgress, |
7002 | | nsIRequest* aRequest, |
7003 | | nsresult aStatus, const char16_t* aMessage) |
7004 | 0 | { |
7005 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
7006 | 0 | return NS_OK; |
7007 | 0 | } |
7008 | | |
7009 | | NS_IMETHODIMP |
7010 | | nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress, |
7011 | | nsIRequest* aRequest, uint32_t aState) |
7012 | 0 | { |
7013 | 0 | MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)"); |
7014 | 0 | return NS_OK; |
7015 | 0 | } |
7016 | | |
7017 | | nsresult |
7018 | | nsDocShell::EndPageLoad(nsIWebProgress* aProgress, |
7019 | | nsIChannel* aChannel, nsresult aStatus) |
7020 | 0 | { |
7021 | 0 | if (!aChannel) { |
7022 | 0 | return NS_ERROR_NULL_POINTER; |
7023 | 0 | } |
7024 | 0 | |
7025 | 0 | // Make sure to discard the initial client if we never created the initial |
7026 | 0 | // about:blank document. Do this before possibly returning from the method |
7027 | 0 | // due to an error. |
7028 | 0 | mInitialClientSource.reset(); |
7029 | 0 |
|
7030 | 0 | nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel); |
7031 | 0 | if (reporter) { |
7032 | 0 | nsCOMPtr<nsILoadGroup> loadGroup; |
7033 | 0 | aChannel->GetLoadGroup(getter_AddRefs(loadGroup)); |
7034 | 0 | if (loadGroup) { |
7035 | 0 | reporter->FlushConsoleReports(loadGroup); |
7036 | 0 | } else { |
7037 | 0 | reporter->FlushConsoleReports(GetDocument()); |
7038 | 0 | } |
7039 | 0 | } |
7040 | 0 |
|
7041 | 0 | nsCOMPtr<nsIURI> url; |
7042 | 0 | nsresult rv = aChannel->GetURI(getter_AddRefs(url)); |
7043 | 0 | if (NS_FAILED(rv)) { |
7044 | 0 | return rv; |
7045 | 0 | } |
7046 | 0 | |
7047 | 0 | nsCOMPtr<nsITimedChannel> timingChannel = do_QueryInterface(aChannel); |
7048 | 0 | if (timingChannel) { |
7049 | 0 | TimeStamp channelCreationTime; |
7050 | 0 | rv = timingChannel->GetChannelCreation(&channelCreationTime); |
7051 | 0 | if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) { |
7052 | 0 | Telemetry::AccumulateTimeDelta(Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME, |
7053 | 0 | channelCreationTime); |
7054 | 0 | nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup = |
7055 | 0 | do_QueryInterface(mLoadGroup); |
7056 | 0 | if (internalLoadGroup) { |
7057 | 0 | internalLoadGroup->OnEndPageLoad(aChannel); |
7058 | 0 | } |
7059 | 0 | } |
7060 | 0 | } |
7061 | 0 |
|
7062 | 0 | // Timing is picked up by the window, we don't need it anymore |
7063 | 0 | mTiming = nullptr; |
7064 | 0 |
|
7065 | 0 | // clean up reload state for meta charset |
7066 | 0 | if (eCharsetReloadRequested == mCharsetReloadState) { |
7067 | 0 | mCharsetReloadState = eCharsetReloadStopOrigional; |
7068 | 0 | } else { |
7069 | 0 | mCharsetReloadState = eCharsetReloadInit; |
7070 | 0 | } |
7071 | 0 |
|
7072 | 0 | // Save a pointer to the currently-loading history entry. |
7073 | 0 | // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history |
7074 | 0 | // entry further down in this method. |
7075 | 0 | nsCOMPtr<nsISHEntry> loadingSHE = mLSHE; |
7076 | 0 | mozilla::Unused << loadingSHE; // XXX: Not sure if we need this anymore |
7077 | 0 |
|
7078 | 0 | // |
7079 | 0 | // one of many safeguards that prevent death and destruction if |
7080 | 0 | // someone is so very very rude as to bring this window down |
7081 | 0 | // during this load handler. |
7082 | 0 | // |
7083 | 0 | nsCOMPtr<nsIDocShell> kungFuDeathGrip(this); |
7084 | 0 |
|
7085 | 0 | // Notify the ContentViewer that the Document has finished loading. This |
7086 | 0 | // will cause any OnLoad(...) and PopState(...) handlers to fire. |
7087 | 0 | if (!mEODForCurrentDocument && mContentViewer) { |
7088 | 0 | mIsExecutingOnLoadHandler = true; |
7089 | 0 | mContentViewer->LoadComplete(aStatus); |
7090 | 0 | mIsExecutingOnLoadHandler = false; |
7091 | 0 |
|
7092 | 0 | mEODForCurrentDocument = true; |
7093 | 0 |
|
7094 | 0 | // If all documents have completed their loading |
7095 | 0 | // favor native event dispatch priorities |
7096 | 0 | // over performance |
7097 | 0 | if (--gNumberOfDocumentsLoading == 0) { |
7098 | 0 | // Hint to use normal native event dispatch priorities |
7099 | 0 | FavorPerformanceHint(false); |
7100 | 0 | } |
7101 | 0 | } |
7102 | 0 | /* Check if the httpChannel has any cache-control related response headers, |
7103 | 0 | * like no-store, no-cache. If so, update SHEntry so that |
7104 | 0 | * when a user goes back/forward to this page, we appropriately do |
7105 | 0 | * form value restoration or load from server. |
7106 | 0 | */ |
7107 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
7108 | 0 | if (!httpChannel) { |
7109 | 0 | // HttpChannel could be hiding underneath a Multipart channel. |
7110 | 0 | GetHttpChannel(aChannel, getter_AddRefs(httpChannel)); |
7111 | 0 | } |
7112 | 0 |
|
7113 | 0 | if (httpChannel) { |
7114 | 0 | // figure out if SH should be saving layout state. |
7115 | 0 | bool discardLayoutState = ShouldDiscardLayoutState(httpChannel); |
7116 | 0 | if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) && |
7117 | 0 | (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) { |
7118 | 0 | mLSHE->SetSaveLayoutStateFlag(false); |
7119 | 0 | } |
7120 | 0 | } |
7121 | 0 |
|
7122 | 0 | // Clear mLSHE after calling the onLoadHandlers. This way, if the |
7123 | 0 | // onLoadHandler tries to load something different in |
7124 | 0 | // itself or one of its children, we can deal with it appropriately. |
7125 | 0 | if (mLSHE) { |
7126 | 0 | mLSHE->SetLoadType(LOAD_HISTORY); |
7127 | 0 |
|
7128 | 0 | // Clear the mLSHE reference to indicate document loading is done one |
7129 | 0 | // way or another. |
7130 | 0 | SetHistoryEntry(&mLSHE, nullptr); |
7131 | 0 | } |
7132 | 0 | // if there's a refresh header in the channel, this method |
7133 | 0 | // will set it up for us. |
7134 | 0 | if (mIsActive || !mDisableMetaRefreshWhenInactive) |
7135 | 0 | RefreshURIFromQueue(); |
7136 | 0 |
|
7137 | 0 | // Test whether this is the top frame or a subframe |
7138 | 0 | bool isTopFrame = true; |
7139 | 0 | nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem; |
7140 | 0 | rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem)); |
7141 | 0 | if (NS_SUCCEEDED(rv) && targetParentTreeItem) { |
7142 | 0 | isTopFrame = false; |
7143 | 0 | } |
7144 | 0 |
|
7145 | 0 | // |
7146 | 0 | // If the page load failed, then deal with the error condition... |
7147 | 0 | // Errors are handled as follows: |
7148 | 0 | // 1. Check to see if it's a file not found error or bad content |
7149 | 0 | // encoding error. |
7150 | 0 | // 2. Send the URI to a keyword server (if enabled) |
7151 | 0 | // 3. If the error was DNS failure, then add www and .com to the URI |
7152 | 0 | // (if appropriate). |
7153 | 0 | // 4. Throw an error dialog box... |
7154 | 0 | // |
7155 | 0 | if (url && NS_FAILED(aStatus)) { |
7156 | 0 | if (aStatus == NS_ERROR_FILE_NOT_FOUND || |
7157 | 0 | aStatus == NS_ERROR_FILE_ACCESS_DENIED || |
7158 | 0 | aStatus == NS_ERROR_CORRUPTED_CONTENT || |
7159 | 0 | aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) { |
7160 | 0 | DisplayLoadError(aStatus, url, nullptr, aChannel); |
7161 | 0 | return NS_OK; |
7162 | 0 | } |
7163 | 0 | |
7164 | 0 | // Handle iframe document not loading error because source was |
7165 | 0 | // a tracking URL. We make a note of this iframe node by including |
7166 | 0 | // it in a dedicated array of blocked tracking nodes under its parent |
7167 | 0 | // document. (document of parent window of blocked document) |
7168 | 0 | if (isTopFrame == false && aStatus == NS_ERROR_TRACKING_URI) { |
7169 | 0 | // frameElement is our nsIContent to be annotated |
7170 | 0 | RefPtr<Element> frameElement; |
7171 | 0 | nsPIDOMWindowOuter* thisWindow = GetWindow(); |
7172 | 0 | if (!thisWindow) { |
7173 | 0 | return NS_OK; |
7174 | 0 | } |
7175 | 0 | |
7176 | 0 | frameElement = thisWindow->GetFrameElement(); |
7177 | 0 | if (!frameElement) { |
7178 | 0 | return NS_OK; |
7179 | 0 | } |
7180 | 0 | |
7181 | 0 | // Parent window |
7182 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentItem; |
7183 | 0 | GetSameTypeParent(getter_AddRefs(parentItem)); |
7184 | 0 | if (!parentItem) { |
7185 | 0 | return NS_OK; |
7186 | 0 | } |
7187 | 0 | |
7188 | 0 | nsCOMPtr<nsIDocument> parentDoc; |
7189 | 0 | parentDoc = parentItem->GetDocument(); |
7190 | 0 | if (!parentDoc) { |
7191 | 0 | return NS_OK; |
7192 | 0 | } |
7193 | 0 | |
7194 | 0 | parentDoc->AddBlockedTrackingNode(frameElement); |
7195 | 0 |
|
7196 | 0 | return NS_OK; |
7197 | 0 | } |
7198 | 0 | |
7199 | 0 | if (sURIFixup) { |
7200 | 0 | // |
7201 | 0 | // Try and make an alternative URI from the old one |
7202 | 0 | // |
7203 | 0 | nsCOMPtr<nsIURI> newURI; |
7204 | 0 | nsCOMPtr<nsIInputStream> newPostData; |
7205 | 0 |
|
7206 | 0 | nsAutoCString oldSpec; |
7207 | 0 | url->GetSpec(oldSpec); |
7208 | 0 |
|
7209 | 0 | // |
7210 | 0 | // First try keyword fixup |
7211 | 0 | // |
7212 | 0 | nsAutoString keywordProviderName, keywordAsSent; |
7213 | 0 | if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) { |
7214 | 0 | bool keywordsEnabled = Preferences::GetBool("keyword.enabled", false); |
7215 | 0 |
|
7216 | 0 | nsAutoCString host; |
7217 | 0 | url->GetHost(host); |
7218 | 0 |
|
7219 | 0 | nsAutoCString scheme; |
7220 | 0 | url->GetScheme(scheme); |
7221 | 0 |
|
7222 | 0 | int32_t dotLoc = host.FindChar('.'); |
7223 | 0 |
|
7224 | 0 | // we should only perform a keyword search under the following |
7225 | 0 | // conditions: |
7226 | 0 | // (0) Pref keyword.enabled is true |
7227 | 0 | // (1) the url scheme is http (or https) |
7228 | 0 | // (2) the url does not have a protocol scheme |
7229 | 0 | // If we don't enforce such a policy, then we end up doing |
7230 | 0 | // keyword searchs on urls we don't intend like imap, file, |
7231 | 0 | // mailbox, etc. This could lead to a security problem where we |
7232 | 0 | // send data to the keyword server that we shouldn't be. |
7233 | 0 | // Someone needs to clean up keywords in general so we can |
7234 | 0 | // determine on a per url basis if we want keywords |
7235 | 0 | // enabled...this is just a bandaid... |
7236 | 0 | if (keywordsEnabled && !scheme.IsEmpty() && |
7237 | 0 | (scheme.Find("http") != 0)) { |
7238 | 0 | keywordsEnabled = false; |
7239 | 0 | } |
7240 | 0 |
|
7241 | 0 | if (keywordsEnabled && (kNotFound == dotLoc)) { |
7242 | 0 | nsCOMPtr<nsIURIFixupInfo> info; |
7243 | 0 | // only send non-qualified hosts to the keyword server |
7244 | 0 | if (!mOriginalUriString.IsEmpty()) { |
7245 | 0 | sURIFixup->KeywordToURI(mOriginalUriString, |
7246 | 0 | getter_AddRefs(newPostData), |
7247 | 0 | getter_AddRefs(info)); |
7248 | 0 | } else { |
7249 | 0 | // |
7250 | 0 | // If this string was passed through nsStandardURL by |
7251 | 0 | // chance, then it may have been converted from UTF-8 to |
7252 | 0 | // ACE, which would result in a completely bogus keyword |
7253 | 0 | // query. Here we try to recover the original Unicode |
7254 | 0 | // value, but this is not 100% correct since the value may |
7255 | 0 | // have been normalized per the IDN normalization rules. |
7256 | 0 | // |
7257 | 0 | // Since we don't have access to the exact original string |
7258 | 0 | // that was entered by the user, this will just have to do. |
7259 | 0 | bool isACE; |
7260 | 0 | nsAutoCString utf8Host; |
7261 | 0 | nsCOMPtr<nsIIDNService> idnSrv = |
7262 | 0 | do_GetService(NS_IDNSERVICE_CONTRACTID); |
7263 | 0 | if (idnSrv && |
7264 | 0 | NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE && |
7265 | 0 | NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) { |
7266 | 0 | sURIFixup->KeywordToURI(utf8Host, |
7267 | 0 | getter_AddRefs(newPostData), |
7268 | 0 | getter_AddRefs(info)); |
7269 | 0 | } else { |
7270 | 0 | sURIFixup->KeywordToURI(host, |
7271 | 0 | getter_AddRefs(newPostData), |
7272 | 0 | getter_AddRefs(info)); |
7273 | 0 | } |
7274 | 0 | } |
7275 | 0 |
|
7276 | 0 | info->GetPreferredURI(getter_AddRefs(newURI)); |
7277 | 0 | if (newURI) { |
7278 | 0 | info->GetKeywordAsSent(keywordAsSent); |
7279 | 0 | info->GetKeywordProviderName(keywordProviderName); |
7280 | 0 | } |
7281 | 0 | } // end keywordsEnabled |
7282 | 0 | } |
7283 | 0 |
|
7284 | 0 | // |
7285 | 0 | // Now try change the address, e.g. turn http://foo into |
7286 | 0 | // http://www.foo.com |
7287 | 0 | // |
7288 | 0 | if (aStatus == NS_ERROR_UNKNOWN_HOST || |
7289 | 0 | aStatus == NS_ERROR_NET_RESET) { |
7290 | 0 | bool doCreateAlternate = true; |
7291 | 0 |
|
7292 | 0 | // Skip fixup for anything except a normal document load |
7293 | 0 | // operation on the topframe. |
7294 | 0 |
|
7295 | 0 | if (mLoadType != LOAD_NORMAL || !isTopFrame) { |
7296 | 0 | doCreateAlternate = false; |
7297 | 0 | } else { |
7298 | 0 | // Test if keyword lookup produced a new URI or not |
7299 | 0 | if (newURI) { |
7300 | 0 | bool sameURI = false; |
7301 | 0 | url->Equals(newURI, &sameURI); |
7302 | 0 | if (!sameURI) { |
7303 | 0 | // Keyword lookup made a new URI so no need to try |
7304 | 0 | // an alternate one. |
7305 | 0 | doCreateAlternate = false; |
7306 | 0 | } |
7307 | 0 | } |
7308 | 0 |
|
7309 | 0 | if (doCreateAlternate) { |
7310 | 0 | // Skip doing this if our channel was redirected, because we |
7311 | 0 | // shouldn't be guessing things about the post-redirect URI. |
7312 | 0 | nsLoadFlags loadFlags = 0; |
7313 | 0 | if (NS_FAILED(aChannel->GetLoadFlags(&loadFlags)) || |
7314 | 0 | (loadFlags & nsIChannel::LOAD_REPLACE)) { |
7315 | 0 | doCreateAlternate = false; |
7316 | 0 | } |
7317 | 0 | } |
7318 | 0 | } |
7319 | 0 | if (doCreateAlternate) { |
7320 | 0 | newURI = nullptr; |
7321 | 0 | newPostData = nullptr; |
7322 | 0 | keywordProviderName.Truncate(); |
7323 | 0 | keywordAsSent.Truncate(); |
7324 | 0 | sURIFixup->CreateFixupURI(oldSpec, |
7325 | 0 | nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI, |
7326 | 0 | getter_AddRefs(newPostData), |
7327 | 0 | getter_AddRefs(newURI)); |
7328 | 0 | } |
7329 | 0 | } |
7330 | 0 |
|
7331 | 0 | // Did we make a new URI that is different to the old one? If so |
7332 | 0 | // load it. |
7333 | 0 | // |
7334 | 0 | if (newURI) { |
7335 | 0 | // Make sure the new URI is different from the old one, |
7336 | 0 | // otherwise there's little point trying to load it again. |
7337 | 0 | bool sameURI = false; |
7338 | 0 | url->Equals(newURI, &sameURI); |
7339 | 0 | if (!sameURI) { |
7340 | 0 | nsAutoCString newSpec; |
7341 | 0 | newURI->GetSpec(newSpec); |
7342 | 0 | NS_ConvertUTF8toUTF16 newSpecW(newSpec); |
7343 | 0 |
|
7344 | 0 | // This notification is meant for Firefox Health Report so it |
7345 | 0 | // can increment counts from the search engine |
7346 | 0 | MaybeNotifyKeywordSearchLoading(keywordProviderName, keywordAsSent); |
7347 | 0 |
|
7348 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); |
7349 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo |
7350 | 0 | ? loadInfo->TriggeringPrincipal() |
7351 | 0 | : nsContentUtils::GetSystemPrincipal(); |
7352 | 0 | return LoadURI(newSpecW, // URI string |
7353 | 0 | LOAD_FLAGS_NONE, // Load flags |
7354 | 0 | nullptr, // Referring URI |
7355 | 0 | newPostData, // Post data stream |
7356 | 0 | nullptr, // Headers stream |
7357 | 0 | triggeringPrincipal); // TriggeringPrincipal |
7358 | 0 | } |
7359 | 0 | } |
7360 | 0 | } |
7361 | 0 |
|
7362 | 0 | // Well, fixup didn't work :-( |
7363 | 0 | // It is time to throw an error dialog box, and be done with it... |
7364 | 0 |
|
7365 | 0 | // Errors to be shown only on top-level frames |
7366 | 0 | if ((aStatus == NS_ERROR_UNKNOWN_HOST || |
7367 | 0 | aStatus == NS_ERROR_CONNECTION_REFUSED || |
7368 | 0 | aStatus == NS_ERROR_UNKNOWN_PROXY_HOST || |
7369 | 0 | aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED || |
7370 | 0 | aStatus == NS_ERROR_BLOCKED_BY_POLICY) && |
7371 | 0 | (isTopFrame || UseErrorPages())) { |
7372 | 0 | DisplayLoadError(aStatus, url, nullptr, aChannel); |
7373 | 0 | } else if (aStatus == NS_ERROR_NET_TIMEOUT || |
7374 | 0 | aStatus == NS_ERROR_REDIRECT_LOOP || |
7375 | 0 | aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE || |
7376 | 0 | aStatus == NS_ERROR_NET_INTERRUPT || |
7377 | 0 | aStatus == NS_ERROR_NET_RESET || |
7378 | 0 | aStatus == NS_ERROR_OFFLINE || |
7379 | 0 | aStatus == NS_ERROR_MALWARE_URI || |
7380 | 0 | aStatus == NS_ERROR_PHISHING_URI || |
7381 | 0 | aStatus == NS_ERROR_UNWANTED_URI || |
7382 | 0 | aStatus == NS_ERROR_HARMFUL_URI || |
7383 | 0 | aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE || |
7384 | 0 | aStatus == NS_ERROR_REMOTE_XUL || |
7385 | 0 | aStatus == NS_ERROR_INTERCEPTION_FAILED || |
7386 | 0 | aStatus == NS_ERROR_NET_INADEQUATE_SECURITY || |
7387 | 0 | NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { |
7388 | 0 | // Errors to be shown for any frame |
7389 | 0 | DisplayLoadError(aStatus, url, nullptr, aChannel); |
7390 | 0 | } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) { |
7391 | 0 | // Non-caching channels will simply return NS_ERROR_OFFLINE. |
7392 | 0 | // Caching channels would have to look at their flags to work |
7393 | 0 | // out which error to return. Or we can fix up the error here. |
7394 | 0 | if (!(mLoadType & LOAD_CMD_HISTORY)) { |
7395 | 0 | aStatus = NS_ERROR_OFFLINE; |
7396 | 0 | } |
7397 | 0 | DisplayLoadError(aStatus, url, nullptr, aChannel); |
7398 | 0 | } |
7399 | 0 | } else if (url && NS_SUCCEEDED(aStatus)) { |
7400 | 0 | // If we have a host |
7401 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); |
7402 | 0 | if (loadInfo) { |
7403 | 0 | PredictorLearnRedirect(url, aChannel, loadInfo->GetOriginAttributes()); |
7404 | 0 | } |
7405 | 0 | } |
7406 | 0 |
|
7407 | 0 | return NS_OK; |
7408 | 0 | } |
7409 | | |
7410 | | //***************************************************************************** |
7411 | | // nsDocShell: Content Viewer Management |
7412 | | //***************************************************************************** |
7413 | | |
7414 | | nsresult |
7415 | | nsDocShell::EnsureContentViewer() |
7416 | 0 | { |
7417 | 0 | if (mContentViewer) { |
7418 | 0 | return NS_OK; |
7419 | 0 | } |
7420 | 0 | if (mIsBeingDestroyed) { |
7421 | 0 | return NS_ERROR_FAILURE; |
7422 | 0 | } |
7423 | 0 | |
7424 | 0 | nsCOMPtr<nsIURI> baseURI; |
7425 | 0 | nsIPrincipal* principal = GetInheritedPrincipal(false); |
7426 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentItem; |
7427 | 0 | GetSameTypeParent(getter_AddRefs(parentItem)); |
7428 | 0 | if (parentItem) { |
7429 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> domWin = GetWindow()) { |
7430 | 0 | nsCOMPtr<Element> parentElement = domWin->GetFrameElementInternal(); |
7431 | 0 | if (parentElement) { |
7432 | 0 | baseURI = parentElement->GetBaseURI(); |
7433 | 0 | } |
7434 | 0 | } |
7435 | 0 | } |
7436 | 0 |
|
7437 | 0 | nsresult rv = CreateAboutBlankContentViewer(principal, baseURI); |
7438 | 0 |
|
7439 | 0 | NS_ENSURE_STATE(mContentViewer); |
7440 | 0 |
|
7441 | 0 | if (NS_SUCCEEDED(rv)) { |
7442 | 0 | nsCOMPtr<nsIDocument> doc(GetDocument()); |
7443 | 0 | NS_ASSERTION(doc, |
7444 | 0 | "Should have doc if CreateAboutBlankContentViewer " |
7445 | 0 | "succeeded!"); |
7446 | 0 |
|
7447 | 0 | doc->SetIsInitialDocument(true); |
7448 | 0 |
|
7449 | 0 | // Documents created using EnsureContentViewer may be transient |
7450 | 0 | // placeholders created by framescripts before content has a chance to |
7451 | 0 | // load. In some cases, window.open(..., "noopener") will create such a |
7452 | 0 | // document (in a new TabGroup) and then synchronously tear it down, firing |
7453 | 0 | // a "pagehide" event. Doing so violates our assertions about |
7454 | 0 | // DocGroups. It's easier to silence the assertion here than to avoid |
7455 | 0 | // creating the extra document. |
7456 | 0 | doc->IgnoreDocGroupMismatches(); |
7457 | 0 | } |
7458 | 0 |
|
7459 | 0 | return rv; |
7460 | 0 | } |
7461 | | |
7462 | | nsresult |
7463 | | nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, |
7464 | | nsIURI* aBaseURI, |
7465 | | bool aTryToSaveOldPresentation, |
7466 | | bool aCheckPermitUnload) |
7467 | 0 | { |
7468 | 0 | nsCOMPtr<nsIDocument> blankDoc; |
7469 | 0 | nsCOMPtr<nsIContentViewer> viewer; |
7470 | 0 | nsresult rv = NS_ERROR_FAILURE; |
7471 | 0 |
|
7472 | 0 | /* mCreatingDocument should never be true at this point. However, it's |
7473 | 0 | a theoretical possibility. We want to know about it and make it stop, |
7474 | 0 | and this sounds like a job for an assertion. */ |
7475 | 0 | NS_ASSERTION(!mCreatingDocument, |
7476 | 0 | "infinite(?) loop creating document averted"); |
7477 | 0 | if (mCreatingDocument) { |
7478 | 0 | return NS_ERROR_FAILURE; |
7479 | 0 | } |
7480 | 0 | |
7481 | 0 | // mContentViewer->PermitUnload may release |this| docshell. |
7482 | 0 | nsCOMPtr<nsIDocShell> kungFuDeathGrip(this); |
7483 | 0 |
|
7484 | 0 | AutoRestore<bool> creatingDocument(mCreatingDocument); |
7485 | 0 | mCreatingDocument = true; |
7486 | 0 |
|
7487 | 0 | if (aPrincipal && !nsContentUtils::IsSystemPrincipal(aPrincipal) && |
7488 | 0 | mItemType != typeChrome) { |
7489 | 0 | MOZ_ASSERT(aPrincipal->OriginAttributesRef() == mOriginAttributes); |
7490 | 0 | } |
7491 | 0 |
|
7492 | 0 | // Make sure timing is created. But first record whether we had it |
7493 | 0 | // already, so we don't clobber the timing for an in-progress load. |
7494 | 0 | bool hadTiming = mTiming; |
7495 | 0 | bool toBeReset = MaybeInitTiming(); |
7496 | 0 | if (mContentViewer) { |
7497 | 0 | if (aCheckPermitUnload) { |
7498 | 0 | // We've got a content viewer already. Make sure the user |
7499 | 0 | // permits us to discard the current document and replace it |
7500 | 0 | // with about:blank. And also ensure we fire the unload events |
7501 | 0 | // in the current document. |
7502 | 0 |
|
7503 | 0 | // Unload gets fired first for |
7504 | 0 | // document loaded from the session history. |
7505 | 0 | mTiming->NotifyBeforeUnload(); |
7506 | 0 |
|
7507 | 0 | bool okToUnload; |
7508 | 0 | rv = mContentViewer->PermitUnload(&okToUnload); |
7509 | 0 |
|
7510 | 0 | if (NS_SUCCEEDED(rv) && !okToUnload) { |
7511 | 0 | // The user chose not to unload the page, interrupt the load. |
7512 | 0 | MaybeResetInitTiming(toBeReset); |
7513 | 0 | return NS_ERROR_FAILURE; |
7514 | 0 | } |
7515 | 0 | if (mTiming) { |
7516 | 0 | mTiming->NotifyUnloadAccepted(mCurrentURI); |
7517 | 0 | } |
7518 | 0 | } |
7519 | 0 |
|
7520 | 0 | mSavingOldViewer = aTryToSaveOldPresentation && |
7521 | 0 | CanSavePresentation(LOAD_NORMAL, nullptr, nullptr); |
7522 | 0 |
|
7523 | 0 | // Make sure to blow away our mLoadingURI just in case. No loads |
7524 | 0 | // from inside this pagehide. |
7525 | 0 | mLoadingURI = nullptr; |
7526 | 0 |
|
7527 | 0 | // Stop any in-progress loading, so that we don't accidentally trigger any |
7528 | 0 | // PageShow notifications from Embed() interrupting our loading below. |
7529 | 0 | Stop(); |
7530 | 0 |
|
7531 | 0 | // Notify the current document that it is about to be unloaded!! |
7532 | 0 | // |
7533 | 0 | // It is important to fire the unload() notification *before* any state |
7534 | 0 | // is changed within the DocShell - otherwise, javascript will get the |
7535 | 0 | // wrong information :-( |
7536 | 0 | // |
7537 | 0 | (void)FirePageHideNotification(!mSavingOldViewer); |
7538 | 0 | // pagehide notification might destroy this docshell. |
7539 | 0 | if (mIsBeingDestroyed) { |
7540 | 0 | return NS_ERROR_DOCSHELL_DYING; |
7541 | 0 | } |
7542 | 0 | } |
7543 | 0 | |
7544 | 0 | // Now make sure we don't think we're in the middle of firing unload after |
7545 | 0 | // this point. This will make us fire unload when the about:blank document |
7546 | 0 | // unloads... but that's ok, more or less. Would be nice if it fired load |
7547 | 0 | // too, of course. |
7548 | 0 | mFiredUnloadEvent = false; |
7549 | 0 |
|
7550 | 0 | nsCOMPtr<nsIDocumentLoaderFactory> docFactory = |
7551 | 0 | nsContentUtils::FindInternalContentViewer(NS_LITERAL_CSTRING("text/html")); |
7552 | 0 |
|
7553 | 0 | if (docFactory) { |
7554 | 0 | nsCOMPtr<nsIPrincipal> principal; |
7555 | 0 | if (mSandboxFlags & SANDBOXED_ORIGIN) { |
7556 | 0 | if (aPrincipal) { |
7557 | 0 | principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal); |
7558 | 0 | } else { |
7559 | 0 | principal = NullPrincipal::CreateWithInheritedAttributes(this); |
7560 | 0 | } |
7561 | 0 | } else { |
7562 | 0 | principal = aPrincipal; |
7563 | 0 | } |
7564 | 0 |
|
7565 | 0 | MaybeCreateInitialClientSource(principal); |
7566 | 0 |
|
7567 | 0 | // generate (about:blank) document to load |
7568 | 0 | blankDoc = nsContentDLF::CreateBlankDocument(mLoadGroup, principal, this); |
7569 | 0 | if (blankDoc) { |
7570 | 0 | // Hack: set the base URI manually, since this document never |
7571 | 0 | // got Reset() with a channel. |
7572 | 0 | blankDoc->SetBaseURI(aBaseURI); |
7573 | 0 |
|
7574 | 0 | // Copy our sandbox flags to the document. These are immutable |
7575 | 0 | // after being set here. |
7576 | 0 | blankDoc->SetSandboxFlags(mSandboxFlags); |
7577 | 0 |
|
7578 | 0 | // create a content viewer for us and the new document |
7579 | 0 | docFactory->CreateInstanceForDocument( |
7580 | 0 | NS_ISUPPORTS_CAST(nsIDocShell*, this), blankDoc, "view", |
7581 | 0 | getter_AddRefs(viewer)); |
7582 | 0 |
|
7583 | 0 | // hook 'em up |
7584 | 0 | if (viewer) { |
7585 | 0 | viewer->SetContainer(this); |
7586 | 0 | rv = Embed(viewer, "", 0); |
7587 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7588 | 0 |
|
7589 | 0 | SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0); |
7590 | 0 | rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK; |
7591 | 0 | } |
7592 | 0 | } |
7593 | 0 | } |
7594 | 0 |
|
7595 | 0 | // The transient about:blank viewer doesn't have a session history entry. |
7596 | 0 | SetHistoryEntry(&mOSHE, nullptr); |
7597 | 0 |
|
7598 | 0 | // Clear out our mTiming like we would in EndPageLoad, if we didn't |
7599 | 0 | // have one before entering this function. |
7600 | 0 | if (!hadTiming) { |
7601 | 0 | mTiming = nullptr; |
7602 | 0 | mBlankTiming = true; |
7603 | 0 | } |
7604 | 0 |
|
7605 | 0 | return rv; |
7606 | 0 | } |
7607 | | |
7608 | | NS_IMETHODIMP |
7609 | | nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal) |
7610 | 0 | { |
7611 | 0 | return CreateAboutBlankContentViewer(aPrincipal, nullptr); |
7612 | 0 | } |
7613 | | |
7614 | | NS_IMETHODIMP |
7615 | | nsDocShell::ForceCreateAboutBlankContentViewer(nsIPrincipal* aPrincipal) |
7616 | 0 | { |
7617 | 0 | return CreateAboutBlankContentViewer(aPrincipal, nullptr, true, false); |
7618 | 0 | } |
7619 | | |
7620 | | bool |
7621 | | nsDocShell::CanSavePresentation(uint32_t aLoadType, |
7622 | | nsIRequest* aNewRequest, |
7623 | | nsIDocument* aNewDocument) |
7624 | 0 | { |
7625 | 0 | if (!mOSHE) { |
7626 | 0 | return false; // no entry to save into |
7627 | 0 | } |
7628 | 0 | |
7629 | 0 | nsCOMPtr<nsIContentViewer> viewer = mOSHE->GetContentViewer(); |
7630 | 0 | if (viewer) { |
7631 | 0 | NS_WARNING("mOSHE already has a content viewer!"); |
7632 | 0 | return false; |
7633 | 0 | } |
7634 | 0 |
|
7635 | 0 | // Only save presentation for "normal" loads and link loads. Anything else |
7636 | 0 | // probably wants to refetch the page, so caching the old presentation |
7637 | 0 | // would be incorrect. |
7638 | 0 | if (aLoadType != LOAD_NORMAL && |
7639 | 0 | aLoadType != LOAD_HISTORY && |
7640 | 0 | aLoadType != LOAD_LINK && |
7641 | 0 | aLoadType != LOAD_STOP_CONTENT && |
7642 | 0 | aLoadType != LOAD_STOP_CONTENT_AND_REPLACE && |
7643 | 0 | aLoadType != LOAD_ERROR_PAGE) { |
7644 | 0 | return false; |
7645 | 0 | } |
7646 | 0 | |
7647 | 0 | // If the session history entry has the saveLayoutState flag set to false, |
7648 | 0 | // then we should not cache the presentation. |
7649 | 0 | if (!mOSHE->GetSaveLayoutStateFlag()) { |
7650 | 0 | return false; |
7651 | 0 | } |
7652 | 0 | |
7653 | 0 | // If the document is not done loading, don't cache it. |
7654 | 0 | if (!mScriptGlobal || mScriptGlobal->IsLoading()) { |
7655 | 0 | return false; |
7656 | 0 | } |
7657 | 0 | |
7658 | 0 | if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument)) { |
7659 | 0 | return false; |
7660 | 0 | } |
7661 | 0 | |
7662 | 0 | // Avoid doing the work of saving the presentation state in the case where |
7663 | 0 | // the content viewer cache is disabled. |
7664 | 0 | if (nsSHistory::GetMaxTotalViewers() == 0) { |
7665 | 0 | return false; |
7666 | 0 | } |
7667 | 0 | |
7668 | 0 | // Don't cache the content viewer if we're in a subframe. |
7669 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
7670 | 0 | GetSameTypeParent(getter_AddRefs(root)); |
7671 | 0 | if (root && root != this) { |
7672 | 0 | return false; // this is a subframe load |
7673 | 0 | } |
7674 | 0 | |
7675 | 0 | // If the document does not want its presentation cached, then don't. |
7676 | 0 | nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc(); |
7677 | 0 | return doc && doc->CanSavePresentation(aNewRequest); |
7678 | 0 | } |
7679 | | |
7680 | | void |
7681 | | nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry) |
7682 | 0 | { |
7683 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
7684 | 0 |
|
7685 | 0 | NS_ASSERTION(!mEditorData, |
7686 | 0 | "Why reattach an editor when we already have one?"); |
7687 | 0 | NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(), |
7688 | 0 | "Reattaching when there's not a detached editor."); |
7689 | 0 |
|
7690 | 0 | if (mEditorData || !aSHEntry) { |
7691 | 0 | return; |
7692 | 0 | } |
7693 | 0 | |
7694 | 0 | mEditorData = aSHEntry->ForgetEditorData(); |
7695 | 0 | if (mEditorData) { |
7696 | | #ifdef DEBUG |
7697 | | nsresult rv = |
7698 | | #endif |
7699 | | mEditorData->ReattachToWindow(this); |
7700 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session"); |
7701 | 0 | } |
7702 | 0 | } |
7703 | | |
7704 | | void |
7705 | | nsDocShell::DetachEditorFromWindow() |
7706 | 0 | { |
7707 | 0 | if (!mEditorData || mEditorData->WaitingForLoad()) { |
7708 | 0 | // If there's nothing to detach, or if the editor data is actually set |
7709 | 0 | // up for the _new_ page that's coming in, don't detach. |
7710 | 0 | return; |
7711 | 0 | } |
7712 | 0 | |
7713 | 0 | NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(), |
7714 | 0 | "Detaching editor when it's already detached."); |
7715 | 0 |
|
7716 | 0 | nsresult res = mEditorData->DetachFromWindow(); |
7717 | 0 | NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor"); |
7718 | 0 |
|
7719 | 0 | if (NS_SUCCEEDED(res)) { |
7720 | 0 | // Make mOSHE hold the owning ref to the editor data. |
7721 | 0 | if (mOSHE) { |
7722 | 0 | MOZ_ASSERT(!mIsBeingDestroyed || !mOSHE->HasDetachedEditor(), |
7723 | 0 | "We should not set the editor data again once after we " |
7724 | 0 | "detached the editor data during destroying this docshell"); |
7725 | 0 | mOSHE->SetEditorData(mEditorData.forget()); |
7726 | 0 | } else { |
7727 | 0 | mEditorData = nullptr; |
7728 | 0 | } |
7729 | 0 | } |
7730 | 0 |
|
7731 | | #ifdef DEBUG |
7732 | | { |
7733 | | bool isEditable; |
7734 | | GetEditable(&isEditable); |
7735 | | NS_ASSERTION(!isEditable, |
7736 | | "Window is still editable after detaching editor."); |
7737 | | } |
7738 | | #endif // DEBUG |
7739 | | } |
7740 | | |
7741 | | nsresult |
7742 | | nsDocShell::CaptureState() |
7743 | 0 | { |
7744 | 0 | if (!mOSHE || mOSHE == mLSHE) { |
7745 | 0 | // No entry to save into, or we're replacing the existing entry. |
7746 | 0 | return NS_ERROR_FAILURE; |
7747 | 0 | } |
7748 | 0 | |
7749 | 0 | if (!mScriptGlobal) { |
7750 | 0 | return NS_ERROR_FAILURE; |
7751 | 0 | } |
7752 | 0 | |
7753 | 0 | nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState(); |
7754 | 0 | NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE); |
7755 | 0 |
|
7756 | | #ifdef DEBUG_PAGE_CACHE |
7757 | | nsCOMPtr<nsIURI> uri = mOSHE->GetURI(); |
7758 | | nsAutoCString spec; |
7759 | | if (uri) { |
7760 | | uri->GetSpec(spec); |
7761 | | } |
7762 | | printf("Saving presentation into session history\n"); |
7763 | | printf(" SH URI: %s\n", spec.get()); |
7764 | | #endif |
7765 | |
|
7766 | 0 | mOSHE->SetWindowState(windowState); |
7767 | 0 |
|
7768 | 0 | // Suspend refresh URIs and save off the timer queue |
7769 | 0 | mOSHE->SetRefreshURIList(mSavedRefreshURIList); |
7770 | 0 |
|
7771 | 0 | // Capture the current content viewer bounds. |
7772 | 0 | if (mContentViewer) { |
7773 | 0 | nsIntRect bounds; |
7774 | 0 | mContentViewer->GetBounds(bounds); |
7775 | 0 | mOSHE->SetViewerBounds(bounds); |
7776 | 0 | } |
7777 | 0 |
|
7778 | 0 | // Capture the docshell hierarchy. |
7779 | 0 | mOSHE->ClearChildShells(); |
7780 | 0 |
|
7781 | 0 | uint32_t childCount = mChildList.Length(); |
7782 | 0 | for (uint32_t i = 0; i < childCount; ++i) { |
7783 | 0 | nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i)); |
7784 | 0 | NS_ASSERTION(childShell, "null child shell"); |
7785 | 0 |
|
7786 | 0 | mOSHE->AddChildShell(childShell); |
7787 | 0 | } |
7788 | 0 |
|
7789 | 0 | mBrowsingContext->CacheChildren(); |
7790 | 0 |
|
7791 | 0 | return NS_OK; |
7792 | 0 | } |
7793 | | |
7794 | | NS_IMETHODIMP |
7795 | | nsDocShell::RestorePresentationEvent::Run() |
7796 | 0 | { |
7797 | 0 | if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory())) { |
7798 | 0 | NS_WARNING("RestoreFromHistory failed"); |
7799 | 0 | } |
7800 | 0 | return NS_OK; |
7801 | 0 | } |
7802 | | |
7803 | | NS_IMETHODIMP |
7804 | | nsDocShell::BeginRestore(nsIContentViewer* aContentViewer, bool aTop) |
7805 | 0 | { |
7806 | 0 | nsresult rv; |
7807 | 0 | if (!aContentViewer) { |
7808 | 0 | rv = EnsureContentViewer(); |
7809 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7810 | 0 |
|
7811 | 0 | aContentViewer = mContentViewer; |
7812 | 0 | } |
7813 | 0 |
|
7814 | 0 | // Dispatch events for restoring the presentation. We try to simulate |
7815 | 0 | // the progress notifications loading the document would cause, so we add |
7816 | 0 | // the document's channel to the loadgroup to initiate stateChange |
7817 | 0 | // notifications. |
7818 | 0 |
|
7819 | 0 | nsCOMPtr<nsIDocument> doc = aContentViewer->GetDocument(); |
7820 | 0 | if (doc) { |
7821 | 0 | nsIChannel* channel = doc->GetChannel(); |
7822 | 0 | if (channel) { |
7823 | 0 | mEODForCurrentDocument = false; |
7824 | 0 | mIsRestoringDocument = true; |
7825 | 0 | mLoadGroup->AddRequest(channel, nullptr); |
7826 | 0 | mIsRestoringDocument = false; |
7827 | 0 | } |
7828 | 0 | } |
7829 | 0 |
|
7830 | 0 | if (!aTop) { |
7831 | 0 | // This point corresponds to us having gotten OnStartRequest or |
7832 | 0 | // STATE_START, so do the same thing that CreateContentViewer does at |
7833 | 0 | // this point to ensure that unload/pagehide events for this document |
7834 | 0 | // will fire when it's unloaded again. |
7835 | 0 | mFiredUnloadEvent = false; |
7836 | 0 |
|
7837 | 0 | // For non-top frames, there is no notion of making sure that the |
7838 | 0 | // previous document is in the domwindow when STATE_START notifications |
7839 | 0 | // happen. We can just call BeginRestore for all of the child shells |
7840 | 0 | // now. |
7841 | 0 | rv = BeginRestoreChildren(); |
7842 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7843 | 0 | } |
7844 | 0 |
|
7845 | 0 | return NS_OK; |
7846 | 0 | } |
7847 | | |
7848 | | nsresult |
7849 | | nsDocShell::BeginRestoreChildren() |
7850 | 0 | { |
7851 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
7852 | 0 | while (iter.HasMore()) { |
7853 | 0 | nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext()); |
7854 | 0 | if (child) { |
7855 | 0 | nsresult rv = child->BeginRestore(nullptr, false); |
7856 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
7857 | 0 | } |
7858 | 0 | } |
7859 | 0 | return NS_OK; |
7860 | 0 | } |
7861 | | |
7862 | | NS_IMETHODIMP |
7863 | | nsDocShell::FinishRestore() |
7864 | 0 | { |
7865 | 0 | // First we call finishRestore() on our children. In the simulated load, |
7866 | 0 | // all of the child frames finish loading before the main document. |
7867 | 0 |
|
7868 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
7869 | 0 | while (iter.HasMore()) { |
7870 | 0 | nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext()); |
7871 | 0 | if (child) { |
7872 | 0 | child->FinishRestore(); |
7873 | 0 | } |
7874 | 0 | } |
7875 | 0 |
|
7876 | 0 | if (mOSHE && mOSHE->HasDetachedEditor()) { |
7877 | 0 | ReattachEditorToWindow(mOSHE); |
7878 | 0 | } |
7879 | 0 |
|
7880 | 0 | nsCOMPtr<nsIDocument> doc = GetDocument(); |
7881 | 0 | if (doc) { |
7882 | 0 | // Finally, we remove the request from the loadgroup. This will |
7883 | 0 | // cause onStateChange(STATE_STOP) to fire, which will fire the |
7884 | 0 | // pageshow event to the chrome. |
7885 | 0 |
|
7886 | 0 | nsIChannel* channel = doc->GetChannel(); |
7887 | 0 | if (channel) { |
7888 | 0 | mIsRestoringDocument = true; |
7889 | 0 | mLoadGroup->RemoveRequest(channel, nullptr, NS_OK); |
7890 | 0 | mIsRestoringDocument = false; |
7891 | 0 | } |
7892 | 0 | } |
7893 | 0 |
|
7894 | 0 | return NS_OK; |
7895 | 0 | } |
7896 | | |
7897 | | NS_IMETHODIMP |
7898 | | nsDocShell::GetRestoringDocument(bool* aRestoring) |
7899 | 0 | { |
7900 | 0 | *aRestoring = mIsRestoringDocument; |
7901 | 0 | return NS_OK; |
7902 | 0 | } |
7903 | | |
7904 | | nsresult |
7905 | | nsDocShell::RestorePresentation(nsISHEntry* aSHEntry, bool* aRestoring) |
7906 | 0 | { |
7907 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
7908 | 0 |
|
7909 | 0 | NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY, |
7910 | 0 | "RestorePresentation should only be called for history loads"); |
7911 | 0 |
|
7912 | 0 | nsCOMPtr<nsIContentViewer> viewer = aSHEntry->GetContentViewer(); |
7913 | 0 |
|
7914 | | #ifdef DEBUG_PAGE_CACHE |
7915 | | nsCOMPtr<nsIURI> uri = aSHEntry->GetURI(); |
7916 | | |
7917 | | nsAutoCString spec; |
7918 | | if (uri) { |
7919 | | uri->GetSpec(spec); |
7920 | | } |
7921 | | #endif |
7922 | |
|
7923 | 0 | *aRestoring = false; |
7924 | 0 |
|
7925 | 0 | if (!viewer) { |
7926 | | #ifdef DEBUG_PAGE_CACHE |
7927 | | printf("no saved presentation for uri: %s\n", spec.get()); |
7928 | | #endif |
7929 | | return NS_OK; |
7930 | 0 | } |
7931 | 0 |
|
7932 | 0 | // We need to make sure the content viewer's container is this docshell. |
7933 | 0 | // In subframe navigation, it's possible for the docshell that the |
7934 | 0 | // content viewer was originally loaded into to be replaced with a |
7935 | 0 | // different one. We don't currently support restoring the presentation |
7936 | 0 | // in that case. |
7937 | 0 |
|
7938 | 0 | nsCOMPtr<nsIDocShell> container; |
7939 | 0 | viewer->GetContainer(getter_AddRefs(container)); |
7940 | 0 | if (!::SameCOMIdentity(container, GetAsSupports(this))) { |
7941 | | #ifdef DEBUG_PAGE_CACHE |
7942 | | printf("No valid container, clearing presentation\n"); |
7943 | | #endif |
7944 | | aSHEntry->SetContentViewer(nullptr); |
7945 | 0 | return NS_ERROR_FAILURE; |
7946 | 0 | } |
7947 | 0 |
|
7948 | 0 | NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation"); |
7949 | 0 |
|
7950 | | #ifdef DEBUG_PAGE_CACHE |
7951 | | printf("restoring presentation from session history: %s\n", spec.get()); |
7952 | | #endif |
7953 | |
|
7954 | 0 | SetHistoryEntry(&mLSHE, aSHEntry); |
7955 | 0 |
|
7956 | 0 | // Post an event that will remove the request after we've returned |
7957 | 0 | // to the event loop. This mimics the way it is called by nsIChannel |
7958 | 0 | // implementations. |
7959 | 0 |
|
7960 | 0 | // Revoke any pending restore (just in case) |
7961 | 0 | NS_ASSERTION(!mRestorePresentationEvent.IsPending(), |
7962 | 0 | "should only have one RestorePresentationEvent"); |
7963 | 0 | mRestorePresentationEvent.Revoke(); |
7964 | 0 |
|
7965 | 0 | RefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this); |
7966 | 0 | nsresult rv = DispatchToTabGroup(TaskCategory::Other, |
7967 | 0 | RefPtr<RestorePresentationEvent>(evt).forget()); |
7968 | 0 | if (NS_SUCCEEDED(rv)) { |
7969 | 0 | mRestorePresentationEvent = evt.get(); |
7970 | 0 | // The rest of the restore processing will happen on our event |
7971 | 0 | // callback. |
7972 | 0 | *aRestoring = true; |
7973 | 0 | } |
7974 | 0 |
|
7975 | 0 | return rv; |
7976 | 0 | } |
7977 | | |
7978 | | namespace { |
7979 | | class MOZ_STACK_CLASS PresentationEventForgetter |
7980 | | { |
7981 | | public: |
7982 | | explicit PresentationEventForgetter( |
7983 | | nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>& |
7984 | | aRestorePresentationEvent) |
7985 | | : mRestorePresentationEvent(aRestorePresentationEvent) |
7986 | | , mEvent(aRestorePresentationEvent.get()) |
7987 | 0 | { |
7988 | 0 | } |
7989 | | |
7990 | | ~PresentationEventForgetter() |
7991 | 0 | { |
7992 | 0 | Forget(); |
7993 | 0 | } |
7994 | | |
7995 | | void Forget() |
7996 | 0 | { |
7997 | 0 | if (mRestorePresentationEvent.get() == mEvent) { |
7998 | 0 | mRestorePresentationEvent.Forget(); |
7999 | 0 | mEvent = nullptr; |
8000 | 0 | } |
8001 | 0 | } |
8002 | | |
8003 | | private: |
8004 | | nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>& |
8005 | | mRestorePresentationEvent; |
8006 | | RefPtr<nsDocShell::RestorePresentationEvent> mEvent; |
8007 | | }; |
8008 | | |
8009 | | } // namespace |
8010 | | |
8011 | | bool |
8012 | | nsDocShell::SandboxFlagsImplyCookies(const uint32_t &aSandboxFlags) |
8013 | 0 | { |
8014 | 0 | return (aSandboxFlags & (SANDBOXED_ORIGIN | SANDBOXED_SCRIPTS)) == 0; |
8015 | 0 | } |
8016 | | |
8017 | | nsresult |
8018 | | nsDocShell::RestoreFromHistory() |
8019 | 0 | { |
8020 | 0 | MOZ_ASSERT(mRestorePresentationEvent.IsPending()); |
8021 | 0 | PresentationEventForgetter forgetter(mRestorePresentationEvent); |
8022 | 0 |
|
8023 | 0 | // This section of code follows the same ordering as CreateContentViewer. |
8024 | 0 | if (!mLSHE) { |
8025 | 0 | return NS_ERROR_FAILURE; |
8026 | 0 | } |
8027 | 0 | |
8028 | 0 | nsCOMPtr<nsIContentViewer> viewer = mLSHE->GetContentViewer(); |
8029 | 0 | if (!viewer) { |
8030 | 0 | return NS_ERROR_FAILURE; |
8031 | 0 | } |
8032 | 0 | |
8033 | 0 | if (mSavingOldViewer) { |
8034 | 0 | // We determined that it was safe to cache the document presentation |
8035 | 0 | // at the time we initiated the new load. We need to check whether |
8036 | 0 | // it's still safe to do so, since there may have been DOM mutations |
8037 | 0 | // or new requests initiated. |
8038 | 0 | nsCOMPtr<nsIDocument> doc = viewer->GetDocument(); |
8039 | 0 | nsIRequest* request = nullptr; |
8040 | 0 | if (doc) { |
8041 | 0 | request = doc->GetChannel(); |
8042 | 0 | } |
8043 | 0 | mSavingOldViewer = CanSavePresentation(mLoadType, request, doc); |
8044 | 0 | } |
8045 | 0 |
|
8046 | 0 | nsCOMPtr<nsIContentViewer> oldCv(mContentViewer); |
8047 | 0 | nsCOMPtr<nsIContentViewer> newCv(viewer); |
8048 | 0 | int32_t minFontSize = 0; |
8049 | 0 | float textZoom = 1.0f; |
8050 | 0 | float pageZoom = 1.0f; |
8051 | 0 | float overrideDPPX = 0.0f; |
8052 | 0 |
|
8053 | 0 | bool styleDisabled = false; |
8054 | 0 | if (oldCv && newCv) { |
8055 | 0 | oldCv->GetMinFontSize(&minFontSize); |
8056 | 0 | oldCv->GetTextZoom(&textZoom); |
8057 | 0 | oldCv->GetFullZoom(&pageZoom); |
8058 | 0 | oldCv->GetOverrideDPPX(&overrideDPPX); |
8059 | 0 | oldCv->GetAuthorStyleDisabled(&styleDisabled); |
8060 | 0 | } |
8061 | 0 |
|
8062 | 0 | // Protect against mLSHE going away via a load triggered from |
8063 | 0 | // pagehide or unload. |
8064 | 0 | nsCOMPtr<nsISHEntry> origLSHE = mLSHE; |
8065 | 0 |
|
8066 | 0 | // Make sure to blow away our mLoadingURI just in case. No loads |
8067 | 0 | // from inside this pagehide. |
8068 | 0 | mLoadingURI = nullptr; |
8069 | 0 |
|
8070 | 0 | // Notify the old content viewer that it's being hidden. |
8071 | 0 | FirePageHideNotification(!mSavingOldViewer); |
8072 | 0 | // pagehide notification might destroy this docshell. |
8073 | 0 | if (mIsBeingDestroyed) { |
8074 | 0 | return NS_ERROR_DOCSHELL_DYING; |
8075 | 0 | } |
8076 | 0 | |
8077 | 0 | // If mLSHE was changed as a result of the pagehide event, then |
8078 | 0 | // something else was loaded. Don't finish restoring. |
8079 | 0 | if (mLSHE != origLSHE) { |
8080 | 0 | return NS_OK; |
8081 | 0 | } |
8082 | 0 | |
8083 | 0 | // Add the request to our load group. We do this before swapping out |
8084 | 0 | // the content viewers so that consumers of STATE_START can access |
8085 | 0 | // the old document. We only deal with the toplevel load at this time -- |
8086 | 0 | // to be consistent with normal document loading, subframes cannot start |
8087 | 0 | // loading until after data arrives, which is after STATE_START completes. |
8088 | 0 | |
8089 | 0 | RefPtr<RestorePresentationEvent> currentPresentationRestoration = |
8090 | 0 | mRestorePresentationEvent.get(); |
8091 | 0 | Stop(); |
8092 | 0 | // Make sure we're still restoring the same presentation. |
8093 | 0 | // If we aren't, docshell is in process doing another load already. |
8094 | 0 | NS_ENSURE_STATE(currentPresentationRestoration == |
8095 | 0 | mRestorePresentationEvent.get()); |
8096 | 0 | BeginRestore(viewer, true); |
8097 | 0 | NS_ENSURE_STATE(currentPresentationRestoration == |
8098 | 0 | mRestorePresentationEvent.get()); |
8099 | 0 | forgetter.Forget(); |
8100 | 0 |
|
8101 | 0 | // Set mFiredUnloadEvent = false so that the unload handler for the |
8102 | 0 | // *new* document will fire. |
8103 | 0 | mFiredUnloadEvent = false; |
8104 | 0 |
|
8105 | 0 | mURIResultedInDocument = true; |
8106 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
8107 | 0 | if (rootSH) { |
8108 | 0 | mPreviousEntryIndex = rootSH->Index(); |
8109 | 0 | rootSH->LegacySHistory()->UpdateIndex(); |
8110 | 0 | mLoadedEntryIndex = rootSH->Index(); |
8111 | | #ifdef DEBUG_PAGE_CACHE |
8112 | | printf("Previous index: %d, Loaded index: %d\n\n", mPreviousEntryIndex, |
8113 | | mLoadedEntryIndex); |
8114 | | #endif |
8115 | | } |
8116 | 0 |
|
8117 | 0 | // Rather than call Embed(), we will retrieve the viewer from the session |
8118 | 0 | // history entry and swap it in. |
8119 | 0 | // XXX can we refactor this so that we can just call Embed()? |
8120 | 0 | PersistLayoutHistoryState(); |
8121 | 0 | nsresult rv; |
8122 | 0 | if (mContentViewer) { |
8123 | 0 | if (mSavingOldViewer && NS_FAILED(CaptureState())) { |
8124 | 0 | if (mOSHE) { |
8125 | 0 | mOSHE->SyncPresentationState(); |
8126 | 0 | } |
8127 | 0 | mSavingOldViewer = false; |
8128 | 0 | } |
8129 | 0 | } |
8130 | 0 |
|
8131 | 0 | mSavedRefreshURIList = nullptr; |
8132 | 0 |
|
8133 | 0 | // In cases where we use a transient about:blank viewer between loads, |
8134 | 0 | // we never show the transient viewer, so _its_ previous viewer is never |
8135 | 0 | // unhooked from the view hierarchy. Destroy any such previous viewer now, |
8136 | 0 | // before we grab the root view sibling, so that we don't grab a view |
8137 | 0 | // that's about to go away. |
8138 | 0 |
|
8139 | 0 | if (mContentViewer) { |
8140 | 0 | nsCOMPtr<nsIContentViewer> previousViewer; |
8141 | 0 | mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer)); |
8142 | 0 | if (previousViewer) { |
8143 | 0 | mContentViewer->SetPreviousViewer(nullptr); |
8144 | 0 | previousViewer->Destroy(); |
8145 | 0 | } |
8146 | 0 | } |
8147 | 0 |
|
8148 | 0 | // Save off the root view's parent and sibling so that we can insert the |
8149 | 0 | // new content viewer's root view at the same position. Also save the |
8150 | 0 | // bounds of the root view's widget. |
8151 | 0 |
|
8152 | 0 | nsView* rootViewSibling = nullptr; |
8153 | 0 | nsView* rootViewParent = nullptr; |
8154 | 0 | nsIntRect newBounds(0, 0, 0, 0); |
8155 | 0 |
|
8156 | 0 | nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell(); |
8157 | 0 | if (oldPresShell) { |
8158 | 0 | nsViewManager* vm = oldPresShell->GetViewManager(); |
8159 | 0 | if (vm) { |
8160 | 0 | nsView* oldRootView = vm->GetRootView(); |
8161 | 0 |
|
8162 | 0 | if (oldRootView) { |
8163 | 0 | rootViewSibling = oldRootView->GetNextSibling(); |
8164 | 0 | rootViewParent = oldRootView->GetParent(); |
8165 | 0 |
|
8166 | 0 | mContentViewer->GetBounds(newBounds); |
8167 | 0 | } |
8168 | 0 | } |
8169 | 0 | } |
8170 | 0 |
|
8171 | 0 | nsCOMPtr<nsIContent> container; |
8172 | 0 | nsCOMPtr<nsIDocument> sibling; |
8173 | 0 | if (rootViewParent && rootViewParent->GetParent()) { |
8174 | 0 | nsIFrame* frame = rootViewParent->GetParent()->GetFrame(); |
8175 | 0 | container = frame ? frame->GetContent() : nullptr; |
8176 | 0 | } |
8177 | 0 | if (rootViewSibling) { |
8178 | 0 | nsIFrame* frame = rootViewSibling->GetFrame(); |
8179 | 0 | sibling = |
8180 | 0 | frame ? frame->PresShell()->GetDocument() : nullptr; |
8181 | 0 | } |
8182 | 0 |
|
8183 | 0 | // Transfer ownership to mContentViewer. By ensuring that either the |
8184 | 0 | // docshell or the session history, but not both, have references to the |
8185 | 0 | // content viewer, we prevent the viewer from being torn down after |
8186 | 0 | // Destroy() is called. |
8187 | 0 |
|
8188 | 0 | if (mContentViewer) { |
8189 | 0 | mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr); |
8190 | 0 | viewer->SetPreviousViewer(mContentViewer); |
8191 | 0 | } |
8192 | 0 | if (mOSHE && (!mContentViewer || !mSavingOldViewer)) { |
8193 | 0 | // We don't plan to save a viewer in mOSHE; tell it to drop |
8194 | 0 | // any other state it's holding. |
8195 | 0 | mOSHE->SyncPresentationState(); |
8196 | 0 | } |
8197 | 0 |
|
8198 | 0 | // Order the mContentViewer setup just like Embed does. |
8199 | 0 | mContentViewer = nullptr; |
8200 | 0 |
|
8201 | 0 | // Now that we're about to switch documents, forget all of our children. |
8202 | 0 | // Note that we cached them as needed up in CaptureState above. |
8203 | 0 | DestroyChildren(); |
8204 | 0 |
|
8205 | 0 | mContentViewer.swap(viewer); |
8206 | 0 |
|
8207 | 0 | // Grab all of the related presentation from the SHEntry now. |
8208 | 0 | // Clearing the viewer from the SHEntry will clear all of this state. |
8209 | 0 | nsCOMPtr<nsISupports> windowState = mLSHE->GetWindowState(); |
8210 | 0 | mLSHE->SetWindowState(nullptr); |
8211 | 0 |
|
8212 | 0 | bool sticky = mLSHE->GetSticky(); |
8213 | 0 |
|
8214 | 0 | nsCOMPtr<nsIDocument> document = mContentViewer->GetDocument(); |
8215 | 0 |
|
8216 | 0 | nsCOMArray<nsIDocShellTreeItem> childShells; |
8217 | 0 | int32_t i = 0; |
8218 | 0 | nsCOMPtr<nsIDocShellTreeItem> child; |
8219 | 0 | while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) && |
8220 | 0 | child) { |
8221 | 0 | childShells.AppendObject(child); |
8222 | 0 | } |
8223 | 0 |
|
8224 | 0 | // get the previous content viewer size |
8225 | 0 | nsIntRect oldBounds(0, 0, 0, 0); |
8226 | 0 | mLSHE->GetViewerBounds(oldBounds); |
8227 | 0 |
|
8228 | 0 | // Restore the refresh URI list. The refresh timers will be restarted |
8229 | 0 | // when EndPageLoad() is called. |
8230 | 0 | nsCOMPtr<nsIMutableArray> refreshURIList = mLSHE->GetRefreshURIList(); |
8231 | 0 |
|
8232 | 0 | // Reattach to the window object. |
8233 | 0 | mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive |
8234 | 0 | rv = mContentViewer->Open(windowState, mLSHE); |
8235 | 0 | mIsRestoringDocument = false; |
8236 | 0 |
|
8237 | 0 | // Hack to keep nsDocShellEditorData alive across the |
8238 | 0 | // SetContentViewer(nullptr) call below. |
8239 | 0 | nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData()); |
8240 | 0 |
|
8241 | 0 | // Now remove it from the cached presentation. |
8242 | 0 | mLSHE->SetContentViewer(nullptr); |
8243 | 0 | mEODForCurrentDocument = false; |
8244 | 0 |
|
8245 | 0 | mLSHE->SetEditorData(data.forget()); |
8246 | 0 |
|
8247 | | #ifdef DEBUG |
8248 | | { |
8249 | | nsCOMPtr<nsIMutableArray> refreshURIs = mLSHE->GetRefreshURIList(); |
8250 | | nsCOMPtr<nsIDocShellTreeItem> childShell; |
8251 | | mLSHE->ChildShellAt(0, getter_AddRefs(childShell)); |
8252 | | NS_ASSERTION(!refreshURIs && !childShell, |
8253 | | "SHEntry should have cleared presentation state"); |
8254 | | } |
8255 | | #endif |
8256 | |
|
8257 | 0 | // Restore the sticky state of the viewer. The viewer has set this state |
8258 | 0 | // on the history entry in Destroy() just before marking itself non-sticky, |
8259 | 0 | // to avoid teardown of the presentation. |
8260 | 0 | mContentViewer->SetSticky(sticky); |
8261 | 0 |
|
8262 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
8263 | 0 |
|
8264 | 0 | // mLSHE is now our currently-loaded document. |
8265 | 0 | SetHistoryEntry(&mOSHE, mLSHE); |
8266 | 0 |
|
8267 | 0 | // XXX special wyciwyg handling in Embed()? |
8268 | 0 |
|
8269 | 0 | // We aren't going to restore any items from the LayoutHistoryState, |
8270 | 0 | // but we don't want them to stay around in case the page is reloaded. |
8271 | 0 | SetLayoutHistoryState(nullptr); |
8272 | 0 |
|
8273 | 0 | // This is the end of our Embed() replacement |
8274 | 0 |
|
8275 | 0 | mSavingOldViewer = false; |
8276 | 0 | mEODForCurrentDocument = false; |
8277 | 0 |
|
8278 | 0 | // Tell the event loop to favor plevents over user events, see comments |
8279 | 0 | // in CreateContentViewer. |
8280 | 0 | if (++gNumberOfDocumentsLoading == 1) { |
8281 | 0 | FavorPerformanceHint(true); |
8282 | 0 | } |
8283 | 0 |
|
8284 | 0 | if (oldCv && newCv) { |
8285 | 0 | newCv->SetMinFontSize(minFontSize); |
8286 | 0 | newCv->SetTextZoom(textZoom); |
8287 | 0 | newCv->SetFullZoom(pageZoom); |
8288 | 0 | newCv->SetOverrideDPPX(overrideDPPX); |
8289 | 0 | newCv->SetAuthorStyleDisabled(styleDisabled); |
8290 | 0 | } |
8291 | 0 |
|
8292 | 0 | if (document) { |
8293 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
8294 | 0 | if (parent) { |
8295 | 0 | nsCOMPtr<nsIDocument> d = parent->GetDocument(); |
8296 | 0 | if (d) { |
8297 | 0 | if (d->EventHandlingSuppressed()) { |
8298 | 0 | document->SuppressEventHandling(d->EventHandlingSuppressed()); |
8299 | 0 | } |
8300 | 0 | } |
8301 | 0 | } |
8302 | 0 |
|
8303 | 0 | // Use the uri from the mLSHE we had when we entered this function |
8304 | 0 | // (which need not match the document's URI if anchors are involved), |
8305 | 0 | // since that's the history entry we're loading. Note that if we use |
8306 | 0 | // origLSHE we don't have to worry about whether the entry in question |
8307 | 0 | // is still mLSHE or whether it's now mOSHE. |
8308 | 0 | nsCOMPtr<nsIURI> uri = origLSHE->GetURI(); |
8309 | 0 | SetCurrentURI(uri, document->GetChannel(), true, 0); |
8310 | 0 | } |
8311 | 0 |
|
8312 | 0 | // This is the end of our CreateContentViewer() replacement. |
8313 | 0 | // Now we simulate a load. First, we restore the state of the javascript |
8314 | 0 | // window object. |
8315 | 0 | nsCOMPtr<nsPIDOMWindowOuter> privWin = GetWindow(); |
8316 | 0 | NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface"); |
8317 | 0 |
|
8318 | 0 | // Now, dispatch a title change event which would happen as the |
8319 | 0 | // <head> is parsed. |
8320 | 0 | document->NotifyPossibleTitleChange(false); |
8321 | 0 |
|
8322 | 0 | // Now we simulate appending child docshells for subframes. |
8323 | 0 | for (i = 0; i < childShells.Count(); ++i) { |
8324 | 0 | nsIDocShellTreeItem* childItem = childShells.ObjectAt(i); |
8325 | 0 | nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem); |
8326 | 0 |
|
8327 | 0 | // Make sure to not clobber the state of the child. Since AddChild |
8328 | 0 | // always clobbers it, save it off first. |
8329 | 0 | bool allowPlugins; |
8330 | 0 | childShell->GetAllowPlugins(&allowPlugins); |
8331 | 0 |
|
8332 | 0 | bool allowJavascript; |
8333 | 0 | childShell->GetAllowJavascript(&allowJavascript); |
8334 | 0 |
|
8335 | 0 | bool allowRedirects; |
8336 | 0 | childShell->GetAllowMetaRedirects(&allowRedirects); |
8337 | 0 |
|
8338 | 0 | bool allowSubframes; |
8339 | 0 | childShell->GetAllowSubframes(&allowSubframes); |
8340 | 0 |
|
8341 | 0 | bool allowImages; |
8342 | 0 | childShell->GetAllowImages(&allowImages); |
8343 | 0 |
|
8344 | 0 | bool allowMedia = childShell->GetAllowMedia(); |
8345 | 0 |
|
8346 | 0 | bool allowDNSPrefetch; |
8347 | 0 | childShell->GetAllowDNSPrefetch(&allowDNSPrefetch); |
8348 | 0 |
|
8349 | 0 | bool allowContentRetargeting = childShell->GetAllowContentRetargeting(); |
8350 | 0 | bool allowContentRetargetingOnChildren = |
8351 | 0 | childShell->GetAllowContentRetargetingOnChildren(); |
8352 | 0 |
|
8353 | 0 | uint32_t defaultLoadFlags; |
8354 | 0 | childShell->GetDefaultLoadFlags(&defaultLoadFlags); |
8355 | 0 |
|
8356 | 0 | // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that |
8357 | 0 | // the child inherits our state. Among other things, this means that the |
8358 | 0 | // child inherits our mIsActive mPrivateBrowsingId, which is what we want. |
8359 | 0 | AddChild(childItem); |
8360 | 0 |
|
8361 | 0 | childShell->SetAllowPlugins(allowPlugins); |
8362 | 0 | childShell->SetAllowJavascript(allowJavascript); |
8363 | 0 | childShell->SetAllowMetaRedirects(allowRedirects); |
8364 | 0 | childShell->SetAllowSubframes(allowSubframes); |
8365 | 0 | childShell->SetAllowImages(allowImages); |
8366 | 0 | childShell->SetAllowMedia(allowMedia); |
8367 | 0 | childShell->SetAllowDNSPrefetch(allowDNSPrefetch); |
8368 | 0 | childShell->SetAllowContentRetargeting(allowContentRetargeting); |
8369 | 0 | childShell->SetAllowContentRetargetingOnChildren( |
8370 | 0 | allowContentRetargetingOnChildren); |
8371 | 0 | childShell->SetDefaultLoadFlags(defaultLoadFlags); |
8372 | 0 |
|
8373 | 0 | rv = childShell->BeginRestore(nullptr, false); |
8374 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
8375 | 0 | } |
8376 | 0 |
|
8377 | 0 | // Make sure to restore the window state after adding the child shells back |
8378 | 0 | // to the tree. This is necessary for Thaw() and Resume() to propagate |
8379 | 0 | // properly. |
8380 | 0 | rv = privWin->RestoreWindowState(windowState); |
8381 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
8382 | 0 |
|
8383 | 0 | nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
8384 | 0 |
|
8385 | 0 | // We may be displayed on a different monitor (or in a different |
8386 | 0 | // HiDPI mode) than when we got into the history list. So we need |
8387 | 0 | // to check if this has happened. See bug 838239. |
8388 | 0 |
|
8389 | 0 | // Because the prescontext normally handles resolution changes via |
8390 | 0 | // a runnable (see nsPresContext::UIResolutionChanged), its device |
8391 | 0 | // context won't be -immediately- updated as a result of calling |
8392 | 0 | // shell->BackingScaleFactorChanged(). |
8393 | 0 |
|
8394 | 0 | // But we depend on that device context when adjusting the view size |
8395 | 0 | // via mContentViewer->SetBounds(newBounds) below. So we need to |
8396 | 0 | // explicitly tell it to check for changed resolution here. |
8397 | 0 | if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) { |
8398 | 0 | shell->BackingScaleFactorChanged(); |
8399 | 0 | } |
8400 | 0 |
|
8401 | 0 | nsViewManager* newVM = shell ? shell->GetViewManager() : nullptr; |
8402 | 0 | nsView* newRootView = newVM ? newVM->GetRootView() : nullptr; |
8403 | 0 |
|
8404 | 0 | // Insert the new root view at the correct location in the view tree. |
8405 | 0 | if (container) { |
8406 | 0 | nsSubDocumentFrame* subDocFrame = |
8407 | 0 | do_QueryFrame(container->GetPrimaryFrame()); |
8408 | 0 | rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr; |
8409 | 0 | } else { |
8410 | 0 | rootViewParent = nullptr; |
8411 | 0 | } |
8412 | 0 | if (sibling && |
8413 | 0 | sibling->GetShell() && |
8414 | 0 | sibling->GetShell()->GetViewManager()) { |
8415 | 0 | rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView(); |
8416 | 0 | } else { |
8417 | 0 | rootViewSibling = nullptr; |
8418 | 0 | } |
8419 | 0 | if (rootViewParent && newRootView && |
8420 | 0 | newRootView->GetParent() != rootViewParent) { |
8421 | 0 | nsViewManager* parentVM = rootViewParent->GetViewManager(); |
8422 | 0 | if (parentVM) { |
8423 | 0 | // InsertChild(parent, child, sib, true) inserts the child after |
8424 | 0 | // sib in content order, which is before sib in view order. BUT |
8425 | 0 | // when sib is null it inserts at the end of the the document |
8426 | 0 | // order, i.e., first in view order. But when oldRootSibling is |
8427 | 0 | // null, the old root as at the end of the view list --- last in |
8428 | 0 | // content order --- and we want to call InsertChild(parent, child, |
8429 | 0 | // nullptr, false) in that case. |
8430 | 0 | parentVM->InsertChild(rootViewParent, newRootView, |
8431 | 0 | rootViewSibling, |
8432 | 0 | rootViewSibling ? true : false); |
8433 | 0 |
|
8434 | 0 | NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling, |
8435 | 0 | "error in InsertChild"); |
8436 | 0 | } |
8437 | 0 | } |
8438 | 0 |
|
8439 | 0 | nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow(); |
8440 | 0 |
|
8441 | 0 | // If parent is suspended, increase suspension count. |
8442 | 0 | // This can't be done as early as event suppression since this |
8443 | 0 | // depends on docshell tree. |
8444 | 0 | privWinInner->SyncStateFromParentWindow(); |
8445 | 0 |
|
8446 | 0 | // Now that all of the child docshells have been put into place, we can |
8447 | 0 | // restart the timers for the window and all of the child frames. |
8448 | 0 | privWinInner->Resume(); |
8449 | 0 |
|
8450 | 0 | // Restore the refresh URI list. The refresh timers will be restarted |
8451 | 0 | // when EndPageLoad() is called. |
8452 | 0 | mRefreshURIList = refreshURIList; |
8453 | 0 |
|
8454 | 0 | // Meta-refresh timers have been restarted for this shell, but not |
8455 | 0 | // for our children. Walk the child shells and restart their timers. |
8456 | 0 | nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
8457 | 0 | while (iter.HasMore()) { |
8458 | 0 | nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext()); |
8459 | 0 | if (child) { |
8460 | 0 | child->ResumeRefreshURIs(); |
8461 | 0 | } |
8462 | 0 | } |
8463 | 0 |
|
8464 | 0 | // Make sure this presentation is the same size as the previous |
8465 | 0 | // presentation. If this is not the same size we showed it at last time, |
8466 | 0 | // then we need to resize the widget. |
8467 | 0 |
|
8468 | 0 | // XXXbryner This interacts poorly with Firefox's infobar. If the old |
8469 | 0 | // presentation had the infobar visible, then we will resize the new |
8470 | 0 | // presentation to that smaller size. However, firing the locationchanged |
8471 | 0 | // event will hide the infobar, which will immediately resize the window |
8472 | 0 | // back to the larger size. A future optimization might be to restore |
8473 | 0 | // the presentation at the "wrong" size, then fire the locationchanged |
8474 | 0 | // event and check whether the docshell's new size is the same as the |
8475 | 0 | // cached viewer size (skipping the resize if they are equal). |
8476 | 0 |
|
8477 | 0 | if (newRootView) { |
8478 | 0 | if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) { |
8479 | | #ifdef DEBUG_PAGE_CACHE |
8480 | | printf("resize widget(%d, %d, %d, %d)\n", newBounds.x, |
8481 | | newBounds.y, newBounds.width, newBounds.height); |
8482 | | #endif |
8483 | | mContentViewer->SetBounds(newBounds); |
8484 | 0 | } else { |
8485 | 0 | nsIScrollableFrame* rootScrollFrame = |
8486 | 0 | shell->GetRootScrollFrameAsScrollable(); |
8487 | 0 | if (rootScrollFrame) { |
8488 | 0 | rootScrollFrame->PostScrolledAreaEventForCurrentArea(); |
8489 | 0 | } |
8490 | 0 | } |
8491 | 0 | } |
8492 | 0 |
|
8493 | 0 | // The FinishRestore call below can kill these, null them out so we don't |
8494 | 0 | // have invalid pointer lying around. |
8495 | 0 | newRootView = rootViewSibling = rootViewParent = nullptr; |
8496 | 0 | newVM = nullptr; |
8497 | 0 |
|
8498 | 0 | // Simulate the completion of the load. |
8499 | 0 | nsDocShell::FinishRestore(); |
8500 | 0 |
|
8501 | 0 | // Restart plugins, and paint the content. |
8502 | 0 | if (shell) { |
8503 | 0 | shell->Thaw(); |
8504 | 0 | } |
8505 | 0 |
|
8506 | 0 | return privWin->FireDelayedDOMEvents(); |
8507 | 0 | } |
8508 | | |
8509 | | nsresult |
8510 | | nsDocShell::CreateContentViewer(const nsACString& aContentType, |
8511 | | nsIRequest* aRequest, |
8512 | | nsIStreamListener** aContentHandler) |
8513 | 0 | { |
8514 | 0 | *aContentHandler = nullptr; |
8515 | 0 |
|
8516 | 0 | if (!mTreeOwner || mIsBeingDestroyed) { |
8517 | 0 | // If we don't have a tree owner, then we're in the process of being |
8518 | 0 | // destroyed. Rather than continue trying to load something, just give up. |
8519 | 0 | return NS_ERROR_DOCSHELL_DYING; |
8520 | 0 | } |
8521 | 0 | |
8522 | 0 | // Can we check the content type of the current content viewer |
8523 | 0 | // and reuse it without destroying it and re-creating it? |
8524 | 0 | |
8525 | 0 | NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?"); |
8526 | 0 |
|
8527 | 0 | // Instantiate the content viewer object |
8528 | 0 | nsCOMPtr<nsIContentViewer> viewer; |
8529 | 0 | nsresult rv = NewContentViewerObj(aContentType, aRequest, mLoadGroup, |
8530 | 0 | aContentHandler, getter_AddRefs(viewer)); |
8531 | 0 |
|
8532 | 0 | if (NS_FAILED(rv)) { |
8533 | 0 | return rv; |
8534 | 0 | } |
8535 | 0 | |
8536 | 0 | // Notify the current document that it is about to be unloaded!! |
8537 | 0 | // |
8538 | 0 | // It is important to fire the unload() notification *before* any state |
8539 | 0 | // is changed within the DocShell - otherwise, javascript will get the |
8540 | 0 | // wrong information :-( |
8541 | 0 | // |
8542 | 0 | |
8543 | 0 | if (mSavingOldViewer) { |
8544 | 0 | // We determined that it was safe to cache the document presentation |
8545 | 0 | // at the time we initiated the new load. We need to check whether |
8546 | 0 | // it's still safe to do so, since there may have been DOM mutations |
8547 | 0 | // or new requests initiated. |
8548 | 0 | nsCOMPtr<nsIDocument> doc = viewer->GetDocument(); |
8549 | 0 | mSavingOldViewer = CanSavePresentation(mLoadType, aRequest, doc); |
8550 | 0 | } |
8551 | 0 |
|
8552 | 0 | NS_ASSERTION(!mLoadingURI, "Re-entering unload?"); |
8553 | 0 |
|
8554 | 0 | nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest); |
8555 | 0 | if (aOpenedChannel) { |
8556 | 0 | aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI)); |
8557 | 0 | } |
8558 | 0 | FirePageHideNotification(!mSavingOldViewer); |
8559 | 0 | if (mIsBeingDestroyed) { |
8560 | 0 | // Force to stop the newly created orphaned viewer. |
8561 | 0 | viewer->Stop(); |
8562 | 0 | return NS_ERROR_DOCSHELL_DYING; |
8563 | 0 | } |
8564 | 0 | mLoadingURI = nullptr; |
8565 | 0 |
|
8566 | 0 | // Set mFiredUnloadEvent = false so that the unload handler for the |
8567 | 0 | // *new* document will fire. |
8568 | 0 | mFiredUnloadEvent = false; |
8569 | 0 |
|
8570 | 0 | // we've created a new document so go ahead and call |
8571 | 0 | // OnLoadingSite(), but don't fire OnLocationChange() |
8572 | 0 | // notifications before we've called Embed(). See bug 284993. |
8573 | 0 | mURIResultedInDocument = true; |
8574 | 0 | bool errorOnLocationChangeNeeded = false; |
8575 | 0 | nsCOMPtr<nsIChannel> failedChannel = mFailedChannel; |
8576 | 0 | nsCOMPtr<nsIURI> failedURI; |
8577 | 0 |
|
8578 | 0 | if (mLoadType == LOAD_ERROR_PAGE) { |
8579 | 0 | // We need to set the SH entry and our current URI here and not |
8580 | 0 | // at the moment we load the page. We want the same behavior |
8581 | 0 | // of Stop() as for a normal page load. See bug 514232 for details. |
8582 | 0 |
|
8583 | 0 | // Revert mLoadType to load type to state the page load failed, |
8584 | 0 | // following function calls need it. |
8585 | 0 | mLoadType = mFailedLoadType; |
8586 | 0 |
|
8587 | 0 |
|
8588 | 0 | nsIDocument* doc = viewer->GetDocument(); |
8589 | 0 | if (doc) { |
8590 | 0 | doc->SetFailedChannel(failedChannel); |
8591 | 0 | } |
8592 | 0 |
|
8593 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal; |
8594 | 0 | if (failedChannel) { |
8595 | 0 | // Make sure we have a URI to set currentURI. |
8596 | 0 | NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI)); |
8597 | 0 | } |
8598 | 0 | else { |
8599 | 0 | // if there is no failed channel we have to explicitly provide |
8600 | 0 | // a triggeringPrincipal for the history entry. |
8601 | 0 | triggeringPrincipal = nsContentUtils::GetSystemPrincipal(); |
8602 | 0 | } |
8603 | 0 |
|
8604 | 0 | if (!failedURI) { |
8605 | 0 | failedURI = mFailedURI; |
8606 | 0 | } |
8607 | 0 | if (!failedURI) { |
8608 | 0 | // We need a URI object to store a session history entry, so make up a URI |
8609 | 0 | NS_NewURI(getter_AddRefs(failedURI), "about:blank"); |
8610 | 0 | } |
8611 | 0 |
|
8612 | 0 | // When we don't have failedURI, something wrong will happen. See |
8613 | 0 | // bug 291876. |
8614 | 0 | MOZ_ASSERT(failedURI, "We don't have a URI for history APIs."); |
8615 | 0 |
|
8616 | 0 | mFailedChannel = nullptr; |
8617 | 0 | mFailedURI = nullptr; |
8618 | 0 |
|
8619 | 0 | // Create an shistory entry for the old load. |
8620 | 0 | if (failedURI) { |
8621 | 0 | errorOnLocationChangeNeeded = OnNewURI( |
8622 | 0 | failedURI, failedChannel, triggeringPrincipal, |
8623 | 0 | nullptr, mLoadType, false, false, false); |
8624 | 0 | } |
8625 | 0 |
|
8626 | 0 | // Be sure to have a correct mLSHE, it may have been cleared by |
8627 | 0 | // EndPageLoad. See bug 302115. |
8628 | 0 | if (mSessionHistory && !mLSHE) { |
8629 | 0 | int32_t idx = mSessionHistory->LegacySHistory()->GetRequestedIndex(); |
8630 | 0 | if (idx == -1) { |
8631 | 0 | idx = mSessionHistory->Index(); |
8632 | 0 | } |
8633 | 0 | mSessionHistory->LegacySHistory()-> |
8634 | 0 | GetEntryAtIndex(idx, getter_AddRefs(mLSHE)); |
8635 | 0 | } |
8636 | 0 |
|
8637 | 0 | mLoadType = LOAD_ERROR_PAGE; |
8638 | 0 | } |
8639 | 0 |
|
8640 | 0 | bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false); |
8641 | 0 |
|
8642 | 0 | // let's try resetting the load group if we need to... |
8643 | 0 | nsCOMPtr<nsILoadGroup> currentLoadGroup; |
8644 | 0 | NS_ENSURE_SUCCESS( |
8645 | 0 | aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)), |
8646 | 0 | NS_ERROR_FAILURE); |
8647 | 0 |
|
8648 | 0 | if (currentLoadGroup != mLoadGroup) { |
8649 | 0 | nsLoadFlags loadFlags = 0; |
8650 | 0 |
|
8651 | 0 | // Cancel any URIs that are currently loading... |
8652 | 0 | // XXX: Need to do this eventually Stop(); |
8653 | 0 | // |
8654 | 0 | // Retarget the document to this loadgroup... |
8655 | 0 | // |
8656 | 0 | /* First attach the channel to the right loadgroup |
8657 | 0 | * and then remove from the old loadgroup. This |
8658 | 0 | * puts the notifications in the right order and |
8659 | 0 | * we don't null-out mLSHE in OnStateChange() for |
8660 | 0 | * all redirected urls |
8661 | 0 | */ |
8662 | 0 | aOpenedChannel->SetLoadGroup(mLoadGroup); |
8663 | 0 |
|
8664 | 0 | // Mark the channel as being a document URI... |
8665 | 0 | aOpenedChannel->GetLoadFlags(&loadFlags); |
8666 | 0 | loadFlags |= nsIChannel::LOAD_DOCUMENT_URI; |
8667 | 0 | if (SandboxFlagsImplyCookies(mSandboxFlags)) { |
8668 | 0 | loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE; |
8669 | 0 | } |
8670 | 0 |
|
8671 | 0 | aOpenedChannel->SetLoadFlags(loadFlags); |
8672 | 0 |
|
8673 | 0 | mLoadGroup->AddRequest(aRequest, nullptr); |
8674 | 0 | if (currentLoadGroup) { |
8675 | 0 | currentLoadGroup->RemoveRequest(aRequest, nullptr, NS_BINDING_RETARGETED); |
8676 | 0 | } |
8677 | 0 |
|
8678 | 0 | // Update the notification callbacks, so that progress and |
8679 | 0 | // status information are sent to the right docshell... |
8680 | 0 | aOpenedChannel->SetNotificationCallbacks(this); |
8681 | 0 | } |
8682 | 0 |
|
8683 | 0 | NS_ENSURE_SUCCESS(Embed(viewer, "", nullptr), NS_ERROR_FAILURE); |
8684 | 0 |
|
8685 | 0 | mSavedRefreshURIList = nullptr; |
8686 | 0 | mSavingOldViewer = false; |
8687 | 0 | mEODForCurrentDocument = false; |
8688 | 0 |
|
8689 | 0 | // if this document is part of a multipart document, |
8690 | 0 | // the ID can be used to distinguish it from the other parts. |
8691 | 0 | nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest)); |
8692 | 0 | if (multiPartChannel) { |
8693 | 0 | nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
8694 | 0 | if (NS_SUCCEEDED(rv) && shell) { |
8695 | 0 | nsIDocument* doc = shell->GetDocument(); |
8696 | 0 | if (doc) { |
8697 | 0 | uint32_t partID; |
8698 | 0 | multiPartChannel->GetPartID(&partID); |
8699 | 0 | doc->SetPartID(partID); |
8700 | 0 | } |
8701 | 0 | } |
8702 | 0 | } |
8703 | 0 |
|
8704 | 0 | // Give hint to native plevent dispatch mechanism. If a document |
8705 | 0 | // is loading the native plevent dispatch mechanism should favor |
8706 | 0 | // performance over normal native event dispatch priorities. |
8707 | 0 | if (++gNumberOfDocumentsLoading == 1) { |
8708 | 0 | // Hint to favor performance for the plevent notification mechanism. |
8709 | 0 | // We want the pages to load as fast as possible even if its means |
8710 | 0 | // native messages might be starved. |
8711 | 0 | FavorPerformanceHint(true); |
8712 | 0 | } |
8713 | 0 |
|
8714 | 0 | if (errorOnLocationChangeNeeded){ |
8715 | 0 | FireOnLocationChange(this, failedChannel, failedURI, |
8716 | 0 | LOCATION_CHANGE_ERROR_PAGE); |
8717 | 0 | } else if (onLocationChangeNeeded) { |
8718 | 0 | FireOnLocationChange(this, aRequest, mCurrentURI, 0); |
8719 | 0 | } |
8720 | 0 |
|
8721 | 0 | return NS_OK; |
8722 | 0 | } |
8723 | | |
8724 | | nsresult |
8725 | | nsDocShell::NewContentViewerObj(const nsACString& aContentType, |
8726 | | nsIRequest* aRequest, nsILoadGroup* aLoadGroup, |
8727 | | nsIStreamListener** aContentHandler, |
8728 | | nsIContentViewer** aViewer) |
8729 | 0 | { |
8730 | 0 | nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest); |
8731 | 0 |
|
8732 | 0 | nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory = |
8733 | 0 | nsContentUtils::FindInternalContentViewer(aContentType); |
8734 | 0 | if (!docLoaderFactory) { |
8735 | 0 | return NS_ERROR_FAILURE; |
8736 | 0 | } |
8737 | 0 | |
8738 | 0 | // Now create an instance of the content viewer nsLayoutDLF makes the |
8739 | 0 | // determination if it should be a "view-source" instead of "view" |
8740 | 0 | nsresult rv = docLoaderFactory->CreateInstance("view", |
8741 | 0 | aOpenedChannel, |
8742 | 0 | aLoadGroup, aContentType, |
8743 | 0 | this, |
8744 | 0 | nullptr, |
8745 | 0 | aContentHandler, |
8746 | 0 | aViewer); |
8747 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
8748 | 0 |
|
8749 | 0 | (*aViewer)->SetContainer(this); |
8750 | 0 | return NS_OK; |
8751 | 0 | } |
8752 | | |
8753 | | nsresult |
8754 | | nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer) |
8755 | 0 | { |
8756 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
8757 | 0 |
|
8758 | 0 | // |
8759 | 0 | // Copy content viewer state from previous or parent content viewer. |
8760 | 0 | // |
8761 | 0 | // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad! |
8762 | 0 | // |
8763 | 0 | // Do NOT to maintain a reference to the old content viewer outside |
8764 | 0 | // of this "copying" block, or it will not be destroyed until the end of |
8765 | 0 | // this routine and all <SCRIPT>s and event handlers fail! (bug 20315) |
8766 | 0 | // |
8767 | 0 | // In this block of code, if we get an error result, we return it |
8768 | 0 | // but if we get a null pointer, that's perfectly legal for parent |
8769 | 0 | // and parentContentViewer. |
8770 | 0 | // |
8771 | 0 |
|
8772 | 0 | int32_t x = 0; |
8773 | 0 | int32_t y = 0; |
8774 | 0 | int32_t cx = 0; |
8775 | 0 | int32_t cy = 0; |
8776 | 0 |
|
8777 | 0 | // This will get the size from the current content viewer or from the |
8778 | 0 | // Init settings |
8779 | 0 | DoGetPositionAndSize(&x, &y, &cx, &cy); |
8780 | 0 |
|
8781 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
8782 | 0 | NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)), |
8783 | 0 | NS_ERROR_FAILURE); |
8784 | 0 | nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem)); |
8785 | 0 |
|
8786 | 0 | const Encoding* forceCharset = nullptr; |
8787 | 0 | const Encoding* hintCharset = nullptr; |
8788 | 0 | int32_t hintCharsetSource; |
8789 | 0 | int32_t minFontSize; |
8790 | 0 | float textZoom; |
8791 | 0 | float pageZoom; |
8792 | 0 | float overrideDPPX; |
8793 | 0 | bool styleDisabled; |
8794 | 0 | // |newMUDV| also serves as a flag to set the data from the above vars |
8795 | 0 | nsCOMPtr<nsIContentViewer> newCv; |
8796 | 0 |
|
8797 | 0 | if (mContentViewer || parent) { |
8798 | 0 | nsCOMPtr<nsIContentViewer> oldCv; |
8799 | 0 | if (mContentViewer) { |
8800 | 0 | // Get any interesting state from old content viewer |
8801 | 0 | // XXX: it would be far better to just reuse the document viewer , |
8802 | 0 | // since we know we're just displaying the same document as before |
8803 | 0 | oldCv = mContentViewer; |
8804 | 0 |
|
8805 | 0 | // Tell the old content viewer to hibernate in session history when |
8806 | 0 | // it is destroyed. |
8807 | 0 |
|
8808 | 0 | if (mSavingOldViewer && NS_FAILED(CaptureState())) { |
8809 | 0 | if (mOSHE) { |
8810 | 0 | mOSHE->SyncPresentationState(); |
8811 | 0 | } |
8812 | 0 | mSavingOldViewer = false; |
8813 | 0 | } |
8814 | 0 | } else { |
8815 | 0 | // No old content viewer, so get state from parent's content viewer |
8816 | 0 | parent->GetContentViewer(getter_AddRefs(oldCv)); |
8817 | 0 | } |
8818 | 0 |
|
8819 | 0 | if (oldCv) { |
8820 | 0 | newCv = aNewViewer; |
8821 | 0 | if (newCv) { |
8822 | 0 | forceCharset = oldCv->GetForceCharset(); |
8823 | 0 | hintCharset = oldCv->GetHintCharset(); |
8824 | 0 | NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSetSource(&hintCharsetSource), |
8825 | 0 | NS_ERROR_FAILURE); |
8826 | 0 | NS_ENSURE_SUCCESS(oldCv->GetMinFontSize(&minFontSize), |
8827 | 0 | NS_ERROR_FAILURE); |
8828 | 0 | NS_ENSURE_SUCCESS(oldCv->GetTextZoom(&textZoom), |
8829 | 0 | NS_ERROR_FAILURE); |
8830 | 0 | NS_ENSURE_SUCCESS(oldCv->GetFullZoom(&pageZoom), |
8831 | 0 | NS_ERROR_FAILURE); |
8832 | 0 | NS_ENSURE_SUCCESS(oldCv->GetOverrideDPPX(&overrideDPPX), |
8833 | 0 | NS_ERROR_FAILURE); |
8834 | 0 | NS_ENSURE_SUCCESS(oldCv->GetAuthorStyleDisabled(&styleDisabled), |
8835 | 0 | NS_ERROR_FAILURE); |
8836 | 0 | } |
8837 | 0 | } |
8838 | 0 | } |
8839 | 0 |
|
8840 | 0 | nscolor bgcolor = NS_RGBA(0, 0, 0, 0); |
8841 | 0 | bool isActive = false; |
8842 | 0 | // Ensure that the content viewer is destroyed *after* the GC - bug 71515 |
8843 | 0 | nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer; |
8844 | 0 | if (contentViewer) { |
8845 | 0 | // Stop any activity that may be happening in the old document before |
8846 | 0 | // releasing it... |
8847 | 0 | contentViewer->Stop(); |
8848 | 0 |
|
8849 | 0 | // Try to extract the canvas background color from the old |
8850 | 0 | // presentation shell, so we can use it for the next document. |
8851 | 0 | nsCOMPtr<nsIPresShell> shell; |
8852 | 0 | contentViewer->GetPresShell(getter_AddRefs(shell)); |
8853 | 0 |
|
8854 | 0 | if (shell) { |
8855 | 0 | bgcolor = shell->GetCanvasBackground(); |
8856 | 0 | isActive = shell->IsActive(); |
8857 | 0 | } |
8858 | 0 |
|
8859 | 0 | contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr); |
8860 | 0 | aNewViewer->SetPreviousViewer(contentViewer); |
8861 | 0 | } |
8862 | 0 | if (mOSHE && (!mContentViewer || !mSavingOldViewer)) { |
8863 | 0 | // We don't plan to save a viewer in mOSHE; tell it to drop |
8864 | 0 | // any other state it's holding. |
8865 | 0 | mOSHE->SyncPresentationState(); |
8866 | 0 | } |
8867 | 0 |
|
8868 | 0 | mContentViewer = nullptr; |
8869 | 0 |
|
8870 | 0 | // Now that we're about to switch documents, forget all of our children. |
8871 | 0 | // Note that we cached them as needed up in CaptureState above. |
8872 | 0 | DestroyChildren(); |
8873 | 0 |
|
8874 | 0 | mContentViewer = aNewViewer; |
8875 | 0 |
|
8876 | 0 | nsCOMPtr<nsIWidget> widget; |
8877 | 0 | NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE); |
8878 | 0 |
|
8879 | 0 | nsIntRect bounds(x, y, cx, cy); |
8880 | 0 |
|
8881 | 0 | mContentViewer->SetNavigationTiming(mTiming); |
8882 | 0 |
|
8883 | 0 | if (NS_FAILED(mContentViewer->Init(widget, bounds))) { |
8884 | 0 | mContentViewer = nullptr; |
8885 | 0 | NS_WARNING("ContentViewer Initialization failed"); |
8886 | 0 | return NS_ERROR_FAILURE; |
8887 | 0 | } |
8888 | 0 |
|
8889 | 0 | // If we have old state to copy, set the old state onto the new content |
8890 | 0 | // viewer |
8891 | 0 | if (newCv) { |
8892 | 0 | newCv->SetForceCharset(forceCharset); |
8893 | 0 | newCv->SetHintCharset(hintCharset); |
8894 | 0 | NS_ENSURE_SUCCESS(newCv->SetHintCharacterSetSource(hintCharsetSource), |
8895 | 0 | NS_ERROR_FAILURE); |
8896 | 0 | NS_ENSURE_SUCCESS(newCv->SetMinFontSize(minFontSize), |
8897 | 0 | NS_ERROR_FAILURE); |
8898 | 0 | NS_ENSURE_SUCCESS(newCv->SetTextZoom(textZoom), |
8899 | 0 | NS_ERROR_FAILURE); |
8900 | 0 | NS_ENSURE_SUCCESS(newCv->SetFullZoom(pageZoom), |
8901 | 0 | NS_ERROR_FAILURE); |
8902 | 0 | NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX), |
8903 | 0 | NS_ERROR_FAILURE); |
8904 | 0 | NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled), |
8905 | 0 | NS_ERROR_FAILURE); |
8906 | 0 | } |
8907 | 0 |
|
8908 | 0 | // Stuff the bgcolor from the old pres shell into the new |
8909 | 0 | // pres shell. This improves page load continuity. |
8910 | 0 | nsCOMPtr<nsIPresShell> shell; |
8911 | 0 | mContentViewer->GetPresShell(getter_AddRefs(shell)); |
8912 | 0 |
|
8913 | 0 | if (shell) { |
8914 | 0 | shell->SetCanvasBackground(bgcolor); |
8915 | 0 | if (isActive) { |
8916 | 0 | shell->SetIsActive(isActive); |
8917 | 0 | } |
8918 | 0 | } |
8919 | 0 |
|
8920 | 0 | // XXX: It looks like the LayoutState gets restored again in Embed() |
8921 | 0 | // right after the call to SetupNewViewer(...) |
8922 | 0 |
|
8923 | 0 | // We don't show the mContentViewer yet, since we want to draw the old page |
8924 | 0 | // until we have enough of the new page to show. Just return with the new |
8925 | 0 | // viewer still set to hidden. |
8926 | 0 |
|
8927 | 0 | return NS_OK; |
8928 | 0 | } |
8929 | | |
8930 | | nsresult |
8931 | | nsDocShell::SetDocCurrentStateObj(nsISHEntry* aShEntry) |
8932 | 0 | { |
8933 | 0 | NS_ENSURE_STATE(mContentViewer); |
8934 | 0 | nsCOMPtr<nsIDocument> document = GetDocument(); |
8935 | 0 | NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); |
8936 | 0 |
|
8937 | 0 | nsCOMPtr<nsIStructuredCloneContainer> scContainer; |
8938 | 0 | if (aShEntry) { |
8939 | 0 | scContainer = aShEntry->GetStateData(); |
8940 | 0 |
|
8941 | 0 | // If aShEntry is null, just set the document's state object to null. |
8942 | 0 | } |
8943 | 0 |
|
8944 | 0 | // It's OK for scContainer too be null here; that just means there's no |
8945 | 0 | // state data associated with this history entry. |
8946 | 0 | document->SetStateObject(scContainer); |
8947 | 0 |
|
8948 | 0 | return NS_OK; |
8949 | 0 | } |
8950 | | |
8951 | | nsresult |
8952 | | nsDocShell::CheckLoadingPermissions() |
8953 | 0 | { |
8954 | 0 | // This method checks whether the caller may load content into |
8955 | 0 | // this docshell. Even though we've done our best to hide windows |
8956 | 0 | // from code that doesn't have the right to access them, it's |
8957 | 0 | // still possible for an evil site to open a window and access |
8958 | 0 | // frames in the new window through window.frames[] (which is |
8959 | 0 | // allAccess for historic reasons), so we still need to do this |
8960 | 0 | // check on load. |
8961 | 0 | nsresult rv = NS_OK; |
8962 | 0 |
|
8963 | 0 | if (!gValidateOrigin || !IsFrame()) { |
8964 | 0 | // Origin validation was turned off, or we're not a frame. |
8965 | 0 | // Permit all loads. |
8966 | 0 |
|
8967 | 0 | return rv; |
8968 | 0 | } |
8969 | 0 | |
8970 | 0 | // Note - The check for a current JSContext here isn't necessarily sensical. |
8971 | 0 | // It's just designed to preserve the old semantics during a mass-conversion |
8972 | 0 | // patch. |
8973 | 0 | if (!nsContentUtils::GetCurrentJSContext()) { |
8974 | 0 | return NS_OK; |
8975 | 0 | } |
8976 | 0 | |
8977 | 0 | // Check if the caller is from the same origin as this docshell, |
8978 | 0 | // or any of its ancestors. |
8979 | 0 | nsCOMPtr<nsIDocShellTreeItem> item(this); |
8980 | 0 | do { |
8981 | 0 | nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(item); |
8982 | 0 | nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo)); |
8983 | 0 |
|
8984 | 0 | nsIPrincipal* p; |
8985 | 0 | if (!sop || !(p = sop->GetPrincipal())) { |
8986 | 0 | return NS_ERROR_UNEXPECTED; |
8987 | 0 | } |
8988 | 0 | |
8989 | 0 | if (nsContentUtils::SubjectPrincipal()->Subsumes(p)) { |
8990 | 0 | // Same origin, permit load |
8991 | 0 | return NS_OK; |
8992 | 0 | } |
8993 | 0 | |
8994 | 0 | nsCOMPtr<nsIDocShellTreeItem> tmp; |
8995 | 0 | item->GetSameTypeParent(getter_AddRefs(tmp)); |
8996 | 0 | item.swap(tmp); |
8997 | 0 | } while (item); |
8998 | 0 |
|
8999 | 0 | return NS_ERROR_DOM_PROP_ACCESS_DENIED; |
9000 | 0 | } |
9001 | | |
9002 | | //***************************************************************************** |
9003 | | // nsDocShell: Site Loading |
9004 | | //***************************************************************************** |
9005 | | |
9006 | | void |
9007 | | nsDocShell::CopyFavicon(nsIURI* aOldURI, |
9008 | | nsIURI* aNewURI, |
9009 | | nsIPrincipal* aLoadingPrincipal, |
9010 | | bool aInPrivateBrowsing) |
9011 | 0 | { |
9012 | 0 | if (XRE_IsContentProcess()) { |
9013 | 0 | dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); |
9014 | 0 | if (contentChild) { |
9015 | 0 | mozilla::ipc::URIParams oldURI, newURI; |
9016 | 0 | SerializeURI(aOldURI, oldURI); |
9017 | 0 | SerializeURI(aNewURI, newURI); |
9018 | 0 | contentChild->SendCopyFavicon(oldURI, newURI, |
9019 | 0 | IPC::Principal(aLoadingPrincipal), |
9020 | 0 | aInPrivateBrowsing); |
9021 | 0 | } |
9022 | 0 | return; |
9023 | 0 | } |
9024 | 0 |
|
9025 | 0 | #ifdef MOZ_PLACES |
9026 | 0 | nsCOMPtr<nsIFaviconService> favSvc = |
9027 | 0 | do_GetService("@mozilla.org/browser/favicon-service;1"); |
9028 | 0 | if (favSvc) { |
9029 | 0 | favSvc->CopyFavicons(aOldURI, aNewURI, |
9030 | 0 | aInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE |
9031 | 0 | : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, nullptr); |
9032 | 0 | } |
9033 | 0 | #endif |
9034 | 0 | } |
9035 | | |
9036 | | class InternalLoadEvent : public Runnable |
9037 | | { |
9038 | | public: |
9039 | | InternalLoadEvent(nsDocShell* aDocShell, |
9040 | | nsIURI* aURI, |
9041 | | nsIURI* aOriginalURI, |
9042 | | Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI, |
9043 | | bool aKeepResultPrincipalURIIfSet, |
9044 | | bool aLoadReplace, |
9045 | | nsIURI* aReferrer, uint32_t aReferrerPolicy, |
9046 | | nsIPrincipal* aTriggeringPrincipal, |
9047 | | nsIPrincipal* aPrincipalToInherit, |
9048 | | uint32_t aFlags, |
9049 | | const char* aTypeHint, |
9050 | | nsIInputStream* aPostData, |
9051 | | nsIInputStream* aHeadersData, |
9052 | | uint32_t aLoadType, |
9053 | | nsISHEntry* aSHEntry, |
9054 | | bool aFirstParty, |
9055 | | const nsAString& aSrcdoc, |
9056 | | nsIDocShell* aSourceDocShell, |
9057 | | nsIURI* aBaseURI) |
9058 | | : mozilla::Runnable("InternalLoadEvent") |
9059 | | , mSrcdoc(aSrcdoc) |
9060 | | , mDocShell(aDocShell) |
9061 | | , mURI(aURI) |
9062 | | , mOriginalURI(aOriginalURI) |
9063 | | , mResultPrincipalURI(aResultPrincipalURI) |
9064 | | , mKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet) |
9065 | | , mLoadReplace(aLoadReplace) |
9066 | | , mReferrer(aReferrer) |
9067 | | , mReferrerPolicy(aReferrerPolicy) |
9068 | | , mTriggeringPrincipal(aTriggeringPrincipal) |
9069 | | , mPrincipalToInherit(aPrincipalToInherit) |
9070 | | , mPostData(aPostData) |
9071 | | , mHeadersData(aHeadersData) |
9072 | | , mSHEntry(aSHEntry) |
9073 | | , mFlags(aFlags) |
9074 | | , mLoadType(aLoadType) |
9075 | | , mFirstParty(aFirstParty) |
9076 | | , mSourceDocShell(aSourceDocShell) |
9077 | | , mBaseURI(aBaseURI) |
9078 | 0 | { |
9079 | 0 | // Make sure to keep null things null as needed |
9080 | 0 | if (aTypeHint) { |
9081 | 0 | mTypeHint = aTypeHint; |
9082 | 0 | } else { |
9083 | 0 | mTypeHint.SetIsVoid(true); |
9084 | 0 | } |
9085 | 0 | } |
9086 | | |
9087 | | NS_IMETHOD |
9088 | | Run() override |
9089 | 0 | { |
9090 | 0 | return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI, |
9091 | 0 | mKeepResultPrincipalURIIfSet, |
9092 | 0 | mLoadReplace, |
9093 | 0 | mReferrer, |
9094 | 0 | mReferrerPolicy, |
9095 | 0 | mTriggeringPrincipal, mPrincipalToInherit, |
9096 | 0 | mFlags, EmptyString(), |
9097 | 0 | mTypeHint.IsVoid() ? nullptr |
9098 | 0 | : mTypeHint.get(), |
9099 | 0 | VoidString(), mPostData, |
9100 | 0 | mHeadersData, mLoadType, mSHEntry, |
9101 | 0 | mFirstParty, mSrcdoc, mSourceDocShell, |
9102 | 0 | mBaseURI, nullptr, |
9103 | 0 | nullptr); |
9104 | 0 | } |
9105 | | |
9106 | | private: |
9107 | | nsCString mTypeHint; |
9108 | | nsString mSrcdoc; |
9109 | | |
9110 | | RefPtr<nsDocShell> mDocShell; |
9111 | | nsCOMPtr<nsIURI> mURI; |
9112 | | nsCOMPtr<nsIURI> mOriginalURI; |
9113 | | Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI; |
9114 | | bool mKeepResultPrincipalURIIfSet; |
9115 | | bool mLoadReplace; |
9116 | | nsCOMPtr<nsIURI> mReferrer; |
9117 | | uint32_t mReferrerPolicy; |
9118 | | nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; |
9119 | | nsCOMPtr<nsIPrincipal> mPrincipalToInherit; |
9120 | | nsCOMPtr<nsIInputStream> mPostData; |
9121 | | nsCOMPtr<nsIInputStream> mHeadersData; |
9122 | | nsCOMPtr<nsISHEntry> mSHEntry; |
9123 | | uint32_t mFlags; |
9124 | | uint32_t mLoadType; |
9125 | | bool mFirstParty; |
9126 | | nsCOMPtr<nsIDocShell> mSourceDocShell; |
9127 | | nsCOMPtr<nsIURI> mBaseURI; |
9128 | | }; |
9129 | | |
9130 | | /** |
9131 | | * Returns true if we started an asynchronous load (i.e., from the network), but |
9132 | | * the document we're loading there hasn't yet become this docshell's active |
9133 | | * document. |
9134 | | * |
9135 | | * When JustStartedNetworkLoad is true, you should be careful about modifying |
9136 | | * mLoadType and mLSHE. These are both set when the asynchronous load first |
9137 | | * starts, and the load expects that, when it eventually runs InternalLoad, |
9138 | | * mLoadType and mLSHE will have their original values. |
9139 | | */ |
9140 | | bool |
9141 | | nsDocShell::JustStartedNetworkLoad() |
9142 | 0 | { |
9143 | 0 | return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel(); |
9144 | 0 | } |
9145 | | |
9146 | | nsresult |
9147 | | nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer, |
9148 | | nsIPrincipal** aResult) |
9149 | 0 | { |
9150 | 0 | nsCOMPtr<nsIPrincipal> prin = |
9151 | 0 | BasePrincipal::CreateCodebasePrincipal(aReferrer, mOriginAttributes); |
9152 | 0 | prin.forget(aResult); |
9153 | 0 |
|
9154 | 0 | return *aResult ? NS_OK : NS_ERROR_FAILURE; |
9155 | 0 | } |
9156 | | |
9157 | | NS_IMETHODIMP |
9158 | | nsDocShell::InternalLoad(nsIURI* aURI, |
9159 | | nsIURI* aOriginalURI, |
9160 | | Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI, |
9161 | | bool aKeepResultPrincipalURIIfSet, |
9162 | | bool aLoadReplace, |
9163 | | nsIURI* aReferrer, |
9164 | | uint32_t aReferrerPolicy, |
9165 | | nsIPrincipal* aTriggeringPrincipal, |
9166 | | nsIPrincipal* aPrincipalToInherit, |
9167 | | uint32_t aFlags, |
9168 | | const nsAString& aWindowTarget, |
9169 | | const char* aTypeHint, |
9170 | | const nsAString& aFileName, |
9171 | | nsIInputStream* aPostData, |
9172 | | nsIInputStream* aHeadersData, |
9173 | | uint32_t aLoadType, |
9174 | | nsISHEntry* aSHEntry, |
9175 | | bool aFirstParty, |
9176 | | const nsAString& aSrcdoc, |
9177 | | nsIDocShell* aSourceDocShell, |
9178 | | nsIURI* aBaseURI, |
9179 | | nsIDocShell** aDocShell, |
9180 | | nsIRequest** aRequest) |
9181 | 0 | { |
9182 | 0 | MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal"); |
9183 | 0 |
|
9184 | 0 | nsresult rv = NS_OK; |
9185 | 0 | mOriginalUriString.Truncate(); |
9186 | 0 |
|
9187 | 0 | MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, |
9188 | 0 | ("DOCSHELL %p InternalLoad %s\n", |
9189 | 0 | this, aURI ? aURI->GetSpecOrDefault().get() : "")); |
9190 | 0 | // Initialize aDocShell/aRequest |
9191 | 0 | if (aDocShell) { |
9192 | 0 | *aDocShell = nullptr; |
9193 | 0 | } |
9194 | 0 | if (aRequest) { |
9195 | 0 | *aRequest = nullptr; |
9196 | 0 | } |
9197 | 0 |
|
9198 | 0 | if (!aURI) { |
9199 | 0 | return NS_ERROR_NULL_POINTER; |
9200 | 0 | } |
9201 | 0 | |
9202 | 0 | NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG); |
9203 | 0 |
|
9204 | 0 | NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE); |
9205 | 0 |
|
9206 | 0 | rv = EnsureScriptEnvironment(); |
9207 | 0 | if (NS_FAILED(rv)) { |
9208 | 0 | return rv; |
9209 | 0 | } |
9210 | 0 | |
9211 | 0 | // wyciwyg urls can only be loaded through history. Any normal load of |
9212 | 0 | // wyciwyg through docshell is illegal. Disallow such loads. |
9213 | 0 | if (aLoadType & LOAD_CMD_NORMAL) { |
9214 | 0 | bool isWyciwyg = false; |
9215 | 0 | rv = aURI->SchemeIs("wyciwyg", &isWyciwyg); |
9216 | 0 | if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) { |
9217 | 0 | return NS_ERROR_FAILURE; |
9218 | 0 | } |
9219 | 0 | } |
9220 | 0 | |
9221 | 0 | bool isJavaScript = false; |
9222 | 0 | if (NS_FAILED(aURI->SchemeIs("javascript", &isJavaScript))) { |
9223 | 0 | isJavaScript = false; |
9224 | 0 | } |
9225 | 0 |
|
9226 | 0 | bool isTargetTopLevelDocShell = false; |
9227 | 0 | nsCOMPtr<nsIDocShell> targetDocShell; |
9228 | 0 | if (!aWindowTarget.IsEmpty()) { |
9229 | 0 | // Locate the target DocShell. |
9230 | 0 | nsCOMPtr<nsIDocShellTreeItem> targetItem; |
9231 | 0 | // Only _self, _parent, and _top are supported in noopener case. But we |
9232 | 0 | // have to be careful to not apply that to the noreferrer case. See bug |
9233 | 0 | // 1358469. |
9234 | 0 | bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) || |
9235 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER); |
9236 | 0 | if (allowNamedTarget || |
9237 | 0 | aWindowTarget.LowerCaseEqualsLiteral("_self") || |
9238 | 0 | aWindowTarget.LowerCaseEqualsLiteral("_parent") || |
9239 | 0 | aWindowTarget.LowerCaseEqualsLiteral("_top")) { |
9240 | 0 | rv = FindItemWithName(aWindowTarget, nullptr, this, false, |
9241 | 0 | getter_AddRefs(targetItem)); |
9242 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
9243 | 0 | } |
9244 | 0 |
|
9245 | 0 | targetDocShell = do_QueryInterface(targetItem); |
9246 | 0 | if (targetDocShell) { |
9247 | 0 | // If the targetDocShell and the rootDocShell are the same, then the |
9248 | 0 | // targetDocShell is the top level document and hence we should |
9249 | 0 | // consider this TYPE_DOCUMENT |
9250 | 0 | // |
9251 | 0 | // For example: |
9252 | 0 | // 1. target="_top" |
9253 | 0 | // 2. target="_parent", where this docshell is in the 2nd level of |
9254 | 0 | // docshell tree. |
9255 | 0 | nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot; |
9256 | 0 | targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); |
9257 | 0 | NS_ASSERTION(sameTypeRoot, |
9258 | 0 | "No document shell root tree item from targetDocShell!"); |
9259 | 0 | nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot); |
9260 | 0 | NS_ASSERTION(rootShell, |
9261 | 0 | "No root docshell from document shell root tree item."); |
9262 | 0 | isTargetTopLevelDocShell = targetDocShell == rootShell; |
9263 | 0 | } else { |
9264 | 0 | // If the targetDocShell doesn't exist, then this is a new docShell |
9265 | 0 | // and we should consider this a TYPE_DOCUMENT load |
9266 | 0 | // |
9267 | 0 | // For example, when target="_blank" |
9268 | 0 | isTargetTopLevelDocShell = true; |
9269 | 0 | } |
9270 | 0 | } |
9271 | 0 |
|
9272 | 0 | // The contentType will be INTERNAL_(I)FRAME if: |
9273 | 0 | // 1. This docshell is for iframe. |
9274 | 0 | // 2. AND aWindowTarget is not a new window, nor a top-level window. |
9275 | 0 | // |
9276 | 0 | // This variable will be used when we call NS_CheckContentLoadPolicy, and |
9277 | 0 | // later when we call DoURILoad. |
9278 | 0 | uint32_t contentType; |
9279 | 0 | if (IsFrame() && !isTargetTopLevelDocShell) { |
9280 | 0 | nsCOMPtr<Element> requestingElement = |
9281 | 0 | mScriptGlobal->AsOuter()->GetFrameElementInternal(); |
9282 | 0 | if (requestingElement) { |
9283 | 0 | contentType = requestingElement->IsHTMLElement(nsGkAtoms::iframe) ? |
9284 | 0 | nsIContentPolicy::TYPE_INTERNAL_IFRAME : nsIContentPolicy::TYPE_INTERNAL_FRAME; |
9285 | 0 | } else { |
9286 | 0 | // If we have lost our frame element by now, just assume we're |
9287 | 0 | // an iframe since that's more common. |
9288 | 0 | contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME; |
9289 | 0 | } |
9290 | 0 | } else { |
9291 | 0 | contentType = nsIContentPolicy::TYPE_DOCUMENT; |
9292 | 0 | isTargetTopLevelDocShell = true; |
9293 | 0 | } |
9294 | 0 |
|
9295 | 0 | // If there's no targetDocShell, that means we are about to create a new |
9296 | 0 | // window (or aWindowTarget is empty). Perform a content policy check before |
9297 | 0 | // creating the window. Please note for all other docshell loads |
9298 | 0 | // content policy checks are performed within the contentSecurityManager |
9299 | 0 | // when the channel is about to be openend. |
9300 | 0 | if (!targetDocShell && !aWindowTarget.IsEmpty()) { |
9301 | 0 | MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT, |
9302 | 0 | "opening a new window requires type to be TYPE_DOCUMENT"); |
9303 | 0 |
|
9304 | 0 | nsISupports* requestingContext = nullptr; |
9305 | 0 | if (XRE_IsContentProcess()) { |
9306 | 0 | // In e10s the child process doesn't have access to the element that |
9307 | 0 | // contains the browsing context (because that element is in the chrome |
9308 | 0 | // process). So we just pass mScriptGlobal. |
9309 | 0 | requestingContext = ToSupports(mScriptGlobal); |
9310 | 0 | } else { |
9311 | 0 | // This is for loading non-e10s tabs and toplevel windows of various |
9312 | 0 | // sorts. |
9313 | 0 | // For the toplevel window cases, requestingElement will be null. |
9314 | 0 | nsCOMPtr<Element> requestingElement = |
9315 | 0 | mScriptGlobal->AsOuter()->GetFrameElementInternal(); |
9316 | 0 | requestingContext = requestingElement; |
9317 | 0 | } |
9318 | 0 |
|
9319 | 0 | // Ideally we should use the same loadinfo as within DoURILoad which |
9320 | 0 | // should match this one when both are applicable. |
9321 | 0 | nsCOMPtr<nsPIDOMWindowOuter> loadingWindow = mScriptGlobal->AsOuter(); |
9322 | 0 | nsCOMPtr<nsILoadInfo> secCheckLoadInfo = |
9323 | 0 | new LoadInfo(loadingWindow, |
9324 | 0 | aTriggeringPrincipal, |
9325 | 0 | requestingContext, |
9326 | 0 | nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK); |
9327 | 0 |
|
9328 | 0 | // Since Content Policy checks are performed within docShell as well as |
9329 | 0 | // the ContentSecurityManager we need a reliable way to let certain |
9330 | 0 | // nsIContentPolicy consumers ignore duplicate calls. |
9331 | 0 | secCheckLoadInfo->SetSkipContentPolicyCheckForWebRequest(true); |
9332 | 0 |
|
9333 | 0 | int16_t shouldLoad = nsIContentPolicy::ACCEPT; |
9334 | 0 | rv = NS_CheckContentLoadPolicy(aURI, |
9335 | 0 | secCheckLoadInfo, |
9336 | 0 | EmptyCString(), // mime guess |
9337 | 0 | &shouldLoad); |
9338 | 0 |
|
9339 | 0 | if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { |
9340 | 0 | if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) { |
9341 | 0 | return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT; |
9342 | 0 | } |
9343 | 0 | |
9344 | 0 | return NS_ERROR_CONTENT_BLOCKED; |
9345 | 0 | } |
9346 | 0 | } |
9347 | 0 |
|
9348 | 0 | nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit; |
9349 | 0 | // |
9350 | 0 | // Get a principal from the current document if necessary. Note that we only |
9351 | 0 | // do this for URIs that inherit a security context and local file URIs; |
9352 | 0 | // in particular we do NOT do this for about:blank. This way, random |
9353 | 0 | // about:blank loads that have no principal (which basically means they were |
9354 | 0 | // done by someone from chrome manually messing with our nsIWebNavigation |
9355 | 0 | // or by C++ setting document.location) don't get a funky principal. If |
9356 | 0 | // callers want something interesting to happen with the about:blank |
9357 | 0 | // principal in this case, they should pass aPrincipalToInherit in. |
9358 | 0 | // |
9359 | 0 | { |
9360 | 0 | bool inherits; |
9361 | 0 | // One more twist: Don't inherit the principal for external loads. |
9362 | 0 | if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit && |
9363 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) && |
9364 | 0 | NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI, |
9365 | 0 | &inherits)) && |
9366 | 0 | inherits) { |
9367 | 0 | principalToInherit = GetInheritedPrincipal(true); |
9368 | 0 | } |
9369 | 0 | } |
9370 | 0 |
|
9371 | 0 | nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument() |
9372 | 0 | : nullptr; |
9373 | 0 |
|
9374 | 0 | const bool isDocumentAuxSandboxed = doc && |
9375 | 0 | (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION); |
9376 | 0 |
|
9377 | 0 | if (aURI && mLoadURIDelegate && aLoadType != LOAD_ERROR_PAGE && |
9378 | 0 | (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) { |
9379 | 0 | // Dispatch only load requests for the current or a new window to the |
9380 | 0 | // delegate, e.g., to allow for GeckoView apps to handle the load event |
9381 | 0 | // outside of Gecko. |
9382 | 0 | const int where = (aWindowTarget.IsEmpty() || targetDocShell) |
9383 | 0 | ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW |
9384 | 0 | : nsIBrowserDOMWindow::OPEN_NEWWINDOW; |
9385 | 0 |
|
9386 | 0 | if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW && isDocumentAuxSandboxed) { |
9387 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
9388 | 0 | } |
9389 | 0 | |
9390 | 0 | bool loadURIHandled = false; |
9391 | 0 | rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal, |
9392 | 0 | &loadURIHandled); |
9393 | 0 | if (NS_SUCCEEDED(rv) && loadURIHandled) { |
9394 | 0 | // The request has been handled, nothing to do here. |
9395 | 0 | return NS_OK; |
9396 | 0 | } |
9397 | 0 | } |
9398 | 0 | |
9399 | 0 | // |
9400 | 0 | // Resolve the window target before going any further... |
9401 | 0 | // If the load has been targeted to another DocShell, then transfer the |
9402 | 0 | // load to it... |
9403 | 0 | // |
9404 | 0 | if (!aWindowTarget.IsEmpty()) { |
9405 | 0 | // We've already done our owner-inheriting. Mask out that bit, so we |
9406 | 0 | // don't try inheriting an owner from the target window if we came up |
9407 | 0 | // with a null owner above. |
9408 | 0 | aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL; |
9409 | 0 |
|
9410 | 0 | bool isNewWindow = false; |
9411 | 0 | if (!targetDocShell) { |
9412 | 0 | // If the docshell's document is sandboxed, only open a new window |
9413 | 0 | // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set. |
9414 | 0 | // (i.e. if allow-popups is specified) |
9415 | 0 | NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE); |
9416 | 0 | if (isDocumentAuxSandboxed) { |
9417 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
9418 | 0 | } |
9419 | 0 | |
9420 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
9421 | 0 | NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE); |
9422 | 0 |
|
9423 | 0 | nsCOMPtr<nsPIDOMWindowOuter> newWin; |
9424 | 0 | nsAutoCString spec; |
9425 | 0 | if (aURI) { |
9426 | 0 | aURI->GetSpec(spec); |
9427 | 0 | } |
9428 | 0 | // If we are a noopener load, we just hand the whole thing over to our |
9429 | 0 | // window. |
9430 | 0 | if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) { |
9431 | 0 | // Various asserts that we know to hold because NO_OPENER loads can only |
9432 | 0 | // happen for links. |
9433 | 0 | MOZ_ASSERT(!aLoadReplace); |
9434 | 0 | MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal); |
9435 | 0 | MOZ_ASSERT((aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) == |
9436 | 0 | INTERNAL_LOAD_FLAGS_NO_OPENER || |
9437 | 0 | (aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) == |
9438 | 0 | (INTERNAL_LOAD_FLAGS_NO_OPENER | |
9439 | 0 | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)); |
9440 | 0 | MOZ_ASSERT(!aPostData); |
9441 | 0 | MOZ_ASSERT(!aHeadersData); |
9442 | 0 | // If OnLinkClickSync was invoked inside the onload handler, the load |
9443 | 0 | // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be |
9444 | 0 | // LOAD_LINK. |
9445 | 0 | MOZ_ASSERT(aLoadType == LOAD_LINK || |
9446 | 0 | aLoadType == LOAD_NORMAL_REPLACE); |
9447 | 0 | MOZ_ASSERT(!aSHEntry); |
9448 | 0 | MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this. |
9449 | 0 |
|
9450 | 0 | RefPtr<nsDocShellLoadInfo> loadInfo = new nsDocShellLoadInfo(); |
9451 | 0 |
|
9452 | 0 | // Set up our loadinfo so it will do the load as much like we would have |
9453 | 0 | // as possible. |
9454 | 0 | loadInfo->SetReferrer(aReferrer); |
9455 | 0 | loadInfo->SetReferrerPolicy((mozilla::net::ReferrerPolicy)aReferrerPolicy); |
9456 | 0 | loadInfo->SetSendReferrer(!(aFlags & |
9457 | 0 | INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER)); |
9458 | 0 | loadInfo->SetOriginalURI(aOriginalURI); |
9459 | 0 | loadInfo->SetMaybeResultPrincipalURI(aResultPrincipalURI); |
9460 | 0 | loadInfo->SetKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet); |
9461 | 0 | loadInfo->SetLoadReplace(aLoadReplace); |
9462 | 0 | loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal); |
9463 | 0 | loadInfo->SetInheritPrincipal( |
9464 | 0 | aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL); |
9465 | 0 | // Explicit principal because we do not want any guesses as to what the |
9466 | 0 | // principal to inherit is: it should be aTriggeringPrincipal. |
9467 | 0 | loadInfo->SetPrincipalIsExplicit(true); |
9468 | 0 | loadInfo->SetLoadType(LOAD_LINK); |
9469 | 0 | loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI); |
9470 | 0 |
|
9471 | 0 | rv = win->Open(NS_ConvertUTF8toUTF16(spec), |
9472 | 0 | aWindowTarget, // window name |
9473 | 0 | EmptyString(), // Features |
9474 | 0 | loadInfo, |
9475 | 0 | true, // aForceNoOpener |
9476 | 0 | getter_AddRefs(newWin)); |
9477 | 0 | MOZ_ASSERT(!newWin); |
9478 | 0 | return rv; |
9479 | 0 | } |
9480 | 0 |
|
9481 | 0 | rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec), |
9482 | 0 | aWindowTarget, // window name |
9483 | 0 | EmptyString(), // Features |
9484 | 0 | getter_AddRefs(newWin)); |
9485 | 0 |
|
9486 | 0 | // In some cases the Open call doesn't actually result in a new |
9487 | 0 | // window being opened. We can detect these cases by examining the |
9488 | 0 | // document in |newWin|, if any. |
9489 | 0 | nsCOMPtr<nsPIDOMWindowOuter> piNewWin = do_QueryInterface(newWin); |
9490 | 0 | if (piNewWin) { |
9491 | 0 | nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc(); |
9492 | 0 | if (!newDoc || newDoc->IsInitialDocument()) { |
9493 | 0 | isNewWindow = true; |
9494 | 0 | aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; |
9495 | 0 | } |
9496 | 0 | } |
9497 | 0 |
|
9498 | 0 | nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin); |
9499 | 0 | targetDocShell = do_QueryInterface(webNav); |
9500 | 0 | } |
9501 | 0 |
|
9502 | 0 | // |
9503 | 0 | // Transfer the load to the target DocShell... Pass nullptr as the |
9504 | 0 | // window target name from to prevent recursive retargeting! |
9505 | 0 | // |
9506 | 0 | if (NS_SUCCEEDED(rv) && targetDocShell) { |
9507 | 0 | rv = targetDocShell->InternalLoad(aURI, |
9508 | 0 | aOriginalURI, |
9509 | 0 | aResultPrincipalURI, |
9510 | 0 | aKeepResultPrincipalURIIfSet, |
9511 | 0 | aLoadReplace, |
9512 | 0 | aReferrer, |
9513 | 0 | aReferrerPolicy, |
9514 | 0 | aTriggeringPrincipal, |
9515 | 0 | principalToInherit, |
9516 | 0 | aFlags, |
9517 | 0 | EmptyString(), // No window target |
9518 | 0 | aTypeHint, |
9519 | 0 | VoidString(), // No forced download |
9520 | 0 | aPostData, |
9521 | 0 | aHeadersData, |
9522 | 0 | aLoadType, |
9523 | 0 | aSHEntry, |
9524 | 0 | aFirstParty, |
9525 | 0 | aSrcdoc, |
9526 | 0 | aSourceDocShell, |
9527 | 0 | aBaseURI, |
9528 | 0 | aDocShell, |
9529 | 0 | aRequest); |
9530 | 0 | if (rv == NS_ERROR_NO_CONTENT) { |
9531 | 0 | // XXXbz except we never reach this code! |
9532 | 0 | if (isNewWindow) { |
9533 | 0 | // |
9534 | 0 | // At this point, a new window has been created, but the |
9535 | 0 | // URI did not have any data associated with it... |
9536 | 0 | // |
9537 | 0 | // So, the best we can do, is to tear down the new window |
9538 | 0 | // that was just created! |
9539 | 0 | // |
9540 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow()) { |
9541 | 0 | domWin->Close(); |
9542 | 0 | } |
9543 | 0 | } |
9544 | 0 | // |
9545 | 0 | // NS_ERROR_NO_CONTENT should not be returned to the |
9546 | 0 | // caller... This is an internal error code indicating that |
9547 | 0 | // the URI had no data associated with it - probably a |
9548 | 0 | // helper-app style protocol (ie. mailto://) |
9549 | 0 | // |
9550 | 0 | rv = NS_OK; |
9551 | 0 | } else if (isNewWindow) { |
9552 | 0 | // XXX: Once new windows are created hidden, the new |
9553 | 0 | // window will need to be made visible... For now, |
9554 | 0 | // do nothing. |
9555 | 0 | } |
9556 | 0 |
|
9557 | 0 | if (NS_SUCCEEDED(rv)) { |
9558 | 0 | // Switch to target tab if we're currently focused window. |
9559 | 0 | // Take loadDivertedInBackground into account so the behavior would be |
9560 | 0 | // the same as how the tab first opened. |
9561 | 0 | bool isTargetActive = false; |
9562 | 0 | targetDocShell->GetIsActive(&isTargetActive); |
9563 | 0 | nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow(); |
9564 | 0 | if (mIsActive && !isTargetActive && domWin && |
9565 | 0 | !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false)) { |
9566 | 0 | if (NS_FAILED(nsContentUtils::DispatchFocusChromeEvent(domWin))) { |
9567 | 0 | return NS_ERROR_FAILURE; |
9568 | 0 | } |
9569 | 0 | } |
9570 | 0 | } |
9571 | 0 | } |
9572 | 0 | |
9573 | 0 | // Else we ran out of memory, or were a popup and got blocked, |
9574 | 0 | // or something. |
9575 | 0 | |
9576 | 0 | return rv; |
9577 | 0 | } |
9578 | 0 | |
9579 | 0 | // |
9580 | 0 | // Load is being targetted at this docshell so return an error if the |
9581 | 0 | // docshell is in the process of being destroyed. |
9582 | 0 | // |
9583 | 0 | if (mIsBeingDestroyed) { |
9584 | 0 | return NS_ERROR_FAILURE; |
9585 | 0 | } |
9586 | 0 | |
9587 | 0 | NS_ENSURE_STATE(!HasUnloadedParent()); |
9588 | 0 |
|
9589 | 0 | rv = CheckLoadingPermissions(); |
9590 | 0 | if (NS_FAILED(rv)) { |
9591 | 0 | return rv; |
9592 | 0 | } |
9593 | 0 | |
9594 | 0 | if (mFiredUnloadEvent) { |
9595 | 0 | if (IsOKToLoadURI(aURI)) { |
9596 | 0 | MOZ_ASSERT(aWindowTarget.IsEmpty(), |
9597 | 0 | "Shouldn't have a window target here!"); |
9598 | 0 |
|
9599 | 0 | // If this is a replace load, make whatever load triggered |
9600 | 0 | // the unload event also a replace load, so we don't |
9601 | 0 | // create extra history entries. |
9602 | 0 | if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) { |
9603 | 0 | mLoadType = LOAD_NORMAL_REPLACE; |
9604 | 0 | } |
9605 | 0 |
|
9606 | 0 | // Do this asynchronously |
9607 | 0 | nsCOMPtr<nsIRunnable> ev = |
9608 | 0 | new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI, |
9609 | 0 | aKeepResultPrincipalURIIfSet, |
9610 | 0 | aLoadReplace, aReferrer, aReferrerPolicy, |
9611 | 0 | aTriggeringPrincipal, principalToInherit, |
9612 | 0 | aFlags, aTypeHint, aPostData, |
9613 | 0 | aHeadersData, aLoadType, aSHEntry, aFirstParty, |
9614 | 0 | aSrcdoc, aSourceDocShell, aBaseURI); |
9615 | 0 | return DispatchToTabGroup(TaskCategory::Other, ev.forget()); |
9616 | 0 | } |
9617 | 0 |
|
9618 | 0 | // Just ignore this load attempt |
9619 | 0 | return NS_OK; |
9620 | 0 | } |
9621 | 0 | |
9622 | 0 | // If a source docshell has been passed, check to see if we are sandboxed |
9623 | 0 | // from it as the result of an iframe or CSP sandbox. |
9624 | 0 | if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) { |
9625 | 0 | return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
9626 | 0 | } |
9627 | 0 | |
9628 | 0 | // If this docshell is owned by a frameloader, make sure to cancel |
9629 | 0 | // possible frameloader initialization before loading a new page. |
9630 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell(); |
9631 | 0 | if (parent) { |
9632 | 0 | nsCOMPtr<nsIDocument> doc = parent->GetDocument(); |
9633 | 0 | if (doc) { |
9634 | 0 | doc->TryCancelFrameLoaderInitialization(this); |
9635 | 0 | } |
9636 | 0 | } |
9637 | 0 |
|
9638 | 0 | bool loadFromExternal = false; |
9639 | 0 |
|
9640 | 0 | // Before going any further vet loads initiated by external programs. |
9641 | 0 | if (aLoadType == LOAD_NORMAL_EXTERNAL) { |
9642 | 0 | loadFromExternal = true; |
9643 | 0 | // Disallow external chrome: loads targetted at content windows |
9644 | 0 | bool isChrome = false; |
9645 | 0 | if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) { |
9646 | 0 | NS_WARNING("blocked external chrome: url -- use '--chrome' option"); |
9647 | 0 | return NS_ERROR_FAILURE; |
9648 | 0 | } |
9649 | 0 |
|
9650 | 0 | // clear the decks to prevent context bleed-through (bug 298255) |
9651 | 0 | rv = CreateAboutBlankContentViewer(nullptr, nullptr); |
9652 | 0 | if (NS_FAILED(rv)) { |
9653 | 0 | return NS_ERROR_FAILURE; |
9654 | 0 | } |
9655 | 0 | |
9656 | 0 | // reset loadType so we don't have to add lots of tests for |
9657 | 0 | // LOAD_NORMAL_EXTERNAL after this point |
9658 | 0 | aLoadType = LOAD_NORMAL; |
9659 | 0 | } |
9660 | 0 |
|
9661 | 0 | mAllowKeywordFixup = |
9662 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0; |
9663 | 0 | mURIResultedInDocument = false; // reset the clock... |
9664 | 0 |
|
9665 | 0 | if (aLoadType == LOAD_NORMAL || |
9666 | 0 | aLoadType == LOAD_STOP_CONTENT || |
9667 | 0 | LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) || |
9668 | 0 | aLoadType == LOAD_HISTORY || |
9669 | 0 | aLoadType == LOAD_LINK) { |
9670 | 0 | nsCOMPtr<nsIURI> currentURI = mCurrentURI; |
9671 | 0 |
|
9672 | 0 | nsAutoCString curHash, newHash; |
9673 | 0 | bool curURIHasRef = false, newURIHasRef = false; |
9674 | 0 |
|
9675 | 0 | nsresult rvURINew = aURI->GetRef(newHash); |
9676 | 0 | if (NS_SUCCEEDED(rvURINew)) { |
9677 | 0 | rvURINew = aURI->GetHasRef(&newURIHasRef); |
9678 | 0 | } |
9679 | 0 |
|
9680 | 0 | bool sameExceptHashes = false; |
9681 | 0 | if (currentURI && NS_SUCCEEDED(rvURINew)) { |
9682 | 0 | nsresult rvURIOld = currentURI->GetRef(curHash); |
9683 | 0 | if (NS_SUCCEEDED(rvURIOld)) { |
9684 | 0 | rvURIOld = currentURI->GetHasRef(&curURIHasRef); |
9685 | 0 | } |
9686 | 0 | if (NS_SUCCEEDED(rvURIOld)) { |
9687 | 0 | if (NS_FAILED(currentURI->EqualsExceptRef(aURI, &sameExceptHashes))) { |
9688 | 0 | sameExceptHashes = false; |
9689 | 0 | } |
9690 | 0 | } |
9691 | 0 | } |
9692 | 0 |
|
9693 | 0 | if (!sameExceptHashes && sURIFixup && currentURI && |
9694 | 0 | NS_SUCCEEDED(rvURINew)) { |
9695 | 0 | // Maybe aURI came from the exposable form of currentURI? |
9696 | 0 | nsCOMPtr<nsIURI> currentExposableURI; |
9697 | 0 | rv = sURIFixup->CreateExposableURI(currentURI, |
9698 | 0 | getter_AddRefs(currentExposableURI)); |
9699 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
9700 | 0 | nsresult rvURIOld = currentExposableURI->GetRef(curHash); |
9701 | 0 | if (NS_SUCCEEDED(rvURIOld)) { |
9702 | 0 | rvURIOld = currentExposableURI->GetHasRef(&curURIHasRef); |
9703 | 0 | } |
9704 | 0 | if (NS_SUCCEEDED(rvURIOld)) { |
9705 | 0 | if (NS_FAILED(currentExposableURI->EqualsExceptRef(aURI, &sameExceptHashes))) { |
9706 | 0 | sameExceptHashes = false; |
9707 | 0 | } |
9708 | 0 | } |
9709 | 0 | } |
9710 | 0 |
|
9711 | 0 | bool historyNavBetweenSameDoc = false; |
9712 | 0 | if (mOSHE && aSHEntry) { |
9713 | 0 | // We're doing a history load. |
9714 | 0 |
|
9715 | 0 | mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc); |
9716 | 0 |
|
9717 | | #ifdef DEBUG |
9718 | | if (historyNavBetweenSameDoc) { |
9719 | | nsCOMPtr<nsIInputStream> currentPostData = mOSHE->GetPostData(); |
9720 | | NS_ASSERTION(currentPostData == aPostData, |
9721 | | "Different POST data for entries for the same page?"); |
9722 | | } |
9723 | | #endif |
9724 | | } |
9725 | 0 |
|
9726 | 0 | // A short-circuited load happens when we navigate between two SHEntries |
9727 | 0 | // for the same document. We do a short-circuited load under two |
9728 | 0 | // circumstances. Either |
9729 | 0 | // |
9730 | 0 | // a) we're navigating between two different SHEntries which share a |
9731 | 0 | // document, or |
9732 | 0 | // |
9733 | 0 | // b) we're navigating to a new shentry whose URI differs from the |
9734 | 0 | // current URI only in its hash, the new hash is non-empty, and |
9735 | 0 | // we're not doing a POST. |
9736 | 0 | // |
9737 | 0 | // The restriction tha the SHEntries in (a) must be different ensures |
9738 | 0 | // that history.go(0) and the like trigger full refreshes, rather than |
9739 | 0 | // short-circuited loads. |
9740 | 0 | bool doShortCircuitedLoad = |
9741 | 0 | (historyNavBetweenSameDoc && mOSHE != aSHEntry) || |
9742 | 0 | (!aSHEntry && !aPostData && |
9743 | 0 | sameExceptHashes && newURIHasRef); |
9744 | 0 |
|
9745 | 0 | if (doShortCircuitedLoad) { |
9746 | 0 | // Save the position of the scrollers. |
9747 | 0 | nscoord cx = 0, cy = 0; |
9748 | 0 | GetCurScrollPos(ScrollOrientation_X, &cx); |
9749 | 0 | GetCurScrollPos(ScrollOrientation_Y, &cy); |
9750 | 0 |
|
9751 | 0 | // Reset mLoadType to its original value once we exit this block, |
9752 | 0 | // because this short-circuited load might have started after a |
9753 | 0 | // normal, network load, and we don't want to clobber its load type. |
9754 | 0 | // See bug 737307. |
9755 | 0 | AutoRestore<uint32_t> loadTypeResetter(mLoadType); |
9756 | 0 |
|
9757 | 0 | // If a non-short-circuit load (i.e., a network load) is pending, |
9758 | 0 | // make this a replacement load, so that we don't add a SHEntry here |
9759 | 0 | // and the network load goes into the SHEntry it expects to. |
9760 | 0 | if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) { |
9761 | 0 | mLoadType = LOAD_NORMAL_REPLACE; |
9762 | 0 | } else { |
9763 | 0 | mLoadType = aLoadType; |
9764 | 0 | } |
9765 | 0 |
|
9766 | 0 | mURIResultedInDocument = true; |
9767 | 0 |
|
9768 | 0 | nsCOMPtr<nsISHEntry> oldLSHE = mLSHE; |
9769 | 0 |
|
9770 | 0 | /* we need to assign mLSHE to aSHEntry right here, so that on History |
9771 | 0 | * loads, SetCurrentURI() called from OnNewURI() will send proper |
9772 | 0 | * onLocationChange() notifications to the browser to update |
9773 | 0 | * back/forward buttons. |
9774 | 0 | */ |
9775 | 0 | SetHistoryEntry(&mLSHE, aSHEntry); |
9776 | 0 |
|
9777 | 0 | // Set the doc's URI according to the new history entry's URI. |
9778 | 0 | nsCOMPtr<nsIDocument> doc = GetDocument(); |
9779 | 0 | NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
9780 | 0 | doc->SetDocumentURI(aURI); |
9781 | 0 |
|
9782 | 0 | /* This is a anchor traversal with in the same page. |
9783 | 0 | * call OnNewURI() so that, this traversal will be |
9784 | 0 | * recorded in session and global history. |
9785 | 0 | */ |
9786 | 0 | nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit; |
9787 | 0 | if (mOSHE) { |
9788 | 0 | newURITriggeringPrincipal = mOSHE->GetTriggeringPrincipal(); |
9789 | 0 | newURIPrincipalToInherit = mOSHE->GetPrincipalToInherit(); |
9790 | 0 | } else { |
9791 | 0 | newURITriggeringPrincipal = aTriggeringPrincipal; |
9792 | 0 | newURIPrincipalToInherit = doc->NodePrincipal(); |
9793 | 0 | } |
9794 | 0 | // Pass true for aCloneSHChildren, since we're not |
9795 | 0 | // changing documents here, so all of our subframes are |
9796 | 0 | // still relevant to the new session history entry. |
9797 | 0 | // |
9798 | 0 | // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT |
9799 | 0 | // flag on firing onLocationChange(...). |
9800 | 0 | // Anyway, aCloneSHChildren param is simply reflecting |
9801 | 0 | // doShortCircuitedLoad in this scope. |
9802 | 0 | OnNewURI(aURI, nullptr, newURITriggeringPrincipal, newURIPrincipalToInherit, |
9803 | 0 | mLoadType, true, true, true); |
9804 | 0 |
|
9805 | 0 | nsCOMPtr<nsIInputStream> postData; |
9806 | 0 | uint32_t cacheKey = 0; |
9807 | 0 |
|
9808 | 0 | bool scrollRestorationIsManual = false; |
9809 | 0 | if (mOSHE) { |
9810 | 0 | /* save current position of scroller(s) (bug 59774) */ |
9811 | 0 | mOSHE->SetScrollPosition(cx, cy); |
9812 | 0 | scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual(); |
9813 | 0 | // Get the postdata and page ident from the current page, if |
9814 | 0 | // the new load is being done via normal means. Note that |
9815 | 0 | // "normal means" can be checked for just by checking for |
9816 | 0 | // LOAD_CMD_NORMAL, given the loadType and allowScroll check |
9817 | 0 | // above -- it filters out some LOAD_CMD_NORMAL cases that we |
9818 | 0 | // wouldn't want here. |
9819 | 0 | if (aLoadType & LOAD_CMD_NORMAL) { |
9820 | 0 | postData = mOSHE->GetPostData(); |
9821 | 0 | cacheKey = mOSHE->GetCacheKey(); |
9822 | 0 |
|
9823 | 0 | // Link our new SHEntry to the old SHEntry's back/forward |
9824 | 0 | // cache data, since the two SHEntries correspond to the |
9825 | 0 | // same document. |
9826 | 0 | if (mLSHE) { |
9827 | 0 | if (!aSHEntry) { |
9828 | 0 | // If we're not doing a history load, scroll restoration |
9829 | 0 | // should be inherited from the previous session history entry. |
9830 | 0 | mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual); |
9831 | 0 | } |
9832 | 0 | mLSHE->AdoptBFCacheEntry(mOSHE); |
9833 | 0 | } |
9834 | 0 | } |
9835 | 0 | } |
9836 | 0 |
|
9837 | 0 | // If we're doing a history load, use its scroll restoration state. |
9838 | 0 | if (aSHEntry) { |
9839 | 0 | scrollRestorationIsManual = aSHEntry->GetScrollRestorationIsManual(); |
9840 | 0 | } |
9841 | 0 |
|
9842 | 0 | /* Assign mOSHE to mLSHE. This will either be a new entry created |
9843 | 0 | * by OnNewURI() for normal loads or aSHEntry for history loads. |
9844 | 0 | */ |
9845 | 0 | if (mLSHE) { |
9846 | 0 | SetHistoryEntry(&mOSHE, mLSHE); |
9847 | 0 | // Save the postData obtained from the previous page |
9848 | 0 | // in to the session history entry created for the |
9849 | 0 | // anchor page, so that any history load of the anchor |
9850 | 0 | // page will restore the appropriate postData. |
9851 | 0 | if (postData) { |
9852 | 0 | mOSHE->SetPostData(postData); |
9853 | 0 | } |
9854 | 0 |
|
9855 | 0 | // Make sure we won't just repost without hitting the |
9856 | 0 | // cache first |
9857 | 0 | if (cacheKey != 0) { |
9858 | 0 | mOSHE->SetCacheKey(cacheKey); |
9859 | 0 | } |
9860 | 0 | } |
9861 | 0 |
|
9862 | 0 | /* Restore the original LSHE if we were loading something |
9863 | 0 | * while short-circuited load was initiated. |
9864 | 0 | */ |
9865 | 0 | SetHistoryEntry(&mLSHE, oldLSHE); |
9866 | 0 | /* Set the title for the SH entry for this target url. so that |
9867 | 0 | * SH menus in go/back/forward buttons won't be empty for this. |
9868 | 0 | */ |
9869 | 0 | if (mSessionHistory) { |
9870 | 0 | int32_t index = mSessionHistory->Index(); |
9871 | 0 | nsCOMPtr<nsISHEntry> shEntry; |
9872 | 0 | mSessionHistory->LegacySHistory()->GetEntryAtIndex( |
9873 | 0 | index, getter_AddRefs(shEntry)); |
9874 | 0 | NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE); |
9875 | 0 | shEntry->SetTitle(mTitle); |
9876 | 0 | } |
9877 | 0 |
|
9878 | 0 | /* Set the title for the Global History entry for this anchor url. |
9879 | 0 | */ |
9880 | 0 | UpdateGlobalHistoryTitle(aURI); |
9881 | 0 |
|
9882 | 0 | SetDocCurrentStateObj(mOSHE); |
9883 | 0 |
|
9884 | 0 | // Inform the favicon service that the favicon for oldURI also |
9885 | 0 | // applies to aURI. |
9886 | 0 | CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing()); |
9887 | 0 |
|
9888 | 0 | RefPtr<nsGlobalWindowOuter> scriptGlobal = mScriptGlobal; |
9889 | 0 | RefPtr<nsGlobalWindowInner> win = scriptGlobal ? |
9890 | 0 | scriptGlobal->GetCurrentInnerWindowInternal() : nullptr; |
9891 | 0 |
|
9892 | 0 | // ScrollToAnchor doesn't necessarily cause us to scroll the window; |
9893 | 0 | // the function decides whether a scroll is appropriate based on the |
9894 | 0 | // arguments it receives. But even if we don't end up scrolling, |
9895 | 0 | // ScrollToAnchor performs other important tasks, such as informing |
9896 | 0 | // the presShell that we have a new hash. See bug 680257. |
9897 | 0 | rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType); |
9898 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
9899 | 0 |
|
9900 | 0 | /* restore previous position of scroller(s), if we're moving |
9901 | 0 | * back in history (bug 59774) |
9902 | 0 | */ |
9903 | 0 | nscoord bx = 0; |
9904 | 0 | nscoord by = 0; |
9905 | 0 | bool needsScrollPosUpdate = false; |
9906 | 0 | if (mOSHE && (aLoadType == LOAD_HISTORY || |
9907 | 0 | aLoadType == LOAD_RELOAD_NORMAL) && |
9908 | 0 | !scrollRestorationIsManual) { |
9909 | 0 | needsScrollPosUpdate = true; |
9910 | 0 | mOSHE->GetScrollPosition(&bx, &by); |
9911 | 0 | } |
9912 | 0 |
|
9913 | 0 | // Dispatch the popstate and hashchange events, as appropriate. |
9914 | 0 | // |
9915 | 0 | // The event dispatch below can cause us to re-enter script and |
9916 | 0 | // destroy the docshell, nulling out mScriptGlobal. Hold a stack |
9917 | 0 | // reference to avoid null derefs. See bug 914521. |
9918 | 0 | if (win) { |
9919 | 0 | // Fire a hashchange event URIs differ, and only in their hashes. |
9920 | 0 | bool doHashchange = sameExceptHashes && |
9921 | 0 | (curURIHasRef != newURIHasRef || !curHash.Equals(newHash)); |
9922 | 0 |
|
9923 | 0 | if (historyNavBetweenSameDoc || doHashchange) { |
9924 | 0 | win->DispatchSyncPopState(); |
9925 | 0 | } |
9926 | 0 |
|
9927 | 0 | if (needsScrollPosUpdate && win->AsInner()->HasActiveDocument()) { |
9928 | 0 | SetCurScrollPosEx(bx, by); |
9929 | 0 | } |
9930 | 0 |
|
9931 | 0 | if (doHashchange) { |
9932 | 0 | // Note that currentURI hasn't changed because it's on the |
9933 | 0 | // stack, so we can just use it directly as the old URI. |
9934 | 0 | win->DispatchAsyncHashchange(currentURI, aURI); |
9935 | 0 | } |
9936 | 0 | } |
9937 | 0 |
|
9938 | 0 | return NS_OK; |
9939 | 0 | } |
9940 | 0 | } |
9941 | 0 |
|
9942 | 0 | // mContentViewer->PermitUnload can destroy |this| docShell, which |
9943 | 0 | // causes the next call of CanSavePresentation to crash. |
9944 | 0 | // Hold onto |this| until we return, to prevent a crash from happening. |
9945 | 0 | // (bug#331040) |
9946 | 0 | nsCOMPtr<nsIDocShell> kungFuDeathGrip(this); |
9947 | 0 |
|
9948 | 0 | // Don't init timing for javascript:, since it generally doesn't |
9949 | 0 | // actually start a load or anything. If it does, we'll init |
9950 | 0 | // timing then, from OnStateChange. |
9951 | 0 |
|
9952 | 0 | // XXXbz mTiming should know what channel it's for, so we don't |
9953 | 0 | // need this hackery. |
9954 | 0 | bool toBeReset = false; |
9955 | 0 | if (!isJavaScript) { |
9956 | 0 | toBeReset = MaybeInitTiming(); |
9957 | 0 | } |
9958 | 0 | bool timeBeforeUnload = aFileName.IsVoid(); |
9959 | 0 | if (mTiming && timeBeforeUnload) { |
9960 | 0 | mTiming->NotifyBeforeUnload(); |
9961 | 0 | } |
9962 | 0 | // Check if the page doesn't want to be unloaded. The javascript: |
9963 | 0 | // protocol handler deals with this for javascript: URLs. |
9964 | 0 | if (!isJavaScript && aFileName.IsVoid() && mContentViewer) { |
9965 | 0 | bool okToUnload; |
9966 | 0 | rv = mContentViewer->PermitUnload(&okToUnload); |
9967 | 0 |
|
9968 | 0 | if (NS_SUCCEEDED(rv) && !okToUnload) { |
9969 | 0 | // The user chose not to unload the page, interrupt the |
9970 | 0 | // load. |
9971 | 0 | MaybeResetInitTiming(toBeReset); |
9972 | 0 | return NS_OK; |
9973 | 0 | } |
9974 | 0 | } |
9975 | 0 | |
9976 | 0 | if (mTiming && timeBeforeUnload) { |
9977 | 0 | mTiming->NotifyUnloadAccepted(mCurrentURI); |
9978 | 0 | } |
9979 | 0 |
|
9980 | 0 | // Check if the webbrowser chrome wants the load to proceed; this can be |
9981 | 0 | // used to cancel attempts to load URIs in the wrong process. |
9982 | 0 | nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner); |
9983 | 0 | if (browserChrome3) { |
9984 | 0 | bool shouldLoad; |
9985 | 0 | rv = browserChrome3->ShouldLoadURI(this, aURI, aReferrer, !!aPostData, |
9986 | 0 | aTriggeringPrincipal, &shouldLoad); |
9987 | 0 | if (NS_SUCCEEDED(rv) && !shouldLoad) { |
9988 | 0 | return NS_OK; |
9989 | 0 | } |
9990 | 0 | } |
9991 | 0 | |
9992 | 0 | // Whenever a top-level browsing context is navigated, the user agent MUST |
9993 | 0 | // lock the orientation of the document to the document's default |
9994 | 0 | // orientation. We don't explicitly check for a top-level browsing context |
9995 | 0 | // here because orientation is only set on top-level browsing contexts. |
9996 | 0 | if (OrientationLock() != hal::eScreenOrientation_None) { |
9997 | | #ifdef DEBUG |
9998 | | nsCOMPtr<nsIDocShellTreeItem> parent; |
9999 | | GetSameTypeParent(getter_AddRefs(parent)); |
10000 | | MOZ_ASSERT(!parent); |
10001 | | #endif |
10002 | | SetOrientationLock(hal::eScreenOrientation_None); |
10003 | 0 | if (mIsActive) { |
10004 | 0 | ScreenOrientation::UpdateActiveOrientationLock( |
10005 | 0 | hal::eScreenOrientation_None); |
10006 | 0 | } |
10007 | 0 | } |
10008 | 0 |
|
10009 | 0 | // Check for saving the presentation here, before calling Stop(). |
10010 | 0 | // This is necessary so that we can catch any pending requests. |
10011 | 0 | // Since the new request has not been created yet, we pass null for the |
10012 | 0 | // new request parameter. |
10013 | 0 | // Also pass nullptr for the document, since it doesn't affect the return |
10014 | 0 | // value for our purposes here. |
10015 | 0 | bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr); |
10016 | 0 |
|
10017 | 0 | // Don't stop current network activity for javascript: URL's since |
10018 | 0 | // they might not result in any data, and thus nothing should be |
10019 | 0 | // stopped in those cases. In the case where they do result in |
10020 | 0 | // data, the javascript: URL channel takes care of stopping |
10021 | 0 | // current network activity. |
10022 | 0 | if (!isJavaScript && aFileName.IsVoid()) { |
10023 | 0 | // Stop any current network activity. |
10024 | 0 | // Also stop content if this is a zombie doc. otherwise |
10025 | 0 | // the onload will be delayed by other loads initiated in the |
10026 | 0 | // background by the first document that |
10027 | 0 | // didn't fully load before the next load was initiated. |
10028 | 0 | // If not a zombie, don't stop content until data |
10029 | 0 | // starts arriving from the new URI... |
10030 | 0 |
|
10031 | 0 | nsCOMPtr<nsIContentViewer> zombieViewer; |
10032 | 0 | if (mContentViewer) { |
10033 | 0 | mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer)); |
10034 | 0 | } |
10035 | 0 |
|
10036 | 0 | if (zombieViewer || |
10037 | 0 | LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) { |
10038 | 0 | rv = Stop(nsIWebNavigation::STOP_ALL); |
10039 | 0 | } else { |
10040 | 0 | rv = Stop(nsIWebNavigation::STOP_NETWORK); |
10041 | 0 | } |
10042 | 0 |
|
10043 | 0 | if (NS_FAILED(rv)) { |
10044 | 0 | return rv; |
10045 | 0 | } |
10046 | 0 | } |
10047 | 0 | |
10048 | 0 | mLoadType = aLoadType; |
10049 | 0 |
|
10050 | 0 | // mLSHE should be assigned to aSHEntry, only after Stop() has |
10051 | 0 | // been called. But when loading an error page, do not clear the |
10052 | 0 | // mLSHE for the real page. |
10053 | 0 | if (mLoadType != LOAD_ERROR_PAGE) { |
10054 | 0 | SetHistoryEntry(&mLSHE, aSHEntry); |
10055 | 0 | if (aSHEntry) { |
10056 | 0 | // We're making history navigation or a reload. Make sure our history ID |
10057 | 0 | // points to the same ID as SHEntry's docshell ID. |
10058 | 0 | mHistoryID = aSHEntry->DocshellID(); |
10059 | 0 | } |
10060 | 0 | } |
10061 | 0 |
|
10062 | 0 | mSavingOldViewer = savePresentation; |
10063 | 0 |
|
10064 | 0 | // If we have a saved content viewer in history, restore and show it now. |
10065 | 0 | if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) { |
10066 | 0 | // It's possible that the previous viewer of mContentViewer is the |
10067 | 0 | // viewer that will end up in aSHEntry when it gets closed. If that's |
10068 | 0 | // the case, we need to go ahead and force it into its shentry so we |
10069 | 0 | // can restore it. |
10070 | 0 | if (mContentViewer) { |
10071 | 0 | nsCOMPtr<nsIContentViewer> prevViewer; |
10072 | 0 | mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer)); |
10073 | 0 | if (prevViewer) { |
10074 | | #ifdef DEBUG |
10075 | | nsCOMPtr<nsIContentViewer> prevPrevViewer; |
10076 | | prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer)); |
10077 | | NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here"); |
10078 | | #endif |
10079 | | nsCOMPtr<nsISHEntry> viewerEntry; |
10080 | 0 | prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry)); |
10081 | 0 | if (viewerEntry == aSHEntry) { |
10082 | 0 | // Make sure this viewer ends up in the right place |
10083 | 0 | mContentViewer->SetPreviousViewer(nullptr); |
10084 | 0 | prevViewer->Destroy(); |
10085 | 0 | } |
10086 | 0 | } |
10087 | 0 | } |
10088 | 0 | nsCOMPtr<nsISHEntry> oldEntry = mOSHE; |
10089 | 0 | bool restoring; |
10090 | 0 | rv = RestorePresentation(aSHEntry, &restoring); |
10091 | 0 | if (restoring) { |
10092 | 0 | return rv; |
10093 | 0 | } |
10094 | 0 | |
10095 | 0 | // We failed to restore the presentation, so clean up. |
10096 | 0 | // Both the old and new history entries could potentially be in |
10097 | 0 | // an inconsistent state. |
10098 | 0 | if (NS_FAILED(rv)) { |
10099 | 0 | if (oldEntry) { |
10100 | 0 | oldEntry->SyncPresentationState(); |
10101 | 0 | } |
10102 | 0 |
|
10103 | 0 | aSHEntry->SyncPresentationState(); |
10104 | 0 | } |
10105 | 0 | } |
10106 | 0 |
|
10107 | 0 | nsAutoString srcdoc; |
10108 | 0 | if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) { |
10109 | 0 | srcdoc = aSrcdoc; |
10110 | 0 | } else { |
10111 | 0 | srcdoc = VoidString(); |
10112 | 0 | } |
10113 | 0 |
|
10114 | 0 | bool isTopLevelDoc = mItemType == typeContent && |
10115 | 0 | (isTargetTopLevelDocShell || |
10116 | 0 | GetIsMozBrowser()); |
10117 | 0 |
|
10118 | 0 | OriginAttributes attrs = GetOriginAttributes(); |
10119 | 0 | attrs.SetFirstPartyDomain(isTopLevelDoc, aURI); |
10120 | 0 |
|
10121 | 0 | PredictorLearn(aURI, nullptr, |
10122 | 0 | nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs); |
10123 | 0 | PredictorPredict(aURI, nullptr, |
10124 | 0 | nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); |
10125 | 0 |
|
10126 | 0 | nsCOMPtr<nsIRequest> req; |
10127 | 0 | rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI, |
10128 | 0 | aKeepResultPrincipalURIIfSet, aLoadReplace, |
10129 | 0 | loadFromExternal, |
10130 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI), |
10131 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC), |
10132 | 0 | aReferrer, |
10133 | 0 | !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), |
10134 | 0 | aReferrerPolicy, |
10135 | 0 | aTriggeringPrincipal, principalToInherit, aTypeHint, |
10136 | 0 | aFileName, aPostData, aHeadersData, |
10137 | 0 | aFirstParty, aDocShell, getter_AddRefs(req), |
10138 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0, |
10139 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0, |
10140 | 0 | (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0, |
10141 | 0 | srcdoc, aBaseURI, contentType); |
10142 | 0 | if (req && aRequest) { |
10143 | 0 | NS_ADDREF(*aRequest = req); |
10144 | 0 | } |
10145 | 0 |
|
10146 | 0 | if (NS_FAILED(rv)) { |
10147 | 0 | nsCOMPtr<nsIChannel> chan(do_QueryInterface(req)); |
10148 | 0 | if (DisplayLoadError(rv, aURI, nullptr, chan) && |
10149 | 0 | (aFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) { |
10150 | 0 | return NS_ERROR_LOAD_SHOWED_ERRORPAGE; |
10151 | 0 | } |
10152 | 0 | |
10153 | 0 | // We won't report any error if this is an unknown protocol error. The reason |
10154 | 0 | // behind this is that it will allow enumeration of external protocols if |
10155 | 0 | // we report an error for each unknown protocol. |
10156 | 0 | if (NS_ERROR_UNKNOWN_PROTOCOL == rv) { |
10157 | 0 | return NS_OK; |
10158 | 0 | } |
10159 | 0 | } |
10160 | 0 | |
10161 | 0 | return rv; |
10162 | 0 | } |
10163 | | |
10164 | | nsIPrincipal* |
10165 | | nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument) |
10166 | 0 | { |
10167 | 0 | nsCOMPtr<nsIDocument> document; |
10168 | 0 | bool inheritedFromCurrent = false; |
10169 | 0 |
|
10170 | 0 | if (aConsiderCurrentDocument && mContentViewer) { |
10171 | 0 | document = mContentViewer->GetDocument(); |
10172 | 0 | inheritedFromCurrent = true; |
10173 | 0 | } |
10174 | 0 |
|
10175 | 0 | if (!document) { |
10176 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentItem; |
10177 | 0 | GetSameTypeParent(getter_AddRefs(parentItem)); |
10178 | 0 | if (parentItem) { |
10179 | 0 | document = parentItem->GetDocument(); |
10180 | 0 | } |
10181 | 0 | } |
10182 | 0 |
|
10183 | 0 | if (!document) { |
10184 | 0 | if (!aConsiderCurrentDocument) { |
10185 | 0 | return nullptr; |
10186 | 0 | } |
10187 | 0 | |
10188 | 0 | // Make sure we end up with _something_ as the principal no matter |
10189 | 0 | // what.If this fails, we'll just get a null docViewer and bail. |
10190 | 0 | EnsureContentViewer(); |
10191 | 0 | if (!mContentViewer) { |
10192 | 0 | return nullptr; |
10193 | 0 | } |
10194 | 0 | document = mContentViewer->GetDocument(); |
10195 | 0 | } |
10196 | 0 |
|
10197 | 0 | //-- Get the document's principal |
10198 | 0 | if (document) { |
10199 | 0 | nsIPrincipal* docPrincipal = document->NodePrincipal(); |
10200 | 0 |
|
10201 | 0 | // Don't allow loads in typeContent docShells to inherit the system |
10202 | 0 | // principal from existing documents. |
10203 | 0 | if (inheritedFromCurrent && |
10204 | 0 | mItemType == typeContent && |
10205 | 0 | nsContentUtils::IsSystemPrincipal(docPrincipal)) { |
10206 | 0 | return nullptr; |
10207 | 0 | } |
10208 | 0 | |
10209 | 0 | return docPrincipal; |
10210 | 0 | } |
10211 | 0 | |
10212 | 0 | return nullptr; |
10213 | 0 | } |
10214 | | |
10215 | | // CSPs upgrade-insecure-requests directive applies to same origin top level |
10216 | | // navigations. Using the SOP would return false for the case when an https |
10217 | | // page triggers and http page to load, even though that http page would be |
10218 | | // upgraded to https later. Hence we have to use that custom function instead |
10219 | | // of simply calling aTriggeringPrincipal->Equals(aResultPrincipal). |
10220 | | static bool |
10221 | | IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal, |
10222 | | nsIPrincipal* aResultPrincipal) |
10223 | 0 | { |
10224 | 0 | MOZ_ASSERT(aTriggeringPrincipal); |
10225 | 0 | MOZ_ASSERT(aResultPrincipal); |
10226 | 0 |
|
10227 | 0 | // we only have to make sure that the following truth table holds: |
10228 | 0 | // aTriggeringPrincipal | aResultPrincipal | Result |
10229 | 0 | // ---------------------------------------------------------------- |
10230 | 0 | // http://example.com/foo.html | http://example.com/bar.html | true |
10231 | 0 | // https://example.com/foo.html | https://example.com/bar.html | true |
10232 | 0 | // https://example.com/foo.html | http://example.com/bar.html | true |
10233 | 0 | if (aTriggeringPrincipal->Equals(aResultPrincipal)) { |
10234 | 0 | return true; |
10235 | 0 | } |
10236 | 0 | |
10237 | 0 | if (!aResultPrincipal->GetIsCodebasePrincipal()) { |
10238 | 0 | return false; |
10239 | 0 | } |
10240 | 0 | |
10241 | 0 | nsCOMPtr<nsIURI> resultURI; |
10242 | 0 | nsresult rv = aResultPrincipal->GetURI(getter_AddRefs(resultURI)); |
10243 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10244 | 0 |
|
10245 | 0 | nsAutoCString resultScheme; |
10246 | 0 | rv = resultURI->GetScheme(resultScheme); |
10247 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10248 | 0 | if (!resultScheme.EqualsLiteral("http")) { |
10249 | 0 | return false; |
10250 | 0 | } |
10251 | 0 | |
10252 | 0 | nsAutoCString tmpResultSpec; |
10253 | 0 | rv = resultURI->GetSpec(tmpResultSpec); |
10254 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10255 | 0 | // replace http with https |
10256 | 0 | tmpResultSpec.ReplaceLiteral(0, 4, "https"); |
10257 | 0 |
|
10258 | 0 | nsCOMPtr<nsIURI> tmpResultURI; |
10259 | 0 | rv = NS_NewURI(getter_AddRefs(tmpResultURI), tmpResultSpec); |
10260 | 0 | NS_ENSURE_SUCCESS(rv, false); |
10261 | 0 |
|
10262 | 0 | mozilla::OriginAttributes tmpOA = |
10263 | 0 | BasePrincipal::Cast(aResultPrincipal)->OriginAttributesRef(); |
10264 | 0 |
|
10265 | 0 | nsCOMPtr<nsIPrincipal> tmpResultPrincipal = |
10266 | 0 | BasePrincipal::CreateCodebasePrincipal(tmpResultURI, tmpOA); |
10267 | 0 |
|
10268 | 0 | return aTriggeringPrincipal->Equals(tmpResultPrincipal); |
10269 | 0 | } |
10270 | | |
10271 | | nsresult |
10272 | | nsDocShell::DoURILoad(nsIURI* aURI, |
10273 | | nsIURI* aOriginalURI, |
10274 | | Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI, |
10275 | | bool aKeepResultPrincipalURIIfSet, |
10276 | | bool aLoadReplace, |
10277 | | bool aLoadFromExternal, |
10278 | | bool aForceAllowDataURI, |
10279 | | bool aOriginalFrameSrc, |
10280 | | nsIURI* aReferrerURI, |
10281 | | bool aSendReferrer, |
10282 | | uint32_t aReferrerPolicy, |
10283 | | nsIPrincipal* aTriggeringPrincipal, |
10284 | | nsIPrincipal* aPrincipalToInherit, |
10285 | | const char* aTypeHint, |
10286 | | const nsAString& aFileName, |
10287 | | nsIInputStream* aPostData, |
10288 | | nsIInputStream* aHeadersData, |
10289 | | bool aFirstParty, |
10290 | | nsIDocShell** aDocShell, |
10291 | | nsIRequest** aRequest, |
10292 | | bool aIsNewWindowTarget, |
10293 | | bool aBypassClassifier, |
10294 | | bool aForceAllowCookies, |
10295 | | const nsAString& aSrcdoc, |
10296 | | nsIURI* aBaseURI, |
10297 | | nsContentPolicyType aContentPolicyType) |
10298 | 0 | { |
10299 | 0 | // Double-check that we're still around to load this URI. |
10300 | 0 | if (mIsBeingDestroyed) { |
10301 | 0 | // Return NS_OK despite not doing anything to avoid throwing exceptions from |
10302 | 0 | // nsLocation::SetHref if the unload handler of the existing page tears us |
10303 | 0 | // down. |
10304 | 0 | return NS_OK; |
10305 | 0 | } |
10306 | 0 | |
10307 | 0 | nsresult rv; |
10308 | 0 | nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv); |
10309 | 0 | if (NS_FAILED(rv)) { |
10310 | 0 | return rv; |
10311 | 0 | } |
10312 | 0 | |
10313 | 0 | if (IsFrame()) { |
10314 | 0 |
|
10315 | 0 | MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME || |
10316 | 0 | aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME, |
10317 | 0 | "DoURILoad thinks this is a frame and InternalLoad does not"); |
10318 | 0 |
|
10319 | 0 | // Only allow view-source scheme in top-level docshells. view-source is |
10320 | 0 | // the only scheme to which this applies at the moment due to potential |
10321 | 0 | // timing attacks to read data from cross-origin iframes. If this widens |
10322 | 0 | // we should add a protocol flag for whether the scheme is allowed in |
10323 | 0 | // frames and use something like nsNetUtil::NS_URIChainHasFlags. |
10324 | 0 | nsCOMPtr<nsIURI> tempURI = aURI; |
10325 | 0 | nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI); |
10326 | 0 | while (nestedURI) { |
10327 | 0 | // view-source should always be an nsINestedURI, loop and check the |
10328 | 0 | // scheme on this and all inner URIs that are also nested URIs. |
10329 | 0 | bool isViewSource = false; |
10330 | 0 | rv = tempURI->SchemeIs("view-source", &isViewSource); |
10331 | 0 | if (NS_FAILED(rv) || isViewSource) { |
10332 | 0 | return NS_ERROR_UNKNOWN_PROTOCOL; |
10333 | 0 | } |
10334 | 0 | nestedURI->GetInnerURI(getter_AddRefs(tempURI)); |
10335 | 0 | nestedURI = do_QueryInterface(tempURI); |
10336 | 0 | } |
10337 | 0 | } else { |
10338 | 0 | MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT, |
10339 | 0 | "DoURILoad thinks this is a document and InternalLoad does not"); |
10340 | 0 | } |
10341 | 0 |
|
10342 | 0 | // open a channel for the url |
10343 | 0 | nsCOMPtr<nsIChannel> channel; |
10344 | 0 |
|
10345 | 0 | bool isSrcdoc = !aSrcdoc.IsVoid(); |
10346 | 0 |
|
10347 | 0 | // There are two cases we care about: |
10348 | 0 | // * Top-level load: In this case, loadingNode is null, but loadingWindow |
10349 | 0 | // is our mScriptGlobal. We pass null for loadingPrincipal in this case. |
10350 | 0 | // * Subframe load: loadingWindow is null, but loadingNode is the frame |
10351 | 0 | // element for the load. loadingPrincipal is the NodePrincipal of the frame |
10352 | 0 | // element. |
10353 | 0 | nsCOMPtr<nsINode> loadingNode; |
10354 | 0 | nsCOMPtr<nsPIDOMWindowOuter> loadingWindow; |
10355 | 0 | nsCOMPtr<nsIPrincipal> loadingPrincipal; |
10356 | 0 | nsCOMPtr<nsISupports> topLevelLoadingContext; |
10357 | 0 |
|
10358 | 0 | if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) { |
10359 | 0 | loadingNode = nullptr; |
10360 | 0 | loadingPrincipal = nullptr; |
10361 | 0 | loadingWindow = mScriptGlobal->AsOuter(); |
10362 | 0 | if (XRE_IsContentProcess()) { |
10363 | 0 | // In e10s the child process doesn't have access to the element that |
10364 | 0 | // contains the browsing context (because that element is in the chrome |
10365 | 0 | // process). |
10366 | 0 | nsCOMPtr<nsITabChild> tabChild = GetTabChild(); |
10367 | 0 | topLevelLoadingContext = ToSupports(tabChild); |
10368 | 0 | } else { |
10369 | 0 | // This is for loading non-e10s tabs and toplevel windows of various |
10370 | 0 | // sorts. |
10371 | 0 | // For the toplevel window cases, requestingElement will be null. |
10372 | 0 | nsCOMPtr<Element> requestingElement = |
10373 | 0 | loadingWindow->GetFrameElementInternal(); |
10374 | 0 | topLevelLoadingContext = requestingElement; |
10375 | 0 | } |
10376 | 0 | } else { |
10377 | 0 | loadingWindow = nullptr; |
10378 | 0 | loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal(); |
10379 | 0 | if (loadingNode) { |
10380 | 0 | // If we have a loading node, then use that as our loadingPrincipal. |
10381 | 0 | loadingPrincipal = loadingNode->NodePrincipal(); |
10382 | | #ifdef DEBUG |
10383 | | // Get the docshell type for requestingElement. |
10384 | | nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc(); |
10385 | | nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell(); |
10386 | | // requestingElement docshell type = current docshell type. |
10387 | | MOZ_ASSERT(mItemType == elementDocShell->ItemType(), |
10388 | | "subframes should have the same docshell type as their parent"); |
10389 | | #endif |
10390 | 0 | } else { |
10391 | 0 | // If this isn't a top-level load and mScriptGlobal's frame element is |
10392 | 0 | // null, then the element got removed from the DOM while we were trying |
10393 | 0 | // to load this resource. This docshell is scheduled for destruction |
10394 | 0 | // already, so bail out here. |
10395 | 0 | return NS_OK; |
10396 | 0 | } |
10397 | 0 | } |
10398 | 0 | |
10399 | 0 | // Getting the right triggeringPrincipal needs to be updated and is only |
10400 | 0 | // ready for use once bug 1182569 landed. Until then, we cannot rely on |
10401 | 0 | // the triggeringPrincipal for TYPE_DOCUMENT loads. |
10402 | 0 | MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal"); |
10403 | 0 |
|
10404 | 0 | bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN; |
10405 | 0 |
|
10406 | 0 | // We want to inherit aPrincipalToInherit when: |
10407 | 0 | // 1. ChannelShouldInheritPrincipal returns true. |
10408 | 0 | // 2. aURI is not data: URI, or data: URI is not configured as unique opaque |
10409 | 0 | // origin. |
10410 | 0 | bool inheritAttrs = false, inheritPrincipal = false; |
10411 | 0 |
|
10412 | 0 | if (aPrincipalToInherit) { |
10413 | 0 | inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal( |
10414 | 0 | aPrincipalToInherit, |
10415 | 0 | aURI, |
10416 | 0 | true, // aInheritForAboutBlank |
10417 | 0 | isSrcdoc); |
10418 | 0 |
|
10419 | 0 | bool isData; |
10420 | 0 | bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() && |
10421 | 0 | NS_SUCCEEDED(aURI->SchemeIs("data", &isData)) && |
10422 | 0 | isData; |
10423 | 0 | inheritPrincipal = inheritAttrs && !isURIUniqueOrigin; |
10424 | 0 | } |
10425 | 0 |
|
10426 | 0 | nsLoadFlags loadFlags = mDefaultLoadFlags; |
10427 | 0 | nsSecurityFlags securityFlags = |
10428 | 0 | nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; |
10429 | 0 |
|
10430 | 0 | if (aFirstParty) { |
10431 | 0 | // tag first party URL loads |
10432 | 0 | loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI; |
10433 | 0 | } |
10434 | 0 |
|
10435 | 0 | if (mLoadType == LOAD_ERROR_PAGE) { |
10436 | 0 | // Error pages are LOAD_BACKGROUND |
10437 | 0 | loadFlags |= nsIChannel::LOAD_BACKGROUND; |
10438 | 0 | securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE; |
10439 | 0 | } |
10440 | 0 |
|
10441 | 0 | if (inheritPrincipal) { |
10442 | 0 | securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; |
10443 | 0 | } |
10444 | 0 | if (isSandBoxed) { |
10445 | 0 | securityFlags |= nsILoadInfo::SEC_SANDBOXED; |
10446 | 0 | } |
10447 | 0 |
|
10448 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = |
10449 | 0 | (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ? |
10450 | 0 | new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext, |
10451 | 0 | securityFlags) : |
10452 | 0 | new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode, |
10453 | 0 | securityFlags, aContentPolicyType); |
10454 | 0 |
|
10455 | 0 | if (aPrincipalToInherit) { |
10456 | 0 | loadInfo->SetPrincipalToInherit(aPrincipalToInherit); |
10457 | 0 | } |
10458 | 0 | loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal); |
10459 | 0 | loadInfo->SetForceAllowDataURI(aForceAllowDataURI); |
10460 | 0 | loadInfo->SetOriginalFrameSrcLoad(aOriginalFrameSrc); |
10461 | 0 |
|
10462 | 0 | // We have to do this in case our OriginAttributes are different from the |
10463 | 0 | // OriginAttributes of the parent document. Or in case there isn't a |
10464 | 0 | // parent document. |
10465 | 0 | bool isTopLevelDoc = mItemType == typeContent && |
10466 | 0 | (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT || |
10467 | 0 | GetIsMozBrowser()); |
10468 | 0 |
|
10469 | 0 | OriginAttributes attrs; |
10470 | 0 |
|
10471 | 0 | // Inherit origin attributes from aPrincipalToInherit if inheritAttrs is true. |
10472 | 0 | // Otherwise we just use the origin attributes from docshell. |
10473 | 0 | if (inheritAttrs) { |
10474 | 0 | MOZ_ASSERT(aPrincipalToInherit, "We should have aPrincipalToInherit here."); |
10475 | 0 | attrs = aPrincipalToInherit->OriginAttributesRef(); |
10476 | 0 | // If firstPartyIsolation is not enabled, then PrincipalToInherit should |
10477 | 0 | // have the same origin attributes with docshell. |
10478 | 0 | MOZ_ASSERT_IF(!OriginAttributes::IsFirstPartyEnabled(), attrs == GetOriginAttributes()); |
10479 | 0 | } else { |
10480 | 0 | attrs = GetOriginAttributes(); |
10481 | 0 | attrs.SetFirstPartyDomain(isTopLevelDoc, aURI); |
10482 | 0 | } |
10483 | 0 |
|
10484 | 0 | rv = loadInfo->SetOriginAttributes(attrs); |
10485 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
10486 | 0 | return rv; |
10487 | 0 | } |
10488 | 0 | |
10489 | 0 | // Document loads should set the reload flag on the channel so that it |
10490 | 0 | // can be exposed on the service worker FetchEvent. |
10491 | 0 | rv = loadInfo->SetIsDocshellReload(mLoadType & LOAD_CMD_RELOAD); |
10492 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10493 | 0 |
|
10494 | 0 | if (!isSrcdoc) { |
10495 | 0 | rv = NS_NewChannelInternal(getter_AddRefs(channel), |
10496 | 0 | aURI, |
10497 | 0 | loadInfo, |
10498 | 0 | nullptr, // PerformanceStorage |
10499 | 0 | nullptr, // loadGroup |
10500 | 0 | static_cast<nsIInterfaceRequestor*>(this), |
10501 | 0 | loadFlags); |
10502 | 0 |
|
10503 | 0 | if (NS_FAILED(rv)) { |
10504 | 0 | if (rv == NS_ERROR_UNKNOWN_PROTOCOL) { |
10505 | 0 | // This is a uri with a protocol scheme we don't know how |
10506 | 0 | // to handle. Embedders might still be interested in |
10507 | 0 | // handling the load, though, so we fire a notification |
10508 | 0 | // before throwing the load away. |
10509 | 0 | bool abort = false; |
10510 | 0 | nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort); |
10511 | 0 | if (NS_SUCCEEDED(rv2) && abort) { |
10512 | 0 | // Hey, they're handling the load for us! How convenient! |
10513 | 0 | return NS_OK; |
10514 | 0 | } |
10515 | 0 | } |
10516 | 0 | return rv; |
10517 | 0 | } |
10518 | 0 | |
10519 | 0 | if (aBaseURI) { |
10520 | 0 | nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel); |
10521 | 0 | if (vsc) { |
10522 | 0 | rv = vsc->SetBaseURI(aBaseURI); |
10523 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
10524 | 0 | } |
10525 | 0 | } |
10526 | 0 | } else { |
10527 | 0 | nsAutoCString scheme; |
10528 | 0 | rv = aURI->GetScheme(scheme); |
10529 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10530 | 0 | bool isViewSource; |
10531 | 0 | aURI->SchemeIs("view-source", &isViewSource); |
10532 | 0 |
|
10533 | 0 | if (isViewSource) { |
10534 | 0 | nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance(); |
10535 | 0 | NS_ENSURE_TRUE(vsh, NS_ERROR_FAILURE); |
10536 | 0 |
|
10537 | 0 | rv = vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc, |
10538 | 0 | loadInfo, getter_AddRefs(channel)); |
10539 | 0 | } else { |
10540 | 0 | rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), |
10541 | 0 | aURI, |
10542 | 0 | aSrcdoc, |
10543 | 0 | NS_LITERAL_CSTRING("text/html"), |
10544 | 0 | loadInfo, |
10545 | 0 | true); |
10546 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10547 | 0 | nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel); |
10548 | 0 | MOZ_ASSERT(isc); |
10549 | 0 | isc->SetBaseURI(aBaseURI); |
10550 | 0 | } |
10551 | 0 | } |
10552 | 0 |
|
10553 | 0 | // Navigational requests that are same origin need to be upgraded in case |
10554 | 0 | // upgrade-insecure-requests is present. Please note that in that case |
10555 | 0 | // the triggeringPrincipal is holding the CSP that potentially |
10556 | 0 | // holds upgrade-insecure-requests. |
10557 | 0 | nsCOMPtr<nsIContentSecurityPolicy> csp; |
10558 | 0 | aTriggeringPrincipal->GetCsp(getter_AddRefs(csp)); |
10559 | 0 | if (csp) { |
10560 | 0 | bool upgradeInsecureRequests = false; |
10561 | 0 | csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests); |
10562 | 0 | if (upgradeInsecureRequests) { |
10563 | 0 | // only upgrade if the navigation is same origin |
10564 | 0 | nsCOMPtr<nsIPrincipal> resultPrincipal; |
10565 | 0 | rv = nsContentUtils::GetSecurityManager()-> |
10566 | 0 | GetChannelResultPrincipal(channel, |
10567 | 0 | getter_AddRefs(resultPrincipal)); |
10568 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10569 | 0 | if (IsConsideredSameOriginForUIR(aTriggeringPrincipal, resultPrincipal)) { |
10570 | 0 | static_cast<LoadInfo*>(loadInfo.get())->SetUpgradeInsecureRequests(); |
10571 | 0 | } |
10572 | 0 | } |
10573 | 0 | } |
10574 | 0 |
|
10575 | 0 |
|
10576 | 0 | nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
10577 | 0 | do_QueryInterface(channel); |
10578 | 0 | if (appCacheChannel) { |
10579 | 0 | // Any document load should not inherit application cache. |
10580 | 0 | appCacheChannel->SetInheritApplicationCache(false); |
10581 | 0 |
|
10582 | 0 | // Loads with the correct permissions should check for a matching |
10583 | 0 | // application cache. |
10584 | 0 | if (GeckoProcessType_Default != XRE_GetProcessType()) { |
10585 | 0 | // Permission will be checked in the parent process |
10586 | 0 | appCacheChannel->SetChooseApplicationCache(true); |
10587 | 0 | } else { |
10588 | 0 | nsCOMPtr<nsIScriptSecurityManager> secMan = |
10589 | 0 | do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
10590 | 0 |
|
10591 | 0 | if (secMan) { |
10592 | 0 | nsCOMPtr<nsIPrincipal> principal; |
10593 | 0 | secMan->GetDocShellCodebasePrincipal(aURI, this, |
10594 | 0 | getter_AddRefs(principal)); |
10595 | 0 | appCacheChannel->SetChooseApplicationCache( |
10596 | 0 | NS_ShouldCheckAppCache(principal)); |
10597 | 0 | } |
10598 | 0 | } |
10599 | 0 | } |
10600 | 0 |
|
10601 | 0 | // Make sure to give the caller a channel if we managed to create one |
10602 | 0 | // This is important for correct error page/session history interaction |
10603 | 0 | if (aRequest) { |
10604 | 0 | NS_ADDREF(*aRequest = channel); |
10605 | 0 | } |
10606 | 0 |
|
10607 | 0 | if (aOriginalURI) { |
10608 | 0 | channel->SetOriginalURI(aOriginalURI); |
10609 | 0 | // The LOAD_REPLACE flag and its handling here will be removed as part |
10610 | 0 | // of bug 1319110. For now preserve its restoration here to not break |
10611 | 0 | // any code expecting it being set specially on redirected channels. |
10612 | 0 | // If the flag has originally been set to change result of |
10613 | 0 | // NS_GetFinalChannelURI it won't have any effect and also won't cause |
10614 | 0 | // any harm. |
10615 | 0 | if (aLoadReplace) { |
10616 | 0 | uint32_t loadFlags; |
10617 | 0 | channel->GetLoadFlags(&loadFlags); |
10618 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10619 | 0 | channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE); |
10620 | 0 | } |
10621 | 0 | } else { |
10622 | 0 | channel->SetOriginalURI(aURI); |
10623 | 0 | } |
10624 | 0 |
|
10625 | 0 | nsCOMPtr<nsIURI> rpURI; |
10626 | 0 | loadInfo->GetResultPrincipalURI(getter_AddRefs(rpURI)); |
10627 | 0 | if (aResultPrincipalURI && |
10628 | 0 | (!aKeepResultPrincipalURIIfSet || !rpURI)) { |
10629 | 0 | // Unconditionally override, we want the replay to be equal to what has |
10630 | 0 | // been captured. |
10631 | 0 | loadInfo->SetResultPrincipalURI(aResultPrincipalURI.ref()); |
10632 | 0 | } |
10633 | 0 |
|
10634 | 0 | if (aTypeHint && *aTypeHint) { |
10635 | 0 | channel->SetContentType(nsDependentCString(aTypeHint)); |
10636 | 0 | mContentTypeHint = aTypeHint; |
10637 | 0 | } else { |
10638 | 0 | mContentTypeHint.Truncate(); |
10639 | 0 | } |
10640 | 0 |
|
10641 | 0 | if (!aFileName.IsVoid()) { |
10642 | 0 | rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT); |
10643 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10644 | 0 | if (!aFileName.IsEmpty()) { |
10645 | 0 | rv = channel->SetContentDispositionFilename(aFileName); |
10646 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10647 | 0 | } |
10648 | 0 | } |
10649 | 0 |
|
10650 | 0 | if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT || |
10651 | 0 | mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) { |
10652 | 0 | rv = SetMixedContentChannel(channel); |
10653 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10654 | 0 | } else if (mMixedContentChannel) { |
10655 | 0 | /* |
10656 | 0 | * If the user "Disables Protection on This Page", we call |
10657 | 0 | * SetMixedContentChannel for the first time, otherwise |
10658 | 0 | * mMixedContentChannel is still null. |
10659 | 0 | * Later, if the new channel passes a same orign check, we remember the |
10660 | 0 | * users decision by calling SetMixedContentChannel using the new channel. |
10661 | 0 | * This way, the user does not have to click the disable protection button |
10662 | 0 | * over and over for browsing the same site. |
10663 | 0 | */ |
10664 | 0 | rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel); |
10665 | 0 | if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) { |
10666 | 0 | SetMixedContentChannel(nullptr); |
10667 | 0 | } |
10668 | 0 | } |
10669 | 0 |
|
10670 | 0 | // hack |
10671 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); |
10672 | 0 | nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal( |
10673 | 0 | do_QueryInterface(channel)); |
10674 | 0 | if (httpChannelInternal) { |
10675 | 0 | if (aForceAllowCookies) { |
10676 | 0 | rv = httpChannelInternal->SetThirdPartyFlags( |
10677 | 0 | nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW); |
10678 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
10679 | 0 | } |
10680 | 0 | if (aFirstParty) { |
10681 | 0 | rv = httpChannelInternal->SetDocumentURI(aURI); |
10682 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
10683 | 0 | } else { |
10684 | 0 | rv = httpChannelInternal->SetDocumentURI(aReferrerURI); |
10685 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
10686 | 0 | } |
10687 | 0 | rv = httpChannelInternal->SetRedirectMode( |
10688 | 0 | nsIHttpChannelInternal::REDIRECT_MODE_MANUAL); |
10689 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
10690 | 0 | } |
10691 | 0 |
|
10692 | 0 | nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel)); |
10693 | 0 | if (props) { |
10694 | 0 | // save true referrer for those who need it (e.g. xpinstall whitelisting) |
10695 | 0 | // Currently only http and ftp channels support this. |
10696 | 0 | props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), |
10697 | 0 | aReferrerURI); |
10698 | 0 | } |
10699 | 0 |
|
10700 | 0 | nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel)); |
10701 | 0 | /* Get the cache Key from SH */ |
10702 | 0 | uint32_t cacheKey = 0; |
10703 | 0 | if (cacheChannel) { |
10704 | 0 | if (mLSHE) { |
10705 | 0 | cacheKey = mLSHE->GetCacheKey(); |
10706 | 0 | } else if (mOSHE) { // for reload cases |
10707 | 0 | cacheKey = mOSHE->GetCacheKey(); |
10708 | 0 | } |
10709 | 0 | } |
10710 | 0 |
|
10711 | 0 | // figure out if we need to set the post data stream on the channel... |
10712 | 0 | if (aPostData) { |
10713 | 0 | nsCOMPtr<nsIFormPOSTActionChannel> postChannel(do_QueryInterface(channel)); |
10714 | 0 | if (postChannel) { |
10715 | 0 | // XXX it's a bit of a hack to rewind the postdata stream here but |
10716 | 0 | // it has to be done in case the post data is being reused multiple |
10717 | 0 | // times. |
10718 | 0 | nsCOMPtr<nsISeekableStream> postDataSeekable = |
10719 | 0 | do_QueryInterface(aPostData); |
10720 | 0 | if (postDataSeekable) { |
10721 | 0 | rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); |
10722 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10723 | 0 | } |
10724 | 0 |
|
10725 | 0 | // we really need to have a content type associated with this stream!! |
10726 | 0 | postChannel->SetUploadStream(aPostData, EmptyCString(), -1); |
10727 | 0 | } |
10728 | 0 |
|
10729 | 0 | /* If there is a valid postdata *and* it is a History Load, |
10730 | 0 | * set up the cache key on the channel, to retrieve the |
10731 | 0 | * data *only* from the cache. If it is a normal reload, the |
10732 | 0 | * cache is free to go to the server for updated postdata. |
10733 | 0 | */ |
10734 | 0 | if (cacheChannel && cacheKey != 0) { |
10735 | 0 | if (mLoadType == LOAD_HISTORY || |
10736 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE) { |
10737 | 0 | cacheChannel->SetCacheKey(cacheKey); |
10738 | 0 | uint32_t loadFlags; |
10739 | 0 | if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) { |
10740 | 0 | channel->SetLoadFlags( |
10741 | 0 | loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE); |
10742 | 0 | } |
10743 | 0 | } else if (mLoadType == LOAD_RELOAD_NORMAL) { |
10744 | 0 | cacheChannel->SetCacheKey(cacheKey); |
10745 | 0 | } |
10746 | 0 | } |
10747 | 0 | } else { |
10748 | 0 | /* If there is no postdata, set the cache key on the channel, and |
10749 | 0 | * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel |
10750 | 0 | * will be free to get it from net if it is not found in cache. |
10751 | 0 | * New cache may use it creatively on CGI pages with GET |
10752 | 0 | * method and even on those that say "no-cache" |
10753 | 0 | */ |
10754 | 0 | if (mLoadType == LOAD_HISTORY || |
10755 | 0 | mLoadType == LOAD_RELOAD_NORMAL || |
10756 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE || |
10757 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE || |
10758 | 0 | mLoadType == LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE) { |
10759 | 0 | if (cacheChannel && cacheKey != 0) { |
10760 | 0 | cacheChannel->SetCacheKey(cacheKey); |
10761 | 0 | } |
10762 | 0 | } |
10763 | 0 | } |
10764 | 0 |
|
10765 | 0 | if (httpChannel) { |
10766 | 0 | if (aHeadersData) { |
10767 | 0 | rv = AddHeadersToChannel(aHeadersData, httpChannel); |
10768 | 0 | } |
10769 | 0 | // Set the referrer explicitly |
10770 | 0 | if (aReferrerURI && aSendReferrer) { |
10771 | 0 | // Referrer is currenly only set for link clicks here. |
10772 | 0 | rv = httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy); |
10773 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
10774 | 0 | } |
10775 | 0 | } |
10776 | 0 |
|
10777 | 0 | nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel); |
10778 | 0 | if (scriptChannel) { |
10779 | 0 | // Allow execution against our context if the principals match |
10780 | 0 | scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL); |
10781 | 0 | } |
10782 | 0 |
|
10783 | 0 | if (aIsNewWindowTarget) { |
10784 | 0 | nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel); |
10785 | 0 | if (props) { |
10786 | 0 | props->SetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"), |
10787 | 0 | true); |
10788 | 0 | } |
10789 | 0 | } |
10790 | 0 |
|
10791 | 0 | nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel)); |
10792 | 0 | if (timedChannel) { |
10793 | 0 | timedChannel->SetTimingEnabled(true); |
10794 | 0 |
|
10795 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
10796 | 0 | if (IsFrame() && win) { |
10797 | 0 | nsCOMPtr<Element> frameElement = win->GetFrameElementInternal(); |
10798 | 0 | if (frameElement) { |
10799 | 0 | timedChannel->SetInitiatorType(frameElement->LocalName()); |
10800 | 0 | } |
10801 | 0 | } |
10802 | 0 | } |
10803 | 0 |
|
10804 | 0 | // Mark the http channel as UrgentStart for top level document loading |
10805 | 0 | // in active tab. |
10806 | 0 | if (mIsActive || (mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY))) { |
10807 | 0 | if (httpChannel && isTopLevelDoc) { |
10808 | 0 | nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel)); |
10809 | 0 | if (cos) { |
10810 | 0 | cos->AddClassFlags(nsIClassOfService::UrgentStart); |
10811 | 0 | } |
10812 | 0 | } |
10813 | 0 | } |
10814 | 0 |
|
10815 | 0 | rv = DoChannelLoad(channel, uriLoader, aBypassClassifier); |
10816 | 0 |
|
10817 | 0 | // |
10818 | 0 | // If the channel load failed, we failed and nsIWebProgress just ain't |
10819 | 0 | // gonna happen. |
10820 | 0 | // |
10821 | 0 | if (NS_SUCCEEDED(rv)) { |
10822 | 0 | if (aDocShell) { |
10823 | 0 | *aDocShell = this; |
10824 | 0 | NS_ADDREF(*aDocShell); |
10825 | 0 | } |
10826 | 0 | } |
10827 | 0 |
|
10828 | 0 | return rv; |
10829 | 0 | } |
10830 | | |
10831 | | static nsresult |
10832 | | AppendSegmentToString(nsIInputStream* aIn, |
10833 | | void* aClosure, |
10834 | | const char* aFromRawSegment, |
10835 | | uint32_t aToOffset, |
10836 | | uint32_t aCount, |
10837 | | uint32_t* aWriteCount) |
10838 | 0 | { |
10839 | 0 | // aFromSegment now contains aCount bytes of data. |
10840 | 0 |
|
10841 | 0 | nsAutoCString* buf = static_cast<nsAutoCString*>(aClosure); |
10842 | 0 | buf->Append(aFromRawSegment, aCount); |
10843 | 0 |
|
10844 | 0 | // Indicate that we have consumed all of aFromSegment |
10845 | 0 | *aWriteCount = aCount; |
10846 | 0 | return NS_OK; |
10847 | 0 | } |
10848 | | |
10849 | | nsresult |
10850 | | nsDocShell::AddHeadersToChannel(nsIInputStream* aHeadersData, |
10851 | | nsIChannel* aGenericChannel) |
10852 | 0 | { |
10853 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel); |
10854 | 0 | NS_ENSURE_STATE(httpChannel); |
10855 | 0 |
|
10856 | 0 | uint32_t numRead; |
10857 | 0 | nsAutoCString headersString; |
10858 | 0 | nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString, |
10859 | 0 | &headersString, |
10860 | 0 | UINT32_MAX, |
10861 | 0 | &numRead); |
10862 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10863 | 0 |
|
10864 | 0 | // used during the manipulation of the String from the InputStream |
10865 | 0 | nsAutoCString headerName; |
10866 | 0 | nsAutoCString headerValue; |
10867 | 0 | int32_t crlf; |
10868 | 0 | int32_t colon; |
10869 | 0 |
|
10870 | 0 | // |
10871 | 0 | // Iterate over the headersString: for each "\r\n" delimited chunk, |
10872 | 0 | // add the value as a header to the nsIHttpChannel |
10873 | 0 | // |
10874 | 0 |
|
10875 | 0 | static const char kWhitespace[] = "\b\t\r\n "; |
10876 | 0 | while (true) { |
10877 | 0 | crlf = headersString.Find("\r\n"); |
10878 | 0 | if (crlf == kNotFound) { |
10879 | 0 | return NS_OK; |
10880 | 0 | } |
10881 | 0 | |
10882 | 0 | const nsACString& oneHeader = StringHead(headersString, crlf); |
10883 | 0 |
|
10884 | 0 | colon = oneHeader.FindChar(':'); |
10885 | 0 | if (colon == kNotFound) { |
10886 | 0 | return NS_ERROR_UNEXPECTED; |
10887 | 0 | } |
10888 | 0 | |
10889 | 0 | headerName = StringHead(oneHeader, colon); |
10890 | 0 | headerValue = Substring(oneHeader, colon + 1); |
10891 | 0 |
|
10892 | 0 | headerName.Trim(kWhitespace); |
10893 | 0 | headerValue.Trim(kWhitespace); |
10894 | 0 |
|
10895 | 0 | headersString.Cut(0, crlf + 2); |
10896 | 0 |
|
10897 | 0 | // |
10898 | 0 | // FINALLY: we can set the header! |
10899 | 0 | // |
10900 | 0 |
|
10901 | 0 | rv = httpChannel->SetRequestHeader(headerName, headerValue, true); |
10902 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
10903 | 0 | } |
10904 | 0 |
|
10905 | 0 | MOZ_ASSERT_UNREACHABLE("oops"); |
10906 | 0 | return NS_ERROR_UNEXPECTED; |
10907 | 0 | } |
10908 | | |
10909 | | nsresult |
10910 | | nsDocShell::DoChannelLoad(nsIChannel* aChannel, |
10911 | | nsIURILoader* aURILoader, |
10912 | | bool aBypassClassifier) |
10913 | 0 | { |
10914 | 0 | nsresult rv; |
10915 | 0 | // Mark the channel as being a document URI and allow content sniffing... |
10916 | 0 | nsLoadFlags loadFlags = 0; |
10917 | 0 | (void)aChannel->GetLoadFlags(&loadFlags); |
10918 | 0 | loadFlags |= nsIChannel::LOAD_DOCUMENT_URI | |
10919 | 0 | nsIChannel::LOAD_CALL_CONTENT_SNIFFERS; |
10920 | 0 |
|
10921 | 0 | if (SandboxFlagsImplyCookies(mSandboxFlags)) { |
10922 | 0 | loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE; |
10923 | 0 | } |
10924 | 0 | // Load attributes depend on load type... |
10925 | 0 | switch (mLoadType) { |
10926 | 0 | case LOAD_HISTORY: { |
10927 | 0 | // Only send VALIDATE_NEVER if mLSHE's URI was never changed via |
10928 | 0 | // push/replaceState (bug 669671). |
10929 | 0 | bool uriModified = false; |
10930 | 0 | if (mLSHE) { |
10931 | 0 | uriModified = mLSHE->GetURIWasModified(); |
10932 | 0 | } |
10933 | 0 |
|
10934 | 0 | if (!uriModified) { |
10935 | 0 | loadFlags |= nsIRequest::VALIDATE_NEVER; |
10936 | 0 | } |
10937 | 0 | break; |
10938 | 0 | } |
10939 | 0 |
|
10940 | 0 | case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE: |
10941 | 0 | case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE: |
10942 | 0 | loadFlags |= nsIRequest::LOAD_BYPASS_CACHE | |
10943 | 0 | nsIRequest::LOAD_FRESH_CONNECTION; |
10944 | 0 | MOZ_FALLTHROUGH; |
10945 | 0 |
|
10946 | 0 | case LOAD_RELOAD_CHARSET_CHANGE: { |
10947 | 0 | // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we only want |
10948 | 0 | // to force cache load for this channel, not the whole loadGroup. |
10949 | 0 | nsCOMPtr<nsICacheInfoChannel> cachingChannel = do_QueryInterface(aChannel); |
10950 | 0 | if (cachingChannel) { |
10951 | 0 | cachingChannel->SetAllowStaleCacheContent(true); |
10952 | 0 | } |
10953 | 0 | break; |
10954 | 0 | } |
10955 | 0 |
|
10956 | 0 | case LOAD_RELOAD_NORMAL: |
10957 | 0 | case LOAD_REFRESH: |
10958 | 0 | loadFlags |= nsIRequest::VALIDATE_ALWAYS; |
10959 | 0 | break; |
10960 | 0 |
|
10961 | 0 | case LOAD_NORMAL_BYPASS_CACHE: |
10962 | 0 | case LOAD_NORMAL_BYPASS_PROXY: |
10963 | 0 | case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE: |
10964 | 0 | case LOAD_NORMAL_ALLOW_MIXED_CONTENT: |
10965 | 0 | case LOAD_RELOAD_BYPASS_CACHE: |
10966 | 0 | case LOAD_RELOAD_BYPASS_PROXY: |
10967 | 0 | case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
10968 | 0 | case LOAD_RELOAD_ALLOW_MIXED_CONTENT: |
10969 | 0 | case LOAD_REPLACE_BYPASS_CACHE: |
10970 | 0 | loadFlags |= nsIRequest::LOAD_BYPASS_CACHE | |
10971 | 0 | nsIRequest::LOAD_FRESH_CONNECTION; |
10972 | 0 | break; |
10973 | 0 |
|
10974 | 0 | case LOAD_NORMAL: |
10975 | 0 | case LOAD_LINK: |
10976 | 0 | // Set cache checking flags |
10977 | 0 | switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) { |
10978 | 0 | case 0: |
10979 | 0 | loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION; |
10980 | 0 | break; |
10981 | 0 | case 1: |
10982 | 0 | loadFlags |= nsIRequest::VALIDATE_ALWAYS; |
10983 | 0 | break; |
10984 | 0 | case 2: |
10985 | 0 | loadFlags |= nsIRequest::VALIDATE_NEVER; |
10986 | 0 | break; |
10987 | 0 | } |
10988 | 0 | break; |
10989 | 0 | } |
10990 | 0 | |
10991 | 0 | if (!aBypassClassifier) { |
10992 | 0 | loadFlags |= nsIChannel::LOAD_CLASSIFY_URI; |
10993 | 0 | } |
10994 | 0 |
|
10995 | 0 | // If the user pressed shift-reload, then do not allow ServiceWorker |
10996 | 0 | // interception to occur. See step 12.1 of the SW HandleFetch algorithm. |
10997 | 0 | if (IsForceReloading()) { |
10998 | 0 | loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; |
10999 | 0 | } |
11000 | 0 |
|
11001 | 0 | (void)aChannel->SetLoadFlags(loadFlags); |
11002 | 0 |
|
11003 | 0 | uint32_t openFlags = 0; |
11004 | 0 | if (mLoadType == LOAD_LINK) { |
11005 | 0 | openFlags |= nsIURILoader::IS_CONTENT_PREFERRED; |
11006 | 0 | } |
11007 | 0 | if (!mAllowContentRetargeting) { |
11008 | 0 | openFlags |= nsIURILoader::DONT_RETARGET; |
11009 | 0 | } |
11010 | 0 |
|
11011 | 0 | // If anything fails here, make sure to clear our initial ClientSource. |
11012 | 0 | auto cleanupInitialClient = MakeScopeExit([&] { |
11013 | 0 | mInitialClientSource.reset(); |
11014 | 0 | }); |
11015 | 0 |
|
11016 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
11017 | 0 | NS_ENSURE_TRUE(win, NS_ERROR_FAILURE); |
11018 | 0 |
|
11019 | 0 | MaybeCreateInitialClientSource(); |
11020 | 0 |
|
11021 | 0 | // Since we are loading a document we need to make sure the proper reserved |
11022 | 0 | // and initial client data is stored on the nsILoadInfo. The |
11023 | 0 | // ClientChannelHelper does this and ensures that it is propagated properly |
11024 | 0 | // on redirects. We pass no reserved client here so that the helper will |
11025 | 0 | // create the reserved ClientSource if necessary. |
11026 | 0 | Maybe<ClientInfo> noReservedClient; |
11027 | 0 | rv = AddClientChannelHelper(aChannel, |
11028 | 0 | std::move(noReservedClient), |
11029 | 0 | GetInitialClientInfo(), |
11030 | 0 | win->EventTargetFor(TaskCategory::Other)); |
11031 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11032 | 0 |
|
11033 | 0 | rv = aURILoader->OpenURI(aChannel, openFlags, this); |
11034 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11035 | 0 |
|
11036 | 0 | // We're about to load a new page and it may take time before necko |
11037 | 0 | // gives back any data, so main thread might have a chance to process a |
11038 | 0 | // collector slice |
11039 | 0 | nsJSContext::MaybeRunNextCollectorSlice(this, JS::gcreason::DOCSHELL); |
11040 | 0 |
|
11041 | 0 | // Success. Keep the initial ClientSource if it exists. |
11042 | 0 | cleanupInitialClient.release(); |
11043 | 0 |
|
11044 | 0 | return NS_OK; |
11045 | 0 | } |
11046 | | |
11047 | | nsresult |
11048 | | nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef, |
11049 | | nsACString& aNewHash, uint32_t aLoadType) |
11050 | 0 | { |
11051 | 0 | if (!mCurrentURI) { |
11052 | 0 | return NS_OK; |
11053 | 0 | } |
11054 | 0 | |
11055 | 0 | nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
11056 | 0 | if (!shell) { |
11057 | 0 | // If we failed to get the shell, or if there is no shell, |
11058 | 0 | // nothing left to do here. |
11059 | 0 | return NS_OK; |
11060 | 0 | } |
11061 | 0 | |
11062 | 0 | nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable(); |
11063 | 0 | if (rootScroll) { |
11064 | 0 | rootScroll->ClearDidHistoryRestore(); |
11065 | 0 | } |
11066 | 0 |
|
11067 | 0 | // If we have no new anchor, we do not want to scroll, unless there is a |
11068 | 0 | // current anchor and we are doing a history load. So return if we have no |
11069 | 0 | // new anchor, and there is no current anchor or the load is not a history |
11070 | 0 | // load. |
11071 | 0 | if ((!aCurHasRef || aLoadType != LOAD_HISTORY) && !aNewHasRef) { |
11072 | 0 | return NS_OK; |
11073 | 0 | } |
11074 | 0 | |
11075 | 0 | // Both the new and current URIs refer to the same page. We can now |
11076 | 0 | // browse to the hash stored in the new URI. |
11077 | 0 | |
11078 | 0 | if (!aNewHash.IsEmpty()) { |
11079 | 0 | // anchor is there, but if it's a load from history, |
11080 | 0 | // we don't have any anchor jumping to do |
11081 | 0 | bool scroll = aLoadType != LOAD_HISTORY && |
11082 | 0 | aLoadType != LOAD_RELOAD_NORMAL; |
11083 | 0 |
|
11084 | 0 | // We assume that the bytes are in UTF-8, as it says in the |
11085 | 0 | // spec: |
11086 | 0 | // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1 |
11087 | 0 |
|
11088 | 0 | // We try the UTF-8 string first, and then try the document's |
11089 | 0 | // charset (see below). If the string is not UTF-8, |
11090 | 0 | // conversion will fail and give us an empty Unicode string. |
11091 | 0 | // In that case, we should just fall through to using the |
11092 | 0 | // page's charset. |
11093 | 0 | nsresult rv = NS_ERROR_FAILURE; |
11094 | 0 | NS_ConvertUTF8toUTF16 uStr(aNewHash); |
11095 | 0 | if (!uStr.IsEmpty()) { |
11096 | 0 | rv = shell->GoToAnchor(uStr, scroll, |
11097 | 0 | nsIPresShell::SCROLL_SMOOTH_AUTO); |
11098 | 0 | } |
11099 | 0 |
|
11100 | 0 | if (NS_FAILED(rv)) { |
11101 | 0 | char* str = ToNewCString(aNewHash); |
11102 | 0 | if (!str) { |
11103 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
11104 | 0 | } |
11105 | 0 | nsUnescape(str); |
11106 | 0 | NS_ConvertUTF8toUTF16 utf16Str(str); |
11107 | 0 | if (!utf16Str.IsEmpty()) { |
11108 | 0 | rv = shell->GoToAnchor(utf16Str, scroll, |
11109 | 0 | nsIPresShell::SCROLL_SMOOTH_AUTO); |
11110 | 0 | } |
11111 | 0 | free(str); |
11112 | 0 | } |
11113 | 0 |
|
11114 | 0 | // Above will fail if the anchor name is not UTF-8. Need to |
11115 | 0 | // convert from document charset to unicode. |
11116 | 0 | if (NS_FAILED(rv)) { |
11117 | 0 | // Get a document charset |
11118 | 0 | NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE); |
11119 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
11120 | 0 | NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
11121 | 0 | nsAutoCString charset; |
11122 | 0 | doc->GetDocumentCharacterSet()->Name(charset); |
11123 | 0 |
|
11124 | 0 | nsCOMPtr<nsITextToSubURI> textToSubURI = |
11125 | 0 | do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); |
11126 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11127 | 0 |
|
11128 | 0 | // Unescape and convert to unicode |
11129 | 0 | nsAutoString uStr; |
11130 | 0 |
|
11131 | 0 | rv = textToSubURI->UnEscapeAndConvert(charset, aNewHash, uStr); |
11132 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11133 | 0 |
|
11134 | 0 | // Ignore return value of GoToAnchor, since it will return an error |
11135 | 0 | // if there is no such anchor in the document, which is actually a |
11136 | 0 | // success condition for us (we want to update the session history |
11137 | 0 | // with the new URI no matter whether we actually scrolled |
11138 | 0 | // somewhere). |
11139 | 0 | // |
11140 | 0 | // When aNewHash contains "%00", unescaped string may be empty. |
11141 | 0 | // And GoToAnchor asserts if we ask it to scroll to an empty ref. |
11142 | 0 | shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty(), |
11143 | 0 | nsIPresShell::SCROLL_SMOOTH_AUTO); |
11144 | 0 | } |
11145 | 0 | } else { |
11146 | 0 | // Tell the shell it's at an anchor, without scrolling. |
11147 | 0 | shell->GoToAnchor(EmptyString(), false); |
11148 | 0 |
|
11149 | 0 | // An empty anchor was found, but if it's a load from history, |
11150 | 0 | // we don't have to jump to the top of the page. Scrollbar |
11151 | 0 | // position will be restored by the caller, based on positions |
11152 | 0 | // stored in session history. |
11153 | 0 | if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) { |
11154 | 0 | return NS_OK; |
11155 | 0 | } |
11156 | 0 | // An empty anchor. Scroll to the top of the page. Ignore the |
11157 | 0 | // return value; failure to scroll here (e.g. if there is no |
11158 | 0 | // root scrollframe) is not grounds for canceling the load! |
11159 | 0 | SetCurScrollPosEx(0, 0); |
11160 | 0 | } |
11161 | 0 |
|
11162 | 0 | return NS_OK; |
11163 | 0 | } |
11164 | | |
11165 | | void |
11166 | | nsDocShell::SetupReferrerFromChannel(nsIChannel* aChannel) |
11167 | 0 | { |
11168 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
11169 | 0 | if (httpChannel) { |
11170 | 0 | nsCOMPtr<nsIURI> referrer; |
11171 | 0 | nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer)); |
11172 | 0 | if (NS_SUCCEEDED(rv)) { |
11173 | 0 | SetReferrerURI(referrer); |
11174 | 0 | } |
11175 | 0 | uint32_t referrerPolicy; |
11176 | 0 | rv = httpChannel->GetReferrerPolicy(&referrerPolicy); |
11177 | 0 | if (NS_SUCCEEDED(rv)) { |
11178 | 0 | SetReferrerPolicy(referrerPolicy); |
11179 | 0 | } |
11180 | 0 | } |
11181 | 0 | } |
11182 | | |
11183 | | bool |
11184 | | nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel, |
11185 | | nsIPrincipal* aTriggeringPrincipal, |
11186 | | nsIPrincipal* aPrincipalToInherit, |
11187 | | uint32_t aLoadType, bool aFireOnLocationChange, |
11188 | | bool aAddToGlobalHistory, bool aCloneSHChildren) |
11189 | 0 | { |
11190 | 0 | MOZ_ASSERT(aURI, "uri is null"); |
11191 | 0 | MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set"); |
11192 | 0 |
|
11193 | 0 | MOZ_ASSERT(!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal)); |
11194 | 0 |
|
11195 | | #if defined(DEBUG) |
11196 | | if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) { |
11197 | | nsAutoCString chanName; |
11198 | | if (aChannel) { |
11199 | | aChannel->GetName(chanName); |
11200 | | } else { |
11201 | | chanName.AssignLiteral("<no channel>"); |
11202 | | } |
11203 | | |
11204 | | MOZ_LOG(gDocShellLog, LogLevel::Debug, |
11205 | | ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", |
11206 | | this, aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType)); |
11207 | | } |
11208 | | #endif |
11209 | |
|
11210 | 0 | bool equalUri = false; |
11211 | 0 |
|
11212 | 0 | // Get the post data and the HTTP response code from the channel. |
11213 | 0 | uint32_t responseStatus = 0; |
11214 | 0 | nsCOMPtr<nsIInputStream> inputStream; |
11215 | 0 | if (aChannel) { |
11216 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
11217 | 0 |
|
11218 | 0 | // Check if the HTTPChannel is hiding under a multiPartChannel |
11219 | 0 | if (!httpChannel) { |
11220 | 0 | GetHttpChannel(aChannel, getter_AddRefs(httpChannel)); |
11221 | 0 | } |
11222 | 0 |
|
11223 | 0 | if (httpChannel) { |
11224 | 0 | nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel)); |
11225 | 0 | if (uploadChannel) { |
11226 | 0 | uploadChannel->GetUploadStream(getter_AddRefs(inputStream)); |
11227 | 0 | } |
11228 | 0 |
|
11229 | 0 | // If the response status indicates an error, unlink this session |
11230 | 0 | // history entry from any entries sharing its document. |
11231 | 0 | nsresult rv = httpChannel->GetResponseStatus(&responseStatus); |
11232 | 0 | if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) { |
11233 | 0 | mLSHE->AbandonBFCacheEntry(); |
11234 | 0 | } |
11235 | 0 | } |
11236 | 0 | } |
11237 | 0 |
|
11238 | 0 | // Determine if this type of load should update history. |
11239 | 0 | bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY || |
11240 | 0 | aLoadType == LOAD_ERROR_PAGE || |
11241 | 0 | aLoadType & LOAD_CMD_HISTORY); |
11242 | 0 |
|
11243 | 0 | // We don't update session history on reload unless we're loading |
11244 | 0 | // an iframe in shift-reload case. |
11245 | 0 | bool updateSHistory = updateGHistory && |
11246 | 0 | (!(aLoadType & LOAD_CMD_RELOAD) || |
11247 | 0 | (IsForceReloadType(aLoadType) && IsFrame())); |
11248 | 0 |
|
11249 | 0 | // Create SH Entry (mLSHE) only if there is a SessionHistory object in the |
11250 | 0 | // current frame or in the root docshell. |
11251 | 0 | RefPtr<ChildSHistory> rootSH = mSessionHistory; |
11252 | 0 | if (!rootSH) { |
11253 | 0 | // Get the handle to SH from the root docshell |
11254 | 0 | rootSH = GetRootSessionHistory(); |
11255 | 0 | } |
11256 | 0 | if (!rootSH) { |
11257 | 0 | updateSHistory = false; |
11258 | 0 | updateGHistory = false; // XXX Why global history too? |
11259 | 0 | } |
11260 | 0 |
|
11261 | 0 | // Check if the url to be loaded is the same as the one already loaded. |
11262 | 0 | if (mCurrentURI) { |
11263 | 0 | aURI->Equals(mCurrentURI, &equalUri); |
11264 | 0 | } |
11265 | 0 |
|
11266 | | #ifdef DEBUG |
11267 | | bool shAvailable = (rootSH != nullptr); |
11268 | | |
11269 | | // XXX This log message is almost useless because |updateSHistory| |
11270 | | // and |updateGHistory| are not correct at this point. |
11271 | | |
11272 | | MOZ_LOG(gDocShellLog, LogLevel::Debug, |
11273 | | (" shAvailable=%i updateSHistory=%i updateGHistory=%i" |
11274 | | " equalURI=%i\n", |
11275 | | shAvailable, updateSHistory, updateGHistory, equalUri)); |
11276 | | |
11277 | | if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) { |
11278 | | // XXX mCurrentURI can be changed from any caller regardless what actual |
11279 | | // loaded document is, so testing mCurrentURI isn't really a reliable way. |
11280 | | // Session restore is one example which changes current URI in order to |
11281 | | // show address before loading. See bug 1301399. |
11282 | | NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), |
11283 | | "no SHEntry for a non-transient viewer?"); |
11284 | | } |
11285 | | #endif |
11286 | |
|
11287 | 0 | /* If the url to be loaded is the same as the one already there, |
11288 | 0 | * and the original loadType is LOAD_NORMAL, LOAD_LINK, or |
11289 | 0 | * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that |
11290 | 0 | * AddToSessionHistory() won't mess with the current SHEntry and |
11291 | 0 | * if this page has any frame children, it also will be handled |
11292 | 0 | * properly. see bug 83684 |
11293 | 0 | * |
11294 | 0 | * NB: If mOSHE is null but we have a current URI, then it means |
11295 | 0 | * that we must be at the transient about:blank content viewer |
11296 | 0 | * (asserted above) and we should let the normal load continue, |
11297 | 0 | * since there's nothing to replace. |
11298 | 0 | * |
11299 | 0 | * XXX Hopefully changing the loadType at this time will not hurt |
11300 | 0 | * anywhere. The other way to take care of sequentially repeating |
11301 | 0 | * frameset pages is to add new methods to nsIDocShellTreeItem. |
11302 | 0 | * Hopefully I don't have to do that. |
11303 | 0 | */ |
11304 | 0 | if (equalUri && |
11305 | 0 | mOSHE && |
11306 | 0 | (mLoadType == LOAD_NORMAL || |
11307 | 0 | mLoadType == LOAD_LINK || |
11308 | 0 | mLoadType == LOAD_STOP_CONTENT) && |
11309 | 0 | !inputStream) { |
11310 | 0 | mLoadType = LOAD_NORMAL_REPLACE; |
11311 | 0 | } |
11312 | 0 |
|
11313 | 0 | // If this is a refresh to the currently loaded url, we don't |
11314 | 0 | // have to update session or global history. |
11315 | 0 | if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) { |
11316 | 0 | SetHistoryEntry(&mLSHE, mOSHE); |
11317 | 0 | } |
11318 | 0 |
|
11319 | 0 | /* If the user pressed shift-reload, cache will create a new cache key |
11320 | 0 | * for the page. Save the new cacheKey in Session History. |
11321 | 0 | * see bug 90098 |
11322 | 0 | */ |
11323 | 0 | if (aChannel && IsForceReloadType(aLoadType)) { |
11324 | 0 | MOZ_ASSERT(!updateSHistory || IsFrame(), |
11325 | 0 | "We shouldn't be updating session history for forced" |
11326 | 0 | " reloads unless we're in a newly created iframe!"); |
11327 | 0 |
|
11328 | 0 | nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aChannel)); |
11329 | 0 | uint32_t cacheKey = 0; |
11330 | 0 | // Get the Cache Key and store it in SH. |
11331 | 0 | if (cacheChannel) { |
11332 | 0 | cacheChannel->GetCacheKey(&cacheKey); |
11333 | 0 | } |
11334 | 0 | // If we already have a loading history entry, store the new cache key |
11335 | 0 | // in it. Otherwise, since we're doing a reload and won't be updating |
11336 | 0 | // our history entry, store the cache key in our current history entry. |
11337 | 0 | if (mLSHE) { |
11338 | 0 | mLSHE->SetCacheKey(cacheKey); |
11339 | 0 | } else if (mOSHE) { |
11340 | 0 | mOSHE->SetCacheKey(cacheKey); |
11341 | 0 | } |
11342 | 0 |
|
11343 | 0 | // Since we're force-reloading, clear all the sub frame history. |
11344 | 0 | ClearFrameHistory(mLSHE); |
11345 | 0 | ClearFrameHistory(mOSHE); |
11346 | 0 | } |
11347 | 0 |
|
11348 | 0 | // Clear subframe history on refresh. |
11349 | 0 | // XXX: history.go(0) won't go this path as aLoadType is LOAD_HISTORY in this |
11350 | 0 | // case. One should re-validate after bug 1331865 fixed. |
11351 | 0 | if (aLoadType == LOAD_REFRESH) { |
11352 | 0 | ClearFrameHistory(mLSHE); |
11353 | 0 | ClearFrameHistory(mOSHE); |
11354 | 0 | } |
11355 | 0 |
|
11356 | 0 | if (updateSHistory) { |
11357 | 0 | // Update session history if necessary... |
11358 | 0 | if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) { |
11359 | 0 | /* This is a fresh page getting loaded for the first time |
11360 | 0 | *.Create a Entry for it and add it to SH, if this is the |
11361 | 0 | * rootDocShell |
11362 | 0 | */ |
11363 | 0 | (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal, |
11364 | 0 | aPrincipalToInherit, aCloneSHChildren, |
11365 | 0 | getter_AddRefs(mLSHE)); |
11366 | 0 | } |
11367 | 0 | } else if (mSessionHistory && mLSHE && mURIResultedInDocument) { |
11368 | 0 | // Even if we don't add anything to SHistory, ensure the current index |
11369 | 0 | // points to the same SHEntry as our mLSHE. |
11370 | 0 | int32_t index = mSessionHistory->LegacySHistory()->GetRequestedIndex(); |
11371 | 0 | if (index == -1) { |
11372 | 0 | index = mSessionHistory->Index(); |
11373 | 0 | } |
11374 | 0 | nsCOMPtr<nsISHEntry> currentSH; |
11375 | 0 | mSessionHistory->LegacySHistory()->GetEntryAtIndex( |
11376 | 0 | index, getter_AddRefs(currentSH)); |
11377 | 0 | if (currentSH != mLSHE) { |
11378 | 0 | mSessionHistory->LegacySHistory()->ReplaceEntry(index, mLSHE); |
11379 | 0 | } |
11380 | 0 | } |
11381 | 0 |
|
11382 | 0 | // If this is a POST request, we do not want to include this in global |
11383 | 0 | // history. |
11384 | 0 | if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) { |
11385 | 0 | nsCOMPtr<nsIURI> previousURI; |
11386 | 0 | uint32_t previousFlags = 0; |
11387 | 0 |
|
11388 | 0 | if (aLoadType & LOAD_CMD_RELOAD) { |
11389 | 0 | // On a reload request, we don't set redirecting flags. |
11390 | 0 | previousURI = aURI; |
11391 | 0 | } else { |
11392 | 0 | ExtractLastVisit(aChannel, getter_AddRefs(previousURI), &previousFlags); |
11393 | 0 | } |
11394 | 0 |
|
11395 | 0 | // Note: We don't use |referrer| when our global history is |
11396 | 0 | // based on IHistory. |
11397 | 0 | nsCOMPtr<nsIURI> referrer; |
11398 | 0 | // Treat referrer as null if there is an error getting it. |
11399 | 0 | (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer)); |
11400 | 0 |
|
11401 | 0 | AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus); |
11402 | 0 | } |
11403 | 0 |
|
11404 | 0 | // If this was a history load or a refresh, or it was a history load but |
11405 | 0 | // later changed to LOAD_NORMAL_REPLACE due to redirection, update the index |
11406 | 0 | // in session history. |
11407 | 0 | if (rootSH && |
11408 | 0 | ((mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD)) || |
11409 | 0 | mLoadType == LOAD_NORMAL_REPLACE)) { |
11410 | 0 | mPreviousEntryIndex = rootSH->Index(); |
11411 | 0 | rootSH->LegacySHistory()->UpdateIndex(); |
11412 | 0 | mLoadedEntryIndex = rootSH->Index(); |
11413 | | #ifdef DEBUG_PAGE_CACHE |
11414 | | printf("Previous index: %d, Loaded index: %d\n\n", |
11415 | | mPreviousEntryIndex, mLoadedEntryIndex); |
11416 | | #endif |
11417 | | } |
11418 | 0 |
|
11419 | 0 | // aCloneSHChildren exactly means "we are not loading a new document". |
11420 | 0 | uint32_t locationFlags = |
11421 | 0 | aCloneSHChildren ? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0; |
11422 | 0 |
|
11423 | 0 | bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel, |
11424 | 0 | aFireOnLocationChange, |
11425 | 0 | locationFlags); |
11426 | 0 | // Make sure to store the referrer from the channel, if any |
11427 | 0 | SetupReferrerFromChannel(aChannel); |
11428 | 0 | return onLocationChangeNeeded; |
11429 | 0 | } |
11430 | | |
11431 | | bool |
11432 | | nsDocShell::OnLoadingSite(nsIChannel* aChannel, bool aFireOnLocationChange, |
11433 | | bool aAddToGlobalHistory) |
11434 | 0 | { |
11435 | 0 | nsCOMPtr<nsIURI> uri; |
11436 | 0 | // If this a redirect, use the final url (uri) |
11437 | 0 | // else use the original url |
11438 | 0 | // |
11439 | 0 | // Note that this should match what documents do (see nsDocument::Reset). |
11440 | 0 | NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); |
11441 | 0 | NS_ENSURE_TRUE(uri, false); |
11442 | 0 |
|
11443 | 0 | // Pass false for aCloneSHChildren, since we're loading a new page here. |
11444 | 0 | return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType, aFireOnLocationChange, |
11445 | 0 | aAddToGlobalHistory, false); |
11446 | 0 | } |
11447 | | |
11448 | | void |
11449 | | nsDocShell::SetReferrerURI(nsIURI* aURI) |
11450 | 0 | { |
11451 | 0 | mReferrerURI = aURI; // This assigment addrefs |
11452 | 0 | } |
11453 | | |
11454 | | void |
11455 | | nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy) |
11456 | 0 | { |
11457 | 0 | mReferrerPolicy = aReferrerPolicy; |
11458 | 0 | } |
11459 | | |
11460 | | //***************************************************************************** |
11461 | | // nsDocShell: Session History |
11462 | | //***************************************************************************** |
11463 | | |
11464 | | NS_IMETHODIMP |
11465 | | nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle, |
11466 | | const nsAString& aURL, bool aReplace, JSContext* aCx) |
11467 | 0 | { |
11468 | 0 | // Implements History.pushState and History.replaceState |
11469 | 0 |
|
11470 | 0 | // Here's what we do, roughly in the order specified by HTML5: |
11471 | 0 | // 1. Serialize aData using structured clone. |
11472 | 0 | // 2. If the third argument is present, |
11473 | 0 | // a. Resolve the url, relative to the first script's base URL |
11474 | 0 | // b. If (a) fails, raise a SECURITY_ERR |
11475 | 0 | // c. Compare the resulting absolute URL to the document's address. If |
11476 | 0 | // any part of the URLs difer other than the <path>, <query>, and |
11477 | 0 | // <fragment> components, raise a SECURITY_ERR and abort. |
11478 | 0 | // 3. If !aReplace: |
11479 | 0 | // Remove from the session history all entries after the current entry, |
11480 | 0 | // as we would after a regular navigation, and save the current |
11481 | 0 | // entry's scroll position (bug 590573). |
11482 | 0 | // 4. As apropriate, either add a state object entry to the session history |
11483 | 0 | // after the current entry with the following properties, or modify the |
11484 | 0 | // current session history entry to set |
11485 | 0 | // a. cloned data as the state object, |
11486 | 0 | // b. if the third argument was present, the absolute URL found in |
11487 | 0 | // step 2 |
11488 | 0 | // Also clear the new history entry's POST data (see bug 580069). |
11489 | 0 | // 5. If aReplace is false (i.e. we're doing a pushState instead of a |
11490 | 0 | // replaceState), notify bfcache that we've navigated to a new page. |
11491 | 0 | // 6. If the third argument is present, set the document's current address |
11492 | 0 | // to the absolute URL found in step 2. |
11493 | 0 | // |
11494 | 0 | // It's important that this function not run arbitrary scripts after step 1 |
11495 | 0 | // and before completing step 5. For example, if a script called |
11496 | 0 | // history.back() before we completed step 5, bfcache might destroy an |
11497 | 0 | // active content viewer. Since EvictOutOfRangeContentViewers at the end of |
11498 | 0 | // step 5 might run script, we can't just put a script blocker around the |
11499 | 0 | // critical section. |
11500 | 0 | // |
11501 | 0 | // Note that we completely ignore the aTitle parameter. |
11502 | 0 |
|
11503 | 0 | nsresult rv; |
11504 | 0 |
|
11505 | 0 | // Don't clobber the load type of an existing network load. |
11506 | 0 | AutoRestore<uint32_t> loadTypeResetter(mLoadType); |
11507 | 0 |
|
11508 | 0 | // pushState effectively becomes replaceState when we've started a network |
11509 | 0 | // load but haven't adopted its document yet. This mirrors what we do with |
11510 | 0 | // changes to the hash at this stage of the game. |
11511 | 0 | if (JustStartedNetworkLoad()) { |
11512 | 0 | aReplace = true; |
11513 | 0 | } |
11514 | 0 |
|
11515 | 0 | nsCOMPtr<nsIDocument> document = GetDocument(); |
11516 | 0 | NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); |
11517 | 0 |
|
11518 | 0 | // Step 1: Serialize aData using structured clone. |
11519 | 0 | nsCOMPtr<nsIStructuredCloneContainer> scContainer; |
11520 | 0 |
|
11521 | 0 | // scContainer->Init might cause arbitrary JS to run, and this code might |
11522 | 0 | // navigate the page we're on, potentially to a different origin! (bug |
11523 | 0 | // 634834) To protect against this, we abort if our principal changes due |
11524 | 0 | // to the InitFromJSVal() call. |
11525 | 0 | { |
11526 | 0 | nsCOMPtr<nsIDocument> origDocument = GetDocument(); |
11527 | 0 | if (!origDocument) { |
11528 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
11529 | 0 | } |
11530 | 0 | nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal(); |
11531 | 0 |
|
11532 | 0 | scContainer = new nsStructuredCloneContainer(); |
11533 | 0 | rv = scContainer->InitFromJSVal(aData, aCx); |
11534 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11535 | 0 |
|
11536 | 0 | nsCOMPtr<nsIDocument> newDocument = GetDocument(); |
11537 | 0 | if (!newDocument) { |
11538 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
11539 | 0 | } |
11540 | 0 | nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal(); |
11541 | 0 |
|
11542 | 0 | bool principalsEqual = false; |
11543 | 0 | origPrincipal->Equals(newPrincipal, &principalsEqual); |
11544 | 0 | NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR); |
11545 | 0 | } |
11546 | 0 |
|
11547 | 0 | // Check that the state object isn't too long. |
11548 | 0 | // Default max length: 640k bytes. |
11549 | 0 | int32_t maxStateObjSize = |
11550 | 0 | Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000); |
11551 | 0 | if (maxStateObjSize < 0) { |
11552 | 0 | maxStateObjSize = 0; |
11553 | 0 | } |
11554 | 0 |
|
11555 | 0 | uint64_t scSize; |
11556 | 0 | rv = scContainer->GetSerializedNBytes(&scSize); |
11557 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11558 | 0 |
|
11559 | 0 | NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, NS_ERROR_ILLEGAL_VALUE); |
11560 | 0 |
|
11561 | 0 | // Step 2: Resolve aURL |
11562 | 0 | bool equalURIs = true; |
11563 | 0 | nsCOMPtr<nsIURI> currentURI; |
11564 | 0 | if (sURIFixup && mCurrentURI) { |
11565 | 0 | rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(currentURI)); |
11566 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11567 | 0 | } else { |
11568 | 0 | currentURI = mCurrentURI; |
11569 | 0 | } |
11570 | 0 | nsCOMPtr<nsIURI> oldURI = currentURI; |
11571 | 0 | nsCOMPtr<nsIURI> newURI; |
11572 | 0 | if (aURL.Length() == 0) { |
11573 | 0 | newURI = currentURI; |
11574 | 0 | } else { |
11575 | 0 | // 2a: Resolve aURL relative to mURI |
11576 | 0 |
|
11577 | 0 | nsIURI* docBaseURI = document->GetDocBaseURI(); |
11578 | 0 | if (!docBaseURI) { |
11579 | 0 | return NS_ERROR_FAILURE; |
11580 | 0 | } |
11581 | 0 | |
11582 | 0 | nsAutoCString spec; |
11583 | 0 | docBaseURI->GetSpec(spec); |
11584 | 0 |
|
11585 | 0 | rv = NS_NewURI(getter_AddRefs(newURI), aURL, |
11586 | 0 | document->GetDocumentCharacterSet(), docBaseURI); |
11587 | 0 |
|
11588 | 0 | // 2b: If 2a fails, raise a SECURITY_ERR |
11589 | 0 | if (NS_FAILED(rv)) { |
11590 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
11591 | 0 | } |
11592 | 0 | |
11593 | 0 | // 2c: Same-origin check. |
11594 | 0 | if (!nsContentUtils::URIIsLocalFile(newURI)) { |
11595 | 0 | // In addition to checking that the security manager says that |
11596 | 0 | // the new URI has the same origin as our current URI, we also |
11597 | 0 | // check that the two URIs have the same userpass. (The |
11598 | 0 | // security manager says that |http://foo.com| and |
11599 | 0 | // |http://me@foo.com| have the same origin.) currentURI |
11600 | 0 | // won't contain the password part of the userpass, so this |
11601 | 0 | // means that it's never valid to specify a password in a |
11602 | 0 | // pushState or replaceState URI. |
11603 | 0 |
|
11604 | 0 | nsCOMPtr<nsIScriptSecurityManager> secMan = |
11605 | 0 | do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
11606 | 0 | NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE); |
11607 | 0 |
|
11608 | 0 | // It's very important that we check that newURI is of the same |
11609 | 0 | // origin as currentURI, not docBaseURI, because a page can |
11610 | 0 | // set docBaseURI arbitrarily to any domain. |
11611 | 0 | nsAutoCString currentUserPass, newUserPass; |
11612 | 0 | NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass), |
11613 | 0 | NS_ERROR_FAILURE); |
11614 | 0 | NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), NS_ERROR_FAILURE); |
11615 | 0 | bool isPrivateWin = |
11616 | 0 | document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0; |
11617 | 0 | if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, newURI, true, isPrivateWin)) || |
11618 | 0 | !currentUserPass.Equals(newUserPass)) { |
11619 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
11620 | 0 | } |
11621 | 0 | } else { |
11622 | 0 | // It's a file:// URI |
11623 | 0 | nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj = |
11624 | 0 | do_QueryInterface(document); |
11625 | 0 |
|
11626 | 0 | if (!docScriptObj) { |
11627 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
11628 | 0 | } |
11629 | 0 | |
11630 | 0 | nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal(); |
11631 | 0 |
|
11632 | 0 | if (!principal || |
11633 | 0 | NS_FAILED(principal->CheckMayLoad(newURI, true, false))) { |
11634 | 0 | return NS_ERROR_DOM_SECURITY_ERR; |
11635 | 0 | } |
11636 | 0 | } |
11637 | 0 | |
11638 | 0 | if (currentURI) { |
11639 | 0 | currentURI->Equals(newURI, &equalURIs); |
11640 | 0 | } else { |
11641 | 0 | equalURIs = false; |
11642 | 0 | } |
11643 | 0 |
|
11644 | 0 | } // end of same-origin check |
11645 | 0 |
|
11646 | 0 | // Step 3: Create a new entry in the session history. This will erase |
11647 | 0 | // all SHEntries after the new entry and make this entry the current |
11648 | 0 | // one. This operation may modify mOSHE, which we need later, so we |
11649 | 0 | // keep a reference here. |
11650 | 0 | NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE); |
11651 | 0 | nsCOMPtr<nsISHEntry> oldOSHE = mOSHE; |
11652 | 0 |
|
11653 | 0 | mLoadType = LOAD_PUSHSTATE; |
11654 | 0 |
|
11655 | 0 | nsCOMPtr<nsISHEntry> newSHEntry; |
11656 | 0 | if (!aReplace) { |
11657 | 0 | // Save the current scroll position (bug 590573). |
11658 | 0 | nscoord cx = 0, cy = 0; |
11659 | 0 | GetCurScrollPos(ScrollOrientation_X, &cx); |
11660 | 0 | GetCurScrollPos(ScrollOrientation_Y, &cy); |
11661 | 0 | mOSHE->SetScrollPosition(cx, cy); |
11662 | 0 |
|
11663 | 0 | bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual(); |
11664 | 0 |
|
11665 | 0 | // Since we're not changing which page we have loaded, pass |
11666 | 0 | // true for aCloneChildren. |
11667 | 0 | rv = AddToSessionHistory(newURI, nullptr, |
11668 | 0 | document->NodePrincipal(), // triggeringPrincipal |
11669 | 0 | nullptr, true, |
11670 | 0 | getter_AddRefs(newSHEntry)); |
11671 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
11672 | 0 |
|
11673 | 0 | NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE); |
11674 | 0 |
|
11675 | 0 | // Session history entries created by pushState inherit scroll restoration |
11676 | 0 | // mode from the current entry. |
11677 | 0 | newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual); |
11678 | 0 |
|
11679 | 0 | // Link the new SHEntry to the old SHEntry's BFCache entry, since the |
11680 | 0 | // two entries correspond to the same document. |
11681 | 0 | NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE); |
11682 | 0 |
|
11683 | 0 | // Set the new SHEntry's title (bug 655273). |
11684 | 0 | nsString title; |
11685 | 0 | mOSHE->GetTitle(title); |
11686 | 0 | newSHEntry->SetTitle(title); |
11687 | 0 |
|
11688 | 0 | // AddToSessionHistory may not modify mOSHE. In case it doesn't, |
11689 | 0 | // we'll just set mOSHE here. |
11690 | 0 | mOSHE = newSHEntry; |
11691 | 0 |
|
11692 | 0 | } else { |
11693 | 0 | newSHEntry = mOSHE; |
11694 | 0 | newSHEntry->SetURI(newURI); |
11695 | 0 | newSHEntry->SetOriginalURI(newURI); |
11696 | 0 | newSHEntry->SetLoadReplace(false); |
11697 | 0 | } |
11698 | 0 |
|
11699 | 0 | // Step 4: Modify new/original session history entry and clear its POST |
11700 | 0 | // data, if there is any. |
11701 | 0 | newSHEntry->SetStateData(scContainer); |
11702 | 0 | newSHEntry->SetPostData(nullptr); |
11703 | 0 |
|
11704 | 0 | // If this push/replaceState changed the document's current URI and the new |
11705 | 0 | // URI differs from the old URI in more than the hash, or if the old |
11706 | 0 | // SHEntry's URI was modified in this way by a push/replaceState call |
11707 | 0 | // set URIWasModified to true for the current SHEntry (bug 669671). |
11708 | 0 | bool sameExceptHashes = true; |
11709 | 0 | newURI->EqualsExceptRef(currentURI, &sameExceptHashes); |
11710 | 0 | bool oldURIWasModified = oldOSHE->GetURIWasModified(); |
11711 | 0 | newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified); |
11712 | 0 |
|
11713 | 0 | // Step 5: If aReplace is false, indicating that we're doing a pushState |
11714 | 0 | // rather than a replaceState, notify bfcache that we've added a page to |
11715 | 0 | // the history so it can evict content viewers if appropriate. Otherwise |
11716 | 0 | // call ReplaceEntry so that we notify nsIHistoryListeners that an entry |
11717 | 0 | // was replaced. |
11718 | 0 | RefPtr<ChildSHistory> rootSH = GetRootSessionHistory(); |
11719 | 0 | NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED); |
11720 | 0 |
|
11721 | 0 | if (!aReplace) { |
11722 | 0 | int32_t curIndex = rootSH->Index(); |
11723 | 0 | if (curIndex > -1) { |
11724 | 0 | rootSH->LegacySHistory()->EvictOutOfRangeContentViewers(curIndex); |
11725 | 0 | } |
11726 | 0 | } else { |
11727 | 0 | nsCOMPtr<nsISHEntry> rootSHEntry = nsSHistory::GetRootSHEntry(newSHEntry); |
11728 | 0 |
|
11729 | 0 | int32_t index = rootSH->LegacySHistory()->GetIndexOfEntry(rootSHEntry); |
11730 | 0 | if (index > -1) { |
11731 | 0 | rootSH->LegacySHistory()->ReplaceEntry(index, rootSHEntry); |
11732 | 0 | } |
11733 | 0 | } |
11734 | 0 |
|
11735 | 0 | // Step 6: If the document's URI changed, update document's URI and update |
11736 | 0 | // global history. |
11737 | 0 | // |
11738 | 0 | // We need to call FireOnLocationChange so that the browser's address bar |
11739 | 0 | // gets updated and the back button is enabled, but we only need to |
11740 | 0 | // explicitly call FireOnLocationChange if we're not calling SetCurrentURI, |
11741 | 0 | // since SetCurrentURI will call FireOnLocationChange for us. |
11742 | 0 | // |
11743 | 0 | // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass |
11744 | 0 | // nullptr for aRequest param to FireOnLocationChange(...). Such an update |
11745 | 0 | // notification is allowed only when we know docshell is not loading a new |
11746 | 0 | // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise, |
11747 | 0 | // FireOnLocationChange(...) breaks security UI. |
11748 | 0 | // |
11749 | 0 | // If the docshell is shutting down, don't update the document URI, as we |
11750 | 0 | // can't load into a docshell that is being destroyed. |
11751 | 0 | if (!equalURIs && !mIsBeingDestroyed) { |
11752 | 0 | document->SetDocumentURI(newURI); |
11753 | 0 | // We can't trust SetCurrentURI to do always fire locationchange events |
11754 | 0 | // when we expect it to, so we hack around that by doing it ourselves... |
11755 | 0 | SetCurrentURI(newURI, nullptr, false, LOCATION_CHANGE_SAME_DOCUMENT); |
11756 | 0 | if (mLoadType != LOAD_ERROR_PAGE) { |
11757 | 0 | FireDummyOnLocationChange(); |
11758 | 0 | } |
11759 | 0 |
|
11760 | 0 | AddURIVisit(newURI, oldURI, oldURI, 0); |
11761 | 0 |
|
11762 | 0 | // AddURIVisit doesn't set the title for the new URI in global history, |
11763 | 0 | // so do that here. |
11764 | 0 | UpdateGlobalHistoryTitle(newURI); |
11765 | 0 |
|
11766 | 0 | // Inform the favicon service that our old favicon applies to this new |
11767 | 0 | // URI. |
11768 | 0 | CopyFavicon(oldURI, newURI, document->NodePrincipal(), UsePrivateBrowsing()); |
11769 | 0 | } else { |
11770 | 0 | FireDummyOnLocationChange(); |
11771 | 0 | } |
11772 | 0 | document->SetStateObject(scContainer); |
11773 | 0 |
|
11774 | 0 | return NS_OK; |
11775 | 0 | } |
11776 | | |
11777 | | NS_IMETHODIMP |
11778 | | nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual) |
11779 | 0 | { |
11780 | 0 | *aIsManual = false; |
11781 | 0 | if (mOSHE) { |
11782 | 0 | *aIsManual = mOSHE->GetScrollRestorationIsManual(); |
11783 | 0 | } |
11784 | 0 |
|
11785 | 0 | return NS_OK; |
11786 | 0 | } |
11787 | | |
11788 | | NS_IMETHODIMP |
11789 | | nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual) |
11790 | 0 | { |
11791 | 0 | if (mOSHE) { |
11792 | 0 | mOSHE->SetScrollRestorationIsManual(aIsManual); |
11793 | 0 | } |
11794 | 0 |
|
11795 | 0 | return NS_OK; |
11796 | 0 | } |
11797 | | |
11798 | | bool |
11799 | | nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel) |
11800 | 0 | { |
11801 | 0 | // I believe none of the about: urls should go in the history. But then |
11802 | 0 | // that could just be me... If the intent is only deny about:blank then we |
11803 | 0 | // should just do a spec compare, rather than two gets of the scheme and |
11804 | 0 | // then the path. -Gagan |
11805 | 0 | nsresult rv; |
11806 | 0 | nsAutoCString buf; |
11807 | 0 |
|
11808 | 0 | rv = aURI->GetScheme(buf); |
11809 | 0 | if (NS_FAILED(rv)) { |
11810 | 0 | return false; |
11811 | 0 | } |
11812 | 0 | |
11813 | 0 | if (buf.EqualsLiteral("about")) { |
11814 | 0 | rv = aURI->GetPathQueryRef(buf); |
11815 | 0 | if (NS_FAILED(rv)) { |
11816 | 0 | return false; |
11817 | 0 | } |
11818 | 0 | |
11819 | 0 | if (buf.EqualsLiteral("blank")) { |
11820 | 0 | return false; |
11821 | 0 | } |
11822 | 0 | // We only want to add about:newtab if it's not privileged: |
11823 | 0 | if (buf.EqualsLiteral("newtab")) { |
11824 | 0 | NS_ENSURE_TRUE(aChannel, false); |
11825 | 0 | nsCOMPtr<nsIPrincipal> resultPrincipal; |
11826 | 0 | rv = nsContentUtils::GetSecurityManager()-> |
11827 | 0 | GetChannelResultPrincipal(aChannel, |
11828 | 0 | getter_AddRefs(resultPrincipal)); |
11829 | 0 | NS_ENSURE_SUCCESS(rv, false); |
11830 | 0 | return !nsContentUtils::IsSystemPrincipal(resultPrincipal); |
11831 | 0 | } |
11832 | 0 | } |
11833 | 0 | |
11834 | 0 | return true; |
11835 | 0 | } |
11836 | | |
11837 | | nsresult |
11838 | | nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel, |
11839 | | nsIPrincipal* aTriggeringPrincipal, |
11840 | | nsIPrincipal* aPrincipalToInherit, |
11841 | | bool aCloneChildren, |
11842 | | nsISHEntry** aNewEntry) |
11843 | 0 | { |
11844 | 0 | MOZ_ASSERT(aURI, "uri is null"); |
11845 | 0 | MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set"); |
11846 | 0 |
|
11847 | | #if defined(DEBUG) |
11848 | | if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) { |
11849 | | nsAutoCString chanName; |
11850 | | if (aChannel) { |
11851 | | aChannel->GetName(chanName); |
11852 | | } else { |
11853 | | chanName.AssignLiteral("<no channel>"); |
11854 | | } |
11855 | | |
11856 | | MOZ_LOG(gDocShellLog, LogLevel::Debug, |
11857 | | ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", |
11858 | | this, aURI->GetSpecOrDefault().get(), chanName.get())); |
11859 | | } |
11860 | | #endif |
11861 | |
|
11862 | 0 | nsresult rv = NS_OK; |
11863 | 0 | nsCOMPtr<nsISHEntry> entry; |
11864 | 0 |
|
11865 | 0 | // Get a handle to the root docshell |
11866 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
11867 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(root)); |
11868 | 0 | /* |
11869 | 0 | * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use |
11870 | 0 | * the existing SH entry in the page and replace the url and |
11871 | 0 | * other vitalities. |
11872 | 0 | */ |
11873 | 0 | if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) && |
11874 | 0 | root != static_cast<nsIDocShellTreeItem*>(this)) { |
11875 | 0 | // This is a subframe |
11876 | 0 | entry = mOSHE; |
11877 | 0 | if (entry) { |
11878 | 0 | int32_t childCount = entry->GetChildCount(); |
11879 | 0 | // Remove all children of this entry |
11880 | 0 | for (int32_t i = childCount - 1; i >= 0; i--) { |
11881 | 0 | nsCOMPtr<nsISHEntry> child; |
11882 | 0 | entry->GetChildAt(i, getter_AddRefs(child)); |
11883 | 0 | entry->RemoveChild(child); |
11884 | 0 | } |
11885 | 0 | entry->AbandonBFCacheEntry(); |
11886 | 0 | } |
11887 | 0 | } |
11888 | 0 |
|
11889 | 0 | // Create a new entry if necessary. |
11890 | 0 | if (!entry) { |
11891 | 0 | entry = do_CreateInstance(NS_SHENTRY_CONTRACTID); |
11892 | 0 |
|
11893 | 0 | if (!entry) { |
11894 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
11895 | 0 | } |
11896 | 0 | } |
11897 | 0 | |
11898 | 0 | // Get the post data & referrer |
11899 | 0 | nsCOMPtr<nsIInputStream> inputStream; |
11900 | 0 | nsCOMPtr<nsIURI> originalURI; |
11901 | 0 | nsCOMPtr<nsIURI> resultPrincipalURI; |
11902 | 0 | bool loadReplace = false; |
11903 | 0 | nsCOMPtr<nsIURI> referrerURI; |
11904 | 0 | uint32_t referrerPolicy = RP_Unset; |
11905 | 0 | uint32_t cacheKey = 0; |
11906 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal; |
11907 | 0 | nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit; |
11908 | 0 | bool expired = false; |
11909 | 0 | bool discardLayoutState = false; |
11910 | 0 | nsCOMPtr<nsICacheInfoChannel> cacheChannel; |
11911 | 0 | if (aChannel) { |
11912 | 0 | cacheChannel = do_QueryInterface(aChannel); |
11913 | 0 |
|
11914 | 0 | /* If there is a caching channel, get the Cache Key and store it |
11915 | 0 | * in SH. |
11916 | 0 | */ |
11917 | 0 | if (cacheChannel) { |
11918 | 0 | cacheChannel->GetCacheKey(&cacheKey); |
11919 | 0 | } |
11920 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
11921 | 0 |
|
11922 | 0 | // Check if the httpChannel is hiding under a multipartChannel |
11923 | 0 | if (!httpChannel) { |
11924 | 0 | GetHttpChannel(aChannel, getter_AddRefs(httpChannel)); |
11925 | 0 | } |
11926 | 0 | if (httpChannel) { |
11927 | 0 | nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel)); |
11928 | 0 | if (uploadChannel) { |
11929 | 0 | uploadChannel->GetUploadStream(getter_AddRefs(inputStream)); |
11930 | 0 | } |
11931 | 0 | httpChannel->GetOriginalURI(getter_AddRefs(originalURI)); |
11932 | 0 | uint32_t loadFlags; |
11933 | 0 | aChannel->GetLoadFlags(&loadFlags); |
11934 | 0 | loadReplace = loadFlags & nsIChannel::LOAD_REPLACE; |
11935 | 0 | rv = httpChannel->GetReferrer(getter_AddRefs(referrerURI)); |
11936 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
11937 | 0 | rv = httpChannel->GetReferrerPolicy(&referrerPolicy); |
11938 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
11939 | 0 |
|
11940 | 0 | discardLayoutState = ShouldDiscardLayoutState(httpChannel); |
11941 | 0 | } |
11942 | 0 |
|
11943 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); |
11944 | 0 | if (loadInfo) { |
11945 | 0 | if (!triggeringPrincipal) { |
11946 | 0 | triggeringPrincipal = loadInfo->TriggeringPrincipal(); |
11947 | 0 | } |
11948 | 0 |
|
11949 | 0 | loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); |
11950 | 0 |
|
11951 | 0 | // For now keep storing just the principal in the SHEntry. |
11952 | 0 | if (!principalToInherit) { |
11953 | 0 | if (loadInfo->GetLoadingSandboxed()) { |
11954 | 0 | if (loadInfo->LoadingPrincipal()) { |
11955 | 0 | principalToInherit = NullPrincipal::CreateWithInheritedAttributes( |
11956 | 0 | loadInfo->LoadingPrincipal()); |
11957 | 0 | } else { |
11958 | 0 | // get the OriginAttributes |
11959 | 0 | OriginAttributes attrs; |
11960 | 0 | loadInfo->GetOriginAttributes(&attrs); |
11961 | 0 | principalToInherit = NullPrincipal::Create(attrs); |
11962 | 0 | } |
11963 | 0 | } else { |
11964 | 0 | principalToInherit = loadInfo->PrincipalToInherit(); |
11965 | 0 | } |
11966 | 0 | } |
11967 | 0 | } |
11968 | 0 | } |
11969 | 0 |
|
11970 | 0 | // Title is set in nsDocShell::SetTitle() |
11971 | 0 | entry->Create(aURI, // uri |
11972 | 0 | EmptyString(), // Title |
11973 | 0 | inputStream, // Post data stream |
11974 | 0 | nullptr, // LayoutHistory state |
11975 | 0 | cacheKey, // CacheKey |
11976 | 0 | mContentTypeHint, // Content-type |
11977 | 0 | triggeringPrincipal, // Channel or provided principal |
11978 | 0 | principalToInherit, |
11979 | 0 | mHistoryID, |
11980 | 0 | mDynamicallyCreated); |
11981 | 0 |
|
11982 | 0 | entry->SetOriginalURI(originalURI); |
11983 | 0 | entry->SetResultPrincipalURI(resultPrincipalURI); |
11984 | 0 | entry->SetLoadReplace(loadReplace); |
11985 | 0 | entry->SetReferrerURI(referrerURI); |
11986 | 0 | entry->SetReferrerPolicy(referrerPolicy); |
11987 | 0 | nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel); |
11988 | 0 | if (inStrmChan) { |
11989 | 0 | bool isSrcdocChannel; |
11990 | 0 | inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel); |
11991 | 0 | if (isSrcdocChannel) { |
11992 | 0 | nsAutoString srcdoc; |
11993 | 0 | inStrmChan->GetSrcdocData(srcdoc); |
11994 | 0 | entry->SetSrcdocData(srcdoc); |
11995 | 0 | nsCOMPtr<nsIURI> baseURI; |
11996 | 0 | inStrmChan->GetBaseURI(getter_AddRefs(baseURI)); |
11997 | 0 | entry->SetBaseURI(baseURI); |
11998 | 0 | } |
11999 | 0 | } |
12000 | 0 | /* If cache got a 'no-store', ask SH not to store |
12001 | 0 | * HistoryLayoutState. By default, SH will set this |
12002 | 0 | * flag to true and save HistoryLayoutState. |
12003 | 0 | */ |
12004 | 0 | if (discardLayoutState) { |
12005 | 0 | entry->SetSaveLayoutStateFlag(false); |
12006 | 0 | } |
12007 | 0 | if (cacheChannel) { |
12008 | 0 | // Check if the page has expired from cache |
12009 | 0 | uint32_t expTime = 0; |
12010 | 0 | cacheChannel->GetCacheTokenExpirationTime(&expTime); |
12011 | 0 | uint32_t now = PRTimeToSeconds(PR_Now()); |
12012 | 0 | if (expTime <= now) { |
12013 | 0 | expired = true; |
12014 | 0 | } |
12015 | 0 | } |
12016 | 0 | if (expired) { |
12017 | 0 | entry->SetExpirationStatus(true); |
12018 | 0 | } |
12019 | 0 |
|
12020 | 0 | if (root == static_cast<nsIDocShellTreeItem*>(this) && mSessionHistory) { |
12021 | 0 | // If we need to clone our children onto the new session |
12022 | 0 | // history entry, do so now. |
12023 | 0 | if (aCloneChildren && mOSHE) { |
12024 | 0 | uint32_t cloneID = mOSHE->GetID(); |
12025 | 0 | nsCOMPtr<nsISHEntry> newEntry; |
12026 | 0 | nsSHistory::CloneAndReplace(mOSHE, this, cloneID, entry, true, |
12027 | 0 | getter_AddRefs(newEntry)); |
12028 | 0 | NS_ASSERTION(entry == newEntry, |
12029 | 0 | "The new session history should be in the new entry"); |
12030 | 0 | } |
12031 | 0 |
|
12032 | 0 | // This is the root docshell |
12033 | 0 | bool addToSHistory = !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY); |
12034 | 0 | if (!addToSHistory) { |
12035 | 0 | // Replace current entry in session history; If the requested index is |
12036 | 0 | // valid, it indicates the loading was triggered by a history load, and |
12037 | 0 | // we should replace the entry at requested index instead. |
12038 | 0 | int32_t index = mSessionHistory->LegacySHistory()->GetRequestedIndex(); |
12039 | 0 | if (index == -1) { |
12040 | 0 | index = mSessionHistory->Index(); |
12041 | 0 | } |
12042 | 0 |
|
12043 | 0 | // Replace the current entry with the new entry |
12044 | 0 | if (index >= 0) { |
12045 | 0 | rv = mSessionHistory->LegacySHistory()->ReplaceEntry(index, entry); |
12046 | 0 | } else { |
12047 | 0 | // If we're trying to replace an inexistant shistory entry, append. |
12048 | 0 | addToSHistory = true; |
12049 | 0 | } |
12050 | 0 | } |
12051 | 0 |
|
12052 | 0 | if (addToSHistory) { |
12053 | 0 | // Add to session history |
12054 | 0 | mPreviousEntryIndex = mSessionHistory->Index(); |
12055 | 0 |
|
12056 | 0 | bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel); |
12057 | 0 | rv = mSessionHistory->LegacySHistory()->AddEntry(entry, shouldPersist); |
12058 | 0 | mLoadedEntryIndex = mSessionHistory->Index(); |
12059 | | #ifdef DEBUG_PAGE_CACHE |
12060 | | printf("Previous index: %d, Loaded index: %d\n\n", |
12061 | | mPreviousEntryIndex, mLoadedEntryIndex); |
12062 | | #endif |
12063 | | } |
12064 | 0 | } else { |
12065 | 0 | // This is a subframe. |
12066 | 0 | if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) { |
12067 | 0 | rv = AddChildSHEntryToParent(entry, mChildOffset, aCloneChildren); |
12068 | 0 | } |
12069 | 0 | } |
12070 | 0 |
|
12071 | 0 | // Return the new SH entry... |
12072 | 0 | if (aNewEntry) { |
12073 | 0 | *aNewEntry = nullptr; |
12074 | 0 | if (NS_SUCCEEDED(rv)) { |
12075 | 0 | entry.forget(aNewEntry); |
12076 | 0 | } |
12077 | 0 | } |
12078 | 0 |
|
12079 | 0 | return rv; |
12080 | 0 | } |
12081 | | |
12082 | | nsresult |
12083 | | nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) |
12084 | 0 | { |
12085 | 0 | if (!IsNavigationAllowed()) { |
12086 | 0 | return NS_OK; |
12087 | 0 | } |
12088 | 0 | |
12089 | 0 | NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE); |
12090 | 0 |
|
12091 | 0 | nsCOMPtr<nsIURI> uri = aEntry->GetURI(); |
12092 | 0 | nsCOMPtr<nsIURI> originalURI = aEntry->GetOriginalURI(); |
12093 | 0 | nsCOMPtr<nsIURI> resultPrincipalURI = aEntry->GetResultPrincipalURI(); |
12094 | 0 | bool loadReplace = aEntry->GetLoadReplace(); |
12095 | 0 | nsCOMPtr<nsIURI> referrerURI = aEntry->GetReferrerURI(); |
12096 | 0 | uint32_t referrerPolicy = aEntry->GetReferrerPolicy(); |
12097 | 0 | nsCOMPtr<nsIInputStream> postData = aEntry->GetPostData(); |
12098 | 0 | nsAutoCString contentType; |
12099 | 0 | aEntry->GetContentType(contentType); |
12100 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = aEntry->GetTriggeringPrincipal(); |
12101 | 0 | nsCOMPtr<nsIPrincipal> principalToInherit = aEntry->GetPrincipalToInherit(); |
12102 | 0 |
|
12103 | 0 | // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if |
12104 | 0 | // that's the only thing holding a ref to aEntry that will cause aEntry to |
12105 | 0 | // die while we're loading it. So hold a strong ref to aEntry here, just |
12106 | 0 | // in case. |
12107 | 0 | nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry); |
12108 | 0 | bool isJS; |
12109 | 0 | nsresult rv = uri->SchemeIs("javascript", &isJS); |
12110 | 0 | if (NS_FAILED(rv) || isJS) { |
12111 | 0 | // We're loading a URL that will execute script from inside asyncOpen. |
12112 | 0 | // Replace the current document with about:blank now to prevent |
12113 | 0 | // anything from the current document from leaking into any JavaScript |
12114 | 0 | // code in the URL. |
12115 | 0 | // Don't cache the presentation if we're going to just reload the |
12116 | 0 | // current entry. Caching would lead to trying to save the different |
12117 | 0 | // content viewers in the same nsISHEntry object. |
12118 | 0 | rv = CreateAboutBlankContentViewer(principalToInherit, nullptr, |
12119 | 0 | aEntry != mOSHE); |
12120 | 0 |
|
12121 | 0 | if (NS_FAILED(rv)) { |
12122 | 0 | // The creation of the intermittent about:blank content |
12123 | 0 | // viewer failed for some reason (potentially because the |
12124 | 0 | // user prevented it). Interrupt the history load. |
12125 | 0 | return NS_OK; |
12126 | 0 | } |
12127 | 0 | |
12128 | 0 | if (!triggeringPrincipal) { |
12129 | 0 | // Ensure that we have a triggeringPrincipal. Otherwise javascript: |
12130 | 0 | // URIs will pick it up from the about:blank page we just loaded, |
12131 | 0 | // and we don't really want even that in this case. |
12132 | 0 | triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this); |
12133 | 0 | } |
12134 | 0 | } |
12135 | 0 |
|
12136 | 0 | /* If there is a valid postdata *and* the user pressed |
12137 | 0 | * reload or shift-reload, take user's permission before we |
12138 | 0 | * repost the data to the server. |
12139 | 0 | */ |
12140 | 0 | if ((aLoadType & LOAD_CMD_RELOAD) && postData) { |
12141 | 0 | bool repost; |
12142 | 0 | rv = ConfirmRepost(&repost); |
12143 | 0 | if (NS_FAILED(rv)) { |
12144 | 0 | return rv; |
12145 | 0 | } |
12146 | 0 | |
12147 | 0 | // If the user pressed cancel in the dialog, return. We're done here. |
12148 | 0 | if (!repost) { |
12149 | 0 | return NS_BINDING_ABORTED; |
12150 | 0 | } |
12151 | 0 | } |
12152 | 0 | |
12153 | 0 | // Do not inherit principal from document (security-critical!); |
12154 | 0 | uint32_t flags = INTERNAL_LOAD_FLAGS_NONE; |
12155 | 0 |
|
12156 | 0 | nsAutoString srcdoc; |
12157 | 0 | nsCOMPtr<nsIURI> baseURI; |
12158 | 0 | if (aEntry->GetIsSrcdocEntry()) { |
12159 | 0 | aEntry->GetSrcdocData(srcdoc); |
12160 | 0 | baseURI = aEntry->GetBaseURI(); |
12161 | 0 | flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; |
12162 | 0 | } else { |
12163 | 0 | srcdoc = VoidString(); |
12164 | 0 | } |
12165 | 0 |
|
12166 | 0 | // If there is no valid triggeringPrincipal, we deny the load |
12167 | 0 | MOZ_ASSERT(triggeringPrincipal, "need a valid triggeringPrincipal to load from history"); |
12168 | 0 | if (!triggeringPrincipal) { |
12169 | 0 | return NS_ERROR_FAILURE; |
12170 | 0 | } |
12171 | 0 | |
12172 | 0 | // Passing nullptr as aSourceDocShell gives the same behaviour as before |
12173 | 0 | // aSourceDocShell was introduced. According to spec we should be passing |
12174 | 0 | // the source browsing context that was used when the history entry was |
12175 | 0 | // first created. bug 947716 has been created to address this issue. |
12176 | 0 | Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI; |
12177 | 0 | emplacedResultPrincipalURI.emplace(std::move(resultPrincipalURI)); |
12178 | 0 | rv = InternalLoad(uri, |
12179 | 0 | originalURI, |
12180 | 0 | emplacedResultPrincipalURI, |
12181 | 0 | false, |
12182 | 0 | loadReplace, |
12183 | 0 | referrerURI, |
12184 | 0 | referrerPolicy, |
12185 | 0 | triggeringPrincipal, |
12186 | 0 | principalToInherit, |
12187 | 0 | flags, |
12188 | 0 | EmptyString(), // No window target |
12189 | 0 | contentType.get(), // Type hint |
12190 | 0 | VoidString(), // No forced file download |
12191 | 0 | postData, // Post data stream |
12192 | 0 | nullptr, // No headers stream |
12193 | 0 | aLoadType, // Load type |
12194 | 0 | aEntry, // SHEntry |
12195 | 0 | true, |
12196 | 0 | srcdoc, |
12197 | 0 | nullptr, // Source docshell, see comment above |
12198 | 0 | baseURI, |
12199 | 0 | nullptr, // No nsIDocShell |
12200 | 0 | nullptr); // No nsIRequest |
12201 | 0 | return rv; |
12202 | 0 | } |
12203 | | |
12204 | | NS_IMETHODIMP |
12205 | | nsDocShell::GetShouldSaveLayoutState(bool* aShould) |
12206 | 0 | { |
12207 | 0 | *aShould = false; |
12208 | 0 | if (mOSHE) { |
12209 | 0 | // Don't capture historystate and save it in history |
12210 | 0 | // if the page asked not to do so. |
12211 | 0 | *aShould = mOSHE->GetSaveLayoutStateFlag(); |
12212 | 0 | } |
12213 | 0 |
|
12214 | 0 | return NS_OK; |
12215 | 0 | } |
12216 | | |
12217 | | nsresult |
12218 | | nsDocShell::PersistLayoutHistoryState() |
12219 | 0 | { |
12220 | 0 | nsresult rv = NS_OK; |
12221 | 0 |
|
12222 | 0 | if (mOSHE) { |
12223 | 0 | bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual(); |
12224 | 0 | nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
12225 | 0 | nsCOMPtr<nsILayoutHistoryState> layoutState; |
12226 | 0 | if (shell) { |
12227 | 0 | rv = shell->CaptureHistoryState(getter_AddRefs(layoutState)); |
12228 | 0 | } else if (scrollRestorationIsManual) { |
12229 | 0 | // Even if we don't have layout anymore, we may want to reset the current |
12230 | 0 | // scroll state in layout history. |
12231 | 0 | GetLayoutHistoryState(getter_AddRefs(layoutState)); |
12232 | 0 | } |
12233 | 0 |
|
12234 | 0 | if (scrollRestorationIsManual && layoutState) { |
12235 | 0 | layoutState->ResetScrollState(); |
12236 | 0 | } |
12237 | 0 | } |
12238 | 0 |
|
12239 | 0 | return rv; |
12240 | 0 | } |
12241 | | |
12242 | | void |
12243 | | nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry) |
12244 | 0 | { |
12245 | 0 | if (aOldEntry == mOSHE) { |
12246 | 0 | mOSHE = aNewEntry; |
12247 | 0 | } |
12248 | 0 |
|
12249 | 0 | if (aOldEntry == mLSHE) { |
12250 | 0 | mLSHE = aNewEntry; |
12251 | 0 | } |
12252 | 0 | } |
12253 | | |
12254 | | void |
12255 | | nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr, nsISHEntry* aEntry) |
12256 | 0 | { |
12257 | 0 | // We need to sync up the docshell and session history trees for |
12258 | 0 | // subframe navigation. If the load was in a subframe, we forward up to |
12259 | 0 | // the root docshell, which will then recursively sync up all docshells |
12260 | 0 | // to their corresponding entries in the new session history tree. |
12261 | 0 | // If we don't do this, then we can cache a content viewer on the wrong |
12262 | 0 | // cloned entry, and subsequently restore it at the wrong time. |
12263 | 0 |
|
12264 | 0 | nsISHEntry* newRootEntry = nsSHistory::GetRootSHEntry(aEntry); |
12265 | 0 | if (newRootEntry) { |
12266 | 0 | // newRootEntry is now the new root entry. |
12267 | 0 | // Find the old root entry as well. |
12268 | 0 |
|
12269 | 0 | // Need a strong ref. on |oldRootEntry| so it isn't destroyed when |
12270 | 0 | // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639). |
12271 | 0 | nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(*aPtr); |
12272 | 0 | if (oldRootEntry) { |
12273 | 0 | nsCOMPtr<nsIDocShellTreeItem> rootAsItem; |
12274 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); |
12275 | 0 | nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem); |
12276 | 0 | if (rootShell) { // if we're the root just set it, nothing to swap |
12277 | 0 | nsSHistory::SwapEntriesData data = { this, newRootEntry }; |
12278 | 0 | nsIDocShell* rootIDocShell = static_cast<nsIDocShell*>(rootShell); |
12279 | 0 | nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell); |
12280 | 0 |
|
12281 | | #ifdef DEBUG |
12282 | | nsresult rv = |
12283 | | #endif |
12284 | | nsSHistory::SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data); |
12285 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed"); |
12286 | 0 | } |
12287 | 0 | } |
12288 | 0 | } |
12289 | 0 |
|
12290 | 0 | *aPtr = aEntry; |
12291 | 0 | } |
12292 | | |
12293 | | already_AddRefed<ChildSHistory> |
12294 | | nsDocShell::GetRootSessionHistory() |
12295 | 0 | { |
12296 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
12297 | 0 | nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(root)); |
12298 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
12299 | 0 | return nullptr; |
12300 | 0 | } |
12301 | 0 | nsCOMPtr<nsIWebNavigation> webnav = do_QueryInterface(root); |
12302 | 0 | if (!webnav) { |
12303 | 0 | return nullptr; |
12304 | 0 | } |
12305 | 0 | return webnav->GetSessionHistory(); |
12306 | 0 | } |
12307 | | |
12308 | | nsresult |
12309 | | nsDocShell::GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn) |
12310 | 0 | { |
12311 | 0 | NS_ENSURE_ARG_POINTER(aReturn); |
12312 | 0 | if (!aChannel) { |
12313 | 0 | return NS_ERROR_FAILURE; |
12314 | 0 | } |
12315 | 0 | |
12316 | 0 | nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel)); |
12317 | 0 | if (multiPartChannel) { |
12318 | 0 | nsCOMPtr<nsIChannel> baseChannel; |
12319 | 0 | multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel)); |
12320 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel)); |
12321 | 0 | *aReturn = httpChannel; |
12322 | 0 | NS_IF_ADDREF(*aReturn); |
12323 | 0 | } |
12324 | 0 | return NS_OK; |
12325 | 0 | } |
12326 | | |
12327 | | bool |
12328 | | nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel) |
12329 | 0 | { |
12330 | 0 | // By default layout State will be saved. |
12331 | 0 | if (!aChannel) { |
12332 | 0 | return false; |
12333 | 0 | } |
12334 | 0 | |
12335 | 0 | // figure out if SH should be saving layout state |
12336 | 0 | bool noStore = false; |
12337 | 0 | Unused << aChannel->IsNoStoreResponse(&noStore); |
12338 | 0 | return noStore; |
12339 | 0 | } |
12340 | | |
12341 | | NS_IMETHODIMP |
12342 | | nsDocShell::GetEditor(nsIEditor** aEditor) |
12343 | 0 | { |
12344 | 0 | NS_ENSURE_ARG_POINTER(aEditor); |
12345 | 0 | RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorInternal(); |
12346 | 0 | htmlEditor.forget(aEditor); |
12347 | 0 | return NS_OK; |
12348 | 0 | } |
12349 | | |
12350 | | NS_IMETHODIMP |
12351 | | nsDocShell::SetEditor(nsIEditor* aEditor) |
12352 | 0 | { |
12353 | 0 | HTMLEditor* htmlEditor = aEditor ? aEditor->AsHTMLEditor() : nullptr; |
12354 | 0 | // If TextEditor comes, throw an error. |
12355 | 0 | if (aEditor && !htmlEditor) { |
12356 | 0 | return NS_ERROR_INVALID_ARG; |
12357 | 0 | } |
12358 | 0 | return SetHTMLEditorInternal(htmlEditor); |
12359 | 0 | } |
12360 | | |
12361 | | HTMLEditor* |
12362 | | nsDocShell::GetHTMLEditorInternal() |
12363 | 0 | { |
12364 | 0 | return mEditorData ? mEditorData->GetHTMLEditor() : nullptr; |
12365 | 0 | } |
12366 | | |
12367 | | nsresult |
12368 | | nsDocShell::SetHTMLEditorInternal(HTMLEditor* aHTMLEditor) |
12369 | 0 | { |
12370 | 0 | if (!aHTMLEditor && !mEditorData) { |
12371 | 0 | return NS_OK; |
12372 | 0 | } |
12373 | 0 | |
12374 | 0 | nsresult rv = EnsureEditorData(); |
12375 | 0 | if (NS_FAILED(rv)) { |
12376 | 0 | return rv; |
12377 | 0 | } |
12378 | 0 | |
12379 | 0 | return mEditorData->SetHTMLEditor(aHTMLEditor); |
12380 | 0 | } |
12381 | | |
12382 | | NS_IMETHODIMP |
12383 | | nsDocShell::GetEditable(bool* aEditable) |
12384 | 0 | { |
12385 | 0 | NS_ENSURE_ARG_POINTER(aEditable); |
12386 | 0 | *aEditable = mEditorData && mEditorData->GetEditable(); |
12387 | 0 | return NS_OK; |
12388 | 0 | } |
12389 | | |
12390 | | NS_IMETHODIMP |
12391 | | nsDocShell::GetHasEditingSession(bool* aHasEditingSession) |
12392 | 0 | { |
12393 | 0 | NS_ENSURE_ARG_POINTER(aHasEditingSession); |
12394 | 0 |
|
12395 | 0 | if (mEditorData) { |
12396 | 0 | nsCOMPtr<nsIEditingSession> editingSession; |
12397 | 0 | mEditorData->GetEditingSession(getter_AddRefs(editingSession)); |
12398 | 0 | *aHasEditingSession = (editingSession.get() != nullptr); |
12399 | 0 | } else { |
12400 | 0 | *aHasEditingSession = false; |
12401 | 0 | } |
12402 | 0 |
|
12403 | 0 | return NS_OK; |
12404 | 0 | } |
12405 | | |
12406 | | NS_IMETHODIMP |
12407 | | nsDocShell::MakeEditable(bool aInWaitForUriLoad) |
12408 | 0 | { |
12409 | 0 | nsresult rv = EnsureEditorData(); |
12410 | 0 | if (NS_FAILED(rv)) { |
12411 | 0 | return rv; |
12412 | 0 | } |
12413 | 0 | |
12414 | 0 | return mEditorData->MakeEditable(aInWaitForUriLoad); |
12415 | 0 | } |
12416 | | |
12417 | | bool |
12418 | | nsDocShell::ChannelIsPost(nsIChannel* aChannel) |
12419 | 0 | { |
12420 | 0 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
12421 | 0 | if (!httpChannel) { |
12422 | 0 | return false; |
12423 | 0 | } |
12424 | 0 | |
12425 | 0 | nsAutoCString method; |
12426 | 0 | Unused << httpChannel->GetRequestMethod(method); |
12427 | 0 | return method.EqualsLiteral("POST"); |
12428 | 0 | } |
12429 | | |
12430 | | void |
12431 | | nsDocShell::ExtractLastVisit(nsIChannel* aChannel, |
12432 | | nsIURI** aURI, |
12433 | | uint32_t* aChannelRedirectFlags) |
12434 | 0 | { |
12435 | 0 | nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel)); |
12436 | 0 | if (!props) { |
12437 | 0 | return; |
12438 | 0 | } |
12439 | 0 | |
12440 | 0 | nsresult rv = props->GetPropertyAsInterface( |
12441 | 0 | NS_LITERAL_STRING("docshell.previousURI"), |
12442 | 0 | NS_GET_IID(nsIURI), |
12443 | 0 | reinterpret_cast<void**>(aURI)); |
12444 | 0 |
|
12445 | 0 | if (NS_FAILED(rv)) { |
12446 | 0 | // There is no last visit for this channel, so this must be the first |
12447 | 0 | // link. Link the visit to the referrer of this request, if any. |
12448 | 0 | // Treat referrer as null if there is an error getting it. |
12449 | 0 | (void)NS_GetReferrerFromChannel(aChannel, aURI); |
12450 | 0 | } else { |
12451 | 0 | rv = props->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"), |
12452 | 0 | aChannelRedirectFlags); |
12453 | 0 |
|
12454 | 0 | NS_WARNING_ASSERTION( |
12455 | 0 | NS_SUCCEEDED(rv), |
12456 | 0 | "Could not fetch previous flags, URI will be treated like referrer"); |
12457 | 0 | } |
12458 | 0 | } |
12459 | | |
12460 | | void |
12461 | | nsDocShell::SaveLastVisit(nsIChannel* aChannel, |
12462 | | nsIURI* aURI, |
12463 | | uint32_t aChannelRedirectFlags) |
12464 | 0 | { |
12465 | 0 | nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel)); |
12466 | 0 | if (!props || !aURI) { |
12467 | 0 | return; |
12468 | 0 | } |
12469 | 0 | |
12470 | 0 | props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"), |
12471 | 0 | aURI); |
12472 | 0 | props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"), |
12473 | 0 | aChannelRedirectFlags); |
12474 | 0 | } |
12475 | | |
12476 | | void |
12477 | | nsDocShell::AddURIVisit(nsIURI* aURI, |
12478 | | nsIURI* aReferrerURI, |
12479 | | nsIURI* aPreviousURI, |
12480 | | uint32_t aChannelRedirectFlags, |
12481 | | uint32_t aResponseStatus) |
12482 | 0 | { |
12483 | 0 | MOZ_ASSERT(aURI, "Visited URI is null!"); |
12484 | 0 | MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE && |
12485 | 0 | mLoadType != LOAD_BYPASS_HISTORY, |
12486 | 0 | "Do not add error or bypass pages to global history"); |
12487 | 0 |
|
12488 | 0 | // Only content-type docshells save URI visits. Also don't do |
12489 | 0 | // anything here if we're not supposed to use global history. |
12490 | 0 | if (mItemType != typeContent || !mUseGlobalHistory || UsePrivateBrowsing()) { |
12491 | 0 | return; |
12492 | 0 | } |
12493 | 0 | |
12494 | 0 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
12495 | 0 |
|
12496 | 0 | if (history) { |
12497 | 0 | uint32_t visitURIFlags = 0; |
12498 | 0 |
|
12499 | 0 | if (!IsFrame()) { |
12500 | 0 | visitURIFlags |= IHistory::TOP_LEVEL; |
12501 | 0 | } |
12502 | 0 |
|
12503 | 0 | if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) { |
12504 | 0 | visitURIFlags |= IHistory::REDIRECT_TEMPORARY; |
12505 | 0 | } else if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) { |
12506 | 0 | visitURIFlags |= IHistory::REDIRECT_PERMANENT; |
12507 | 0 | } else { |
12508 | 0 | MOZ_ASSERT(!aChannelRedirectFlags, |
12509 | 0 | "One of REDIRECT_TEMPORARY or REDIRECT_PERMANENT must be set " |
12510 | 0 | "if any flags in aChannelRedirectFlags is set."); |
12511 | 0 | } |
12512 | 0 |
|
12513 | 0 | if (aResponseStatus >= 300 && aResponseStatus < 400) { |
12514 | 0 | visitURIFlags |= IHistory::REDIRECT_SOURCE; |
12515 | 0 | if (aResponseStatus == 301 || aResponseStatus == 308) { |
12516 | 0 | visitURIFlags |= IHistory::REDIRECT_SOURCE_PERMANENT; |
12517 | 0 | } |
12518 | 0 | } |
12519 | 0 | // Errors 400-501 and 505 are considered unrecoverable, in the sense a |
12520 | 0 | // simple retry attempt by the user is unlikely to solve them. |
12521 | 0 | // 408 is special cased, since may actually indicate a temporary |
12522 | 0 | // connection problem. |
12523 | 0 | else if (aResponseStatus != 408 && |
12524 | 0 | ((aResponseStatus >= 400 && aResponseStatus <= 501) || |
12525 | 0 | aResponseStatus == 505)) { |
12526 | 0 | visitURIFlags |= IHistory::UNRECOVERABLE_ERROR; |
12527 | 0 | } |
12528 | 0 |
|
12529 | 0 | (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags); |
12530 | 0 | } |
12531 | 0 | } |
12532 | | |
12533 | | //***************************************************************************** |
12534 | | // nsDocShell: Helper Routines |
12535 | | //***************************************************************************** |
12536 | | |
12537 | | NS_IMETHODIMP |
12538 | | nsDocShell::SetLoadType(uint32_t aLoadType) |
12539 | 0 | { |
12540 | 0 | mLoadType = aLoadType; |
12541 | 0 | return NS_OK; |
12542 | 0 | } |
12543 | | |
12544 | | NS_IMETHODIMP |
12545 | | nsDocShell::GetLoadType(uint32_t* aLoadType) |
12546 | 0 | { |
12547 | 0 | *aLoadType = mLoadType; |
12548 | 0 | return NS_OK; |
12549 | 0 | } |
12550 | | |
12551 | | nsresult |
12552 | | nsDocShell::ConfirmRepost(bool* aRepost) |
12553 | 0 | { |
12554 | 0 | nsCOMPtr<nsIPrompt> prompter; |
12555 | 0 | CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter))); |
12556 | 0 | if (!prompter) { |
12557 | 0 | return NS_ERROR_NOT_AVAILABLE; |
12558 | 0 | } |
12559 | 0 | |
12560 | 0 | nsCOMPtr<nsIStringBundleService> stringBundleService = |
12561 | 0 | mozilla::services::GetStringBundleService(); |
12562 | 0 | if (!stringBundleService) { |
12563 | 0 | return NS_ERROR_FAILURE; |
12564 | 0 | } |
12565 | 0 | |
12566 | 0 | nsCOMPtr<nsIStringBundle> appBundle; |
12567 | 0 | nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL, |
12568 | 0 | getter_AddRefs(appBundle)); |
12569 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
12570 | 0 |
|
12571 | 0 | nsCOMPtr<nsIStringBundle> brandBundle; |
12572 | 0 | rv = stringBundleService->CreateBundle(kBrandBundleURL, |
12573 | 0 | getter_AddRefs(brandBundle)); |
12574 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
12575 | 0 |
|
12576 | 0 | NS_ASSERTION(prompter && brandBundle && appBundle, |
12577 | 0 | "Unable to set up repost prompter."); |
12578 | 0 |
|
12579 | 0 | nsAutoString brandName; |
12580 | 0 | rv = brandBundle->GetStringFromName("brandShortName", brandName); |
12581 | 0 |
|
12582 | 0 | nsAutoString msgString, button0Title; |
12583 | 0 | if (NS_FAILED(rv)) { // No brand, use the generic version. |
12584 | 0 | rv = appBundle->GetStringFromName("confirmRepostPrompt", msgString); |
12585 | 0 | } else { |
12586 | 0 | // Brand available - if the app has an override file with formatting, the |
12587 | 0 | // app name will be included. Without an override, the prompt will look |
12588 | 0 | // like the generic version. |
12589 | 0 | const char16_t* formatStrings[] = { brandName.get() }; |
12590 | 0 | rv = appBundle->FormatStringFromName("confirmRepostPrompt", |
12591 | 0 | formatStrings, |
12592 | 0 | ArrayLength(formatStrings), |
12593 | 0 | msgString); |
12594 | 0 | } |
12595 | 0 | if (NS_FAILED(rv)) { |
12596 | 0 | return rv; |
12597 | 0 | } |
12598 | 0 | |
12599 | 0 | rv = appBundle->GetStringFromName("resendButton.label", button0Title); |
12600 | 0 | if (NS_FAILED(rv)) { |
12601 | 0 | return rv; |
12602 | 0 | } |
12603 | 0 | |
12604 | 0 | // Make the repost prompt tab modal to prevent malicious pages from locking |
12605 | 0 | // up the browser, see bug 1412559 for an example. |
12606 | 0 | if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompter)) { |
12607 | 0 | promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true); |
12608 | 0 | } |
12609 | 0 |
|
12610 | 0 | int32_t buttonPressed; |
12611 | 0 | // The actual value here is irrelevant, but we can't pass an invalid |
12612 | 0 | // bool through XPConnect. |
12613 | 0 | bool checkState = false; |
12614 | 0 | rv = prompter->ConfirmEx( |
12615 | 0 | nullptr, msgString.get(), |
12616 | 0 | (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) + |
12617 | 0 | (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL), |
12618 | 0 | button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed); |
12619 | 0 | if (NS_FAILED(rv)) { |
12620 | 0 | return rv; |
12621 | 0 | } |
12622 | 0 | |
12623 | 0 | *aRepost = (buttonPressed == 0); |
12624 | 0 | return NS_OK; |
12625 | 0 | } |
12626 | | |
12627 | | nsresult |
12628 | | nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt, |
12629 | | nsIStringBundle** aStringBundle) |
12630 | 0 | { |
12631 | 0 | NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt), |
12632 | 0 | NS_ERROR_FAILURE); |
12633 | 0 |
|
12634 | 0 | nsCOMPtr<nsIStringBundleService> stringBundleService = |
12635 | 0 | mozilla::services::GetStringBundleService(); |
12636 | 0 | NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE); |
12637 | 0 |
|
12638 | 0 | NS_ENSURE_SUCCESS( |
12639 | 0 | stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle), |
12640 | 0 | NS_ERROR_FAILURE); |
12641 | 0 |
|
12642 | 0 | return NS_OK; |
12643 | 0 | } |
12644 | | |
12645 | | nsIScrollableFrame* |
12646 | | nsDocShell::GetRootScrollFrame() |
12647 | 0 | { |
12648 | 0 | nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
12649 | 0 | NS_ENSURE_TRUE(shell, nullptr); |
12650 | 0 |
|
12651 | 0 | return shell->GetRootScrollFrameAsScrollable(); |
12652 | 0 | } |
12653 | | |
12654 | | nsresult |
12655 | | nsDocShell::EnsureScriptEnvironment() |
12656 | 0 | { |
12657 | 0 | if (mScriptGlobal) { |
12658 | 0 | return NS_OK; |
12659 | 0 | } |
12660 | 0 | |
12661 | 0 | if (mIsBeingDestroyed) { |
12662 | 0 | return NS_ERROR_NOT_AVAILABLE; |
12663 | 0 | } |
12664 | 0 | |
12665 | | #ifdef DEBUG |
12666 | | NS_ASSERTION(!mInEnsureScriptEnv, |
12667 | | "Infinite loop! Calling EnsureScriptEnvironment() from " |
12668 | | "within EnsureScriptEnvironment()!"); |
12669 | | |
12670 | | // Yeah, this isn't re-entrant safe, but that's ok since if we |
12671 | | // re-enter this method, we'll infinitely loop... |
12672 | | AutoRestore<bool> boolSetter(mInEnsureScriptEnv); |
12673 | | mInEnsureScriptEnv = true; |
12674 | | #endif |
12675 | | |
12676 | 0 | nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner)); |
12677 | 0 | NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE); |
12678 | 0 |
|
12679 | 0 | uint32_t chromeFlags; |
12680 | 0 | browserChrome->GetChromeFlags(&chromeFlags); |
12681 | 0 |
|
12682 | 0 | // If our window is modal and we're not opened as chrome, make |
12683 | 0 | // this window a modal content window. |
12684 | 0 | mScriptGlobal = NS_NewScriptGlobalObject(mItemType == typeChrome); |
12685 | 0 | MOZ_ASSERT(mScriptGlobal); |
12686 | 0 |
|
12687 | 0 | mScriptGlobal->SetDocShell(this); |
12688 | 0 |
|
12689 | 0 | // Ensure the script object is set up to run script. |
12690 | 0 | return mScriptGlobal->EnsureScriptEnvironment(); |
12691 | 0 | } |
12692 | | |
12693 | | nsresult |
12694 | | nsDocShell::EnsureEditorData() |
12695 | 0 | { |
12696 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
12697 | 0 |
|
12698 | 0 | bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor(); |
12699 | 0 | if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) { |
12700 | 0 | // We shouldn't recreate the editor data if it already exists, or |
12701 | 0 | // we're shutting down, or we already have a detached editor data |
12702 | 0 | // stored in the session history. We should only have one editordata |
12703 | 0 | // per docshell. |
12704 | 0 | mEditorData = new nsDocShellEditorData(this); |
12705 | 0 | } |
12706 | 0 |
|
12707 | 0 | return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE; |
12708 | 0 | } |
12709 | | |
12710 | | nsresult |
12711 | | nsDocShell::EnsureFind() |
12712 | 0 | { |
12713 | 0 | if (!mFind) { |
12714 | 0 | mFind = new nsWebBrowserFind(); |
12715 | 0 | } |
12716 | 0 |
|
12717 | 0 | // we promise that the nsIWebBrowserFind that we return has been set |
12718 | 0 | // up to point to the focused, or content window, so we have to |
12719 | 0 | // set that up each time. |
12720 | 0 |
|
12721 | 0 | nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject(); |
12722 | 0 | NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED); |
12723 | 0 |
|
12724 | 0 | // default to our window |
12725 | 0 | nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_QueryInterface(scriptGO); |
12726 | 0 | nsCOMPtr<nsPIDOMWindowOuter> windowToSearch; |
12727 | 0 | nsFocusManager::GetFocusedDescendant(ourWindow, |
12728 | 0 | nsFocusManager::eIncludeAllDescendants, |
12729 | 0 | getter_AddRefs(windowToSearch)); |
12730 | 0 |
|
12731 | 0 | nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind); |
12732 | 0 | if (!findInFrames) { |
12733 | 0 | return NS_ERROR_NO_INTERFACE; |
12734 | 0 | } |
12735 | 0 | |
12736 | 0 | nsresult rv = findInFrames->SetRootSearchFrame(ourWindow); |
12737 | 0 | if (NS_FAILED(rv)) { |
12738 | 0 | return rv; |
12739 | 0 | } |
12740 | 0 | rv = findInFrames->SetCurrentSearchFrame(windowToSearch); |
12741 | 0 | if (NS_FAILED(rv)) { |
12742 | 0 | return rv; |
12743 | 0 | } |
12744 | 0 | |
12745 | 0 | return NS_OK; |
12746 | 0 | } |
12747 | | |
12748 | | bool |
12749 | | nsDocShell::IsFrame() |
12750 | 0 | { |
12751 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
12752 | 0 | GetSameTypeParent(getter_AddRefs(parent)); |
12753 | 0 | return !!parent; |
12754 | 0 | } |
12755 | | |
12756 | | NS_IMETHODIMP |
12757 | | nsDocShell::IsBeingDestroyed(bool* aDoomed) |
12758 | 0 | { |
12759 | 0 | NS_ENSURE_ARG(aDoomed); |
12760 | 0 | *aDoomed = mIsBeingDestroyed; |
12761 | 0 | return NS_OK; |
12762 | 0 | } |
12763 | | |
12764 | | NS_IMETHODIMP |
12765 | | nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult) |
12766 | 0 | { |
12767 | 0 | NS_ENSURE_ARG(aResult); |
12768 | 0 | *aResult = mIsExecutingOnLoadHandler; |
12769 | 0 | return NS_OK; |
12770 | 0 | } |
12771 | | |
12772 | | NS_IMETHODIMP |
12773 | | nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState** aLayoutHistoryState) |
12774 | 0 | { |
12775 | 0 | if (mOSHE) { |
12776 | 0 | nsCOMPtr<nsILayoutHistoryState> state = mOSHE->GetLayoutHistoryState(); |
12777 | 0 | state.forget(aLayoutHistoryState); |
12778 | 0 | } |
12779 | 0 | return NS_OK; |
12780 | 0 | } |
12781 | | |
12782 | | NS_IMETHODIMP |
12783 | | nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState* aLayoutHistoryState) |
12784 | 0 | { |
12785 | 0 | if (mOSHE) { |
12786 | 0 | mOSHE->SetLayoutHistoryState(aLayoutHistoryState); |
12787 | 0 | } |
12788 | 0 | return NS_OK; |
12789 | 0 | } |
12790 | | |
12791 | | nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy( |
12792 | | nsIInterfaceRequestor* aRequestor) |
12793 | 0 | { |
12794 | 0 | if (aRequestor) { |
12795 | 0 | mWeakPtr = do_GetWeakReference(aRequestor); |
12796 | 0 | } |
12797 | 0 | } |
12798 | | |
12799 | | nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy() |
12800 | 0 | { |
12801 | 0 | mWeakPtr = nullptr; |
12802 | 0 | } |
12803 | | |
12804 | | NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor) |
12805 | | |
12806 | | NS_IMETHODIMP |
12807 | | nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID& aIID, |
12808 | | void** aSink) |
12809 | 0 | { |
12810 | 0 | NS_ENSURE_ARG_POINTER(aSink); |
12811 | 0 | nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr); |
12812 | 0 | if (ifReq) { |
12813 | 0 | return ifReq->GetInterface(aIID, aSink); |
12814 | 0 | } |
12815 | 0 | *aSink = nullptr; |
12816 | 0 | return NS_NOINTERFACE; |
12817 | 0 | } |
12818 | | |
12819 | | nsresult |
12820 | | nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer) |
12821 | 0 | { |
12822 | 0 | if (!aContentViewer) { |
12823 | 0 | return NS_ERROR_FAILURE; |
12824 | 0 | } |
12825 | 0 | |
12826 | 0 | nsCOMPtr<nsIURI> baseURI; |
12827 | 0 | nsresult rv = NS_ERROR_NOT_AVAILABLE; |
12828 | 0 |
|
12829 | 0 | if (sURIFixup) { |
12830 | 0 | rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(baseURI)); |
12831 | 0 | } |
12832 | 0 |
|
12833 | 0 | // Get the current document and set the base uri |
12834 | 0 | if (baseURI) { |
12835 | 0 | nsIDocument* document = aContentViewer->GetDocument(); |
12836 | 0 | if (document) { |
12837 | 0 | document->SetBaseURI(baseURI); |
12838 | 0 | } |
12839 | 0 | } |
12840 | 0 | return rv; |
12841 | 0 | } |
12842 | | |
12843 | | //***************************************************************************** |
12844 | | // nsDocShell::nsIAuthPromptProvider |
12845 | | //***************************************************************************** |
12846 | | |
12847 | | NS_IMETHODIMP |
12848 | | nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& aIID, |
12849 | | void** aResult) |
12850 | 0 | { |
12851 | 0 | // a priority prompt request will override a false mAllowAuth setting |
12852 | 0 | bool priorityPrompt = (aPromptReason == PROMPT_PROXY); |
12853 | 0 |
|
12854 | 0 | if (!mAllowAuth && !priorityPrompt) { |
12855 | 0 | return NS_ERROR_NOT_AVAILABLE; |
12856 | 0 | } |
12857 | 0 | |
12858 | 0 | // we're either allowing auth, or it's a proxy request |
12859 | 0 | nsresult rv; |
12860 | 0 | nsCOMPtr<nsIPromptFactory> wwatch = |
12861 | 0 | do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); |
12862 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
12863 | 0 |
|
12864 | 0 | rv = EnsureScriptEnvironment(); |
12865 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
12866 | 0 |
|
12867 | 0 | // Get the an auth prompter for our window so that the parenting |
12868 | 0 | // of the dialogs works as it should when using tabs. |
12869 | 0 |
|
12870 | 0 | return wwatch->GetPrompt(mScriptGlobal->AsOuter(), aIID, |
12871 | 0 | reinterpret_cast<void**>(aResult)); |
12872 | 0 | } |
12873 | | |
12874 | | //***************************************************************************** |
12875 | | // nsDocShell::nsILoadContext |
12876 | | //***************************************************************************** |
12877 | | |
12878 | | NS_IMETHODIMP |
12879 | | nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy** aWindow) |
12880 | 0 | { |
12881 | 0 | CallGetInterface(this, aWindow); |
12882 | 0 | return NS_OK; |
12883 | 0 | } |
12884 | | |
12885 | | NS_IMETHODIMP |
12886 | | nsDocShell::GetTopWindow(mozIDOMWindowProxy** aWindow) |
12887 | 0 | { |
12888 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
12889 | 0 | if (win) { |
12890 | 0 | win = win->GetTop(); |
12891 | 0 | } |
12892 | 0 | win.forget(aWindow); |
12893 | 0 | return NS_OK; |
12894 | 0 | } |
12895 | | |
12896 | | NS_IMETHODIMP |
12897 | | nsDocShell::GetTopFrameElement(Element** aElement) |
12898 | 0 | { |
12899 | 0 | *aElement = nullptr; |
12900 | 0 | nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow(); |
12901 | 0 | if (!win) { |
12902 | 0 | return NS_OK; |
12903 | 0 | } |
12904 | 0 | |
12905 | 0 | nsCOMPtr<nsPIDOMWindowOuter> top = win->GetScriptableTop(); |
12906 | 0 | NS_ENSURE_TRUE(top, NS_ERROR_FAILURE); |
12907 | 0 |
|
12908 | 0 | // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is |
12909 | 0 | // inside <iframe mozbrowser>, we want to return the iframe, not null. |
12910 | 0 | // And we want to cross the content/chrome boundary. |
12911 | 0 | RefPtr<Element> elt = top->GetFrameElementInternal(); |
12912 | 0 | elt.forget(aElement); |
12913 | 0 | return NS_OK; |
12914 | 0 | } |
12915 | | |
12916 | | NS_IMETHODIMP |
12917 | | nsDocShell::GetNestedFrameId(uint64_t* aId) |
12918 | 0 | { |
12919 | 0 | *aId = 0; |
12920 | 0 | return NS_OK; |
12921 | 0 | } |
12922 | | |
12923 | | NS_IMETHODIMP |
12924 | | nsDocShell::GetUseTrackingProtection(bool* aUseTrackingProtection) |
12925 | 0 | { |
12926 | 0 | *aUseTrackingProtection = false; |
12927 | 0 |
|
12928 | 0 | bool cbEnabled = StaticPrefs::browser_contentblocking_enabled(); |
12929 | 0 | static bool sTPEnabled = false; |
12930 | 0 | static bool sTPInPBEnabled = false; |
12931 | 0 | static bool sPrefsInit = false; |
12932 | 0 |
|
12933 | 0 | if (!sPrefsInit) { |
12934 | 0 | sPrefsInit = true; |
12935 | 0 | Preferences::AddBoolVarCache(&sTPEnabled, |
12936 | 0 | "privacy.trackingprotection.enabled", false); |
12937 | 0 | Preferences::AddBoolVarCache(&sTPInPBEnabled, |
12938 | 0 | "privacy.trackingprotection.pbmode.enabled", false); |
12939 | 0 | } |
12940 | 0 |
|
12941 | 0 | if (mUseTrackingProtection || (cbEnabled && sTPEnabled) || |
12942 | 0 | (cbEnabled && UsePrivateBrowsing() && sTPInPBEnabled)) { |
12943 | 0 | *aUseTrackingProtection = true; |
12944 | 0 | return NS_OK; |
12945 | 0 | } |
12946 | 0 | |
12947 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
12948 | 0 | if (parent) { |
12949 | 0 | return parent->GetUseTrackingProtection(aUseTrackingProtection); |
12950 | 0 | } |
12951 | 0 | |
12952 | 0 | return NS_OK; |
12953 | 0 | } |
12954 | | |
12955 | | NS_IMETHODIMP |
12956 | | nsDocShell::SetUseTrackingProtection(bool aUseTrackingProtection) |
12957 | 0 | { |
12958 | 0 | mUseTrackingProtection = aUseTrackingProtection; |
12959 | 0 | return NS_OK; |
12960 | 0 | } |
12961 | | |
12962 | | NS_IMETHODIMP |
12963 | | nsDocShell::GetIsContent(bool* aIsContent) |
12964 | 0 | { |
12965 | 0 | *aIsContent = (mItemType == typeContent); |
12966 | 0 | return NS_OK; |
12967 | 0 | } |
12968 | | |
12969 | | bool |
12970 | | nsDocShell::IsOKToLoadURI(nsIURI* aURI) |
12971 | 0 | { |
12972 | 0 | MOZ_ASSERT(aURI, "Must have a URI!"); |
12973 | 0 |
|
12974 | 0 | if (!mFiredUnloadEvent) { |
12975 | 0 | return true; |
12976 | 0 | } |
12977 | 0 | |
12978 | 0 | if (!mLoadingURI) { |
12979 | 0 | return false; |
12980 | 0 | } |
12981 | 0 | |
12982 | 0 | |
12983 | 0 | bool isPrivateWin = false; |
12984 | 0 | nsIDocument *doc = GetDocument(); |
12985 | 0 | if (doc) { |
12986 | 0 | isPrivateWin = |
12987 | 0 | doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0; |
12988 | 0 | } |
12989 | 0 |
|
12990 | 0 | nsCOMPtr<nsIScriptSecurityManager> secMan = |
12991 | 0 | do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
12992 | 0 | return secMan && |
12993 | 0 | NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false, isPrivateWin)); |
12994 | 0 | } |
12995 | | |
12996 | | // |
12997 | | // Routines for selection and clipboard |
12998 | | // |
12999 | | nsresult |
13000 | | nsDocShell::GetControllerForCommand(const char* aCommand, |
13001 | | nsIController** aResult) |
13002 | 0 | { |
13003 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
13004 | 0 | *aResult = nullptr; |
13005 | 0 |
|
13006 | 0 | NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE); |
13007 | 0 |
|
13008 | 0 | nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot(); |
13009 | 0 | NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); |
13010 | 0 |
|
13011 | 0 | return root->GetControllerForCommand(aCommand, false /* for any window */, |
13012 | 0 | aResult); |
13013 | 0 | } |
13014 | | |
13015 | | NS_IMETHODIMP |
13016 | | nsDocShell::IsCommandEnabled(const char* aCommand, bool* aResult) |
13017 | 0 | { |
13018 | 0 | NS_ENSURE_ARG_POINTER(aResult); |
13019 | 0 | *aResult = false; |
13020 | 0 |
|
13021 | 0 | nsresult rv = NS_ERROR_FAILURE; |
13022 | 0 |
|
13023 | 0 | nsCOMPtr<nsIController> controller; |
13024 | 0 | rv = GetControllerForCommand(aCommand, getter_AddRefs(controller)); |
13025 | 0 | if (controller) { |
13026 | 0 | rv = controller->IsCommandEnabled(aCommand, aResult); |
13027 | 0 | } |
13028 | 0 |
|
13029 | 0 | return rv; |
13030 | 0 | } |
13031 | | |
13032 | | NS_IMETHODIMP |
13033 | | nsDocShell::DoCommand(const char* aCommand) |
13034 | 0 | { |
13035 | 0 | nsresult rv = NS_ERROR_FAILURE; |
13036 | 0 |
|
13037 | 0 | nsCOMPtr<nsIController> controller; |
13038 | 0 | rv = GetControllerForCommand(aCommand, getter_AddRefs(controller)); |
13039 | 0 | if (controller) { |
13040 | 0 | rv = controller->DoCommand(aCommand); |
13041 | 0 | } |
13042 | 0 |
|
13043 | 0 | return rv; |
13044 | 0 | } |
13045 | | |
13046 | | NS_IMETHODIMP |
13047 | | nsDocShell::DoCommandWithParams(const char* aCommand, nsICommandParams* aParams) |
13048 | 0 | { |
13049 | 0 | nsCOMPtr<nsIController> controller; |
13050 | 0 | nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller)); |
13051 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
13052 | 0 | return rv; |
13053 | 0 | } |
13054 | 0 | |
13055 | 0 | nsCOMPtr<nsICommandController> commandController = |
13056 | 0 | do_QueryInterface(controller, &rv); |
13057 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
13058 | 0 | return rv; |
13059 | 0 | } |
13060 | 0 | |
13061 | 0 | return commandController->DoCommandWithParams(aCommand, aParams); |
13062 | 0 | } |
13063 | | |
13064 | | nsresult |
13065 | | nsDocShell::EnsureCommandHandler() |
13066 | 0 | { |
13067 | 0 | if (!mCommandManager) { |
13068 | 0 | nsCOMPtr<nsPICommandUpdater> commandUpdater = new nsCommandManager(); |
13069 | 0 |
|
13070 | 0 | nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow(); |
13071 | 0 | nsresult rv = commandUpdater->Init(domWindow); |
13072 | 0 | if (NS_SUCCEEDED(rv)) { |
13073 | 0 | mCommandManager = do_QueryInterface(commandUpdater); |
13074 | 0 | } |
13075 | 0 | } |
13076 | 0 |
|
13077 | 0 | return mCommandManager ? NS_OK : NS_ERROR_FAILURE; |
13078 | 0 | } |
13079 | | |
13080 | | // link handling |
13081 | | |
13082 | | class OnLinkClickEvent : public Runnable |
13083 | | { |
13084 | | public: |
13085 | | OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, |
13086 | | nsIURI* aURI, |
13087 | | const char16_t* aTargetSpec, |
13088 | | const nsAString& aFileName, |
13089 | | nsIInputStream* aPostDataStream, |
13090 | | nsIInputStream* aHeadersDataStream, |
13091 | | bool aNoOpenerImplied, |
13092 | | bool aIsUserTriggered, |
13093 | | bool aIsTrusted, |
13094 | | nsIPrincipal* aTriggeringPrincipal); |
13095 | | |
13096 | | NS_IMETHOD Run() override |
13097 | 0 | { |
13098 | 0 | nsAutoPopupStatePusher popupStatePusher(mPopupState); |
13099 | 0 |
|
13100 | 0 | // We need to set up an AutoJSAPI here for the following reason: When we do |
13101 | 0 | // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal |
13102 | 0 | // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode(). |
13103 | 0 | // So we need to fake things so that we don't look like native code as far |
13104 | 0 | // as LegacyIsCallerNativeCode() is concerned. |
13105 | 0 | AutoJSAPI jsapi; |
13106 | 0 | if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) { |
13107 | 0 | mHandler->OnLinkClickSync(mContent, mURI, |
13108 | 0 | mTargetSpec.get(), mFileName, |
13109 | 0 | mPostDataStream, |
13110 | 0 | mHeadersDataStream, mNoOpenerImplied, |
13111 | 0 | nullptr, nullptr, mIsUserTriggered, |
13112 | 0 | mTriggeringPrincipal); |
13113 | 0 | } |
13114 | 0 | return NS_OK; |
13115 | 0 | } |
13116 | | |
13117 | | private: |
13118 | | RefPtr<nsDocShell> mHandler; |
13119 | | nsCOMPtr<nsIURI> mURI; |
13120 | | nsString mTargetSpec; |
13121 | | nsString mFileName; |
13122 | | nsCOMPtr<nsIInputStream> mPostDataStream; |
13123 | | nsCOMPtr<nsIInputStream> mHeadersDataStream; |
13124 | | nsCOMPtr<nsIContent> mContent; |
13125 | | PopupControlState mPopupState; |
13126 | | bool mNoOpenerImplied; |
13127 | | bool mIsUserTriggered; |
13128 | | bool mIsTrusted; |
13129 | | nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; |
13130 | | }; |
13131 | | |
13132 | | OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, |
13133 | | nsIContent* aContent, |
13134 | | nsIURI* aURI, |
13135 | | const char16_t* aTargetSpec, |
13136 | | const nsAString& aFileName, |
13137 | | nsIInputStream* aPostDataStream, |
13138 | | nsIInputStream* aHeadersDataStream, |
13139 | | bool aNoOpenerImplied, |
13140 | | bool aIsUserTriggered, |
13141 | | bool aIsTrusted, |
13142 | | nsIPrincipal* aTriggeringPrincipal) |
13143 | | : mozilla::Runnable("OnLinkClickEvent") |
13144 | | , mHandler(aHandler) |
13145 | | , mURI(aURI) |
13146 | | , mTargetSpec(aTargetSpec) |
13147 | | , mFileName(aFileName) |
13148 | | , mPostDataStream(aPostDataStream) |
13149 | | , mHeadersDataStream(aHeadersDataStream) |
13150 | | , mContent(aContent) |
13151 | | , mPopupState(mHandler->mScriptGlobal->GetPopupControlState()) |
13152 | | , mNoOpenerImplied(aNoOpenerImplied) |
13153 | | , mIsUserTriggered(aIsUserTriggered) |
13154 | | , mIsTrusted(aIsTrusted) |
13155 | | , mTriggeringPrincipal(aTriggeringPrincipal) |
13156 | 0 | { |
13157 | 0 | } |
13158 | | |
13159 | | NS_IMETHODIMP |
13160 | | nsDocShell::OnLinkClick(nsIContent* aContent, |
13161 | | nsIURI* aURI, |
13162 | | const char16_t* aTargetSpec, |
13163 | | const nsAString& aFileName, |
13164 | | nsIInputStream* aPostDataStream, |
13165 | | nsIInputStream* aHeadersDataStream, |
13166 | | bool aIsUserTriggered, |
13167 | | bool aIsTrusted, |
13168 | | nsIPrincipal* aTriggeringPrincipal) |
13169 | 0 | { |
13170 | 0 | NS_ASSERTION(NS_IsMainThread(), "wrong thread"); |
13171 | 0 |
|
13172 | 0 | if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) { |
13173 | 0 | return NS_OK; |
13174 | 0 | } |
13175 | 0 | |
13176 | 0 | // On history navigation through Back/Forward buttons, don't execute |
13177 | 0 | // automatic JavaScript redirection such as |anchorElement.click()| or |
13178 | 0 | // |formElement.submit()|. |
13179 | 0 | // |
13180 | 0 | // XXX |formElement.submit()| bypasses this checkpoint because it calls |
13181 | 0 | // nsDocShell::OnLinkClickSync(...) instead. |
13182 | 0 | if (ShouldBlockLoadingForBackButton()) { |
13183 | 0 | return NS_OK; |
13184 | 0 | } |
13185 | 0 | |
13186 | 0 | if (aContent->IsEditable()) { |
13187 | 0 | return NS_OK; |
13188 | 0 | } |
13189 | 0 | |
13190 | 0 | nsresult rv = NS_ERROR_FAILURE; |
13191 | 0 | nsAutoString target; |
13192 | 0 |
|
13193 | 0 | nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner); |
13194 | 0 | bool noOpenerImplied = false; |
13195 | 0 | if (browserChrome3) { |
13196 | 0 | nsAutoString oldTarget(aTargetSpec); |
13197 | 0 | rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI, |
13198 | 0 | aContent, mIsAppTab, target); |
13199 | 0 | if (!oldTarget.Equals(target)) { |
13200 | 0 | noOpenerImplied = true; |
13201 | 0 | } |
13202 | 0 | } |
13203 | 0 |
|
13204 | 0 | if (NS_FAILED(rv)) { |
13205 | 0 | target = aTargetSpec; |
13206 | 0 | } |
13207 | 0 |
|
13208 | 0 | nsCOMPtr<nsIRunnable> ev = |
13209 | 0 | new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName, |
13210 | 0 | aPostDataStream, aHeadersDataStream, noOpenerImplied, |
13211 | 0 | aIsUserTriggered, aIsTrusted, aTriggeringPrincipal); |
13212 | 0 | return DispatchToTabGroup(TaskCategory::UI, ev.forget()); |
13213 | 0 | } |
13214 | | |
13215 | | static bool |
13216 | | IsElementAnchorOrArea(nsIContent* aContent) |
13217 | 0 | { |
13218 | 0 | // Make sure we are dealing with either an <A> or <AREA> element in the HTML |
13219 | 0 | // or XHTML namespace. |
13220 | 0 | return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area); |
13221 | 0 | } |
13222 | | |
13223 | | NS_IMETHODIMP |
13224 | | nsDocShell::OnLinkClickSync(nsIContent* aContent, |
13225 | | nsIURI* aURI, |
13226 | | const char16_t* aTargetSpec, |
13227 | | const nsAString& aFileName, |
13228 | | nsIInputStream* aPostDataStream, |
13229 | | nsIInputStream* aHeadersDataStream, |
13230 | | bool aNoOpenerImplied, |
13231 | | nsIDocShell** aDocShell, |
13232 | | nsIRequest** aRequest, |
13233 | | bool aIsUserTriggered, |
13234 | | nsIPrincipal* aTriggeringPrincipal) |
13235 | 0 | { |
13236 | 0 | // Initialize the DocShell / Request |
13237 | 0 | if (aDocShell) { |
13238 | 0 | *aDocShell = nullptr; |
13239 | 0 | } |
13240 | 0 | if (aRequest) { |
13241 | 0 | *aRequest = nullptr; |
13242 | 0 | } |
13243 | 0 |
|
13244 | 0 | if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) { |
13245 | 0 | return NS_OK; |
13246 | 0 | } |
13247 | 0 | |
13248 | 0 | // XXX When the linking node was HTMLFormElement, it is synchronous event. |
13249 | 0 | // That is, the caller of this method is not |OnLinkClickEvent::Run()| |
13250 | 0 | // but |HTMLFormElement::SubmitSubmission(...)|. |
13251 | 0 | if (aContent->IsHTMLElement(nsGkAtoms::form) && |
13252 | 0 | ShouldBlockLoadingForBackButton()) { |
13253 | 0 | return NS_OK; |
13254 | 0 | } |
13255 | 0 | |
13256 | 0 | if (aContent->IsEditable()) { |
13257 | 0 | return NS_OK; |
13258 | 0 | } |
13259 | 0 | |
13260 | 0 | { |
13261 | 0 | // defer to an external protocol handler if necessary... |
13262 | 0 | nsCOMPtr<nsIExternalProtocolService> extProtService = |
13263 | 0 | do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID); |
13264 | 0 | if (extProtService) { |
13265 | 0 | nsAutoCString scheme; |
13266 | 0 | aURI->GetScheme(scheme); |
13267 | 0 | if (!scheme.IsEmpty()) { |
13268 | 0 | // if the URL scheme does not correspond to an exposed protocol, then we |
13269 | 0 | // need to hand this link click over to the external protocol handler. |
13270 | 0 | bool isExposed; |
13271 | 0 | nsresult rv = |
13272 | 0 | extProtService->IsExposedProtocol(scheme.get(), &isExposed); |
13273 | 0 | if (NS_SUCCEEDED(rv) && !isExposed) { |
13274 | 0 | return extProtService->LoadURI(aURI, this); |
13275 | 0 | } |
13276 | 0 | } |
13277 | 0 | } |
13278 | 0 | } |
13279 | 0 | |
13280 | 0 | uint32_t flags = INTERNAL_LOAD_FLAGS_NONE; |
13281 | 0 | if (IsElementAnchorOrArea(aContent)) { |
13282 | 0 | MOZ_ASSERT(aContent->IsHTMLElement()); |
13283 | 0 | nsAutoString referrer; |
13284 | 0 | aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer); |
13285 | 0 | nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer); |
13286 | 0 | while (tok.hasMoreTokens()) { |
13287 | 0 | const nsAString& token = tok.nextToken(); |
13288 | 0 | if (token.LowerCaseEqualsLiteral("noreferrer")) { |
13289 | 0 | flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER | |
13290 | 0 | INTERNAL_LOAD_FLAGS_NO_OPENER; |
13291 | 0 | // We now have all the flags we could possibly have, so just stop. |
13292 | 0 | break; |
13293 | 0 | } |
13294 | 0 | if (token.LowerCaseEqualsLiteral("noopener")) { |
13295 | 0 | flags |= INTERNAL_LOAD_FLAGS_NO_OPENER; |
13296 | 0 | } |
13297 | 0 | } |
13298 | 0 | if (aNoOpenerImplied) { |
13299 | 0 | flags |= INTERNAL_LOAD_FLAGS_NO_OPENER; |
13300 | 0 | } |
13301 | 0 | } |
13302 | 0 |
|
13303 | 0 | // Get the owner document of the link that was clicked, this will be |
13304 | 0 | // the document that the link is in, or the last document that the |
13305 | 0 | // link was in. From that document, we'll get the URI to use as the |
13306 | 0 | // referer, since the current URI in this docshell may be a |
13307 | 0 | // new document that we're in the process of loading. |
13308 | 0 | nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc(); |
13309 | 0 | NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED); |
13310 | 0 |
|
13311 | 0 | // Now check that the refererDoc's inner window is the current inner |
13312 | 0 | // window for mScriptGlobal. If it's not, then we don't want to |
13313 | 0 | // follow this link. |
13314 | 0 | nsPIDOMWindowInner* refererInner = refererDoc->GetInnerWindow(); |
13315 | 0 | NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED); |
13316 | 0 | if (!mScriptGlobal || |
13317 | 0 | mScriptGlobal->AsOuter()->GetCurrentInnerWindow() != refererInner) { |
13318 | 0 | // We're no longer the current inner window |
13319 | 0 | return NS_OK; |
13320 | 0 | } |
13321 | 0 | |
13322 | 0 | nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI(); |
13323 | 0 | uint32_t refererPolicy = refererDoc->GetReferrerPolicy(); |
13324 | 0 |
|
13325 | 0 | // get referrer attribute from clicked link and parse it |
13326 | 0 | // if per element referrer is enabled, the element referrer overrules |
13327 | 0 | // the document wide referrer |
13328 | 0 | if (IsElementAnchorOrArea(aContent)) { |
13329 | 0 | net::ReferrerPolicy refPolEnum = |
13330 | 0 | aContent->AsElement()->GetReferrerPolicyAsEnum(); |
13331 | 0 | if (refPolEnum != RP_Unset) { |
13332 | 0 | refererPolicy = refPolEnum; |
13333 | 0 | } |
13334 | 0 | } |
13335 | 0 |
|
13336 | 0 | // referer could be null here in some odd cases, but that's ok, |
13337 | 0 | // we'll just load the link w/o sending a referer in those cases. |
13338 | 0 |
|
13339 | 0 | nsAutoString target(aTargetSpec); |
13340 | 0 |
|
13341 | 0 | // If this is an anchor element, grab its type property to use as a hint |
13342 | 0 | nsAutoString typeHint; |
13343 | 0 | RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::FromNode(aContent); |
13344 | 0 | if (anchor) { |
13345 | 0 | anchor->GetType(typeHint); |
13346 | 0 | NS_ConvertUTF16toUTF8 utf8Hint(typeHint); |
13347 | 0 | nsAutoCString type, dummy; |
13348 | 0 | NS_ParseRequestContentType(utf8Hint, type, dummy); |
13349 | 0 | CopyUTF8toUTF16(type, typeHint); |
13350 | 0 | } |
13351 | 0 |
|
13352 | 0 | // if the triggeringPrincipal is not passed explicitly, then we |
13353 | 0 | // fall back to using doc->NodePrincipal() as the triggeringPrincipal. |
13354 | 0 | nsCOMPtr<nsIPrincipal> triggeringPrincipal = |
13355 | 0 | aTriggeringPrincipal ? aTriggeringPrincipal |
13356 | 0 | : aContent->NodePrincipal(); |
13357 | 0 |
|
13358 | 0 | // Link click (or form submission) can be triggered inside an onload handler, |
13359 | 0 | // and we don't want to add history entry in this case. |
13360 | 0 | bool inOnLoadHandler = false; |
13361 | 0 | GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
13362 | 0 | uint32_t loadType = inOnLoadHandler ? LOAD_NORMAL_REPLACE : LOAD_LINK; |
13363 | 0 |
|
13364 | 0 | if (aIsUserTriggered) { |
13365 | 0 | flags |= INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED; |
13366 | 0 | } |
13367 | 0 |
|
13368 | 0 | nsresult rv = InternalLoad(aURI, // New URI |
13369 | 0 | nullptr, // Original URI |
13370 | 0 | Nothing(), // Let the protocol handler assign it |
13371 | 0 | false, |
13372 | 0 | false, // LoadReplace |
13373 | 0 | referer, // Referer URI |
13374 | 0 | refererPolicy, // Referer policy |
13375 | 0 | triggeringPrincipal, |
13376 | 0 | aContent->NodePrincipal(), |
13377 | 0 | flags, |
13378 | 0 | target, // Window target |
13379 | 0 | NS_LossyConvertUTF16toASCII(typeHint).get(), |
13380 | 0 | aFileName, // Download as file |
13381 | 0 | aPostDataStream, // Post data stream |
13382 | 0 | aHeadersDataStream, // Headers stream |
13383 | 0 | loadType, // Load type |
13384 | 0 | nullptr, // No SHEntry |
13385 | 0 | true, // first party site |
13386 | 0 | VoidString(), // No srcdoc |
13387 | 0 | this, // We are the source |
13388 | 0 | nullptr, // baseURI not needed |
13389 | 0 | aDocShell, // DocShell out-param |
13390 | 0 | aRequest); // Request out-param |
13391 | 0 | if (NS_SUCCEEDED(rv)) { |
13392 | 0 | nsPingListener::DispatchPings(this, aContent, aURI, referer, refererPolicy); |
13393 | 0 | } |
13394 | 0 | return rv; |
13395 | 0 | } |
13396 | | |
13397 | | NS_IMETHODIMP |
13398 | | nsDocShell::OnOverLink(nsIContent* aContent, |
13399 | | nsIURI* aURI, |
13400 | | const char16_t* aTargetSpec) |
13401 | 0 | { |
13402 | 0 | if (aContent->IsEditable()) { |
13403 | 0 | return NS_OK; |
13404 | 0 | } |
13405 | 0 | |
13406 | 0 | nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner); |
13407 | 0 | nsresult rv = NS_ERROR_FAILURE; |
13408 | 0 |
|
13409 | 0 | nsCOMPtr<nsIWebBrowserChrome> browserChrome; |
13410 | 0 | if (!browserChrome2) { |
13411 | 0 | browserChrome = do_GetInterface(mTreeOwner); |
13412 | 0 | if (!browserChrome) { |
13413 | 0 | return rv; |
13414 | 0 | } |
13415 | 0 | } |
13416 | 0 | |
13417 | 0 | nsAutoCString spec; |
13418 | 0 | rv = aURI->GetDisplaySpec(spec); |
13419 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
13420 | 0 |
|
13421 | 0 | NS_ConvertUTF8toUTF16 uStr(spec); |
13422 | 0 |
|
13423 | 0 | PredictorPredict(aURI, mCurrentURI, |
13424 | 0 | nsINetworkPredictor::PREDICT_LINK, |
13425 | 0 | aContent->NodePrincipal()->OriginAttributesRef(), |
13426 | 0 | nullptr); |
13427 | 0 |
|
13428 | 0 | if (browserChrome2) { |
13429 | 0 | rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK, |
13430 | 0 | uStr, aContent); |
13431 | 0 | } else { |
13432 | 0 | rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get()); |
13433 | 0 | } |
13434 | 0 | return rv; |
13435 | 0 | } |
13436 | | |
13437 | | NS_IMETHODIMP |
13438 | | nsDocShell::OnLeaveLink() |
13439 | 0 | { |
13440 | 0 | nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner)); |
13441 | 0 | nsresult rv = NS_ERROR_FAILURE; |
13442 | 0 |
|
13443 | 0 | if (browserChrome) { |
13444 | 0 | rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, |
13445 | 0 | EmptyString().get()); |
13446 | 0 | } |
13447 | 0 | return rv; |
13448 | 0 | } |
13449 | | |
13450 | | bool |
13451 | | nsDocShell::ShouldBlockLoadingForBackButton() |
13452 | 0 | { |
13453 | 0 | if (!(mLoadType & LOAD_CMD_HISTORY) || |
13454 | 0 | EventStateManager::IsHandlingUserInput() || |
13455 | 0 | !Preferences::GetBool("accessibility.blockjsredirection")) { |
13456 | 0 | return false; |
13457 | 0 | } |
13458 | 0 | |
13459 | 0 | bool canGoForward = false; |
13460 | 0 | GetCanGoForward(&canGoForward); |
13461 | 0 | return canGoForward; |
13462 | 0 | } |
13463 | | |
13464 | | bool |
13465 | | nsDocShell::PluginsAllowedInCurrentDoc() |
13466 | 0 | { |
13467 | 0 |
|
13468 | 0 | if (!mContentViewer) { |
13469 | 0 | return false; |
13470 | 0 | } |
13471 | 0 | |
13472 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
13473 | 0 | if (!doc) { |
13474 | 0 | return false; |
13475 | 0 | } |
13476 | 0 | |
13477 | 0 | return doc->GetAllowPlugins(); |
13478 | 0 | } |
13479 | | |
13480 | | //---------------------------------------------------------------------- |
13481 | | // Web Shell Services API |
13482 | | |
13483 | | // This functions is only called when a new charset is detected in loading a |
13484 | | // document. |
13485 | | nsresult |
13486 | | nsDocShell::CharsetChangeReloadDocument(const char* aCharset, int32_t aSource) |
13487 | 0 | { |
13488 | 0 | // XXX hack. keep the aCharset and aSource wait to pick it up |
13489 | 0 | nsCOMPtr<nsIContentViewer> cv; |
13490 | 0 | NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE); |
13491 | 0 | if (cv) { |
13492 | 0 | int32_t hint; |
13493 | 0 | cv->GetHintCharacterSetSource(&hint); |
13494 | 0 | if (aSource > hint) { |
13495 | 0 | nsCString charset(aCharset); |
13496 | 0 | cv->SetHintCharacterSet(charset); |
13497 | 0 | cv->SetHintCharacterSetSource(aSource); |
13498 | 0 | if (eCharsetReloadRequested != mCharsetReloadState) { |
13499 | 0 | mCharsetReloadState = eCharsetReloadRequested; |
13500 | 0 | switch (mLoadType) { |
13501 | 0 | case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
13502 | 0 | return Reload(LOAD_FLAGS_CHARSET_CHANGE | |
13503 | 0 | LOAD_FLAGS_BYPASS_CACHE | |
13504 | 0 | LOAD_FLAGS_BYPASS_PROXY); |
13505 | 0 | case LOAD_RELOAD_BYPASS_CACHE: |
13506 | 0 | return Reload(LOAD_FLAGS_CHARSET_CHANGE | |
13507 | 0 | LOAD_FLAGS_BYPASS_CACHE); |
13508 | 0 | default: |
13509 | 0 | return Reload(LOAD_FLAGS_CHARSET_CHANGE); |
13510 | 0 | } |
13511 | 0 | } |
13512 | 0 | } |
13513 | 0 | } |
13514 | 0 | // return failure if this request is not accepted due to mCharsetReloadState |
13515 | 0 | return NS_ERROR_DOCSHELL_REQUEST_REJECTED; |
13516 | 0 | } |
13517 | | |
13518 | | nsresult |
13519 | | nsDocShell::CharsetChangeStopDocumentLoad() |
13520 | 0 | { |
13521 | 0 | if (eCharsetReloadRequested != mCharsetReloadState) { |
13522 | 0 | Stop(nsIWebNavigation::STOP_ALL); |
13523 | 0 | return NS_OK; |
13524 | 0 | } |
13525 | 0 | // return failer if this request is not accepted due to mCharsetReloadState |
13526 | 0 | return NS_ERROR_DOCSHELL_REQUEST_REJECTED; |
13527 | 0 | } |
13528 | | |
13529 | | NS_IMETHODIMP |
13530 | | nsDocShell::SetIsPrinting(bool aIsPrinting) |
13531 | 0 | { |
13532 | 0 | mIsPrintingOrPP = aIsPrinting; |
13533 | 0 | return NS_OK; |
13534 | 0 | } |
13535 | | |
13536 | | NS_IMETHODIMP |
13537 | | nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview) |
13538 | 0 | { |
13539 | 0 | *aPrintPreview = nullptr; |
13540 | 0 | #if NS_PRINT_PREVIEW |
13541 | 0 | nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer); |
13542 | 0 | if (!print || !print->IsInitializedForPrintPreview()) { |
13543 | 0 | // XXX: Creating a brand new content viewer to host preview every |
13544 | 0 | // time we enter here seems overwork. We could skip ahead to where |
13545 | 0 | // we QI the mContentViewer if the current URI is either about:blank |
13546 | 0 | // or about:printpreview. |
13547 | 0 | Stop(nsIWebNavigation::STOP_ALL); |
13548 | 0 | nsCOMPtr<nsIPrincipal> principal = NullPrincipal::CreateWithInheritedAttributes(this); |
13549 | 0 | nsCOMPtr<nsIURI> uri; |
13550 | 0 | NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview")); |
13551 | 0 | nsresult rv = CreateAboutBlankContentViewer(principal, uri); |
13552 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
13553 | 0 | // Here we manually set current URI since we have just created a |
13554 | 0 | // brand new content viewer (about:blank) to host preview. |
13555 | 0 | SetCurrentURI(uri, nullptr, true, 0); |
13556 | 0 | print = do_QueryInterface(mContentViewer); |
13557 | 0 | NS_ENSURE_STATE(print); |
13558 | 0 | print->InitializeForPrintPreview(); |
13559 | 0 | } |
13560 | 0 | nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print); |
13561 | 0 | result.forget(aPrintPreview); |
13562 | 0 | return NS_OK; |
13563 | | #else |
13564 | | return NS_ERROR_NOT_IMPLEMENTED; |
13565 | | #endif |
13566 | | } |
13567 | | |
13568 | | #ifdef DEBUG |
13569 | | unsigned long nsDocShell::gNumberOfDocShells = 0; |
13570 | | #endif |
13571 | | |
13572 | | NS_IMETHODIMP |
13573 | | nsDocShell::GetCanExecuteScripts(bool* aResult) |
13574 | 0 | { |
13575 | 0 | *aResult = mCanExecuteScripts; |
13576 | 0 | return NS_OK; |
13577 | 0 | } |
13578 | | |
13579 | | /* [infallible] */ NS_IMETHODIMP |
13580 | | nsDocShell::SetFrameType(uint32_t aFrameType) |
13581 | 0 | { |
13582 | 0 | mFrameType = aFrameType; |
13583 | 0 | return NS_OK; |
13584 | 0 | } |
13585 | | |
13586 | | /* [infallible] */ NS_IMETHODIMP |
13587 | | nsDocShell::GetFrameType(uint32_t* aFrameType) |
13588 | 0 | { |
13589 | 0 | *aFrameType = mFrameType; |
13590 | 0 | return NS_OK; |
13591 | 0 | } |
13592 | | |
13593 | | /* [infallible] */ NS_IMETHODIMP |
13594 | | nsDocShell::GetIsMozBrowser(bool* aIsMozBrowser) |
13595 | 0 | { |
13596 | 0 | *aIsMozBrowser = (mFrameType == FRAME_TYPE_BROWSER); |
13597 | 0 | return NS_OK; |
13598 | 0 | } |
13599 | | |
13600 | | uint32_t |
13601 | | nsDocShell::GetInheritedFrameType() |
13602 | 0 | { |
13603 | 0 | if (mFrameType != FRAME_TYPE_REGULAR) { |
13604 | 0 | return mFrameType; |
13605 | 0 | } |
13606 | 0 | |
13607 | 0 | nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
13608 | 0 | GetSameTypeParent(getter_AddRefs(parentAsItem)); |
13609 | 0 |
|
13610 | 0 | nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem); |
13611 | 0 | if (!parent) { |
13612 | 0 | return FRAME_TYPE_REGULAR; |
13613 | 0 | } |
13614 | 0 | |
13615 | 0 | return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType(); |
13616 | 0 | } |
13617 | | |
13618 | | /* [infallible] */ NS_IMETHODIMP |
13619 | | nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement) |
13620 | 0 | { |
13621 | 0 | bool result = mFrameType == FRAME_TYPE_BROWSER && |
13622 | 0 | mOriginAttributes.mInIsolatedMozBrowser; |
13623 | 0 | *aIsIsolatedMozBrowserElement = result; |
13624 | 0 | return NS_OK; |
13625 | 0 | } |
13626 | | |
13627 | | /* [infallible] */ NS_IMETHODIMP |
13628 | | nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) |
13629 | 0 | { |
13630 | 0 | MOZ_ASSERT(!mOriginAttributes.mInIsolatedMozBrowser || |
13631 | 0 | (GetInheritedFrameType() == FRAME_TYPE_BROWSER), |
13632 | 0 | "Isolated mozbrowser should only be true inside browser frames"); |
13633 | 0 | bool result = (GetInheritedFrameType() == FRAME_TYPE_BROWSER) && |
13634 | 0 | mOriginAttributes.mInIsolatedMozBrowser; |
13635 | 0 | *aIsInIsolatedMozBrowserElement = result; |
13636 | 0 | return NS_OK; |
13637 | 0 | } |
13638 | | |
13639 | | /* [infallible] */ NS_IMETHODIMP |
13640 | | nsDocShell::GetIsInMozBrowser(bool* aIsInMozBrowser) |
13641 | 0 | { |
13642 | 0 | *aIsInMozBrowser = (GetInheritedFrameType() == FRAME_TYPE_BROWSER); |
13643 | 0 | return NS_OK; |
13644 | 0 | } |
13645 | | |
13646 | | /* [infallible] */ NS_IMETHODIMP |
13647 | | nsDocShell::GetIsTopLevelContentDocShell(bool* aIsTopLevelContentDocShell) |
13648 | 0 | { |
13649 | 0 | *aIsTopLevelContentDocShell = false; |
13650 | 0 |
|
13651 | 0 | if (mItemType == typeContent) { |
13652 | 0 | nsCOMPtr<nsIDocShellTreeItem> root; |
13653 | 0 | GetSameTypeRootTreeItem(getter_AddRefs(root)); |
13654 | 0 | *aIsTopLevelContentDocShell = root.get() == static_cast<nsIDocShellTreeItem*>(this); |
13655 | 0 | } |
13656 | 0 |
|
13657 | 0 | return NS_OK; |
13658 | 0 | } |
13659 | | |
13660 | | // Implements nsILoadContext.originAttributes |
13661 | | NS_IMETHODIMP |
13662 | | nsDocShell::GetScriptableOriginAttributes(JS::MutableHandle<JS::Value> aVal) |
13663 | 0 | { |
13664 | 0 | JSContext* cx = nsContentUtils::GetCurrentJSContext(); |
13665 | 0 | MOZ_ASSERT(cx); |
13666 | 0 |
|
13667 | 0 | return GetOriginAttributes(cx, aVal); |
13668 | 0 | } |
13669 | | |
13670 | | // Implements nsIDocShell.GetOriginAttributes() |
13671 | | NS_IMETHODIMP |
13672 | | nsDocShell::GetOriginAttributes(JSContext* aCx, |
13673 | | JS::MutableHandle<JS::Value> aVal) |
13674 | 0 | { |
13675 | 0 | bool ok = ToJSValue(aCx, mOriginAttributes, aVal); |
13676 | 0 | NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); |
13677 | 0 | return NS_OK; |
13678 | 0 | } |
13679 | | |
13680 | | bool |
13681 | | nsDocShell::CanSetOriginAttributes() |
13682 | 0 | { |
13683 | 0 | MOZ_ASSERT(mChildList.IsEmpty()); |
13684 | 0 | if (!mChildList.IsEmpty()) { |
13685 | 0 | return false; |
13686 | 0 | } |
13687 | 0 | |
13688 | 0 | // TODO: Bug 1273058 - mContentViewer should be null when setting origin |
13689 | 0 | // attributes. |
13690 | 0 | if (mContentViewer) { |
13691 | 0 | nsIDocument* doc = mContentViewer->GetDocument(); |
13692 | 0 | if (doc) { |
13693 | 0 | nsIURI* uri = doc->GetDocumentURI(); |
13694 | 0 | if (!uri) { |
13695 | 0 | return false; |
13696 | 0 | } |
13697 | 0 | nsCString uriSpec = uri->GetSpecOrDefault(); |
13698 | 0 | MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank")); |
13699 | 0 | if (!uriSpec.EqualsLiteral("about:blank")) { |
13700 | 0 | return false; |
13701 | 0 | } |
13702 | 0 | } |
13703 | 0 | } |
13704 | 0 | |
13705 | 0 | return true; |
13706 | 0 | } |
13707 | | |
13708 | | bool |
13709 | | nsDocShell::ServiceWorkerAllowedToControlWindow(nsIPrincipal* aPrincipal, |
13710 | | nsIURI* aURI) |
13711 | 0 | { |
13712 | 0 | MOZ_ASSERT(aPrincipal); |
13713 | 0 | MOZ_ASSERT(aURI); |
13714 | 0 |
|
13715 | 0 | if (UsePrivateBrowsing() || mSandboxFlags) { |
13716 | 0 | return false; |
13717 | 0 | } |
13718 | 0 | |
13719 | 0 | nsCOMPtr<nsIDocShellTreeItem> parent; |
13720 | 0 | GetSameTypeParent(getter_AddRefs(parent)); |
13721 | 0 | nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr; |
13722 | 0 | nsPIDOMWindowInner* parentInner = |
13723 | 0 | parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr; |
13724 | 0 |
|
13725 | 0 | nsContentUtils::StorageAccess storage = |
13726 | 0 | nsContentUtils::StorageAllowedForNewWindow(aPrincipal, aURI, parentInner); |
13727 | 0 |
|
13728 | 0 | return storage == nsContentUtils::StorageAccess::eAllow; |
13729 | 0 | } |
13730 | | |
13731 | | nsresult |
13732 | | nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs) |
13733 | 0 | { |
13734 | 0 | MOZ_ASSERT(!mIsBeingDestroyed); |
13735 | 0 |
|
13736 | 0 | if (!CanSetOriginAttributes()) { |
13737 | 0 | return NS_ERROR_FAILURE; |
13738 | 0 | } |
13739 | 0 | |
13740 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
13741 | 0 | mOriginAttributes = aAttrs; |
13742 | 0 |
|
13743 | 0 | bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0; |
13744 | 0 | // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId |
13745 | 0 | if (mItemType == typeChrome && isPrivate) { |
13746 | 0 | mOriginAttributes.mPrivateBrowsingId = 0; |
13747 | 0 | } |
13748 | 0 |
|
13749 | 0 | SetPrivateBrowsing(isPrivate); |
13750 | 0 | AssertOriginAttributesMatchPrivateBrowsing(); |
13751 | 0 |
|
13752 | 0 | return NS_OK; |
13753 | 0 | } |
13754 | | |
13755 | | NS_IMETHODIMP |
13756 | | nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes, |
13757 | | JSContext* aCx) |
13758 | 0 | { |
13759 | 0 | if (!aOriginAttributes.isObject()) { |
13760 | 0 | return NS_ERROR_INVALID_ARG; |
13761 | 0 | } |
13762 | 0 | |
13763 | 0 | OriginAttributes attrs; |
13764 | 0 | if (!attrs.Init(aCx, aOriginAttributes)) { |
13765 | 0 | return NS_ERROR_INVALID_ARG; |
13766 | 0 | } |
13767 | 0 | |
13768 | 0 | return SetOriginAttributes(attrs); |
13769 | 0 | } |
13770 | | |
13771 | | NS_IMETHODIMP |
13772 | | nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes, |
13773 | | JSContext* aCx) |
13774 | 0 | { |
13775 | 0 | OriginAttributes attrs; |
13776 | 0 | if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { |
13777 | 0 | return NS_ERROR_INVALID_ARG; |
13778 | 0 | } |
13779 | 0 | |
13780 | 0 | return SetOriginAttributes(attrs); |
13781 | 0 | } |
13782 | | |
13783 | | NS_IMETHODIMP |
13784 | | nsDocShell::GetAsyncPanZoomEnabled(bool* aOut) |
13785 | 0 | { |
13786 | 0 | if (nsIPresShell* presShell = GetPresShell()) { |
13787 | 0 | *aOut = presShell->AsyncPanZoomEnabled(); |
13788 | 0 | return NS_OK; |
13789 | 0 | } |
13790 | 0 | |
13791 | 0 | // If we don't have a presShell, fall back to the default platform value of |
13792 | 0 | // whether or not APZ is enabled. |
13793 | 0 | *aOut = gfxPlatform::AsyncPanZoomEnabled(); |
13794 | 0 | return NS_OK; |
13795 | 0 | } |
13796 | | |
13797 | | bool |
13798 | | nsDocShell::HasUnloadedParent() |
13799 | 0 | { |
13800 | 0 | RefPtr<nsDocShell> parent = GetParentDocshell(); |
13801 | 0 | while (parent) { |
13802 | 0 | bool inUnload = false; |
13803 | 0 | parent->GetIsInUnload(&inUnload); |
13804 | 0 | if (inUnload) { |
13805 | 0 | return true; |
13806 | 0 | } |
13807 | 0 | parent = parent->GetParentDocshell(); |
13808 | 0 | } |
13809 | 0 | return false; |
13810 | 0 | } |
13811 | | |
13812 | | void |
13813 | | nsDocShell::UpdateGlobalHistoryTitle(nsIURI* aURI) |
13814 | 0 | { |
13815 | 0 | if (mUseGlobalHistory && !UsePrivateBrowsing()) { |
13816 | 0 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
13817 | 0 | if (history) { |
13818 | 0 | history->SetURITitle(aURI, mTitle); |
13819 | 0 | } |
13820 | 0 | } |
13821 | 0 | } |
13822 | | |
13823 | | bool |
13824 | | nsDocShell::IsInvisible() |
13825 | 0 | { |
13826 | 0 | return mInvisible; |
13827 | 0 | } |
13828 | | |
13829 | | void |
13830 | | nsDocShell::SetInvisible(bool aInvisible) |
13831 | 0 | { |
13832 | 0 | mInvisible = aInvisible; |
13833 | 0 | } |
13834 | | |
13835 | | void |
13836 | | nsDocShell::SetOpener(nsITabParent* aOpener) |
13837 | 0 | { |
13838 | 0 | mOpener = do_GetWeakReference(aOpener); |
13839 | 0 | } |
13840 | | |
13841 | | nsITabParent* |
13842 | | nsDocShell::GetOpener() |
13843 | 0 | { |
13844 | 0 | nsCOMPtr<nsITabParent> opener(do_QueryReferent(mOpener)); |
13845 | 0 | return opener; |
13846 | 0 | } |
13847 | | |
13848 | | // The caller owns |aAsyncCause| here. |
13849 | | void |
13850 | | nsDocShell::NotifyJSRunToCompletionStart(const char* aReason, |
13851 | | const char16_t* aFunctionName, |
13852 | | const char16_t* aFilename, |
13853 | | const uint32_t aLineNumber, |
13854 | | JS::Handle<JS::Value> aAsyncStack, |
13855 | | const char* aAsyncCause) |
13856 | 0 | { |
13857 | 0 | // If first start, mark interval start. |
13858 | 0 | if (mJSRunToCompletionDepth == 0) { |
13859 | 0 | RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); |
13860 | 0 | if (timelines && timelines->HasConsumer(this)) { |
13861 | 0 | timelines->AddMarkerForDocShell(this, |
13862 | 0 | mozilla::MakeUnique<JavascriptTimelineMarker>( |
13863 | 0 | aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START, |
13864 | 0 | aAsyncStack, aAsyncCause)); |
13865 | 0 | } |
13866 | 0 | } |
13867 | 0 |
|
13868 | 0 | mJSRunToCompletionDepth++; |
13869 | 0 | } |
13870 | | |
13871 | | void |
13872 | | nsDocShell::NotifyJSRunToCompletionStop() |
13873 | 0 | { |
13874 | 0 | mJSRunToCompletionDepth--; |
13875 | 0 |
|
13876 | 0 | // If last stop, mark interval end. |
13877 | 0 | if (mJSRunToCompletionDepth == 0) { |
13878 | 0 | RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); |
13879 | 0 | if (timelines && timelines->HasConsumer(this)) { |
13880 | 0 | timelines->AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END); |
13881 | 0 | } |
13882 | 0 | } |
13883 | 0 | } |
13884 | | |
13885 | | void |
13886 | | nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider, |
13887 | | const nsString& aKeyword) |
13888 | 0 | { |
13889 | 0 | if (aProvider.IsEmpty()) { |
13890 | 0 | return; |
13891 | 0 | } |
13892 | 0 | |
13893 | 0 | if (XRE_IsContentProcess()) { |
13894 | 0 | dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); |
13895 | 0 | if (contentChild) { |
13896 | 0 | contentChild->SendNotifyKeywordSearchLoading(aProvider, aKeyword); |
13897 | 0 | } |
13898 | 0 | return; |
13899 | 0 | } |
13900 | 0 |
|
13901 | 0 | #ifdef MOZ_TOOLKIT_SEARCH |
13902 | 0 | nsCOMPtr<nsIBrowserSearchService> searchSvc = |
13903 | 0 | do_GetService("@mozilla.org/browser/search-service;1"); |
13904 | 0 | if (searchSvc) { |
13905 | 0 | nsCOMPtr<nsISearchEngine> searchEngine; |
13906 | 0 | searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine)); |
13907 | 0 | if (searchEngine) { |
13908 | 0 | nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService(); |
13909 | 0 | if (obsSvc) { |
13910 | 0 | // Note that "keyword-search" refers to a search via the url |
13911 | 0 | // bar, not a bookmarks keyword search. |
13912 | 0 | obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get()); |
13913 | 0 | } |
13914 | 0 | } |
13915 | 0 | } |
13916 | 0 | #endif |
13917 | 0 | } |
13918 | | |
13919 | | NS_IMETHODIMP |
13920 | | nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, nsIChannel* aChannel, |
13921 | | bool* aShouldIntercept) |
13922 | 0 | { |
13923 | 0 | return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel, |
13924 | 0 | aShouldIntercept); |
13925 | 0 | } |
13926 | | |
13927 | | NS_IMETHODIMP |
13928 | | nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel) |
13929 | 0 | { |
13930 | 0 | return mInterceptController->ChannelIntercepted(aChannel); |
13931 | 0 | } |
13932 | | |
13933 | | bool |
13934 | | nsDocShell::InFrameSwap() |
13935 | 0 | { |
13936 | 0 | RefPtr<nsDocShell> shell = this; |
13937 | 0 | do { |
13938 | 0 | if (shell->mInFrameSwap) { |
13939 | 0 | return true; |
13940 | 0 | } |
13941 | 0 | shell = shell->GetParentDocshell(); |
13942 | 0 | } while (shell); |
13943 | 0 | return false; |
13944 | 0 | } |
13945 | | |
13946 | | UniquePtr<ClientSource> |
13947 | | nsDocShell::TakeInitialClientSource() |
13948 | 0 | { |
13949 | 0 | return std::move(mInitialClientSource); |
13950 | 0 | } |
13951 | | |
13952 | | NS_IMETHODIMP |
13953 | | nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError) |
13954 | 0 | { |
13955 | 0 | if (mContentViewer) { |
13956 | 0 | nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument(); |
13957 | 0 | if (doc) { |
13958 | 0 | doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError); |
13959 | 0 | } |
13960 | 0 | } |
13961 | 0 | return NS_OK; |
13962 | 0 | } |
13963 | | |
13964 | | NS_IMETHODIMP |
13965 | | nsDocShell::GetEditingSession(nsIEditingSession** aEditSession) |
13966 | 0 | { |
13967 | 0 | if (!NS_SUCCEEDED(EnsureEditorData())) { |
13968 | 0 | return NS_ERROR_FAILURE; |
13969 | 0 | } |
13970 | 0 | |
13971 | 0 | mEditorData->GetEditingSession(aEditSession); |
13972 | 0 | return *aEditSession ? NS_OK : NS_ERROR_FAILURE; |
13973 | 0 | } |
13974 | | |
13975 | | NS_IMETHODIMP |
13976 | | nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild) |
13977 | 0 | { |
13978 | 0 | *aTabChild = GetTabChild().take(); |
13979 | 0 | return *aTabChild ? NS_OK : NS_ERROR_FAILURE; |
13980 | 0 | } |
13981 | | |
13982 | | already_AddRefed<nsITabChild> |
13983 | | nsDocShell::GetTabChild() |
13984 | 0 | { |
13985 | 0 | nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner); |
13986 | 0 | nsCOMPtr<nsITabChild> tc = do_GetInterface(owner); |
13987 | 0 | return tc.forget(); |
13988 | 0 | } |
13989 | | |
13990 | | nsICommandManager* |
13991 | | nsDocShell::GetCommandManager() |
13992 | 0 | { |
13993 | 0 | NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr); |
13994 | 0 | return mCommandManager; |
13995 | 0 | } |
13996 | | |
13997 | | NS_IMETHODIMP |
13998 | | nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult) |
13999 | 0 | { |
14000 | 0 | MOZ_ASSERT(aResult); |
14001 | 0 |
|
14002 | 0 | nsPIDOMWindowOuter* outer = GetWindow(); |
14003 | 0 | MOZ_ASSERT(outer); |
14004 | 0 |
|
14005 | 0 | // If we are not toplevel then we are not the only toplevel window in the tab |
14006 | 0 | // group. |
14007 | 0 | if (outer->GetScriptableParentOrNull()) { |
14008 | 0 | *aResult = false; |
14009 | 0 | return NS_OK; |
14010 | 0 | } |
14011 | 0 | |
14012 | 0 | // If we have any other toplevel windows in our tab group, then we are not the |
14013 | 0 | // only toplevel window in the tab group. |
14014 | 0 | nsTArray<nsPIDOMWindowOuter*> toplevelWindows = |
14015 | 0 | outer->TabGroup()->GetTopLevelWindows(); |
14016 | 0 | if (toplevelWindows.Length() > 1) { |
14017 | 0 | *aResult = false; |
14018 | 0 | return NS_OK; |
14019 | 0 | } |
14020 | 0 | MOZ_ASSERT(toplevelWindows.Length() == 1); |
14021 | 0 | MOZ_ASSERT(toplevelWindows[0] == outer); |
14022 | 0 |
|
14023 | 0 | *aResult = true; |
14024 | 0 | return NS_OK; |
14025 | 0 | } |
14026 | | |
14027 | | NS_IMETHODIMP |
14028 | | nsDocShell::GetAwaitingLargeAlloc(bool* aResult) |
14029 | 0 | { |
14030 | 0 | MOZ_ASSERT(aResult); |
14031 | 0 | nsCOMPtr<nsITabChild> tabChild = GetTabChild(); |
14032 | 0 | if (!tabChild) { |
14033 | 0 | *aResult = false; |
14034 | 0 | return NS_OK; |
14035 | 0 | } |
14036 | 0 | *aResult = static_cast<TabChild*>(tabChild.get())->IsAwaitingLargeAlloc(); |
14037 | 0 | return NS_OK; |
14038 | 0 | } |
14039 | | |
14040 | | NS_IMETHODIMP_(void) |
14041 | | nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) |
14042 | 0 | { |
14043 | 0 | aAttrs = mOriginAttributes; |
14044 | 0 | } |
14045 | | |
14046 | | HTMLEditor* |
14047 | | nsIDocShell::GetHTMLEditor() |
14048 | 0 | { |
14049 | 0 | nsDocShell* docShell = static_cast<nsDocShell*>(this); |
14050 | 0 | return docShell->GetHTMLEditorInternal(); |
14051 | 0 | } |
14052 | | |
14053 | | nsresult |
14054 | | nsIDocShell::SetHTMLEditor(HTMLEditor* aHTMLEditor) |
14055 | 0 | { |
14056 | 0 | nsDocShell* docShell = static_cast<nsDocShell*>(this); |
14057 | 0 | return docShell->SetHTMLEditorInternal(aHTMLEditor); |
14058 | 0 | } |
14059 | | |
14060 | | NS_IMETHODIMP |
14061 | | nsDocShell::GetDisplayMode(uint32_t* aDisplayMode) |
14062 | 0 | { |
14063 | 0 | NS_ENSURE_ARG_POINTER(aDisplayMode); |
14064 | 0 | *aDisplayMode = mDisplayMode; |
14065 | 0 | return NS_OK; |
14066 | 0 | } |
14067 | | |
14068 | | NS_IMETHODIMP |
14069 | | nsDocShell::SetDisplayMode(uint32_t aDisplayMode) |
14070 | 0 | { |
14071 | 0 | if (!(aDisplayMode == nsIDocShell::DISPLAY_MODE_BROWSER || |
14072 | 0 | aDisplayMode == nsIDocShell::DISPLAY_MODE_STANDALONE || |
14073 | 0 | aDisplayMode == nsIDocShell::DISPLAY_MODE_FULLSCREEN || |
14074 | 0 | aDisplayMode == nsIDocShell::DISPLAY_MODE_MINIMAL_UI)) { |
14075 | 0 | return NS_ERROR_INVALID_ARG; |
14076 | 0 | } |
14077 | 0 | |
14078 | 0 | if (aDisplayMode != mDisplayMode) { |
14079 | 0 | mDisplayMode = aDisplayMode; |
14080 | 0 |
|
14081 | 0 | RefPtr<nsPresContext> presContext; |
14082 | 0 | if (NS_SUCCEEDED(GetPresContext(getter_AddRefs(presContext)))) { |
14083 | 0 | presContext->MediaFeatureValuesChangedAllDocuments({ |
14084 | 0 | MediaFeatureChangeReason::DisplayModeChange }); |
14085 | 0 | } |
14086 | 0 | } |
14087 | 0 |
|
14088 | 0 | return NS_OK; |
14089 | 0 | } |
14090 | | |
14091 | | NS_IMETHODIMP |
14092 | | nsDocShell::SetColorMatrix(float* aMatrix, uint32_t aMatrixLen) |
14093 | 0 | { |
14094 | 0 | if (aMatrixLen == 20) { |
14095 | 0 | mColorMatrix.reset(new gfx::Matrix5x4()); |
14096 | 0 | MOZ_ASSERT(aMatrixLen * sizeof(*aMatrix) == sizeof(mColorMatrix->components)); |
14097 | 0 | memcpy(mColorMatrix->components, aMatrix, sizeof(mColorMatrix->components)); |
14098 | 0 | } else if (aMatrixLen == 0) { |
14099 | 0 | mColorMatrix.reset(); |
14100 | 0 | } else { |
14101 | 0 | return NS_ERROR_INVALID_ARG; |
14102 | 0 | } |
14103 | 0 | |
14104 | 0 | nsIPresShell* presShell = GetPresShell(); |
14105 | 0 | if (!presShell) { |
14106 | 0 | return NS_ERROR_FAILURE; |
14107 | 0 | } |
14108 | 0 | |
14109 | 0 | nsIFrame* frame = presShell->GetRootFrame(); |
14110 | 0 | if (!frame) { |
14111 | 0 | return NS_ERROR_FAILURE; |
14112 | 0 | } |
14113 | 0 | |
14114 | 0 | frame->SchedulePaint(); |
14115 | 0 |
|
14116 | 0 | return NS_OK; |
14117 | 0 | } |
14118 | | |
14119 | | NS_IMETHODIMP |
14120 | | nsDocShell::GetColorMatrix(uint32_t* aMatrixLen, float** aMatrix) |
14121 | 0 | { |
14122 | 0 | NS_ENSURE_ARG_POINTER(aMatrixLen); |
14123 | 0 | *aMatrixLen = 0; |
14124 | 0 |
|
14125 | 0 | NS_ENSURE_ARG_POINTER(aMatrix); |
14126 | 0 | *aMatrix = nullptr; |
14127 | 0 |
|
14128 | 0 | if (mColorMatrix) { |
14129 | 0 | *aMatrix = (float*)moz_xmalloc(20 * sizeof(float)); |
14130 | 0 | MOZ_ASSERT(20 * sizeof(float) == sizeof(mColorMatrix->components)); |
14131 | 0 | *aMatrixLen = 20; |
14132 | 0 | memcpy(*aMatrix, mColorMatrix->components, 20 * sizeof(float)); |
14133 | 0 | } |
14134 | 0 |
|
14135 | 0 | return NS_OK; |
14136 | 0 | } |
14137 | | |
14138 | | bool |
14139 | | nsDocShell::IsForceReloading() |
14140 | 0 | { |
14141 | 0 | return IsForceReloadType(mLoadType); |
14142 | 0 | } |
14143 | | |
14144 | | already_AddRefed<BrowsingContext> |
14145 | | nsDocShell::GetBrowsingContext() const |
14146 | 0 | { |
14147 | 0 | RefPtr<BrowsingContext> browsingContext = mBrowsingContext; |
14148 | 0 | return browsingContext.forget(); |
14149 | 0 | } |
14150 | | |
14151 | | NS_IMETHODIMP |
14152 | | nsDocShell::GetBrowsingContext(BrowsingContext** aBrowsingContext) |
14153 | 0 | { |
14154 | 0 | *aBrowsingContext = do_AddRef(mBrowsingContext).take(); |
14155 | 0 | return NS_OK; |
14156 | 0 | } |
14157 | | |
14158 | | void |
14159 | | nsIDocShell::AttachBrowsingContext(nsIDocShell* aParentDocShell) |
14160 | 0 | { |
14161 | 0 | RefPtr<BrowsingContext> childContext = |
14162 | 0 | nsDocShell::Cast(this)->GetBrowsingContext(); |
14163 | 0 | RefPtr<BrowsingContext> parentContext; |
14164 | 0 | if (aParentDocShell) { |
14165 | 0 | parentContext = |
14166 | 0 | nsDocShell::Cast(aParentDocShell)->GetBrowsingContext(); |
14167 | 0 | } |
14168 | 0 | childContext->Attach(parentContext); |
14169 | 0 | } |
14170 | | |
14171 | | void |
14172 | | nsIDocShell::DetachBrowsingContext() |
14173 | 0 | { |
14174 | 0 | RefPtr<BrowsingContext> browsingContext = |
14175 | 0 | nsDocShell::Cast(this)->GetBrowsingContext(); |
14176 | 0 | browsingContext->Detach(); |
14177 | 0 | } |