1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: ft=cpp tw=78 sw=4 et ts=4 sts=4 cin
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is the Mozilla browser.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications, Inc.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
24 * Travis Bogard <travis@netscape.com>
25 * Pierre Phaneuf <pp@ludusdesign.com>
26 * Peter Annema <disttsc@bart.nl>
27 * Dan Rosen <dr@netscape.com>
28 * Mats Palmgren <mats.palmgren@bredband.net>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
45 // so we can get logging even in release builds (but only for some things)
46 #define FORCE_PR_LOG 1
49 #include "nsIBrowserDOMWindow.h"
50 #include "nsIComponentManager.h"
51 #include "nsIContent.h"
52 #include "nsIDocument.h"
53 #include "nsIDOMDocument.h"
54 #include "nsIDOMNSDocument.h"
55 #include "nsIDOMElement.h"
56 #include "nsIDOMStorage.h"
57 #include "nsPIDOMStorage.h"
58 #include "nsIDocumentViewer.h"
59 #include "nsIDocumentLoaderFactory.h"
60 #include "nsCURILoader.h"
61 #include "nsURILoader.h"
62 #include "nsDocShellCID.h"
63 #include "nsLayoutCID.h"
65 #include "nsIDOMScriptObjectFactory.h"
66 #include "nsNetUtil.h"
69 #include "nsIMarkupDocumentViewer.h"
70 #include "nsXPIDLString.h"
71 #include "nsReadableUtils.h"
72 #include "nsIDOMEventTarget.h"
73 #include "nsIDOMChromeWindow.h"
74 #include "nsIDOMWindowInternal.h"
75 #include "nsIWebBrowserChrome.h"
77 #include "nsGfxCIID.h"
78 #include "nsIObserverService.h"
79 #include "nsIPrompt.h"
80 #include "nsIAuthPrompt.h"
81 #include "nsIAuthPrompt2.h"
82 #include "nsTextFormatter.h"
83 #include "nsIChannelEventSink.h"
84 #include "nsIUploadChannel.h"
85 #include "nsISecurityEventSink.h"
86 #include "nsIScriptSecurityManager.h"
87 #include "nsIJSContextStack.h"
88 #include "nsIScriptObjectPrincipal.h"
89 #include "nsDocumentCharsetInfoCID.h"
90 #include "nsICanvasFrame.h"
91 #include "nsIScrollableFrame.h"
92 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
93 #include "nsICategoryManager.h"
94 #include "nsXPCOMCID.h"
95 #include "nsISeekableStream.h"
96 #include "nsAutoPtr.h"
97 #include "nsIPrefService.h"
98 #include "nsIPrefBranch.h"
99 #include "nsIPrefBranch2.h"
100 #include "nsIWritablePropertyBag2.h"
101 #include "nsIAppShell.h"
102 #include "nsWidgetsCID.h"
103 #include "nsDOMJSUtils.h"
104 #include "nsIInterfaceRequestorUtils.h"
106 #include "nsIViewManager.h"
107 #include "nsIScrollableView.h"
108 #include "nsIScriptChannel.h"
109 #include "nsIURIClassifier.h"
110 #include "nsIOfflineCacheUpdate.h"
111 #include "nsCPrefetchService.h"
113 // we want to explore making the document own the load group
114 // so we can associate the document URI with the load group.
115 // until this point, we have an evil hack:
116 #include "nsIHttpChannelInternal.h"
120 #include "nsDocShell.h"
121 #include "nsDocShellLoadInfo.h"
122 #include "nsCDefaultURIFixup.h"
123 #include "nsDocShellEnumerator.h"
124 #include "nsSHistory.h"
125 #include "nsDocShellEditorData.h"
128 #include "nsDOMError.h"
129 #include "nsEscape.h"
132 #include "nsIUploadChannel.h"
133 #include "nsIProgressEventSink.h"
134 #include "nsIWebProgress.h"
135 #include "nsILayoutHistoryState.h"
136 #include "nsITimer.h"
137 #include "nsISHistoryInternal.h"
138 #include "nsIPrincipal.h"
139 #include "nsIFileURL.h"
140 #include "nsIHistoryEntry.h"
141 #include "nsISHistoryListener.h"
142 #include "nsIWindowWatcher.h"
143 #include "nsIPromptFactory.h"
144 #include "nsIObserver.h"
145 #include "nsINestedURI.h"
146 #include "nsITransportSecurityInfo.h"
147 #include "nsINSSErrorsService.h"
148 #include "nsIApplicationCache.h"
149 #include "nsIApplicationCacheChannel.h"
150 #include "nsIApplicationCacheContainer.h"
151 #include "nsIPermissionManager.h"
154 #include "nsIEditingSession.h"
156 #include "nsPIDOMWindow.h"
157 #include "nsIDOMDocument.h"
158 #include "nsICachingChannel.h"
159 #include "nsICacheVisitor.h"
160 #include "nsICacheEntryDescriptor.h"
161 #include "nsIMultiPartChannel.h"
162 #include "nsIWyciwygChannel.h"
164 // The following are for bug #13871: Prevent frameset spoofing
165 #include "nsIHTMLDocument.h"
167 // For reporting errors with the console service.
168 // These can go away if error reporting is propagated up past nsDocShell.
169 #include "nsIConsoleService.h"
170 #include "nsIScriptError.h"
172 // used to dispatch urls to default protocol handlers
173 #include "nsCExternalHandlerService.h"
174 #include "nsIExternalProtocolService.h"
176 #include "nsIFocusController.h"
178 #include "nsITextToSubURI.h"
180 #include "nsIJARChannel.h"
185 #include "nsISelectionDisplay.h"
187 #include "nsIGlobalHistory2.h"
188 #include "nsIGlobalHistory3.h"
190 #ifdef DEBUG_DOCSHELL_FOCUS
191 #include "nsIEventStateManager.h"
194 #include "nsIFrame.h"
197 #include "nsIWebBrowserChromeFocus.h"
199 #include "nsPluginError.h"
201 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID
,
202 NS_DOM_SCRIPT_OBJECT_FACTORY_CID
);
203 static NS_DEFINE_CID(kAppShellCID
, NS_APPSHELL_CID
);
205 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
206 //#define DEBUG_DOCSHELL_FOCUS
207 #define DEBUG_PAGE_CACHE
210 #include "nsContentErrors.h"
211 #include "nsIFocusEventSuppressor.h"
213 // Number of documents currently loading
214 static PRInt32 gNumberOfDocumentsLoading
= 0;
216 // Global count of existing docshells.
217 static PRInt32 gDocShellCount
= 0;
219 // Global reference to the URI fixup service.
220 nsIURIFixup
*nsDocShell::sURIFixup
= 0;
222 // True means we validate window targets to prevent frameset
223 // spoofing. Initialize this to a non-bolean value so we know to check
224 // the pref on the creation of the first docshell.
225 static PRBool gValidateOrigin
= (PRBool
)0xffffffff;
227 // Hint for native dispatch of events on how long to delay after
228 // all documents have loaded in milliseconds before favoring normal
229 // native event dispatch priorites over performance
230 #define NS_EVENT_STARVATION_DELAY_HINT 2000
232 // This is needed for displaying an error message
233 // when navigation is attempted on a document when printing
234 // The value arbitrary as long as it doesn't conflict with
235 // any of the other values in the errors in DisplayLoadError
236 #define NS_ERROR_DOCUMENT_IS_PRINTMODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL,2001)
240 static PRLogModuleInfo
* gDocShellLog
;
242 static PRLogModuleInfo
* gDocShellLeakLog
;
245 const char kBrandBundleURL
[] = "chrome://branding/locale/brand.properties";
246 const char kAppstringsBundleURL
[] = "chrome://global/locale/appstrings.properties";
249 FavorPerformanceHint(PRBool perfOverStarvation
, PRUint32 starvationDelay
)
251 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(kAppShellCID
);
253 appShell
->FavorPerformanceHint(perfOverStarvation
, starvationDelay
);
256 //*****************************************************************************
257 //*** nsDocShellFocusController
258 //*****************************************************************************
260 class nsDocShellFocusController
264 static nsDocShellFocusController
* GetInstance() { return &mDocShellFocusControllerSingleton
; }
265 virtual ~nsDocShellFocusController(){}
267 void Focus(nsIDocShell
* aDS
);
268 void ClosingDown(nsIDocShell
* aDS
);
271 nsDocShellFocusController(){}
273 nsIDocShell
* mFocusedDocShell
; // very weak reference
276 static nsDocShellFocusController mDocShellFocusControllerSingleton
;
279 nsDocShellFocusController
nsDocShellFocusController::mDocShellFocusControllerSingleton
;
281 //*****************************************************************************
282 //*** nsDocShell: Object Management
283 //*****************************************************************************
285 nsDocShell::nsDocShell():
287 mAllowSubframes(PR_TRUE
),
288 mAllowPlugins(PR_TRUE
),
289 mAllowJavascript(PR_TRUE
),
290 mAllowMetaRedirects(PR_TRUE
),
291 mAllowImages(PR_TRUE
),
292 mFocusDocFirst(PR_FALSE
),
294 mCreatingDocument(PR_FALSE
),
295 mUseErrorPages(PR_FALSE
),
296 mObserveErrorPages(PR_TRUE
),
298 mAllowKeywordFixup(PR_FALSE
),
299 mIsOffScreenBrowser(PR_FALSE
),
300 mFiredUnloadEvent(PR_FALSE
),
301 mEODForCurrentDocument(PR_FALSE
),
302 mURIResultedInDocument(PR_FALSE
),
303 mIsBeingDestroyed(PR_FALSE
),
304 mIsExecutingOnLoadHandler(PR_FALSE
),
305 mIsPrintingOrPP(PR_FALSE
),
306 mSavingOldViewer(PR_FALSE
),
307 mAppType(nsIDocShell::APP_TYPE_UNKNOWN
),
309 mBusyFlags(BUSY_FLAGS_NONE
),
312 mItemType(typeContent
),
313 mDefaultScrollbarPref(Scrollbar_Auto
, Scrollbar_Auto
),
314 mPreviousTransIndex(-1),
315 mLoadedTransIndex(-1),
317 mChromeEventHandler(nsnull
)
319 , mInEnsureScriptEnv(PR_FALSE
)
322 if (gDocShellCount
++ == 0) {
323 NS_ASSERTION(sURIFixup
== nsnull
,
324 "Huh, sURIFixup not null in first nsDocShell ctor!");
326 CallGetService(NS_URIFIXUP_CONTRACTID
, &sURIFixup
);
332 gDocShellLog
= PR_NewLogModule("nsDocShell");
334 if (nsnull
== gDocShellLeakLog
)
335 gDocShellLeakLog
= PR_NewLogModule("nsDocShellLeak");
336 if (gDocShellLeakLog
)
337 PR_LOG(gDocShellLeakLog
, PR_LOG_DEBUG
, ("DOCSHELL %p created\n", this));
341 nsDocShell::~nsDocShell()
343 nsDocShellFocusController
* dsfc
= nsDocShellFocusController::GetInstance();
345 dsfc
->ClosingDown(this);
349 if (--gDocShellCount
== 0) {
350 NS_IF_RELEASE(sURIFixup
);
354 if (gDocShellLeakLog
)
355 PR_LOG(gDocShellLeakLog
, PR_LOG_DEBUG
, ("DOCSHELL %p destroyed\n", this));
362 nsresult rv
= nsDocLoader::Init();
363 NS_ENSURE_SUCCESS(rv
, rv
);
365 NS_ASSERTION(mLoadGroup
, "Something went wrong!");
367 mContentListener
= new nsDSURIContentListener(this);
368 NS_ENSURE_TRUE(mContentListener
, NS_ERROR_OUT_OF_MEMORY
);
370 rv
= mContentListener
->Init();
371 NS_ENSURE_SUCCESS(rv
, rv
);
373 if (!mStorages
.Init())
374 return NS_ERROR_OUT_OF_MEMORY
;
376 // We want to hold a strong ref to the loadgroup, so it better hold a weak
377 // ref to us... use an InterfaceRequestorProxy to do this.
378 nsCOMPtr
<InterfaceRequestorProxy
> proxy
=
379 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor
*>
381 NS_ENSURE_TRUE(proxy
, NS_ERROR_OUT_OF_MEMORY
);
382 mLoadGroup
->SetNotificationCallbacks(proxy
);
384 rv
= nsDocLoader::AddDocLoaderAsChildOfRoot(this);
385 NS_ENSURE_SUCCESS(rv
, rv
);
387 // Add as |this| a progress listener to itself. A little weird, but
388 // simpler than reproducing all the listener-notification logic in
389 // overrides of the various methods via which nsDocLoader can be
390 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
391 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT
|
392 nsIWebProgress::NOTIFY_STATE_NETWORK
);
397 nsDocShell::DestroyChildren()
399 nsCOMPtr
<nsIDocShellTreeItem
> shell
;
400 PRInt32 n
= mChildList
.Count();
401 for (PRInt32 i
= 0; i
< n
; i
++) {
402 shell
= do_QueryInterface(ChildAt(i
));
403 NS_ASSERTION(shell
, "docshell has null child");
406 shell
->SetTreeOwner(nsnull
);
410 nsDocLoader::DestroyChildren();
413 //*****************************************************************************
414 // nsDocShell::nsISupports
415 //*****************************************************************************
417 NS_IMPL_ADDREF_INHERITED(nsDocShell
, nsDocLoader
)
418 NS_IMPL_RELEASE_INHERITED(nsDocShell
, nsDocLoader
)
420 NS_INTERFACE_MAP_BEGIN(nsDocShell
)
421 NS_INTERFACE_MAP_ENTRY(nsIDocShell
)
422 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem
)
423 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode
)
424 NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory
)
425 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation
)
426 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
427 NS_INTERFACE_MAP_ENTRY(nsIScrollable
)
428 NS_INTERFACE_MAP_ENTRY(nsITextScroll
)
429 NS_INTERFACE_MAP_ENTRY(nsIDocCharset
)
430 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner
)
431 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI
)
432 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
433 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
434 NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer
)
435 NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell
)
436 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor
)
437 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider
)
438 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
439 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
440 NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_1_9_1
)
441 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader
)
443 ///*****************************************************************************
444 // nsDocShell::nsIInterfaceRequestor
445 //*****************************************************************************
446 NS_IMETHODIMP
nsDocShell::GetInterface(const nsIID
& aIID
, void **aSink
)
448 NS_PRECONDITION(aSink
, "null out param");
452 if (aIID
.Equals(NS_GET_IID(nsIURIContentListener
))) {
453 *aSink
= mContentListener
;
455 else if (aIID
.Equals(NS_GET_IID(nsIScriptGlobalObject
)) &&
456 NS_SUCCEEDED(EnsureScriptEnvironment())) {
457 *aSink
= mScriptGlobal
;
459 else if ((aIID
.Equals(NS_GET_IID(nsIDOMWindowInternal
)) ||
460 aIID
.Equals(NS_GET_IID(nsPIDOMWindow
)) ||
461 aIID
.Equals(NS_GET_IID(nsIDOMWindow
))) &&
462 NS_SUCCEEDED(EnsureScriptEnvironment())) {
463 return mScriptGlobal
->QueryInterface(aIID
, aSink
);
465 else if (aIID
.Equals(NS_GET_IID(nsIDOMDocument
)) &&
466 NS_SUCCEEDED(EnsureContentViewer())) {
467 mContentViewer
->GetDOMDocument((nsIDOMDocument
**) aSink
);
468 return *aSink
? NS_OK
: NS_NOINTERFACE
;
470 else if (aIID
.Equals(NS_GET_IID(nsIApplicationCacheContainer
))) {
473 // Return application cache associated with this docshell, if any
475 nsCOMPtr
<nsIContentViewer
> contentViewer
;
476 GetContentViewer(getter_AddRefs(contentViewer
));
478 return NS_ERROR_NO_INTERFACE
;
480 nsCOMPtr
<nsIDOMDocument
> domDoc
;
481 contentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
482 NS_ASSERTION(domDoc
, "Should have a document.");
484 return NS_ERROR_NO_INTERFACE
;
486 #if defined(PR_LOGGING) && defined(DEBUG)
487 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
488 ("nsDocShell[%p]: returning app cache container %p",
489 this, domDoc
.get()));
491 return domDoc
->QueryInterface(aIID
, aSink
);
493 else if (aIID
.Equals(NS_GET_IID(nsIPrompt
)) &&
494 NS_SUCCEEDED(EnsureScriptEnvironment())) {
496 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
497 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
498 NS_ENSURE_SUCCESS(rv
, rv
);
500 nsCOMPtr
<nsIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
502 // Get the an auth prompter for our window so that the parenting
503 // of the dialogs works as it should when using tabs.
506 rv
= wwatch
->GetNewPrompter(window
, &prompt
);
507 NS_ENSURE_SUCCESS(rv
, rv
);
512 else if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
)) ||
513 aIID
.Equals(NS_GET_IID(nsIAuthPrompt2
))) {
515 GetAuthPrompt(PROMPT_NORMAL
, aIID
, aSink
)) ?
516 NS_OK
: NS_NOINTERFACE
;
518 else if (aIID
.Equals(NS_GET_IID(nsISHistory
))) {
519 nsCOMPtr
<nsISHistory
> shistory
;
522 GetSessionHistory(getter_AddRefs(shistory
));
523 if (NS_SUCCEEDED(rv
) && shistory
) {
525 NS_ADDREF((nsISupports
*) * aSink
);
528 return NS_NOINTERFACE
;
530 else if (aIID
.Equals(NS_GET_IID(nsIWebBrowserFind
))) {
531 nsresult rv
= EnsureFind();
532 if (NS_FAILED(rv
)) return rv
;
535 NS_ADDREF((nsISupports
*)*aSink
);
538 else if (aIID
.Equals(NS_GET_IID(nsIEditingSession
)) && NS_SUCCEEDED(EnsureEditorData())) {
539 nsCOMPtr
<nsIEditingSession
> editingSession
;
540 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
543 *aSink
= editingSession
;
544 NS_ADDREF((nsISupports
*)*aSink
);
548 return NS_NOINTERFACE
;
550 else if (aIID
.Equals(NS_GET_IID(nsIClipboardDragDropHookList
))
551 && NS_SUCCEEDED(EnsureTransferableHookData())) {
552 *aSink
= mTransferableHookData
;
553 NS_ADDREF((nsISupports
*)*aSink
);
556 else if (aIID
.Equals(NS_GET_IID(nsISelectionDisplay
))) {
557 nsCOMPtr
<nsIPresShell
> shell
;
558 nsresult rv
= GetPresShell(getter_AddRefs(shell
));
559 if (NS_SUCCEEDED(rv
) && shell
)
560 return shell
->QueryInterface(aIID
,aSink
);
562 else if (aIID
.Equals(NS_GET_IID(nsIDocShellTreeOwner
))) {
563 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
564 nsresult rv
= GetTreeOwner(getter_AddRefs(treeOwner
));
565 if (NS_SUCCEEDED(rv
) && treeOwner
)
566 return treeOwner
->QueryInterface(aIID
, aSink
);
569 return nsDocLoader::GetInterface(aIID
, aSink
);
572 NS_IF_ADDREF(((nsISupports
*) * aSink
));
573 return *aSink
? NS_OK
: NS_NOINTERFACE
;
578 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType
)
580 PRUint32 loadType
= LOAD_NORMAL
;
582 switch (aDocShellLoadType
) {
583 case nsIDocShellLoadInfo::loadNormal
:
584 loadType
= LOAD_NORMAL
;
586 case nsIDocShellLoadInfo::loadNormalReplace
:
587 loadType
= LOAD_NORMAL_REPLACE
;
589 case nsIDocShellLoadInfo::loadNormalExternal
:
590 loadType
= LOAD_NORMAL_EXTERNAL
;
592 case nsIDocShellLoadInfo::loadHistory
:
593 loadType
= LOAD_HISTORY
;
595 case nsIDocShellLoadInfo::loadNormalBypassCache
:
596 loadType
= LOAD_NORMAL_BYPASS_CACHE
;
598 case nsIDocShellLoadInfo::loadNormalBypassProxy
:
599 loadType
= LOAD_NORMAL_BYPASS_PROXY
;
601 case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache
:
602 loadType
= LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
;
604 case nsIDocShellLoadInfo::loadReloadNormal
:
605 loadType
= LOAD_RELOAD_NORMAL
;
607 case nsIDocShellLoadInfo::loadReloadCharsetChange
:
608 loadType
= LOAD_RELOAD_CHARSET_CHANGE
;
610 case nsIDocShellLoadInfo::loadReloadBypassCache
:
611 loadType
= LOAD_RELOAD_BYPASS_CACHE
;
613 case nsIDocShellLoadInfo::loadReloadBypassProxy
:
614 loadType
= LOAD_RELOAD_BYPASS_PROXY
;
616 case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
:
617 loadType
= LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
;
619 case nsIDocShellLoadInfo::loadLink
:
620 loadType
= LOAD_LINK
;
622 case nsIDocShellLoadInfo::loadRefresh
:
623 loadType
= LOAD_REFRESH
;
625 case nsIDocShellLoadInfo::loadBypassHistory
:
626 loadType
= LOAD_BYPASS_HISTORY
;
628 case nsIDocShellLoadInfo::loadStopContent
:
629 loadType
= LOAD_STOP_CONTENT
;
631 case nsIDocShellLoadInfo::loadStopContentAndReplace
:
632 loadType
= LOAD_STOP_CONTENT_AND_REPLACE
;
635 NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
642 nsDocShellInfoLoadType
643 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType
)
645 nsDocShellInfoLoadType docShellLoadType
= nsIDocShellLoadInfo::loadNormal
;
648 docShellLoadType
= nsIDocShellLoadInfo::loadNormal
;
650 case LOAD_NORMAL_REPLACE
:
651 docShellLoadType
= nsIDocShellLoadInfo::loadNormalReplace
;
653 case LOAD_NORMAL_EXTERNAL
:
654 docShellLoadType
= nsIDocShellLoadInfo::loadNormalExternal
;
656 case LOAD_NORMAL_BYPASS_CACHE
:
657 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassCache
;
659 case LOAD_NORMAL_BYPASS_PROXY
:
660 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassProxy
;
662 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
663 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassProxyAndCache
;
666 docShellLoadType
= nsIDocShellLoadInfo::loadHistory
;
668 case LOAD_RELOAD_NORMAL
:
669 docShellLoadType
= nsIDocShellLoadInfo::loadReloadNormal
;
671 case LOAD_RELOAD_CHARSET_CHANGE
:
672 docShellLoadType
= nsIDocShellLoadInfo::loadReloadCharsetChange
;
674 case LOAD_RELOAD_BYPASS_CACHE
:
675 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassCache
;
677 case LOAD_RELOAD_BYPASS_PROXY
:
678 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassProxy
;
680 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
681 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
;
684 docShellLoadType
= nsIDocShellLoadInfo::loadLink
;
687 docShellLoadType
= nsIDocShellLoadInfo::loadRefresh
;
689 case LOAD_BYPASS_HISTORY
:
690 case LOAD_ERROR_PAGE
:
691 docShellLoadType
= nsIDocShellLoadInfo::loadBypassHistory
;
693 case LOAD_STOP_CONTENT
:
694 docShellLoadType
= nsIDocShellLoadInfo::loadStopContent
;
696 case LOAD_STOP_CONTENT_AND_REPLACE
:
697 docShellLoadType
= nsIDocShellLoadInfo::loadStopContentAndReplace
;
700 NS_NOTREACHED("Unexpected load type value");
703 return docShellLoadType
;
706 //*****************************************************************************
707 // nsDocShell::nsIDocShell
708 //*****************************************************************************
710 nsDocShell::LoadURI(nsIURI
* aURI
,
711 nsIDocShellLoadInfo
* aLoadInfo
,
715 NS_PRECONDITION(aLoadInfo
|| (aLoadFlags
& EXTRA_LOAD_FLAGS
) == 0,
717 NS_PRECONDITION((aLoadFlags
& 0xf) == 0, "Should not have these flags set");
719 // Note: we allow loads to get through here even if mFiredUnloadEvent is
720 // true; that case will get handled in LoadInternal or LoadHistoryEntry.
721 if (IsPrintingOrPP()) {
722 return NS_OK
; // JS may not handle returning of an error code
725 nsCOMPtr
<nsIURI
> referrer
;
726 nsCOMPtr
<nsIInputStream
> postStream
;
727 nsCOMPtr
<nsIInputStream
> headersStream
;
728 nsCOMPtr
<nsISupports
> owner
;
729 PRBool inheritOwner
= PR_FALSE
;
730 PRBool sendReferrer
= PR_TRUE
;
731 nsCOMPtr
<nsISHEntry
> shEntry
;
732 nsXPIDLString target
;
733 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
737 // Extract the info from the DocShellLoadInfo struct...
739 aLoadInfo
->GetReferrer(getter_AddRefs(referrer
));
741 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
742 aLoadInfo
->GetLoadType(<
);
743 // Get the appropriate loadType from nsIDocShellLoadInfo type
744 loadType
= ConvertDocShellLoadInfoToLoadType(lt
);
746 aLoadInfo
->GetOwner(getter_AddRefs(owner
));
747 aLoadInfo
->GetInheritOwner(&inheritOwner
);
748 aLoadInfo
->GetSHEntry(getter_AddRefs(shEntry
));
749 aLoadInfo
->GetTarget(getter_Copies(target
));
750 aLoadInfo
->GetPostDataStream(getter_AddRefs(postStream
));
751 aLoadInfo
->GetHeadersStream(getter_AddRefs(headersStream
));
752 aLoadInfo
->GetSendReferrer(&sendReferrer
);
755 #if defined(PR_LOGGING) && defined(DEBUG)
756 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
757 nsCAutoString uristr
;
758 aURI
->GetAsciiSpec(uristr
);
759 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
760 ("nsDocShell[%p]: loading %s with flags 0x%08x",
761 this, uristr
.get(), aLoadFlags
));
766 !LOAD_TYPE_HAS_FLAGS(loadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
767 // First verify if this is a subframe.
768 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
769 GetSameTypeParent(getter_AddRefs(parentAsItem
));
770 nsCOMPtr
<nsIDocShell
> parentDS(do_QueryInterface(parentAsItem
));
771 PRUint32 parentLoadType
;
773 if (parentDS
&& parentDS
!= static_cast<nsIDocShell
*>(this)) {
774 /* OK. It is a subframe. Checkout the
775 * parent's loadtype. If the parent was loaded thro' a history
776 * mechanism, then get the SH entry for the child from the parent.
777 * This is done to restore frameset navigation while going back/forward.
778 * If the parent was loaded through any other loadType, set the
779 * child's loadType too accordingly, so that session history does not
783 // Get the parent's load type
784 parentDS
->GetLoadType(&parentLoadType
);
786 nsCOMPtr
<nsIDocShellHistory
> parent(do_QueryInterface(parentAsItem
));
788 // Get the ShEntry for the child from the parent
789 parent
->GetChildSHEntry(mChildOffset
, getter_AddRefs(shEntry
));
790 // Make some decisions on the child frame's loadType based on the
791 // parent's loadType.
792 if (mCurrentURI
== nsnull
) {
793 // This is a newly created frame. Check for exception cases first.
794 // By default the subframe will inherit the parent's loadType.
795 if (shEntry
&& (parentLoadType
== LOAD_NORMAL
||
796 parentLoadType
== LOAD_LINK
||
797 parentLoadType
== LOAD_NORMAL_EXTERNAL
)) {
798 // The parent was loaded normally. In this case, this *brand new* child really shouldn't
799 // have a SHEntry. If it does, it could be because the parent is replacing an
800 // existing frame with a new frame, in the onLoadHandler. We don't want this
801 // url to get into session history. Clear off shEntry, and set laod type to
802 // LOAD_BYPASS_HISTORY.
803 PRBool inOnLoadHandler
=PR_FALSE
;
804 parentDS
->GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
805 if (inOnLoadHandler
) {
806 loadType
= LOAD_NORMAL_REPLACE
;
810 else if (parentLoadType
== LOAD_REFRESH
) {
811 // Clear shEntry. For refresh loads, we have to load
812 // what comes thro' the pipe, not what's in history.
815 else if ((parentLoadType
== LOAD_BYPASS_HISTORY
) ||
816 (parentLoadType
== LOAD_ERROR_PAGE
) ||
818 ((parentLoadType
& LOAD_CMD_HISTORY
) ||
819 (parentLoadType
== LOAD_RELOAD_NORMAL
) ||
820 (parentLoadType
== LOAD_RELOAD_CHARSET_CHANGE
)))) {
821 // If the parent url, bypassed history or was loaded from
822 // history, pass on the parent's loadType to the new child
823 // frame too, so that the child frame will also
824 // avoid getting into history.
825 loadType
= parentLoadType
;
829 // This is a pre-existing subframe. If the load was not originally initiated
830 // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
831 // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading
832 // a new page in this child. Check parent's and self's busy flag and if it is set,
833 // we don't want this onLoadHandler load to get in to session history.
834 PRUint32 parentBusy
= BUSY_FLAGS_NONE
;
835 PRUint32 selfBusy
= BUSY_FLAGS_NONE
;
836 parentDS
->GetBusyFlags(&parentBusy
);
837 GetBusyFlags(&selfBusy
);
838 if (((parentBusy
& BUSY_FLAGS_BUSY
) ||
839 (selfBusy
& BUSY_FLAGS_BUSY
)) &&
841 loadType
= LOAD_NORMAL_REPLACE
;
848 // This is the root docshell. If we got here while
849 // executing an onLoad Handler,this load will not go
850 // into session history.
851 PRBool inOnLoadHandler
=PR_FALSE
;
852 GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
853 if (inOnLoadHandler
) {
854 loadType
= LOAD_NORMAL_REPLACE
;
861 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
862 ("nsDocShell[%p]: loading from session history", this));
865 rv
= LoadHistoryEntry(shEntry
, loadType
);
867 // Perform the load...
869 // We need an owner (a referring principal). 4 possibilities:
870 // (1) If the system principal was passed in and we're a typeContent
871 // docshell, inherit the principal from the current document
873 // (2) In all other cases when the principal passed in is not null,
874 // use that principal.
875 // (3) If the caller has allowed inheriting from the current document,
876 // or if we're being called from system code (eg chrome JS or pure
877 // C++) then inheritOwner should be true and InternalLoad will get
878 // an owner from the current document. If none of these things are
880 // (4) we pass a null owner into the channel, and an owner will be
881 // created later from the channel's internal data.
883 // NOTE: This all only works because the only thing the owner is used
884 // for in InternalLoad is data:, javascript:, and about:blank
885 // URIs. For other URIs this would all be dead wrong!
886 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
887 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
888 NS_ENSURE_SUCCESS(rv
, rv
);
890 if (owner
&& mItemType
!= typeChrome
) {
891 nsCOMPtr
<nsIPrincipal
> ownerPrincipal
= do_QueryInterface(owner
);
893 rv
= secMan
->IsSystemPrincipal(ownerPrincipal
, &isSystem
);
894 NS_ENSURE_SUCCESS(rv
, rv
);
898 inheritOwner
= PR_TRUE
;
901 if (!owner
&& !inheritOwner
) {
902 // See if there's system or chrome JS code running
903 rv
= secMan
->SubjectPrincipalIsSystem(&inheritOwner
);
905 // Set it back to false
906 inheritOwner
= PR_FALSE
;
913 flags
|= INTERNAL_LOAD_FLAGS_INHERIT_OWNER
;
916 flags
|= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
;
918 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
)
919 flags
|= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
921 if (aLoadFlags
& LOAD_FLAGS_FIRST_LOAD
)
922 flags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
924 if (aLoadFlags
& LOAD_FLAGS_BYPASS_CLASSIFIER
)
925 flags
|= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
;
927 rv
= InternalLoad(aURI
,
932 nsnull
, // No type hint
936 nsnull
, // No SHEntry
938 nsnull
, // No nsIDocShell
939 nsnull
); // No nsIRequest
946 nsDocShell::LoadStream(nsIInputStream
*aStream
, nsIURI
* aURI
,
947 const nsACString
&aContentType
,
948 const nsACString
&aContentCharset
,
949 nsIDocShellLoadInfo
* aLoadInfo
)
951 NS_ENSURE_ARG(aStream
);
953 mAllowKeywordFixup
= PR_FALSE
;
955 // if the caller doesn't pass in a URI we need to create a dummy URI. necko
956 // currently requires a URI in various places during the load. Some consumers
958 nsCOMPtr
<nsIURI
> uri
= aURI
;
962 uri
= do_CreateInstance(NS_SIMPLEURI_CONTRACTID
, &rv
);
965 // Make sure that the URI spec "looks" like a protocol and path...
966 // For now, just use a bogus protocol called "internal"
967 rv
= uri
->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
972 PRUint32 loadType
= LOAD_NORMAL
;
974 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
975 (void) aLoadInfo
->GetLoadType(<
);
976 // Get the appropriate LoadType from nsIDocShellLoadInfo type
977 loadType
= ConvertDocShellLoadInfoToLoadType(lt
);
980 NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK
), NS_ERROR_FAILURE
);
982 mLoadType
= loadType
;
984 // build up a channel for this stream.
985 nsCOMPtr
<nsIChannel
> channel
;
986 NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
987 (getter_AddRefs(channel
), uri
, aStream
,
988 aContentType
, aContentCharset
),
991 nsCOMPtr
<nsIURILoader
>
992 uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID
));
993 NS_ENSURE_TRUE(uriLoader
, NS_ERROR_FAILURE
);
995 NS_ENSURE_SUCCESS(DoChannelLoad(channel
, uriLoader
, PR_FALSE
),
1001 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo
** aLoadInfo
)
1003 nsDocShellLoadInfo
*loadInfo
= new nsDocShellLoadInfo();
1004 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
1005 nsCOMPtr
<nsIDocShellLoadInfo
> localRef(loadInfo
);
1007 *aLoadInfo
= localRef
;
1008 NS_ADDREF(*aLoadInfo
);
1014 * Reset state to a new content model within the current document and the document
1015 * viewer. Called by the document before initiating an out of band document.write().
1018 nsDocShell::PrepareForNewContentModel()
1020 mEODForCurrentDocument
= PR_FALSE
;
1026 nsDocShell::FirePageHideNotification(PRBool aIsUnload
)
1028 if (mContentViewer
&& !mFiredUnloadEvent
) {
1029 // Keep an explicit reference since calling PageHide could release
1031 nsCOMPtr
<nsIContentViewer
> kungFuDeathGrip(mContentViewer
);
1032 mFiredUnloadEvent
= PR_TRUE
;
1034 mContentViewer
->PageHide(aIsUnload
);
1036 nsAutoTArray
<nsCOMPtr
<nsIDocShell
>, 8> kids
;
1037 PRInt32 i
, n
= mChildList
.Count();
1038 kids
.SetCapacity(n
);
1039 for (i
= 0; i
< n
; i
++) {
1040 kids
.AppendElement(do_QueryInterface(ChildAt(i
)));
1044 for (i
= 0; i
< n
; ++i
) {
1046 kids
[i
]->FirePageHideNotification(aIsUnload
);
1049 // Now make sure our editor, if any, is detached before we go
1051 DetachEditorFromWindow();
1058 // Bug 13871: Prevent frameset spoofing
1060 // This routine answers: 'Is origin's document from same domain as
1061 // target's document?'
1063 // file: uris are considered the same domain for the purpose of
1064 // frame navigation regardless of script accessibility (bug 420425)
1068 nsDocShell::ValidateOrigin(nsIDocShellTreeItem
* aOriginTreeItem
,
1069 nsIDocShellTreeItem
* aTargetTreeItem
)
1071 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
1072 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
1073 NS_ENSURE_TRUE(securityManager
, PR_FALSE
);
1075 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
;
1077 securityManager
->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal
));
1078 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
1080 if (subjectPrincipal
) {
1081 // We're called from JS, check if UniversalBrowserWrite is
1083 PRBool ubwEnabled
= PR_FALSE
;
1084 rv
= securityManager
->IsCapabilityEnabled("UniversalBrowserWrite",
1086 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
1093 // Get origin document principal
1094 nsCOMPtr
<nsIDOMDocument
> originDOMDocument
=
1095 do_GetInterface(aOriginTreeItem
);
1096 nsCOMPtr
<nsIDocument
> originDocument(do_QueryInterface(originDOMDocument
));
1097 NS_ENSURE_TRUE(originDocument
, PR_FALSE
);
1099 // Get target principal
1100 nsCOMPtr
<nsIDOMDocument
> targetDOMDocument
=
1101 do_GetInterface(aTargetTreeItem
);
1102 nsCOMPtr
<nsIDocument
> targetDocument(do_QueryInterface(targetDOMDocument
));
1103 NS_ENSURE_TRUE(targetDocument
, PR_FALSE
);
1106 rv
= originDocument
->NodePrincipal()->
1107 Equals(targetDocument
->NodePrincipal(), &equal
);
1108 if (NS_SUCCEEDED(rv
) && equal
) {
1112 // Not strictly equal, special case if both are file: uris
1113 PRBool originIsFile
= PR_FALSE
;
1114 PRBool targetIsFile
= PR_FALSE
;
1115 nsCOMPtr
<nsIURI
> originURI
;
1116 nsCOMPtr
<nsIURI
> targetURI
;
1117 nsCOMPtr
<nsIURI
> innerOriginURI
;
1118 nsCOMPtr
<nsIURI
> innerTargetURI
;
1120 rv
= originDocument
->NodePrincipal()->GetURI(getter_AddRefs(originURI
));
1121 if (NS_SUCCEEDED(rv
) && originURI
)
1122 innerOriginURI
= NS_GetInnermostURI(originURI
);
1124 rv
= targetDocument
->NodePrincipal()->GetURI(getter_AddRefs(targetURI
));
1125 if (NS_SUCCEEDED(rv
) && targetURI
)
1126 innerTargetURI
= NS_GetInnermostURI(targetURI
);
1128 return innerOriginURI
&& innerTargetURI
&&
1129 NS_SUCCEEDED(innerOriginURI
->SchemeIs("file", &originIsFile
)) &&
1130 NS_SUCCEEDED(innerTargetURI
->SchemeIs("file", &targetIsFile
)) &&
1131 originIsFile
&& targetIsFile
;
1135 nsDocShell::GetEldestPresContext(nsPresContext
** aPresContext
)
1137 nsresult rv
= NS_OK
;
1139 NS_ENSURE_ARG_POINTER(aPresContext
);
1140 *aPresContext
= nsnull
;
1142 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
1144 nsCOMPtr
<nsIContentViewer
> prevViewer
;
1145 viewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
1147 viewer
= prevViewer
;
1149 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(viewer
));
1151 rv
= docv
->GetPresContext(aPresContext
);
1160 nsDocShell::GetPresContext(nsPresContext
** aPresContext
)
1162 NS_ENSURE_ARG_POINTER(aPresContext
);
1163 *aPresContext
= nsnull
;
1165 if (!mContentViewer
)
1168 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(mContentViewer
));
1169 NS_ENSURE_TRUE(docv
, NS_ERROR_NO_INTERFACE
);
1171 return docv
->GetPresContext(aPresContext
);
1175 nsDocShell::GetPresShell(nsIPresShell
** aPresShell
)
1177 nsresult rv
= NS_OK
;
1179 NS_ENSURE_ARG_POINTER(aPresShell
);
1180 *aPresShell
= nsnull
;
1182 nsCOMPtr
<nsPresContext
> presContext
;
1183 (void) GetPresContext(getter_AddRefs(presContext
));
1186 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1193 nsDocShell::GetEldestPresShell(nsIPresShell
** aPresShell
)
1195 nsresult rv
= NS_OK
;
1197 NS_ENSURE_ARG_POINTER(aPresShell
);
1198 *aPresShell
= nsnull
;
1200 nsCOMPtr
<nsPresContext
> presContext
;
1201 (void) GetEldestPresContext(getter_AddRefs(presContext
));
1204 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1211 nsDocShell::GetContentViewer(nsIContentViewer
** aContentViewer
)
1213 NS_ENSURE_ARG_POINTER(aContentViewer
);
1215 *aContentViewer
= mContentViewer
;
1216 NS_IF_ADDREF(*aContentViewer
);
1221 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget
* aChromeEventHandler
)
1223 nsCOMPtr
<nsPIDOMEventTarget
> piTarget
=
1224 do_QueryInterface(aChromeEventHandler
);
1225 // Weak reference. Don't addref.
1226 mChromeEventHandler
= piTarget
;
1228 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
1230 win
->SetChromeEventHandler(piTarget
);
1237 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget
** aChromeEventHandler
)
1239 NS_ENSURE_ARG_POINTER(aChromeEventHandler
);
1240 nsCOMPtr
<nsIDOMEventTarget
> target
= do_QueryInterface(mChromeEventHandler
);
1241 target
.swap(*aChromeEventHandler
);
1245 /* [noscript] void setCurrentURI (in nsIURI uri); */
1247 nsDocShell::SetCurrentURI(nsIURI
*aURI
)
1249 SetCurrentURI(aURI
, nsnull
, PR_TRUE
);
1254 nsDocShell::SetCurrentURI(nsIURI
*aURI
, nsIRequest
*aRequest
,
1255 PRBool aFireOnLocationChange
)
1258 if (gDocShellLeakLog
&& PR_LOG_TEST(gDocShellLeakLog
, PR_LOG_DEBUG
)) {
1261 aURI
->GetSpec(spec
);
1262 PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec
.get());
1266 // We don't want to send a location change when we're displaying an error
1267 // page, and we don't want to change our idea of "current URI" either
1268 if (mLoadType
== LOAD_ERROR_PAGE
) {
1272 mCurrentURI
= NS_TryToMakeImmutable(aURI
);
1274 PRBool isRoot
= PR_FALSE
; // Is this the root docshell
1275 PRBool isSubFrame
= PR_FALSE
; // Is this a subframe navigation?
1277 nsCOMPtr
<nsIDocShellTreeItem
> root
;
1279 GetSameTypeRootTreeItem(getter_AddRefs(root
));
1280 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this))
1282 // This is the root docshell
1286 mLSHE
->GetIsSubFrame(&isSubFrame
);
1289 if (!isSubFrame
&& !isRoot
) {
1291 * We don't want to send OnLocationChange notifications when
1292 * a subframe is being loaded for the first time, while
1293 * visiting a frameset page
1298 if (aFireOnLocationChange
) {
1299 FireOnLocationChange(this, aRequest
, aURI
);
1301 return !aFireOnLocationChange
;
1305 nsDocShell::GetCharset(char** aCharset
)
1307 NS_ENSURE_ARG_POINTER(aCharset
);
1310 nsCOMPtr
<nsIPresShell
> presShell
;
1311 GetPresShell(getter_AddRefs(presShell
));
1312 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
1313 nsIDocument
*doc
= presShell
->GetDocument();
1314 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
1315 *aCharset
= ToNewCString(doc
->GetDocumentCharacterSet());
1317 return NS_ERROR_OUT_OF_MEMORY
;
1324 nsDocShell::SetCharset(const char* aCharset
)
1326 // set the default charset
1327 nsCOMPtr
<nsIContentViewer
> viewer
;
1328 GetContentViewer(getter_AddRefs(viewer
));
1330 nsCOMPtr
<nsIMarkupDocumentViewer
> muDV(do_QueryInterface(viewer
));
1332 NS_ENSURE_SUCCESS(muDV
->SetDefaultCharacterSet(nsDependentCString(aCharset
)),
1337 // set the charset override
1338 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
;
1339 GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
1341 nsCOMPtr
<nsIAtom
> csAtom
;
1342 csAtom
= do_GetAtom(aCharset
);
1343 dcInfo
->SetForcedCharset(csAtom
);
1350 nsDocShell::GetDocumentCharsetInfo(nsIDocumentCharsetInfo
**
1351 aDocumentCharsetInfo
)
1353 NS_ENSURE_ARG_POINTER(aDocumentCharsetInfo
);
1355 // if the mDocumentCharsetInfo does not exist already, we create it now
1356 if (!mDocumentCharsetInfo
) {
1357 mDocumentCharsetInfo
= do_CreateInstance(NS_DOCUMENTCHARSETINFO_CONTRACTID
);
1358 if (!mDocumentCharsetInfo
)
1359 return NS_ERROR_FAILURE
;
1362 *aDocumentCharsetInfo
= mDocumentCharsetInfo
;
1363 NS_IF_ADDREF(*aDocumentCharsetInfo
);
1368 nsDocShell::SetDocumentCharsetInfo(nsIDocumentCharsetInfo
*
1369 aDocumentCharsetInfo
)
1371 mDocumentCharsetInfo
= aDocumentCharsetInfo
;
1376 nsDocShell::GetChannelIsUnsafe(PRBool
*aUnsafe
)
1378 *aUnsafe
= PR_FALSE
;
1380 nsCOMPtr
<nsIChannel
> channel
;
1381 GetCurrentDocumentChannel(getter_AddRefs(channel
));
1386 nsCOMPtr
<nsIJARChannel
> jarChannel
= do_QueryInterface(channel
);
1391 return jarChannel
->GetIsUnsafe(aUnsafe
);
1395 nsDocShell::GetAllowPlugins(PRBool
* aAllowPlugins
)
1397 NS_ENSURE_ARG_POINTER(aAllowPlugins
);
1399 *aAllowPlugins
= mAllowPlugins
;
1400 if (!mAllowPlugins
) {
1405 *aAllowPlugins
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1410 nsDocShell::SetAllowPlugins(PRBool aAllowPlugins
)
1412 mAllowPlugins
= aAllowPlugins
;
1413 //XXX should enable or disable a plugin host
1418 nsDocShell::GetAllowJavascript(PRBool
* aAllowJavascript
)
1420 NS_ENSURE_ARG_POINTER(aAllowJavascript
);
1422 *aAllowJavascript
= mAllowJavascript
;
1423 if (!mAllowJavascript
) {
1428 *aAllowJavascript
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1433 nsDocShell::SetAllowJavascript(PRBool aAllowJavascript
)
1435 mAllowJavascript
= aAllowJavascript
;
1439 NS_IMETHODIMP
nsDocShell::GetAllowMetaRedirects(PRBool
* aReturn
)
1441 NS_ENSURE_ARG_POINTER(aReturn
);
1443 *aReturn
= mAllowMetaRedirects
;
1444 if (!mAllowMetaRedirects
) {
1449 *aReturn
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1453 NS_IMETHODIMP
nsDocShell::SetAllowMetaRedirects(PRBool aValue
)
1455 mAllowMetaRedirects
= aValue
;
1459 NS_IMETHODIMP
nsDocShell::GetAllowSubframes(PRBool
* aAllowSubframes
)
1461 NS_ENSURE_ARG_POINTER(aAllowSubframes
);
1463 *aAllowSubframes
= mAllowSubframes
;
1467 NS_IMETHODIMP
nsDocShell::SetAllowSubframes(PRBool aAllowSubframes
)
1469 mAllowSubframes
= aAllowSubframes
;
1473 NS_IMETHODIMP
nsDocShell::GetAllowImages(PRBool
* aAllowImages
)
1475 NS_ENSURE_ARG_POINTER(aAllowImages
);
1477 *aAllowImages
= mAllowImages
;
1481 NS_IMETHODIMP
nsDocShell::SetAllowImages(PRBool aAllowImages
)
1483 mAllowImages
= aAllowImages
;
1488 nsDocShell::GetDocShellEnumerator(PRInt32 aItemType
, PRInt32 aDirection
, nsISimpleEnumerator
**outEnum
)
1490 NS_ENSURE_ARG_POINTER(outEnum
);
1493 nsRefPtr
<nsDocShellEnumerator
> docShellEnum
;
1494 if (aDirection
== ENUMERATE_FORWARDS
)
1495 docShellEnum
= new nsDocShellForwardsEnumerator
;
1497 docShellEnum
= new nsDocShellBackwardsEnumerator
;
1499 if (!docShellEnum
) return NS_ERROR_OUT_OF_MEMORY
;
1501 nsresult rv
= docShellEnum
->SetEnumDocShellType(aItemType
);
1502 if (NS_FAILED(rv
)) return rv
;
1504 rv
= docShellEnum
->SetEnumerationRootItem((nsIDocShellTreeItem
*)this);
1505 if (NS_FAILED(rv
)) return rv
;
1507 rv
= docShellEnum
->First();
1508 if (NS_FAILED(rv
)) return rv
;
1510 rv
= docShellEnum
->QueryInterface(NS_GET_IID(nsISimpleEnumerator
), (void **)outEnum
);
1516 nsDocShell::GetAppType(PRUint32
* aAppType
)
1518 *aAppType
= mAppType
;
1523 nsDocShell::SetAppType(PRUint32 aAppType
)
1525 mAppType
= aAppType
;
1531 nsDocShell::GetAllowAuth(PRBool
* aAllowAuth
)
1533 *aAllowAuth
= mAllowAuth
;
1538 nsDocShell::SetAllowAuth(PRBool aAllowAuth
)
1540 mAllowAuth
= aAllowAuth
;
1545 nsDocShell::GetZoom(float *zoom
)
1547 NS_ENSURE_ARG_POINTER(zoom
);
1553 nsDocShell::SetZoom(float zoom
)
1555 return NS_ERROR_NOT_IMPLEMENTED
;
1559 nsDocShell::GetMarginWidth(PRInt32
* aWidth
)
1561 NS_ENSURE_ARG_POINTER(aWidth
);
1563 *aWidth
= mMarginWidth
;
1568 nsDocShell::SetMarginWidth(PRInt32 aWidth
)
1570 mMarginWidth
= aWidth
;
1575 nsDocShell::GetMarginHeight(PRInt32
* aHeight
)
1577 NS_ENSURE_ARG_POINTER(aHeight
);
1579 *aHeight
= mMarginHeight
;
1584 nsDocShell::SetMarginHeight(PRInt32 aHeight
)
1586 mMarginHeight
= aHeight
;
1591 nsDocShell::GetBusyFlags(PRUint32
* aBusyFlags
)
1593 NS_ENSURE_ARG_POINTER(aBusyFlags
);
1595 *aBusyFlags
= mBusyFlags
;
1600 nsDocShell::TabToTreeOwner(PRBool aForward
, PRBool
* aTookFocus
)
1602 NS_ENSURE_ARG_POINTER(aTookFocus
);
1604 nsCOMPtr
<nsIWebBrowserChromeFocus
> chromeFocus
= do_GetInterface(mTreeOwner
);
1607 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusNextElement());
1609 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusPrevElement());
1611 *aTookFocus
= PR_FALSE
;
1617 nsDocShell::GetSecurityUI(nsISecureBrowserUI
**aSecurityUI
)
1619 NS_IF_ADDREF(*aSecurityUI
= mSecurityUI
);
1624 nsDocShell::SetSecurityUI(nsISecureBrowserUI
*aSecurityUI
)
1626 mSecurityUI
= aSecurityUI
;
1631 nsDocShell::GetUseErrorPages(PRBool
*aUseErrorPages
)
1633 *aUseErrorPages
= mUseErrorPages
;
1638 nsDocShell::SetUseErrorPages(PRBool aUseErrorPages
)
1640 // If mUseErrorPages is set explicitly, stop observing the pref.
1641 if (mObserveErrorPages
) {
1642 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
));
1644 prefs
->RemoveObserver("browser.xul.error_pages.enabled", this);
1645 mObserveErrorPages
= PR_FALSE
;
1648 mUseErrorPages
= aUseErrorPages
;
1653 nsDocShell::GetPreviousTransIndex(PRInt32
*aPreviousTransIndex
)
1655 *aPreviousTransIndex
= mPreviousTransIndex
;
1660 nsDocShell::GetLoadedTransIndex(PRInt32
*aLoadedTransIndex
)
1662 *aLoadedTransIndex
= mLoadedTransIndex
;
1667 nsDocShell::HistoryPurged(PRInt32 aNumEntries
)
1669 // These indices are used for fastback cache eviction, to determine
1670 // which session history entries are candidates for content viewer
1671 // eviction. We need to adjust by the number of entries that we
1672 // just purged from history, so that we look at the right session history
1673 // entries during eviction.
1674 mPreviousTransIndex
= PR_MAX(-1, mPreviousTransIndex
- aNumEntries
);
1675 mLoadedTransIndex
= PR_MAX(0, mLoadedTransIndex
- aNumEntries
);
1677 PRInt32 count
= mChildList
.Count();
1678 for (PRInt32 i
= 0; i
< count
; ++i
) {
1679 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
1681 shell
->HistoryPurged(aNumEntries
);
1689 nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal
* aPrincipal
,
1691 nsIDOMStorage
** aStorage
)
1693 NS_ENSURE_ARG_POINTER(aStorage
);
1699 nsCOMPtr
<nsIURI
> codebaseURI
;
1700 nsresult rv
= aPrincipal
->GetDomain(getter_AddRefs(codebaseURI
));
1701 NS_ENSURE_SUCCESS(rv
, rv
);
1703 rv
= aPrincipal
->GetURI(getter_AddRefs(codebaseURI
));
1704 NS_ENSURE_SUCCESS(rv
, rv
);
1710 rv
= GetSessionStorageForURI(codebaseURI
, aCreate
, aStorage
);
1711 NS_ENSURE_SUCCESS(rv
, rv
);
1713 nsCOMPtr
<nsPIDOMStorage
> piStorage
= do_QueryInterface(*aStorage
);
1715 PRBool canAccess
= piStorage
->CanAccess(aPrincipal
);
1716 NS_ASSERTION(canAccess
,
1717 "GetSessionStorageForPrincipal got a storage "
1718 "that could not be accessed!");
1720 NS_RELEASE(*aStorage
);
1721 return NS_ERROR_DOM_SECURITY_ERR
;
1729 nsDocShell::GetSessionStorageForURI(nsIURI
* aURI
,
1730 nsIDOMStorage
** aStorage
)
1732 return GetSessionStorageForURI(aURI
, PR_TRUE
, aStorage
);
1736 nsDocShell::GetSessionStorageForURI(nsIURI
* aURI
,
1738 nsIDOMStorage
** aStorage
)
1740 NS_ENSURE_ARG(aURI
);
1741 NS_ENSURE_ARG_POINTER(aStorage
);
1745 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(aURI
);
1746 NS_ASSERTION(innerURI
, "Failed to get innermost URI");
1748 return NS_ERROR_FAILURE
;
1750 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
1751 nsresult rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
1756 return NS_ERROR_FAILURE
;
1758 nsDocShell
* topDocShell
= static_cast<nsDocShell
*>(topItem
.get());
1759 if (topDocShell
!= this)
1760 return topDocShell
->GetSessionStorageForURI(aURI
, aCreate
, aStorage
);
1762 nsCAutoString currentDomain
;
1763 rv
= innerURI
->GetAsciiHost(currentDomain
);
1764 NS_ENSURE_SUCCESS(rv
, rv
);
1766 if (currentDomain
.IsEmpty())
1769 if (!mStorages
.Get(currentDomain
, aStorage
) && aCreate
) {
1770 nsCOMPtr
<nsIDOMStorage
> newstorage
=
1771 do_CreateInstance("@mozilla.org/dom/storage;1");
1773 return NS_ERROR_OUT_OF_MEMORY
;
1775 nsCOMPtr
<nsPIDOMStorage
> pistorage
= do_QueryInterface(newstorage
);
1777 return NS_ERROR_FAILURE
;
1778 pistorage
->Init(NS_ConvertUTF8toUTF16(currentDomain
), PR_FALSE
);
1780 if (!mStorages
.Put(currentDomain
, newstorage
))
1781 return NS_ERROR_OUT_OF_MEMORY
;
1783 newstorage
.swap(*aStorage
);
1790 nsDocShell::AddSessionStorage(const nsACString
& aDomain
,
1791 nsIDOMStorage
* aStorage
)
1793 NS_ENSURE_ARG_POINTER(aStorage
);
1795 if (aDomain
.IsEmpty())
1798 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
1799 nsresult rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
1804 nsCOMPtr
<nsIDocShell
> topDocShell
= do_QueryInterface(topItem
);
1805 if (topDocShell
== this) {
1806 // Do not replace an existing session storage.
1807 if (mStorages
.GetWeak(aDomain
))
1808 return NS_ERROR_NOT_AVAILABLE
;
1810 if (!mStorages
.Put(aDomain
, aStorage
))
1811 return NS_ERROR_OUT_OF_MEMORY
;
1814 return topDocShell
->AddSessionStorage(aDomain
, aStorage
);
1822 nsDocShell::GetCurrentDocumentChannel(nsIChannel
** aResult
)
1825 if (!mContentViewer
)
1828 nsCOMPtr
<nsIDOMDocument
> domDoc
;
1829 nsresult rv
= mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
1833 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(domDoc
));
1835 *aResult
= doc
->GetChannel();
1836 NS_IF_ADDREF(*aResult
);
1842 //*****************************************************************************
1843 // nsDocShell::nsIDocShellTreeItem
1844 //*****************************************************************************
1847 nsDocShell::GetName(PRUnichar
** aName
)
1849 NS_ENSURE_ARG_POINTER(aName
);
1850 *aName
= ToNewUnicode(mName
);
1855 nsDocShell::SetName(const PRUnichar
* aName
)
1857 mName
= aName
; // this does a copy of aName
1862 nsDocShell::NameEquals(const PRUnichar
*aName
, PRBool
*_retval
)
1864 NS_ENSURE_ARG_POINTER(aName
);
1865 NS_ENSURE_ARG_POINTER(_retval
);
1866 *_retval
= mName
.Equals(aName
);
1871 nsDocShell::GetItemType(PRInt32
* aItemType
)
1873 NS_ENSURE_ARG_POINTER(aItemType
);
1875 *aItemType
= mItemType
;
1880 nsDocShell::SetItemType(PRInt32 aItemType
)
1882 NS_ENSURE_ARG((aItemType
== typeChrome
) || (typeContent
== aItemType
));
1884 // Only allow setting the type on root docshells. Those would be the ones
1885 // that have the docloader service as mParent or have no mParent at all.
1886 nsCOMPtr
<nsIDocumentLoader
> docLoaderService
=
1887 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
1888 NS_ENSURE_TRUE(docLoaderService
, NS_ERROR_UNEXPECTED
);
1890 NS_ENSURE_STATE(!mParent
|| mParent
== docLoaderService
);
1892 mItemType
= aItemType
;
1894 // disable auth prompting for anything but content
1895 mAllowAuth
= mItemType
== typeContent
;
1901 nsDocShell::GetParent(nsIDocShellTreeItem
** aParent
)
1906 CallQueryInterface(mParent
, aParent
);
1908 // Note that in the case when the parent is not an nsIDocShellTreeItem we
1909 // don't want to throw; we just want to return null.
1914 nsDocShell::SetDocLoaderParent(nsDocLoader
* aParent
)
1916 nsDocLoader::SetDocLoaderParent(aParent
);
1918 // Curse ambiguous nsISupports inheritance!
1919 nsISupports
* parent
= GetAsSupports(aParent
);
1921 // If parent is another docshell, we inherit all their flags for
1922 // allowing plugins, scripting etc.
1923 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(parent
));
1924 if (parentAsDocShell
)
1927 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowPlugins(&value
)))
1929 SetAllowPlugins(value
);
1931 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowJavascript(&value
)))
1933 SetAllowJavascript(value
);
1935 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowMetaRedirects(&value
)))
1937 SetAllowMetaRedirects(value
);
1939 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowSubframes(&value
)))
1941 SetAllowSubframes(value
);
1943 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowImages(&value
)))
1945 SetAllowImages(value
);
1949 nsCOMPtr
<nsIURIContentListener
> parentURIListener(do_GetInterface(parent
));
1950 if (parentURIListener
)
1951 mContentListener
->SetParentContentListener(parentURIListener
);
1956 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem
** aParent
)
1958 NS_ENSURE_ARG_POINTER(aParent
);
1961 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
1962 do_QueryInterface(GetAsSupports(mParent
));
1967 NS_ENSURE_SUCCESS(parent
->GetItemType(&parentType
), NS_ERROR_FAILURE
);
1969 if (parentType
== mItemType
) {
1970 parent
.swap(*aParent
);
1976 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
1978 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
1979 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
1981 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
1982 NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent
)), NS_ERROR_FAILURE
);
1984 *aRootTreeItem
= parent
;
1985 NS_ENSURE_SUCCESS((*aRootTreeItem
)->GetParent(getter_AddRefs(parent
)),
1988 NS_ADDREF(*aRootTreeItem
);
1993 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
1995 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
1996 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
1998 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
1999 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent
)),
2002 *aRootTreeItem
= parent
;
2003 NS_ENSURE_SUCCESS((*aRootTreeItem
)->
2004 GetSameTypeParent(getter_AddRefs(parent
)),
2007 NS_ADDREF(*aRootTreeItem
);
2013 nsDocShell::CanAccessItem(nsIDocShellTreeItem
* aTargetItem
,
2014 nsIDocShellTreeItem
* aAccessingItem
,
2015 PRBool aConsiderOpener
)
2017 NS_PRECONDITION(aTargetItem
, "Must have target item!");
2019 if (!gValidateOrigin
|| !aAccessingItem
) {
2024 // XXXbz should we care if aAccessingItem or the document therein is
2025 // chrome? Should those get extra privileges?
2027 // For historical context, see:
2029 // Bug 13871: Prevent frameset spoofing
2030 // Bug 103638: Targets with same name in different windows open in wrong
2031 // window with javascript
2032 // Bug 408052: Adopt "ancestor" frame navigation policy
2034 // Now do a security check
2036 // Allow navigation if
2037 // 1) aAccessingItem can script aTargetItem or one of its ancestors in
2038 // the frame hierarchy or
2039 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
2040 // 3) aTargetItem is a top-level frame and aAccessingItem can target
2041 // its opener per rule (1) or (2).
2043 if (aTargetItem
== aAccessingItem
) {
2044 // A frame is allowed to navigate itself.
2048 nsCOMPtr
<nsIDocShellTreeItem
> accessingRoot
;
2049 aAccessingItem
->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot
));
2051 if (aTargetItem
== accessingRoot
) {
2052 // A frame can navigate its root.
2056 // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
2057 nsCOMPtr
<nsIDocShellTreeItem
> target
= aTargetItem
;
2059 if (ValidateOrigin(aAccessingItem
, target
)) {
2063 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2064 target
->GetSameTypeParent(getter_AddRefs(parent
));
2065 parent
.swap(target
);
2068 nsCOMPtr
<nsIDocShellTreeItem
> targetRoot
;
2069 aTargetItem
->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot
));
2071 if (aTargetItem
!= targetRoot
) {
2072 // target is a subframe, not in accessor's frame hierarchy, and all its
2073 // ancestors have origins different from that of the accessor. Don't
2078 if (!aConsiderOpener
) {
2083 nsCOMPtr
<nsIDOMWindow
> targetWindow(do_GetInterface(aTargetItem
));
2084 nsCOMPtr
<nsIDOMWindowInternal
> targetInternal(do_QueryInterface(targetWindow
));
2085 if (!targetInternal
) {
2086 NS_ERROR("This should not happen, really");
2090 nsCOMPtr
<nsIDOMWindowInternal
> targetOpener
;
2091 targetInternal
->GetOpener(getter_AddRefs(targetOpener
));
2092 nsCOMPtr
<nsIWebNavigation
> openerWebNav(do_GetInterface(targetOpener
));
2093 nsCOMPtr
<nsIDocShellTreeItem
> openerItem(do_QueryInterface(openerWebNav
));
2099 return CanAccessItem(openerItem
, aAccessingItem
, PR_FALSE
);
2103 ItemIsActive(nsIDocShellTreeItem
*aItem
)
2105 nsCOMPtr
<nsIDOMWindow
> tmp(do_GetInterface(aItem
));
2106 nsCOMPtr
<nsIDOMWindowInternal
> window(do_QueryInterface(tmp
));
2111 if (NS_SUCCEEDED(window
->GetClosed(&isClosed
)) && !isClosed
) {
2120 nsDocShell::FindItemWithName(const PRUnichar
* aName
,
2121 nsISupports
* aRequestor
,
2122 nsIDocShellTreeItem
* aOriginalRequestor
,
2123 nsIDocShellTreeItem
** _retval
)
2125 NS_ENSURE_ARG(aName
);
2126 NS_ENSURE_ARG_POINTER(_retval
);
2128 // If we don't find one, we return NS_OK and a null result
2136 nsCOMPtr
<nsIDocShellTreeItem
> foundItem
;
2138 // This is the entry point into the target-finding algorithm. Check
2139 // for special names. This should only be done once, hence the check
2140 // for a null aRequestor.
2142 nsDependentString
name(aName
);
2143 if (name
.LowerCaseEqualsLiteral("_self")) {
2146 else if (name
.LowerCaseEqualsLiteral("_blank"))
2148 // Just return null. Caller must handle creating a new window with
2149 // a blank name himself.
2152 else if (name
.LowerCaseEqualsLiteral("_parent"))
2154 GetSameTypeParent(getter_AddRefs(foundItem
));
2158 else if (name
.LowerCaseEqualsLiteral("_top"))
2160 GetSameTypeRootTreeItem(getter_AddRefs(foundItem
));
2161 NS_ASSERTION(foundItem
, "Must have this; worst case it's us!");
2163 // _main is an IE target which should be case-insensitive but isn't
2164 // see bug 217886 for details
2165 else if (name
.LowerCaseEqualsLiteral("_content") ||
2166 name
.EqualsLiteral("_main"))
2168 // Must pass our same type root as requestor to the
2169 // treeowner to make sure things work right.
2170 nsCOMPtr
<nsIDocShellTreeItem
> root
;
2171 GetSameTypeRootTreeItem(getter_AddRefs(root
));
2173 NS_ASSERTION(root
, "Must have this; worst case it's us!");
2174 mTreeOwner
->FindItemWithName(aName
, root
, aOriginalRequestor
,
2175 getter_AddRefs(foundItem
));
2179 NS_ERROR("Someone isn't setting up the tree owner. "
2180 "You might like to try that. "
2181 "Things will.....you know, work.");
2182 // Note: _content should always exist. If we don't have one
2183 // hanging off the treeowner, just create a named window....
2184 // so don't return here, in case we did that and can now find
2186 // XXXbz should we be using |root| instead of creating
2192 if (foundItem
&& !CanAccessItem(foundItem
, aOriginalRequestor
)) {
2197 // We return foundItem here even if it's not an active
2198 // item since all the names we've dealt with so far are
2199 // special cases that we won't bother looking for further.
2201 foundItem
.swap(*_retval
);
2208 // First we check our name.
2209 if (mName
.Equals(aName
) && ItemIsActive(this) &&
2210 CanAccessItem(this, aOriginalRequestor
)) {
2211 NS_ADDREF(*_retval
= this);
2215 // This QI may fail, but the places where we want to compare, comparing
2216 // against nsnull serves the same purpose.
2217 nsCOMPtr
<nsIDocShellTreeItem
> reqAsTreeItem(do_QueryInterface(aRequestor
));
2219 // Second we check our children making sure not to ask a child if
2220 // it is the aRequestor.
2224 FindChildWithName(aName
, PR_TRUE
, PR_TRUE
, reqAsTreeItem
,
2225 aOriginalRequestor
, _retval
);
2226 NS_ASSERTION(NS_SUCCEEDED(rv
),
2227 "FindChildWithName should not be failing here.");
2231 // Third if we have a parent and it isn't the requestor then we
2232 // should ask it to do the search. If it is the requestor we
2233 // should just stop here and let the parent do the rest. If we
2234 // don't have a parent, then we should ask the
2235 // docShellTreeOwner to do the search.
2236 nsCOMPtr
<nsIDocShellTreeItem
> parentAsTreeItem
=
2237 do_QueryInterface(GetAsSupports(mParent
));
2238 if (parentAsTreeItem
) {
2239 if (parentAsTreeItem
== reqAsTreeItem
)
2243 parentAsTreeItem
->GetItemType(&parentType
);
2244 if (parentType
== mItemType
) {
2245 return parentAsTreeItem
->
2246 FindItemWithName(aName
,
2247 static_cast<nsIDocShellTreeItem
*>
2254 // If the parent is null or not of the same type fall through and ask tree
2257 // This may fail, but comparing against null serves the same purpose
2258 nsCOMPtr
<nsIDocShellTreeOwner
>
2259 reqAsTreeOwner(do_QueryInterface(aRequestor
));
2261 if (mTreeOwner
&& mTreeOwner
!= reqAsTreeOwner
) {
2263 FindItemWithName(aName
, this, aOriginalRequestor
, _retval
);
2270 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner
** aTreeOwner
)
2272 NS_ENSURE_ARG_POINTER(aTreeOwner
);
2274 *aTreeOwner
= mTreeOwner
;
2275 NS_IF_ADDREF(*aTreeOwner
);
2279 #ifdef DEBUG_DOCSHELL_FOCUS
2281 PrintDocTree(nsIDocShellTreeItem
* aParentNode
, int aLevel
)
2283 for (PRInt32 i
=0;i
<aLevel
;i
++) printf(" ");
2285 PRInt32 childWebshellCount
;
2286 aParentNode
->GetChildCount(&childWebshellCount
);
2287 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(aParentNode
));
2289 aParentNode
->GetItemType(&type
);
2290 nsCOMPtr
<nsIPresShell
> presShell
;
2291 parentAsDocShell
->GetPresShell(getter_AddRefs(presShell
));
2292 nsCOMPtr
<nsPresContext
> presContext
;
2293 parentAsDocShell
->GetPresContext(getter_AddRefs(presContext
));
2294 nsIDocument
*doc
= presShell
->GetDocument();
2296 nsCOMPtr
<nsIDOMWindowInternal
> domwin(doc
->GetWindow());
2298 nsCOMPtr
<nsIWidget
> widget
;
2299 nsIViewManager
* vm
= presShell
->GetViewManager();
2301 vm
->GetWidget(getter_AddRefs(widget
));
2303 nsIContent
* rootContent
= doc
->GetRootContent();
2305 printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
2306 (void*)parentAsDocShell
.get(),
2307 type
==nsIDocShellTreeItem::typeChrome
?"Chr":"Con",
2308 (void*)doc
, (void*)domwin
.get(),
2309 (void*)presContext
->EventStateManager(), (void*)rootContent
);
2311 if (childWebshellCount
> 0) {
2312 for (PRInt32 i
=0;i
<childWebshellCount
;i
++) {
2313 nsCOMPtr
<nsIDocShellTreeItem
> child
;
2314 aParentNode
->GetChildAt(i
, getter_AddRefs(child
));
2315 PrintDocTree(child
, aLevel
+1);
2321 PrintDocTree(nsIDocShellTreeItem
* aParentNode
)
2323 NS_ASSERTION(aParentNode
, "Pointer is null!");
2325 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
2326 aParentNode
->GetParent(getter_AddRefs(parentItem
));
2327 while (parentItem
) {
2328 nsCOMPtr
<nsIDocShellTreeItem
>tmp
;
2329 parentItem
->GetParent(getter_AddRefs(tmp
));
2337 parentItem
= aParentNode
;
2340 PrintDocTree(parentItem
, 0);
2345 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
)
2347 #ifdef DEBUG_DOCSHELL_FOCUS
2348 nsCOMPtr
<nsIDocShellTreeItem
> item(do_QueryInterface(aTreeOwner
));
2354 // Don't automatically set the progress based on the tree owner for frames
2356 nsCOMPtr
<nsIWebProgress
> webProgress
=
2357 do_QueryInterface(GetAsSupports(this));
2360 nsCOMPtr
<nsIWebProgressListener
>
2361 oldListener(do_QueryInterface(mTreeOwner
));
2362 nsCOMPtr
<nsIWebProgressListener
>
2363 newListener(do_QueryInterface(aTreeOwner
));
2366 webProgress
->RemoveProgressListener(oldListener
);
2370 webProgress
->AddProgressListener(newListener
,
2371 nsIWebProgress::NOTIFY_ALL
);
2376 mTreeOwner
= aTreeOwner
; // Weak reference per API
2378 PRInt32 i
, n
= mChildList
.Count();
2379 for (i
= 0; i
< n
; i
++) {
2380 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryInterface(ChildAt(i
));
2381 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
2382 PRInt32 childType
= ~mItemType
; // Set it to not us in case the get fails
2383 child
->GetItemType(&childType
); // We don't care if this fails, if it does we won't set the owner
2384 if (childType
== mItemType
)
2385 child
->SetTreeOwner(aTreeOwner
);
2392 nsDocShell::SetChildOffset(PRUint32 aChildOffset
)
2394 mChildOffset
= aChildOffset
;
2399 nsDocShell::GetIsInUnload(PRBool
* aIsInUnload
)
2401 *aIsInUnload
= mFiredUnloadEvent
;
2405 //*****************************************************************************
2406 // nsDocShell::nsIDocShellTreeNode
2407 //*****************************************************************************
2410 nsDocShell::GetChildCount(PRInt32
* aChildCount
)
2412 NS_ENSURE_ARG_POINTER(aChildCount
);
2413 *aChildCount
= mChildList
.Count();
2420 nsDocShell::AddChild(nsIDocShellTreeItem
* aChild
)
2422 NS_ENSURE_ARG_POINTER(aChild
);
2424 nsRefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
2425 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
2427 // Make sure we're not creating a loop in the docshell tree
2428 nsDocLoader
* ancestor
= this;
2430 if (childAsDocLoader
== ancestor
) {
2431 return NS_ERROR_ILLEGAL_VALUE
;
2433 ancestor
= ancestor
->GetParent();
2436 // Make sure to remove the child from its current parent.
2437 nsDocLoader
* childsParent
= childAsDocLoader
->GetParent();
2439 childsParent
->RemoveChildLoader(childAsDocLoader
);
2442 // Make sure to clear the treeowner in case this child is a different type
2444 aChild
->SetTreeOwner(nsnull
);
2446 nsresult res
= AddChildLoader(childAsDocLoader
);
2447 NS_ENSURE_SUCCESS(res
, res
);
2448 NS_ASSERTION(mChildList
.Count() > 0,
2449 "child list must not be empty after a successful add");
2451 // Set the child's index in the parent's children list
2452 // XXX What if the parent had different types of children?
2453 // XXX in that case docshell hierarchy and SH hierarchy won't match.
2455 nsCOMPtr
<nsIDocShell
> childDocShell
= do_QueryInterface(aChild
);
2456 if (childDocShell
) {
2457 // If there are frameloaders in the finalization list, reduce
2458 // the offset so that the SH hierarchy is more likely to match the
2459 // docshell hierarchy
2460 nsCOMPtr
<nsIDOMDocument
> domDoc
=
2461 do_GetInterface(GetAsSupports(this));
2462 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
2463 PRUint32 offset
= mChildList
.Count() - 1;
2465 PRUint32 oldChildCount
= offset
; // Current child count - 1
2466 for (PRUint32 i
= 0; i
< oldChildCount
; ++i
) {
2467 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
2468 if (doc
->FrameLoaderScheduledToBeFinalized(child
)) {
2474 childDocShell
->SetChildOffset(offset
);
2478 /* Set the child's global history if the parent has one */
2479 if (mGlobalHistory
) {
2480 nsCOMPtr
<nsIDocShellHistory
>
2481 dsHistoryChild(do_QueryInterface(aChild
));
2483 dsHistoryChild
->SetUseGlobalHistory(PR_TRUE
);
2487 PRInt32 childType
= ~mItemType
; // Set it to not us in case the get fails
2488 aChild
->GetItemType(&childType
);
2489 if (childType
!= mItemType
)
2491 // Everything below here is only done when the child is the same type.
2494 aChild
->SetTreeOwner(mTreeOwner
);
2496 nsCOMPtr
<nsIDocShell
> childAsDocShell(do_QueryInterface(aChild
));
2497 if (!childAsDocShell
)
2500 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
2502 // Now take this document's charset and set the parentCharset field of the
2503 // child's DocumentCharsetInfo to it. We'll later use that field, in the
2504 // loading process, for the charset choosing algorithm.
2505 // If we fail, at any point, we just return NS_OK.
2506 // This code has some performance impact. But this will be reduced when
2507 // the current charset will finally be stored as an Atom, avoiding the
2508 // alias resolution extra look-up.
2510 // we are NOT going to propagate the charset is this Chrome's docshell
2511 if (mItemType
== nsIDocShellTreeItem::typeChrome
)
2514 // get the child's docCSInfo object
2515 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
= NULL
;
2516 res
= childAsDocShell
->GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
2517 if (NS_FAILED(res
) || (!dcInfo
))
2520 // get the parent's current charset
2521 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(mContentViewer
));
2524 nsCOMPtr
<nsIDocument
> doc
;
2525 res
= docv
->GetDocument(getter_AddRefs(doc
));
2526 if (NS_FAILED(res
) || (!doc
))
2528 const nsACString
&parentCS
= doc
->GetDocumentCharacterSet();
2530 PRBool isWyciwyg
= PR_FALSE
;
2533 // Check if the url is wyciwyg
2534 mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
2538 // If this docshell is loaded from a wyciwyg: URI, don't
2539 // advertise our charset since it does not in any way reflect
2540 // the actual source charset, which is what we're trying to
2543 // set the child's parentCharset
2544 nsCOMPtr
<nsIAtom
> parentCSAtom(do_GetAtom(parentCS
));
2545 res
= dcInfo
->SetParentCharset(parentCSAtom
);
2549 PRInt32 charsetSource
= doc
->GetDocumentCharacterSetSource();
2551 // set the child's parentCharset
2552 res
= dcInfo
->SetParentCharsetSource(charsetSource
);
2557 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
2563 nsDocShell::RemoveChild(nsIDocShellTreeItem
* aChild
)
2565 NS_ENSURE_ARG_POINTER(aChild
);
2567 nsRefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
2568 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
2570 nsresult rv
= RemoveChildLoader(childAsDocLoader
);
2571 NS_ENSURE_SUCCESS(rv
, rv
);
2573 aChild
->SetTreeOwner(nsnull
);
2575 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader
);
2579 nsDocShell::GetChildAt(PRInt32 aIndex
, nsIDocShellTreeItem
** aChild
)
2581 NS_ENSURE_ARG_POINTER(aChild
);
2585 NS_WARNING("Negative index passed to GetChildAt");
2587 else if (aIndex
>= mChildList
.Count()) {
2588 NS_WARNING("Too large an index passed to GetChildAt");
2592 nsIDocumentLoader
* child
= SafeChildAt(aIndex
);
2593 NS_ENSURE_TRUE(child
, NS_ERROR_UNEXPECTED
);
2595 return CallQueryInterface(child
, aChild
);
2599 nsDocShell::FindChildWithName(const PRUnichar
* aName
,
2600 PRBool aRecurse
, PRBool aSameType
,
2601 nsIDocShellTreeItem
* aRequestor
,
2602 nsIDocShellTreeItem
* aOriginalRequestor
,
2603 nsIDocShellTreeItem
** _retval
)
2605 NS_ENSURE_ARG(aName
);
2606 NS_ENSURE_ARG_POINTER(_retval
);
2608 *_retval
= nsnull
; // if we don't find one, we return NS_OK and a null result
2613 nsXPIDLString childName
;
2614 PRInt32 i
, n
= mChildList
.Count();
2615 for (i
= 0; i
< n
; i
++) {
2616 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryInterface(ChildAt(i
));
2617 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
2619 child
->GetItemType(&childType
);
2621 if (aSameType
&& (childType
!= mItemType
))
2624 PRBool childNameEquals
= PR_FALSE
;
2625 child
->NameEquals(aName
, &childNameEquals
);
2626 if (childNameEquals
&& ItemIsActive(child
) &&
2627 CanAccessItem(child
, aOriginalRequestor
)) {
2628 child
.swap(*_retval
);
2632 if (childType
!= mItemType
) //Only ask it to check children if it is same type
2635 if (aRecurse
&& (aRequestor
!= child
)) // Only ask the child if it isn't the requestor
2637 // See if child contains the shell with the given name
2641 child
->FindChildWithName(aName
, PR_TRUE
,
2643 static_cast<nsIDocShellTreeItem
*>
2647 NS_ASSERTION(NS_SUCCEEDED(rv
),
2648 "FindChildWithName should not fail here");
2649 if (*_retval
) // found it
2656 //*****************************************************************************
2657 // nsDocShell::nsIDocShellHistory
2658 //*****************************************************************************
2660 nsDocShell::GetChildSHEntry(PRInt32 aChildOffset
, nsISHEntry
** aResult
)
2662 nsresult rv
= NS_OK
;
2664 NS_ENSURE_ARG_POINTER(aResult
);
2668 // A nsISHEntry for a child is *only* available when the parent is in
2669 // the progress of loading a document too...
2672 /* Before looking for the subframe's url, check
2673 * the expiration status of the parent. If the parent
2674 * has expired from cache, then subframes will not be
2675 * loaded from history in certain situations.
2677 PRBool parentExpired
=PR_FALSE
;
2678 mLSHE
->GetExpirationStatus(&parentExpired
);
2680 /* Get the parent's Load Type so that it can be set on the child too.
2681 * By default give a loadHistory value
2683 PRUint32 loadType
= nsIDocShellLoadInfo::loadHistory
;
2684 mLSHE
->GetLoadType(&loadType
);
2685 // If the user did a shift-reload on this frameset page,
2686 // we don't want to load the subframes from history.
2687 if (loadType
== nsIDocShellLoadInfo::loadReloadBypassCache
||
2688 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxy
||
2689 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
||
2690 loadType
== nsIDocShellLoadInfo::loadRefresh
)
2693 /* If the user pressed reload and the parent frame has expired
2694 * from cache, we do not want to load the child frame from history.
2696 if (parentExpired
&& (loadType
== nsIDocShellLoadInfo::loadReloadNormal
)) {
2697 // The parent has expired. Return null.
2702 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
));
2704 // Get the child subframe from session history.
2705 rv
= container
->GetChildAt(aChildOffset
, aResult
);
2707 (*aResult
)->SetLoadType(loadType
);
2714 nsDocShell::AddChildSHEntry(nsISHEntry
* aCloneRef
, nsISHEntry
* aNewEntry
,
2715 PRInt32 aChildOffset
)
2720 /* You get here if you are currently building a
2721 * hierarchy ie.,you just visited a frameset page
2723 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
, &rv
));
2725 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
2728 else if (!aCloneRef
) {
2729 /* This is an initial load in some subframe. Just append it if we can */
2730 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mOSHE
, &rv
));
2732 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
2735 else if (mSessionHistory
) {
2736 /* You are currently in the rootDocShell.
2737 * You will get here when a subframe has a new url
2738 * to load and you have walked up the tree all the
2739 * way to the top to clone the current SHEntry hierarchy
2740 * and replace the subframe where a new url was loaded with
2744 nsCOMPtr
<nsIHistoryEntry
> currentHE
;
2745 mSessionHistory
->GetIndex(&index
);
2747 return NS_ERROR_FAILURE
;
2749 rv
= mSessionHistory
->GetEntryAtIndex(index
, PR_FALSE
,
2750 getter_AddRefs(currentHE
));
2751 NS_ENSURE_TRUE(currentHE
, NS_ERROR_FAILURE
);
2753 nsCOMPtr
<nsISHEntry
> currentEntry(do_QueryInterface(currentHE
));
2755 PRUint32 cloneID
= 0;
2756 nsCOMPtr
<nsISHEntry
> nextEntry
;
2757 aCloneRef
->GetID(&cloneID
);
2758 rv
= CloneAndReplace(currentEntry
, this, cloneID
, aNewEntry
,
2759 getter_AddRefs(nextEntry
));
2761 if (NS_SUCCEEDED(rv
)) {
2762 nsCOMPtr
<nsISHistoryInternal
>
2763 shPrivate(do_QueryInterface(mSessionHistory
));
2764 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
2765 rv
= shPrivate
->AddEntry(nextEntry
, PR_TRUE
);
2770 /* Just pass this along */
2771 nsCOMPtr
<nsIDocShellHistory
> parent
=
2772 do_QueryInterface(GetAsSupports(mParent
), &rv
);
2774 rv
= parent
->AddChildSHEntry(aCloneRef
, aNewEntry
, aChildOffset
);
2781 nsDocShell::DoAddChildSHEntry(nsISHEntry
* aNewEntry
, PRInt32 aChildOffset
)
2783 /* You will get here when you are in a subframe and
2784 * a new url has been loaded on you.
2785 * The mOSHE in this subframe will be the previous url's
2786 * mOSHE. This mOSHE will be used as the identification
2787 * for this subframe in the CloneAndReplace function.
2790 // In this case, we will end up calling AddEntry, which increases the
2791 // current index by 1
2792 nsCOMPtr
<nsISHistory
> rootSH
;
2793 GetRootSessionHistory(getter_AddRefs(rootSH
));
2795 rootSH
->GetIndex(&mPreviousTransIndex
);
2799 nsCOMPtr
<nsIDocShellHistory
> parent
=
2800 do_QueryInterface(GetAsSupports(mParent
), &rv
);
2802 rv
= parent
->AddChildSHEntry(mOSHE
, aNewEntry
, aChildOffset
);
2807 rootSH
->GetIndex(&mLoadedTransIndex
);
2808 #ifdef DEBUG_PAGE_CACHE
2809 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
2818 nsDocShell::SetUseGlobalHistory(PRBool aUseGlobalHistory
)
2822 if (!aUseGlobalHistory
) {
2823 mGlobalHistory
= nsnull
;
2827 if (mGlobalHistory
) {
2831 mGlobalHistory
= do_GetService(NS_GLOBALHISTORY2_CONTRACTID
, &rv
);
2836 nsDocShell::GetUseGlobalHistory(PRBool
*aUseGlobalHistory
)
2838 *aUseGlobalHistory
= (mGlobalHistory
!= nsnull
);
2842 //-------------------------------------
2843 //-- Helper Method for Print discovery
2844 //-------------------------------------
2846 nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog
)
2848 if (mIsPrintingOrPP
&& aDisplayErrorDialog
) {
2849 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE
, nsnull
, nsnull
);
2852 return mIsPrintingOrPP
;
2856 nsDocShell::IsNavigationAllowed(PRBool aDisplayPrintErrorDialog
)
2858 return !IsPrintingOrPP(aDisplayPrintErrorDialog
) && !mFiredUnloadEvent
;
2861 //*****************************************************************************
2862 // nsDocShell::nsIWebNavigation
2863 //*****************************************************************************
2866 nsDocShell::GetCanGoBack(PRBool
* aCanGoBack
)
2868 if (!IsNavigationAllowed(PR_FALSE
)) {
2869 *aCanGoBack
= PR_FALSE
;
2870 return NS_OK
; // JS may not handle returning of an error code
2873 nsCOMPtr
<nsISHistory
> rootSH
;
2874 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
2875 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
2876 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
2877 rv
= webnav
->GetCanGoBack(aCanGoBack
);
2883 nsDocShell::GetCanGoForward(PRBool
* aCanGoForward
)
2885 if (!IsNavigationAllowed(PR_FALSE
)) {
2886 *aCanGoForward
= PR_FALSE
;
2887 return NS_OK
; // JS may not handle returning of an error code
2890 nsCOMPtr
<nsISHistory
> rootSH
;
2891 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
2892 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
2893 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
2894 rv
= webnav
->GetCanGoForward(aCanGoForward
);
2900 nsDocShell::GoBack()
2902 if (!IsNavigationAllowed()) {
2903 return NS_OK
; // JS may not handle returning of an error code
2906 nsCOMPtr
<nsISHistory
> rootSH
;
2907 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
2908 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
2909 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
2910 rv
= webnav
->GoBack();
2916 nsDocShell::GoForward()
2918 if (!IsNavigationAllowed()) {
2919 return NS_OK
; // JS may not handle returning of an error code
2922 nsCOMPtr
<nsISHistory
> rootSH
;
2923 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
2924 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
2925 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
2926 rv
= webnav
->GoForward();
2931 NS_IMETHODIMP
nsDocShell::GotoIndex(PRInt32 aIndex
)
2933 if (!IsNavigationAllowed()) {
2934 return NS_OK
; // JS may not handle returning of an error code
2937 nsCOMPtr
<nsISHistory
> rootSH
;
2938 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
2939 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
2940 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
2941 rv
= webnav
->GotoIndex(aIndex
);
2948 nsDocShell::LoadURI(const PRUnichar
* aURI
,
2949 PRUint32 aLoadFlags
,
2950 nsIURI
* aReferringURI
,
2951 nsIInputStream
* aPostStream
,
2952 nsIInputStream
* aHeaderStream
)
2954 NS_ASSERTION((aLoadFlags
& 0xf) == 0, "Unexpected flags");
2956 if (!IsNavigationAllowed()) {
2957 return NS_OK
; // JS may not handle returning of an error code
2959 nsCOMPtr
<nsIURI
> uri
;
2960 nsresult rv
= NS_OK
;
2962 // Create a URI from our string; if that succeeds, we want to
2963 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
2966 NS_ConvertUTF16toUTF8
uriString(aURI
);
2967 // Cleanup the empty spaces that might be on each end.
2968 uriString
.Trim(" ");
2969 // Eliminate embedded newlines, which single-line text fields now allow:
2970 uriString
.StripChars("\r\n");
2971 NS_ENSURE_TRUE(!uriString
.IsEmpty(), NS_ERROR_FAILURE
);
2973 rv
= NS_NewURI(getter_AddRefs(uri
), uriString
);
2975 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
2979 // Call the fixup object. This will clobber the rv from NS_NewURI
2980 // above, but that's fine with us. Note that we need to do this even
2981 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
2982 // (things like view-source:mozilla.org for example).
2983 PRUint32 fixupFlags
= 0;
2984 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) {
2985 fixupFlags
|= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
;
2987 rv
= sURIFixup
->CreateFixupURI(uriString
, fixupFlags
,
2988 getter_AddRefs(uri
));
2990 // else no fixup service so just use the URI we created and see
2993 if (NS_ERROR_MALFORMED_URI
== rv
) {
2994 DisplayLoadError(rv
, uri
, aURI
);
2997 if (NS_FAILED(rv
) || !uri
)
2998 return NS_ERROR_FAILURE
;
3000 PopupControlState popupState
;
3001 if (aLoadFlags
& LOAD_FLAGS_ALLOW_POPUPS
) {
3002 popupState
= openAllowed
;
3003 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_POPUPS
;
3005 popupState
= openOverridden
;
3007 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
3008 nsAutoPopupStatePusher
statePusher(win
, popupState
);
3010 // Don't pass certain flags that aren't needed and end up confusing
3011 // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
3012 // passed to LoadURI though, since it uses them.
3013 PRUint32 extraFlags
= (aLoadFlags
& EXTRA_LOAD_FLAGS
);
3014 aLoadFlags
&= ~EXTRA_LOAD_FLAGS
;
3016 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
3017 rv
= CreateLoadInfo(getter_AddRefs(loadInfo
));
3018 if (NS_FAILED(rv
)) return rv
;
3020 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
3021 loadInfo
->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType
));
3022 loadInfo
->SetPostDataStream(aPostStream
);
3023 loadInfo
->SetReferrer(aReferringURI
);
3024 loadInfo
->SetHeadersStream(aHeaderStream
);
3026 rv
= LoadURI(uri
, loadInfo
, extraFlags
, PR_TRUE
);
3032 nsDocShell::DisplayLoadError(nsresult aError
, nsIURI
*aURI
,
3033 const PRUnichar
*aURL
,
3034 nsIChannel
* aFailedChannel
)
3036 // Get prompt and string bundle servcies
3037 nsCOMPtr
<nsIPrompt
> prompter
;
3038 nsCOMPtr
<nsIStringBundle
> stringBundle
;
3039 GetPromptAndStringBundle(getter_AddRefs(prompter
),
3040 getter_AddRefs(stringBundle
));
3042 NS_ENSURE_TRUE(stringBundle
, NS_ERROR_FAILURE
);
3043 NS_ENSURE_TRUE(prompter
, NS_ERROR_FAILURE
);
3046 const PRUint32 kMaxFormatStrArgs
= 3;
3047 nsAutoString formatStrs
[kMaxFormatStrArgs
];
3048 PRUint32 formatStrCount
= 0;
3049 PRBool addHostPort
= PR_FALSE
;
3050 nsresult rv
= NS_OK
;
3051 nsAutoString messageStr
;
3052 nsCAutoString cssClass
;
3053 nsCAutoString errorPage
;
3055 errorPage
.AssignLiteral("neterror");
3057 // Turn the error code into a human readable error message.
3058 if (NS_ERROR_UNKNOWN_PROTOCOL
== aError
) {
3059 NS_ENSURE_ARG_POINTER(aURI
);
3060 // extract the scheme
3061 nsCAutoString scheme
;
3062 aURI
->GetScheme(scheme
);
3063 CopyASCIItoUTF16(scheme
, formatStrs
[0]);
3065 error
.AssignLiteral("protocolNotFound");
3067 else if (NS_ERROR_FILE_NOT_FOUND
== aError
) {
3068 NS_ENSURE_ARG_POINTER(aURI
);
3069 error
.AssignLiteral("fileNotFound");
3071 else if (NS_ERROR_UNKNOWN_HOST
== aError
) {
3072 NS_ENSURE_ARG_POINTER(aURI
);
3075 nsCOMPtr
<nsIURI
> innermostURI
= NS_GetInnermostURI(aURI
);
3076 innermostURI
->GetHost(host
);
3077 CopyUTF8toUTF16(host
, formatStrs
[0]);
3079 error
.AssignLiteral("dnsNotFound");
3081 else if(NS_ERROR_CONNECTION_REFUSED
== aError
) {
3082 NS_ENSURE_ARG_POINTER(aURI
);
3083 addHostPort
= PR_TRUE
;
3084 error
.AssignLiteral("connectionFailure");
3086 else if(NS_ERROR_NET_INTERRUPT
== aError
) {
3087 NS_ENSURE_ARG_POINTER(aURI
);
3088 addHostPort
= PR_TRUE
;
3089 error
.AssignLiteral("netInterrupt");
3091 else if (NS_ERROR_NET_TIMEOUT
== aError
) {
3092 NS_ENSURE_ARG_POINTER(aURI
);
3095 aURI
->GetHost(host
);
3096 CopyUTF8toUTF16(host
, formatStrs
[0]);
3098 error
.AssignLiteral("netTimeout");
3100 else if (NS_ERROR_GET_MODULE(aError
) == NS_ERROR_MODULE_SECURITY
) {
3101 nsCOMPtr
<nsINSSErrorsService
> nsserr
=
3102 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID
);
3104 PRUint32 errorClass
;
3106 NS_FAILED(nsserr
->GetErrorClass(aError
, &errorClass
))) {
3107 errorClass
= nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL
;
3110 nsCOMPtr
<nsISupports
> securityInfo
;
3111 nsCOMPtr
<nsITransportSecurityInfo
> tsi
;
3113 aFailedChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
3114 tsi
= do_QueryInterface(securityInfo
);
3116 // Usually we should have aFailedChannel and get a detailed message
3117 tsi
->GetErrorMessage(getter_Copies(messageStr
));
3120 // No channel, let's obtain the generic error message
3122 nsserr
->GetErrorMessage(aError
, messageStr
);
3125 if (!messageStr
.IsEmpty()) {
3126 if (errorClass
== nsINSSErrorsService::ERROR_CLASS_BAD_CERT
) {
3127 error
.AssignLiteral("nssBadCert");
3128 PRBool expert
= PR_FALSE
;
3129 mPrefs
->GetBoolPref("browser.xul.error_pages.expert_bad_cert",
3132 cssClass
.AssignLiteral("expertBadCert");
3135 // See if an alternate cert error page is registered
3136 nsXPIDLCString alternateErrorPage
;
3137 mPrefs
->GetCharPref("security.alternate_certificate_error_page",
3138 getter_Copies(alternateErrorPage
));
3139 if (alternateErrorPage
)
3140 errorPage
.Assign(alternateErrorPage
);
3142 error
.AssignLiteral("nssFailure2");
3145 } else if (NS_ERROR_PHISHING_URI
== aError
|| NS_ERROR_MALWARE_URI
== aError
) {
3147 aURI
->GetHost(host
);
3148 CopyUTF8toUTF16(host
, formatStrs
[0]);
3151 // Malware and phishing detectors may want to use an alternate error
3152 // page, but if the pref's not set, we'll fall back on the standard page
3153 nsXPIDLCString alternateErrorPage
;
3154 mPrefs
->GetCharPref("urlclassifier.alternate_error_page",
3155 getter_Copies(alternateErrorPage
));
3156 if (alternateErrorPage
)
3157 errorPage
.Assign(alternateErrorPage
);
3159 if (NS_ERROR_PHISHING_URI
== aError
)
3160 error
.AssignLiteral("phishingBlocked");
3162 error
.AssignLiteral("malwareBlocked");
3163 cssClass
.AssignLiteral("blacklist");
3166 // Errors requiring simple formatting
3168 case NS_ERROR_MALFORMED_URI
:
3170 error
.AssignLiteral("malformedURI");
3172 case NS_ERROR_REDIRECT_LOOP
:
3173 // Doc failed to load because the server generated too many redirects
3174 error
.AssignLiteral("redirectLoop");
3176 case NS_ERROR_UNKNOWN_SOCKET_TYPE
:
3177 // Doc failed to load because PSM is not installed
3178 error
.AssignLiteral("unknownSocketType");
3180 case NS_ERROR_NET_RESET
:
3181 // Doc failed to load because the server kept reseting the connection
3182 // before we could read any data from it
3183 error
.AssignLiteral("netReset");
3185 case NS_ERROR_DOCUMENT_NOT_CACHED
:
3186 // Doc failed to load because we are offline and the cache does not
3187 // contain a copy of the document.
3188 error
.AssignLiteral("netOffline");
3190 case NS_ERROR_DOCUMENT_IS_PRINTMODE
:
3191 // Doc navigation attempted while Printing or Print Preview
3192 error
.AssignLiteral("isprinting");
3194 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED
:
3195 // Port blocked for security reasons
3196 addHostPort
= PR_TRUE
;
3197 error
.AssignLiteral("deniedPortAccess");
3199 case NS_ERROR_UNKNOWN_PROXY_HOST
:
3200 // Proxy hostname could not be resolved.
3201 error
.AssignLiteral("proxyResolveFailure");
3203 case NS_ERROR_PROXY_CONNECTION_REFUSED
:
3204 // Proxy connection was refused.
3205 error
.AssignLiteral("proxyConnectFailure");
3207 case NS_ERROR_INVALID_CONTENT_ENCODING
:
3208 // Bad Content Encoding.
3209 error
.AssignLiteral("contentEncodingError");
3211 case NS_ERROR_UNSAFE_CONTENT_TYPE
:
3212 // Channel refused to load from an unrecognized content type.
3213 error
.AssignLiteral("unsafeContentType");
3218 // Test if the error should be displayed
3219 if (error
.IsEmpty()) {
3223 // Test if the error needs to be formatted
3224 if (!messageStr
.IsEmpty()) {
3225 // already obtained message
3229 // Build up the host:port string.
3230 nsCAutoString hostport
;
3232 aURI
->GetHostPort(hostport
);
3234 hostport
.AssignLiteral("?");
3236 CopyUTF8toUTF16(hostport
, formatStrs
[formatStrCount
++]);
3240 rv
= NS_ERROR_NOT_AVAILABLE
;
3242 // displaying "file://" is aesthetically unpleasing and could even be
3243 // confusing to the user
3244 PRBool isFileURI
= PR_FALSE
;
3245 rv
= aURI
->SchemeIs("file", &isFileURI
);
3246 if (NS_SUCCEEDED(rv
) && isFileURI
)
3247 aURI
->GetPath(spec
);
3249 aURI
->GetSpec(spec
);
3251 nsCAutoString charset
;
3252 // unescape and convert from origin charset
3253 aURI
->GetOriginCharset(charset
);
3254 nsCOMPtr
<nsITextToSubURI
> textToSubURI(
3255 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
));
3256 if (NS_SUCCEEDED(rv
)) {
3257 rv
= textToSubURI
->UnEscapeURIForUI(charset
, spec
, formatStrs
[formatStrCount
]);
3260 spec
.AssignLiteral("?");
3263 CopyUTF8toUTF16(spec
, formatStrs
[formatStrCount
]);
3267 const PRUnichar
*strs
[kMaxFormatStrArgs
];
3268 for (PRUint32 i
= 0; i
< formatStrCount
; i
++) {
3269 strs
[i
] = formatStrs
[i
].get();
3272 rv
= stringBundle
->FormatStringFromName(
3274 strs
, formatStrCount
, getter_Copies(str
));
3275 NS_ENSURE_SUCCESS(rv
, rv
);
3276 messageStr
.Assign(str
.get());
3279 // Display the error as a page or an alert prompt
3280 NS_ENSURE_FALSE(messageStr
.IsEmpty(), NS_ERROR_FAILURE
);
3281 // Note: For now, display an alert instead of an error page if we have no
3282 // URI object. Missing URI objects are handled badly by session history.
3283 if (mUseErrorPages
&& aURI
&& aFailedChannel
) {
3284 // Display an error page
3285 LoadErrorPage(aURI
, aURL
, errorPage
.get(), error
.get(),
3286 messageStr
.get(), cssClass
.get(), aFailedChannel
);
3290 // The prompter reqires that our private window has a document (or it
3291 // asserts). Satisfy that assertion now since GetDocument will force
3292 // creation of one if it hasn't already been created.
3293 nsCOMPtr
<nsPIDOMWindow
> pwin(do_QueryInterface(mScriptGlobal
));
3295 nsCOMPtr
<nsIDOMDocument
> doc
;
3296 pwin
->GetDocument(getter_AddRefs(doc
));
3299 // Display a message box
3300 prompter
->Alert(nsnull
, messageStr
.get());
3308 nsDocShell::LoadErrorPage(nsIURI
*aURI
, const PRUnichar
*aURL
,
3309 const char *aErrorPage
,
3310 const PRUnichar
*aErrorType
,
3311 const PRUnichar
*aDescription
,
3312 const char *aCSSClass
,
3313 nsIChannel
* aFailedChannel
)
3315 #if defined(PR_LOGGING) && defined(DEBUG)
3316 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
3318 aURI
->GetSpec(spec
);
3320 nsCAutoString chanName
;
3322 aFailedChannel
->GetName(chanName
);
3324 chanName
.AssignLiteral("<no channel>");
3326 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
3327 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
3328 spec
.get(), NS_ConvertUTF16toUTF8(aURL
).get(), chanName
.get()));
3331 // Create an shistory entry for the old load, if we have a channel
3332 if (aFailedChannel
) {
3333 mURIResultedInDocument
= PR_TRUE
;
3334 OnLoadingSite(aFailedChannel
, PR_TRUE
, PR_FALSE
);
3336 mURIResultedInDocument
= PR_TRUE
;
3337 OnNewURI(aURI
, nsnull
, nsnull
, mLoadType
, PR_TRUE
, PR_FALSE
);
3339 // Be sure to have a correct mLSHE, it may have been cleared by
3340 // EndPageLoad. See bug 302115.
3341 if (mSessionHistory
&& !mLSHE
) {
3343 mSessionHistory
->GetRequestedIndex(&idx
);
3345 mSessionHistory
->GetIndex(&idx
);
3347 nsCOMPtr
<nsIHistoryEntry
> entry
;
3348 mSessionHistory
->GetEntryAtIndex(idx
, PR_FALSE
,
3349 getter_AddRefs(entry
));
3350 mLSHE
= do_QueryInterface(entry
);
3354 nsCAutoString charset
;
3357 // Set our current URI
3358 SetCurrentURI(aURI
);
3360 nsresult rv
= aURI
->GetSpec(url
);
3361 rv
|= aURI
->GetOriginCharset(charset
);
3362 NS_ENSURE_SUCCESS(rv
, rv
);
3366 CopyUTF16toUTF8(aURL
, url
);
3370 return NS_ERROR_INVALID_POINTER
;
3373 // Create a URL to pass all the error information through to the page.
3375 char *escapedUrl
= nsEscape(url
.get(), url_Path
);
3376 char *escapedCharset
= nsEscape(charset
.get(), url_Path
);
3377 char *escapedError
= nsEscape(NS_ConvertUTF16toUTF8(aErrorType
).get(), url_Path
);
3378 char *escapedDescription
= nsEscape(NS_ConvertUTF16toUTF8(aDescription
).get(), url_Path
);
3379 char *escapedCSSClass
= nsEscape(aCSSClass
, url_Path
);
3381 nsCString
errorPageUrl("about:");
3382 errorPageUrl
.AppendASCII(aErrorPage
);
3383 errorPageUrl
.AppendLiteral("?e=");
3385 errorPageUrl
.AppendASCII(escapedError
);
3386 errorPageUrl
.AppendLiteral("&u=");
3387 errorPageUrl
.AppendASCII(escapedUrl
);
3388 if (escapedCSSClass
&& escapedCSSClass
[0]) {
3389 errorPageUrl
.AppendASCII("&s=");
3390 errorPageUrl
.AppendASCII(escapedCSSClass
);
3392 errorPageUrl
.AppendLiteral("&c=");
3393 errorPageUrl
.AppendASCII(escapedCharset
);
3394 errorPageUrl
.AppendLiteral("&d=");
3395 errorPageUrl
.AppendASCII(escapedDescription
);
3397 nsMemory::Free(escapedDescription
);
3398 nsMemory::Free(escapedError
);
3399 nsMemory::Free(escapedUrl
);
3400 nsMemory::Free(escapedCharset
);
3401 nsMemory::Free(escapedCSSClass
);
3403 nsCOMPtr
<nsIURI
> errorPageURI
;
3404 nsresult rv
= NS_NewURI(getter_AddRefs(errorPageURI
), errorPageUrl
);
3405 NS_ENSURE_SUCCESS(rv
, rv
);
3407 return InternalLoad(errorPageURI
, nsnull
, nsnull
,
3408 INTERNAL_LOAD_FLAGS_INHERIT_OWNER
, nsnull
, nsnull
,
3409 nsnull
, nsnull
, LOAD_ERROR_PAGE
,
3410 nsnull
, PR_TRUE
, nsnull
, nsnull
);
3415 nsDocShell::Reload(PRUint32 aReloadFlags
)
3417 if (!IsNavigationAllowed()) {
3418 return NS_OK
; // JS may not handle returning of an error code
3421 NS_ASSERTION(((aReloadFlags
& 0xf) == 0),
3422 "Reload command not updated to use load flags!");
3423 NS_ASSERTION((aReloadFlags
& EXTRA_LOAD_FLAGS
) == 0,
3424 "Don't pass these flags to Reload");
3426 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL
, aReloadFlags
);
3427 NS_ENSURE_TRUE(IsValidLoadType(loadType
), NS_ERROR_INVALID_ARG
);
3429 // Send notifications to the HistoryListener if any, about the impending reload
3430 nsCOMPtr
<nsISHistory
> rootSH
;
3431 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3432 nsCOMPtr
<nsISHistoryInternal
> shistInt(do_QueryInterface(rootSH
));
3433 PRBool canReload
= PR_TRUE
;
3435 nsCOMPtr
<nsISHistoryListener
> listener
;
3436 shistInt
->GetListener(getter_AddRefs(listener
));
3438 listener
->OnHistoryReload(mCurrentURI
, aReloadFlags
, &canReload
);
3445 /* If you change this part of code, make sure bug 45297 does not re-occur */
3447 rv
= LoadHistoryEntry(mOSHE
, loadType
);
3449 else if (mLSHE
) { // In case a reload happened before the current load is done
3450 rv
= LoadHistoryEntry(mLSHE
, loadType
);
3453 nsCOMPtr
<nsIDOMDocument
> domDoc(do_GetInterface(GetAsSupports(this)));
3454 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(domDoc
));
3456 nsIPrincipal
* principal
= nsnull
;
3457 nsAutoString contentTypeHint
;
3459 principal
= doc
->NodePrincipal();
3460 doc
->GetContentType(contentTypeHint
);
3463 rv
= InternalLoad(mCurrentURI
,
3466 INTERNAL_LOAD_FLAGS_NONE
, // Do not inherit owner from document
3467 nsnull
, // No window target
3468 NS_LossyConvertUTF16toASCII(contentTypeHint
).get(),
3469 nsnull
, // No post data
3470 nsnull
, // No headers data
3471 loadType
, // Load type
3472 nsnull
, // No SHEntry
3474 nsnull
, // No nsIDocShell
3475 nsnull
); // No nsIRequest
3483 nsDocShell::Stop(PRUint32 aStopFlags
)
3485 // Revoke any pending event related to content viewer restoration
3486 mRestorePresentationEvent
.Revoke();
3488 if (nsIWebNavigation::STOP_CONTENT
& aStopFlags
) {
3489 // Stop the document loading
3491 mContentViewer
->Stop();
3494 if (nsIWebNavigation::STOP_NETWORK
& aStopFlags
) {
3495 // Suspend any timers that were set for this loader. We'll clear
3496 // them out for good in CreateContentViewer.
3497 if (mRefreshURIList
) {
3498 SuspendRefreshURIs();
3499 mSavedRefreshURIList
.swap(mRefreshURIList
);
3500 mRefreshURIList
= nsnull
;
3504 mClassifier
->Cancel();
3505 mClassifier
= nsnull
;
3508 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
3509 // just call Stop() on us as an nsIDocumentLoader... We need fewer
3515 PRInt32 count
= mChildList
.Count();
3516 for (n
= 0; n
< count
; n
++) {
3517 nsCOMPtr
<nsIWebNavigation
> shellAsNav(do_QueryInterface(ChildAt(n
)));
3519 shellAsNav
->Stop(aStopFlags
);
3526 NS_IMETHODIMP nsDocShell::SetDocument(nsIDOMDocument* aDocument,
3527 const PRUnichar* aContentType)
3530 NS_ERROR("Not Yet Implemented");
3531 return NS_ERROR_FAILURE;
3536 nsDocShell::GetDocument(nsIDOMDocument
** aDocument
)
3538 NS_ENSURE_ARG_POINTER(aDocument
);
3539 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE
);
3541 return mContentViewer
->GetDOMDocument(aDocument
);
3545 nsDocShell::GetCurrentURI(nsIURI
** aURI
)
3547 NS_ENSURE_ARG_POINTER(aURI
);
3550 return NS_EnsureSafeToReturn(mCurrentURI
, aURI
);
3558 nsDocShell::GetReferringURI(nsIURI
** aURI
)
3560 NS_ENSURE_ARG_POINTER(aURI
);
3562 *aURI
= mReferrerURI
;
3563 NS_IF_ADDREF(*aURI
);
3569 nsDocShell::SetSessionHistory(nsISHistory
* aSessionHistory
)
3572 NS_ENSURE_TRUE(aSessionHistory
, NS_ERROR_FAILURE
);
3573 // make sure that we are the root docshell and
3574 // set a handle to root docshell in SH.
3576 nsCOMPtr
<nsIDocShellTreeItem
> root
;
3577 /* Get the root docshell. If *this* is the root docshell
3578 * then save a handle to *this* in SH. SH needs it to do
3579 * traversions thro' its entries
3581 GetSameTypeRootTreeItem(getter_AddRefs(root
));
3582 NS_ENSURE_TRUE(root
, NS_ERROR_FAILURE
);
3583 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this)) {
3584 mSessionHistory
= aSessionHistory
;
3585 nsCOMPtr
<nsISHistoryInternal
>
3586 shPrivate(do_QueryInterface(mSessionHistory
));
3587 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
3588 shPrivate
->SetRootDocShell(this);
3591 return NS_ERROR_FAILURE
;
3597 nsDocShell::GetSessionHistory(nsISHistory
** aSessionHistory
)
3599 NS_ENSURE_ARG_POINTER(aSessionHistory
);
3600 *aSessionHistory
= mSessionHistory
;
3601 NS_IF_ADDREF(*aSessionHistory
);
3605 //*****************************************************************************
3606 // nsDocShell::nsIWebPageDescriptor
3607 //*****************************************************************************
3609 nsDocShell::LoadPage(nsISupports
*aPageDescriptor
, PRUint32 aDisplayType
)
3611 nsCOMPtr
<nsISHEntry
> shEntryIn(do_QueryInterface(aPageDescriptor
));
3613 // Currently, the opaque 'page descriptor' is an nsISHEntry...
3615 return NS_ERROR_INVALID_POINTER
;
3618 // Now clone shEntryIn, since we might end up modifying it later on, and we
3619 // want a page descriptor to be reusable.
3620 nsCOMPtr
<nsISHEntry
> shEntry
;
3621 nsresult rv
= shEntryIn
->Clone(getter_AddRefs(shEntry
));
3622 NS_ENSURE_SUCCESS(rv
, rv
);
3625 // load the page as view-source
3627 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE
== aDisplayType
) {
3628 nsCOMPtr
<nsIURI
> oldUri
, newUri
;
3629 nsCString spec
, newSpec
;
3631 // Create a new view-source URI and replace the original.
3632 rv
= shEntry
->GetURI(getter_AddRefs(oldUri
));
3636 oldUri
->GetSpec(spec
);
3637 newSpec
.AppendLiteral("view-source:");
3638 newSpec
.Append(spec
);
3640 rv
= NS_NewURI(getter_AddRefs(newUri
), newSpec
);
3641 if (NS_FAILED(rv
)) {
3644 shEntry
->SetURI(newUri
);
3647 rv
= LoadHistoryEntry(shEntry
, LOAD_HISTORY
);
3652 nsDocShell::GetCurrentDescriptor(nsISupports
**aPageDescriptor
)
3654 NS_PRECONDITION(aPageDescriptor
, "Null out param?");
3656 *aPageDescriptor
= nsnull
;
3658 nsISHEntry
* src
= mOSHE
? mOSHE
: mLSHE
;
3660 nsCOMPtr
<nsISHEntry
> dest
;
3662 nsresult rv
= src
->Clone(getter_AddRefs(dest
));
3663 if (NS_FAILED(rv
)) {
3667 // null out inappropriate cloned attributes...
3668 dest
->SetParent(nsnull
);
3669 dest
->SetIsSubFrame(PR_FALSE
);
3671 return CallQueryInterface(dest
, aPageDescriptor
);
3674 return NS_ERROR_NOT_AVAILABLE
;
3678 //*****************************************************************************
3679 // nsDocShell::nsIBaseWindow
3680 //*****************************************************************************
3683 nsDocShell::InitWindow(nativeWindow parentNativeWindow
,
3684 nsIWidget
* parentWidget
, PRInt32 x
, PRInt32 y
,
3685 PRInt32 cx
, PRInt32 cy
)
3687 NS_ENSURE_ARG(parentWidget
); // DocShells must get a widget for a parent
3689 SetParentWidget(parentWidget
);
3690 SetPositionAndSize(x
, y
, cx
, cy
, PR_FALSE
);
3696 nsDocShell::Create()
3698 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
3699 "Unexpected item type in docshell");
3701 nsresult rv
= NS_ERROR_FAILURE
;
3702 mPrefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
);
3703 NS_ENSURE_SUCCESS(rv
, rv
);
3707 rv
= mPrefs
->GetBoolPref("browser.frames.enabled", &tmpbool
);
3708 if (NS_SUCCEEDED(rv
))
3709 mAllowSubframes
= tmpbool
;
3711 if (gValidateOrigin
== (PRBool
)0xffffffff) {
3712 // Check pref to see if we should prevent frameset spoofing
3713 rv
= mPrefs
->GetBoolPref("browser.frame.validate_origin", &tmpbool
);
3714 if (NS_SUCCEEDED(rv
)) {
3715 gValidateOrigin
= tmpbool
;
3717 gValidateOrigin
= PR_TRUE
;
3721 // Should we use XUL error pages instead of alerts if possible?
3722 rv
= mPrefs
->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool
);
3723 if (NS_SUCCEEDED(rv
))
3724 mUseErrorPages
= tmpbool
;
3726 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
, &rv
));
3727 if (NS_SUCCEEDED(rv
) && mObserveErrorPages
) {
3728 prefs
->AddObserver("browser.xul.error_pages.enabled", this, PR_FALSE
);
3731 nsCOMPtr
<nsIObserverService
> serv
= do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
3733 const char* msg
= mItemType
== typeContent
?
3734 NS_WEBNAVIGATION_CREATE
: NS_CHROME_WEBNAVIGATION_CREATE
;
3735 serv
->NotifyObservers(GetAsSupports(this), msg
, nsnull
);
3742 nsDocShell::Destroy()
3744 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
3745 "Unexpected item type in docshell");
3747 if (!mIsBeingDestroyed
) {
3748 nsCOMPtr
<nsIObserverService
> serv
=
3749 do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
3751 const char* msg
= mItemType
== typeContent
?
3752 NS_WEBNAVIGATION_DESTROY
: NS_CHROME_WEBNAVIGATION_DESTROY
;
3753 serv
->NotifyObservers(GetAsSupports(this), msg
, nsnull
);
3757 mIsBeingDestroyed
= PR_TRUE
;
3759 // Remove our pref observers
3760 if (mObserveErrorPages
) {
3761 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
));
3763 prefs
->RemoveObserver("browser.xul.error_pages.enabled", this);
3764 mObserveErrorPages
= PR_FALSE
;
3768 // Make sure to blow away our mLoadingURI just in case. No loads
3769 // from inside this pagehide.
3770 mLoadingURI
= nsnull
;
3772 // Fire unload event before we blow anything away.
3773 (void) FirePageHideNotification(PR_TRUE
);
3775 // Clear pointers to any detached nsEditorData that's lying
3776 // around in shistory entries. Breaks cycle. See bug 430921.
3778 mOSHE
->SetEditorData(nsnull
);
3780 mLSHE
->SetEditorData(nsnull
);
3782 // Note: mContentListener can be null if Init() failed and we're being
3783 // called from the destructor.
3784 if (mContentListener
) {
3785 mContentListener
->DropDocShellreference();
3786 mContentListener
->SetParentContentListener(nsnull
);
3787 // Note that we do NOT set mContentListener to null here; that
3788 // way if someone tries to do a load in us after this point
3789 // the nsDSURIContentListener will block it. All of which
3790 // means that we should do this before calling Stop(), of
3794 // Stop any URLs that are currently being loaded...
3795 Stop(nsIWebNavigation::STOP_ALL
);
3797 mEditorData
= nsnull
;
3799 mTransferableHookData
= nsnull
;
3801 // Save the state of the current document, before destroying the window.
3802 // This is needed to capture the state of a frameset when the new document
3803 // causes the frameset to be destroyed...
3804 PersistLayoutHistoryState();
3806 // Remove this docshell from its parent's child list
3807 nsCOMPtr
<nsIDocShellTreeItem
> docShellParentAsItem
=
3808 do_QueryInterface(GetAsSupports(mParent
));
3809 if (docShellParentAsItem
)
3810 docShellParentAsItem
->RemoveChild(this);
3812 nsCOMPtr
<nsIFocusEventSuppressorService
> suppressor
;
3813 if (mContentViewer
) {
3815 do_GetService(NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CONTRACTID
);
3816 NS_ENSURE_STATE(suppressor
);
3817 suppressor
->Suppress();
3818 mContentViewer
->Close(nsnull
);
3819 mContentViewer
->Destroy();
3820 mContentViewer
= nsnull
;
3823 nsDocLoader::Destroy();
3825 mParentWidget
= nsnull
;
3826 mCurrentURI
= nsnull
;
3828 if (mScriptGlobal
) {
3829 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
3830 win
->SetDocShell(nsnull
);
3832 mScriptGlobal
= nsnull
;
3835 mSessionHistory
= nsnull
;
3836 SetTreeOwner(nsnull
);
3838 // required to break ref cycle
3839 mSecurityUI
= nsnull
;
3841 // Cancel any timers that were set for this docshell; this is needed
3842 // to break the cycle between us and the timers.
3843 CancelRefreshURITimers();
3845 suppressor
->Unsuppress();
3851 nsDocShell::SetPosition(PRInt32 x
, PRInt32 y
)
3857 NS_ENSURE_SUCCESS(mContentViewer
->Move(x
, y
), NS_ERROR_FAILURE
);
3863 nsDocShell::GetPosition(PRInt32
* aX
, PRInt32
* aY
)
3865 PRInt32 dummyHolder
;
3866 return GetPositionAndSize(aX
, aY
, &dummyHolder
, &dummyHolder
);
3870 nsDocShell::SetSize(PRInt32 aCX
, PRInt32 aCY
, PRBool aRepaint
)
3872 PRInt32 x
= 0, y
= 0;
3873 GetPosition(&x
, &y
);
3874 return SetPositionAndSize(x
, y
, aCX
, aCY
, aRepaint
);
3878 nsDocShell::GetSize(PRInt32
* aCX
, PRInt32
* aCY
)
3880 PRInt32 dummyHolder
;
3881 return GetPositionAndSize(&dummyHolder
, &dummyHolder
, aCX
, aCY
);
3885 nsDocShell::SetPositionAndSize(PRInt32 x
, PRInt32 y
, PRInt32 cx
,
3886 PRInt32 cy
, PRBool fRepaint
)
3891 mBounds
.height
= cy
;
3893 // Hold strong ref, since SetBounds can make us null out mContentViewer
3894 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
3896 //XXX Border figured in here or is that handled elsewhere?
3897 NS_ENSURE_SUCCESS(viewer
->SetBounds(mBounds
), NS_ERROR_FAILURE
);
3904 nsDocShell::GetPositionAndSize(PRInt32
* x
, PRInt32
* y
, PRInt32
* cx
,
3907 // We should really consider just getting this information from
3908 // our window instead of duplicating the storage and code...
3909 nsCOMPtr
<nsIDOMDocument
> document(do_GetInterface(GetAsSupports(mParent
)));
3910 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(document
));
3912 doc
->FlushPendingNotifications(Flush_Layout
);
3915 DoGetPositionAndSize(x
, y
, cx
, cy
);
3920 nsDocShell::DoGetPositionAndSize(PRInt32
* x
, PRInt32
* y
, PRInt32
* cx
,
3928 *cx
= mBounds
.width
;
3930 *cy
= mBounds
.height
;
3934 nsDocShell::Repaint(PRBool aForce
)
3936 nsCOMPtr
<nsPresContext
> context
;
3937 GetPresContext(getter_AddRefs(context
));
3938 NS_ENSURE_TRUE(context
, NS_ERROR_FAILURE
);
3940 nsIViewManager
* viewManager
= context
->GetViewManager();
3941 NS_ENSURE_TRUE(viewManager
, NS_ERROR_FAILURE
);
3943 // what about aForce ?
3944 NS_ENSURE_SUCCESS(viewManager
->UpdateAllViews(0), NS_ERROR_FAILURE
);
3949 nsDocShell::GetParentWidget(nsIWidget
** parentWidget
)
3951 NS_ENSURE_ARG_POINTER(parentWidget
);
3953 *parentWidget
= mParentWidget
;
3954 NS_IF_ADDREF(*parentWidget
);
3960 nsDocShell::SetParentWidget(nsIWidget
* aParentWidget
)
3962 mParentWidget
= aParentWidget
;
3968 nsDocShell::GetParentNativeWindow(nativeWindow
* parentNativeWindow
)
3970 NS_ENSURE_ARG_POINTER(parentNativeWindow
);
3973 *parentNativeWindow
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
3975 *parentNativeWindow
= nsnull
;
3981 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow
)
3983 return NS_ERROR_NOT_IMPLEMENTED
;
3987 nsDocShell::GetVisibility(PRBool
* aVisibility
)
3989 NS_ENSURE_ARG_POINTER(aVisibility
);
3991 *aVisibility
= PR_FALSE
;
3993 if (!mContentViewer
)
3996 nsCOMPtr
<nsIPresShell
> presShell
;
3997 GetPresShell(getter_AddRefs(presShell
));
4001 // get the view manager
4002 nsIViewManager
* vm
= presShell
->GetViewManager();
4003 NS_ENSURE_TRUE(vm
, NS_ERROR_FAILURE
);
4005 // get the root view
4006 nsIView
*view
= nsnull
; // views are not ref counted
4007 NS_ENSURE_SUCCESS(vm
->GetRootView(view
), NS_ERROR_FAILURE
);
4008 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
4010 // if our root view is hidden, we are not visible
4011 if (view
->GetVisibility() == nsViewVisibility_kHide
)
4014 // otherwise, we must walk up the document and view trees checking
4015 // for a hidden view, unless we're an off screen browser, which
4016 // would make this test meaningless.
4018 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= this;
4019 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
4020 treeItem
->GetParent(getter_AddRefs(parentItem
));
4021 while (parentItem
) {
4022 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(treeItem
));
4023 docShell
->GetPresShell(getter_AddRefs(presShell
));
4025 nsCOMPtr
<nsIDocShell
> parentDS
= do_QueryInterface(parentItem
);
4026 nsCOMPtr
<nsIPresShell
> pPresShell
;
4027 parentDS
->GetPresShell(getter_AddRefs(pPresShell
));
4029 // Null-check for crash in bug 267804
4031 NS_NOTREACHED("parent docshell has null pres shell");
4035 nsIContent
*shellContent
=
4036 pPresShell
->GetDocument()->FindContentForSubDocument(presShell
->GetDocument());
4037 NS_ASSERTION(shellContent
, "subshell not in the map");
4039 nsIFrame
* frame
= pPresShell
->GetPrimaryFrameFor(shellContent
);
4040 PRBool isDocShellOffScreen
= PR_FALSE
;
4041 docShell
->GetIsOffScreenBrowser(&isDocShellOffScreen
);
4042 if (frame
&& !frame
->AreAncestorViewsVisible() && !isDocShellOffScreen
)
4045 treeItem
= parentItem
;
4046 treeItem
->GetParent(getter_AddRefs(parentItem
));
4049 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
4050 if (!treeOwnerAsWin
) {
4051 *aVisibility
= PR_TRUE
;
4055 // Check with the tree owner as well to give embedders a chance to
4056 // expose visibility as well.
4057 return treeOwnerAsWin
->GetVisibility(aVisibility
);
4061 nsDocShell::SetIsOffScreenBrowser(PRBool aIsOffScreen
)
4063 mIsOffScreenBrowser
= aIsOffScreen
;
4068 nsDocShell::GetIsOffScreenBrowser(PRBool
*aIsOffScreen
)
4070 *aIsOffScreen
= mIsOffScreenBrowser
;
4075 nsDocShell::SetVisibility(PRBool aVisibility
)
4077 if (!mContentViewer
)
4080 mContentViewer
->Show();
4083 mContentViewer
->Hide();
4090 nsDocShell::GetEnabled(PRBool
*aEnabled
)
4092 NS_ENSURE_ARG_POINTER(aEnabled
);
4093 *aEnabled
= PR_TRUE
;
4094 return NS_ERROR_NOT_IMPLEMENTED
;
4098 nsDocShell::SetEnabled(PRBool aEnabled
)
4100 return NS_ERROR_NOT_IMPLEMENTED
;
4104 nsDocShell::GetBlurSuppression(PRBool
*aBlurSuppression
)
4106 NS_ENSURE_ARG_POINTER(aBlurSuppression
);
4107 *aBlurSuppression
= PR_FALSE
;
4108 return NS_ERROR_NOT_IMPLEMENTED
;
4112 nsDocShell::SetBlurSuppression(PRBool aBlurSuppression
)
4114 return NS_ERROR_NOT_IMPLEMENTED
;
4118 nsDocShell::GetMainWidget(nsIWidget
** aMainWidget
)
4120 // We don't create our own widget, so simply return the parent one.
4121 return GetParentWidget(aMainWidget
);
4125 nsDocShell::SetFocus()
4127 #ifdef DEBUG_DOCSHELL_FOCUS
4128 printf("nsDocShell::SetFocus %p\n", (void*)this);
4131 // Tell itself (and the DocShellFocusController) who has focus
4132 // this way focus gets removed from the currently focused DocShell
4134 SetHasFocus(PR_TRUE
);
4140 nsDocShell::GetTitle(PRUnichar
** aTitle
)
4142 NS_ENSURE_ARG_POINTER(aTitle
);
4144 *aTitle
= ToNewUnicode(mTitle
);
4149 nsDocShell::SetTitle(const PRUnichar
* aTitle
)
4151 // Store local title
4154 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
4155 GetSameTypeParent(getter_AddRefs(parent
));
4157 // When title is set on the top object it should then be passed to the
4160 nsCOMPtr
<nsIBaseWindow
>
4161 treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
4163 treeOwnerAsWin
->SetTitle(aTitle
);
4166 if (mGlobalHistory
&& mCurrentURI
&& mLoadType
!= LOAD_ERROR_PAGE
) {
4167 mGlobalHistory
->SetPageTitle(mCurrentURI
, nsDependentString(aTitle
));
4171 // Update SessionHistory with the document's title. If the
4172 // page was loaded from history or the page bypassed history,
4173 // there is no need to update the title. There is no need to
4174 // go to mSessionHistory to update the title. Setting it in mOSHE
4176 if (mOSHE
&& (mLoadType
!= LOAD_BYPASS_HISTORY
) &&
4177 (mLoadType
!= LOAD_HISTORY
) && (mLoadType
!= LOAD_ERROR_PAGE
)) {
4178 mOSHE
->SetTitle(mTitle
);
4185 //*****************************************************************************
4186 // nsDocShell::nsIScrollable
4187 //*****************************************************************************
4190 nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation
, PRInt32
* curPos
)
4192 NS_ENSURE_ARG_POINTER(curPos
);
4194 nsIScrollableView
* scrollView
;
4195 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4198 return NS_ERROR_FAILURE
;
4202 NS_ENSURE_SUCCESS(scrollView
->GetScrollPosition(x
, y
), NS_ERROR_FAILURE
);
4204 switch (scrollOrientation
) {
4205 case ScrollOrientation_X
:
4209 case ScrollOrientation_Y
:
4214 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4216 return NS_ERROR_FAILURE
;
4220 nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation
, PRInt32 curPos
)
4222 nsIScrollableView
* scrollView
;
4223 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4226 return NS_ERROR_FAILURE
;
4233 GetCurScrollPos(scrollOrientation
, &other
);
4235 switch (scrollOrientation
) {
4236 case ScrollOrientation_X
:
4241 case ScrollOrientation_Y
:
4247 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4249 y
= 0; // fix compiler warning, not actually executed
4252 NS_ENSURE_SUCCESS(scrollView
->ScrollTo(x
, y
, 0),
4258 nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos
, PRInt32 curVerticalPos
)
4260 nsIScrollableView
* scrollView
;
4261 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4264 return NS_ERROR_FAILURE
;
4267 NS_ENSURE_SUCCESS(scrollView
->ScrollTo(curHorizontalPos
, curVerticalPos
, 0),
4272 // XXX This is wrong
4274 nsDocShell::GetScrollRange(PRInt32 scrollOrientation
,
4275 PRInt32
* minPos
, PRInt32
* maxPos
)
4277 NS_ENSURE_ARG_POINTER(minPos
&& maxPos
);
4279 nsIScrollableView
* scrollView
;
4280 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4283 return NS_ERROR_FAILURE
;
4289 NS_ENSURE_SUCCESS(scrollView
->GetContainerSize(&cx
, &cy
), NS_ERROR_FAILURE
);
4292 switch (scrollOrientation
) {
4293 case ScrollOrientation_X
:
4297 case ScrollOrientation_Y
:
4302 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4305 return NS_ERROR_FAILURE
;
4309 nsDocShell::SetScrollRange(PRInt32 scrollOrientation
,
4310 PRInt32 minPos
, PRInt32 maxPos
)
4314 Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
4315 something less than the current thumb position, curPos is set = to maxPos.
4317 @return NS_OK - Setting or Getting completed successfully.
4318 NS_ERROR_INVALID_ARG - returned when curPos is not within the
4321 return NS_ERROR_FAILURE
;
4325 nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos
,
4326 PRInt32 maxHorizontalPos
, PRInt32 minVerticalPos
,
4327 PRInt32 maxVerticalPos
)
4331 Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
4332 something less than the current thumb position, curPos is set = to maxPos.
4334 @return NS_OK - Setting or Getting completed successfully.
4335 NS_ERROR_INVALID_ARG - returned when curPos is not within the
4338 return NS_ERROR_FAILURE
;
4341 // This returns setting for all documents in this webshell
4343 nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation
,
4344 PRInt32
* scrollbarPref
)
4346 NS_ENSURE_ARG_POINTER(scrollbarPref
);
4347 switch (scrollOrientation
) {
4348 case ScrollOrientation_X
:
4349 *scrollbarPref
= mDefaultScrollbarPref
.x
;
4352 case ScrollOrientation_Y
:
4353 *scrollbarPref
= mDefaultScrollbarPref
.y
;
4357 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4359 return NS_ERROR_FAILURE
;
4362 // Set scrolling preference for all documents in this shell
4364 // There are three possible values stored in the shell:
4365 // 1) nsIScrollable::Scrollbar_Never = no scrollbar
4366 // 2) nsIScrollable::Scrollbar_Auto = scrollbar appears if the document
4367 // being displayed would normally have scrollbar
4368 // 3) nsIScrollable::Scrollbar_Always = scrollbar always appears
4370 // One important client is nsHTMLFrameInnerFrame::CreateWebShell()
4372 nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation
,
4373 PRInt32 scrollbarPref
)
4375 switch (scrollOrientation
) {
4376 case ScrollOrientation_X
:
4377 mDefaultScrollbarPref
.x
= scrollbarPref
;
4380 case ScrollOrientation_Y
:
4381 mDefaultScrollbarPref
.y
= scrollbarPref
;
4385 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4387 return NS_ERROR_FAILURE
;
4391 nsDocShell::GetScrollbarVisibility(PRBool
* verticalVisible
,
4392 PRBool
* horizontalVisible
)
4394 nsIScrollableView
* scrollView
;
4395 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4398 return NS_ERROR_FAILURE
;
4400 // We should now call nsLayoutUtils::GetScrollableFrameFor,
4401 // but we can't because of stupid linkage!
4402 nsIFrame
* scrollFrame
=
4403 static_cast<nsIFrame
*>(scrollView
->View()->GetParent()->GetClientData());
4405 return NS_ERROR_FAILURE
;
4406 nsIScrollableFrame
* scrollable
= do_QueryFrame(scrollFrame
);
4408 return NS_ERROR_FAILURE
;
4410 nsMargin scrollbars
= scrollable
->GetActualScrollbarSizes();
4411 if (verticalVisible
)
4412 *verticalVisible
= scrollbars
.left
!= 0 || scrollbars
.right
!= 0;
4413 if (horizontalVisible
)
4414 *horizontalVisible
= scrollbars
.top
!= 0 || scrollbars
.bottom
!= 0;
4419 //*****************************************************************************
4420 // nsDocShell::nsITextScroll
4421 //*****************************************************************************
4424 nsDocShell::ScrollByLines(PRInt32 numLines
)
4426 nsIScrollableView
* scrollView
;
4428 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4431 return NS_ERROR_FAILURE
;
4434 NS_ENSURE_SUCCESS(scrollView
->ScrollByLines(0, numLines
), NS_ERROR_FAILURE
);
4440 nsDocShell::ScrollByPages(PRInt32 numPages
)
4442 nsIScrollableView
* scrollView
;
4444 NS_ENSURE_SUCCESS(GetRootScrollableView(&scrollView
),
4447 return NS_ERROR_FAILURE
;
4450 NS_ENSURE_SUCCESS(scrollView
->ScrollByPages(0, numPages
), NS_ERROR_FAILURE
);
4455 //*****************************************************************************
4456 // nsDocShell::nsIScriptGlobalObjectOwner
4457 //*****************************************************************************
4459 nsIScriptGlobalObject
*
4460 nsDocShell::GetScriptGlobalObject()
4462 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nsnull
);
4464 return mScriptGlobal
;
4467 //*****************************************************************************
4468 // nsDocShell::nsIRefreshURI
4469 //*****************************************************************************
4472 nsDocShell::RefreshURI(nsIURI
* aURI
, PRInt32 aDelay
, PRBool aRepeat
,
4473 PRBool aMetaRefresh
)
4475 NS_ENSURE_ARG(aURI
);
4477 /* Check if Meta refresh/redirects are permitted. Some
4478 * embedded applications may not want to do this.
4479 * Must do this before sending out NOTIFY_REFRESH events
4480 * because listeners may have side effects (e.g. displaying a
4481 * button to manually trigger the refresh later).
4483 PRBool allowRedirects
= PR_TRUE
;
4484 GetAllowMetaRedirects(&allowRedirects
);
4485 if (!allowRedirects
)
4488 // If any web progress listeners are listening for NOTIFY_REFRESH events,
4489 // give them a chance to block this refresh.
4491 nsresult rv
= aURI
->Equals(mCurrentURI
, &sameURI
);
4494 if (!RefreshAttempted(this, aURI
, aDelay
, sameURI
))
4497 nsRefreshTimer
*refreshTimer
= new nsRefreshTimer();
4498 NS_ENSURE_TRUE(refreshTimer
, NS_ERROR_OUT_OF_MEMORY
);
4499 PRUint32 busyFlags
= 0;
4500 GetBusyFlags(&busyFlags
);
4502 nsCOMPtr
<nsISupports
> dataRef
= refreshTimer
; // Get the ref count to 1
4504 refreshTimer
->mDocShell
= this;
4505 refreshTimer
->mURI
= aURI
;
4506 refreshTimer
->mDelay
= aDelay
;
4507 refreshTimer
->mRepeat
= aRepeat
;
4508 refreshTimer
->mMetaRefresh
= aMetaRefresh
;
4510 if (!mRefreshURIList
) {
4511 NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList
)),
4515 if (busyFlags
& BUSY_FLAGS_BUSY
) {
4516 // We are busy loading another page. Don't create the
4517 // timer right now. Instead queue up the request and trigger the
4518 // timer in EndPageLoad().
4519 mRefreshURIList
->AppendElement(refreshTimer
);
4522 // There is no page loading going on right now. Create the
4523 // timer and fire it right away.
4524 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance("@mozilla.org/timer;1");
4525 NS_ENSURE_TRUE(timer
, NS_ERROR_FAILURE
);
4527 mRefreshURIList
->AppendElement(timer
); // owning timer ref
4528 timer
->InitWithCallback(refreshTimer
, aDelay
, nsITimer::TYPE_ONE_SHOT
);
4534 nsDocShell::ForceRefreshURIFromTimer(nsIURI
* aURI
,
4536 PRBool aMetaRefresh
,
4539 NS_PRECONDITION(aTimer
, "Must have a timer here");
4541 // Remove aTimer from mRefreshURIList if needed
4542 if (mRefreshURIList
) {
4544 mRefreshURIList
->Count(&n
);
4546 for (PRUint32 i
= 0; i
< n
; ++i
) {
4547 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
4548 if (timer
== aTimer
) {
4549 mRefreshURIList
->RemoveElementAt(i
);
4555 return ForceRefreshURI(aURI
, aDelay
, aMetaRefresh
);
4559 nsDocShell::ForceRefreshURI(nsIURI
* aURI
,
4561 PRBool aMetaRefresh
)
4563 NS_ENSURE_ARG(aURI
);
4565 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
4566 CreateLoadInfo(getter_AddRefs(loadInfo
));
4567 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
4569 /* We do need to pass in a referrer, but we don't want it to
4570 * be sent to the server.
4572 loadInfo
->SetSendReferrer(PR_FALSE
);
4574 /* for most refreshes the current URI is an appropriate
4577 loadInfo
->SetReferrer(mCurrentURI
);
4579 /* Check if this META refresh causes a redirection
4582 PRBool equalUri
= PR_FALSE
;
4583 nsresult rv
= aURI
->Equals(mCurrentURI
, &equalUri
);
4584 if (NS_SUCCEEDED(rv
) && (!equalUri
) && aMetaRefresh
) {
4586 /* It is a META refresh based redirection. Now check if it happened
4587 within the threshold time we have in mind(15000 ms as defined by
4588 REFRESH_REDIRECT_TIMER). If so, pass a REPLACE flag to LoadURI().
4590 if (aDelay
<= REFRESH_REDIRECT_TIMER
) {
4591 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace
);
4593 /* for redirects we mimic HTTP, which passes the
4596 nsCOMPtr
<nsIURI
> internalReferrer
;
4597 GetReferringURI(getter_AddRefs(internalReferrer
));
4598 if (internalReferrer
) {
4599 loadInfo
->SetReferrer(internalReferrer
);
4603 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadRefresh
);
4605 * LoadURI(...) will cancel all refresh timers... This causes the
4606 * Timer and its refreshData instance to be released...
4608 LoadURI(aURI
, loadInfo
, nsIWebNavigation::LOAD_FLAGS_NONE
, PR_TRUE
);
4612 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadRefresh
);
4614 LoadURI(aURI
, loadInfo
, nsIWebNavigation::LOAD_FLAGS_NONE
, PR_TRUE
);
4620 nsDocShell::SetupRefreshURIFromHeader(nsIURI
* aBaseURI
,
4621 const nsACString
& aHeader
)
4623 // Refresh headers are parsed with the following format in mind
4624 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
4625 // By the time we are here, the following is true:
4626 // header = "REFRESH"
4627 // content = "5; URL=http://uri" // note the URL attribute is
4628 // optional, if it is absent, the currently loaded url is used.
4629 // Also note that the seconds and URL separator can be either
4630 // a ';' or a ','. The ',' separator should be illegal but CNN
4633 // We need to handle the following strings, where
4634 // - X is a set of digits
4635 // - URI is either a relative or absolute URI
4637 // Note that URI should start with "url=" but we allow omission
4640 // empty string. use the currently loaded URI
4641 // and refresh immediately.
4642 // "X" || "X;" || "X,"
4643 // Refresh the currently loaded URI in X seconds.
4644 // "X; URI" || "X, URI"
4645 // Refresh using URI as the destination in X seconds.
4646 // "URI" || "; URI" || ", URI"
4647 // Refresh immediately using URI as the destination.
4649 // Currently, anything immediately following the URI, if
4650 // separated by any char in the set "'\"\t\r\n " will be
4651 // ignored. So "10; url=go.html ; foo=bar" will work,
4652 // and so will "10; url='go.html'; foo=bar". However,
4653 // "10; url=go.html; foo=bar" will result in the uri
4654 // "go.html;" since ';' and ',' are valid uri characters.
4656 // Note that we need to remove any tokens wrapping the URI.
4657 // These tokens currently include spaces, double and single
4660 // when done, seconds is 0 or the given number of seconds
4661 // uriAttrib is empty or the URI specified
4662 nsCAutoString uriAttrib
;
4663 PRInt32 seconds
= 0;
4664 PRBool specifiesSeconds
= PR_FALSE
;
4666 nsACString::const_iterator iter
, tokenStart
, doneIterating
;
4668 aHeader
.BeginReading(iter
);
4669 aHeader
.EndReading(doneIterating
);
4671 // skip leading whitespace
4672 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
4677 // skip leading + and -
4678 if (iter
!= doneIterating
&& (*iter
== '-' || *iter
== '+'))
4682 while (iter
!= doneIterating
&& (*iter
>= '0' && *iter
<= '9')) {
4683 seconds
= seconds
* 10 + (*iter
- '0');
4684 specifiesSeconds
= PR_TRUE
;
4688 if (iter
!= doneIterating
) {
4689 // if we started with a '-', number is negative
4690 if (*tokenStart
== '-')
4693 // skip to next ';' or ','
4694 nsACString::const_iterator iterAfterDigit
= iter
;
4695 while (iter
!= doneIterating
&& !(*iter
== ';' || *iter
== ','))
4697 if (specifiesSeconds
)
4699 // Non-whitespace characters here mean that the string is
4700 // malformed but tolerate sites that specify a decimal point,
4701 // even though meta refresh only works on whole seconds.
4702 if (iter
== iterAfterDigit
&&
4703 !nsCRT::IsAsciiSpace(*iter
) && *iter
!= '.')
4705 // The characters between the seconds and the next
4706 // section are just garbage!
4707 // e.g. content="2a0z+,URL=http://www.mozilla.org/"
4708 // Just ignore this redirect.
4709 return NS_ERROR_FAILURE
;
4711 else if (nsCRT::IsAsciiSpace(*iter
))
4713 // We've had at least one whitespace so tolerate the mistake
4714 // and drop through.
4715 // e.g. content="10 foo"
4723 // skip any remaining whitespace
4724 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
4728 if (iter
!= doneIterating
&& (*iter
== ';' || *iter
== ',')) {
4733 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
4737 // possible start of URI
4740 // skip "url = " to real start of URI
4741 if (iter
!= doneIterating
&& (*iter
== 'u' || *iter
== 'U')) {
4743 if (iter
!= doneIterating
&& (*iter
== 'r' || *iter
== 'R')) {
4745 if (iter
!= doneIterating
&& (*iter
== 'l' || *iter
== 'L')) {
4749 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
4752 if (iter
!= doneIterating
&& *iter
== '=') {
4756 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
4759 // found real start of URI
4766 // skip a leading '"' or '\''.
4768 PRBool isQuotedURI
= PR_FALSE
;
4769 if (tokenStart
!= doneIterating
&& (*tokenStart
== '"' || *tokenStart
== '\''))
4771 isQuotedURI
= PR_TRUE
;
4775 // set iter to start of URI
4778 // tokenStart here points to the beginning of URI
4780 // grab the rest of the URI
4781 while (iter
!= doneIterating
)
4783 if (isQuotedURI
&& (*iter
== '"' || *iter
== '\''))
4788 // move iter one back if the last character is a '"' or '\''
4789 if (iter
!= tokenStart
&& isQuotedURI
) {
4791 if (!(*iter
== '"' || *iter
== '\''))
4795 // URI is whatever's contained from tokenStart to iter.
4796 // note: if tokenStart == doneIterating, so is iter.
4798 nsresult rv
= NS_OK
;
4800 nsCOMPtr
<nsIURI
> uri
;
4801 PRBool specifiesURI
= PR_FALSE
;
4802 if (tokenStart
== iter
) {
4806 uriAttrib
= Substring(tokenStart
, iter
);
4807 // NS_NewURI takes care of any whitespace surrounding the URL
4808 rv
= NS_NewURI(getter_AddRefs(uri
), uriAttrib
, nsnull
, aBaseURI
);
4809 specifiesURI
= PR_TRUE
;
4812 // No URI or seconds were specified
4813 if (!specifiesSeconds
&& !specifiesURI
)
4815 // Do nothing because the alternative is to spin around in a refresh
4817 return NS_ERROR_FAILURE
;
4820 if (NS_SUCCEEDED(rv
)) {
4821 nsCOMPtr
<nsIScriptSecurityManager
>
4822 securityManager(do_GetService
4823 (NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
4824 if (NS_SUCCEEDED(rv
)) {
4825 rv
= securityManager
->
4826 CheckLoadURI(aBaseURI
, uri
,
4827 nsIScriptSecurityManager::
4828 LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
);
4829 if (NS_SUCCEEDED(rv
)) {
4830 // Since we can't travel back in time yet, just pretend
4831 // negative numbers do nothing at all.
4833 return NS_ERROR_FAILURE
;
4835 rv
= RefreshURI(uri
, seconds
* 1000, PR_FALSE
, PR_TRUE
);
4842 NS_IMETHODIMP
nsDocShell::SetupRefreshURI(nsIChannel
* aChannel
)
4845 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
, &rv
));
4846 if (NS_SUCCEEDED(rv
)) {
4847 nsCAutoString refreshHeader
;
4848 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
4851 if (!refreshHeader
.IsEmpty()) {
4852 SetupReferrerFromChannel(aChannel
);
4853 rv
= SetupRefreshURIFromHeader(mCurrentURI
, refreshHeader
);
4854 if (NS_SUCCEEDED(rv
)) {
4855 return NS_REFRESHURI_HEADER_FOUND
;
4863 DoCancelRefreshURITimers(nsISupportsArray
* aTimerList
)
4869 aTimerList
->Count(&n
);
4872 nsCOMPtr
<nsITimer
> timer(do_QueryElementAt(aTimerList
, --n
));
4874 aTimerList
->RemoveElementAt(n
); // bye bye owning timer ref
4882 nsDocShell::CancelRefreshURITimers()
4884 DoCancelRefreshURITimers(mRefreshURIList
);
4885 DoCancelRefreshURITimers(mSavedRefreshURIList
);
4886 mRefreshURIList
= nsnull
;
4887 mSavedRefreshURIList
= nsnull
;
4893 nsDocShell::GetRefreshPending(PRBool
* _retval
)
4895 if (!mRefreshURIList
) {
4896 *_retval
= PR_FALSE
;
4901 nsresult rv
= mRefreshURIList
->Count(&count
);
4902 if (NS_SUCCEEDED(rv
))
4903 *_retval
= (count
!= 0);
4908 nsDocShell::SuspendRefreshURIs()
4910 if (mRefreshURIList
) {
4912 mRefreshURIList
->Count(&n
);
4914 for (PRUint32 i
= 0; i
< n
; ++i
) {
4915 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
4917 continue; // this must be a nsRefreshURI already
4919 // Replace this timer object with a nsRefreshTimer object.
4920 nsCOMPtr
<nsITimerCallback
> callback
;
4921 timer
->GetCallback(getter_AddRefs(callback
));
4925 nsCOMPtr
<nsITimerCallback
> rt
= do_QueryInterface(callback
);
4926 NS_ASSERTION(rt
, "RefreshURIList timer callbacks should only be RefreshTimer objects");
4928 mRefreshURIList
->ReplaceElementAt(rt
, i
);
4932 // Suspend refresh URIs for our child shells as well.
4933 PRInt32 n
= mChildList
.Count();
4935 for (PRInt32 i
= 0; i
< n
; ++i
) {
4936 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
4938 shell
->SuspendRefreshURIs();
4945 nsDocShell::ResumeRefreshURIs()
4947 RefreshURIFromQueue();
4949 // Resume refresh URIs for our child shells as well.
4950 PRInt32 n
= mChildList
.Count();
4952 for (PRInt32 i
= 0; i
< n
; ++i
) {
4953 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
4955 shell
->ResumeRefreshURIs();
4962 nsDocShell::RefreshURIFromQueue()
4964 if (!mRefreshURIList
)
4967 mRefreshURIList
->Count(&n
);
4970 nsCOMPtr
<nsISupports
> element
;
4971 mRefreshURIList
->GetElementAt(--n
, getter_AddRefs(element
));
4972 nsCOMPtr
<nsITimerCallback
> refreshInfo(do_QueryInterface(element
));
4975 // This is the nsRefreshTimer object, waiting to be
4976 // setup in a timer object and fired.
4977 // Create the timer and trigger it.
4978 PRUint32 delay
= static_cast<nsRefreshTimer
*>(static_cast<nsITimerCallback
*>(refreshInfo
))->GetDelay();
4979 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance("@mozilla.org/timer;1");
4981 // Replace the nsRefreshTimer element in the queue with
4982 // its corresponding timer object, so that in case another
4983 // load comes through before the timer can go off, the timer will
4984 // get cancelled in CancelRefreshURITimer()
4985 mRefreshURIList
->ReplaceElementAt(timer
, n
);
4986 timer
->InitWithCallback(refreshInfo
, delay
, nsITimer::TYPE_ONE_SHOT
);
4994 //*****************************************************************************
4995 // nsDocShell::nsIContentViewerContainer
4996 //*****************************************************************************
4999 nsDocShell::Embed(nsIContentViewer
* aContentViewer
,
5000 const char *aCommand
, nsISupports
* aExtraInfo
)
5002 // Save the LayoutHistoryState of the previous document, before
5003 // setting up new document
5004 PersistLayoutHistoryState();
5006 nsresult rv
= SetupNewViewer(aContentViewer
);
5008 // If we are loading a wyciwyg url from history, change the base URI for
5009 // the document to the original http url that created the document.write().
5010 // This makes sure that all relative urls in a document.written page loaded
5011 // via history work properly.
5013 (mLoadType
& LOAD_CMD_HISTORY
||
5014 mLoadType
== LOAD_RELOAD_NORMAL
||
5015 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
)){
5016 PRBool isWyciwyg
= PR_FALSE
;
5017 // Check if the url is wyciwyg
5018 rv
= mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
5019 if (isWyciwyg
&& NS_SUCCEEDED(rv
))
5020 SetBaseUrlForWyciwyg(aContentViewer
);
5022 // XXX What if SetupNewViewer fails?
5024 // Restore the editing state, if it's stored in session history.
5025 if (mLSHE
->HasDetachedEditor()) {
5026 ReattachEditorToWindow(mLSHE
);
5028 SetHistoryEntry(&mOSHE
, mLSHE
);
5031 PRBool updateHistory
= PR_TRUE
;
5033 // Determine if this type of load should update history
5034 switch (mLoadType
) {
5035 case LOAD_NORMAL_REPLACE
:
5036 case LOAD_STOP_CONTENT_AND_REPLACE
:
5037 case LOAD_RELOAD_BYPASS_CACHE
:
5038 case LOAD_RELOAD_BYPASS_PROXY
:
5039 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
5040 updateHistory
= PR_FALSE
;
5047 SetLayoutHistoryState(nsnull
);
5052 /* void setIsPrinting (in boolean aIsPrinting); */
5054 nsDocShell::SetIsPrinting(PRBool aIsPrinting
)
5056 mIsPrintingOrPP
= aIsPrinting
;
5060 //*****************************************************************************
5061 // nsDocShell::nsIWebProgressListener
5062 //*****************************************************************************
5065 nsDocShell::OnProgressChange(nsIWebProgress
* aProgress
,
5066 nsIRequest
* aRequest
,
5067 PRInt32 aCurSelfProgress
,
5068 PRInt32 aMaxSelfProgress
,
5069 PRInt32 aCurTotalProgress
,
5070 PRInt32 aMaxTotalProgress
)
5076 nsDocShell::OnStateChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
5077 PRUint32 aStateFlags
, nsresult aStatus
)
5081 // Update the busy cursor
5082 if ((~aStateFlags
& (STATE_START
| STATE_IS_NETWORK
)) == 0) {
5083 nsCOMPtr
<nsIWyciwygChannel
> wcwgChannel(do_QueryInterface(aRequest
));
5084 nsCOMPtr
<nsIWebProgress
> webProgress
=
5085 do_QueryInterface(GetAsSupports(this));
5087 // Was the wyciwyg document loaded on this docshell?
5088 if (wcwgChannel
&& !mLSHE
&& (mItemType
== typeContent
) && aProgress
== webProgress
.get()) {
5089 nsCOMPtr
<nsIURI
> uri
;
5090 wcwgChannel
->GetURI(getter_AddRefs(uri
));
5092 PRBool equalUri
= PR_TRUE
;
5093 // Store the wyciwyg url in session history, only if it is
5094 // being loaded fresh for the first time. We don't want
5095 // multiple entries for successive loads
5097 NS_SUCCEEDED(uri
->Equals(mCurrentURI
, &equalUri
)) &&
5099 // This is a document.write(). Get the made-up url
5100 // from the channel and store it in session history.
5101 rv
= AddToSessionHistory(uri
, wcwgChannel
, nsnull
,
5102 getter_AddRefs(mLSHE
));
5103 SetCurrentURI(uri
, aRequest
, PR_TRUE
);
5104 // Save history state of the previous page
5105 rv
= PersistLayoutHistoryState();
5107 SetHistoryEntry(&mOSHE
, mLSHE
);
5111 // Page has begun to load
5112 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_BEFORE_PAGE_LOAD
;
5113 nsCOMPtr
<nsIWidget
> mainWidget
;
5114 GetMainWidget(getter_AddRefs(mainWidget
));
5116 mainWidget
->SetCursor(eCursor_spinning
);
5119 else if ((~aStateFlags
& (STATE_TRANSFERRING
| STATE_IS_DOCUMENT
)) == 0) {
5121 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_PAGE_LOADING
;
5123 else if ((aStateFlags
& STATE_STOP
) && (aStateFlags
& STATE_IS_NETWORK
)) {
5124 // Page has finished loading
5125 mBusyFlags
= BUSY_FLAGS_NONE
;
5126 nsCOMPtr
<nsIWidget
> mainWidget
;
5127 GetMainWidget(getter_AddRefs(mainWidget
));
5129 mainWidget
->SetCursor(eCursor_standard
);
5132 if ((~aStateFlags
& (STATE_IS_DOCUMENT
| STATE_STOP
)) == 0) {
5133 nsCOMPtr
<nsIWebProgress
> webProgress
=
5134 do_QueryInterface(GetAsSupports(this));
5135 // Is the document stop notification for this document?
5136 if (aProgress
== webProgress
.get()) {
5137 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
5138 EndPageLoad(aProgress
, channel
, aStatus
);
5141 // note that redirect state changes will go through here as well, but it
5142 // is better to handle those in OnRedirectStateChange where more
5143 // information is available.
5148 nsDocShell::OnLocationChange(nsIWebProgress
* aProgress
,
5149 nsIRequest
* aRequest
, nsIURI
* aURI
)
5151 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5156 nsDocShell::OnRedirectStateChange(nsIChannel
* aOldChannel
,
5157 nsIChannel
* aNewChannel
,
5158 PRUint32 aRedirectFlags
,
5159 PRUint32 aStateFlags
)
5161 NS_ASSERTION(aStateFlags
& STATE_REDIRECTING
,
5162 "Calling OnRedirectStateChange when there is no redirect");
5163 if (!(aStateFlags
& STATE_IS_DOCUMENT
))
5164 return; // not a toplevel document
5166 // If this load is being checked by the URI classifier, we need to
5167 // query the classifier again for the new URI.
5169 mClassifier
->OnRedirect(aOldChannel
, aNewChannel
);
5172 nsCOMPtr
<nsIGlobalHistory3
> history3(do_QueryInterface(mGlobalHistory
));
5173 nsresult result
= NS_ERROR_NOT_IMPLEMENTED
;
5175 // notify global history of this redirect
5176 result
= history3
->AddDocumentRedirect(aOldChannel
, aNewChannel
,
5177 aRedirectFlags
, !IsFrame());
5180 if (result
== NS_ERROR_NOT_IMPLEMENTED
) {
5181 // when there is no GlobalHistory3, or it doesn't implement
5182 // AddToplevelRedirect, we fall back to GlobalHistory2. Just notify
5183 // that the redirecting page was a rePdirect so it will be link colored
5185 nsCOMPtr
<nsIURI
> oldURI
;
5186 aOldChannel
->GetURI(getter_AddRefs(oldURI
));
5188 return; // nothing to tell anybody about
5189 AddToGlobalHistory(oldURI
, PR_TRUE
, aOldChannel
);
5192 // check if the new load should go through the application cache.
5193 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
5194 do_QueryInterface(aNewChannel
);
5195 if (appCacheChannel
) {
5196 nsCOMPtr
<nsIURI
> newURI
;
5197 aNewChannel
->GetURI(getter_AddRefs(newURI
));
5198 appCacheChannel
->SetChooseApplicationCache(ShouldCheckAppCache(newURI
));
5203 nsDocShell::OnStatusChange(nsIWebProgress
* aWebProgress
,
5204 nsIRequest
* aRequest
,
5205 nsresult aStatus
, const PRUnichar
* aMessage
)
5207 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5212 nsDocShell::OnSecurityChange(nsIWebProgress
* aWebProgress
,
5213 nsIRequest
* aRequest
, PRUint32 state
)
5215 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5221 nsDocShell::EndPageLoad(nsIWebProgress
* aProgress
,
5222 nsIChannel
* aChannel
, nsresult aStatus
)
5225 // one of many safeguards that prevent death and destruction if
5226 // someone is so very very rude as to bring this window down
5227 // during this load handler.
5229 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
5231 // We're done with the URI classifier for this channel
5232 mClassifier
= nsnull
;
5235 // Notify the ContentViewer that the Document has finished loading...
5237 // This will cause any OnLoad(...) handlers to fire, if it is a HTML
5240 if (!mEODForCurrentDocument
&& mContentViewer
) {
5241 mIsExecutingOnLoadHandler
= PR_TRUE
;
5242 mContentViewer
->LoadComplete(aStatus
);
5243 mIsExecutingOnLoadHandler
= PR_FALSE
;
5245 mEODForCurrentDocument
= PR_TRUE
;
5247 // If all documents have completed their loading
5248 // favor native event dispatch priorities
5250 if (--gNumberOfDocumentsLoading
== 0) {
5251 // Hint to use normal native event dispatch priorities
5252 FavorPerformanceHint(PR_FALSE
, NS_EVENT_STARVATION_DELAY_HINT
);
5255 /* Check if the httpChannel has any cache-control related response headers,
5256 * like no-store, no-cache. If so, update SHEntry so that
5257 * when a user goes back/forward to this page, we appropriately do
5258 * form value restoration or load from server.
5260 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
5261 if (!httpChannel
) // HttpChannel could be hiding underneath a Multipart channel.
5262 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
5265 // figure out if SH should be saving layout state.
5266 PRBool discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
5267 if (mLSHE
&& discardLayoutState
&& (mLoadType
& LOAD_CMD_NORMAL
) &&
5268 (mLoadType
!= LOAD_BYPASS_HISTORY
) && (mLoadType
!= LOAD_ERROR_PAGE
))
5269 mLSHE
->SetSaveLayoutStateFlag(PR_FALSE
);
5272 // Clear mLSHE after calling the onLoadHandlers. This way, if the
5273 // onLoadHandler tries to load something different in
5274 // itself or one of its children, we can deal with it appropriately.
5276 mLSHE
->SetLoadType(nsIDocShellLoadInfo::loadHistory
);
5278 // Clear the mLSHE reference to indicate document loading is done one
5280 SetHistoryEntry(&mLSHE
, nsnull
);
5282 // if there's a refresh header in the channel, this method
5283 // will set it up for us.
5284 RefreshURIFromQueue();
5290 //*****************************************************************************
5291 // nsDocShell: Content Viewer Management
5292 //*****************************************************************************
5295 nsDocShell::EnsureContentViewer()
5299 if (mIsBeingDestroyed
)
5300 return NS_ERROR_FAILURE
;
5302 nsIPrincipal
* principal
= nsnull
;
5304 nsCOMPtr
<nsPIDOMWindow
> piDOMWindow(do_QueryInterface(mScriptGlobal
));
5306 principal
= piDOMWindow
->GetOpenerScriptPrincipal();
5310 principal
= GetInheritedPrincipal(PR_FALSE
);
5313 nsresult rv
= CreateAboutBlankContentViewer(principal
);
5315 if (NS_SUCCEEDED(rv
)) {
5316 nsCOMPtr
<nsIDOMDocument
> domDoc
;
5317 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
5318 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(domDoc
));
5320 "Should have doc if CreateAboutBlankContentViewer "
5323 doc
->SetIsInitialDocument(PR_TRUE
);
5330 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal
* aPrincipal
)
5332 nsCOMPtr
<nsIDocument
> blankDoc
;
5333 nsCOMPtr
<nsIContentViewer
> viewer
;
5334 nsresult rv
= NS_ERROR_FAILURE
;
5336 /* mCreatingDocument should never be true at this point. However, it's
5337 a theoretical possibility. We want to know about it and make it stop,
5338 and this sounds like a job for an assertion. */
5339 NS_ASSERTION(!mCreatingDocument
, "infinite(?) loop creating document averted");
5340 if (mCreatingDocument
)
5341 return NS_ERROR_FAILURE
;
5343 mCreatingDocument
= PR_TRUE
;
5345 // mContentViewer->PermitUnload may release |this| docshell.
5346 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
5348 if (mContentViewer
) {
5349 // We've got a content viewer already. Make sure the user
5350 // permits us to discard the current document and replace it
5351 // with about:blank. And also ensure we fire the unload events
5352 // in the current document.
5355 rv
= mContentViewer
->PermitUnload(&okToUnload
);
5357 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
5358 // The user chose not to unload the page, interrupt the load.
5359 return NS_ERROR_FAILURE
;
5362 mSavingOldViewer
= CanSavePresentation(LOAD_NORMAL
, nsnull
, nsnull
);
5364 // Make sure to blow away our mLoadingURI just in case. No loads
5365 // from inside this pagehide.
5366 mLoadingURI
= nsnull
;
5368 // Notify the current document that it is about to be unloaded!!
5370 // It is important to fire the unload() notification *before* any state
5371 // is changed within the DocShell - otherwise, javascript will get the
5372 // wrong information :-(
5374 (void) FirePageHideNotification(!mSavingOldViewer
);
5377 // Now make sure we don't think we're in the middle of firing unload after
5378 // this point. This will make us fire unload when the about:blank document
5379 // unloads... but that's ok, more or less. Would be nice if it fired load
5381 mFiredUnloadEvent
= PR_FALSE
;
5383 // one helper factory, please
5384 nsCOMPtr
<nsICategoryManager
> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID
));
5386 return NS_ERROR_FAILURE
;
5388 nsXPIDLCString contractId
;
5389 rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", "text/html", getter_Copies(contractId
));
5393 nsCOMPtr
<nsIDocumentLoaderFactory
> docFactory(do_GetService(contractId
));
5395 // generate (about:blank) document to load
5396 docFactory
->CreateBlankDocument(mLoadGroup
, aPrincipal
,
5397 getter_AddRefs(blankDoc
));
5399 blankDoc
->SetContainer(static_cast<nsIDocShell
*>(this));
5401 // create a content viewer for us and the new document
5402 docFactory
->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell
*, this),
5403 blankDoc
, "view", getter_AddRefs(viewer
));
5407 viewer
->SetContainer(static_cast<nsIContentViewerContainer
*>(this));
5408 nsCOMPtr
<nsIDOMDocument
> domdoc(do_QueryInterface(blankDoc
));
5409 Embed(viewer
, "", 0);
5410 viewer
->SetDOMDocument(domdoc
);
5412 SetCurrentURI(blankDoc
->GetDocumentURI(), nsnull
, PR_TRUE
);
5417 mCreatingDocument
= PR_FALSE
;
5419 // The transient about:blank viewer doesn't have a session history entry.
5420 SetHistoryEntry(&mOSHE
, nsnull
);
5426 nsDocShell::CanSavePresentation(PRUint32 aLoadType
,
5427 nsIRequest
*aNewRequest
,
5428 nsIDocument
*aNewDocument
)
5431 return PR_FALSE
; // no entry to save into
5433 // Only save presentation for "normal" loads and link loads. Anything else
5434 // probably wants to refetch the page, so caching the old presentation
5435 // would be incorrect.
5436 if (aLoadType
!= LOAD_NORMAL
&&
5437 aLoadType
!= LOAD_HISTORY
&&
5438 aLoadType
!= LOAD_LINK
&&
5439 aLoadType
!= LOAD_STOP_CONTENT
&&
5440 aLoadType
!= LOAD_STOP_CONTENT_AND_REPLACE
&&
5441 aLoadType
!= LOAD_ERROR_PAGE
)
5444 // If the session history entry has the saveLayoutState flag set to false,
5445 // then we should not cache the presentation.
5446 PRBool canSaveState
;
5447 mOSHE
->GetSaveLayoutStateFlag(&canSaveState
);
5448 if (canSaveState
== PR_FALSE
)
5451 // If the document is not done loading, don't cache it.
5452 nsCOMPtr
<nsPIDOMWindow
> pWin
= do_QueryInterface(mScriptGlobal
);
5453 if (!pWin
|| pWin
->IsLoading())
5456 if (pWin
->WouldReuseInnerWindow(aNewDocument
))
5459 // Avoid doing the work of saving the presentation state in the case where
5460 // the content viewer cache is disabled.
5461 if (nsSHistory::GetMaxTotalViewers() == 0)
5464 // Don't cache the content viewer if we're in a subframe and the subframe
5465 // pref is disabled.
5466 PRBool cacheFrames
= PR_FALSE
;
5467 mPrefs
->GetBoolPref("browser.sessionhistory.cache_subframes",
5470 nsCOMPtr
<nsIDocShellTreeItem
> root
;
5471 GetSameTypeParent(getter_AddRefs(root
));
5472 if (root
&& root
!= this) {
5473 return PR_FALSE
; // this is a subframe load
5477 // If the document does not want its presentation cached, then don't.
5478 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(pWin
->GetExtantDocument());
5479 if (!doc
|| !doc
->CanSavePresentation(aNewRequest
))
5486 nsDocShell::ReattachEditorToWindow(nsISHEntry
*aSHEntry
)
5488 NS_ASSERTION(!mEditorData
,
5489 "Why reattach an editor when we already have one?");
5490 NS_ASSERTION(aSHEntry
&& aSHEntry
->HasDetachedEditor(),
5491 "Reattaching when there's not a detached editor.");
5493 if (mEditorData
|| !aSHEntry
)
5496 mEditorData
= aSHEntry
->ForgetEditorData();
5498 nsresult res
= mEditorData
->ReattachToWindow(this);
5499 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to reattach editing session");
5504 nsDocShell::DetachEditorFromWindow(nsISHEntry
*aSHEntry
)
5509 NS_ASSERTION(!aSHEntry
|| !aSHEntry
->HasDetachedEditor(),
5510 "Detaching editor when it's already detached.");
5512 nsresult res
= mEditorData
->DetachFromWindow();
5513 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to detach editor");
5515 if (NS_SUCCEEDED(res
)) {
5516 // Make aSHEntry hold the owning ref to the editor data.
5518 aSHEntry
->SetEditorData(mEditorData
.forget());
5520 mEditorData
= nsnull
;
5526 GetEditable(&isEditable
);
5527 NS_ASSERTION(!isEditable
,
5528 "Window is still editable after detaching editor.");
5535 nsDocShell::DetachEditorFromWindow()
5537 DetachEditorFromWindow(mOSHE
);
5541 nsDocShell::CaptureState()
5543 if (!mOSHE
|| mOSHE
== mLSHE
) {
5544 // No entry to save into, or we're replacing the existing entry.
5545 return NS_ERROR_FAILURE
;
5548 nsCOMPtr
<nsPIDOMWindow
> privWin
= do_QueryInterface(mScriptGlobal
);
5550 return NS_ERROR_FAILURE
;
5552 nsCOMPtr
<nsISupports
> windowState
;
5553 nsresult rv
= privWin
->SaveWindowState(getter_AddRefs(windowState
));
5554 NS_ENSURE_SUCCESS(rv
, rv
);
5556 #ifdef DEBUG_PAGE_CACHE
5557 nsCOMPtr
<nsIURI
> uri
;
5558 mOSHE
->GetURI(getter_AddRefs(uri
));
5562 printf("Saving presentation into session history\n");
5563 printf(" SH URI: %s\n", spec
.get());
5566 rv
= mOSHE
->SetWindowState(windowState
);
5567 NS_ENSURE_SUCCESS(rv
, rv
);
5569 // Suspend refresh URIs and save off the timer queue
5570 rv
= mOSHE
->SetRefreshURIList(mSavedRefreshURIList
);
5571 NS_ENSURE_SUCCESS(rv
, rv
);
5573 // Capture the current content viewer bounds.
5574 nsCOMPtr
<nsIPresShell
> shell
;
5575 nsDocShell::GetPresShell(getter_AddRefs(shell
));
5577 nsIViewManager
*vm
= shell
->GetViewManager();
5579 nsIView
*rootView
= nsnull
;
5580 vm
->GetRootView(rootView
);
5582 nsIWidget
*widget
= rootView
->GetWidget();
5584 nsIntRect
bounds(0, 0, 0, 0);
5585 widget
->GetBounds(bounds
);
5586 rv
= mOSHE
->SetViewerBounds(bounds
);
5592 // Capture the docshell hierarchy.
5593 mOSHE
->ClearChildShells();
5595 PRInt32 childCount
= mChildList
.Count();
5596 for (PRInt32 i
= 0; i
< childCount
; ++i
) {
5597 nsCOMPtr
<nsIDocShellTreeItem
> childShell
= do_QueryInterface(ChildAt(i
));
5598 NS_ASSERTION(childShell
, "null child shell");
5600 mOSHE
->AddChildShell(childShell
);
5607 nsDocShell::RestorePresentationEvent::Run()
5609 if (mDocShell
&& NS_FAILED(mDocShell
->RestoreFromHistory()))
5610 NS_WARNING("RestoreFromHistory failed");
5615 nsDocShell::BeginRestore(nsIContentViewer
*aContentViewer
, PRBool aTop
)
5618 if (!aContentViewer
) {
5619 rv
= EnsureContentViewer();
5620 NS_ENSURE_SUCCESS(rv
, rv
);
5622 aContentViewer
= mContentViewer
;
5625 // Dispatch events for restoring the presentation. We try to simulate
5626 // the progress notifications loading the document would cause, so we add
5627 // the document's channel to the loadgroup to initiate stateChange
5630 nsCOMPtr
<nsIDOMDocument
> domDoc
;
5631 aContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
5632 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
5634 nsIChannel
*channel
= doc
->GetChannel();
5636 mEODForCurrentDocument
= PR_FALSE
;
5637 mIsRestoringDocument
= PR_TRUE
;
5638 mLoadGroup
->AddRequest(channel
, nsnull
);
5639 mIsRestoringDocument
= PR_FALSE
;
5644 // This point corresponds to us having gotten OnStartRequest or
5645 // STATE_START, so do the same thing that CreateContentViewer does at
5646 // this point to ensure that unload/pagehide events for this document
5647 // will fire when it's unloaded again.
5648 mFiredUnloadEvent
= PR_FALSE
;
5650 // For non-top frames, there is no notion of making sure that the
5651 // previous document is in the domwindow when STATE_START notifications
5652 // happen. We can just call BeginRestore for all of the child shells
5654 rv
= BeginRestoreChildren();
5655 NS_ENSURE_SUCCESS(rv
, rv
);
5662 nsDocShell::BeginRestoreChildren()
5664 PRInt32 n
= mChildList
.Count();
5665 for (PRInt32 i
= 0; i
< n
; ++i
) {
5666 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
5668 nsresult rv
= child
->BeginRestore(nsnull
, PR_FALSE
);
5669 NS_ENSURE_SUCCESS(rv
, rv
);
5676 nsDocShell::FinishRestore()
5678 // First we call finishRestore() on our children. In the simulated load,
5679 // all of the child frames finish loading before the main document.
5681 PRInt32 n
= mChildList
.Count();
5682 for (PRInt32 i
= 0; i
< n
; ++i
) {
5683 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
5685 child
->FinishRestore();
5689 if (mOSHE
&& mOSHE
->HasDetachedEditor()) {
5690 ReattachEditorToWindow(mOSHE
);
5693 if (mContentViewer
) {
5694 nsCOMPtr
<nsIDOMDocument
> domDoc
;
5695 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
5697 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
5699 // Finally, we remove the request from the loadgroup. This will
5700 // cause onStateChange(STATE_STOP) to fire, which will fire the
5701 // pageshow event to the chrome.
5703 nsIChannel
*channel
= doc
->GetChannel();
5705 mIsRestoringDocument
= PR_TRUE
;
5706 mLoadGroup
->RemoveRequest(channel
, nsnull
, NS_OK
);
5707 mIsRestoringDocument
= PR_FALSE
;
5716 nsDocShell::GetRestoringDocument(PRBool
*aRestoring
)
5718 *aRestoring
= mIsRestoringDocument
;
5723 nsDocShell::RestorePresentation(nsISHEntry
*aSHEntry
, PRBool
*aRestoring
)
5725 NS_ASSERTION(mLoadType
& LOAD_CMD_HISTORY
,
5726 "RestorePresentation should only be called for history loads");
5728 nsCOMPtr
<nsIContentViewer
> viewer
;
5729 aSHEntry
->GetContentViewer(getter_AddRefs(viewer
));
5731 #ifdef DEBUG_PAGE_CACHE
5732 nsCOMPtr
<nsIURI
> uri
;
5733 aSHEntry
->GetURI(getter_AddRefs(uri
));
5740 *aRestoring
= PR_FALSE
;
5743 #ifdef DEBUG_PAGE_CACHE
5744 printf("no saved presentation for uri: %s\n", spec
.get());
5749 // We need to make sure the content viewer's container is this docshell.
5750 // In subframe navigation, it's possible for the docshell that the
5751 // content viewer was originally loaded into to be replaced with a
5752 // different one. We don't currently support restoring the presentation
5755 nsCOMPtr
<nsISupports
> container
;
5756 viewer
->GetContainer(getter_AddRefs(container
));
5757 if (!::SameCOMIdentity(container
, GetAsSupports(this))) {
5758 #ifdef DEBUG_PAGE_CACHE
5759 printf("No valid container, clearing presentation\n");
5761 aSHEntry
->SetContentViewer(nsnull
);
5762 return NS_ERROR_FAILURE
;
5765 NS_ASSERTION(mContentViewer
!= viewer
, "Restoring existing presentation");
5767 #ifdef DEBUG_PAGE_CACHE
5768 printf("restoring presentation from session history: %s\n", spec
.get());
5771 SetHistoryEntry(&mLSHE
, aSHEntry
);
5773 // Add the request to our load group. We do this before swapping out
5774 // the content viewers so that consumers of STATE_START can access
5775 // the old document. We only deal with the toplevel load at this time --
5776 // to be consistent with normal document loading, subframes cannot start
5777 // loading until after data arrives, which is after STATE_START completes.
5779 BeginRestore(viewer
, PR_TRUE
);
5781 // Post an event that will remove the request after we've returned
5782 // to the event loop. This mimics the way it is called by nsIChannel
5785 // Revoke any pending restore (just in case)
5786 NS_ASSERTION(!mRestorePresentationEvent
.IsPending(),
5787 "should only have one RestorePresentationEvent");
5788 mRestorePresentationEvent
.Revoke();
5790 nsRefPtr
<RestorePresentationEvent
> evt
= new RestorePresentationEvent(this);
5791 nsresult rv
= NS_DispatchToCurrentThread(evt
);
5792 if (NS_SUCCEEDED(rv
)) {
5793 mRestorePresentationEvent
= evt
.get();
5794 // The rest of the restore processing will happen on our event
5796 *aRestoring
= PR_TRUE
;
5803 nsDocShell::RestoreFromHistory()
5805 mRestorePresentationEvent
.Forget();
5807 // This section of code follows the same ordering as CreateContentViewer.
5809 return NS_ERROR_FAILURE
;
5811 nsCOMPtr
<nsIContentViewer
> viewer
;
5812 mLSHE
->GetContentViewer(getter_AddRefs(viewer
));
5814 return NS_ERROR_FAILURE
;
5816 if (mSavingOldViewer
) {
5817 // We determined that it was safe to cache the document presentation
5818 // at the time we initiated the new load. We need to check whether
5819 // it's still safe to do so, since there may have been DOM mutations
5820 // or new requests initiated.
5821 nsCOMPtr
<nsIDOMDocument
> domDoc
;
5822 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
5823 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
5824 nsIRequest
*request
= nsnull
;
5826 request
= doc
->GetChannel();
5827 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
5830 nsCOMPtr
<nsIMarkupDocumentViewer
> oldMUDV(do_QueryInterface(mContentViewer
));
5831 nsCOMPtr
<nsIMarkupDocumentViewer
> newMUDV(do_QueryInterface(viewer
));
5832 float textZoom
= 1.0f
;
5833 float pageZoom
= 1.0f
;
5834 if (oldMUDV
&& newMUDV
) {
5835 oldMUDV
->GetTextZoom(&textZoom
);
5836 oldMUDV
->GetFullZoom(&pageZoom
);
5839 // Protect against mLSHE going away via a load triggered from
5840 // pagehide or unload.
5841 nsCOMPtr
<nsISHEntry
> origLSHE
= mLSHE
;
5843 // Make sure to blow away our mLoadingURI just in case. No loads
5844 // from inside this pagehide.
5845 mLoadingURI
= nsnull
;
5847 // Notify the old content viewer that it's being hidden.
5848 FirePageHideNotification(!mSavingOldViewer
);
5850 // If mLSHE was changed as a result of the pagehide event, then
5851 // something else was loaded. Don't finish restoring.
5852 if (mLSHE
!= origLSHE
)
5855 // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
5856 // *new* document will fire.
5857 mFiredUnloadEvent
= PR_FALSE
;
5859 mURIResultedInDocument
= PR_TRUE
;
5860 nsCOMPtr
<nsISHistory
> rootSH
;
5861 GetRootSessionHistory(getter_AddRefs(rootSH
));
5863 nsCOMPtr
<nsISHistoryInternal
> hist
= do_QueryInterface(rootSH
);
5864 rootSH
->GetIndex(&mPreviousTransIndex
);
5865 hist
->UpdateIndex();
5866 rootSH
->GetIndex(&mLoadedTransIndex
);
5867 #ifdef DEBUG_PAGE_CACHE
5868 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
5873 // Rather than call Embed(), we will retrieve the viewer from the session
5874 // history entry and swap it in.
5875 // XXX can we refactor this so that we can just call Embed()?
5876 PersistLayoutHistoryState();
5878 if (mContentViewer
) {
5879 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
5881 mOSHE
->SyncPresentationState();
5883 mSavingOldViewer
= PR_FALSE
;
5887 mSavedRefreshURIList
= nsnull
;
5889 // In cases where we use a transient about:blank viewer between loads,
5890 // we never show the transient viewer, so _its_ previous viewer is never
5891 // unhooked from the view hierarchy. Destroy any such previous viewer now,
5892 // before we grab the root view sibling, so that we don't grab a view
5893 // that's about to go away.
5895 if (mContentViewer
) {
5896 nsCOMPtr
<nsIContentViewer
> previousViewer
;
5897 mContentViewer
->GetPreviousViewer(getter_AddRefs(previousViewer
));
5898 if (previousViewer
) {
5899 mContentViewer
->SetPreviousViewer(nsnull
);
5900 previousViewer
->Destroy();
5904 // Save off the root view's parent and sibling so that we can insert the
5905 // new content viewer's root view at the same position. Also save the
5906 // bounds of the root view's widget.
5908 nsIView
*rootViewSibling
= nsnull
, *rootViewParent
= nsnull
;
5909 nsIntRect
newBounds(0, 0, 0, 0);
5911 nsCOMPtr
<nsIPresShell
> oldPresShell
;
5912 nsDocShell::GetPresShell(getter_AddRefs(oldPresShell
));
5914 nsIViewManager
*vm
= oldPresShell
->GetViewManager();
5916 nsIView
*oldRootView
= nsnull
;
5917 vm
->GetRootView(oldRootView
);
5920 rootViewSibling
= oldRootView
->GetNextSibling();
5921 rootViewParent
= oldRootView
->GetParent();
5923 nsIWidget
*widget
= oldRootView
->GetWidget();
5925 widget
->GetBounds(newBounds
);
5931 // Transfer ownership to mContentViewer. By ensuring that either the
5932 // docshell or the session history, but not both, have references to the
5933 // content viewer, we prevent the viewer from being torn down after
5934 // Destroy() is called.
5936 if (mContentViewer
) {
5937 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nsnull
);
5938 viewer
->SetPreviousViewer(mContentViewer
);
5941 mContentViewer
.swap(viewer
);
5942 viewer
= nsnull
; // force a release to complete ownership transfer
5944 // Grab all of the related presentation from the SHEntry now.
5945 // Clearing the viewer from the SHEntry will clear all of this state.
5946 nsCOMPtr
<nsISupports
> windowState
;
5947 mLSHE
->GetWindowState(getter_AddRefs(windowState
));
5948 mLSHE
->SetWindowState(nsnull
);
5951 mLSHE
->GetSticky(&sticky
);
5953 nsCOMPtr
<nsIDOMDocument
> domDoc
;
5954 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
5956 nsCOMArray
<nsIDocShellTreeItem
> childShells
;
5958 nsCOMPtr
<nsIDocShellTreeItem
> child
;
5959 while (NS_SUCCEEDED(mLSHE
->ChildShellAt(i
++, getter_AddRefs(child
))) &&
5961 childShells
.AppendObject(child
);
5964 // get the previous content viewer size
5965 nsIntRect
oldBounds(0, 0, 0, 0);
5966 mLSHE
->GetViewerBounds(oldBounds
);
5968 // Restore the refresh URI list. The refresh timers will be restarted
5969 // when EndPageLoad() is called.
5970 nsCOMPtr
<nsISupportsArray
> refreshURIList
;
5971 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIList
));
5973 // Reattach to the window object.
5974 rv
= mContentViewer
->Open(windowState
, mLSHE
);
5976 // Now remove it from the cached presentation.
5977 mLSHE
->SetContentViewer(nsnull
);
5978 mEODForCurrentDocument
= PR_FALSE
;
5982 nsCOMPtr
<nsISupportsArray
> refreshURIs
;
5983 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIs
));
5984 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
5985 mLSHE
->ChildShellAt(0, getter_AddRefs(childShell
));
5986 NS_ASSERTION(!refreshURIs
&& !childShell
,
5987 "SHEntry should have cleared presentation state");
5991 // Restore the sticky state of the viewer. The viewer has set this state
5992 // on the history entry in Destroy() just before marking itself non-sticky,
5993 // to avoid teardown of the presentation.
5994 mContentViewer
->SetSticky(sticky
);
5996 // Now that we have switched documents, forget all of our children.
5998 NS_ENSURE_SUCCESS(rv
, rv
);
6000 // mLSHE is now our currently-loaded document.
6001 SetHistoryEntry(&mOSHE
, mLSHE
);
6003 // XXX special wyciwyg handling in Embed()?
6005 // We aren't going to restore any items from the LayoutHistoryState,
6006 // but we don't want them to stay around in case the page is reloaded.
6007 SetLayoutHistoryState(nsnull
);
6009 // This is the end of our Embed() replacement
6011 mSavingOldViewer
= PR_FALSE
;
6012 mEODForCurrentDocument
= PR_FALSE
;
6014 // Tell the event loop to favor plevents over user events, see comments
6015 // in CreateContentViewer.
6016 if (++gNumberOfDocumentsLoading
== 1)
6017 FavorPerformanceHint(PR_TRUE
, NS_EVENT_STARVATION_DELAY_HINT
);
6020 if (oldMUDV
&& newMUDV
) {
6021 newMUDV
->SetTextZoom(textZoom
);
6022 newMUDV
->SetFullZoom(pageZoom
);
6025 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDoc
);
6027 // Use the uri from the mLSHE we had when we entered this function
6028 // (which need not match the document's URI if anchors are involved),
6029 // since that's the history entry we're loading. Note that if we use
6030 // origLSHE we don't have to worry about whether the entry in question
6031 // is still mLSHE or whether it's now mOSHE.
6032 nsCOMPtr
<nsIURI
> uri
;
6033 origLSHE
->GetURI(getter_AddRefs(uri
));
6034 SetCurrentURI(uri
, document
->GetChannel(), PR_TRUE
);
6037 // This is the end of our CreateContentViewer() replacement.
6038 // Now we simulate a load. First, we restore the state of the javascript
6040 nsCOMPtr
<nsPIDOMWindow
> privWin
=
6041 do_GetInterface(static_cast<nsIInterfaceRequestor
*>(this));
6042 NS_ASSERTION(privWin
, "could not get nsPIDOMWindow interface");
6044 rv
= privWin
->RestoreWindowState(windowState
);
6045 NS_ENSURE_SUCCESS(rv
, rv
);
6047 // Now, dispatch a title change event which would happen as the
6048 // <head> is parsed.
6049 document
->NotifyPossibleTitleChange(PR_FALSE
);
6051 // Now we simulate appending child docshells for subframes.
6052 for (i
= 0; i
< childShells
.Count(); ++i
) {
6053 nsIDocShellTreeItem
*childItem
= childShells
.ObjectAt(i
);
6054 nsCOMPtr
<nsIDocShell
> childShell
= do_QueryInterface(childItem
);
6056 // Make sure to not clobber the state of the child. Since AddChild
6057 // always clobbers it, save it off first.
6058 PRBool allowPlugins
;
6059 childShell
->GetAllowPlugins(&allowPlugins
);
6061 PRBool allowJavascript
;
6062 childShell
->GetAllowJavascript(&allowJavascript
);
6064 PRBool allowRedirects
;
6065 childShell
->GetAllowMetaRedirects(&allowRedirects
);
6067 PRBool allowSubframes
;
6068 childShell
->GetAllowSubframes(&allowSubframes
);
6071 childShell
->GetAllowImages(&allowImages
);
6073 AddChild(childItem
);
6075 childShell
->SetAllowPlugins(allowPlugins
);
6076 childShell
->SetAllowJavascript(allowJavascript
);
6077 childShell
->SetAllowMetaRedirects(allowRedirects
);
6078 childShell
->SetAllowSubframes(allowSubframes
);
6079 childShell
->SetAllowImages(allowImages
);
6081 rv
= childShell
->BeginRestore(nsnull
, PR_FALSE
);
6082 NS_ENSURE_SUCCESS(rv
, rv
);
6085 nsCOMPtr
<nsIPresShell
> shell
;
6086 nsDocShell::GetPresShell(getter_AddRefs(shell
));
6088 nsIViewManager
*newVM
= shell
? shell
->GetViewManager() : nsnull
;
6089 nsIView
*newRootView
= nsnull
;
6091 newVM
->GetRootView(newRootView
);
6093 // Insert the new root view at the correct location in the view tree.
6094 if (rootViewParent
) {
6095 nsIViewManager
*parentVM
= rootViewParent
->GetViewManager();
6097 if (parentVM
&& newRootView
) {
6098 // InsertChild(parent, child, sib, PR_TRUE) inserts the child after
6099 // sib in content order, which is before sib in view order. BUT
6100 // when sib is null it inserts at the end of the the document
6101 // order, i.e., first in view order. But when oldRootSibling is
6102 // null, the old root as at the end of the view list --- last in
6103 // content order --- and we want to call InsertChild(parent, child,
6104 // nsnull, PR_FALSE) in that case.
6105 parentVM
->InsertChild(rootViewParent
, newRootView
,
6107 rootViewSibling
? PR_TRUE
: PR_FALSE
);
6109 NS_ASSERTION(newRootView
->GetNextSibling() == rootViewSibling
,
6110 "error in InsertChild");
6114 // Now that all of the child docshells have been put into place, we can
6115 // restart the timers for the window and all of the child frames.
6116 privWin
->ResumeTimeouts();
6118 // Restore the refresh URI list. The refresh timers will be restarted
6119 // when EndPageLoad() is called.
6120 mRefreshURIList
= refreshURIList
;
6122 // Meta-refresh timers have been restarted for this shell, but not
6123 // for our children. Walk the child shells and restart their timers.
6124 PRInt32 n
= mChildList
.Count();
6125 for (i
= 0; i
< n
; ++i
) {
6126 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
6128 child
->ResumeRefreshURIs();
6131 // Make sure this presentation is the same size as the previous
6132 // presentation. If this is not the same size we showed it at last time,
6133 // then we need to resize the widget.
6135 // XXXbryner This interacts poorly with Firefox's infobar. If the old
6136 // presentation had the infobar visible, then we will resize the new
6137 // presentation to that smaller size. However, firing the locationchanged
6138 // event will hide the infobar, which will immediately resize the window
6139 // back to the larger size. A future optimization might be to restore
6140 // the presentation at the "wrong" size, then fire the locationchanged
6141 // event and check whether the docshell's new size is the same as the
6142 // cached viewer size (skipping the resize if they are equal).
6145 nsIWidget
*widget
= newRootView
->GetWidget();
6146 if (widget
&& !newBounds
.IsEmpty() && newBounds
!= oldBounds
) {
6147 #ifdef DEBUG_PAGE_CACHE
6148 printf("resize widget(%d, %d, %d, %d)\n", newBounds
.x
,
6149 newBounds
.y
, newBounds
.width
, newBounds
.height
);
6152 widget
->Resize(newBounds
.x
, newBounds
.y
, newBounds
.width
,
6153 newBounds
.height
, PR_FALSE
);
6157 // Simulate the completion of the load.
6158 nsDocShell::FinishRestore();
6160 // Restart plugins, and paint the content.
6164 return privWin
->FireDelayedDOMEvents();
6168 nsDocShell::CreateContentViewer(const char *aContentType
,
6169 nsIRequest
* request
,
6170 nsIStreamListener
** aContentHandler
)
6172 *aContentHandler
= nsnull
;
6174 // Can we check the content type of the current content viewer
6175 // and reuse it without destroying it and re-creating it?
6177 NS_ASSERTION(mLoadGroup
, "Someone ignored return from Init()?");
6179 // Instantiate the content viewer object
6180 nsCOMPtr
<nsIContentViewer
> viewer
;
6181 nsresult rv
= NewContentViewerObj(aContentType
, request
, mLoadGroup
,
6182 aContentHandler
, getter_AddRefs(viewer
));
6185 return NS_ERROR_FAILURE
;
6187 // Notify the current document that it is about to be unloaded!!
6189 // It is important to fire the unload() notification *before* any state
6190 // is changed within the DocShell - otherwise, javascript will get the
6191 // wrong information :-(
6194 if (mSavingOldViewer
) {
6195 // We determined that it was safe to cache the document presentation
6196 // at the time we initiated the new load. We need to check whether
6197 // it's still safe to do so, since there may have been DOM mutations
6198 // or new requests initiated.
6199 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6200 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6201 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
6202 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
6205 NS_ASSERTION(!mLoadingURI
, "Re-entering unload?");
6207 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(request
);
6208 if (aOpenedChannel
) {
6209 aOpenedChannel
->GetURI(getter_AddRefs(mLoadingURI
));
6211 FirePageHideNotification(!mSavingOldViewer
);
6212 mLoadingURI
= nsnull
;
6214 // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
6215 // *new* document will fire.
6216 mFiredUnloadEvent
= PR_FALSE
;
6218 // we've created a new document so go ahead and call
6219 // OnLoadingSite(), but don't fire OnLocationChange()
6220 // notifications before we've called Embed(). See bug 284993.
6221 mURIResultedInDocument
= PR_TRUE
;
6223 PRBool onLocationChangeNeeded
= OnLoadingSite(aOpenedChannel
, PR_FALSE
);
6225 // let's try resetting the load group if we need to...
6226 nsCOMPtr
<nsILoadGroup
> currentLoadGroup
;
6227 NS_ENSURE_SUCCESS(aOpenedChannel
->
6228 GetLoadGroup(getter_AddRefs(currentLoadGroup
)),
6231 if (currentLoadGroup
!= mLoadGroup
) {
6232 nsLoadFlags loadFlags
= 0;
6234 //Cancel any URIs that are currently loading...
6235 /// XXX: Need to do this eventually Stop();
6237 // Retarget the document to this loadgroup...
6239 /* First attach the channel to the right loadgroup
6240 * and then remove from the old loadgroup. This
6241 * puts the notifications in the right order and
6242 * we don't null-out mLSHE in OnStateChange() for
6243 * all redirected urls
6245 aOpenedChannel
->SetLoadGroup(mLoadGroup
);
6247 // Mark the channel as being a document URI...
6248 aOpenedChannel
->GetLoadFlags(&loadFlags
);
6249 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
;
6251 aOpenedChannel
->SetLoadFlags(loadFlags
);
6253 mLoadGroup
->AddRequest(request
, nsnull
);
6254 if (currentLoadGroup
)
6255 currentLoadGroup
->RemoveRequest(request
, nsnull
,
6256 NS_BINDING_RETARGETED
);
6258 // Update the notification callbacks, so that progress and
6259 // status information are sent to the right docshell...
6260 aOpenedChannel
->SetNotificationCallbacks(this);
6263 NS_ENSURE_SUCCESS(Embed(viewer
, "", (nsISupports
*) nsnull
),
6266 mSavedRefreshURIList
= nsnull
;
6267 mSavingOldViewer
= PR_FALSE
;
6268 mEODForCurrentDocument
= PR_FALSE
;
6270 // if this document is part of a multipart document,
6271 // the ID can be used to distinguish it from the other parts.
6272 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(request
));
6273 if (multiPartChannel
) {
6274 nsCOMPtr
<nsIPresShell
> shell
;
6275 rv
= GetPresShell(getter_AddRefs(shell
));
6276 if (NS_SUCCEEDED(rv
) && shell
) {
6277 nsIDocument
*doc
= shell
->GetDocument();
6280 multiPartChannel
->GetPartID(&partID
);
6281 doc
->SetPartID(partID
);
6286 // Give hint to native plevent dispatch mechanism. If a document
6287 // is loading the native plevent dispatch mechanism should favor
6288 // performance over normal native event dispatch priorities.
6289 if (++gNumberOfDocumentsLoading
== 1) {
6290 // Hint to favor performance for the plevent notification mechanism.
6291 // We want the pages to load as fast as possible even if its means
6292 // native messages might be starved.
6293 FavorPerformanceHint(PR_TRUE
, NS_EVENT_STARVATION_DELAY_HINT
);
6296 if (onLocationChangeNeeded
) {
6297 FireOnLocationChange(this, request
, mCurrentURI
);
6304 nsDocShell::NewContentViewerObj(const char *aContentType
,
6305 nsIRequest
* request
, nsILoadGroup
* aLoadGroup
,
6306 nsIStreamListener
** aContentHandler
,
6307 nsIContentViewer
** aViewer
)
6309 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(request
);
6312 nsCOMPtr
<nsICategoryManager
> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID
, &rv
));
6316 nsXPIDLCString contractId
;
6317 rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", aContentType
, getter_Copies(contractId
));
6319 // Create an instance of the document-loader-factory
6320 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
;
6321 if (NS_SUCCEEDED(rv
))
6322 docLoaderFactory
= do_GetService(contractId
.get());
6324 if (!docLoaderFactory
) {
6325 return NS_ERROR_FAILURE
;
6328 // Now create an instance of the content viewer
6329 // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
6330 NS_ENSURE_SUCCESS(docLoaderFactory
->CreateInstance("view",
6332 aLoadGroup
, aContentType
,
6333 static_cast<nsIContentViewerContainer
*>(this),
6339 (*aViewer
)->SetContainer(static_cast<nsIContentViewerContainer
*>(this));
6344 nsDocShell::SetupNewViewer(nsIContentViewer
* aNewViewer
)
6347 // Copy content viewer state from previous or parent content viewer.
6349 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
6351 // Do NOT to maintain a reference to the old content viewer outside
6352 // of this "copying" block, or it will not be destroyed until the end of
6353 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
6355 // In this block of code, if we get an error result, we return it
6356 // but if we get a null pointer, that's perfectly legal for parent
6357 // and parentContentViewer.
6365 // This will get the size from the current content viewer or from the
6367 DoGetPositionAndSize(&x
, &y
, &cx
, &cy
);
6369 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
6370 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem
)),
6372 nsCOMPtr
<nsIDocShell
> parent(do_QueryInterface(parentAsItem
));
6374 nsCAutoString defaultCharset
;
6375 nsCAutoString forceCharset
;
6376 nsCAutoString hintCharset
;
6377 PRInt32 hintCharsetSource
;
6378 nsCAutoString prevDocCharset
;
6381 PRBool styleDisabled
;
6382 // |newMUDV| also serves as a flag to set the data from the above vars
6383 nsCOMPtr
<nsIMarkupDocumentViewer
> newMUDV
;
6385 if (mContentViewer
|| parent
) {
6386 nsCOMPtr
<nsIMarkupDocumentViewer
> oldMUDV
;
6387 if (mContentViewer
) {
6388 // Get any interesting state from old content viewer
6389 // XXX: it would be far better to just reuse the document viewer ,
6390 // since we know we're just displaying the same document as before
6391 oldMUDV
= do_QueryInterface(mContentViewer
);
6393 // Tell the old content viewer to hibernate in session history when
6396 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
6398 mOSHE
->SyncPresentationState();
6400 mSavingOldViewer
= PR_FALSE
;
6404 // No old content viewer, so get state from parent's content viewer
6405 nsCOMPtr
<nsIContentViewer
> parentContentViewer
;
6406 parent
->GetContentViewer(getter_AddRefs(parentContentViewer
));
6407 oldMUDV
= do_QueryInterface(parentContentViewer
);
6413 newMUDV
= do_QueryInterface(aNewViewer
,&rv
);
6415 NS_ENSURE_SUCCESS(oldMUDV
->
6416 GetDefaultCharacterSet(defaultCharset
),
6418 NS_ENSURE_SUCCESS(oldMUDV
->
6419 GetForceCharacterSet(forceCharset
),
6421 NS_ENSURE_SUCCESS(oldMUDV
->
6422 GetHintCharacterSet(hintCharset
),
6424 NS_ENSURE_SUCCESS(oldMUDV
->
6425 GetHintCharacterSetSource(&hintCharsetSource
),
6427 NS_ENSURE_SUCCESS(oldMUDV
->
6428 GetTextZoom(&textZoom
),
6430 NS_ENSURE_SUCCESS(oldMUDV
->
6431 GetFullZoom(&pageZoom
),
6433 NS_ENSURE_SUCCESS(oldMUDV
->
6434 GetAuthorStyleDisabled(&styleDisabled
),
6436 NS_ENSURE_SUCCESS(oldMUDV
->
6437 GetPrevDocCharacterSet(prevDocCharset
),
6443 // It is necessary to obtain the focus controller to utilize its ability
6444 // to suppress focus. This is necessary to fix Win32-only bugs related to
6445 // a loss of focus when mContentViewer is set to null. The internal window
6446 // is destroyed, and the OS focuses the parent window. This call ends up
6447 // notifying the focus controller that the outer window should focus
6448 // and this hoses us on any link traversal.
6450 // Please do not touch any of the focus controller code here without
6451 // testing bugs #28580 and 50509. These are immensely important bugs,
6452 // so PLEASE take care not to regress them if you decide to alter this
6453 // code later -- hyatt
6454 nsIFocusController
*focusController
= nsnull
;
6455 if (mScriptGlobal
) {
6456 nsCOMPtr
<nsPIDOMWindow
> ourWindow
= do_QueryInterface(mScriptGlobal
);
6457 focusController
= ourWindow
->GetRootFocusController();
6458 if (focusController
) {
6459 // Suppress the command dispatcher.
6460 focusController
->SetSuppressFocus(PR_TRUE
,
6461 "Win32-Only Link Traversal Issue");
6462 // Remove focus from the element that has it
6463 nsCOMPtr
<nsIDOMWindowInternal
> focusedWindow
;
6464 focusController
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
6466 // We want to null out the last focused element if the document containing
6467 // it is going away. If the last focused element is in a descendent
6468 // window of our domwindow, its document will be destroyed when we
6469 // destroy our children. So, check for this case and null out the
6470 // last focused element. See bug 70484.
6472 PRBool isSubWindow
= PR_FALSE
;
6473 nsCOMPtr
<nsIDOMWindow
> curwin
;
6475 focusedWindow
->GetParent(getter_AddRefs(curwin
));
6477 if (curwin
== ourWindow
) {
6478 isSubWindow
= PR_TRUE
;
6482 // don't use nsCOMPtr here to avoid extra addref
6483 // when assigning to curwin
6485 curwin
->GetParent(&temp
);
6486 if (curwin
== temp
) {
6490 curwin
= dont_AddRef(temp
);
6493 if (ourWindow
== focusedWindow
|| isSubWindow
)
6494 focusController
->ResetElementFocus();
6498 nscolor bgcolor
= NS_RGBA(0, 0, 0, 0);
6499 PRBool bgSet
= PR_FALSE
;
6501 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
6502 nsCOMPtr
<nsIContentViewer
> kungfuDeathGrip
= mContentViewer
;
6503 if (mContentViewer
) {
6504 // Stop any activity that may be happening in the old document before
6506 mContentViewer
->Stop();
6508 // Try to extract the default background color from the old
6509 // view manager, so we can use it for the next document.
6510 nsCOMPtr
<nsIDocumentViewer
> docviewer
=
6511 do_QueryInterface(mContentViewer
);
6514 nsCOMPtr
<nsIPresShell
> shell
;
6515 docviewer
->GetPresShell(getter_AddRefs(shell
));
6518 nsIViewManager
* vm
= shell
->GetViewManager();
6521 vm
->GetDefaultBackgroundColor(&bgcolor
);
6522 // If the background color is not known, don't propagate it.
6523 bgSet
= NS_GET_A(bgcolor
) != 0;
6528 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nsnull
);
6529 aNewViewer
->SetPreviousViewer(mContentViewer
);
6531 mContentViewer
= nsnull
;
6534 mContentViewer
= aNewViewer
;
6536 nsCOMPtr
<nsIWidget
> widget
;
6537 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget
)), NS_ERROR_FAILURE
);
6539 nsIntRect
bounds(x
, y
, cx
, cy
);
6541 if (NS_FAILED(mContentViewer
->Init(widget
, bounds
))) {
6542 mContentViewer
= nsnull
;
6543 NS_ERROR("ContentViewer Initialization failed");
6544 return NS_ERROR_FAILURE
;
6547 // If we have old state to copy, set the old state onto the new content
6550 NS_ENSURE_SUCCESS(newMUDV
->SetDefaultCharacterSet(defaultCharset
),
6552 NS_ENSURE_SUCCESS(newMUDV
->SetForceCharacterSet(forceCharset
),
6554 NS_ENSURE_SUCCESS(newMUDV
->SetHintCharacterSet(hintCharset
),
6556 NS_ENSURE_SUCCESS(newMUDV
->
6557 SetHintCharacterSetSource(hintCharsetSource
),
6559 NS_ENSURE_SUCCESS(newMUDV
->SetPrevDocCharacterSet(prevDocCharset
),
6561 NS_ENSURE_SUCCESS(newMUDV
->SetTextZoom(textZoom
),
6563 NS_ENSURE_SUCCESS(newMUDV
->SetFullZoom(pageZoom
),
6565 NS_ENSURE_SUCCESS(newMUDV
->SetAuthorStyleDisabled(styleDisabled
),
6569 // End copying block (Don't mess with the old content/document viewer
6572 // See the book I wrote above regarding why the focus controller is
6573 // being used here. -- hyatt
6575 /* Note it's important that focus suppression be turned off no earlier
6576 because in cases where the docshell is lazily creating an about:blank
6577 document, mContentViewer->Init finally puts a reference to that
6578 document into the DOM window, which prevents an infinite recursion
6579 attempting to lazily create the document as focus is unsuppressed
6581 if (focusController
)
6582 focusController
->SetSuppressFocus(PR_FALSE
,
6583 "Win32-Only Link Traversal Issue");
6585 if (bgSet
&& widget
) {
6586 // Stuff the bgcolor from the last view manager into the new
6587 // view manager. This improves page load continuity.
6588 nsCOMPtr
<nsIDocumentViewer
> docviewer
=
6589 do_QueryInterface(mContentViewer
);
6592 nsCOMPtr
<nsIPresShell
> shell
;
6593 docviewer
->GetPresShell(getter_AddRefs(shell
));
6596 nsIViewManager
* vm
= shell
->GetViewManager();
6599 vm
->SetDefaultBackgroundColor(bgcolor
);
6605 // XXX: It looks like the LayoutState gets restored again in Embed()
6606 // right after the call to SetupNewViewer(...)
6608 // We don't show the mContentViewer yet, since we want to draw the old page
6609 // until we have enough of the new page to show. Just return with the new
6610 // viewer still set to hidden.
6612 // Now that we have switched documents, forget all of our children
6620 nsDocShell::CheckLoadingPermissions()
6622 // This method checks whether the caller may load content into
6623 // this docshell. Even though we've done our best to hide windows
6624 // from code that doesn't have the right to access them, it's
6625 // still possible for an evil site to open a window and access
6626 // frames in the new window through window.frames[] (which is
6627 // allAccess for historic reasons), so we still need to do this
6629 nsresult rv
= NS_OK
, sameOrigin
= NS_OK
;
6631 if (!gValidateOrigin
|| !IsFrame()) {
6632 // Origin validation was turned off, or we're not a frame.
6633 // Permit all loads.
6638 // We're a frame. Check that the caller has write permission to
6639 // the parent before allowing it to load anything into this
6642 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
6643 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
6644 NS_ENSURE_SUCCESS(rv
, rv
);
6646 PRBool ubwEnabled
= PR_FALSE
;
6647 rv
= securityManager
->IsCapabilityEnabled("UniversalBrowserWrite",
6649 if (NS_FAILED(rv
) || ubwEnabled
) {
6653 nsCOMPtr
<nsIPrincipal
> subjPrincipal
;
6654 rv
= securityManager
->GetSubjectPrincipal(getter_AddRefs(subjPrincipal
));
6655 NS_ENSURE_TRUE(NS_SUCCEEDED(rv
) && subjPrincipal
, rv
);
6657 // Check if the caller is from the same origin as this docshell,
6658 // or any of it's ancestors.
6659 nsCOMPtr
<nsIDocShellTreeItem
> item(this);
6661 nsCOMPtr
<nsIScriptGlobalObject
> sgo(do_GetInterface(item
));
6662 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(sgo
));
6665 if (!sop
|| !(p
= sop
->GetPrincipal())) {
6666 return NS_ERROR_UNEXPECTED
;
6671 sameOrigin
= subjPrincipal
->Equals(p
, &equal
);
6672 if (NS_SUCCEEDED(sameOrigin
)) {
6674 // Same origin, permit load
6679 sameOrigin
= NS_ERROR_DOM_PROP_ACCESS_DENIED
;
6682 nsCOMPtr
<nsIDocShellTreeItem
> tmp
;
6683 item
->GetSameTypeParent(getter_AddRefs(tmp
));
6690 //*****************************************************************************
6691 // nsDocShell: Site Loading
6692 //*****************************************************************************
6693 class InternalLoadEvent
: public nsRunnable
6696 InternalLoadEvent(nsDocShell
* aDocShell
, nsIURI
* aURI
, nsIURI
* aReferrer
,
6697 nsISupports
* aOwner
, PRUint32 aFlags
,
6698 const char* aTypeHint
, nsIInputStream
* aPostData
,
6699 nsIInputStream
* aHeadersData
, PRUint32 aLoadType
,
6700 nsISHEntry
* aSHEntry
, PRBool aFirstParty
) :
6701 mDocShell(aDocShell
),
6703 mReferrer(aReferrer
),
6706 mPostData(aPostData
),
6707 mHeadersData(aHeadersData
),
6708 mLoadType(aLoadType
),
6710 mFirstParty(aFirstParty
)
6712 // Make sure to keep null things null as needed
6714 mTypeHint
= aTypeHint
;
6719 return mDocShell
->InternalLoad(mURI
, mReferrer
, mOwner
, mFlags
,
6720 nsnull
, mTypeHint
.get(),
6721 mPostData
, mHeadersData
, mLoadType
,
6722 mSHEntry
, mFirstParty
, nsnull
, nsnull
);
6726 nsRefPtr
<nsDocShell
> mDocShell
;
6727 nsCOMPtr
<nsIURI
> mURI
;
6728 nsCOMPtr
<nsIURI
> mReferrer
;
6729 nsCOMPtr
<nsISupports
> mOwner
;
6732 // Use IDL strings so .get() returns null by default
6733 nsXPIDLString mWindowTarget
;
6734 nsXPIDLCString mTypeHint
;
6736 nsCOMPtr
<nsIInputStream
> mPostData
;
6737 nsCOMPtr
<nsIInputStream
> mHeadersData
;
6739 nsCOMPtr
<nsISHEntry
> mSHEntry
;
6744 nsDocShell::InternalLoad(nsIURI
* aURI
,
6746 nsISupports
* aOwner
,
6748 const PRUnichar
*aWindowTarget
,
6749 const char* aTypeHint
,
6750 nsIInputStream
* aPostData
,
6751 nsIInputStream
* aHeadersData
,
6753 nsISHEntry
* aSHEntry
,
6755 nsIDocShell
** aDocShell
,
6756 nsIRequest
** aRequest
)
6758 nsresult rv
= NS_OK
;
6761 if (gDocShellLeakLog
&& PR_LOG_TEST(gDocShellLeakLog
, PR_LOG_DEBUG
)) {
6764 aURI
->GetSpec(spec
);
6765 PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec
.get());
6769 // Initialize aDocShell/aRequest
6771 *aDocShell
= nsnull
;
6778 return NS_ERROR_NULL_POINTER
;
6781 NS_ENSURE_TRUE(IsValidLoadType(aLoadType
), NS_ERROR_INVALID_ARG
);
6783 NS_ENSURE_TRUE(!mIsBeingDestroyed
, NS_ERROR_NOT_AVAILABLE
);
6785 // wyciwyg urls can only be loaded through history. Any normal load of
6786 // wyciwyg through docshell is illegal. Disallow such loads.
6787 if (aLoadType
& LOAD_CMD_NORMAL
) {
6788 PRBool isWyciwyg
= PR_FALSE
;
6789 rv
= aURI
->SchemeIs("wyciwyg", &isWyciwyg
);
6790 if ((isWyciwyg
&& NS_SUCCEEDED(rv
)) || NS_FAILED(rv
))
6791 return NS_ERROR_FAILURE
;
6794 PRBool bIsJavascript
= PR_FALSE
;
6795 if (NS_FAILED(aURI
->SchemeIs("javascript", &bIsJavascript
))) {
6796 bIsJavascript
= PR_FALSE
;
6800 // First, notify any nsIContentPolicy listeners about the document load.
6801 // Only abort the load if a content policy listener explicitly vetos it!
6803 nsCOMPtr
<nsIDOMElement
> requestingElement
;
6804 // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
6805 nsCOMPtr
<nsPIDOMWindow
> privateWin(do_QueryInterface(mScriptGlobal
));
6807 requestingElement
= privateWin
->GetFrameElementInternal();
6809 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
6810 PRUint32 contentType
;
6812 NS_ASSERTION(requestingElement
, "A frame but no DOM element!?");
6813 contentType
= nsIContentPolicy::TYPE_SUBDOCUMENT
;
6815 contentType
= nsIContentPolicy::TYPE_DOCUMENT
;
6818 nsISupports
* context
= requestingElement
;
6820 context
= mScriptGlobal
;
6823 // XXXbz would be nice to know the loading principal here... but we don't
6824 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
;
6826 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
6827 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
6828 NS_ENSURE_SUCCESS(rv
, rv
);
6830 rv
= secMan
->GetCodebasePrincipal(aReferrer
,
6831 getter_AddRefs(loadingPrincipal
));
6834 rv
= NS_CheckContentLoadPolicy(contentType
,
6838 EmptyCString(), //mime guess
6842 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
)) {
6843 if (NS_SUCCEEDED(rv
) && shouldLoad
== nsIContentPolicy::REJECT_TYPE
) {
6844 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT
;
6847 return NS_ERROR_CONTENT_BLOCKED
;
6850 nsCOMPtr
<nsISupports
> owner(aOwner
);
6852 // Get an owner from the current document if necessary. Note that we only
6853 // do this for URIs that inherit a security context and local file URIs;
6854 // in particular we do NOT do this for about:blank. This way, random
6855 // about:blank loads that have no owner (which basically means they were
6856 // done by someone from chrome manually messing with our nsIWebNavigation
6857 // or by C++ setting document.location) don't get a funky principal. If
6858 // callers want something interesting to happen with the about:blank
6859 // principal in this case, they should pass an owner in.
6863 // One more twist: Don't inherit the owner for external loads.
6864 if (aLoadType
!= LOAD_NORMAL_EXTERNAL
&& !owner
&&
6865 (aFlags
& INTERNAL_LOAD_FLAGS_INHERIT_OWNER
) &&
6866 ((NS_SUCCEEDED(URIInheritsSecurityContext(aURI
, &inherits
)) &&
6867 inherits
) || URIIsLocalFile(aURI
))) {
6869 // Don't allow loads that would inherit our security context
6870 // if this document came from an unsafe channel.
6871 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= this;
6873 nsCOMPtr
<nsIDocShell
> itemDocShell
=
6874 do_QueryInterface(treeItem
);
6877 NS_SUCCEEDED(itemDocShell
->GetChannelIsUnsafe(&isUnsafe
)) &&
6879 return NS_ERROR_DOM_SECURITY_ERR
;
6882 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
6883 treeItem
->GetSameTypeParent(getter_AddRefs(parent
));
6884 parent
.swap(treeItem
);
6887 owner
= GetInheritedPrincipal(PR_TRUE
);
6892 // Resolve the window target before going any further...
6893 // If the load has been targeted to another DocShell, then transfer the
6896 if (aWindowTarget
&& *aWindowTarget
) {
6897 // We've already done our owner-inheriting. Mask out that bit, so we
6898 // don't try inheriting an owner from the target window if we came up
6899 // with a null owner above.
6900 aFlags
= aFlags
& ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER
;
6902 // Locate the target DocShell.
6903 // This may involve creating a new toplevel window - if necessary.
6905 nsCOMPtr
<nsIDocShellTreeItem
> targetItem
;
6906 FindItemWithName(aWindowTarget
, nsnull
, this,
6907 getter_AddRefs(targetItem
));
6909 nsCOMPtr
<nsIDocShell
> targetDocShell
= do_QueryInterface(targetItem
);
6911 PRBool isNewWindow
= PR_FALSE
;
6912 if (!targetDocShell
) {
6913 nsCOMPtr
<nsIDOMWindowInternal
> win
=
6914 do_GetInterface(GetAsSupports(this));
6915 NS_ENSURE_TRUE(win
, NS_ERROR_NOT_AVAILABLE
);
6917 nsDependentString
name(aWindowTarget
);
6918 nsCOMPtr
<nsIDOMWindow
> newWin
;
6919 rv
= win
->Open(EmptyString(), // URL to load
6920 name
, // window name
6921 EmptyString(), // Features
6922 getter_AddRefs(newWin
));
6924 // In some cases the Open call doesn't actually result in a new
6925 // window being opened. We can detect these cases by examining the
6926 // document in |newWin|, if any.
6927 nsCOMPtr
<nsPIDOMWindow
> piNewWin
= do_QueryInterface(newWin
);
6929 nsCOMPtr
<nsIDocument
> newDoc
=
6930 do_QueryInterface(piNewWin
->GetExtantDocument());
6931 if (!newDoc
|| newDoc
->IsInitialDocument()) {
6932 isNewWindow
= PR_TRUE
;
6933 aFlags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
6937 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(newWin
);
6938 targetDocShell
= do_QueryInterface(webNav
);
6942 // Transfer the load to the target DocShell... Pass nsnull as the
6943 // window target name from to prevent recursive retargeting!
6945 if (NS_SUCCEEDED(rv
) && targetDocShell
) {
6946 rv
= targetDocShell
->InternalLoad(aURI
,
6950 nsnull
, // No window target
6959 if (rv
== NS_ERROR_NO_CONTENT
) {
6960 // XXXbz except we never reach this code!
6963 // At this point, a new window has been created, but the
6964 // URI did not have any data associated with it...
6966 // So, the best we can do, is to tear down the new window
6967 // that was just created!
6969 nsCOMPtr
<nsIDOMWindowInternal
> domWin
=
6970 do_GetInterface(targetDocShell
);
6976 // NS_ERROR_NO_CONTENT should not be returned to the
6977 // caller... This is an internal error code indicating that
6978 // the URI had no data associated with it - probably a
6979 // helper-app style protocol (ie. mailto://)
6983 else if (isNewWindow
) {
6984 // XXX: Once new windows are created hidden, the new
6985 // window will need to be made visible... For now,
6990 // Else we ran out of memory, or were a popup and got blocked,
6997 // Load is being targetted at this docshell so return an error if the
6998 // docshell is in the process of being destroyed.
7000 if (mIsBeingDestroyed
) {
7001 return NS_ERROR_FAILURE
;
7004 rv
= CheckLoadingPermissions();
7005 if (NS_FAILED(rv
)) {
7009 // If this docshell is owned by a frameloader, make sure to cancel
7010 // possible frameloader initialization before loading a new page.
7011 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
7012 GetParent(getter_AddRefs(parent
));
7014 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_GetInterface(parent
);
7015 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
7017 doc
->TryCancelFrameLoaderInitialization(this);
7021 if (mFiredUnloadEvent
) {
7022 if (IsOKToLoadURI(aURI
)) {
7023 NS_PRECONDITION(!aWindowTarget
|| !*aWindowTarget
,
7024 "Shouldn't have a window target here!");
7026 // If this is a replace load, make whatever load triggered
7027 // the unload event also a replace load, so we don't
7028 // create extra history entries.
7029 if (LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
7030 mLoadType
= LOAD_NORMAL_REPLACE
;
7033 // Do this asynchronously
7034 nsCOMPtr
<nsIRunnable
> ev
=
7035 new InternalLoadEvent(this, aURI
, aReferrer
, aOwner
, aFlags
,
7036 aTypeHint
, aPostData
, aHeadersData
,
7037 aLoadType
, aSHEntry
, aFirstParty
);
7038 return NS_DispatchToCurrentThread(ev
);
7041 // Just ignore this load attempt
7045 // Before going any further vet loads initiated by external programs.
7046 if (aLoadType
== LOAD_NORMAL_EXTERNAL
) {
7047 // Disallow external chrome: loads targetted at content windows
7048 PRBool isChrome
= PR_FALSE
;
7049 if (NS_SUCCEEDED(aURI
->SchemeIs("chrome", &isChrome
)) && isChrome
) {
7050 NS_WARNING("blocked external chrome: url -- use '-chrome' option");
7051 return NS_ERROR_FAILURE
;
7054 // clear the decks to prevent context bleed-through (bug 298255)
7055 rv
= CreateAboutBlankContentViewer(nsnull
);
7057 return NS_ERROR_FAILURE
;
7059 // reset loadType so we don't have to add lots of tests for
7060 // LOAD_NORMAL_EXTERNAL after this point
7061 aLoadType
= LOAD_NORMAL
;
7064 mAllowKeywordFixup
=
7065 (aFlags
& INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) != 0;
7066 mURIResultedInDocument
= PR_FALSE
; // reset the clock...
7070 // Check to see if the new URI is an anchor in the existing document.
7071 // Skip this check if we're doing some sort of abnormal load, if the
7072 // new load is a non-history load and has postdata, or if we're doing
7073 // a history load and the page identifiers of mOSHE and aSHEntry
7076 PRBool allowScroll
= PR_TRUE
;
7078 allowScroll
= (aPostData
== nsnull
);
7080 PRUint32 ourPageIdent
;
7081 mOSHE
->GetPageIdentifier(&ourPageIdent
);
7082 PRUint32 otherPageIdent
;
7083 aSHEntry
->GetPageIdentifier(&otherPageIdent
);
7084 allowScroll
= (ourPageIdent
== otherPageIdent
);
7087 nsCOMPtr
<nsIInputStream
> currentPostData
;
7088 mOSHE
->GetPostData(getter_AddRefs(currentPostData
));
7089 NS_ASSERTION(currentPostData
== aPostData
,
7090 "Different POST data for entries for the same page?");
7095 if ((aLoadType
== LOAD_NORMAL
||
7096 aLoadType
== LOAD_STOP_CONTENT
||
7097 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) ||
7098 aLoadType
== LOAD_HISTORY
||
7099 aLoadType
== LOAD_LINK
) && allowScroll
) {
7100 PRBool wasAnchor
= PR_FALSE
;
7102 NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI
, &wasAnchor
, aLoadType
, &cx
, &cy
), NS_ERROR_FAILURE
);
7104 mLoadType
= aLoadType
;
7105 mURIResultedInDocument
= PR_TRUE
;
7107 /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
7108 * SetCurrentURI() called from OnNewURI() will send proper
7109 * onLocationChange() notifications to the browser to update
7110 * back/forward buttons.
7112 SetHistoryEntry(&mLSHE
, aSHEntry
);
7114 /* This is a anchor traversal with in the same page.
7115 * call OnNewURI() so that, this traversal will be
7116 * recorded in session and global history.
7118 nsCOMPtr
<nsISupports
> owner
;
7120 mOSHE
->GetOwner(getter_AddRefs(owner
));
7122 OnNewURI(aURI
, nsnull
, owner
, mLoadType
, PR_TRUE
);
7123 nsCOMPtr
<nsIInputStream
> postData
;
7124 PRUint32 pageIdent
= PR_UINT32_MAX
;
7125 nsCOMPtr
<nsISupports
> cacheKey
;
7128 /* save current position of scroller(s) (bug 59774) */
7129 mOSHE
->SetScrollPosition(cx
, cy
);
7130 // Get the postdata and page ident from the current page, if
7131 // the new load is being done via normal means. Note that
7132 // "normal means" can be checked for just by checking for
7133 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
7134 // above -- it filters out some LOAD_CMD_NORMAL cases that we
7135 // wouldn't want here.
7136 if (aLoadType
& LOAD_CMD_NORMAL
) {
7137 mOSHE
->GetPostData(getter_AddRefs(postData
));
7138 mOSHE
->GetPageIdentifier(&pageIdent
);
7139 mOSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
7143 /* Assign mOSHE to mLSHE. This will either be a new entry created
7144 * by OnNewURI() for normal loads or aSHEntry for history loads.
7147 SetHistoryEntry(&mOSHE
, mLSHE
);
7148 // Save the postData obtained from the previous page
7149 // in to the session history entry created for the
7150 // anchor page, so that any history load of the anchor
7151 // page will restore the appropriate postData.
7153 mOSHE
->SetPostData(postData
);
7155 // Make sure we won't just repost without hitting the
7158 mOSHE
->SetCacheKey(cacheKey
);
7160 // Propagate our page ident to the new mOSHE so that
7161 // we'll know it just differed by a scroll on the page.
7162 if (pageIdent
!= PR_UINT32_MAX
)
7163 mOSHE
->SetPageIdentifier(pageIdent
);
7166 /* restore previous position of scroller(s), if we're moving
7167 * back in history (bug 59774)
7169 if (mOSHE
&& (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
))
7172 mOSHE
->GetScrollPosition(&bx
, &by
);
7173 SetCurScrollPosEx(bx
, by
);
7176 /* Clear out mLSHE so that further anchor visits get
7177 * recorded in SH and SH won't misbehave.
7179 SetHistoryEntry(&mLSHE
, nsnull
);
7180 /* Set the title for the SH entry for this target url. so that
7181 * SH menus in go/back/forward buttons won't be empty for this.
7183 if (mSessionHistory
) {
7185 mSessionHistory
->GetIndex(&index
);
7186 nsCOMPtr
<nsIHistoryEntry
> hEntry
;
7187 mSessionHistory
->GetEntryAtIndex(index
, PR_FALSE
,
7188 getter_AddRefs(hEntry
));
7189 NS_ENSURE_TRUE(hEntry
, NS_ERROR_FAILURE
);
7190 nsCOMPtr
<nsISHEntry
> shEntry(do_QueryInterface(hEntry
));
7192 shEntry
->SetTitle(mTitle
);
7199 // mContentViewer->PermitUnload can destroy |this| docShell, which
7200 // causes the next call of CanSavePresentation to crash.
7201 // Hold onto |this| until we return, to prevent a crash from happening.
7203 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
7205 // Check if the page doesn't want to be unloaded. The javascript:
7206 // protocol handler deals with this for javascript: URLs.
7207 if (!bIsJavascript
&& mContentViewer
) {
7209 rv
= mContentViewer
->PermitUnload(&okToUnload
);
7211 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
7212 // The user chose not to unload the page, interrupt the
7218 // Check for saving the presentation here, before calling Stop().
7219 // This is necessary so that we can catch any pending requests.
7220 // Since the new request has not been created yet, we pass null for the
7221 // new request parameter.
7222 // Also pass nsnull for the document, since it doesn't affect the return
7223 // value for our purposes here.
7224 PRBool savePresentation
= CanSavePresentation(aLoadType
, nsnull
, nsnull
);
7226 // Don't stop current network activity for javascript: URL's since
7227 // they might not result in any data, and thus nothing should be
7228 // stopped in those cases. In the case where they do result in
7229 // data, the javascript: URL channel takes care of stopping
7230 // current network activity.
7231 if (!bIsJavascript
) {
7232 // Stop any current network activity.
7233 // Also stop content if this is a zombie doc. otherwise
7234 // the onload will be delayed by other loads initiated in the
7235 // background by the first document that
7236 // didn't fully load before the next load was initiated.
7237 // If not a zombie, don't stop content until data
7238 // starts arriving from the new URI...
7240 nsCOMPtr
<nsIContentViewer
> zombieViewer
;
7241 if (mContentViewer
) {
7242 mContentViewer
->GetPreviousViewer(getter_AddRefs(zombieViewer
));
7246 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_STOP_CONTENT
)) {
7247 rv
= Stop(nsIWebNavigation::STOP_ALL
);
7249 rv
= Stop(nsIWebNavigation::STOP_NETWORK
);
7256 mLoadType
= aLoadType
;
7258 // mLSHE should be assigned to aSHEntry, only after Stop() has
7259 // been called. But when loading an error page, do not clear the
7260 // mLSHE for the real page.
7261 if (mLoadType
!= LOAD_ERROR_PAGE
)
7262 SetHistoryEntry(&mLSHE
, aSHEntry
);
7264 mSavingOldViewer
= savePresentation
;
7266 // If we have a saved content viewer in history, restore and show it now.
7267 if (aSHEntry
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
7268 // It's possible that the previous viewer of mContentViewer is the
7269 // viewer that will end up in aSHEntry when it gets closed. If that's
7270 // the case, we need to go ahead and force it into its shentry so we
7272 if (mContentViewer
) {
7273 nsCOMPtr
<nsIContentViewer
> prevViewer
;
7274 mContentViewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
7277 nsCOMPtr
<nsIContentViewer
> prevPrevViewer
;
7278 prevViewer
->GetPreviousViewer(getter_AddRefs(prevPrevViewer
));
7279 NS_ASSERTION(!prevPrevViewer
, "Should never have viewer chain here");
7281 nsCOMPtr
<nsISHEntry
> viewerEntry
;
7282 prevViewer
->GetHistoryEntry(getter_AddRefs(viewerEntry
));
7283 if (viewerEntry
== aSHEntry
) {
7284 // Make sure this viewer ends up in the right place
7285 mContentViewer
->SetPreviousViewer(nsnull
);
7286 prevViewer
->Destroy();
7290 nsCOMPtr
<nsISHEntry
> oldEntry
= mOSHE
;
7292 rv
= RestorePresentation(aSHEntry
, &restoring
);
7296 // We failed to restore the presentation, so clean up.
7297 // Both the old and new history entries could potentially be in
7298 // an inconsistent state.
7299 if (NS_FAILED(rv
)) {
7301 oldEntry
->SyncPresentationState();
7303 aSHEntry
->SyncPresentationState();
7307 nsCOMPtr
<nsIRequest
> req
;
7308 rv
= DoURILoad(aURI
, aReferrer
,
7309 !(aFlags
& INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
),
7310 owner
, aTypeHint
, aPostData
, aHeadersData
, aFirstParty
,
7311 aDocShell
, getter_AddRefs(req
),
7312 (aFlags
& INTERNAL_LOAD_FLAGS_FIRST_LOAD
) != 0,
7313 (aFlags
& INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
) != 0);
7314 if (req
&& aRequest
)
7315 NS_ADDREF(*aRequest
= req
);
7317 if (NS_FAILED(rv
)) {
7318 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(req
));
7319 DisplayLoadError(rv
, aURI
, nsnull
, chan
);
7326 nsDocShell::GetInheritedPrincipal(PRBool aConsiderCurrentDocument
)
7328 nsCOMPtr
<nsIDocument
> document
;
7330 if (aConsiderCurrentDocument
&& mContentViewer
) {
7331 nsCOMPtr
<nsIDocumentViewer
>
7332 docViewer(do_QueryInterface(mContentViewer
));
7335 docViewer
->GetDocument(getter_AddRefs(document
));
7339 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
7340 GetSameTypeParent(getter_AddRefs(parentItem
));
7342 nsCOMPtr
<nsIDOMDocument
> parentDomDoc(do_GetInterface(parentItem
));
7343 document
= do_QueryInterface(parentDomDoc
);
7348 if (!aConsiderCurrentDocument
) {
7352 // Make sure we end up with _something_ as the principal no matter
7354 EnsureContentViewer(); // If this fails, we'll just get a null
7355 // docViewer and bail.
7357 nsCOMPtr
<nsIDocumentViewer
>
7358 docViewer(do_QueryInterface(mContentViewer
));
7361 docViewer
->GetDocument(getter_AddRefs(document
));
7364 //-- Get the document's principal
7366 return document
->NodePrincipal();
7373 nsDocShell::ShouldCheckAppCache(nsIURI
*aURI
)
7375 nsCOMPtr
<nsIOfflineCacheUpdateService
> offlineService
=
7376 do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID
);
7377 if (!offlineService
) {
7382 nsresult rv
= offlineService
->OfflineAppAllowedForURI(aURI
,
7385 return NS_SUCCEEDED(rv
) && allowed
;
7389 nsDocShell::DoURILoad(nsIURI
* aURI
,
7390 nsIURI
* aReferrerURI
,
7391 PRBool aSendReferrer
,
7392 nsISupports
* aOwner
,
7393 const char * aTypeHint
,
7394 nsIInputStream
* aPostData
,
7395 nsIInputStream
* aHeadersData
,
7397 nsIDocShell
** aDocShell
,
7398 nsIRequest
** aRequest
,
7399 PRBool aIsNewWindowTarget
,
7400 PRBool aBypassClassifier
)
7403 nsCOMPtr
<nsIURILoader
> uriLoader
;
7405 uriLoader
= do_GetService(NS_URI_LOADER_CONTRACTID
, &rv
);
7406 if (NS_FAILED(rv
)) return rv
;
7408 nsLoadFlags loadFlags
= nsIRequest::LOAD_NORMAL
;
7410 // tag first party URL loads
7411 loadFlags
|= nsIChannel::LOAD_INITIAL_DOCUMENT_URI
;
7414 if (mLoadType
== LOAD_ERROR_PAGE
) {
7415 // Error pages are LOAD_BACKGROUND
7416 loadFlags
|= nsIChannel::LOAD_BACKGROUND
;
7419 // open a channel for the url
7420 nsCOMPtr
<nsIChannel
> channel
;
7422 rv
= NS_NewChannel(getter_AddRefs(channel
),
7426 static_cast<nsIInterfaceRequestor
*>(this),
7428 if (NS_FAILED(rv
)) {
7429 if (rv
== NS_ERROR_UNKNOWN_PROTOCOL
) {
7430 // This is a uri with a protocol scheme we don't know how
7431 // to handle. Embedders might still be interested in
7432 // handling the load, though, so we fire a notification
7433 // before throwing the load away.
7434 PRBool abort
= PR_FALSE
;
7435 nsresult rv2
= mContentListener
->OnStartURIOpen(aURI
, &abort
);
7436 if (NS_SUCCEEDED(rv2
) && abort
) {
7437 // Hey, they're handling the load for us! How convenient!
7445 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
7446 do_QueryInterface(channel
);
7447 if (appCacheChannel
) {
7448 // Any document load should not inherit application cache.
7449 appCacheChannel
->SetInheritApplicationCache(PR_FALSE
);
7451 // Loads with the correct permissions should check for a matching
7452 // application cache.
7453 appCacheChannel
->SetChooseApplicationCache(ShouldCheckAppCache(aURI
));
7456 // Make sure to give the caller a channel if we managed to create one
7457 // This is important for correct error page/session history interaction
7459 NS_ADDREF(*aRequest
= channel
);
7461 channel
->SetOriginalURI(aURI
);
7462 if (aTypeHint
&& *aTypeHint
) {
7463 channel
->SetContentType(nsDependentCString(aTypeHint
));
7464 mContentTypeHint
= aTypeHint
;
7467 mContentTypeHint
.Truncate();
7471 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
7472 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInternal(do_QueryInterface(channel
));
7473 if (httpChannelInternal
) {
7475 httpChannelInternal
->SetDocumentURI(aURI
);
7477 httpChannelInternal
->SetDocumentURI(aReferrerURI
);
7481 nsCOMPtr
<nsIWritablePropertyBag2
> props(do_QueryInterface(channel
));
7484 // save true referrer for those who need it (e.g. xpinstall whitelisting)
7485 // Currently only http and ftp channels support this.
7486 props
->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
7491 // If this is a HTTP channel, then set up the HTTP specific information
7492 // (ie. POST data, referrer, ...)
7495 nsCOMPtr
<nsICachingChannel
> cacheChannel(do_QueryInterface(httpChannel
));
7496 /* Get the cache Key from SH */
7497 nsCOMPtr
<nsISupports
> cacheKey
;
7499 mLSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
7501 else if (mOSHE
) // for reload cases
7502 mOSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
7504 // figure out if we need to set the post data stream on the channel...
7505 // right now, this is only done for http channels.....
7507 // XXX it's a bit of a hack to rewind the postdata stream here but
7508 // it has to be done in case the post data is being reused multiple
7510 nsCOMPtr
<nsISeekableStream
>
7511 postDataSeekable(do_QueryInterface(aPostData
));
7512 if (postDataSeekable
) {
7513 rv
= postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
7514 NS_ENSURE_SUCCESS(rv
, rv
);
7517 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
7518 NS_ASSERTION(uploadChannel
, "http must support nsIUploadChannel");
7520 // we really need to have a content type associated with this stream!!
7521 uploadChannel
->SetUploadStream(aPostData
, EmptyCString(), -1);
7522 /* If there is a valid postdata *and* it is a History Load,
7523 * set up the cache key on the channel, to retrieve the
7524 * data *only* from the cache. If it is a normal reload, the
7525 * cache is free to go to the server for updated postdata.
7527 if (cacheChannel
&& cacheKey
) {
7528 if (mLoadType
== LOAD_HISTORY
|| mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
7529 cacheChannel
->SetCacheKey(cacheKey
);
7531 if (NS_SUCCEEDED(channel
->GetLoadFlags(&loadFlags
)))
7532 channel
->SetLoadFlags(loadFlags
| nsICachingChannel::LOAD_ONLY_FROM_CACHE
);
7534 else if (mLoadType
== LOAD_RELOAD_NORMAL
)
7535 cacheChannel
->SetCacheKey(cacheKey
);
7539 /* If there is no postdata, set the cache key on the channel, and
7540 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
7541 * will be free to get it from net if it is not found in cache.
7542 * New cache may use it creatively on CGI pages with GET
7543 * method and even on those that say "no-cache"
7545 if (mLoadType
== LOAD_HISTORY
|| mLoadType
== LOAD_RELOAD_NORMAL
7546 || mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
7547 if (cacheChannel
&& cacheKey
)
7548 cacheChannel
->SetCacheKey(cacheKey
);
7552 rv
= AddHeadersToChannel(aHeadersData
, httpChannel
);
7554 // Set the referrer explicitly
7555 if (aReferrerURI
&& aSendReferrer
) {
7556 // Referrer is currenly only set for link clicks here.
7557 httpChannel
->SetReferrer(aReferrerURI
);
7561 // Set the owner of the channel, but only for channels that can't
7562 // provide their own security context.
7564 // XXX: Is seems wrong that the owner is ignored - even if one is
7565 // supplied) unless the URI is javascript or data or about:blank.
7566 // XXX: If this is ever changed, check all callers for what owners they're
7567 // passing in. In particular, see the code and comments in LoadURI
7568 // where we fall back on inheriting the owner if called
7569 // from chrome. That would be very wrong if this code changed
7570 // anything but channels that can't provide their own security context!
7572 // (Currently chrome URIs set the owner when they are created!
7573 // So setting a NULL owner would be bad!)
7575 // If this code ever changes, change nsObjectLoadingContent::LoadObject
7578 // We expect URIInheritsSecurityContext to return success for an
7579 // about:blank URI, so don't call IsAboutBlank() if this call fails.
7580 rv
= URIInheritsSecurityContext(aURI
, &inherit
);
7581 if (NS_SUCCEEDED(rv
) && (inherit
|| IsAboutBlank(aURI
))) {
7582 channel
->SetOwner(aOwner
);
7586 // file: uri special-casing
7588 // If this is a file: load opened from another file: then it may need
7589 // to inherit the owner from the referrer so they can script each other.
7590 // If we don't set the owner explicitly then each file: gets an owner
7591 // based on its own codebase later.
7593 nsCOMPtr
<nsIPrincipal
> ownerPrincipal(do_QueryInterface(aOwner
));
7594 if (URIIsLocalFile(aURI
) && ownerPrincipal
&&
7595 NS_SUCCEEDED(ownerPrincipal
->CheckMayLoad(aURI
, PR_FALSE
))) {
7596 // One more check here. CheckMayLoad will always return true for the
7597 // system principal, but we do NOT want to inherit in that case.
7599 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
7600 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
7602 NS_SUCCEEDED(secMan
->IsSystemPrincipal(ownerPrincipal
,
7605 channel
->SetOwner(aOwner
);
7609 nsCOMPtr
<nsIScriptChannel
> scriptChannel
= do_QueryInterface(channel
);
7610 if (scriptChannel
) {
7611 // Allow execution against our context if the principals match
7613 SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
7616 if (aIsNewWindowTarget
) {
7617 nsCOMPtr
<nsIWritablePropertyBag2
> props
= do_QueryInterface(channel
);
7619 props
->SetPropertyAsBool(
7620 NS_LITERAL_STRING("docshell.newWindowTarget"),
7625 rv
= DoChannelLoad(channel
, uriLoader
, aBypassClassifier
);
7628 // If the channel load failed, we failed and nsIWebProgress just ain't
7631 if (NS_SUCCEEDED(rv
)) {
7634 NS_ADDREF(*aDocShell
);
7642 AppendSegmentToString(nsIInputStream
*in
,
7644 const char *fromRawSegment
,
7647 PRUint32
*writeCount
)
7649 // aFromSegment now contains aCount bytes of data.
7651 nsCAutoString
*buf
= static_cast<nsCAutoString
*>(closure
);
7652 buf
->Append(fromRawSegment
, count
);
7654 // Indicate that we have consumed all of aFromSegment
7655 *writeCount
= count
;
7660 nsDocShell::AddHeadersToChannel(nsIInputStream
*aHeadersData
,
7661 nsIChannel
*aGenericChannel
)
7663 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aGenericChannel
);
7664 NS_ENSURE_STATE(httpChannel
);
7667 nsCAutoString headersString
;
7668 nsresult rv
= aHeadersData
->ReadSegments(AppendSegmentToString
,
7672 NS_ENSURE_SUCCESS(rv
, rv
);
7674 // used during the manipulation of the String from the InputStream
7675 nsCAutoString headerName
;
7676 nsCAutoString headerValue
;
7681 // Iterate over the headersString: for each "\r\n" delimited chunk,
7682 // add the value as a header to the nsIHttpChannel
7685 static const char kWhitespace
[] = "\b\t\r\n ";
7687 crlf
= headersString
.Find("\r\n");
7688 if (crlf
== kNotFound
)
7691 const nsCSubstring
&oneHeader
= StringHead(headersString
, crlf
);
7693 colon
= oneHeader
.FindChar(':');
7694 if (colon
== kNotFound
)
7695 return NS_ERROR_UNEXPECTED
;
7697 headerName
= StringHead(oneHeader
, colon
);
7698 headerValue
= Substring(oneHeader
, colon
+ 1);
7700 headerName
.Trim(kWhitespace
);
7701 headerValue
.Trim(kWhitespace
);
7703 headersString
.Cut(0, crlf
+ 2);
7706 // FINALLY: we can set the header!
7709 rv
= httpChannel
->SetRequestHeader(headerName
, headerValue
, PR_TRUE
);
7710 NS_ENSURE_SUCCESS(rv
, rv
);
7713 NS_NOTREACHED("oops");
7714 return NS_ERROR_UNEXPECTED
;
7717 nsresult
nsDocShell::DoChannelLoad(nsIChannel
* aChannel
,
7718 nsIURILoader
* aURILoader
,
7719 PRBool aBypassClassifier
)
7722 // Mark the channel as being a document URI and allow content sniffing...
7723 nsLoadFlags loadFlags
= 0;
7724 (void) aChannel
->GetLoadFlags(&loadFlags
);
7725 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
|
7726 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS
;
7728 // Load attributes depend on load type...
7729 switch (mLoadType
) {
7731 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
7734 case LOAD_RELOAD_CHARSET_CHANGE
:
7735 loadFlags
|= nsIRequest::LOAD_FROM_CACHE
;
7738 case LOAD_RELOAD_NORMAL
:
7740 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
7743 case LOAD_NORMAL_BYPASS_CACHE
:
7744 case LOAD_NORMAL_BYPASS_PROXY
:
7745 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
7746 case LOAD_RELOAD_BYPASS_CACHE
:
7747 case LOAD_RELOAD_BYPASS_PROXY
:
7748 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
7749 loadFlags
|= nsIRequest::LOAD_BYPASS_CACHE
;
7754 // Set cache checking flags
7755 PRInt32 prefSetting
;
7758 GetIntPref("browser.cache.check_doc_frequency",
7760 switch (prefSetting
) {
7762 loadFlags
|= nsIRequest::VALIDATE_ONCE_PER_SESSION
;
7765 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
7768 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
7775 (void) aChannel
->SetLoadFlags(loadFlags
);
7777 rv
= aURILoader
->OpenURI(aChannel
,
7778 (mLoadType
== LOAD_LINK
),
7780 NS_ENSURE_SUCCESS(rv
, rv
);
7782 if (!aBypassClassifier
) {
7783 rv
= CheckClassifier(aChannel
);
7784 if (NS_FAILED(rv
)) {
7785 aChannel
->Cancel(rv
);
7794 nsDocShell::CheckClassifier(nsIChannel
*aChannel
)
7796 nsRefPtr
<nsClassifierCallback
> classifier
= new nsClassifierCallback();
7797 if (!classifier
) return NS_ERROR_OUT_OF_MEMORY
;
7799 nsresult rv
= classifier
->Start(aChannel
, PR_FALSE
);
7800 NS_ENSURE_SUCCESS(rv
, rv
);
7802 mClassifier
= classifier
;
7808 nsDocShell::ScrollIfAnchor(nsIURI
* aURI
, PRBool
* aWasAnchor
,
7809 PRUint32 aLoadType
, nscoord
*cx
, nscoord
*cy
)
7811 NS_ASSERTION(aURI
, "null uri arg");
7812 NS_ASSERTION(aWasAnchor
, "null anchor arg");
7814 if (aURI
== nsnull
|| aWasAnchor
== nsnull
) {
7815 return NS_ERROR_FAILURE
;
7818 *aWasAnchor
= PR_FALSE
;
7824 nsCOMPtr
<nsIPresShell
> shell
;
7825 nsresult rv
= GetPresShell(getter_AddRefs(shell
));
7826 if (NS_FAILED(rv
) || !shell
) {
7827 // If we failed to get the shell, or if there is no shell,
7828 // nothing left to do here.
7833 // NOTE: we assume URIs are absolute for comparison purposes
7835 nsCAutoString currentSpec
;
7836 NS_ENSURE_SUCCESS(mCurrentURI
->GetSpec(currentSpec
),
7839 nsCAutoString newSpec
;
7840 NS_ENSURE_SUCCESS(aURI
->GetSpec(newSpec
), NS_ERROR_FAILURE
);
7842 // Search for hash marks in the current URI and the new URI and
7843 // take a copy of everything to the left of the hash for
7846 const char kHash
= '#';
7848 // Split the new URI into a left and right part
7849 // (assume we're parsing it out right
7850 nsACString::const_iterator urlStart
, urlEnd
, refStart
, refEnd
;
7851 newSpec
.BeginReading(urlStart
);
7852 newSpec
.EndReading(refEnd
);
7854 PRInt32 hashNew
= newSpec
.FindChar(kHash
);
7856 return NS_OK
; // Strange URI
7862 urlEnd
.advance(hashNew
);
7865 ++refStart
; // advanced past '#'
7870 urlEnd
= refStart
= refEnd
;
7872 const nsACString
& sNewLeft
= Substring(urlStart
, urlEnd
);
7873 const nsACString
& sNewRef
= Substring(refStart
, refEnd
);
7875 // Split the current URI in a left and right part
7876 nsACString::const_iterator currentLeftStart
, currentLeftEnd
;
7877 currentSpec
.BeginReading(currentLeftStart
);
7879 PRInt32 hashCurrent
= currentSpec
.FindChar(kHash
);
7880 if (hashCurrent
== 0) {
7881 return NS_OK
; // Strange URI
7884 if (hashCurrent
> 0) {
7885 currentLeftEnd
= currentLeftStart
;
7886 currentLeftEnd
.advance(hashCurrent
);
7889 currentSpec
.EndReading(currentLeftEnd
);
7892 // If we have no new anchor, we do not want to scroll, unless there is a
7893 // current anchor and we are doing a history load. So return if we have no
7894 // new anchor, and there is no current anchor or the load is not a history
7896 NS_ASSERTION(hashNew
!= 0 && hashCurrent
!= 0,
7897 "What happened to the early returns above?");
7898 if (hashNew
== kNotFound
&&
7899 (hashCurrent
== kNotFound
|| aLoadType
!= LOAD_HISTORY
)) {
7903 // Compare the URIs.
7905 // NOTE: this is a case sensitive comparison because some parts of the
7906 // URI are case sensitive, and some are not. i.e. the domain name
7907 // is case insensitive but the the paths are not.
7909 // This means that comparing "http://www.ABC.com/" to "http://www.abc.com/"
7910 // will fail this test.
7912 if (!Substring(currentLeftStart
, currentLeftEnd
).Equals(sNewLeft
)) {
7913 return NS_OK
; // URIs not the same
7916 // Now we know we are dealing with an anchor
7917 *aWasAnchor
= PR_TRUE
;
7919 // Both the new and current URIs refer to the same page. We can now
7920 // browse to the hash stored in the new URI.
7922 // But first let's capture positions of scroller(s) that can
7923 // (and usually will) be modified by GoToAnchor() call.
7925 GetCurScrollPos(ScrollOrientation_X
, cx
);
7926 GetCurScrollPos(ScrollOrientation_Y
, cy
);
7928 if (!sNewRef
.IsEmpty()) {
7929 // anchor is there, but if it's a load from history,
7930 // we don't have any anchor jumping to do
7931 PRBool scroll
= aLoadType
!= LOAD_HISTORY
&&
7932 aLoadType
!= LOAD_RELOAD_NORMAL
;
7934 char *str
= ToNewCString(sNewRef
);
7936 return NS_ERROR_OUT_OF_MEMORY
;
7939 // nsUnescape modifies the string that is passed into it.
7942 // We assume that the bytes are in UTF-8, as it says in the
7944 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
7946 // We try the UTF-8 string first, and then try the document's
7947 // charset (see below). If the string is not UTF-8,
7948 // conversion will fail and give us an empty Unicode string.
7949 // In that case, we should just fall through to using the
7951 rv
= NS_ERROR_FAILURE
;
7952 NS_ConvertUTF8toUTF16
uStr(str
);
7953 if (!uStr
.IsEmpty()) {
7954 rv
= shell
->GoToAnchor(NS_ConvertUTF8toUTF16(str
), scroll
);
7956 nsMemory::Free(str
);
7958 // Above will fail if the anchor name is not UTF-8. Need to
7959 // convert from document charset to unicode.
7960 if (NS_FAILED(rv
)) {
7962 // Get a document charset
7963 NS_ENSURE_TRUE(mContentViewer
, NS_ERROR_FAILURE
);
7964 nsCOMPtr
<nsIDocumentViewer
>
7965 docv(do_QueryInterface(mContentViewer
));
7966 NS_ENSURE_TRUE(docv
, NS_ERROR_FAILURE
);
7967 nsCOMPtr
<nsIDocument
> doc
;
7968 rv
= docv
->GetDocument(getter_AddRefs(doc
));
7969 NS_ENSURE_SUCCESS(rv
, rv
);
7970 const nsACString
&aCharset
= doc
->GetDocumentCharacterSet();
7972 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
7973 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
7974 NS_ENSURE_SUCCESS(rv
, rv
);
7976 // Unescape and convert to unicode
7979 rv
= textToSubURI
->UnEscapeAndConvert(PromiseFlatCString(aCharset
).get(),
7980 PromiseFlatCString(sNewRef
).get(),
7981 getter_Copies(uStr
));
7982 NS_ENSURE_SUCCESS(rv
, rv
);
7984 // Ignore return value of GoToAnchor, since it will return an error
7985 // if there is no such anchor in the document, which is actually a
7986 // success condition for us (we want to update the session history
7987 // with the new URI no matter whether we actually scrolled
7989 shell
->GoToAnchor(uStr
, scroll
);
7994 // Tell the shell it's at an anchor, without scrolling.
7995 shell
->GoToAnchor(EmptyString(), PR_FALSE
);
7997 // An empty anchor was found, but if it's a load from history,
7998 // we don't have to jump to the top of the page. Scrollbar
7999 // position will be restored by the caller, based on positions
8000 // stored in session history.
8001 if (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
)
8003 //An empty anchor. Scroll to the top of the page.
8004 rv
= SetCurScrollPosEx(0, 0);
8011 nsDocShell::SetupReferrerFromChannel(nsIChannel
* aChannel
)
8013 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
8015 nsCOMPtr
<nsIURI
> referrer
;
8016 nsresult rv
= httpChannel
->GetReferrer(getter_AddRefs(referrer
));
8017 if (NS_SUCCEEDED(rv
)) {
8018 SetReferrerURI(referrer
);
8024 nsDocShell::OnNewURI(nsIURI
* aURI
, nsIChannel
* aChannel
, nsISupports
* aOwner
,
8025 PRUint32 aLoadType
, PRBool aFireOnLocationChange
,
8026 PRBool aAddToGlobalHistory
)
8028 NS_PRECONDITION(aURI
, "uri is null");
8029 NS_PRECONDITION(!aChannel
|| !aOwner
, "Shouldn't have both set");
8031 #if defined(PR_LOGGING) && defined(DEBUG)
8032 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
8034 aURI
->GetSpec(spec
);
8036 nsCAutoString chanName
;
8038 aChannel
->GetName(chanName
);
8040 chanName
.AssignLiteral("<no channel>");
8042 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
8043 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec
.get(),
8044 chanName
.get(), aLoadType
));
8048 PRBool updateHistory
= PR_TRUE
;
8049 PRBool equalUri
= PR_FALSE
;
8050 PRBool shAvailable
= PR_TRUE
;
8052 // Get the post data from the channel
8053 nsCOMPtr
<nsIInputStream
> inputStream
;
8055 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
8057 // Check if the HTTPChannel is hiding under a multiPartChannel
8059 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
8063 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
8064 if (uploadChannel
) {
8065 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
8069 /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
8070 * the current frame or in the root docshell
8072 nsCOMPtr
<nsISHistory
> rootSH
= mSessionHistory
;
8074 // Get the handle to SH from the root docshell
8075 GetRootSessionHistory(getter_AddRefs(rootSH
));
8077 shAvailable
= PR_FALSE
;
8081 // Determine if this type of load should update history.
8082 if (aLoadType
== LOAD_BYPASS_HISTORY
||
8083 aLoadType
== LOAD_ERROR_PAGE
||
8084 aLoadType
& LOAD_CMD_HISTORY
||
8085 aLoadType
& LOAD_CMD_RELOAD
)
8086 updateHistory
= PR_FALSE
;
8088 // Check if the url to be loaded is the same as the one already loaded.
8090 aURI
->Equals(mCurrentURI
, &equalUri
);
8093 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
8094 (" shAvailable=%i updateHistory=%i equalURI=%i\n",
8095 shAvailable
, updateHistory
, equalUri
));
8098 /* If the url to be loaded is the same as the one already there,
8099 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
8100 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
8101 * AddToSessionHistory() won't mess with the current SHEntry and
8102 * if this page has any frame children, it also will be handled
8103 * properly. see bug 83684
8105 * XXX Hopefully changing the loadType at this time will not hurt
8106 * anywhere. The other way to take care of sequentially repeating
8107 * frameset pages is to add new methods to nsIDocShellTreeItem.
8108 * Hopefully I don't have to do that.
8111 (mLoadType
== LOAD_NORMAL
||
8112 mLoadType
== LOAD_LINK
||
8113 mLoadType
== LOAD_STOP_CONTENT
) &&
8116 mLoadType
= LOAD_NORMAL_REPLACE
;
8119 // If this is a refresh to the currently loaded url, we don't
8120 // have to update session or global history.
8121 if (mLoadType
== LOAD_REFRESH
&& !inputStream
&& equalUri
) {
8122 SetHistoryEntry(&mLSHE
, mOSHE
);
8126 /* If the user pressed shift-reload, cache will create a new cache key
8127 * for the page. Save the new cacheKey in Session History.
8131 (aLoadType
== LOAD_RELOAD_BYPASS_CACHE
||
8132 aLoadType
== LOAD_RELOAD_BYPASS_PROXY
||
8133 aLoadType
== LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
)) {
8134 NS_ASSERTION(!updateHistory
,
8135 "We shouldn't be updating history for forced reloads!");
8137 nsCOMPtr
<nsICachingChannel
> cacheChannel(do_QueryInterface(aChannel
));
8138 nsCOMPtr
<nsISupports
> cacheKey
;
8139 // Get the Cache Key and store it in SH.
8141 cacheChannel
->GetCacheKey(getter_AddRefs(cacheKey
));
8142 // If we already have a loading history entry, store the new cache key
8143 // in it. Otherwise, since we're doing a reload and won't be updating
8144 // our history entry, store the cache key in our current history entry.
8146 mLSHE
->SetCacheKey(cacheKey
);
8148 mOSHE
->SetCacheKey(cacheKey
);
8151 if (updateHistory
&& shAvailable
) {
8152 // Update session history if necessary...
8153 if (!mLSHE
&& (mItemType
== typeContent
) && mURIResultedInDocument
) {
8154 /* This is a fresh page getting loaded for the first time
8155 *.Create a Entry for it and add it to SH, if this is the
8158 (void) AddToSessionHistory(aURI
, aChannel
, aOwner
,
8159 getter_AddRefs(mLSHE
));
8162 // Update Global history
8163 if (aAddToGlobalHistory
) {
8164 // Get the referrer uri from the channel
8165 AddToGlobalHistory(aURI
, PR_FALSE
, aChannel
);
8169 // If this was a history load, update the index in
8171 if (rootSH
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
8172 nsCOMPtr
<nsISHistoryInternal
> shInternal(do_QueryInterface(rootSH
));
8174 rootSH
->GetIndex(&mPreviousTransIndex
);
8175 shInternal
->UpdateIndex();
8176 rootSH
->GetIndex(&mLoadedTransIndex
);
8177 #ifdef DEBUG_PAGE_CACHE
8178 printf("Previous index: %d, Loaded index: %d\n\n",
8179 mPreviousTransIndex
, mLoadedTransIndex
);
8183 PRBool onLocationChangeNeeded
= SetCurrentURI(aURI
, aChannel
,
8184 aFireOnLocationChange
);
8185 // Make sure to store the referrer from the channel, if any
8186 SetupReferrerFromChannel(aChannel
);
8187 return onLocationChangeNeeded
;
8191 nsDocShell::OnLoadingSite(nsIChannel
* aChannel
, PRBool aFireOnLocationChange
,
8192 PRBool aAddToGlobalHistory
)
8194 nsCOMPtr
<nsIURI
> uri
;
8195 // If this a redirect, use the final url (uri)
8196 // else use the original url
8198 // Note that this should match what documents do (see nsDocument::Reset).
8199 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
8200 NS_ENSURE_TRUE(uri
, PR_FALSE
);
8202 return OnNewURI(uri
, aChannel
, nsnull
, mLoadType
, aFireOnLocationChange
,
8203 aAddToGlobalHistory
);
8208 nsDocShell::SetReferrerURI(nsIURI
* aURI
)
8210 mReferrerURI
= aURI
; // This assigment addrefs
8213 //*****************************************************************************
8214 // nsDocShell: Session History
8215 //*****************************************************************************
8217 nsDocShell::ShouldAddToSessionHistory(nsIURI
* aURI
)
8219 // I believe none of the about: urls should go in the history. But then
8220 // that could just be me... If the intent is only deny about:blank then we
8221 // should just do a spec compare, rather than two gets of the scheme and
8222 // then the path. -Gagan
8226 rv
= aURI
->GetScheme(buf
);
8230 if (buf
.Equals("about")) {
8231 rv
= aURI
->GetPath(buf
);
8235 if (buf
.Equals("blank")) {
8243 nsDocShell::AddToSessionHistory(nsIURI
* aURI
, nsIChannel
* aChannel
,
8244 nsISupports
* aOwner
, nsISHEntry
** aNewEntry
)
8246 NS_PRECONDITION(aURI
, "uri is null");
8247 NS_PRECONDITION(!aChannel
|| !aOwner
, "Shouldn't have both set");
8249 #if defined(PR_LOGGING) && defined(DEBUG)
8250 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
8252 aURI
->GetSpec(spec
);
8254 nsCAutoString chanName
;
8256 aChannel
->GetName(chanName
);
8258 chanName
.AssignLiteral("<no channel>");
8260 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
8261 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec
.get(),
8266 nsresult rv
= NS_OK
;
8267 nsCOMPtr
<nsISHEntry
> entry
;
8268 PRBool shouldPersist
;
8270 shouldPersist
= ShouldAddToSessionHistory(aURI
);
8272 // Get a handle to the root docshell
8273 nsCOMPtr
<nsIDocShellTreeItem
> root
;
8274 GetSameTypeRootTreeItem(getter_AddRefs(root
));
8276 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
8277 * the existing SH entry in the page and replace the url and
8280 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) &&
8281 root
!= static_cast<nsIDocShellTreeItem
*>(this)) {
8282 // This is a subframe
8284 nsCOMPtr
<nsISHContainer
> shContainer(do_QueryInterface(entry
));
8286 PRInt32 childCount
= 0;
8287 shContainer
->GetChildCount(&childCount
);
8288 // Remove all children of this entry
8289 for (PRInt32 i
= childCount
- 1; i
>= 0; i
--) {
8290 nsCOMPtr
<nsISHEntry
> child
;
8291 shContainer
->GetChildAt(i
, getter_AddRefs(child
));
8292 shContainer
->RemoveChild(child
);
8297 // Create a new entry if necessary.
8299 entry
= do_CreateInstance(NS_SHENTRY_CONTRACTID
);
8302 return NS_ERROR_OUT_OF_MEMORY
;
8306 // Get the post data & referrer
8307 nsCOMPtr
<nsIInputStream
> inputStream
;
8308 nsCOMPtr
<nsIURI
> referrerURI
;
8309 nsCOMPtr
<nsISupports
> cacheKey
;
8310 nsCOMPtr
<nsISupports
> cacheToken
;
8311 nsCOMPtr
<nsISupports
> owner
= aOwner
;
8312 PRBool expired
= PR_FALSE
;
8313 PRBool discardLayoutState
= PR_FALSE
;
8315 nsCOMPtr
<nsICachingChannel
>
8316 cacheChannel(do_QueryInterface(aChannel
));
8317 /* If there is a caching channel, get the Cache Key and store it
8321 cacheChannel
->GetCacheKey(getter_AddRefs(cacheKey
));
8322 cacheChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
8324 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
8326 // Check if the httpChannel is hiding under a multipartChannel
8328 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
8331 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
8332 if (uploadChannel
) {
8333 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
8335 httpChannel
->GetReferrer(getter_AddRefs(referrerURI
));
8337 discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
8339 aChannel
->GetOwner(getter_AddRefs(owner
));
8342 //Title is set in nsDocShell::SetTitle()
8343 entry
->Create(aURI
, // uri
8344 EmptyString(), // Title
8345 inputStream
, // Post data stream
8346 nsnull
, // LayoutHistory state
8347 cacheKey
, // CacheKey
8348 mContentTypeHint
, // Content-type
8349 owner
); // Channel or provided owner
8350 entry
->SetReferrerURI(referrerURI
);
8351 /* If cache got a 'no-store', ask SH not to store
8352 * HistoryLayoutState. By default, SH will set this
8353 * flag to PR_TRUE and save HistoryLayoutState.
8355 if (discardLayoutState
) {
8356 entry
->SetSaveLayoutStateFlag(PR_FALSE
);
8359 // Check if the page has expired from cache
8360 nsCOMPtr
<nsICacheEntryInfo
> cacheEntryInfo(do_QueryInterface(cacheToken
));
8361 if (cacheEntryInfo
) {
8363 cacheEntryInfo
->GetExpirationTime(&expTime
);
8364 PRUint32 now
= PRTimeToSeconds(PR_Now());
8370 if (expired
== PR_TRUE
)
8371 entry
->SetExpirationStatus(PR_TRUE
);
8374 if (root
== static_cast<nsIDocShellTreeItem
*>(this) && mSessionHistory
) {
8375 // This is the root docshell
8376 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
8377 // Replace current entry in session history.
8379 mSessionHistory
->GetIndex(&index
);
8380 nsCOMPtr
<nsISHistoryInternal
> shPrivate(do_QueryInterface(mSessionHistory
));
8381 // Replace the current entry with the new entry
8383 rv
= shPrivate
->ReplaceEntry(index
, entry
);
8386 // Add to session history
8387 nsCOMPtr
<nsISHistoryInternal
>
8388 shPrivate(do_QueryInterface(mSessionHistory
));
8389 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
8390 mSessionHistory
->GetIndex(&mPreviousTransIndex
);
8391 rv
= shPrivate
->AddEntry(entry
, shouldPersist
);
8392 mSessionHistory
->GetIndex(&mLoadedTransIndex
);
8393 #ifdef DEBUG_PAGE_CACHE
8394 printf("Previous index: %d, Loaded index: %d\n\n",
8395 mPreviousTransIndex
, mLoadedTransIndex
);
8400 // This is a subframe.
8401 if (!mOSHE
|| !LOAD_TYPE_HAS_FLAGS(mLoadType
,
8402 LOAD_FLAGS_REPLACE_HISTORY
))
8403 rv
= DoAddChildSHEntry(entry
, mChildOffset
);
8406 // Return the new SH entry...
8408 *aNewEntry
= nsnull
;
8409 if (NS_SUCCEEDED(rv
)) {
8411 NS_ADDREF(*aNewEntry
);
8420 nsDocShell::LoadHistoryEntry(nsISHEntry
* aEntry
, PRUint32 aLoadType
)
8422 if (!IsNavigationAllowed()) {
8426 nsCOMPtr
<nsIURI
> uri
;
8427 nsCOMPtr
<nsIInputStream
> postData
;
8428 nsCOMPtr
<nsIURI
> referrerURI
;
8429 nsCAutoString contentType
;
8430 nsCOMPtr
<nsISupports
> owner
;
8432 NS_ENSURE_TRUE(aEntry
, NS_ERROR_FAILURE
);
8434 NS_ENSURE_SUCCESS(aEntry
->GetURI(getter_AddRefs(uri
)), NS_ERROR_FAILURE
);
8435 NS_ENSURE_SUCCESS(aEntry
->GetReferrerURI(getter_AddRefs(referrerURI
)),
8437 NS_ENSURE_SUCCESS(aEntry
->GetPostData(getter_AddRefs(postData
)),
8439 NS_ENSURE_SUCCESS(aEntry
->GetContentType(contentType
), NS_ERROR_FAILURE
);
8440 NS_ENSURE_SUCCESS(aEntry
->GetOwner(getter_AddRefs(owner
)),
8443 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
8444 // that's the only thing holding a ref to aEntry that will cause aEntry to
8445 // die while we're loading it. So hold a strong ref to aEntry here, just
8447 nsCOMPtr
<nsISHEntry
> kungFuDeathGrip(aEntry
);
8449 nsresult rv
= uri
->SchemeIs("javascript", &isJS
);
8450 if (NS_FAILED(rv
) || isJS
) {
8451 // We're loading a URL that will execute script from inside asyncOpen.
8452 // Replace the current document with about:blank now to prevent
8453 // anything from the current document from leaking into any JavaScript
8455 nsCOMPtr
<nsIPrincipal
> prin
= do_QueryInterface(owner
);
8456 rv
= CreateAboutBlankContentViewer(prin
);
8458 if (NS_FAILED(rv
)) {
8459 // The creation of the intermittent about:blank content
8460 // viewer failed for some reason (potentially because the
8461 // user prevented it). Interrupt the history load.
8466 // Ensure that we have an owner. Otherwise javascript: URIs will
8467 // pick it up from the about:blank page we just loaded, and we
8468 // don't really want even that in this case.
8469 owner
= do_CreateInstance("@mozilla.org/nullprincipal;1");
8470 NS_ENSURE_TRUE(owner
, NS_ERROR_OUT_OF_MEMORY
);
8474 /* If there is a valid postdata *and* the user pressed
8475 * reload or shift-reload, take user's permission before we
8476 * repost the data to the server.
8478 if ((aLoadType
& LOAD_CMD_RELOAD
) && postData
) {
8480 rv
= ConfirmRepost(&repost
);
8481 if (NS_FAILED(rv
)) return rv
;
8483 // If the user pressed cancel in the dialog, return. We're done here.
8485 return NS_BINDING_ABORTED
;
8488 rv
= InternalLoad(uri
,
8491 INTERNAL_LOAD_FLAGS_NONE
, // Do not inherit owner from document (security-critical!)
8492 nsnull
, // No window target
8493 contentType
.get(), // Type hint
8494 postData
, // Post data stream
8495 nsnull
, // No headers stream
8496 aLoadType
, // Load type
8499 nsnull
, // No nsIDocShell
8500 nsnull
); // No nsIRequest
8504 NS_IMETHODIMP
nsDocShell::GetShouldSaveLayoutState(PRBool
* aShould
)
8506 *aShould
= PR_FALSE
;
8508 // Don't capture historystate and save it in history
8509 // if the page asked not to do so.
8510 mOSHE
->GetSaveLayoutStateFlag(aShould
);
8516 NS_IMETHODIMP
nsDocShell::PersistLayoutHistoryState()
8518 nsresult rv
= NS_OK
;
8521 nsCOMPtr
<nsIPresShell
> shell
;
8522 rv
= GetPresShell(getter_AddRefs(shell
));
8523 if (NS_SUCCEEDED(rv
) && shell
) {
8524 nsCOMPtr
<nsILayoutHistoryState
> layoutState
;
8525 rv
= shell
->CaptureHistoryState(getter_AddRefs(layoutState
),
8533 /* static */ nsresult
8534 nsDocShell::WalkHistoryEntries(nsISHEntry
*aRootEntry
,
8535 nsDocShell
*aRootShell
,
8536 WalkHistoryEntriesFunc aCallback
,
8539 NS_ENSURE_TRUE(aRootEntry
, NS_ERROR_FAILURE
);
8541 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(aRootEntry
));
8543 return NS_ERROR_FAILURE
;
8546 container
->GetChildCount(&childCount
);
8547 for (PRInt32 i
= 0; i
< childCount
; i
++) {
8548 nsCOMPtr
<nsISHEntry
> childEntry
;
8549 container
->GetChildAt(i
, getter_AddRefs(childEntry
));
8551 // childEntry can be null for valid reasons, for example if the
8552 // docshell at index i never loaded anything useful.
8556 nsDocShell
*childShell
= nsnull
;
8558 // Walk the children of aRootShell and see if one of them
8559 // has srcChild as a SHEntry.
8561 PRInt32 childCount
= aRootShell
->mChildList
.Count();
8562 for (PRInt32 j
= 0; j
< childCount
; ++j
) {
8564 static_cast<nsDocShell
*>(aRootShell
->ChildAt(j
));
8566 if (child
->HasHistoryEntry(childEntry
)) {
8572 nsresult rv
= aCallback(childEntry
, childShell
, i
, aData
);
8573 NS_ENSURE_SUCCESS(rv
, rv
);
8579 // callback data for WalkHistoryEntries
8580 struct NS_STACK_CLASS CloneAndReplaceData
8582 CloneAndReplaceData(PRUint32 aCloneID
, nsISHEntry
*aReplaceEntry
,
8583 nsISHEntry
*aDestTreeParent
)
8584 : cloneID(aCloneID
),
8585 replaceEntry(aReplaceEntry
),
8586 destTreeParent(aDestTreeParent
) { }
8589 nsISHEntry
*replaceEntry
;
8590 nsISHEntry
*destTreeParent
;
8591 nsCOMPtr
<nsISHEntry
> resultEntry
;
8594 /* static */ nsresult
8595 nsDocShell::CloneAndReplaceChild(nsISHEntry
*aEntry
, nsDocShell
*aShell
,
8596 PRInt32 aEntryIndex
, void *aData
)
8598 nsresult result
= NS_OK
;
8599 nsCOMPtr
<nsISHEntry
> dest
;
8601 CloneAndReplaceData
*data
= static_cast<CloneAndReplaceData
*>(aData
);
8602 PRUint32 cloneID
= data
->cloneID
;
8603 nsISHEntry
*replaceEntry
= data
->replaceEntry
;
8606 aEntry
->GetID(&srcID
);
8608 if (srcID
== cloneID
) {
8609 // Just replace the entry, and don't walk the children.
8610 dest
= replaceEntry
;
8611 dest
->SetIsSubFrame(PR_TRUE
);
8613 // Clone the SHEntry...
8614 result
= aEntry
->Clone(getter_AddRefs(dest
));
8615 if (NS_FAILED(result
))
8618 // This entry is for a subframe navigation
8619 dest
->SetIsSubFrame(PR_TRUE
);
8621 // Walk the children
8622 CloneAndReplaceData
childData(cloneID
, replaceEntry
, dest
);
8623 result
= WalkHistoryEntries(aEntry
, aShell
,
8624 CloneAndReplaceChild
, &childData
);
8625 if (NS_FAILED(result
))
8629 aShell
->SwapHistoryEntries(aEntry
, dest
);
8632 nsCOMPtr
<nsISHContainer
> container
=
8633 do_QueryInterface(data
->destTreeParent
);
8635 container
->AddChild(dest
, aEntryIndex
);
8637 data
->resultEntry
= dest
;
8641 /* static */ nsresult
8642 nsDocShell::CloneAndReplace(nsISHEntry
*aSrcEntry
,
8643 nsDocShell
*aSrcShell
,
8645 nsISHEntry
*aReplaceEntry
,
8646 nsISHEntry
**aResultEntry
)
8648 NS_ENSURE_ARG_POINTER(aResultEntry
);
8649 NS_ENSURE_TRUE(aReplaceEntry
, NS_ERROR_FAILURE
);
8651 CloneAndReplaceData
data(aCloneID
, aReplaceEntry
, nsnull
);
8652 nsresult rv
= CloneAndReplaceChild(aSrcEntry
, aSrcShell
, 0, &data
);
8654 data
.resultEntry
.swap(*aResultEntry
);
8660 nsDocShell::SwapHistoryEntries(nsISHEntry
*aOldEntry
, nsISHEntry
*aNewEntry
)
8662 if (aOldEntry
== mOSHE
)
8665 if (aOldEntry
== mLSHE
)
8670 struct SwapEntriesData
8672 nsDocShell
*ignoreShell
; // constant; the shell to ignore
8673 nsISHEntry
*destTreeRoot
; // constant; the root of the dest tree
8674 nsISHEntry
*destTreeParent
; // constant; the node under destTreeRoot
8675 // whose children will correspond to aEntry
8680 nsDocShell::SetChildHistoryEntry(nsISHEntry
*aEntry
, nsDocShell
*aShell
,
8681 PRInt32 aEntryIndex
, void *aData
)
8683 SwapEntriesData
*data
= static_cast<SwapEntriesData
*>(aData
);
8684 nsDocShell
*ignoreShell
= data
->ignoreShell
;
8686 if (!aShell
|| aShell
== ignoreShell
)
8689 nsISHEntry
*destTreeRoot
= data
->destTreeRoot
;
8691 nsCOMPtr
<nsISHEntry
> destEntry
;
8692 nsCOMPtr
<nsISHContainer
> container
=
8693 do_QueryInterface(data
->destTreeParent
);
8696 // aEntry is a clone of some child of destTreeParent, but since the
8697 // trees aren't necessarily in sync, we'll have to locate it.
8698 // Note that we could set aShell's entry to null if we don't find a
8699 // corresponding entry under destTreeParent.
8701 PRUint32 targetID
, id
;
8702 aEntry
->GetID(&targetID
);
8704 // First look at the given index, since this is the common case.
8705 nsCOMPtr
<nsISHEntry
> entry
;
8706 container
->GetChildAt(aEntryIndex
, getter_AddRefs(entry
));
8707 if (entry
&& NS_SUCCEEDED(entry
->GetID(&id
)) && id
== targetID
) {
8708 destEntry
.swap(entry
);
8711 container
->GetChildCount(&childCount
);
8712 for (PRInt32 i
= 0; i
< childCount
; ++i
) {
8713 container
->GetChildAt(i
, getter_AddRefs(entry
));
8718 if (id
== targetID
) {
8719 destEntry
.swap(entry
);
8725 destEntry
= destTreeRoot
;
8728 aShell
->SwapHistoryEntries(aEntry
, destEntry
);
8730 // Now handle the children of aEntry.
8731 SwapEntriesData childData
= { ignoreShell
, destTreeRoot
, destEntry
};
8732 return WalkHistoryEntries(aEntry
, aShell
,
8733 SetChildHistoryEntry
, &childData
);
8738 GetRootSHEntry(nsISHEntry
*aEntry
)
8740 nsCOMPtr
<nsISHEntry
> rootEntry
= aEntry
;
8741 nsISHEntry
*result
= nsnull
;
8744 result
->GetParent(getter_AddRefs(rootEntry
));
8752 nsDocShell::SetHistoryEntry(nsCOMPtr
<nsISHEntry
> *aPtr
, nsISHEntry
*aEntry
)
8754 // We need to sync up the docshell and session history trees for
8755 // subframe navigation. If the load was in a subframe, we forward up to
8756 // the root docshell, which will then recursively sync up all docshells
8757 // to their corresponding entries in the new session history tree.
8758 // If we don't do this, then we can cache a content viewer on the wrong
8759 // cloned entry, and subsequently restore it at the wrong time.
8761 nsISHEntry
*newRootEntry
= GetRootSHEntry(aEntry
);
8763 // newRootEntry is now the new root entry.
8764 // Find the old root entry as well.
8766 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
8767 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
8768 nsCOMPtr
<nsISHEntry
> oldRootEntry
= GetRootSHEntry(*aPtr
);
8770 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
8771 GetSameTypeParent(getter_AddRefs(parentAsItem
));
8772 nsCOMPtr
<nsIDocShell
> rootShell
= do_QueryInterface(parentAsItem
);
8773 if (rootShell
) { // if we're the root just set it, nothing to swap
8774 SwapEntriesData data
= { this, newRootEntry
};
8775 nsIDocShell
*rootIDocShell
=
8776 static_cast<nsIDocShell
*>(rootShell
);
8777 nsDocShell
*rootDocShell
= static_cast<nsDocShell
*>
8783 SetChildHistoryEntry(oldRootEntry
, rootDocShell
,
8785 NS_ASSERTION(NS_SUCCEEDED(rv
), "SetChildHistoryEntry failed");
8795 nsDocShell::GetRootSessionHistory(nsISHistory
** aReturn
)
8799 nsCOMPtr
<nsIDocShellTreeItem
> root
;
8800 //Get the root docshell
8801 rv
= GetSameTypeRootTreeItem(getter_AddRefs(root
));
8802 // QI to nsIWebNavigation
8803 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav(do_QueryInterface(root
));
8805 // Get the handle to SH from the root docshell
8806 rv
= rootAsWebnav
->GetSessionHistory(aReturn
);
8812 nsDocShell::GetHttpChannel(nsIChannel
* aChannel
, nsIHttpChannel
** aReturn
)
8814 NS_ENSURE_ARG_POINTER(aReturn
);
8816 return NS_ERROR_FAILURE
;
8818 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(aChannel
));
8819 if (multiPartChannel
) {
8820 nsCOMPtr
<nsIChannel
> baseChannel
;
8821 multiPartChannel
->GetBaseChannel(getter_AddRefs(baseChannel
));
8822 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(baseChannel
));
8823 *aReturn
= httpChannel
;
8824 NS_IF_ADDREF(*aReturn
);
8830 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel
* aChannel
)
8832 // By default layout State will be saved.
8836 // figure out if SH should be saving layout state
8837 nsCOMPtr
<nsISupports
> securityInfo
;
8838 PRBool noStore
= PR_FALSE
, noCache
= PR_FALSE
;
8839 aChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
8840 aChannel
->IsNoStoreResponse(&noStore
);
8841 aChannel
->IsNoCacheResponse(&noCache
);
8843 return (noStore
|| (noCache
&& securityInfo
));
8846 //*****************************************************************************
8847 // nsDocShell: nsIEditorDocShell
8848 //*****************************************************************************
8850 NS_IMETHODIMP
nsDocShell::GetEditor(nsIEditor
* *aEditor
)
8852 NS_ENSURE_ARG_POINTER(aEditor
);
8859 return mEditorData
->GetEditor(aEditor
);
8862 NS_IMETHODIMP
nsDocShell::SetEditor(nsIEditor
* aEditor
)
8864 nsresult rv
= EnsureEditorData();
8865 if (NS_FAILED(rv
)) return rv
;
8867 return mEditorData
->SetEditor(aEditor
);
8871 NS_IMETHODIMP
nsDocShell::GetEditable(PRBool
*aEditable
)
8873 NS_ENSURE_ARG_POINTER(aEditable
);
8874 *aEditable
= mEditorData
&& mEditorData
->GetEditable();
8879 NS_IMETHODIMP
nsDocShell::GetHasEditingSession(PRBool
*aHasEditingSession
)
8881 NS_ENSURE_ARG_POINTER(aHasEditingSession
);
8885 nsCOMPtr
<nsIEditingSession
> editingSession
;
8886 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
8887 *aHasEditingSession
= (editingSession
.get() != nsnull
);
8891 *aHasEditingSession
= PR_FALSE
;
8897 NS_IMETHODIMP
nsDocShell::MakeEditable(PRBool inWaitForUriLoad
)
8899 nsresult rv
= EnsureEditorData();
8900 if (NS_FAILED(rv
)) return rv
;
8902 return mEditorData
->MakeEditable(inWaitForUriLoad
);
8906 nsDocShell::AddToGlobalHistory(nsIURI
* aURI
, PRBool aRedirect
,
8907 nsIChannel
* aChannel
)
8909 if (mItemType
!= typeContent
|| !mGlobalHistory
)
8912 // If this is a POST request, we do not want to include this in global
8913 // history, so return early.
8914 nsCOMPtr
<nsIHttpChannel
> hchan(do_QueryInterface(aChannel
));
8917 nsresult rv
= hchan
->GetRequestMethod(type
);
8918 if (NS_SUCCEEDED(rv
) && type
.EqualsLiteral("POST"))
8923 nsresult rv
= mGlobalHistory
->IsVisited(aURI
, &visited
);
8927 nsCOMPtr
<nsIURI
> referrer
;
8929 NS_GetReferrerFromChannel(aChannel
, getter_AddRefs(referrer
));
8931 rv
= mGlobalHistory
->AddURI(aURI
, aRedirect
, !IsFrame(), referrer
);
8936 nsCOMPtr
<nsIObserverService
> obsService
=
8937 do_GetService("@mozilla.org/observer-service;1");
8939 obsService
->NotifyObservers(aURI
, NS_LINK_VISITED_EVENT_TOPIC
, nsnull
);
8946 //*****************************************************************************
8947 // nsDocShell: Helper Routines
8948 //*****************************************************************************
8951 nsDocShell::SetLoadType(PRUint32 aLoadType
)
8953 mLoadType
= aLoadType
;
8958 nsDocShell::GetLoadType(PRUint32
* aLoadType
)
8960 *aLoadType
= mLoadType
;
8965 nsDocShell::ConfirmRepost(PRBool
* aRepost
)
8968 nsCOMPtr
<nsIPrompt
> prompter
;
8969 CallGetInterface(this, static_cast<nsIPrompt
**>(getter_AddRefs(prompter
)));
8971 nsCOMPtr
<nsIStringBundleService
>
8972 stringBundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID
, &rv
));
8973 NS_ENSURE_SUCCESS(rv
, rv
);
8975 nsCOMPtr
<nsIStringBundle
> appBundle
;
8976 rv
= stringBundleService
->CreateBundle(kAppstringsBundleURL
,
8977 getter_AddRefs(appBundle
));
8978 NS_ENSURE_SUCCESS(rv
, rv
);
8980 nsCOMPtr
<nsIStringBundle
> brandBundle
;
8981 rv
= stringBundleService
->CreateBundle(kBrandBundleURL
, getter_AddRefs(brandBundle
));
8982 NS_ENSURE_SUCCESS(rv
, rv
);
8984 NS_ASSERTION(prompter
&& brandBundle
&& appBundle
,
8985 "Unable to set up repost prompter.");
8987 nsXPIDLString brandName
;
8988 rv
= brandBundle
->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
8989 getter_Copies(brandName
));
8991 nsXPIDLString msgString
, button0Title
;
8992 if (NS_FAILED(rv
)) { // No brand, use the generic version.
8993 rv
= appBundle
->GetStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
8994 getter_Copies(msgString
));
8997 // Brand available - if the app has an override file with formatting, the app name will
8998 // be included. Without an override, the prompt will look like the generic version.
8999 const PRUnichar
*formatStrings
[] = { brandName
.get() };
9000 rv
= appBundle
->FormatStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
9001 formatStrings
, NS_ARRAY_LENGTH(formatStrings
),
9002 getter_Copies(msgString
));
9004 if (NS_FAILED(rv
)) return rv
;
9006 rv
= appBundle
->GetStringFromName(NS_LITERAL_STRING("resendButton.label").get(),
9007 getter_Copies(button0Title
));
9008 if (NS_FAILED(rv
)) return rv
;
9010 PRInt32 buttonPressed
;
9012 ConfirmEx(nsnull
, msgString
.get(),
9013 (nsIPrompt::BUTTON_POS_0
* nsIPrompt::BUTTON_TITLE_IS_STRING
) +
9014 (nsIPrompt::BUTTON_POS_1
* nsIPrompt::BUTTON_TITLE_CANCEL
),
9015 button0Title
.get(), nsnull
, nsnull
, nsnull
, nsnull
, &buttonPressed
);
9016 if (NS_FAILED(rv
)) return rv
;
9018 *aRepost
= (buttonPressed
== 0);
9023 nsDocShell::GetPromptAndStringBundle(nsIPrompt
** aPrompt
,
9024 nsIStringBundle
** aStringBundle
)
9026 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt
), (void **) aPrompt
),
9029 nsCOMPtr
<nsIStringBundleService
>
9030 stringBundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID
));
9031 NS_ENSURE_TRUE(stringBundleService
, NS_ERROR_FAILURE
);
9033 NS_ENSURE_SUCCESS(stringBundleService
->
9034 CreateBundle(kAppstringsBundleURL
,
9042 nsDocShell::GetChildOffset(nsIDOMNode
* aChild
, nsIDOMNode
* aParent
,
9045 NS_ENSURE_ARG_POINTER(aChild
|| aParent
);
9047 nsCOMPtr
<nsIDOMNodeList
> childNodes
;
9048 NS_ENSURE_SUCCESS(aParent
->GetChildNodes(getter_AddRefs(childNodes
)),
9050 NS_ENSURE_TRUE(childNodes
, NS_ERROR_FAILURE
);
9054 for (; PR_TRUE
; i
++) {
9055 nsCOMPtr
<nsIDOMNode
> childNode
;
9056 NS_ENSURE_SUCCESS(childNodes
->Item(i
, getter_AddRefs(childNode
)),
9058 NS_ENSURE_TRUE(childNode
, NS_ERROR_FAILURE
);
9060 if (childNode
.get() == aChild
) {
9066 return NS_ERROR_FAILURE
;
9070 nsDocShell::GetRootScrollableView(nsIScrollableView
** aOutScrollView
)
9072 NS_ENSURE_ARG_POINTER(aOutScrollView
);
9074 nsCOMPtr
<nsIPresShell
> shell
;
9075 NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(shell
)), NS_ERROR_FAILURE
);
9076 NS_ENSURE_TRUE(shell
, NS_ERROR_NULL_POINTER
);
9078 NS_ENSURE_SUCCESS(shell
->GetViewManager()->GetRootScrollableView(aOutScrollView
),
9081 if (*aOutScrollView
== nsnull
) {
9082 return NS_ERROR_FAILURE
;
9088 class nsDebugAutoBoolTrueSetter
9091 nsDebugAutoBoolTrueSetter(PRBool
*aBool
)
9097 ~nsDebugAutoBoolTrueSetter()
9107 nsDocShell::EnsureScriptEnvironment()
9112 if (mIsBeingDestroyed
) {
9113 return NS_ERROR_NOT_AVAILABLE
;
9117 NS_ASSERTION(!mInEnsureScriptEnv
,
9118 "Infinite loop! Calling EnsureScriptEnvironment() from "
9119 "within EnsureScriptEnvironment()!");
9121 // Yeah, this isn't re-entrant safe, but that's ok since if we
9122 // re-enter this method, we'll infinitely loop...
9123 nsDebugAutoBoolTrueSetter
boolSetter(&mInEnsureScriptEnv
);
9126 nsCOMPtr
<nsIDOMScriptObjectFactory
> factory
=
9127 do_GetService(kDOMScriptObjectFactoryCID
);
9128 NS_ENSURE_TRUE(factory
, NS_ERROR_FAILURE
);
9130 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
9131 NS_ENSURE_TRUE(browserChrome
, NS_ERROR_NOT_AVAILABLE
);
9133 PRUint32 chromeFlags
;
9134 browserChrome
->GetChromeFlags(&chromeFlags
);
9136 PRBool isModalContentWindow
=
9137 (chromeFlags
& nsIWebBrowserChrome::CHROME_MODAL
) &&
9138 !(chromeFlags
& nsIWebBrowserChrome::CHROME_OPENAS_CHROME
);
9140 // If our window is modal and we're not opened as chrome, make
9141 // this window a modal content window.
9142 factory
->NewScriptGlobalObject(mItemType
== typeChrome
,
9143 isModalContentWindow
,
9144 getter_AddRefs(mScriptGlobal
));
9145 NS_ENSURE_TRUE(mScriptGlobal
, NS_ERROR_FAILURE
);
9147 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
9148 win
->SetDocShell(static_cast<nsIDocShell
*>(this));
9150 // Ensure the script object is set to run javascript - other languages
9152 // XXXmarkh - should this be setup to run the default language for this doc?
9154 rv
= mScriptGlobal
->EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT
);
9155 NS_ENSURE_SUCCESS(rv
, rv
);
9162 nsDocShell::EnsureEditorData()
9164 PRBool openDocHasDetachedEditor
= mOSHE
&& mOSHE
->HasDetachedEditor();
9165 if (!mEditorData
&& !mIsBeingDestroyed
&& !openDocHasDetachedEditor
) {
9166 // We shouldn't recreate the editor data if it already exists, or
9167 // we're shutting down, or we already have a detached editor data
9168 // stored in the session history. We should only have one editordata
9170 mEditorData
= new nsDocShellEditorData(this);
9173 return mEditorData
? NS_OK
: NS_ERROR_NOT_AVAILABLE
;
9177 nsDocShell::EnsureTransferableHookData()
9179 if (!mTransferableHookData
) {
9180 mTransferableHookData
= new nsTransferableHookData();
9181 if (!mTransferableHookData
) return NS_ERROR_OUT_OF_MEMORY
;
9188 NS_IMETHODIMP
nsDocShell::EnsureFind()
9193 mFind
= do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv
);
9194 if (NS_FAILED(rv
)) return rv
;
9197 // we promise that the nsIWebBrowserFind that we return has been set
9198 // up to point to the focused, or content window, so we have to
9199 // set that up each time.
9201 nsIScriptGlobalObject
* scriptGO
= GetScriptGlobalObject();
9202 NS_ENSURE_TRUE(scriptGO
, NS_ERROR_UNEXPECTED
);
9204 // default to our window
9205 nsCOMPtr
<nsIDOMWindow
> rootWindow
= do_QueryInterface(scriptGO
);
9206 nsCOMPtr
<nsIDOMWindow
> windowToSearch
= rootWindow
;
9208 // if we can, search the focused window
9209 nsCOMPtr
<nsPIDOMWindow
> ourWindow
= do_QueryInterface(scriptGO
);
9210 nsIFocusController
*focusController
= nsnull
;
9212 focusController
= ourWindow
->GetRootFocusController();
9213 if (focusController
)
9215 nsCOMPtr
<nsIDOMWindowInternal
> focusedWindow
;
9216 focusController
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
9218 windowToSearch
= focusedWindow
;
9221 nsCOMPtr
<nsIWebBrowserFindInFrames
> findInFrames
= do_QueryInterface(mFind
);
9222 if (!findInFrames
) return NS_ERROR_NO_INTERFACE
;
9224 rv
= findInFrames
->SetRootSearchFrame(rootWindow
);
9225 if (NS_FAILED(rv
)) return rv
;
9226 rv
= findInFrames
->SetCurrentSearchFrame(windowToSearch
);
9227 if (NS_FAILED(rv
)) return rv
;
9233 nsDocShell::IsFrame()
9235 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
9236 do_QueryInterface(GetAsSupports(mParent
));
9238 PRInt32 parentType
= ~mItemType
; // Not us
9239 parent
->GetItemType(&parentType
);
9240 if (parentType
== mItemType
) // This is a frame
9248 nsDocShell::GetHasFocus(PRBool
*aHasFocus
)
9250 *aHasFocus
= mHasFocus
;
9255 nsDocShell::SetHasFocus(PRBool aHasFocus
)
9257 #ifdef DEBUG_DOCSHELL_FOCUS
9258 printf(">>>>>>>>>> nsDocShell::SetHasFocus: %p %s\n", (void*)this,
9259 aHasFocus
?"Yes":"No");
9262 mHasFocus
= aHasFocus
;
9264 nsDocShellFocusController
* dsfc
= nsDocShellFocusController::GetInstance();
9265 if (dsfc
&& aHasFocus
) {
9270 // We may be in a situation where the focus outline was shown
9271 // on this document because the user tabbed into it, but the focus
9272 // is now switching to another document via a click. In this case,
9273 // we need to make sure the focus outline is removed from this document.
9274 SetCanvasHasFocus(PR_FALSE
);
9280 // Find an nsICanvasFrame under aFrame. Only search the principal
9281 // child lists. aFrame must be non-null.
9282 static nsICanvasFrame
* FindCanvasFrame(nsIFrame
* aFrame
)
9284 nsICanvasFrame
* canvasFrame
= do_QueryFrame(aFrame
);
9289 nsIFrame
* kid
= aFrame
->GetFirstChild(nsnull
);
9291 canvasFrame
= FindCanvasFrame(kid
);
9295 kid
= kid
->GetNextSibling();
9301 //-------------------------------------------------------
9302 // Tells the HTMLFrame/CanvasFrame that is now has focus
9304 nsDocShell::SetCanvasHasFocus(PRBool aCanvasHasFocus
)
9306 if (mEditorData
&& mEditorData
->GetEditable())
9307 return NS_ERROR_NOT_AVAILABLE
;
9309 nsCOMPtr
<nsIPresShell
> presShell
;
9310 GetPresShell(getter_AddRefs(presShell
));
9311 if (!presShell
) return NS_ERROR_FAILURE
;
9313 nsIDocument
*doc
= presShell
->GetDocument();
9314 if (!doc
) return NS_ERROR_FAILURE
;
9316 nsIContent
*rootContent
= doc
->GetRootContent();
9318 nsIFrame
* frame
= presShell
->GetPrimaryFrameFor(rootContent
);
9320 frame
= frame
->GetParent();
9322 nsICanvasFrame
* canvasFrame
= do_QueryFrame(frame
);
9324 return canvasFrame
->SetHasFocus(aCanvasHasFocus
);
9329 // Look for the frame the hard way
9330 nsIFrame
* frame
= presShell
->GetRootFrame();
9332 nsICanvasFrame
* canvasFrame
= FindCanvasFrame(frame
);
9334 return canvasFrame
->SetHasFocus(aCanvasHasFocus
);
9339 return NS_ERROR_FAILURE
;
9343 nsDocShell::GetCanvasHasFocus(PRBool
*aCanvasHasFocus
)
9345 return NS_ERROR_FAILURE
;
9348 /* boolean IsBeingDestroyed (); */
9350 nsDocShell::IsBeingDestroyed(PRBool
*aDoomed
)
9352 NS_ENSURE_ARG(aDoomed
);
9353 *aDoomed
= mIsBeingDestroyed
;
9359 nsDocShell::GetIsExecutingOnLoadHandler(PRBool
*aResult
)
9361 NS_ENSURE_ARG(aResult
);
9362 *aResult
= mIsExecutingOnLoadHandler
;
9367 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState
**aLayoutHistoryState
)
9370 mOSHE
->GetLayoutHistoryState(aLayoutHistoryState
);
9375 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState
*aLayoutHistoryState
)
9378 mOSHE
->SetLayoutHistoryState(aLayoutHistoryState
);
9382 //*****************************************************************************
9383 //*** nsRefreshTimer: Object Management
9384 //*****************************************************************************
9386 nsRefreshTimer::nsRefreshTimer()
9387 : mDelay(0), mRepeat(PR_FALSE
), mMetaRefresh(PR_FALSE
)
9391 nsRefreshTimer::~nsRefreshTimer()
9395 //*****************************************************************************
9396 // nsRefreshTimer::nsISupports
9397 //*****************************************************************************
9399 NS_IMPL_THREADSAFE_ADDREF(nsRefreshTimer
)
9400 NS_IMPL_THREADSAFE_RELEASE(nsRefreshTimer
)
9402 NS_INTERFACE_MAP_BEGIN(nsRefreshTimer
)
9403 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsITimerCallback
)
9404 NS_INTERFACE_MAP_ENTRY(nsITimerCallback
)
9405 NS_INTERFACE_MAP_END_THREADSAFE
9407 ///*****************************************************************************
9408 // nsRefreshTimer::nsITimerCallback
9409 //******************************************************************************
9411 nsRefreshTimer::Notify(nsITimer
* aTimer
)
9413 NS_ASSERTION(mDocShell
, "DocShell is somehow null");
9415 if (mDocShell
&& aTimer
) {
9416 // Get the delay count to determine load type
9418 aTimer
->GetDelay(&delay
);
9419 mDocShell
->ForceRefreshURIFromTimer(mURI
, delay
, mMetaRefresh
, aTimer
);
9424 //*****************************************************************************
9425 //*** nsDocShellFocusController: Object Management
9426 //*****************************************************************************
9428 nsDocShellFocusController::Focus(nsIDocShell
* aDocShell
)
9430 #ifdef DEBUG_DOCSHELL_FOCUS
9431 printf("****** nsDocShellFocusController Focus To: %p Blur To: %p\n",
9432 (void*)aDocShell
, (void*)mFocusedDocShell
);
9435 if (aDocShell
!= mFocusedDocShell
) {
9436 if (mFocusedDocShell
) {
9437 mFocusedDocShell
->SetHasFocus(PR_FALSE
);
9439 mFocusedDocShell
= aDocShell
;
9444 //--------------------------------------------------
9445 // This is need for when the document with focus goes away
9447 nsDocShellFocusController::ClosingDown(nsIDocShell
* aDocShell
)
9449 if (aDocShell
== mFocusedDocShell
) {
9450 mFocusedDocShell
= nsnull
;
9454 //*****************************************************************************
9455 // nsDocShell::InterfaceRequestorProxy
9456 //*****************************************************************************
9457 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor
* p
)
9460 mWeakPtr
= do_GetWeakReference(p
);
9464 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
9469 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDocShell::InterfaceRequestorProxy
, nsIInterfaceRequestor
)
9472 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID
& aIID
, void **aSink
)
9474 NS_ENSURE_ARG_POINTER(aSink
);
9475 nsCOMPtr
<nsIInterfaceRequestor
> ifReq
= do_QueryReferent(mWeakPtr
);
9477 return ifReq
->GetInterface(aIID
, aSink
);
9480 return NS_NOINTERFACE
;
9484 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer
* aContentViewer
)
9486 if (!aContentViewer
)
9487 return NS_ERROR_FAILURE
;
9489 nsCOMPtr
<nsIURI
> baseURI
;
9490 nsCOMPtr
<nsIDocument
> document
;
9491 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
9494 rv
= sURIFixup
->CreateExposableURI(mCurrentURI
,
9495 getter_AddRefs(baseURI
));
9497 // Get the current document and set the base uri
9499 nsCOMPtr
<nsIDocumentViewer
> docViewer(do_QueryInterface(aContentViewer
));
9501 rv
= docViewer
->GetDocument(getter_AddRefs(document
));
9503 rv
= document
->SetBaseURI(baseURI
);
9509 //*****************************************************************************
9510 // nsDocShell::nsIAuthPromptProvider
9511 //*****************************************************************************
9514 nsDocShell::GetAuthPrompt(PRUint32 aPromptReason
, const nsIID
& iid
,
9517 // a priority prompt request will override a false mAllowAuth setting
9518 PRBool priorityPrompt
= (aPromptReason
== PROMPT_PROXY
);
9520 if (!mAllowAuth
&& !priorityPrompt
)
9521 return NS_ERROR_NOT_AVAILABLE
;
9523 // we're either allowing auth, or it's a proxy request
9525 nsCOMPtr
<nsIPromptFactory
> wwatch
=
9526 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
9527 NS_ENSURE_SUCCESS(rv
, rv
);
9529 rv
= EnsureScriptEnvironment();
9530 NS_ENSURE_SUCCESS(rv
, rv
);
9532 nsCOMPtr
<nsIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
9534 // Get the an auth prompter for our window so that the parenting
9535 // of the dialogs works as it should when using tabs.
9537 return wwatch
->GetPrompt(window
, iid
,
9538 reinterpret_cast<void**>(aResult
));
9541 //*****************************************************************************
9542 // nsDocShell::nsIObserver
9543 //*****************************************************************************
9546 nsDocShell::Observe(nsISupports
*aSubject
, const char *aTopic
,
9547 const PRUnichar
*aData
)
9549 nsresult rv
= NS_OK
;
9550 if (mObserveErrorPages
&&
9551 !nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
) &&
9552 !nsCRT::strcmp(aData
,
9553 NS_LITERAL_STRING("browser.xul.error_pages.enabled").get())) {
9555 nsCOMPtr
<nsIPrefBranch
> prefs(do_QueryInterface(aSubject
, &rv
));
9556 NS_ENSURE_SUCCESS(rv
, rv
);
9559 rv
= prefs
->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool
);
9560 if (NS_SUCCEEDED(rv
))
9561 mUseErrorPages
= tmpbool
;
9564 rv
= NS_ERROR_UNEXPECTED
;
9569 //*****************************************************************************
9570 // nsDocShell::nsILoadContext
9571 //*****************************************************************************
9573 nsDocShell::GetAssociatedWindow(nsIDOMWindow
** aWindow
)
9575 return CallGetInterface(this, aWindow
);
9579 nsDocShell::GetTopWindow(nsIDOMWindow
** aWindow
)
9582 nsCOMPtr
<nsIDOMWindow
> win
= do_GetInterface(GetAsSupports(this), &rv
);
9583 NS_ENSURE_SUCCESS(rv
, rv
);
9584 return win
->GetTop(aWindow
);
9588 nsDocShell::IsAppOfType(PRUint32 aAppType
, PRBool
*aIsOfType
)
9590 nsCOMPtr
<nsIDocShell
> shell
= this;
9593 shell
->GetAppType(&type
);
9594 if (type
== aAppType
) {
9595 *aIsOfType
= PR_TRUE
;
9598 nsCOMPtr
<nsIDocShellTreeItem
> item
= do_QueryInterface(shell
);
9599 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
9600 item
->GetParent(getter_AddRefs(parent
));
9601 shell
= do_QueryInterface(parent
);
9604 *aIsOfType
= PR_FALSE
;
9609 nsDocShell::GetIsContent(PRBool
*aIsContent
)
9611 *aIsContent
= (mItemType
== typeContent
);
9617 nsDocShell::URIInheritsSecurityContext(nsIURI
* aURI
, PRBool
* aResult
)
9619 // Note: about:blank URIs do NOT inherit the security context from the
9620 // current document, which is what this function tests for...
9621 return NS_URIChainHasFlags(aURI
,
9622 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
,
9628 nsDocShell::URIIsLocalFile(nsIURI
*aURI
)
9631 nsCOMPtr
<nsINetUtil
> util
= do_GetIOService();
9633 return util
&& NS_SUCCEEDED(util
->ProtocolHasFlags(aURI
,
9634 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
9641 nsDocShell::IsAboutBlank(nsIURI
* aURI
)
9643 NS_PRECONDITION(aURI
, "Must have URI");
9645 // GetSpec can be expensive for some URIs, so check the scheme first.
9646 PRBool isAbout
= PR_FALSE
;
9647 if (NS_FAILED(aURI
->SchemeIs("about", &isAbout
)) || !isAbout
) {
9653 return str
.EqualsLiteral("about:blank");
9657 nsDocShell::IsOKToLoadURI(nsIURI
* aURI
)
9659 NS_PRECONDITION(aURI
, "Must have a URI!");
9661 if (!mFiredUnloadEvent
) {
9669 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
9670 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
9673 NS_SUCCEEDED(secMan
->CheckSameOriginURI(aURI
, mLoadingURI
, PR_FALSE
));
9676 //*****************************************************************************
9677 // nsClassifierCallback
9678 //*****************************************************************************
9680 NS_IMPL_ISUPPORTS5(nsClassifierCallback
,
9681 nsIChannelClassifier
,
9682 nsIURIClassifierCallback
,
9684 nsIChannelEventSink
,
9685 nsIInterfaceRequestor
)
9688 nsClassifierCallback::Run()
9694 NS_ASSERTION(!mSuspendedChannel
,
9695 "nsClassifierCallback::Run() called while a "
9696 "channel is still suspended.");
9698 nsCOMPtr
<nsIChannel
> channel
;
9699 channel
.swap(mChannel
);
9701 // Don't bother to run the classifier on a load that has already failed.
9702 // (this might happen after a redirect)
9704 channel
->GetStatus(&status
);
9705 if (NS_FAILED(status
))
9708 // Don't bother to run the classifier on a cached load that was
9709 // previously classified.
9710 if (HasBeenClassified(channel
)) {
9714 nsCOMPtr
<nsIURI
> uri
;
9715 nsresult rv
= channel
->GetURI(getter_AddRefs(uri
));
9716 NS_ENSURE_SUCCESS(rv
, rv
);
9718 // Don't bother checking certain types of URIs.
9720 rv
= NS_URIChainHasFlags(uri
,
9721 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD
,
9723 NS_ENSURE_SUCCESS(rv
, rv
);
9724 if (hasFlags
) return NS_OK
;
9726 rv
= NS_URIChainHasFlags(uri
,
9727 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
9729 NS_ENSURE_SUCCESS(rv
, rv
);
9730 if (hasFlags
) return NS_OK
;
9732 rv
= NS_URIChainHasFlags(uri
,
9733 nsIProtocolHandler::URI_IS_UI_RESOURCE
,
9735 NS_ENSURE_SUCCESS(rv
, rv
);
9736 if (hasFlags
) return NS_OK
;
9738 rv
= NS_URIChainHasFlags(uri
,
9739 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE
,
9741 NS_ENSURE_SUCCESS(rv
, rv
);
9742 if (hasFlags
) return NS_OK
;
9744 nsCOMPtr
<nsIURIClassifier
> uriClassifier
=
9745 do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID
, &rv
);
9746 if (rv
== NS_ERROR_FACTORY_NOT_REGISTERED
||
9747 rv
== NS_ERROR_NOT_AVAILABLE
) {
9748 // no URI classifier, ignore this failure.
9751 NS_ENSURE_SUCCESS(rv
, rv
);
9753 PRBool expectCallback
;
9754 rv
= uriClassifier
->Classify(uri
, this, &expectCallback
);
9755 if (NS_FAILED(rv
)) return rv
;
9757 if (expectCallback
) {
9758 // Suspend the channel, it will be resumed when we get the classifier
9760 rv
= channel
->Suspend();
9761 if (NS_FAILED(rv
)) {
9762 // Some channels (including nsJSChannel) fail on Suspend. This
9763 // shouldn't be fatal, but will prevent malware from being
9764 // blocked on these channels.
9768 mSuspendedChannel
= channel
;
9770 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9771 ("nsClassifierCallback[%p]: suspended channel %p",
9772 this, mSuspendedChannel
.get()));
9779 // Note in the cache entry that this URL was classified, so that future
9780 // cached loads don't need to be checked.
9782 nsClassifierCallback::MarkEntryClassified(nsresult status
)
9784 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
9785 do_QueryInterface(mSuspendedChannel
);
9786 if (!cachingChannel
) {
9790 nsCOMPtr
<nsISupports
> cacheToken
;
9791 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
9796 nsCOMPtr
<nsICacheEntryDescriptor
> cacheEntry
=
9797 do_QueryInterface(cacheToken
);
9802 cacheEntry
->SetMetaDataElement("docshell:classified",
9803 NS_SUCCEEDED(status
) ? "1" : nsnull
);
9807 nsClassifierCallback::HasBeenClassified(nsIChannel
*aChannel
)
9809 nsCOMPtr
<nsICachingChannel
> cachingChannel
=
9810 do_QueryInterface(aChannel
);
9811 if (!cachingChannel
) {
9815 // Only check the tag if we are loading from the cache without
9818 if (NS_FAILED(cachingChannel
->IsFromCache(&fromCache
)) || !fromCache
) {
9822 nsCOMPtr
<nsISupports
> cacheToken
;
9823 cachingChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
9828 nsCOMPtr
<nsICacheEntryDescriptor
> cacheEntry
=
9829 do_QueryInterface(cacheToken
);
9835 cacheEntry
->GetMetaDataElement("docshell:classified", getter_Copies(tag
));
9836 return tag
.EqualsLiteral("1");
9840 nsClassifierCallback::OnClassifyComplete(nsresult aErrorCode
)
9842 if (mSuspendedChannel
) {
9843 MarkEntryClassified(aErrorCode
);
9845 if (NS_FAILED(aErrorCode
)) {
9847 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9848 ("nsClassifierCallback[%p]: cancelling channel %p with error code: %d",
9849 this, mSuspendedChannel
.get(), aErrorCode
));
9851 mSuspendedChannel
->Cancel(aErrorCode
);
9854 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9855 ("nsClassifierCallback[%p]: resuming channel %p from OnClassifyComplete",
9856 this, mSuspendedChannel
.get()));
9858 mSuspendedChannel
->Resume();
9859 mSuspendedChannel
= nsnull
;
9866 nsClassifierCallback::Start(nsIChannel
*aChannel
, PRBool aInstallListener
)
9868 mChannel
= aChannel
;
9870 if (aInstallListener
) {
9871 nsresult rv
= aChannel
->GetNotificationCallbacks
9872 (getter_AddRefs(mNotificationCallbacks
));
9873 NS_ENSURE_SUCCESS(rv
, rv
);
9875 rv
= aChannel
->SetNotificationCallbacks
9876 (static_cast<nsIInterfaceRequestor
*>(this));
9877 NS_ENSURE_SUCCESS(rv
, rv
);
9884 nsClassifierCallback::OnRedirect(nsIChannel
*aOldChannel
,
9885 nsIChannel
*aNewChannel
)
9887 mChannel
= aNewChannel
;
9889 // we call the Run() from the main loop to give the channel a
9890 // chance to AsyncOpen() before we suspend it.
9891 NS_DispatchToCurrentThread(this);
9897 nsClassifierCallback::Cancel()
9899 if (mSuspendedChannel
) {
9901 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9902 ("nsClassifierCallback[%p]: resuming channel %p from Cancel()",
9903 this, mSuspendedChannel
.get()));
9905 mSuspendedChannel
->Resume();
9906 mSuspendedChannel
= nsnull
;
9917 nsClassifierCallback::OnChannelRedirect(nsIChannel
*aOldChannel
,
9918 nsIChannel
*aNewChannel
,
9921 nsresult rv
= OnRedirect(aOldChannel
, aNewChannel
);
9922 NS_ENSURE_SUCCESS(rv
, rv
);
9924 if (mNotificationCallbacks
) {
9925 nsCOMPtr
<nsIChannelEventSink
> sink
=
9926 do_GetInterface(mNotificationCallbacks
);
9928 return sink
->OnChannelRedirect(aOldChannel
, aNewChannel
, aFlags
);
9936 nsClassifierCallback::GetInterface(const nsIID
&aIID
, void **aResult
)
9938 if (aIID
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
9940 *aResult
= static_cast<nsIChannelEventSink
*>(this);
9942 } else if (mNotificationCallbacks
) {
9943 return mNotificationCallbacks
->GetInterface(aIID
, aResult
);
9945 return NS_ERROR_NO_INTERFACE
;