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 "mozilla/dom/Element.h"
53 #include "nsIDocument.h"
54 #include "nsIDOMDocument.h"
55 #include "nsIDOM3Document.h"
56 #include "nsIDOMNSDocument.h"
57 #include "nsIDOMElement.h"
58 #include "nsIDOMStorageObsolete.h"
59 #include "nsIDOMStorage.h"
60 #include "nsPIDOMStorage.h"
61 #include "nsIDocumentViewer.h"
62 #include "nsIDocumentLoaderFactory.h"
63 #include "nsCURILoader.h"
64 #include "nsURILoader.h"
65 #include "nsDocShellCID.h"
66 #include "nsLayoutCID.h"
68 #include "nsIDOMScriptObjectFactory.h"
69 #include "nsNetUtil.h"
72 #include "nsIMarkupDocumentViewer.h"
73 #include "nsXPIDLString.h"
74 #include "nsReadableUtils.h"
75 #include "nsIDOMEventTarget.h"
76 #include "nsIDOMChromeWindow.h"
77 #include "nsIDOMWindowInternal.h"
78 #include "nsIWebBrowserChrome.h"
80 #include "nsGfxCIID.h"
81 #include "nsIObserverService.h"
82 #include "nsIPrompt.h"
83 #include "nsIAuthPrompt.h"
84 #include "nsIAuthPrompt2.h"
85 #include "nsTextFormatter.h"
86 #include "nsIChannelEventSink.h"
87 #include "nsIUploadChannel.h"
88 #include "nsISecurityEventSink.h"
89 #include "mozilla/FunctionTimer.h"
90 #include "nsIScriptSecurityManager.h"
91 #include "nsIJSContextStack.h"
92 #include "nsIScriptObjectPrincipal.h"
93 #include "nsDocumentCharsetInfoCID.h"
94 #include "nsIScrollableFrame.h"
95 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
96 #include "nsICategoryManager.h"
97 #include "nsXPCOMCID.h"
98 #include "nsISeekableStream.h"
99 #include "nsAutoPtr.h"
100 #include "nsIPrefService.h"
101 #include "nsIPrefBranch.h"
102 #include "nsIPrefBranch2.h"
103 #include "nsIWritablePropertyBag2.h"
104 #include "nsIAppShell.h"
105 #include "nsWidgetsCID.h"
106 #include "nsDOMJSUtils.h"
107 #include "nsIInterfaceRequestorUtils.h"
109 #include "nsIViewManager.h"
110 #include "nsIScriptChannel.h"
111 #include "nsIOfflineCacheUpdate.h"
112 #include "nsCPrefetchService.h"
115 // we want to explore making the document own the load group
116 // so we can associate the document URI with the load group.
117 // until this point, we have an evil hack:
118 #include "nsIHttpChannelInternal.h"
122 #include "nsDocShell.h"
123 #include "nsDocShellLoadInfo.h"
124 #include "nsCDefaultURIFixup.h"
125 #include "nsDocShellEnumerator.h"
126 #include "nsSHistory.h"
127 #include "nsDocShellEditorData.h"
130 #include "nsDOMError.h"
131 #include "nsEscape.h"
134 #include "nsIUploadChannel.h"
135 #include "nsIProgressEventSink.h"
136 #include "nsIWebProgress.h"
137 #include "nsILayoutHistoryState.h"
138 #include "nsITimer.h"
139 #include "nsISHistoryInternal.h"
140 #include "nsIPrincipal.h"
141 #include "nsIFileURL.h"
142 #include "nsIHistoryEntry.h"
143 #include "nsISHistoryListener.h"
144 #include "nsIWindowWatcher.h"
145 #include "nsIPromptFactory.h"
146 #include "nsIObserver.h"
147 #include "nsINestedURI.h"
148 #include "nsITransportSecurityInfo.h"
149 #include "nsINSSErrorsService.h"
150 #include "nsIApplicationCache.h"
151 #include "nsIApplicationCacheChannel.h"
152 #include "nsIApplicationCacheContainer.h"
153 #include "nsIPermissionManager.h"
154 #include "nsStreamUtils.h"
155 #include "nsIController.h"
156 #include "nsPICommandUpdater.h"
157 #include "nsIDOMHTMLAnchorElement.h"
158 #include "nsIWebBrowserChrome2.h"
161 #include "nsIEditingSession.h"
163 #include "nsPIDOMWindow.h"
164 #include "nsPIWindowRoot.h"
165 #include "nsIDOMDocument.h"
166 #include "nsICachingChannel.h"
167 #include "nsICacheVisitor.h"
168 #include "nsICacheEntryDescriptor.h"
169 #include "nsIMultiPartChannel.h"
170 #include "nsIWyciwygChannel.h"
172 // The following are for bug #13871: Prevent frameset spoofing
173 #include "nsIHTMLDocument.h"
175 // For reporting errors with the console service.
176 // These can go away if error reporting is propagated up past nsDocShell.
177 #include "nsIConsoleService.h"
178 #include "nsIScriptError.h"
180 // used to dispatch urls to default protocol handlers
181 #include "nsCExternalHandlerService.h"
182 #include "nsIExternalProtocolService.h"
184 #include "nsFocusManager.h"
186 #include "nsITextToSubURI.h"
188 #include "nsIJARChannel.h"
193 #include "nsISelectionDisplay.h"
195 #include "nsIGlobalHistory2.h"
196 #include "nsIGlobalHistory3.h"
198 #ifdef DEBUG_DOCSHELL_FOCUS
199 #include "nsIEventStateManager.h"
202 #include "nsIFrame.h"
205 #include "nsIWebBrowserChromeFocus.h"
208 #include "nsIDocumentViewerPrint.h"
209 #include "nsIWebBrowserPrint.h"
212 #include "nsPluginError.h"
214 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID
,
215 NS_DOM_SCRIPT_OBJECT_FACTORY_CID
);
216 static NS_DEFINE_CID(kAppShellCID
, NS_APPSHELL_CID
);
218 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
219 //#define DEBUG_DOCSHELL_FOCUS
220 #define DEBUG_PAGE_CACHE
223 #include "nsContentErrors.h"
224 #include "nsIChannelPolicy.h"
225 #include "nsIContentSecurityPolicy.h"
227 using namespace mozilla
;
229 // Number of documents currently loading
230 static PRInt32 gNumberOfDocumentsLoading
= 0;
232 // Global count of existing docshells.
233 static PRInt32 gDocShellCount
= 0;
235 // Global reference to the URI fixup service.
236 nsIURIFixup
*nsDocShell::sURIFixup
= 0;
238 // True means we validate window targets to prevent frameset
239 // spoofing. Initialize this to a non-bolean value so we know to check
240 // the pref on the creation of the first docshell.
241 static PRBool gValidateOrigin
= (PRBool
)0xffffffff;
243 // Hint for native dispatch of events on how long to delay after
244 // all documents have loaded in milliseconds before favoring normal
245 // native event dispatch priorites over performance
246 #define NS_EVENT_STARVATION_DELAY_HINT 2000
248 // This is needed for displaying an error message
249 // when navigation is attempted on a document when printing
250 // The value arbitrary as long as it doesn't conflict with
251 // any of the other values in the errors in DisplayLoadError
252 #define NS_ERROR_DOCUMENT_IS_PRINTMODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL,2001)
256 static PRLogModuleInfo
* gDocShellLog
;
258 static PRLogModuleInfo
* gDocShellLeakLog
;
261 const char kBrandBundleURL
[] = "chrome://branding/locale/brand.properties";
262 const char kAppstringsBundleURL
[] = "chrome://global/locale/appstrings.properties";
265 FavorPerformanceHint(PRBool perfOverStarvation
, PRUint32 starvationDelay
)
267 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(kAppShellCID
);
269 appShell
->FavorPerformanceHint(perfOverStarvation
, starvationDelay
);
272 //*****************************************************************************
274 //*****************************************************************************
276 #define PREF_PINGS_ENABLED "browser.send_pings"
277 #define PREF_PINGS_MAX_PER_LINK "browser.send_pings.max_per_link"
278 #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
280 // Check prefs to see if pings are enabled and if so what restrictions might
284 // This parameter returns the number of pings that are allowed per link click
286 // @param requireSameHost
287 // This parameter returns PR_TRUE if pings are restricted to the same host as
288 // the document in which the click occurs. If the same host restriction is
289 // imposed, then we still allow for pings to cross over to different
290 // protocols and ports for flexibility and because it is not possible to send
294 // PR_TRUE if pings are enabled and PR_FALSE otherwise.
297 PingsEnabled(PRInt32
*maxPerLink
, PRBool
*requireSameHost
)
299 PRBool allow
= PR_FALSE
;
302 *requireSameHost
= PR_TRUE
;
304 nsCOMPtr
<nsIPrefBranch
> prefs
=
305 do_GetService(NS_PREFSERVICE_CONTRACTID
);
308 if (NS_SUCCEEDED(prefs
->GetBoolPref(PREF_PINGS_ENABLED
, &val
)))
311 prefs
->GetIntPref(PREF_PINGS_MAX_PER_LINK
, maxPerLink
);
312 prefs
->GetBoolPref(PREF_PINGS_REQUIRE_SAME_HOST
, requireSameHost
);
320 CheckPingURI(nsIURI
* uri
, nsIContent
* content
)
325 // Check with nsIScriptSecurityManager
326 nsCOMPtr
<nsIScriptSecurityManager
> ssmgr
=
327 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
328 NS_ENSURE_TRUE(ssmgr
, PR_FALSE
);
331 ssmgr
->CheckLoadURIWithPrincipal(content
->NodePrincipal(), uri
,
332 nsIScriptSecurityManager::STANDARD
);
337 // Ignore non-HTTP(S)
339 if ((NS_FAILED(uri
->SchemeIs("http", &match
)) || !match
) &&
340 (NS_FAILED(uri
->SchemeIs("https", &match
)) || !match
)) {
344 // Check with contentpolicy
345 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
346 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING
,
348 content
->NodePrincipal(),
350 EmptyCString(), // mime hint
353 return NS_SUCCEEDED(rv
) && NS_CP_ACCEPTED(shouldLoad
);
356 typedef void (* ForEachPingCallback
)(void *closure
, nsIContent
*content
,
357 nsIURI
*uri
, nsIIOService
*ios
);
360 ForEachPing(nsIContent
*content
, ForEachPingCallback callback
, void *closure
)
362 // NOTE: Using nsIDOMNSHTMLAnchorElement2::GetPing isn't really worth it here
363 // since we'd still need to parse the resulting string. Instead, we
364 // just parse the raw attribute. It might be nice if the content node
365 // implemented an interface that exposed an enumeration of nsIURIs.
367 // Make sure we are dealing with either an <A> or <AREA> element in the HTML
368 // or XHTML namespace.
369 if (!content
->IsHTML())
371 nsIAtom
*nameAtom
= content
->Tag();
372 if (!nameAtom
->Equals(NS_LITERAL_STRING("a")) &&
373 !nameAtom
->Equals(NS_LITERAL_STRING("area")))
376 nsCOMPtr
<nsIAtom
> pingAtom
= do_GetAtom("ping");
381 content
->GetAttr(kNameSpaceID_None
, pingAtom
, value
);
385 nsCOMPtr
<nsIIOService
> ios
= do_GetIOService();
389 nsIDocument
*doc
= content
->GetOwnerDoc();
393 // value contains relative URIs split on spaces (U+0020)
394 const PRUnichar
*start
= value
.BeginReading();
395 const PRUnichar
*end
= value
.EndReading();
396 const PRUnichar
*iter
= start
;
398 if (iter
< end
&& *iter
!= ' ') {
400 } else { // iter is pointing at either end or a space
401 while (*start
== ' ' && start
< iter
)
404 nsCOMPtr
<nsIURI
> uri
, baseURI
= content
->GetBaseURI();
405 ios
->NewURI(NS_ConvertUTF16toUTF8(Substring(start
, iter
)),
406 doc
->GetDocumentCharacterSet().get(),
407 baseURI
, getter_AddRefs(uri
));
408 if (CheckPingURI(uri
, content
)) {
409 callback(closure
, content
, uri
, ios
);
412 start
= iter
= iter
+ 1;
419 //----------------------------------------------------------------------
421 // We wait this many milliseconds before killing the ping channel...
422 #define PING_TIMEOUT 10000
425 OnPingTimeout(nsITimer
*timer
, void *closure
)
427 nsILoadGroup
*loadGroup
= static_cast<nsILoadGroup
*>(closure
);
428 loadGroup
->Cancel(NS_ERROR_ABORT
);
429 loadGroup
->Release();
432 // Check to see if two URIs have the same host or not
434 IsSameHost(nsIURI
*uri1
, nsIURI
*uri2
)
436 nsCAutoString host1
, host2
;
437 uri1
->GetAsciiHost(host1
);
438 uri2
->GetAsciiHost(host2
);
439 return host1
.Equals(host2
);
442 class nsPingListener
: public nsIStreamListener
443 , public nsIInterfaceRequestor
444 , public nsIChannelEventSink
448 NS_DECL_NSIREQUESTOBSERVER
449 NS_DECL_NSISTREAMLISTENER
450 NS_DECL_NSIINTERFACEREQUESTOR
451 NS_DECL_NSICHANNELEVENTSINK
453 nsPingListener(PRBool requireSameHost
, nsIContent
* content
)
454 : mRequireSameHost(requireSameHost
),
459 PRBool mRequireSameHost
;
460 nsCOMPtr
<nsIContent
> mContent
;
463 NS_IMPL_ISUPPORTS4(nsPingListener
, nsIStreamListener
, nsIRequestObserver
,
464 nsIInterfaceRequestor
, nsIChannelEventSink
)
467 nsPingListener::OnStartRequest(nsIRequest
*request
, nsISupports
*context
)
473 nsPingListener::OnDataAvailable(nsIRequest
*request
, nsISupports
*context
,
474 nsIInputStream
*stream
, PRUint32 offset
,
478 return stream
->ReadSegments(NS_DiscardSegment
, nsnull
, count
, &result
);
482 nsPingListener::OnStopRequest(nsIRequest
*request
, nsISupports
*context
,
489 nsPingListener::GetInterface(const nsIID
&iid
, void **result
)
491 if (iid
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
493 *result
= (nsIChannelEventSink
*) this;
497 return NS_ERROR_NO_INTERFACE
;
501 nsPingListener::OnChannelRedirect(nsIChannel
*oldChan
, nsIChannel
*newChan
,
504 nsCOMPtr
<nsIURI
> newURI
;
505 newChan
->GetURI(getter_AddRefs(newURI
));
507 if (!CheckPingURI(newURI
, mContent
))
508 return NS_ERROR_ABORT
;
510 if (!mRequireSameHost
)
513 // XXXbz should this be using something more like the nsContentUtils
514 // same-origin checker?
515 nsCOMPtr
<nsIURI
> oldURI
;
516 oldChan
->GetURI(getter_AddRefs(oldURI
));
517 NS_ENSURE_STATE(oldURI
&& newURI
);
519 if (!IsSameHost(oldURI
, newURI
))
520 return NS_ERROR_ABORT
;
525 struct SendPingInfo
{
528 PRBool requireSameHost
;
533 SendPing(void *closure
, nsIContent
*content
, nsIURI
*uri
, nsIIOService
*ios
)
535 SendPingInfo
*info
= static_cast<SendPingInfo
*>(closure
);
536 if (info
->numPings
>= info
->maxPings
)
539 if (info
->requireSameHost
) {
540 // Make sure the referrer and the given uri share the same origin. We
541 // only require the same hostname. The scheme and port may differ.
542 if (!IsSameHost(uri
, info
->referrer
))
546 nsIDocument
*doc
= content
->GetOwnerDoc();
550 nsCOMPtr
<nsIChannel
> chan
;
551 ios
->NewChannelFromURI(uri
, getter_AddRefs(chan
));
555 // Don't bother caching the result of this URI load.
556 chan
->SetLoadFlags(nsIRequest::INHIBIT_CACHING
);
558 nsCOMPtr
<nsIHttpChannel
> httpChan
= do_QueryInterface(chan
);
562 // This is needed in order for 3rd-party cookie blocking to work.
563 nsCOMPtr
<nsIHttpChannelInternal
> httpInternal
= do_QueryInterface(httpChan
);
565 httpInternal
->SetDocumentURI(doc
->GetDocumentURI());
568 httpChan
->SetReferrer(info
->referrer
);
570 httpChan
->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
572 // Remove extraneous request headers (to reduce request size)
573 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
574 EmptyCString(), PR_FALSE
);
575 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
576 EmptyCString(), PR_FALSE
);
577 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept-charset"),
578 EmptyCString(), PR_FALSE
);
579 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
580 EmptyCString(), PR_FALSE
);
582 nsCOMPtr
<nsIUploadChannel
> uploadChan
= do_QueryInterface(httpChan
);
586 // To avoid sending an unnecessary Content-Type header, we encode the
587 // closing portion of the headers in the POST body.
588 NS_NAMED_LITERAL_CSTRING(uploadData
, "Content-Length: 0\r\n\r\n");
590 nsCOMPtr
<nsIInputStream
> uploadStream
;
591 NS_NewPostDataStream(getter_AddRefs(uploadStream
), PR_FALSE
,
596 uploadChan
->SetUploadStream(uploadStream
, EmptyCString(), -1);
598 // The channel needs to have a loadgroup associated with it, so that we can
599 // cancel the channel and any redirected channels it may create.
600 nsCOMPtr
<nsILoadGroup
> loadGroup
=
601 do_CreateInstance(NS_LOADGROUP_CONTRACTID
);
604 chan
->SetLoadGroup(loadGroup
);
606 // Construct a listener that merely discards any response. If successful at
607 // opening the channel, then it is not necessary to hold a reference to the
608 // channel. The networking subsystem will take care of that for us.
609 nsCOMPtr
<nsIStreamListener
> listener
=
610 new nsPingListener(info
->requireSameHost
, content
);
614 // Observe redirects as well:
615 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
= do_QueryInterface(listener
);
616 NS_ASSERTION(callbacks
, "oops");
617 loadGroup
->SetNotificationCallbacks(callbacks
);
619 chan
->AsyncOpen(listener
, nsnull
);
621 // Even if AsyncOpen failed, we still count this as a successful ping. It's
622 // possible that AsyncOpen may have failed after triggering some background
623 // process that may have written something to the network.
626 // Prevent ping requests from stalling and never being garbage collected...
627 nsCOMPtr
<nsITimer
> timer
=
628 do_CreateInstance(NS_TIMER_CONTRACTID
);
630 nsresult rv
= timer
->InitWithFuncCallback(OnPingTimeout
, loadGroup
,
632 nsITimer::TYPE_ONE_SHOT
);
633 if (NS_SUCCEEDED(rv
)) {
634 // When the timer expires, the callback function will release this
635 // reference to the loadgroup.
636 static_cast<nsILoadGroup
*>(loadGroup
.get())->AddRef();
641 // If we failed to setup the timer, then we should just cancel the channel
642 // because we won't be able to ensure that it goes away in a timely manner.
644 chan
->Cancel(NS_ERROR_ABORT
);
647 // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
649 DispatchPings(nsIContent
*content
, nsIURI
*referrer
)
653 if (!PingsEnabled(&info
.maxPings
, &info
.requireSameHost
))
655 if (info
.maxPings
== 0)
659 info
.referrer
= referrer
;
661 ForEachPing(content
, SendPing
, &info
);
664 static nsISHEntry
* GetRootSHEntry(nsISHEntry
*entry
);
666 //*****************************************************************************
667 //*** nsDocShell: Object Management
668 //*****************************************************************************
670 // Note: operator new zeros our memory
671 nsDocShell::nsDocShell():
673 mDefaultScrollbarPref(Scrollbar_Auto
, Scrollbar_Auto
),
675 mChromeEventHandler(nsnull
),
676 mCharsetReloadState(eCharsetReloadInit
),
678 mBusyFlags(BUSY_FLAGS_NONE
),
679 mAppType(nsIDocShell::APP_TYPE_UNKNOWN
),
682 mItemType(typeContent
),
683 mPreviousTransIndex(-1),
684 mLoadedTransIndex(-1),
685 mAllowSubframes(PR_TRUE
),
686 mAllowPlugins(PR_TRUE
),
687 mAllowJavascript(PR_TRUE
),
688 mAllowMetaRedirects(PR_TRUE
),
689 mAllowImages(PR_TRUE
),
690 mAllowDNSPrefetch(PR_TRUE
),
691 mCreatingDocument(PR_FALSE
),
692 mUseErrorPages(PR_FALSE
),
693 mObserveErrorPages(PR_TRUE
),
695 mAllowKeywordFixup(PR_FALSE
),
696 mIsOffScreenBrowser(PR_FALSE
),
697 mFiredUnloadEvent(PR_FALSE
),
698 mEODForCurrentDocument(PR_FALSE
),
699 mURIResultedInDocument(PR_FALSE
),
700 mIsBeingDestroyed(PR_FALSE
),
701 mIsExecutingOnLoadHandler(PR_FALSE
),
702 mIsPrintingOrPP(PR_FALSE
),
703 mSavingOldViewer(PR_FALSE
)
705 , mInEnsureScriptEnv(PR_FALSE
)
708 if (gDocShellCount
++ == 0) {
709 NS_ASSERTION(sURIFixup
== nsnull
,
710 "Huh, sURIFixup not null in first nsDocShell ctor!");
712 CallGetService(NS_URIFIXUP_CONTRACTID
, &sURIFixup
);
718 gDocShellLog
= PR_NewLogModule("nsDocShell");
720 if (nsnull
== gDocShellLeakLog
)
721 gDocShellLeakLog
= PR_NewLogModule("nsDocShellLeak");
722 if (gDocShellLeakLog
)
723 PR_LOG(gDocShellLeakLog
, PR_LOG_DEBUG
, ("DOCSHELL %p created\n", this));
727 // We're counting the number of |nsDocShells| to help find leaks
728 ++gNumberOfDocShells
;
731 printf("++DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells
);
735 nsDocShell::~nsDocShell()
739 if (--gDocShellCount
== 0) {
740 NS_IF_RELEASE(sURIFixup
);
744 if (gDocShellLeakLog
)
745 PR_LOG(gDocShellLeakLog
, PR_LOG_DEBUG
, ("DOCSHELL %p destroyed\n", this));
749 // We're counting the number of |nsDocShells| to help find leaks
750 --gNumberOfDocShells
;
753 printf("--DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells
);
760 nsresult rv
= nsDocLoader::Init();
761 NS_ENSURE_SUCCESS(rv
, rv
);
763 NS_ASSERTION(mLoadGroup
, "Something went wrong!");
765 mContentListener
= new nsDSURIContentListener(this);
766 NS_ENSURE_TRUE(mContentListener
, NS_ERROR_OUT_OF_MEMORY
);
768 rv
= mContentListener
->Init();
769 NS_ENSURE_SUCCESS(rv
, rv
);
771 if (!mStorages
.Init())
772 return NS_ERROR_OUT_OF_MEMORY
;
774 // We want to hold a strong ref to the loadgroup, so it better hold a weak
775 // ref to us... use an InterfaceRequestorProxy to do this.
776 nsCOMPtr
<InterfaceRequestorProxy
> proxy
=
777 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor
*>
779 NS_ENSURE_TRUE(proxy
, NS_ERROR_OUT_OF_MEMORY
);
780 mLoadGroup
->SetNotificationCallbacks(proxy
);
782 rv
= nsDocLoader::AddDocLoaderAsChildOfRoot(this);
783 NS_ENSURE_SUCCESS(rv
, rv
);
785 // Add as |this| a progress listener to itself. A little weird, but
786 // simpler than reproducing all the listener-notification logic in
787 // overrides of the various methods via which nsDocLoader can be
788 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
789 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT
|
790 nsIWebProgress::NOTIFY_STATE_NETWORK
);
795 nsDocShell::DestroyChildren()
797 nsCOMPtr
<nsIDocShellTreeItem
> shell
;
798 PRInt32 n
= mChildList
.Count();
799 for (PRInt32 i
= 0; i
< n
; i
++) {
800 shell
= do_QueryInterface(ChildAt(i
));
801 NS_ASSERTION(shell
, "docshell has null child");
804 shell
->SetTreeOwner(nsnull
);
808 nsDocLoader::DestroyChildren();
811 //*****************************************************************************
812 // nsDocShell::nsISupports
813 //*****************************************************************************
815 NS_IMPL_ADDREF_INHERITED(nsDocShell
, nsDocLoader
)
816 NS_IMPL_RELEASE_INHERITED(nsDocShell
, nsDocLoader
)
818 NS_INTERFACE_MAP_BEGIN(nsDocShell
)
819 NS_INTERFACE_MAP_ENTRY(nsIDocShell
)
820 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem
)
821 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode
)
822 NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory
)
823 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation
)
824 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
825 NS_INTERFACE_MAP_ENTRY(nsIScrollable
)
826 NS_INTERFACE_MAP_ENTRY(nsITextScroll
)
827 NS_INTERFACE_MAP_ENTRY(nsIDocCharset
)
828 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner
)
829 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI
)
830 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
831 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
832 NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer
)
833 NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell
)
834 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor
)
835 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider
)
836 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
837 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
838 NS_INTERFACE_MAP_ENTRY(nsIWebShellServices
)
839 NS_INTERFACE_MAP_ENTRY(nsILinkHandler
)
840 NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands
)
841 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader
)
843 ///*****************************************************************************
844 // nsDocShell::nsIInterfaceRequestor
845 //*****************************************************************************
846 NS_IMETHODIMP
nsDocShell::GetInterface(const nsIID
& aIID
, void **aSink
)
848 NS_PRECONDITION(aSink
, "null out param");
852 if (aIID
.Equals(NS_GET_IID(nsICommandManager
))) {
853 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE
);
854 *aSink
= mCommandManager
;
856 else if (aIID
.Equals(NS_GET_IID(nsIURIContentListener
))) {
857 *aSink
= mContentListener
;
859 else if (aIID
.Equals(NS_GET_IID(nsIScriptGlobalObject
)) &&
860 NS_SUCCEEDED(EnsureScriptEnvironment())) {
861 *aSink
= mScriptGlobal
;
863 else if ((aIID
.Equals(NS_GET_IID(nsIDOMWindowInternal
)) ||
864 aIID
.Equals(NS_GET_IID(nsPIDOMWindow
)) ||
865 aIID
.Equals(NS_GET_IID(nsIDOMWindow
))) &&
866 NS_SUCCEEDED(EnsureScriptEnvironment())) {
867 return mScriptGlobal
->QueryInterface(aIID
, aSink
);
869 else if (aIID
.Equals(NS_GET_IID(nsIDOMDocument
)) &&
870 NS_SUCCEEDED(EnsureContentViewer())) {
871 mContentViewer
->GetDOMDocument((nsIDOMDocument
**) aSink
);
872 return *aSink
? NS_OK
: NS_NOINTERFACE
;
874 else if (aIID
.Equals(NS_GET_IID(nsIDocument
)) &&
875 NS_SUCCEEDED(EnsureContentViewer())) {
876 nsCOMPtr
<nsIDOMDocument
> domDoc
;
877 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
879 return NS_NOINTERFACE
;
880 return domDoc
->QueryInterface(aIID
, aSink
);
882 else if (aIID
.Equals(NS_GET_IID(nsIApplicationCacheContainer
))) {
885 // Return application cache associated with this docshell, if any
887 nsCOMPtr
<nsIContentViewer
> contentViewer
;
888 GetContentViewer(getter_AddRefs(contentViewer
));
890 return NS_ERROR_NO_INTERFACE
;
892 nsCOMPtr
<nsIDOMDocument
> domDoc
;
893 contentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
894 NS_ASSERTION(domDoc
, "Should have a document.");
896 return NS_ERROR_NO_INTERFACE
;
898 #if defined(PR_LOGGING) && defined(DEBUG)
899 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
900 ("nsDocShell[%p]: returning app cache container %p",
901 this, domDoc
.get()));
903 return domDoc
->QueryInterface(aIID
, aSink
);
905 else if (aIID
.Equals(NS_GET_IID(nsIPrompt
)) &&
906 NS_SUCCEEDED(EnsureScriptEnvironment())) {
908 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
909 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
910 NS_ENSURE_SUCCESS(rv
, rv
);
912 nsCOMPtr
<nsIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
914 // Get the an auth prompter for our window so that the parenting
915 // of the dialogs works as it should when using tabs.
918 rv
= wwatch
->GetNewPrompter(window
, &prompt
);
919 NS_ENSURE_SUCCESS(rv
, rv
);
924 else if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
)) ||
925 aIID
.Equals(NS_GET_IID(nsIAuthPrompt2
))) {
927 GetAuthPrompt(PROMPT_NORMAL
, aIID
, aSink
)) ?
928 NS_OK
: NS_NOINTERFACE
;
930 else if (aIID
.Equals(NS_GET_IID(nsISHistory
))) {
931 nsCOMPtr
<nsISHistory
> shistory
;
934 GetSessionHistory(getter_AddRefs(shistory
));
935 if (NS_SUCCEEDED(rv
) && shistory
) {
937 NS_ADDREF((nsISupports
*) * aSink
);
940 return NS_NOINTERFACE
;
942 else if (aIID
.Equals(NS_GET_IID(nsIWebBrowserFind
))) {
943 nsresult rv
= EnsureFind();
944 if (NS_FAILED(rv
)) return rv
;
947 NS_ADDREF((nsISupports
*)*aSink
);
950 else if (aIID
.Equals(NS_GET_IID(nsIEditingSession
)) && NS_SUCCEEDED(EnsureEditorData())) {
951 nsCOMPtr
<nsIEditingSession
> editingSession
;
952 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
955 *aSink
= editingSession
;
956 NS_ADDREF((nsISupports
*)*aSink
);
960 return NS_NOINTERFACE
;
962 else if (aIID
.Equals(NS_GET_IID(nsIClipboardDragDropHookList
))
963 && NS_SUCCEEDED(EnsureTransferableHookData())) {
964 *aSink
= mTransferableHookData
;
965 NS_ADDREF((nsISupports
*)*aSink
);
968 else if (aIID
.Equals(NS_GET_IID(nsISelectionDisplay
))) {
969 nsCOMPtr
<nsIPresShell
> shell
;
970 nsresult rv
= GetPresShell(getter_AddRefs(shell
));
971 if (NS_SUCCEEDED(rv
) && shell
)
972 return shell
->QueryInterface(aIID
,aSink
);
974 else if (aIID
.Equals(NS_GET_IID(nsIDocShellTreeOwner
))) {
975 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
976 nsresult rv
= GetTreeOwner(getter_AddRefs(treeOwner
));
977 if (NS_SUCCEEDED(rv
) && treeOwner
)
978 return treeOwner
->QueryInterface(aIID
, aSink
);
981 return nsDocLoader::GetInterface(aIID
, aSink
);
984 NS_IF_ADDREF(((nsISupports
*) * aSink
));
985 return *aSink
? NS_OK
: NS_NOINTERFACE
;
990 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType
)
992 PRUint32 loadType
= LOAD_NORMAL
;
994 switch (aDocShellLoadType
) {
995 case nsIDocShellLoadInfo::loadNormal
:
996 loadType
= LOAD_NORMAL
;
998 case nsIDocShellLoadInfo::loadNormalReplace
:
999 loadType
= LOAD_NORMAL_REPLACE
;
1001 case nsIDocShellLoadInfo::loadNormalExternal
:
1002 loadType
= LOAD_NORMAL_EXTERNAL
;
1004 case nsIDocShellLoadInfo::loadHistory
:
1005 loadType
= LOAD_HISTORY
;
1007 case nsIDocShellLoadInfo::loadNormalBypassCache
:
1008 loadType
= LOAD_NORMAL_BYPASS_CACHE
;
1010 case nsIDocShellLoadInfo::loadNormalBypassProxy
:
1011 loadType
= LOAD_NORMAL_BYPASS_PROXY
;
1013 case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache
:
1014 loadType
= LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
;
1016 case nsIDocShellLoadInfo::loadReloadNormal
:
1017 loadType
= LOAD_RELOAD_NORMAL
;
1019 case nsIDocShellLoadInfo::loadReloadCharsetChange
:
1020 loadType
= LOAD_RELOAD_CHARSET_CHANGE
;
1022 case nsIDocShellLoadInfo::loadReloadBypassCache
:
1023 loadType
= LOAD_RELOAD_BYPASS_CACHE
;
1025 case nsIDocShellLoadInfo::loadReloadBypassProxy
:
1026 loadType
= LOAD_RELOAD_BYPASS_PROXY
;
1028 case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
:
1029 loadType
= LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
;
1031 case nsIDocShellLoadInfo::loadLink
:
1032 loadType
= LOAD_LINK
;
1034 case nsIDocShellLoadInfo::loadRefresh
:
1035 loadType
= LOAD_REFRESH
;
1037 case nsIDocShellLoadInfo::loadBypassHistory
:
1038 loadType
= LOAD_BYPASS_HISTORY
;
1040 case nsIDocShellLoadInfo::loadStopContent
:
1041 loadType
= LOAD_STOP_CONTENT
;
1043 case nsIDocShellLoadInfo::loadStopContentAndReplace
:
1044 loadType
= LOAD_STOP_CONTENT_AND_REPLACE
;
1046 case nsIDocShellLoadInfo::loadPushState
:
1047 loadType
= LOAD_PUSHSTATE
;
1050 NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
1057 nsDocShellInfoLoadType
1058 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType
)
1060 nsDocShellInfoLoadType docShellLoadType
= nsIDocShellLoadInfo::loadNormal
;
1061 switch (aLoadType
) {
1063 docShellLoadType
= nsIDocShellLoadInfo::loadNormal
;
1065 case LOAD_NORMAL_REPLACE
:
1066 docShellLoadType
= nsIDocShellLoadInfo::loadNormalReplace
;
1068 case LOAD_NORMAL_EXTERNAL
:
1069 docShellLoadType
= nsIDocShellLoadInfo::loadNormalExternal
;
1071 case LOAD_NORMAL_BYPASS_CACHE
:
1072 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassCache
;
1074 case LOAD_NORMAL_BYPASS_PROXY
:
1075 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassProxy
;
1077 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
1078 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassProxyAndCache
;
1081 docShellLoadType
= nsIDocShellLoadInfo::loadHistory
;
1083 case LOAD_RELOAD_NORMAL
:
1084 docShellLoadType
= nsIDocShellLoadInfo::loadReloadNormal
;
1086 case LOAD_RELOAD_CHARSET_CHANGE
:
1087 docShellLoadType
= nsIDocShellLoadInfo::loadReloadCharsetChange
;
1089 case LOAD_RELOAD_BYPASS_CACHE
:
1090 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassCache
;
1092 case LOAD_RELOAD_BYPASS_PROXY
:
1093 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassProxy
;
1095 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
1096 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
;
1099 docShellLoadType
= nsIDocShellLoadInfo::loadLink
;
1102 docShellLoadType
= nsIDocShellLoadInfo::loadRefresh
;
1104 case LOAD_BYPASS_HISTORY
:
1105 case LOAD_ERROR_PAGE
:
1106 docShellLoadType
= nsIDocShellLoadInfo::loadBypassHistory
;
1108 case LOAD_STOP_CONTENT
:
1109 docShellLoadType
= nsIDocShellLoadInfo::loadStopContent
;
1111 case LOAD_STOP_CONTENT_AND_REPLACE
:
1112 docShellLoadType
= nsIDocShellLoadInfo::loadStopContentAndReplace
;
1114 case LOAD_PUSHSTATE
:
1115 docShellLoadType
= nsIDocShellLoadInfo::loadPushState
;
1118 NS_NOTREACHED("Unexpected load type value");
1121 return docShellLoadType
;
1124 //*****************************************************************************
1125 // nsDocShell::nsIDocShell
1126 //*****************************************************************************
1128 nsDocShell::LoadURI(nsIURI
* aURI
,
1129 nsIDocShellLoadInfo
* aLoadInfo
,
1130 PRUint32 aLoadFlags
,
1133 NS_PRECONDITION(aLoadInfo
|| (aLoadFlags
& EXTRA_LOAD_FLAGS
) == 0,
1134 "Unexpected flags");
1135 NS_PRECONDITION((aLoadFlags
& 0xf) == 0, "Should not have these flags set");
1137 // Note: we allow loads to get through here even if mFiredUnloadEvent is
1138 // true; that case will get handled in LoadInternal or LoadHistoryEntry.
1139 if (IsPrintingOrPP()) {
1140 return NS_OK
; // JS may not handle returning of an error code
1143 nsCOMPtr
<nsIURI
> referrer
;
1144 nsCOMPtr
<nsIInputStream
> postStream
;
1145 nsCOMPtr
<nsIInputStream
> headersStream
;
1146 nsCOMPtr
<nsISupports
> owner
;
1147 PRBool inheritOwner
= PR_FALSE
;
1148 PRBool ownerIsExplicit
= PR_FALSE
;
1149 PRBool sendReferrer
= PR_TRUE
;
1150 nsCOMPtr
<nsISHEntry
> shEntry
;
1151 nsXPIDLString target
;
1152 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
1154 NS_ENSURE_ARG(aURI
);
1156 // Extract the info from the DocShellLoadInfo struct...
1158 aLoadInfo
->GetReferrer(getter_AddRefs(referrer
));
1160 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
1161 aLoadInfo
->GetLoadType(<
);
1162 // Get the appropriate loadType from nsIDocShellLoadInfo type
1163 loadType
= ConvertDocShellLoadInfoToLoadType(lt
);
1165 aLoadInfo
->GetOwner(getter_AddRefs(owner
));
1166 aLoadInfo
->GetInheritOwner(&inheritOwner
);
1167 aLoadInfo
->GetOwnerIsExplicit(&ownerIsExplicit
);
1168 aLoadInfo
->GetSHEntry(getter_AddRefs(shEntry
));
1169 aLoadInfo
->GetTarget(getter_Copies(target
));
1170 aLoadInfo
->GetPostDataStream(getter_AddRefs(postStream
));
1171 aLoadInfo
->GetHeadersStream(getter_AddRefs(headersStream
));
1172 aLoadInfo
->GetSendReferrer(&sendReferrer
);
1175 #if defined(PR_LOGGING) && defined(DEBUG)
1176 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
1177 nsCAutoString uristr
;
1178 aURI
->GetAsciiSpec(uristr
);
1179 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
1180 ("nsDocShell[%p]: loading %s with flags 0x%08x",
1181 this, uristr
.get(), aLoadFlags
));
1186 !LOAD_TYPE_HAS_FLAGS(loadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
1187 // First verify if this is a subframe.
1188 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
1189 GetSameTypeParent(getter_AddRefs(parentAsItem
));
1190 nsCOMPtr
<nsIDocShell
> parentDS(do_QueryInterface(parentAsItem
));
1191 PRUint32 parentLoadType
;
1193 if (parentDS
&& parentDS
!= static_cast<nsIDocShell
*>(this)) {
1194 /* OK. It is a subframe. Checkout the
1195 * parent's loadtype. If the parent was loaded thro' a history
1196 * mechanism, then get the SH entry for the child from the parent.
1197 * This is done to restore frameset navigation while going back/forward.
1198 * If the parent was loaded through any other loadType, set the
1199 * child's loadType too accordingly, so that session history does not
1203 // Get the parent's load type
1204 parentDS
->GetLoadType(&parentLoadType
);
1206 nsCOMPtr
<nsIDocShellHistory
> parent(do_QueryInterface(parentAsItem
));
1208 // Get the ShEntry for the child from the parent
1209 parent
->GetChildSHEntry(mChildOffset
, getter_AddRefs(shEntry
));
1210 // Make some decisions on the child frame's loadType based on the
1211 // parent's loadType.
1212 if (mCurrentURI
== nsnull
) {
1213 // This is a newly created frame. Check for exception cases first.
1214 // By default the subframe will inherit the parent's loadType.
1215 if (shEntry
&& (parentLoadType
== LOAD_NORMAL
||
1216 parentLoadType
== LOAD_LINK
||
1217 parentLoadType
== LOAD_NORMAL_EXTERNAL
)) {
1218 // The parent was loaded normally. In this case, this *brand new* child really shouldn't
1219 // have a SHEntry. If it does, it could be because the parent is replacing an
1220 // existing frame with a new frame, in the onLoadHandler. We don't want this
1221 // url to get into session history. Clear off shEntry, and set load type to
1222 // LOAD_BYPASS_HISTORY.
1223 PRBool inOnLoadHandler
=PR_FALSE
;
1224 parentDS
->GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
1225 if (inOnLoadHandler
) {
1226 loadType
= LOAD_NORMAL_REPLACE
;
1230 else if (parentLoadType
== LOAD_REFRESH
) {
1231 // Clear shEntry. For refresh loads, we have to load
1232 // what comes thro' the pipe, not what's in history.
1235 else if ((parentLoadType
== LOAD_BYPASS_HISTORY
) ||
1236 (parentLoadType
== LOAD_ERROR_PAGE
) ||
1238 ((parentLoadType
& LOAD_CMD_HISTORY
) ||
1239 (parentLoadType
== LOAD_RELOAD_NORMAL
) ||
1240 (parentLoadType
== LOAD_RELOAD_CHARSET_CHANGE
)))) {
1241 // If the parent url, bypassed history or was loaded from
1242 // history, pass on the parent's loadType to the new child
1243 // frame too, so that the child frame will also
1244 // avoid getting into history.
1245 loadType
= parentLoadType
;
1249 // This is a pre-existing subframe. If the load was not originally initiated
1250 // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
1251 // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading
1252 // a new page in this child. Check parent's and self's busy flag and if it is set,
1253 // we don't want this onLoadHandler load to get in to session history.
1254 PRUint32 parentBusy
= BUSY_FLAGS_NONE
;
1255 PRUint32 selfBusy
= BUSY_FLAGS_NONE
;
1256 parentDS
->GetBusyFlags(&parentBusy
);
1257 GetBusyFlags(&selfBusy
);
1258 if (((parentBusy
& BUSY_FLAGS_BUSY
) ||
1259 (selfBusy
& BUSY_FLAGS_BUSY
)) &&
1261 loadType
= LOAD_NORMAL_REPLACE
;
1268 // This is the root docshell. If we got here while
1269 // executing an onLoad Handler,this load will not go
1270 // into session history.
1271 PRBool inOnLoadHandler
=PR_FALSE
;
1272 GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
1273 if (inOnLoadHandler
) {
1274 loadType
= LOAD_NORMAL_REPLACE
;
1281 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
1282 ("nsDocShell[%p]: loading from session history", this));
1285 return LoadHistoryEntry(shEntry
, loadType
);
1288 // Perform the load...
1290 // We need an owner (a referring principal).
1292 // If ownerIsExplicit is not set there are 4 possibilities:
1293 // (1) If the system principal was passed in and we're a typeContent
1294 // docshell, inherit the principal from the current document
1296 // (2) In all other cases when the principal passed in is not null,
1297 // use that principal.
1298 // (3) If the caller has allowed inheriting from the current document,
1299 // or if we're being called from system code (eg chrome JS or pure
1300 // C++) then inheritOwner should be true and InternalLoad will get
1301 // an owner from the current document. If none of these things are
1303 // (4) we pass a null owner into the channel, and an owner will be
1304 // created later from the channel's internal data.
1306 // If ownerIsExplicit *is* set, there are 4 possibilities
1307 // (1) If the system principal was passed in and we're a typeContent
1308 // docshell, return an error.
1309 // (2) In all other cases when the principal passed in is not null,
1310 // use that principal.
1311 // (3) If the caller has allowed inheriting from the current document,
1312 // then inheritOwner should be true and InternalLoad will get an owner
1313 // from the current document. If none of these things are true, then
1314 // (4) we pass a null owner into the channel, and an owner will be
1315 // created later from the channel's internal data.
1317 // NOTE: This all only works because the only thing the owner is used
1318 // for in InternalLoad is data:, javascript:, and about:blank
1319 // URIs. For other URIs this would all be dead wrong!
1321 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
1322 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
1323 NS_ENSURE_SUCCESS(rv
, rv
);
1325 if (owner
&& mItemType
!= typeChrome
) {
1326 nsCOMPtr
<nsIPrincipal
> ownerPrincipal
= do_QueryInterface(owner
);
1328 rv
= secMan
->IsSystemPrincipal(ownerPrincipal
, &isSystem
);
1329 NS_ENSURE_SUCCESS(rv
, rv
);
1332 if (ownerIsExplicit
) {
1333 return NS_ERROR_DOM_SECURITY_ERR
;
1336 inheritOwner
= PR_TRUE
;
1339 if (!owner
&& !inheritOwner
&& !ownerIsExplicit
) {
1340 // See if there's system or chrome JS code running
1341 rv
= secMan
->SubjectPrincipalIsSystem(&inheritOwner
);
1342 if (NS_FAILED(rv
)) {
1343 // Set it back to false
1344 inheritOwner
= PR_FALSE
;
1351 flags
|= INTERNAL_LOAD_FLAGS_INHERIT_OWNER
;
1354 flags
|= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
;
1356 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
)
1357 flags
|= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
1359 if (aLoadFlags
& LOAD_FLAGS_FIRST_LOAD
)
1360 flags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
1362 if (aLoadFlags
& LOAD_FLAGS_BYPASS_CLASSIFIER
)
1363 flags
|= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
;
1365 if (aLoadFlags
& LOAD_FLAGS_FORCE_ALLOW_COOKIES
)
1366 flags
|= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES
;
1368 return InternalLoad(aURI
,
1373 nsnull
, // No type hint
1377 nsnull
, // No SHEntry
1379 nsnull
, // No nsIDocShell
1380 nsnull
); // No nsIRequest
1384 nsDocShell::LoadStream(nsIInputStream
*aStream
, nsIURI
* aURI
,
1385 const nsACString
&aContentType
,
1386 const nsACString
&aContentCharset
,
1387 nsIDocShellLoadInfo
* aLoadInfo
)
1389 NS_ENSURE_ARG(aStream
);
1391 mAllowKeywordFixup
= PR_FALSE
;
1393 // if the caller doesn't pass in a URI we need to create a dummy URI. necko
1394 // currently requires a URI in various places during the load. Some consumers
1396 nsCOMPtr
<nsIURI
> uri
= aURI
;
1399 nsresult rv
= NS_OK
;
1400 uri
= do_CreateInstance(NS_SIMPLEURI_CONTRACTID
, &rv
);
1403 // Make sure that the URI spec "looks" like a protocol and path...
1404 // For now, just use a bogus protocol called "internal"
1405 rv
= uri
->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
1410 PRUint32 loadType
= LOAD_NORMAL
;
1412 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
1413 (void) aLoadInfo
->GetLoadType(<
);
1414 // Get the appropriate LoadType from nsIDocShellLoadInfo type
1415 loadType
= ConvertDocShellLoadInfoToLoadType(lt
);
1418 NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK
), NS_ERROR_FAILURE
);
1420 mLoadType
= loadType
;
1422 // build up a channel for this stream.
1423 nsCOMPtr
<nsIChannel
> channel
;
1424 NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
1425 (getter_AddRefs(channel
), uri
, aStream
,
1426 aContentType
, aContentCharset
),
1429 nsCOMPtr
<nsIURILoader
>
1430 uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID
));
1431 NS_ENSURE_TRUE(uriLoader
, NS_ERROR_FAILURE
);
1433 NS_ENSURE_SUCCESS(DoChannelLoad(channel
, uriLoader
, PR_FALSE
),
1439 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo
** aLoadInfo
)
1441 nsDocShellLoadInfo
*loadInfo
= new nsDocShellLoadInfo();
1442 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
1443 nsCOMPtr
<nsIDocShellLoadInfo
> localRef(loadInfo
);
1445 *aLoadInfo
= localRef
;
1446 NS_ADDREF(*aLoadInfo
);
1452 * Reset state to a new content model within the current document and the document
1453 * viewer. Called by the document before initiating an out of band document.write().
1456 nsDocShell::PrepareForNewContentModel()
1458 mEODForCurrentDocument
= PR_FALSE
;
1464 nsDocShell::FirePageHideNotification(PRBool aIsUnload
)
1466 if (mContentViewer
&& !mFiredUnloadEvent
) {
1467 // Keep an explicit reference since calling PageHide could release
1469 nsCOMPtr
<nsIContentViewer
> kungFuDeathGrip(mContentViewer
);
1470 mFiredUnloadEvent
= PR_TRUE
;
1472 mContentViewer
->PageHide(aIsUnload
);
1474 nsAutoTArray
<nsCOMPtr
<nsIDocShell
>, 8> kids
;
1475 PRInt32 i
, n
= mChildList
.Count();
1476 kids
.SetCapacity(n
);
1477 for (i
= 0; i
< n
; i
++) {
1478 kids
.AppendElement(do_QueryInterface(ChildAt(i
)));
1482 for (i
= 0; i
< n
; ++i
) {
1484 kids
[i
]->FirePageHideNotification(aIsUnload
);
1487 // Now make sure our editor, if any, is detached before we go
1489 DetachEditorFromWindow();
1496 // Bug 13871: Prevent frameset spoofing
1498 // This routine answers: 'Is origin's document from same domain as
1499 // target's document?'
1501 // file: uris are considered the same domain for the purpose of
1502 // frame navigation regardless of script accessibility (bug 420425)
1506 nsDocShell::ValidateOrigin(nsIDocShellTreeItem
* aOriginTreeItem
,
1507 nsIDocShellTreeItem
* aTargetTreeItem
)
1509 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
1510 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
1511 NS_ENSURE_TRUE(securityManager
, PR_FALSE
);
1513 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
;
1515 securityManager
->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal
));
1516 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
1518 if (subjectPrincipal
) {
1519 // We're called from JS, check if UniversalBrowserWrite is
1521 PRBool ubwEnabled
= PR_FALSE
;
1522 rv
= securityManager
->IsCapabilityEnabled("UniversalBrowserWrite",
1524 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
1531 // Get origin document principal
1532 nsCOMPtr
<nsIDOMDocument
> originDOMDocument
=
1533 do_GetInterface(aOriginTreeItem
);
1534 nsCOMPtr
<nsIDocument
> originDocument(do_QueryInterface(originDOMDocument
));
1535 NS_ENSURE_TRUE(originDocument
, PR_FALSE
);
1537 // Get target principal
1538 nsCOMPtr
<nsIDOMDocument
> targetDOMDocument
=
1539 do_GetInterface(aTargetTreeItem
);
1540 nsCOMPtr
<nsIDocument
> targetDocument(do_QueryInterface(targetDOMDocument
));
1541 NS_ENSURE_TRUE(targetDocument
, PR_FALSE
);
1544 rv
= originDocument
->NodePrincipal()->
1545 Equals(targetDocument
->NodePrincipal(), &equal
);
1546 if (NS_SUCCEEDED(rv
) && equal
) {
1550 // Not strictly equal, special case if both are file: uris
1551 PRBool originIsFile
= PR_FALSE
;
1552 PRBool targetIsFile
= PR_FALSE
;
1553 nsCOMPtr
<nsIURI
> originURI
;
1554 nsCOMPtr
<nsIURI
> targetURI
;
1555 nsCOMPtr
<nsIURI
> innerOriginURI
;
1556 nsCOMPtr
<nsIURI
> innerTargetURI
;
1558 rv
= originDocument
->NodePrincipal()->GetURI(getter_AddRefs(originURI
));
1559 if (NS_SUCCEEDED(rv
) && originURI
)
1560 innerOriginURI
= NS_GetInnermostURI(originURI
);
1562 rv
= targetDocument
->NodePrincipal()->GetURI(getter_AddRefs(targetURI
));
1563 if (NS_SUCCEEDED(rv
) && targetURI
)
1564 innerTargetURI
= NS_GetInnermostURI(targetURI
);
1566 return innerOriginURI
&& innerTargetURI
&&
1567 NS_SUCCEEDED(innerOriginURI
->SchemeIs("file", &originIsFile
)) &&
1568 NS_SUCCEEDED(innerTargetURI
->SchemeIs("file", &targetIsFile
)) &&
1569 originIsFile
&& targetIsFile
;
1573 nsDocShell::GetEldestPresContext(nsPresContext
** aPresContext
)
1575 nsresult rv
= NS_OK
;
1577 NS_ENSURE_ARG_POINTER(aPresContext
);
1578 *aPresContext
= nsnull
;
1580 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
1582 nsCOMPtr
<nsIContentViewer
> prevViewer
;
1583 viewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
1585 viewer
= prevViewer
;
1587 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(viewer
));
1589 rv
= docv
->GetPresContext(aPresContext
);
1598 nsDocShell::GetPresContext(nsPresContext
** aPresContext
)
1600 NS_ENSURE_ARG_POINTER(aPresContext
);
1601 *aPresContext
= nsnull
;
1603 if (!mContentViewer
)
1606 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(mContentViewer
));
1607 NS_ENSURE_TRUE(docv
, NS_ERROR_NO_INTERFACE
);
1609 return docv
->GetPresContext(aPresContext
);
1613 nsDocShell::GetPresShell(nsIPresShell
** aPresShell
)
1615 nsresult rv
= NS_OK
;
1617 NS_ENSURE_ARG_POINTER(aPresShell
);
1618 *aPresShell
= nsnull
;
1620 nsRefPtr
<nsPresContext
> presContext
;
1621 (void) GetPresContext(getter_AddRefs(presContext
));
1624 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1631 nsDocShell::GetEldestPresShell(nsIPresShell
** aPresShell
)
1633 nsresult rv
= NS_OK
;
1635 NS_ENSURE_ARG_POINTER(aPresShell
);
1636 *aPresShell
= nsnull
;
1638 nsRefPtr
<nsPresContext
> presContext
;
1639 (void) GetEldestPresContext(getter_AddRefs(presContext
));
1642 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1649 nsDocShell::GetContentViewer(nsIContentViewer
** aContentViewer
)
1651 NS_ENSURE_ARG_POINTER(aContentViewer
);
1653 *aContentViewer
= mContentViewer
;
1654 NS_IF_ADDREF(*aContentViewer
);
1659 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget
* aChromeEventHandler
)
1661 nsCOMPtr
<nsPIDOMEventTarget
> piTarget
=
1662 do_QueryInterface(aChromeEventHandler
);
1663 // Weak reference. Don't addref.
1664 mChromeEventHandler
= piTarget
;
1666 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
1668 win
->SetChromeEventHandler(piTarget
);
1675 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget
** aChromeEventHandler
)
1677 NS_ENSURE_ARG_POINTER(aChromeEventHandler
);
1678 nsCOMPtr
<nsIDOMEventTarget
> target
= do_QueryInterface(mChromeEventHandler
);
1679 target
.swap(*aChromeEventHandler
);
1683 /* [noscript] void setCurrentURI (in nsIURI uri); */
1685 nsDocShell::SetCurrentURI(nsIURI
*aURI
)
1687 SetCurrentURI(aURI
, nsnull
, PR_TRUE
);
1692 nsDocShell::SetCurrentURI(nsIURI
*aURI
, nsIRequest
*aRequest
,
1693 PRBool aFireOnLocationChange
)
1696 if (gDocShellLeakLog
&& PR_LOG_TEST(gDocShellLeakLog
, PR_LOG_DEBUG
)) {
1699 aURI
->GetSpec(spec
);
1700 PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec
.get());
1704 // We don't want to send a location change when we're displaying an error
1705 // page, and we don't want to change our idea of "current URI" either
1706 if (mLoadType
== LOAD_ERROR_PAGE
) {
1710 mCurrentURI
= NS_TryToMakeImmutable(aURI
);
1712 PRBool isRoot
= PR_FALSE
; // Is this the root docshell
1713 PRBool isSubFrame
= PR_FALSE
; // Is this a subframe navigation?
1715 nsCOMPtr
<nsIDocShellTreeItem
> root
;
1717 GetSameTypeRootTreeItem(getter_AddRefs(root
));
1718 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this))
1720 // This is the root docshell
1724 mLSHE
->GetIsSubFrame(&isSubFrame
);
1727 if (!isSubFrame
&& !isRoot
) {
1729 * We don't want to send OnLocationChange notifications when
1730 * a subframe is being loaded for the first time, while
1731 * visiting a frameset page
1736 if (aFireOnLocationChange
) {
1737 FireOnLocationChange(this, aRequest
, aURI
);
1739 return !aFireOnLocationChange
;
1743 nsDocShell::GetCharset(char** aCharset
)
1745 NS_ENSURE_ARG_POINTER(aCharset
);
1748 nsCOMPtr
<nsIPresShell
> presShell
;
1749 GetPresShell(getter_AddRefs(presShell
));
1750 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
1751 nsIDocument
*doc
= presShell
->GetDocument();
1752 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
1753 *aCharset
= ToNewCString(doc
->GetDocumentCharacterSet());
1755 return NS_ERROR_OUT_OF_MEMORY
;
1762 nsDocShell::SetCharset(const char* aCharset
)
1764 // set the default charset
1765 nsCOMPtr
<nsIContentViewer
> viewer
;
1766 GetContentViewer(getter_AddRefs(viewer
));
1768 nsCOMPtr
<nsIMarkupDocumentViewer
> muDV(do_QueryInterface(viewer
));
1770 nsCString
charset(aCharset
);
1771 NS_ENSURE_SUCCESS(muDV
->SetDefaultCharacterSet(charset
),
1776 // set the charset override
1777 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
;
1778 GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
1780 nsCOMPtr
<nsIAtom
> csAtom
;
1781 csAtom
= do_GetAtom(aCharset
);
1782 dcInfo
->SetForcedCharset(csAtom
);
1789 nsDocShell::GetDocumentCharsetInfo(nsIDocumentCharsetInfo
**
1790 aDocumentCharsetInfo
)
1792 NS_ENSURE_ARG_POINTER(aDocumentCharsetInfo
);
1794 // if the mDocumentCharsetInfo does not exist already, we create it now
1795 if (!mDocumentCharsetInfo
) {
1796 mDocumentCharsetInfo
= do_CreateInstance(NS_DOCUMENTCHARSETINFO_CONTRACTID
);
1797 if (!mDocumentCharsetInfo
)
1798 return NS_ERROR_FAILURE
;
1801 *aDocumentCharsetInfo
= mDocumentCharsetInfo
;
1802 NS_IF_ADDREF(*aDocumentCharsetInfo
);
1807 nsDocShell::SetDocumentCharsetInfo(nsIDocumentCharsetInfo
*
1808 aDocumentCharsetInfo
)
1810 mDocumentCharsetInfo
= aDocumentCharsetInfo
;
1815 nsDocShell::GetChannelIsUnsafe(PRBool
*aUnsafe
)
1817 *aUnsafe
= PR_FALSE
;
1819 nsIChannel
* channel
= GetCurrentDocChannel();
1824 nsCOMPtr
<nsIJARChannel
> jarChannel
= do_QueryInterface(channel
);
1829 return jarChannel
->GetIsUnsafe(aUnsafe
);
1833 nsDocShell::GetAllowPlugins(PRBool
* aAllowPlugins
)
1835 NS_ENSURE_ARG_POINTER(aAllowPlugins
);
1837 *aAllowPlugins
= mAllowPlugins
;
1838 if (!mAllowPlugins
) {
1843 *aAllowPlugins
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1848 nsDocShell::SetAllowPlugins(PRBool aAllowPlugins
)
1850 mAllowPlugins
= aAllowPlugins
;
1851 //XXX should enable or disable a plugin host
1856 nsDocShell::GetAllowJavascript(PRBool
* aAllowJavascript
)
1858 NS_ENSURE_ARG_POINTER(aAllowJavascript
);
1860 *aAllowJavascript
= mAllowJavascript
;
1861 if (!mAllowJavascript
) {
1866 *aAllowJavascript
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1871 nsDocShell::SetAllowJavascript(PRBool aAllowJavascript
)
1873 mAllowJavascript
= aAllowJavascript
;
1877 NS_IMETHODIMP
nsDocShell::GetAllowMetaRedirects(PRBool
* aReturn
)
1879 NS_ENSURE_ARG_POINTER(aReturn
);
1881 *aReturn
= mAllowMetaRedirects
;
1882 if (!mAllowMetaRedirects
) {
1887 *aReturn
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1891 NS_IMETHODIMP
nsDocShell::SetAllowMetaRedirects(PRBool aValue
)
1893 mAllowMetaRedirects
= aValue
;
1897 NS_IMETHODIMP
nsDocShell::GetAllowSubframes(PRBool
* aAllowSubframes
)
1899 NS_ENSURE_ARG_POINTER(aAllowSubframes
);
1901 *aAllowSubframes
= mAllowSubframes
;
1905 NS_IMETHODIMP
nsDocShell::SetAllowSubframes(PRBool aAllowSubframes
)
1907 mAllowSubframes
= aAllowSubframes
;
1911 NS_IMETHODIMP
nsDocShell::GetAllowImages(PRBool
* aAllowImages
)
1913 NS_ENSURE_ARG_POINTER(aAllowImages
);
1915 *aAllowImages
= mAllowImages
;
1919 NS_IMETHODIMP
nsDocShell::SetAllowImages(PRBool aAllowImages
)
1921 mAllowImages
= aAllowImages
;
1925 NS_IMETHODIMP
nsDocShell::GetAllowDNSPrefetch(PRBool
* aAllowDNSPrefetch
)
1927 *aAllowDNSPrefetch
= mAllowDNSPrefetch
;
1931 NS_IMETHODIMP
nsDocShell::SetAllowDNSPrefetch(PRBool aAllowDNSPrefetch
)
1933 mAllowDNSPrefetch
= aAllowDNSPrefetch
;
1938 nsDocShell::GetDocShellEnumerator(PRInt32 aItemType
, PRInt32 aDirection
, nsISimpleEnumerator
**outEnum
)
1940 NS_ENSURE_ARG_POINTER(outEnum
);
1943 nsRefPtr
<nsDocShellEnumerator
> docShellEnum
;
1944 if (aDirection
== ENUMERATE_FORWARDS
)
1945 docShellEnum
= new nsDocShellForwardsEnumerator
;
1947 docShellEnum
= new nsDocShellBackwardsEnumerator
;
1949 if (!docShellEnum
) return NS_ERROR_OUT_OF_MEMORY
;
1951 nsresult rv
= docShellEnum
->SetEnumDocShellType(aItemType
);
1952 if (NS_FAILED(rv
)) return rv
;
1954 rv
= docShellEnum
->SetEnumerationRootItem((nsIDocShellTreeItem
*)this);
1955 if (NS_FAILED(rv
)) return rv
;
1957 rv
= docShellEnum
->First();
1958 if (NS_FAILED(rv
)) return rv
;
1960 rv
= docShellEnum
->QueryInterface(NS_GET_IID(nsISimpleEnumerator
), (void **)outEnum
);
1966 nsDocShell::GetAppType(PRUint32
* aAppType
)
1968 *aAppType
= mAppType
;
1973 nsDocShell::SetAppType(PRUint32 aAppType
)
1975 mAppType
= aAppType
;
1981 nsDocShell::GetAllowAuth(PRBool
* aAllowAuth
)
1983 *aAllowAuth
= mAllowAuth
;
1988 nsDocShell::SetAllowAuth(PRBool aAllowAuth
)
1990 mAllowAuth
= aAllowAuth
;
1995 nsDocShell::GetZoom(float *zoom
)
1997 NS_ENSURE_ARG_POINTER(zoom
);
2003 nsDocShell::SetZoom(float zoom
)
2005 return NS_ERROR_NOT_IMPLEMENTED
;
2009 nsDocShell::GetMarginWidth(PRInt32
* aWidth
)
2011 NS_ENSURE_ARG_POINTER(aWidth
);
2013 *aWidth
= mMarginWidth
;
2018 nsDocShell::SetMarginWidth(PRInt32 aWidth
)
2020 mMarginWidth
= aWidth
;
2025 nsDocShell::GetMarginHeight(PRInt32
* aHeight
)
2027 NS_ENSURE_ARG_POINTER(aHeight
);
2029 *aHeight
= mMarginHeight
;
2034 nsDocShell::SetMarginHeight(PRInt32 aHeight
)
2036 mMarginHeight
= aHeight
;
2041 nsDocShell::GetBusyFlags(PRUint32
* aBusyFlags
)
2043 NS_ENSURE_ARG_POINTER(aBusyFlags
);
2045 *aBusyFlags
= mBusyFlags
;
2050 nsDocShell::TabToTreeOwner(PRBool aForward
, PRBool
* aTookFocus
)
2052 NS_ENSURE_ARG_POINTER(aTookFocus
);
2054 nsCOMPtr
<nsIWebBrowserChromeFocus
> chromeFocus
= do_GetInterface(mTreeOwner
);
2057 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusNextElement());
2059 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusPrevElement());
2061 *aTookFocus
= PR_FALSE
;
2067 nsDocShell::GetSecurityUI(nsISecureBrowserUI
**aSecurityUI
)
2069 NS_IF_ADDREF(*aSecurityUI
= mSecurityUI
);
2074 nsDocShell::SetSecurityUI(nsISecureBrowserUI
*aSecurityUI
)
2076 mSecurityUI
= aSecurityUI
;
2081 nsDocShell::GetUseErrorPages(PRBool
*aUseErrorPages
)
2083 *aUseErrorPages
= mUseErrorPages
;
2088 nsDocShell::SetUseErrorPages(PRBool aUseErrorPages
)
2090 // If mUseErrorPages is set explicitly, stop observing the pref.
2091 if (mObserveErrorPages
) {
2092 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
));
2094 prefs
->RemoveObserver("browser.xul.error_pages.enabled", this);
2095 mObserveErrorPages
= PR_FALSE
;
2098 mUseErrorPages
= aUseErrorPages
;
2103 nsDocShell::GetPreviousTransIndex(PRInt32
*aPreviousTransIndex
)
2105 *aPreviousTransIndex
= mPreviousTransIndex
;
2110 nsDocShell::GetLoadedTransIndex(PRInt32
*aLoadedTransIndex
)
2112 *aLoadedTransIndex
= mLoadedTransIndex
;
2117 nsDocShell::HistoryPurged(PRInt32 aNumEntries
)
2119 // These indices are used for fastback cache eviction, to determine
2120 // which session history entries are candidates for content viewer
2121 // eviction. We need to adjust by the number of entries that we
2122 // just purged from history, so that we look at the right session history
2123 // entries during eviction.
2124 mPreviousTransIndex
= NS_MAX(-1, mPreviousTransIndex
- aNumEntries
);
2125 mLoadedTransIndex
= NS_MAX(0, mLoadedTransIndex
- aNumEntries
);
2127 PRInt32 count
= mChildList
.Count();
2128 for (PRInt32 i
= 0; i
< count
; ++i
) {
2129 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
2131 shell
->HistoryPurged(aNumEntries
);
2140 GetPrincipalDomain(nsIPrincipal
* aPrincipal
, nsACString
& aDomain
)
2144 nsCOMPtr
<nsIURI
> codebaseURI
;
2145 nsresult rv
= aPrincipal
->GetDomain(getter_AddRefs(codebaseURI
));
2146 NS_ENSURE_SUCCESS(rv
, rv
);
2148 rv
= aPrincipal
->GetURI(getter_AddRefs(codebaseURI
));
2149 NS_ENSURE_SUCCESS(rv
, rv
);
2155 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(codebaseURI
);
2156 NS_ASSERTION(innerURI
, "Failed to get innermost URI");
2157 NS_ENSURE_SUCCESS(rv
, rv
);
2159 rv
= innerURI
->GetAsciiHost(aDomain
);
2167 nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal
* aPrincipal
,
2168 const nsAString
& aDocumentURI
,
2170 nsIDOMStorage
** aStorage
)
2172 NS_ENSURE_ARG_POINTER(aStorage
);
2180 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
2181 rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
2186 return NS_ERROR_FAILURE
;
2188 nsDocShell
* topDocShell
= static_cast<nsDocShell
*>(topItem
.get());
2189 if (topDocShell
!= this)
2190 return topDocShell
->GetSessionStorageForPrincipal(aPrincipal
,
2195 nsCAutoString currentDomain
;
2196 rv
= GetPrincipalDomain(aPrincipal
, currentDomain
);
2200 if (currentDomain
.IsEmpty())
2203 if (!mStorages
.Get(currentDomain
, aStorage
) && aCreate
) {
2204 nsCOMPtr
<nsIDOMStorage
> newstorage
=
2205 do_CreateInstance("@mozilla.org/dom/storage;2");
2207 return NS_ERROR_OUT_OF_MEMORY
;
2209 nsCOMPtr
<nsPIDOMStorage
> pistorage
= do_QueryInterface(newstorage
);
2211 return NS_ERROR_FAILURE
;
2212 rv
= pistorage
->InitAsSessionStorage(aPrincipal
, aDocumentURI
);
2216 if (!mStorages
.Put(currentDomain
, newstorage
))
2217 return NS_ERROR_OUT_OF_MEMORY
;
2219 newstorage
.swap(*aStorage
);
2220 #if defined(PR_LOGGING) && defined(DEBUG)
2221 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2222 ("nsDocShell[%p]: created a new sessionStorage %p",
2226 else if (*aStorage
) {
2227 nsCOMPtr
<nsPIDOMStorage
> piStorage
= do_QueryInterface(*aStorage
);
2229 PRBool canAccess
= piStorage
->CanAccess(aPrincipal
);
2230 NS_ASSERTION(canAccess
,
2231 "GetSessionStorageForPrincipal got a storage "
2232 "that could not be accessed!");
2234 NS_RELEASE(*aStorage
);
2235 return NS_ERROR_DOM_SECURITY_ERR
;
2239 #if defined(PR_LOGGING) && defined(DEBUG)
2240 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2241 ("nsDocShell[%p]: returns existing sessionStorage %p",
2247 // We are asked to create a new storage object. This indicates
2248 // that a new windows wants it. At this moment we "fork" the existing
2249 // storage object (what it means is described in the paragraph bellow).
2250 // We must create a single object per a single window to distinguish
2251 // a window originating oparations on the storage object to succesfully
2252 // prevent dispatch of a storage event to this same window that ivoked
2253 // a change in its storage. We also do this to correctly fill
2254 // documentURI property in the storage event.
2256 // The difference between clone and fork is that clone creates
2257 // a completelly new and independent storage, but fork only creates
2258 // a new object wrapping the storage implementation and data and
2259 // the forked storage then behaves completelly the same way as
2260 // the storage it has been forked of, all such forked storage objects
2261 // shares their state and data and change on one such object affects
2262 // all others the same way.
2263 nsCOMPtr
<nsPIDOMStorage
> piStorage
= do_QueryInterface(*aStorage
);
2264 nsCOMPtr
<nsIDOMStorage
> fork
= piStorage
->Fork(aDocumentURI
);
2265 #if defined(PR_LOGGING) && defined(DEBUG)
2266 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2267 ("nsDocShell[%p]: forked sessionStorage %p to %p",
2268 this, *aStorage
, fork
.get()));
2270 fork
.swap(*aStorage
);
2277 nsDocShell::GetSessionStorageForURI(nsIURI
* aURI
,
2278 const nsAString
& aDocumentURI
,
2279 nsIDOMStorage
** aStorage
)
2281 return GetSessionStorageForURI(aURI
, aDocumentURI
, PR_TRUE
, aStorage
);
2285 nsDocShell::GetSessionStorageForURI(nsIURI
* aURI
,
2286 const nsSubstring
& aDocumentURI
,
2288 nsIDOMStorage
** aStorage
)
2290 NS_ENSURE_ARG(aURI
);
2291 NS_ENSURE_ARG_POINTER(aStorage
);
2297 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
2298 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
2299 NS_ENSURE_SUCCESS(rv
, rv
);
2301 // This is terrible hack and should go away along with this whole method.
2302 nsCOMPtr
<nsIPrincipal
> principal
;
2303 rv
= securityManager
->GetCodebasePrincipal(aURI
, getter_AddRefs(principal
));
2307 return GetSessionStorageForPrincipal(principal
, aDocumentURI
, aCreate
, aStorage
);
2311 nsDocShell::AddSessionStorage(nsIPrincipal
* aPrincipal
,
2312 nsIDOMStorage
* aStorage
)
2314 NS_ENSURE_ARG_POINTER(aStorage
);
2319 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
2320 nsresult rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
2325 nsCOMPtr
<nsIDocShell
> topDocShell
= do_QueryInterface(topItem
);
2326 if (topDocShell
== this) {
2327 nsCAutoString currentDomain
;
2328 rv
= GetPrincipalDomain(aPrincipal
, currentDomain
);
2332 if (currentDomain
.IsEmpty())
2333 return NS_ERROR_FAILURE
;
2335 // Do not replace an existing session storage.
2336 if (mStorages
.GetWeak(currentDomain
))
2337 return NS_ERROR_NOT_AVAILABLE
;
2339 #if defined(PR_LOGGING) && defined(DEBUG)
2340 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2341 ("nsDocShell[%p]: was added a sessionStorage %p",
2344 if (!mStorages
.Put(currentDomain
, aStorage
))
2345 return NS_ERROR_OUT_OF_MEMORY
;
2348 return topDocShell
->AddSessionStorage(aPrincipal
, aStorage
);
2356 nsDocShell::GetCurrentDocumentChannel(nsIChannel
** aResult
)
2358 NS_IF_ADDREF(*aResult
= GetCurrentDocChannel());
2363 nsDocShell::GetCurrentDocChannel()
2365 if (mContentViewer
) {
2366 nsIDocument
* doc
= mContentViewer
->GetDocument();
2368 return doc
->GetChannel();
2374 //*****************************************************************************
2375 // nsDocShell::nsIDocShellTreeItem
2376 //*****************************************************************************
2379 nsDocShell::GetName(PRUnichar
** aName
)
2381 NS_ENSURE_ARG_POINTER(aName
);
2382 *aName
= ToNewUnicode(mName
);
2387 nsDocShell::SetName(const PRUnichar
* aName
)
2389 mName
= aName
; // this does a copy of aName
2394 nsDocShell::NameEquals(const PRUnichar
*aName
, PRBool
*_retval
)
2396 NS_ENSURE_ARG_POINTER(aName
);
2397 NS_ENSURE_ARG_POINTER(_retval
);
2398 *_retval
= mName
.Equals(aName
);
2403 nsDocShell::GetItemType(PRInt32
* aItemType
)
2405 NS_ENSURE_ARG_POINTER(aItemType
);
2407 *aItemType
= mItemType
;
2412 nsDocShell::SetItemType(PRInt32 aItemType
)
2414 NS_ENSURE_ARG((aItemType
== typeChrome
) || (typeContent
== aItemType
));
2416 // Only allow setting the type on root docshells. Those would be the ones
2417 // that have the docloader service as mParent or have no mParent at all.
2418 nsCOMPtr
<nsIDocumentLoader
> docLoaderService
=
2419 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
2420 NS_ENSURE_TRUE(docLoaderService
, NS_ERROR_UNEXPECTED
);
2422 NS_ENSURE_STATE(!mParent
|| mParent
== docLoaderService
);
2424 mItemType
= aItemType
;
2426 // disable auth prompting for anything but content
2427 mAllowAuth
= mItemType
== typeContent
;
2429 nsRefPtr
<nsPresContext
> presContext
= nsnull
;
2430 GetPresContext(getter_AddRefs(presContext
));
2432 presContext
->InvalidateIsChromeCache();
2439 nsDocShell::GetParent(nsIDocShellTreeItem
** aParent
)
2444 CallQueryInterface(mParent
, aParent
);
2446 // Note that in the case when the parent is not an nsIDocShellTreeItem we
2447 // don't want to throw; we just want to return null.
2452 nsDocShell::SetDocLoaderParent(nsDocLoader
* aParent
)
2454 nsDocLoader::SetDocLoaderParent(aParent
);
2456 // Curse ambiguous nsISupports inheritance!
2457 nsISupports
* parent
= GetAsSupports(aParent
);
2459 // If parent is another docshell, we inherit all their flags for
2460 // allowing plugins, scripting etc.
2461 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(parent
));
2462 if (parentAsDocShell
)
2465 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowPlugins(&value
)))
2467 SetAllowPlugins(value
);
2469 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowJavascript(&value
)))
2471 SetAllowJavascript(value
);
2473 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowMetaRedirects(&value
)))
2475 SetAllowMetaRedirects(value
);
2477 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowSubframes(&value
)))
2479 SetAllowSubframes(value
);
2481 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowImages(&value
)))
2483 SetAllowImages(value
);
2485 if (NS_FAILED(parentAsDocShell
->GetAllowDNSPrefetch(&value
))) {
2488 SetAllowDNSPrefetch(value
);
2491 nsCOMPtr
<nsIURIContentListener
> parentURIListener(do_GetInterface(parent
));
2492 if (parentURIListener
)
2493 mContentListener
->SetParentContentListener(parentURIListener
);
2498 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem
** aParent
)
2500 NS_ENSURE_ARG_POINTER(aParent
);
2503 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
2504 do_QueryInterface(GetAsSupports(mParent
));
2509 NS_ENSURE_SUCCESS(parent
->GetItemType(&parentType
), NS_ERROR_FAILURE
);
2511 if (parentType
== mItemType
) {
2512 parent
.swap(*aParent
);
2518 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
2520 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
2521 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
2523 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2524 NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent
)), NS_ERROR_FAILURE
);
2526 *aRootTreeItem
= parent
;
2527 NS_ENSURE_SUCCESS((*aRootTreeItem
)->GetParent(getter_AddRefs(parent
)),
2530 NS_ADDREF(*aRootTreeItem
);
2535 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
2537 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
2538 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
2540 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2541 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent
)),
2544 *aRootTreeItem
= parent
;
2545 NS_ENSURE_SUCCESS((*aRootTreeItem
)->
2546 GetSameTypeParent(getter_AddRefs(parent
)),
2549 NS_ADDREF(*aRootTreeItem
);
2555 nsDocShell::CanAccessItem(nsIDocShellTreeItem
* aTargetItem
,
2556 nsIDocShellTreeItem
* aAccessingItem
,
2557 PRBool aConsiderOpener
)
2559 NS_PRECONDITION(aTargetItem
, "Must have target item!");
2561 if (!gValidateOrigin
|| !aAccessingItem
) {
2566 // XXXbz should we care if aAccessingItem or the document therein is
2567 // chrome? Should those get extra privileges?
2569 // For historical context, see:
2571 // Bug 13871: Prevent frameset spoofing
2572 // Bug 103638: Targets with same name in different windows open in wrong
2573 // window with javascript
2574 // Bug 408052: Adopt "ancestor" frame navigation policy
2576 // Now do a security check
2578 // Allow navigation if
2579 // 1) aAccessingItem can script aTargetItem or one of its ancestors in
2580 // the frame hierarchy or
2581 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
2582 // 3) aTargetItem is a top-level frame and aAccessingItem can target
2583 // its opener per rule (1) or (2).
2585 if (aTargetItem
== aAccessingItem
) {
2586 // A frame is allowed to navigate itself.
2590 nsCOMPtr
<nsIDocShellTreeItem
> accessingRoot
;
2591 aAccessingItem
->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot
));
2593 if (aTargetItem
== accessingRoot
) {
2594 // A frame can navigate its root.
2598 // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
2599 nsCOMPtr
<nsIDocShellTreeItem
> target
= aTargetItem
;
2601 if (ValidateOrigin(aAccessingItem
, target
)) {
2605 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2606 target
->GetSameTypeParent(getter_AddRefs(parent
));
2607 parent
.swap(target
);
2610 nsCOMPtr
<nsIDocShellTreeItem
> targetRoot
;
2611 aTargetItem
->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot
));
2613 if (aTargetItem
!= targetRoot
) {
2614 // target is a subframe, not in accessor's frame hierarchy, and all its
2615 // ancestors have origins different from that of the accessor. Don't
2620 if (!aConsiderOpener
) {
2625 nsCOMPtr
<nsIDOMWindow
> targetWindow(do_GetInterface(aTargetItem
));
2626 nsCOMPtr
<nsIDOMWindowInternal
> targetInternal(do_QueryInterface(targetWindow
));
2627 if (!targetInternal
) {
2628 NS_ERROR("This should not happen, really");
2632 nsCOMPtr
<nsIDOMWindowInternal
> targetOpener
;
2633 targetInternal
->GetOpener(getter_AddRefs(targetOpener
));
2634 nsCOMPtr
<nsIWebNavigation
> openerWebNav(do_GetInterface(targetOpener
));
2635 nsCOMPtr
<nsIDocShellTreeItem
> openerItem(do_QueryInterface(openerWebNav
));
2641 return CanAccessItem(openerItem
, aAccessingItem
, PR_FALSE
);
2645 ItemIsActive(nsIDocShellTreeItem
*aItem
)
2647 nsCOMPtr
<nsIDOMWindow
> tmp(do_GetInterface(aItem
));
2648 nsCOMPtr
<nsIDOMWindowInternal
> window(do_QueryInterface(tmp
));
2653 if (NS_SUCCEEDED(window
->GetClosed(&isClosed
)) && !isClosed
) {
2662 nsDocShell::FindItemWithName(const PRUnichar
* aName
,
2663 nsISupports
* aRequestor
,
2664 nsIDocShellTreeItem
* aOriginalRequestor
,
2665 nsIDocShellTreeItem
** _retval
)
2667 NS_ENSURE_ARG(aName
);
2668 NS_ENSURE_ARG_POINTER(_retval
);
2670 // If we don't find one, we return NS_OK and a null result
2678 nsCOMPtr
<nsIDocShellTreeItem
> foundItem
;
2680 // This is the entry point into the target-finding algorithm. Check
2681 // for special names. This should only be done once, hence the check
2682 // for a null aRequestor.
2684 nsDependentString
name(aName
);
2685 if (name
.LowerCaseEqualsLiteral("_self")) {
2688 else if (name
.LowerCaseEqualsLiteral("_blank"))
2690 // Just return null. Caller must handle creating a new window with
2691 // a blank name himself.
2694 else if (name
.LowerCaseEqualsLiteral("_parent"))
2696 GetSameTypeParent(getter_AddRefs(foundItem
));
2700 else if (name
.LowerCaseEqualsLiteral("_top"))
2702 GetSameTypeRootTreeItem(getter_AddRefs(foundItem
));
2703 NS_ASSERTION(foundItem
, "Must have this; worst case it's us!");
2705 // _main is an IE target which should be case-insensitive but isn't
2706 // see bug 217886 for details
2707 else if (name
.LowerCaseEqualsLiteral("_content") ||
2708 name
.EqualsLiteral("_main"))
2710 // Must pass our same type root as requestor to the
2711 // treeowner to make sure things work right.
2712 nsCOMPtr
<nsIDocShellTreeItem
> root
;
2713 GetSameTypeRootTreeItem(getter_AddRefs(root
));
2715 NS_ASSERTION(root
, "Must have this; worst case it's us!");
2716 mTreeOwner
->FindItemWithName(aName
, root
, aOriginalRequestor
,
2717 getter_AddRefs(foundItem
));
2721 NS_ERROR("Someone isn't setting up the tree owner. "
2722 "You might like to try that. "
2723 "Things will.....you know, work.");
2724 // Note: _content should always exist. If we don't have one
2725 // hanging off the treeowner, just create a named window....
2726 // so don't return here, in case we did that and can now find
2728 // XXXbz should we be using |root| instead of creating
2734 if (foundItem
&& !CanAccessItem(foundItem
, aOriginalRequestor
)) {
2739 // We return foundItem here even if it's not an active
2740 // item since all the names we've dealt with so far are
2741 // special cases that we won't bother looking for further.
2743 foundItem
.swap(*_retval
);
2750 // First we check our name.
2751 if (mName
.Equals(aName
) && ItemIsActive(this) &&
2752 CanAccessItem(this, aOriginalRequestor
)) {
2753 NS_ADDREF(*_retval
= this);
2757 // This QI may fail, but the places where we want to compare, comparing
2758 // against nsnull serves the same purpose.
2759 nsCOMPtr
<nsIDocShellTreeItem
> reqAsTreeItem(do_QueryInterface(aRequestor
));
2761 // Second we check our children making sure not to ask a child if
2762 // it is the aRequestor.
2766 FindChildWithName(aName
, PR_TRUE
, PR_TRUE
, reqAsTreeItem
,
2767 aOriginalRequestor
, _retval
);
2768 NS_ASSERTION(NS_SUCCEEDED(rv
),
2769 "FindChildWithName should not be failing here.");
2773 // Third if we have a parent and it isn't the requestor then we
2774 // should ask it to do the search. If it is the requestor we
2775 // should just stop here and let the parent do the rest. If we
2776 // don't have a parent, then we should ask the
2777 // docShellTreeOwner to do the search.
2778 nsCOMPtr
<nsIDocShellTreeItem
> parentAsTreeItem
=
2779 do_QueryInterface(GetAsSupports(mParent
));
2780 if (parentAsTreeItem
) {
2781 if (parentAsTreeItem
== reqAsTreeItem
)
2785 parentAsTreeItem
->GetItemType(&parentType
);
2786 if (parentType
== mItemType
) {
2787 return parentAsTreeItem
->
2788 FindItemWithName(aName
,
2789 static_cast<nsIDocShellTreeItem
*>
2796 // If the parent is null or not of the same type fall through and ask tree
2799 // This may fail, but comparing against null serves the same purpose
2800 nsCOMPtr
<nsIDocShellTreeOwner
>
2801 reqAsTreeOwner(do_QueryInterface(aRequestor
));
2803 if (mTreeOwner
&& mTreeOwner
!= reqAsTreeOwner
) {
2805 FindItemWithName(aName
, this, aOriginalRequestor
, _retval
);
2812 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner
** aTreeOwner
)
2814 NS_ENSURE_ARG_POINTER(aTreeOwner
);
2816 *aTreeOwner
= mTreeOwner
;
2817 NS_IF_ADDREF(*aTreeOwner
);
2821 #ifdef DEBUG_DOCSHELL_FOCUS
2823 PrintDocTree(nsIDocShellTreeItem
* aParentNode
, int aLevel
)
2825 for (PRInt32 i
=0;i
<aLevel
;i
++) printf(" ");
2827 PRInt32 childWebshellCount
;
2828 aParentNode
->GetChildCount(&childWebshellCount
);
2829 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(aParentNode
));
2831 aParentNode
->GetItemType(&type
);
2832 nsCOMPtr
<nsIPresShell
> presShell
;
2833 parentAsDocShell
->GetPresShell(getter_AddRefs(presShell
));
2834 nsRefPtr
<nsPresContext
> presContext
;
2835 parentAsDocShell
->GetPresContext(getter_AddRefs(presContext
));
2836 nsIDocument
*doc
= presShell
->GetDocument();
2838 nsCOMPtr
<nsIDOMWindowInternal
> domwin(doc
->GetWindow());
2840 nsCOMPtr
<nsIWidget
> widget
;
2841 nsIViewManager
* vm
= presShell
->GetViewManager();
2843 vm
->GetWidget(getter_AddRefs(widget
));
2845 dom::Element
* rootElement
= doc
->GetRootElement();
2847 printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
2848 (void*)parentAsDocShell
.get(),
2849 type
==nsIDocShellTreeItem::typeChrome
?"Chr":"Con",
2850 (void*)doc
, (void*)domwin
.get(),
2851 (void*)presContext
->EventStateManager(), (void*)rootElement
);
2853 if (childWebshellCount
> 0) {
2854 for (PRInt32 i
=0;i
<childWebshellCount
;i
++) {
2855 nsCOMPtr
<nsIDocShellTreeItem
> child
;
2856 aParentNode
->GetChildAt(i
, getter_AddRefs(child
));
2857 PrintDocTree(child
, aLevel
+1);
2863 PrintDocTree(nsIDocShellTreeItem
* aParentNode
)
2865 NS_ASSERTION(aParentNode
, "Pointer is null!");
2867 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
2868 aParentNode
->GetParent(getter_AddRefs(parentItem
));
2869 while (parentItem
) {
2870 nsCOMPtr
<nsIDocShellTreeItem
>tmp
;
2871 parentItem
->GetParent(getter_AddRefs(tmp
));
2879 parentItem
= aParentNode
;
2882 PrintDocTree(parentItem
, 0);
2887 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
)
2889 #ifdef DEBUG_DOCSHELL_FOCUS
2890 nsCOMPtr
<nsIDocShellTreeItem
> item(do_QueryInterface(aTreeOwner
));
2896 // Don't automatically set the progress based on the tree owner for frames
2898 nsCOMPtr
<nsIWebProgress
> webProgress
=
2899 do_QueryInterface(GetAsSupports(this));
2902 nsCOMPtr
<nsIWebProgressListener
>
2903 oldListener(do_QueryInterface(mTreeOwner
));
2904 nsCOMPtr
<nsIWebProgressListener
>
2905 newListener(do_QueryInterface(aTreeOwner
));
2908 webProgress
->RemoveProgressListener(oldListener
);
2912 webProgress
->AddProgressListener(newListener
,
2913 nsIWebProgress::NOTIFY_ALL
);
2918 mTreeOwner
= aTreeOwner
; // Weak reference per API
2920 PRInt32 i
, n
= mChildList
.Count();
2921 for (i
= 0; i
< n
; i
++) {
2922 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryInterface(ChildAt(i
));
2923 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
2924 PRInt32 childType
= ~mItemType
; // Set it to not us in case the get fails
2925 child
->GetItemType(&childType
); // We don't care if this fails, if it does we won't set the owner
2926 if (childType
== mItemType
)
2927 child
->SetTreeOwner(aTreeOwner
);
2934 nsDocShell::SetChildOffset(PRUint32 aChildOffset
)
2936 mChildOffset
= aChildOffset
;
2941 nsDocShell::GetIsInUnload(PRBool
* aIsInUnload
)
2943 *aIsInUnload
= mFiredUnloadEvent
;
2947 //*****************************************************************************
2948 // nsDocShell::nsIDocShellTreeNode
2949 //*****************************************************************************
2952 nsDocShell::GetChildCount(PRInt32
* aChildCount
)
2954 NS_ENSURE_ARG_POINTER(aChildCount
);
2955 *aChildCount
= mChildList
.Count();
2962 nsDocShell::AddChild(nsIDocShellTreeItem
* aChild
)
2964 NS_ENSURE_ARG_POINTER(aChild
);
2966 nsRefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
2967 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
2969 // Make sure we're not creating a loop in the docshell tree
2970 nsDocLoader
* ancestor
= this;
2972 if (childAsDocLoader
== ancestor
) {
2973 return NS_ERROR_ILLEGAL_VALUE
;
2975 ancestor
= ancestor
->GetParent();
2978 // Make sure to remove the child from its current parent.
2979 nsDocLoader
* childsParent
= childAsDocLoader
->GetParent();
2981 childsParent
->RemoveChildLoader(childAsDocLoader
);
2984 // Make sure to clear the treeowner in case this child is a different type
2986 aChild
->SetTreeOwner(nsnull
);
2988 nsresult res
= AddChildLoader(childAsDocLoader
);
2989 NS_ENSURE_SUCCESS(res
, res
);
2990 NS_ASSERTION(mChildList
.Count() > 0,
2991 "child list must not be empty after a successful add");
2993 // Set the child's index in the parent's children list
2994 // XXX What if the parent had different types of children?
2995 // XXX in that case docshell hierarchy and SH hierarchy won't match.
2997 nsCOMPtr
<nsIDocShell
> childDocShell
= do_QueryInterface(aChild
);
2998 if (childDocShell
) {
2999 // If there are frameloaders in the finalization list, reduce
3000 // the offset so that the SH hierarchy is more likely to match the
3001 // docshell hierarchy
3002 nsCOMPtr
<nsIDOMDocument
> domDoc
=
3003 do_GetInterface(GetAsSupports(this));
3004 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
3005 PRUint32 offset
= mChildList
.Count() - 1;
3007 PRUint32 oldChildCount
= offset
; // Current child count - 1
3008 for (PRUint32 i
= 0; i
< oldChildCount
; ++i
) {
3009 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
3010 if (doc
->FrameLoaderScheduledToBeFinalized(child
)) {
3016 childDocShell
->SetChildOffset(offset
);
3020 /* Set the child's global history if the parent has one */
3021 if (mGlobalHistory
) {
3022 nsCOMPtr
<nsIDocShellHistory
>
3023 dsHistoryChild(do_QueryInterface(aChild
));
3025 dsHistoryChild
->SetUseGlobalHistory(PR_TRUE
);
3029 PRInt32 childType
= ~mItemType
; // Set it to not us in case the get fails
3030 aChild
->GetItemType(&childType
);
3031 if (childType
!= mItemType
)
3033 // Everything below here is only done when the child is the same type.
3036 aChild
->SetTreeOwner(mTreeOwner
);
3038 nsCOMPtr
<nsIDocShell
> childAsDocShell(do_QueryInterface(aChild
));
3039 if (!childAsDocShell
)
3042 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3044 // Now take this document's charset and set the parentCharset field of the
3045 // child's DocumentCharsetInfo to it. We'll later use that field, in the
3046 // loading process, for the charset choosing algorithm.
3047 // If we fail, at any point, we just return NS_OK.
3048 // This code has some performance impact. But this will be reduced when
3049 // the current charset will finally be stored as an Atom, avoiding the
3050 // alias resolution extra look-up.
3052 // we are NOT going to propagate the charset is this Chrome's docshell
3053 if (mItemType
== nsIDocShellTreeItem::typeChrome
)
3056 // get the child's docCSInfo object
3057 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
= NULL
;
3058 res
= childAsDocShell
->GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
3059 if (NS_FAILED(res
) || (!dcInfo
))
3062 // get the parent's current charset
3063 if (!mContentViewer
)
3065 nsIDocument
* doc
= mContentViewer
->GetDocument();
3068 const nsACString
&parentCS
= doc
->GetDocumentCharacterSet();
3070 PRBool isWyciwyg
= PR_FALSE
;
3073 // Check if the url is wyciwyg
3074 mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
3078 // If this docshell is loaded from a wyciwyg: URI, don't
3079 // advertise our charset since it does not in any way reflect
3080 // the actual source charset, which is what we're trying to
3083 // set the child's parentCharset
3084 nsCOMPtr
<nsIAtom
> parentCSAtom(do_GetAtom(parentCS
));
3085 res
= dcInfo
->SetParentCharset(parentCSAtom
);
3089 PRInt32 charsetSource
= doc
->GetDocumentCharacterSetSource();
3091 // set the child's parentCharset
3092 res
= dcInfo
->SetParentCharsetSource(charsetSource
);
3097 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3103 nsDocShell::RemoveChild(nsIDocShellTreeItem
* aChild
)
3105 NS_ENSURE_ARG_POINTER(aChild
);
3107 nsRefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
3108 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
3110 nsresult rv
= RemoveChildLoader(childAsDocLoader
);
3111 NS_ENSURE_SUCCESS(rv
, rv
);
3113 aChild
->SetTreeOwner(nsnull
);
3115 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader
);
3119 nsDocShell::GetChildAt(PRInt32 aIndex
, nsIDocShellTreeItem
** aChild
)
3121 NS_ENSURE_ARG_POINTER(aChild
);
3125 NS_WARNING("Negative index passed to GetChildAt");
3127 else if (aIndex
>= mChildList
.Count()) {
3128 NS_WARNING("Too large an index passed to GetChildAt");
3132 nsIDocumentLoader
* child
= SafeChildAt(aIndex
);
3133 NS_ENSURE_TRUE(child
, NS_ERROR_UNEXPECTED
);
3135 return CallQueryInterface(child
, aChild
);
3139 nsDocShell::FindChildWithName(const PRUnichar
* aName
,
3140 PRBool aRecurse
, PRBool aSameType
,
3141 nsIDocShellTreeItem
* aRequestor
,
3142 nsIDocShellTreeItem
* aOriginalRequestor
,
3143 nsIDocShellTreeItem
** _retval
)
3145 NS_ENSURE_ARG(aName
);
3146 NS_ENSURE_ARG_POINTER(_retval
);
3148 *_retval
= nsnull
; // if we don't find one, we return NS_OK and a null result
3153 nsXPIDLString childName
;
3154 PRInt32 i
, n
= mChildList
.Count();
3155 for (i
= 0; i
< n
; i
++) {
3156 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryInterface(ChildAt(i
));
3157 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
3159 child
->GetItemType(&childType
);
3161 if (aSameType
&& (childType
!= mItemType
))
3164 PRBool childNameEquals
= PR_FALSE
;
3165 child
->NameEquals(aName
, &childNameEquals
);
3166 if (childNameEquals
&& ItemIsActive(child
) &&
3167 CanAccessItem(child
, aOriginalRequestor
)) {
3168 child
.swap(*_retval
);
3172 if (childType
!= mItemType
) //Only ask it to check children if it is same type
3175 if (aRecurse
&& (aRequestor
!= child
)) // Only ask the child if it isn't the requestor
3177 // See if child contains the shell with the given name
3181 child
->FindChildWithName(aName
, PR_TRUE
,
3183 static_cast<nsIDocShellTreeItem
*>
3187 NS_ASSERTION(NS_SUCCEEDED(rv
),
3188 "FindChildWithName should not fail here");
3189 if (*_retval
) // found it
3196 //*****************************************************************************
3197 // nsDocShell::nsIDocShellHistory
3198 //*****************************************************************************
3200 nsDocShell::GetChildSHEntry(PRInt32 aChildOffset
, nsISHEntry
** aResult
)
3202 nsresult rv
= NS_OK
;
3204 NS_ENSURE_ARG_POINTER(aResult
);
3208 // A nsISHEntry for a child is *only* available when the parent is in
3209 // the progress of loading a document too...
3212 /* Before looking for the subframe's url, check
3213 * the expiration status of the parent. If the parent
3214 * has expired from cache, then subframes will not be
3215 * loaded from history in certain situations.
3217 PRBool parentExpired
=PR_FALSE
;
3218 mLSHE
->GetExpirationStatus(&parentExpired
);
3220 /* Get the parent's Load Type so that it can be set on the child too.
3221 * By default give a loadHistory value
3223 PRUint32 loadType
= nsIDocShellLoadInfo::loadHistory
;
3224 mLSHE
->GetLoadType(&loadType
);
3225 // If the user did a shift-reload on this frameset page,
3226 // we don't want to load the subframes from history.
3227 if (loadType
== nsIDocShellLoadInfo::loadReloadBypassCache
||
3228 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxy
||
3229 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
||
3230 loadType
== nsIDocShellLoadInfo::loadRefresh
)
3233 /* If the user pressed reload and the parent frame has expired
3234 * from cache, we do not want to load the child frame from history.
3236 if (parentExpired
&& (loadType
== nsIDocShellLoadInfo::loadReloadNormal
)) {
3237 // The parent has expired. Return null.
3242 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
));
3244 // Get the child subframe from session history.
3245 rv
= container
->GetChildAt(aChildOffset
, aResult
);
3247 (*aResult
)->SetLoadType(loadType
);
3254 nsDocShell::AddChildSHEntry(nsISHEntry
* aCloneRef
, nsISHEntry
* aNewEntry
,
3255 PRInt32 aChildOffset
, PRUint32 loadType
)
3259 if (mLSHE
&& loadType
!= LOAD_PUSHSTATE
) {
3260 /* You get here if you are currently building a
3261 * hierarchy ie.,you just visited a frameset page
3263 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
, &rv
));
3265 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
3268 else if (!aCloneRef
) {
3269 /* This is an initial load in some subframe. Just append it if we can */
3270 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mOSHE
, &rv
));
3272 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
3275 else if (mSessionHistory
) {
3276 /* You are currently in the rootDocShell.
3277 * You will get here when a subframe has a new url
3278 * to load and you have walked up the tree all the
3279 * way to the top to clone the current SHEntry hierarchy
3280 * and replace the subframe where a new url was loaded with
3284 nsCOMPtr
<nsIHistoryEntry
> currentHE
;
3285 mSessionHistory
->GetIndex(&index
);
3287 return NS_ERROR_FAILURE
;
3289 rv
= mSessionHistory
->GetEntryAtIndex(index
, PR_FALSE
,
3290 getter_AddRefs(currentHE
));
3291 NS_ENSURE_TRUE(currentHE
, NS_ERROR_FAILURE
);
3293 nsCOMPtr
<nsISHEntry
> currentEntry(do_QueryInterface(currentHE
));
3295 PRUint32 cloneID
= 0;
3296 nsCOMPtr
<nsISHEntry
> nextEntry
;
3297 aCloneRef
->GetID(&cloneID
);
3298 rv
= CloneAndReplace(currentEntry
, this, cloneID
, aNewEntry
,
3299 getter_AddRefs(nextEntry
));
3301 if (NS_SUCCEEDED(rv
)) {
3302 nsCOMPtr
<nsISHistoryInternal
>
3303 shPrivate(do_QueryInterface(mSessionHistory
));
3304 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
3305 rv
= shPrivate
->AddEntry(nextEntry
, PR_TRUE
);
3310 /* Just pass this along */
3311 nsCOMPtr
<nsIDocShellHistory
> parent
=
3312 do_QueryInterface(GetAsSupports(mParent
), &rv
);
3314 rv
= parent
->AddChildSHEntry(aCloneRef
, aNewEntry
, aChildOffset
,
3322 nsDocShell::DoAddChildSHEntry(nsISHEntry
* aNewEntry
, PRInt32 aChildOffset
)
3324 /* You will get here when you are in a subframe and
3325 * a new url has been loaded on you.
3326 * The mOSHE in this subframe will be the previous url's
3327 * mOSHE. This mOSHE will be used as the identification
3328 * for this subframe in the CloneAndReplace function.
3331 // In this case, we will end up calling AddEntry, which increases the
3332 // current index by 1
3333 nsCOMPtr
<nsISHistory
> rootSH
;
3334 GetRootSessionHistory(getter_AddRefs(rootSH
));
3336 rootSH
->GetIndex(&mPreviousTransIndex
);
3340 nsCOMPtr
<nsIDocShellHistory
> parent
=
3341 do_QueryInterface(GetAsSupports(mParent
), &rv
);
3343 rv
= parent
->AddChildSHEntry(mOSHE
, aNewEntry
, aChildOffset
, mLoadType
);
3348 rootSH
->GetIndex(&mLoadedTransIndex
);
3349 #ifdef DEBUG_PAGE_CACHE
3350 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
3359 nsDocShell::SetUseGlobalHistory(PRBool aUseGlobalHistory
)
3363 if (!aUseGlobalHistory
) {
3364 mGlobalHistory
= nsnull
;
3368 if (mGlobalHistory
) {
3372 mGlobalHistory
= do_GetService(NS_GLOBALHISTORY2_CONTRACTID
, &rv
);
3377 nsDocShell::GetUseGlobalHistory(PRBool
*aUseGlobalHistory
)
3379 *aUseGlobalHistory
= (mGlobalHistory
!= nsnull
);
3383 //-------------------------------------
3384 //-- Helper Method for Print discovery
3385 //-------------------------------------
3387 nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog
)
3389 if (mIsPrintingOrPP
&& aDisplayErrorDialog
) {
3390 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE
, nsnull
, nsnull
);
3393 return mIsPrintingOrPP
;
3397 nsDocShell::IsNavigationAllowed(PRBool aDisplayPrintErrorDialog
)
3399 return !IsPrintingOrPP(aDisplayPrintErrorDialog
) && !mFiredUnloadEvent
;
3402 //*****************************************************************************
3403 // nsDocShell::nsIWebNavigation
3404 //*****************************************************************************
3407 nsDocShell::GetCanGoBack(PRBool
* aCanGoBack
)
3409 if (!IsNavigationAllowed(PR_FALSE
)) {
3410 *aCanGoBack
= PR_FALSE
;
3411 return NS_OK
; // JS may not handle returning of an error code
3414 nsCOMPtr
<nsISHistory
> rootSH
;
3415 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3416 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3417 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3418 rv
= webnav
->GetCanGoBack(aCanGoBack
);
3424 nsDocShell::GetCanGoForward(PRBool
* aCanGoForward
)
3426 if (!IsNavigationAllowed(PR_FALSE
)) {
3427 *aCanGoForward
= PR_FALSE
;
3428 return NS_OK
; // JS may not handle returning of an error code
3431 nsCOMPtr
<nsISHistory
> rootSH
;
3432 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3433 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3434 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3435 rv
= webnav
->GetCanGoForward(aCanGoForward
);
3441 nsDocShell::GoBack()
3443 if (!IsNavigationAllowed()) {
3444 return NS_OK
; // JS may not handle returning of an error code
3447 nsCOMPtr
<nsISHistory
> rootSH
;
3448 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3449 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3450 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3451 rv
= webnav
->GoBack();
3457 nsDocShell::GoForward()
3459 if (!IsNavigationAllowed()) {
3460 return NS_OK
; // JS may not handle returning of an error code
3463 nsCOMPtr
<nsISHistory
> rootSH
;
3464 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3465 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3466 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3467 rv
= webnav
->GoForward();
3472 NS_IMETHODIMP
nsDocShell::GotoIndex(PRInt32 aIndex
)
3474 if (!IsNavigationAllowed()) {
3475 return NS_OK
; // JS may not handle returning of an error code
3478 nsCOMPtr
<nsISHistory
> rootSH
;
3479 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3480 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3481 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3482 rv
= webnav
->GotoIndex(aIndex
);
3488 nsDocShell::LoadURI(const PRUnichar
* aURI
,
3489 PRUint32 aLoadFlags
,
3490 nsIURI
* aReferringURI
,
3491 nsIInputStream
* aPostStream
,
3492 nsIInputStream
* aHeaderStream
)
3494 NS_ASSERTION((aLoadFlags
& 0xf) == 0, "Unexpected flags");
3496 if (!IsNavigationAllowed()) {
3497 return NS_OK
; // JS may not handle returning of an error code
3499 nsCOMPtr
<nsIURI
> uri
;
3500 nsresult rv
= NS_OK
;
3502 // Create a URI from our string; if that succeeds, we want to
3503 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
3506 NS_ConvertUTF16toUTF8
uriString(aURI
);
3507 // Cleanup the empty spaces that might be on each end.
3508 uriString
.Trim(" ");
3509 // Eliminate embedded newlines, which single-line text fields now allow:
3510 uriString
.StripChars("\r\n");
3511 NS_ENSURE_TRUE(!uriString
.IsEmpty(), NS_ERROR_FAILURE
);
3513 rv
= NS_NewURI(getter_AddRefs(uri
), uriString
);
3515 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
3519 // Call the fixup object. This will clobber the rv from NS_NewURI
3520 // above, but that's fine with us. Note that we need to do this even
3521 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
3522 // (things like view-source:mozilla.org for example).
3523 PRUint32 fixupFlags
= 0;
3524 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) {
3525 fixupFlags
|= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
;
3527 rv
= sURIFixup
->CreateFixupURI(uriString
, fixupFlags
,
3528 getter_AddRefs(uri
));
3530 // else no fixup service so just use the URI we created and see
3533 if (NS_ERROR_MALFORMED_URI
== rv
) {
3534 DisplayLoadError(rv
, uri
, aURI
);
3537 if (NS_FAILED(rv
) || !uri
)
3538 return NS_ERROR_FAILURE
;
3540 PopupControlState popupState
;
3541 if (aLoadFlags
& LOAD_FLAGS_ALLOW_POPUPS
) {
3542 popupState
= openAllowed
;
3543 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_POPUPS
;
3545 popupState
= openOverridden
;
3547 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
3548 nsAutoPopupStatePusher
statePusher(win
, popupState
);
3550 // Don't pass certain flags that aren't needed and end up confusing
3551 // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
3552 // passed to LoadURI though, since it uses them.
3553 PRUint32 extraFlags
= (aLoadFlags
& EXTRA_LOAD_FLAGS
);
3554 aLoadFlags
&= ~EXTRA_LOAD_FLAGS
;
3556 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
3557 rv
= CreateLoadInfo(getter_AddRefs(loadInfo
));
3558 if (NS_FAILED(rv
)) return rv
;
3560 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
3561 loadInfo
->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType
));
3562 loadInfo
->SetPostDataStream(aPostStream
);
3563 loadInfo
->SetReferrer(aReferringURI
);
3564 loadInfo
->SetHeadersStream(aHeaderStream
);
3566 rv
= LoadURI(uri
, loadInfo
, extraFlags
, PR_TRUE
);
3572 nsDocShell::DisplayLoadError(nsresult aError
, nsIURI
*aURI
,
3573 const PRUnichar
*aURL
,
3574 nsIChannel
* aFailedChannel
)
3576 // Get prompt and string bundle servcies
3577 nsCOMPtr
<nsIPrompt
> prompter
;
3578 nsCOMPtr
<nsIStringBundle
> stringBundle
;
3579 GetPromptAndStringBundle(getter_AddRefs(prompter
),
3580 getter_AddRefs(stringBundle
));
3582 NS_ENSURE_TRUE(stringBundle
, NS_ERROR_FAILURE
);
3583 NS_ENSURE_TRUE(prompter
, NS_ERROR_FAILURE
);
3586 const PRUint32 kMaxFormatStrArgs
= 3;
3587 nsAutoString formatStrs
[kMaxFormatStrArgs
];
3588 PRUint32 formatStrCount
= 0;
3589 PRBool addHostPort
= PR_FALSE
;
3590 nsresult rv
= NS_OK
;
3591 nsAutoString messageStr
;
3592 nsCAutoString cssClass
;
3593 nsCAutoString errorPage
;
3595 errorPage
.AssignLiteral("neterror");
3597 // Turn the error code into a human readable error message.
3598 if (NS_ERROR_UNKNOWN_PROTOCOL
== aError
) {
3599 NS_ENSURE_ARG_POINTER(aURI
);
3600 // extract the scheme
3601 nsCAutoString scheme
;
3602 aURI
->GetScheme(scheme
);
3603 CopyASCIItoUTF16(scheme
, formatStrs
[0]);
3605 error
.AssignLiteral("protocolNotFound");
3607 else if (NS_ERROR_FILE_NOT_FOUND
== aError
) {
3608 NS_ENSURE_ARG_POINTER(aURI
);
3609 error
.AssignLiteral("fileNotFound");
3611 else if (NS_ERROR_UNKNOWN_HOST
== aError
) {
3612 NS_ENSURE_ARG_POINTER(aURI
);
3615 nsCOMPtr
<nsIURI
> innermostURI
= NS_GetInnermostURI(aURI
);
3616 innermostURI
->GetHost(host
);
3617 CopyUTF8toUTF16(host
, formatStrs
[0]);
3619 error
.AssignLiteral("dnsNotFound");
3621 else if(NS_ERROR_CONNECTION_REFUSED
== aError
) {
3622 NS_ENSURE_ARG_POINTER(aURI
);
3623 addHostPort
= PR_TRUE
;
3624 error
.AssignLiteral("connectionFailure");
3626 else if(NS_ERROR_NET_INTERRUPT
== aError
) {
3627 NS_ENSURE_ARG_POINTER(aURI
);
3628 addHostPort
= PR_TRUE
;
3629 error
.AssignLiteral("netInterrupt");
3631 else if (NS_ERROR_NET_TIMEOUT
== aError
) {
3632 NS_ENSURE_ARG_POINTER(aURI
);
3635 aURI
->GetHost(host
);
3636 CopyUTF8toUTF16(host
, formatStrs
[0]);
3638 error
.AssignLiteral("netTimeout");
3640 else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION
== aError
) {
3642 cssClass
.AssignLiteral("neterror");
3643 error
.AssignLiteral("cspFrameAncestorBlocked");
3645 else if (NS_ERROR_GET_MODULE(aError
) == NS_ERROR_MODULE_SECURITY
) {
3646 nsCOMPtr
<nsINSSErrorsService
> nsserr
=
3647 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID
);
3649 PRUint32 errorClass
;
3651 NS_FAILED(nsserr
->GetErrorClass(aError
, &errorClass
))) {
3652 errorClass
= nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL
;
3655 nsCOMPtr
<nsISupports
> securityInfo
;
3656 nsCOMPtr
<nsITransportSecurityInfo
> tsi
;
3658 aFailedChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
3659 tsi
= do_QueryInterface(securityInfo
);
3661 // Usually we should have aFailedChannel and get a detailed message
3662 tsi
->GetErrorMessage(getter_Copies(messageStr
));
3665 // No channel, let's obtain the generic error message
3667 nsserr
->GetErrorMessage(aError
, messageStr
);
3670 if (!messageStr
.IsEmpty()) {
3671 if (errorClass
== nsINSSErrorsService::ERROR_CLASS_BAD_CERT
) {
3672 error
.AssignLiteral("nssBadCert");
3673 PRBool expert
= PR_FALSE
;
3674 mPrefs
->GetBoolPref("browser.xul.error_pages.expert_bad_cert",
3677 cssClass
.AssignLiteral("expertBadCert");
3680 // See if an alternate cert error page is registered
3681 nsXPIDLCString alternateErrorPage
;
3682 mPrefs
->GetCharPref("security.alternate_certificate_error_page",
3683 getter_Copies(alternateErrorPage
));
3684 if (alternateErrorPage
)
3685 errorPage
.Assign(alternateErrorPage
);
3687 error
.AssignLiteral("nssFailure2");
3690 } else if (NS_ERROR_PHISHING_URI
== aError
|| NS_ERROR_MALWARE_URI
== aError
) {
3692 aURI
->GetHost(host
);
3693 CopyUTF8toUTF16(host
, formatStrs
[0]);
3696 // Malware and phishing detectors may want to use an alternate error
3697 // page, but if the pref's not set, we'll fall back on the standard page
3698 nsXPIDLCString alternateErrorPage
;
3699 mPrefs
->GetCharPref("urlclassifier.alternate_error_page",
3700 getter_Copies(alternateErrorPage
));
3701 if (alternateErrorPage
)
3702 errorPage
.Assign(alternateErrorPage
);
3704 if (NS_ERROR_PHISHING_URI
== aError
)
3705 error
.AssignLiteral("phishingBlocked");
3707 error
.AssignLiteral("malwareBlocked");
3708 cssClass
.AssignLiteral("blacklist");
3711 // Errors requiring simple formatting
3713 case NS_ERROR_MALFORMED_URI
:
3715 error
.AssignLiteral("malformedURI");
3717 case NS_ERROR_REDIRECT_LOOP
:
3718 // Doc failed to load because the server generated too many redirects
3719 error
.AssignLiteral("redirectLoop");
3721 case NS_ERROR_UNKNOWN_SOCKET_TYPE
:
3722 // Doc failed to load because PSM is not installed
3723 error
.AssignLiteral("unknownSocketType");
3725 case NS_ERROR_NET_RESET
:
3726 // Doc failed to load because the server kept reseting the connection
3727 // before we could read any data from it
3728 error
.AssignLiteral("netReset");
3730 case NS_ERROR_DOCUMENT_NOT_CACHED
:
3731 // Doc failed to load because we are offline and the cache does not
3732 // contain a copy of the document.
3733 error
.AssignLiteral("netOffline");
3735 case NS_ERROR_DOCUMENT_IS_PRINTMODE
:
3736 // Doc navigation attempted while Printing or Print Preview
3737 error
.AssignLiteral("isprinting");
3739 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED
:
3740 // Port blocked for security reasons
3741 addHostPort
= PR_TRUE
;
3742 error
.AssignLiteral("deniedPortAccess");
3744 case NS_ERROR_UNKNOWN_PROXY_HOST
:
3745 // Proxy hostname could not be resolved.
3746 error
.AssignLiteral("proxyResolveFailure");
3748 case NS_ERROR_PROXY_CONNECTION_REFUSED
:
3749 // Proxy connection was refused.
3750 error
.AssignLiteral("proxyConnectFailure");
3752 case NS_ERROR_INVALID_CONTENT_ENCODING
:
3753 // Bad Content Encoding.
3754 error
.AssignLiteral("contentEncodingError");
3756 case NS_ERROR_UNSAFE_CONTENT_TYPE
:
3757 // Channel refused to load from an unrecognized content type.
3758 error
.AssignLiteral("unsafeContentType");
3763 // Test if the error should be displayed
3764 if (error
.IsEmpty()) {
3768 // Test if the error needs to be formatted
3769 if (!messageStr
.IsEmpty()) {
3770 // already obtained message
3774 // Build up the host:port string.
3775 nsCAutoString hostport
;
3777 aURI
->GetHostPort(hostport
);
3779 hostport
.AssignLiteral("?");
3781 CopyUTF8toUTF16(hostport
, formatStrs
[formatStrCount
++]);
3785 rv
= NS_ERROR_NOT_AVAILABLE
;
3787 // displaying "file://" is aesthetically unpleasing and could even be
3788 // confusing to the user
3789 PRBool isFileURI
= PR_FALSE
;
3790 rv
= aURI
->SchemeIs("file", &isFileURI
);
3791 if (NS_SUCCEEDED(rv
) && isFileURI
)
3792 aURI
->GetPath(spec
);
3794 aURI
->GetSpec(spec
);
3796 nsCAutoString charset
;
3797 // unescape and convert from origin charset
3798 aURI
->GetOriginCharset(charset
);
3799 nsCOMPtr
<nsITextToSubURI
> textToSubURI(
3800 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
));
3801 if (NS_SUCCEEDED(rv
)) {
3802 rv
= textToSubURI
->UnEscapeURIForUI(charset
, spec
, formatStrs
[formatStrCount
]);
3805 spec
.AssignLiteral("?");
3808 CopyUTF8toUTF16(spec
, formatStrs
[formatStrCount
]);
3812 const PRUnichar
*strs
[kMaxFormatStrArgs
];
3813 for (PRUint32 i
= 0; i
< formatStrCount
; i
++) {
3814 strs
[i
] = formatStrs
[i
].get();
3817 rv
= stringBundle
->FormatStringFromName(
3819 strs
, formatStrCount
, getter_Copies(str
));
3820 NS_ENSURE_SUCCESS(rv
, rv
);
3821 messageStr
.Assign(str
.get());
3824 // Display the error as a page or an alert prompt
3825 NS_ENSURE_FALSE(messageStr
.IsEmpty(), NS_ERROR_FAILURE
);
3826 // Note: For now, display an alert instead of an error page if we have no
3827 // URI object. Missing URI objects are handled badly by session history.
3828 if (mUseErrorPages
&& aURI
&& aFailedChannel
) {
3829 // Display an error page
3830 LoadErrorPage(aURI
, aURL
, errorPage
.get(), error
.get(),
3831 messageStr
.get(), cssClass
.get(), aFailedChannel
);
3835 // The prompter reqires that our private window has a document (or it
3836 // asserts). Satisfy that assertion now since GetDocument will force
3837 // creation of one if it hasn't already been created.
3838 nsCOMPtr
<nsPIDOMWindow
> pwin(do_QueryInterface(mScriptGlobal
));
3840 nsCOMPtr
<nsIDOMDocument
> doc
;
3841 pwin
->GetDocument(getter_AddRefs(doc
));
3844 // Display a message box
3845 prompter
->Alert(nsnull
, messageStr
.get());
3853 nsDocShell::LoadErrorPage(nsIURI
*aURI
, const PRUnichar
*aURL
,
3854 const char *aErrorPage
,
3855 const PRUnichar
*aErrorType
,
3856 const PRUnichar
*aDescription
,
3857 const char *aCSSClass
,
3858 nsIChannel
* aFailedChannel
)
3860 #if defined(PR_LOGGING) && defined(DEBUG)
3861 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
3863 aURI
->GetSpec(spec
);
3865 nsCAutoString chanName
;
3867 aFailedChannel
->GetName(chanName
);
3869 chanName
.AssignLiteral("<no channel>");
3871 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
3872 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
3873 spec
.get(), NS_ConvertUTF16toUTF8(aURL
).get(), chanName
.get()));
3876 mFailedChannel
= aFailedChannel
;
3878 mFailedLoadType
= mLoadType
;
3881 // If we don't give mLSHE a new doc identifier here, when we go back or
3882 // forward to another SHEntry with the same doc identifier, the error
3883 // page will persist.
3884 mLSHE
->SetUniqueDocIdentifier();
3888 nsCAutoString charset
;
3891 nsresult rv
= aURI
->GetSpec(url
);
3892 rv
|= aURI
->GetOriginCharset(charset
);
3893 NS_ENSURE_SUCCESS(rv
, rv
);
3897 CopyUTF16toUTF8(aURL
, url
);
3901 return NS_ERROR_INVALID_POINTER
;
3904 // Create a URL to pass all the error information through to the page.
3906 char *escapedUrl
= nsEscape(url
.get(), url_Path
);
3907 char *escapedCharset
= nsEscape(charset
.get(), url_Path
);
3908 char *escapedError
= nsEscape(NS_ConvertUTF16toUTF8(aErrorType
).get(), url_Path
);
3909 char *escapedDescription
= nsEscape(NS_ConvertUTF16toUTF8(aDescription
).get(), url_Path
);
3910 char *escapedCSSClass
= nsEscape(aCSSClass
, url_Path
);
3912 nsCString
errorPageUrl("about:");
3913 errorPageUrl
.AppendASCII(aErrorPage
);
3914 errorPageUrl
.AppendLiteral("?e=");
3916 errorPageUrl
.AppendASCII(escapedError
);
3917 errorPageUrl
.AppendLiteral("&u=");
3918 errorPageUrl
.AppendASCII(escapedUrl
);
3919 if (escapedCSSClass
&& escapedCSSClass
[0]) {
3920 errorPageUrl
.AppendASCII("&s=");
3921 errorPageUrl
.AppendASCII(escapedCSSClass
);
3923 errorPageUrl
.AppendLiteral("&c=");
3924 errorPageUrl
.AppendASCII(escapedCharset
);
3925 errorPageUrl
.AppendLiteral("&d=");
3926 errorPageUrl
.AppendASCII(escapedDescription
);
3928 nsMemory::Free(escapedDescription
);
3929 nsMemory::Free(escapedError
);
3930 nsMemory::Free(escapedUrl
);
3931 nsMemory::Free(escapedCharset
);
3932 nsMemory::Free(escapedCSSClass
);
3934 nsCOMPtr
<nsIURI
> errorPageURI
;
3935 nsresult rv
= NS_NewURI(getter_AddRefs(errorPageURI
), errorPageUrl
);
3936 NS_ENSURE_SUCCESS(rv
, rv
);
3938 return InternalLoad(errorPageURI
, nsnull
, nsnull
,
3939 INTERNAL_LOAD_FLAGS_INHERIT_OWNER
, nsnull
, nsnull
,
3940 nsnull
, nsnull
, LOAD_ERROR_PAGE
,
3941 nsnull
, PR_TRUE
, nsnull
, nsnull
);
3946 nsDocShell::Reload(PRUint32 aReloadFlags
)
3948 if (!IsNavigationAllowed()) {
3949 return NS_OK
; // JS may not handle returning of an error code
3952 NS_ASSERTION(((aReloadFlags
& 0xf) == 0),
3953 "Reload command not updated to use load flags!");
3954 NS_ASSERTION((aReloadFlags
& EXTRA_LOAD_FLAGS
) == 0,
3955 "Don't pass these flags to Reload");
3957 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL
, aReloadFlags
);
3958 NS_ENSURE_TRUE(IsValidLoadType(loadType
), NS_ERROR_INVALID_ARG
);
3960 // Send notifications to the HistoryListener if any, about the impending reload
3961 nsCOMPtr
<nsISHistory
> rootSH
;
3962 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3963 nsCOMPtr
<nsISHistoryInternal
> shistInt(do_QueryInterface(rootSH
));
3964 PRBool canReload
= PR_TRUE
;
3966 nsCOMPtr
<nsISHistoryListener
> listener
;
3967 shistInt
->GetListener(getter_AddRefs(listener
));
3969 listener
->OnHistoryReload(mCurrentURI
, aReloadFlags
, &canReload
);
3976 /* If you change this part of code, make sure bug 45297 does not re-occur */
3978 rv
= LoadHistoryEntry(mOSHE
, loadType
);
3980 else if (mLSHE
) { // In case a reload happened before the current load is done
3981 rv
= LoadHistoryEntry(mLSHE
, loadType
);
3984 nsCOMPtr
<nsIDOMDocument
> domDoc(do_GetInterface(GetAsSupports(this)));
3985 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(domDoc
));
3987 nsIPrincipal
* principal
= nsnull
;
3988 nsAutoString contentTypeHint
;
3990 principal
= doc
->NodePrincipal();
3991 doc
->GetContentType(contentTypeHint
);
3994 rv
= InternalLoad(mCurrentURI
,
3997 INTERNAL_LOAD_FLAGS_NONE
, // Do not inherit owner from document
3998 nsnull
, // No window target
3999 NS_LossyConvertUTF16toASCII(contentTypeHint
).get(),
4000 nsnull
, // No post data
4001 nsnull
, // No headers data
4002 loadType
, // Load type
4003 nsnull
, // No SHEntry
4005 nsnull
, // No nsIDocShell
4006 nsnull
); // No nsIRequest
4014 nsDocShell::Stop(PRUint32 aStopFlags
)
4016 // Revoke any pending event related to content viewer restoration
4017 mRestorePresentationEvent
.Revoke();
4019 if (mLoadType
== LOAD_ERROR_PAGE
) {
4021 // Since error page loads never unset mLSHE, do so now
4022 SetHistoryEntry(&mOSHE
, mLSHE
);
4023 SetHistoryEntry(&mLSHE
, nsnull
);
4026 mFailedChannel
= nsnull
;
4027 mFailedURI
= nsnull
;
4030 if (nsIWebNavigation::STOP_CONTENT
& aStopFlags
) {
4031 // Stop the document loading
4033 mContentViewer
->Stop();
4036 if (nsIWebNavigation::STOP_NETWORK
& aStopFlags
) {
4037 // Suspend any timers that were set for this loader. We'll clear
4038 // them out for good in CreateContentViewer.
4039 if (mRefreshURIList
) {
4040 SuspendRefreshURIs();
4041 mSavedRefreshURIList
.swap(mRefreshURIList
);
4042 mRefreshURIList
= nsnull
;
4045 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
4046 // just call Stop() on us as an nsIDocumentLoader... We need fewer
4052 PRInt32 count
= mChildList
.Count();
4053 for (n
= 0; n
< count
; n
++) {
4054 nsCOMPtr
<nsIWebNavigation
> shellAsNav(do_QueryInterface(ChildAt(n
)));
4056 shellAsNav
->Stop(aStopFlags
);
4063 nsDocShell::GetDocument(nsIDOMDocument
** aDocument
)
4065 NS_ENSURE_ARG_POINTER(aDocument
);
4066 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE
);
4068 return mContentViewer
->GetDOMDocument(aDocument
);
4072 nsDocShell::GetCurrentURI(nsIURI
** aURI
)
4074 NS_ENSURE_ARG_POINTER(aURI
);
4077 return NS_EnsureSafeToReturn(mCurrentURI
, aURI
);
4085 nsDocShell::GetReferringURI(nsIURI
** aURI
)
4087 NS_ENSURE_ARG_POINTER(aURI
);
4089 *aURI
= mReferrerURI
;
4090 NS_IF_ADDREF(*aURI
);
4096 nsDocShell::SetSessionHistory(nsISHistory
* aSessionHistory
)
4099 NS_ENSURE_TRUE(aSessionHistory
, NS_ERROR_FAILURE
);
4100 // make sure that we are the root docshell and
4101 // set a handle to root docshell in SH.
4103 nsCOMPtr
<nsIDocShellTreeItem
> root
;
4104 /* Get the root docshell. If *this* is the root docshell
4105 * then save a handle to *this* in SH. SH needs it to do
4106 * traversions thro' its entries
4108 GetSameTypeRootTreeItem(getter_AddRefs(root
));
4109 NS_ENSURE_TRUE(root
, NS_ERROR_FAILURE
);
4110 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this)) {
4111 mSessionHistory
= aSessionHistory
;
4112 nsCOMPtr
<nsISHistoryInternal
>
4113 shPrivate(do_QueryInterface(mSessionHistory
));
4114 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
4115 shPrivate
->SetRootDocShell(this);
4118 return NS_ERROR_FAILURE
;
4124 nsDocShell::GetSessionHistory(nsISHistory
** aSessionHistory
)
4126 NS_ENSURE_ARG_POINTER(aSessionHistory
);
4127 *aSessionHistory
= mSessionHistory
;
4128 NS_IF_ADDREF(*aSessionHistory
);
4132 //*****************************************************************************
4133 // nsDocShell::nsIWebPageDescriptor
4134 //*****************************************************************************
4136 nsDocShell::LoadPage(nsISupports
*aPageDescriptor
, PRUint32 aDisplayType
)
4138 nsCOMPtr
<nsISHEntry
> shEntryIn(do_QueryInterface(aPageDescriptor
));
4140 // Currently, the opaque 'page descriptor' is an nsISHEntry...
4142 return NS_ERROR_INVALID_POINTER
;
4145 // Now clone shEntryIn, since we might end up modifying it later on, and we
4146 // want a page descriptor to be reusable.
4147 nsCOMPtr
<nsISHEntry
> shEntry
;
4148 nsresult rv
= shEntryIn
->Clone(getter_AddRefs(shEntry
));
4149 NS_ENSURE_SUCCESS(rv
, rv
);
4152 // load the page as view-source
4154 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE
== aDisplayType
) {
4155 nsCOMPtr
<nsIURI
> oldUri
, newUri
;
4156 nsCString spec
, newSpec
;
4158 // Create a new view-source URI and replace the original.
4159 rv
= shEntry
->GetURI(getter_AddRefs(oldUri
));
4163 oldUri
->GetSpec(spec
);
4164 newSpec
.AppendLiteral("view-source:");
4165 newSpec
.Append(spec
);
4167 rv
= NS_NewURI(getter_AddRefs(newUri
), newSpec
);
4168 if (NS_FAILED(rv
)) {
4171 shEntry
->SetURI(newUri
);
4174 rv
= LoadHistoryEntry(shEntry
, LOAD_HISTORY
);
4179 nsDocShell::GetCurrentDescriptor(nsISupports
**aPageDescriptor
)
4181 NS_PRECONDITION(aPageDescriptor
, "Null out param?");
4183 *aPageDescriptor
= nsnull
;
4185 nsISHEntry
* src
= mOSHE
? mOSHE
: mLSHE
;
4187 nsCOMPtr
<nsISHEntry
> dest
;
4189 nsresult rv
= src
->Clone(getter_AddRefs(dest
));
4190 if (NS_FAILED(rv
)) {
4194 // null out inappropriate cloned attributes...
4195 dest
->SetParent(nsnull
);
4196 dest
->SetIsSubFrame(PR_FALSE
);
4198 return CallQueryInterface(dest
, aPageDescriptor
);
4201 return NS_ERROR_NOT_AVAILABLE
;
4205 //*****************************************************************************
4206 // nsDocShell::nsIBaseWindow
4207 //*****************************************************************************
4210 nsDocShell::InitWindow(nativeWindow parentNativeWindow
,
4211 nsIWidget
* parentWidget
, PRInt32 x
, PRInt32 y
,
4212 PRInt32 cx
, PRInt32 cy
)
4214 SetParentWidget(parentWidget
);
4215 SetPositionAndSize(x
, y
, cx
, cy
, PR_FALSE
);
4221 nsDocShell::Create()
4224 // We've already been created
4228 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
4229 "Unexpected item type in docshell");
4231 nsresult rv
= NS_ERROR_FAILURE
;
4232 mPrefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
);
4233 NS_ENSURE_SUCCESS(rv
, rv
);
4237 rv
= mPrefs
->GetBoolPref("browser.frames.enabled", &tmpbool
);
4238 if (NS_SUCCEEDED(rv
))
4239 mAllowSubframes
= tmpbool
;
4241 if (gValidateOrigin
== (PRBool
)0xffffffff) {
4242 // Check pref to see if we should prevent frameset spoofing
4243 rv
= mPrefs
->GetBoolPref("browser.frame.validate_origin", &tmpbool
);
4244 if (NS_SUCCEEDED(rv
)) {
4245 gValidateOrigin
= tmpbool
;
4247 gValidateOrigin
= PR_TRUE
;
4251 // Should we use XUL error pages instead of alerts if possible?
4252 rv
= mPrefs
->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool
);
4253 if (NS_SUCCEEDED(rv
))
4254 mUseErrorPages
= tmpbool
;
4256 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
, &rv
));
4257 if (NS_SUCCEEDED(rv
) && mObserveErrorPages
) {
4258 prefs
->AddObserver("browser.xul.error_pages.enabled", this, PR_FALSE
);
4261 nsCOMPtr
<nsIObserverService
> serv
= do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
4263 const char* msg
= mItemType
== typeContent
?
4264 NS_WEBNAVIGATION_CREATE
: NS_CHROME_WEBNAVIGATION_CREATE
;
4265 serv
->NotifyObservers(GetAsSupports(this), msg
, nsnull
);
4272 nsDocShell::Destroy()
4274 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
4275 "Unexpected item type in docshell");
4277 if (!mIsBeingDestroyed
) {
4278 nsCOMPtr
<nsIObserverService
> serv
=
4279 do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
4281 const char* msg
= mItemType
== typeContent
?
4282 NS_WEBNAVIGATION_DESTROY
: NS_CHROME_WEBNAVIGATION_DESTROY
;
4283 serv
->NotifyObservers(GetAsSupports(this), msg
, nsnull
);
4287 mIsBeingDestroyed
= PR_TRUE
;
4289 // Remove our pref observers
4290 if (mObserveErrorPages
) {
4291 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
));
4293 prefs
->RemoveObserver("browser.xul.error_pages.enabled", this);
4294 mObserveErrorPages
= PR_FALSE
;
4298 // Make sure to blow away our mLoadingURI just in case. No loads
4299 // from inside this pagehide.
4300 mLoadingURI
= nsnull
;
4302 // Fire unload event before we blow anything away.
4303 (void) FirePageHideNotification(PR_TRUE
);
4305 // Clear pointers to any detached nsEditorData that's lying
4306 // around in shistory entries. Breaks cycle. See bug 430921.
4308 mOSHE
->SetEditorData(nsnull
);
4310 mLSHE
->SetEditorData(nsnull
);
4312 // Note: mContentListener can be null if Init() failed and we're being
4313 // called from the destructor.
4314 if (mContentListener
) {
4315 mContentListener
->DropDocShellreference();
4316 mContentListener
->SetParentContentListener(nsnull
);
4317 // Note that we do NOT set mContentListener to null here; that
4318 // way if someone tries to do a load in us after this point
4319 // the nsDSURIContentListener will block it. All of which
4320 // means that we should do this before calling Stop(), of
4324 // Stop any URLs that are currently being loaded...
4325 Stop(nsIWebNavigation::STOP_ALL
);
4327 mEditorData
= nsnull
;
4329 mTransferableHookData
= nsnull
;
4331 // Save the state of the current document, before destroying the window.
4332 // This is needed to capture the state of a frameset when the new document
4333 // causes the frameset to be destroyed...
4334 PersistLayoutHistoryState();
4336 // Remove this docshell from its parent's child list
4337 nsCOMPtr
<nsIDocShellTreeItem
> docShellParentAsItem
=
4338 do_QueryInterface(GetAsSupports(mParent
));
4339 if (docShellParentAsItem
)
4340 docShellParentAsItem
->RemoveChild(this);
4342 if (mContentViewer
) {
4343 mContentViewer
->Close(nsnull
);
4344 mContentViewer
->Destroy();
4345 mContentViewer
= nsnull
;
4348 nsDocLoader::Destroy();
4350 mParentWidget
= nsnull
;
4351 mCurrentURI
= nsnull
;
4353 if (mScriptGlobal
) {
4354 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
4355 win
->SetDocShell(nsnull
);
4357 mScriptGlobal
= nsnull
;
4360 if (mSessionHistory
) {
4361 // We want to destroy these content viewers now rather than
4362 // letting their destruction wait for the session history
4363 // entries to get garbage collected. (Bug 488394)
4364 nsCOMPtr
<nsISHistoryInternal
> shPrivate
=
4365 do_QueryInterface(mSessionHistory
);
4367 shPrivate
->EvictAllContentViewers();
4369 mSessionHistory
= nsnull
;
4372 SetTreeOwner(nsnull
);
4374 // required to break ref cycle
4375 mSecurityUI
= nsnull
;
4377 // Cancel any timers that were set for this docshell; this is needed
4378 // to break the cycle between us and the timers.
4379 CancelRefreshURITimers();
4384 nsDocShell::SetPosition(PRInt32 x
, PRInt32 y
)
4390 NS_ENSURE_SUCCESS(mContentViewer
->Move(x
, y
), NS_ERROR_FAILURE
);
4396 nsDocShell::GetPosition(PRInt32
* aX
, PRInt32
* aY
)
4398 PRInt32 dummyHolder
;
4399 return GetPositionAndSize(aX
, aY
, &dummyHolder
, &dummyHolder
);
4403 nsDocShell::SetSize(PRInt32 aCX
, PRInt32 aCY
, PRBool aRepaint
)
4405 PRInt32 x
= 0, y
= 0;
4406 GetPosition(&x
, &y
);
4407 return SetPositionAndSize(x
, y
, aCX
, aCY
, aRepaint
);
4411 nsDocShell::GetSize(PRInt32
* aCX
, PRInt32
* aCY
)
4413 PRInt32 dummyHolder
;
4414 return GetPositionAndSize(&dummyHolder
, &dummyHolder
, aCX
, aCY
);
4418 nsDocShell::SetPositionAndSize(PRInt32 x
, PRInt32 y
, PRInt32 cx
,
4419 PRInt32 cy
, PRBool fRepaint
)
4424 mBounds
.height
= cy
;
4426 // Hold strong ref, since SetBounds can make us null out mContentViewer
4427 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
4429 //XXX Border figured in here or is that handled elsewhere?
4430 NS_ENSURE_SUCCESS(viewer
->SetBounds(mBounds
), NS_ERROR_FAILURE
);
4437 nsDocShell::GetPositionAndSize(PRInt32
* x
, PRInt32
* y
, PRInt32
* cx
,
4440 // We should really consider just getting this information from
4441 // our window instead of duplicating the storage and code...
4443 // Caller wants to know our size; make sure to give them up to
4444 // date information.
4445 nsCOMPtr
<nsIDOMDocument
> document(do_GetInterface(GetAsSupports(mParent
)));
4446 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(document
));
4448 doc
->FlushPendingNotifications(Flush_Layout
);
4452 DoGetPositionAndSize(x
, y
, cx
, cy
);
4457 nsDocShell::DoGetPositionAndSize(PRInt32
* x
, PRInt32
* y
, PRInt32
* cx
,
4465 *cx
= mBounds
.width
;
4467 *cy
= mBounds
.height
;
4471 nsDocShell::Repaint(PRBool aForce
)
4473 nsCOMPtr
<nsIPresShell
> presShell
;
4474 GetPresShell(getter_AddRefs(presShell
));
4475 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
4477 nsIViewManager
* viewManager
= presShell
->GetViewManager();
4478 NS_ENSURE_TRUE(viewManager
, NS_ERROR_FAILURE
);
4480 // what about aForce ?
4481 NS_ENSURE_SUCCESS(viewManager
->UpdateAllViews(0), NS_ERROR_FAILURE
);
4486 nsDocShell::GetParentWidget(nsIWidget
** parentWidget
)
4488 NS_ENSURE_ARG_POINTER(parentWidget
);
4490 *parentWidget
= mParentWidget
;
4491 NS_IF_ADDREF(*parentWidget
);
4497 nsDocShell::SetParentWidget(nsIWidget
* aParentWidget
)
4499 mParentWidget
= aParentWidget
;
4505 nsDocShell::GetParentNativeWindow(nativeWindow
* parentNativeWindow
)
4507 NS_ENSURE_ARG_POINTER(parentNativeWindow
);
4510 *parentNativeWindow
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
4512 *parentNativeWindow
= nsnull
;
4518 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow
)
4520 return NS_ERROR_NOT_IMPLEMENTED
;
4524 nsDocShell::GetVisibility(PRBool
* aVisibility
)
4526 NS_ENSURE_ARG_POINTER(aVisibility
);
4528 *aVisibility
= PR_FALSE
;
4530 if (!mContentViewer
)
4533 nsCOMPtr
<nsIPresShell
> presShell
;
4534 GetPresShell(getter_AddRefs(presShell
));
4538 // get the view manager
4539 nsIViewManager
* vm
= presShell
->GetViewManager();
4540 NS_ENSURE_TRUE(vm
, NS_ERROR_FAILURE
);
4542 // get the root view
4543 nsIView
*view
= nsnull
; // views are not ref counted
4544 NS_ENSURE_SUCCESS(vm
->GetRootView(view
), NS_ERROR_FAILURE
);
4545 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
4547 // if our root view is hidden, we are not visible
4548 if (view
->GetVisibility() == nsViewVisibility_kHide
)
4551 // otherwise, we must walk up the document and view trees checking
4552 // for a hidden view, unless we're an off screen browser, which
4553 // would make this test meaningless.
4555 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= this;
4556 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
4557 treeItem
->GetParent(getter_AddRefs(parentItem
));
4558 while (parentItem
) {
4559 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(treeItem
));
4560 docShell
->GetPresShell(getter_AddRefs(presShell
));
4562 nsCOMPtr
<nsIDocShell
> parentDS
= do_QueryInterface(parentItem
);
4563 nsCOMPtr
<nsIPresShell
> pPresShell
;
4564 parentDS
->GetPresShell(getter_AddRefs(pPresShell
));
4566 // Null-check for crash in bug 267804
4568 NS_NOTREACHED("parent docshell has null pres shell");
4572 nsIContent
*shellContent
=
4573 pPresShell
->GetDocument()->FindContentForSubDocument(presShell
->GetDocument());
4574 NS_ASSERTION(shellContent
, "subshell not in the map");
4576 nsIFrame
* frame
= shellContent
? shellContent
->GetPrimaryFrame() : nsnull
;
4577 PRBool isDocShellOffScreen
= PR_FALSE
;
4578 docShell
->GetIsOffScreenBrowser(&isDocShellOffScreen
);
4579 if (frame
&& !frame
->AreAncestorViewsVisible() && !isDocShellOffScreen
)
4582 treeItem
= parentItem
;
4583 treeItem
->GetParent(getter_AddRefs(parentItem
));
4586 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
4587 if (!treeOwnerAsWin
) {
4588 *aVisibility
= PR_TRUE
;
4592 // Check with the tree owner as well to give embedders a chance to
4593 // expose visibility as well.
4594 return treeOwnerAsWin
->GetVisibility(aVisibility
);
4598 nsDocShell::SetIsOffScreenBrowser(PRBool aIsOffScreen
)
4600 mIsOffScreenBrowser
= aIsOffScreen
;
4605 nsDocShell::GetIsOffScreenBrowser(PRBool
*aIsOffScreen
)
4607 *aIsOffScreen
= mIsOffScreenBrowser
;
4612 nsDocShell::SetVisibility(PRBool aVisibility
)
4614 if (!mContentViewer
)
4617 mContentViewer
->Show();
4620 mContentViewer
->Hide();
4627 nsDocShell::GetEnabled(PRBool
*aEnabled
)
4629 NS_ENSURE_ARG_POINTER(aEnabled
);
4630 *aEnabled
= PR_TRUE
;
4631 return NS_ERROR_NOT_IMPLEMENTED
;
4635 nsDocShell::SetEnabled(PRBool aEnabled
)
4637 return NS_ERROR_NOT_IMPLEMENTED
;
4641 nsDocShell::GetBlurSuppression(PRBool
*aBlurSuppression
)
4643 NS_ENSURE_ARG_POINTER(aBlurSuppression
);
4644 *aBlurSuppression
= PR_FALSE
;
4645 return NS_ERROR_NOT_IMPLEMENTED
;
4649 nsDocShell::SetBlurSuppression(PRBool aBlurSuppression
)
4651 return NS_ERROR_NOT_IMPLEMENTED
;
4655 nsDocShell::SetFocus()
4661 nsDocShell::GetMainWidget(nsIWidget
** aMainWidget
)
4663 // We don't create our own widget, so simply return the parent one.
4664 return GetParentWidget(aMainWidget
);
4668 nsDocShell::GetTitle(PRUnichar
** aTitle
)
4670 NS_ENSURE_ARG_POINTER(aTitle
);
4672 *aTitle
= ToNewUnicode(mTitle
);
4677 nsDocShell::SetTitle(const PRUnichar
* aTitle
)
4679 // Store local title
4682 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
4683 GetSameTypeParent(getter_AddRefs(parent
));
4685 // When title is set on the top object it should then be passed to the
4688 nsCOMPtr
<nsIBaseWindow
>
4689 treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
4691 treeOwnerAsWin
->SetTitle(aTitle
);
4694 if (mGlobalHistory
&& mCurrentURI
&& mLoadType
!= LOAD_ERROR_PAGE
) {
4695 mGlobalHistory
->SetPageTitle(mCurrentURI
, nsString(mTitle
));
4699 // Update SessionHistory with the document's title.
4700 if (mOSHE
&& mLoadType
!= LOAD_BYPASS_HISTORY
&&
4701 mLoadType
!= LOAD_ERROR_PAGE
) {
4703 mOSHE
->SetTitle(mTitle
);
4709 //*****************************************************************************
4710 // nsDocShell::nsIScrollable
4711 //*****************************************************************************
4714 nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation
, PRInt32
* curPos
)
4716 NS_ENSURE_ARG_POINTER(curPos
);
4718 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4719 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4721 nsPoint pt
= sf
->GetScrollPosition();
4723 switch (scrollOrientation
) {
4724 case ScrollOrientation_X
:
4728 case ScrollOrientation_Y
:
4733 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4738 nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation
, PRInt32 curPos
)
4740 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4741 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4743 nsPoint pt
= sf
->GetScrollPosition();
4745 switch (scrollOrientation
) {
4746 case ScrollOrientation_X
:
4750 case ScrollOrientation_Y
:
4755 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4758 sf
->ScrollTo(pt
, nsIScrollableFrame::INSTANT
);
4763 nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos
, PRInt32 curVerticalPos
)
4765 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4766 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4768 sf
->ScrollTo(nsPoint(curHorizontalPos
, curVerticalPos
),
4769 nsIScrollableFrame::INSTANT
);
4773 // XXX This is wrong
4775 nsDocShell::GetScrollRange(PRInt32 scrollOrientation
,
4776 PRInt32
* minPos
, PRInt32
* maxPos
)
4778 NS_ENSURE_ARG_POINTER(minPos
&& maxPos
);
4780 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4781 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4783 nsSize portSize
= sf
->GetScrollPortRect().Size();
4784 nsRect range
= sf
->GetScrollRange();
4786 switch (scrollOrientation
) {
4787 case ScrollOrientation_X
:
4789 *maxPos
= range
.XMost() + portSize
.width
;
4792 case ScrollOrientation_Y
:
4794 *maxPos
= range
.YMost() + portSize
.height
;
4798 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4803 nsDocShell::SetScrollRange(PRInt32 scrollOrientation
,
4804 PRInt32 minPos
, PRInt32 maxPos
)
4808 Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
4809 something less than the current thumb position, curPos is set = to maxPos.
4811 @return NS_OK - Setting or Getting completed successfully.
4812 NS_ERROR_INVALID_ARG - returned when curPos is not within the
4815 return NS_ERROR_FAILURE
;
4819 nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos
,
4820 PRInt32 maxHorizontalPos
, PRInt32 minVerticalPos
,
4821 PRInt32 maxVerticalPos
)
4825 Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
4826 something less than the current thumb position, curPos is set = to maxPos.
4828 @return NS_OK - Setting or Getting completed successfully.
4829 NS_ERROR_INVALID_ARG - returned when curPos is not within the
4832 return NS_ERROR_FAILURE
;
4835 // This returns setting for all documents in this docshell
4837 nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation
,
4838 PRInt32
* scrollbarPref
)
4840 NS_ENSURE_ARG_POINTER(scrollbarPref
);
4841 switch (scrollOrientation
) {
4842 case ScrollOrientation_X
:
4843 *scrollbarPref
= mDefaultScrollbarPref
.x
;
4846 case ScrollOrientation_Y
:
4847 *scrollbarPref
= mDefaultScrollbarPref
.y
;
4851 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4853 return NS_ERROR_FAILURE
;
4856 // Set scrolling preference for all documents in this shell
4858 // There are three possible values stored in the shell:
4859 // 1) nsIScrollable::Scrollbar_Never = no scrollbar
4860 // 2) nsIScrollable::Scrollbar_Auto = scrollbar appears if the document
4861 // being displayed would normally have scrollbar
4862 // 3) nsIScrollable::Scrollbar_Always = scrollbar always appears
4864 // One important client is nsHTMLFrameInnerFrame::CreateWebShell()
4866 nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation
,
4867 PRInt32 scrollbarPref
)
4869 switch (scrollOrientation
) {
4870 case ScrollOrientation_X
:
4871 mDefaultScrollbarPref
.x
= scrollbarPref
;
4874 case ScrollOrientation_Y
:
4875 mDefaultScrollbarPref
.y
= scrollbarPref
;
4879 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
4881 return NS_ERROR_FAILURE
;
4885 nsDocShell::GetScrollbarVisibility(PRBool
* verticalVisible
,
4886 PRBool
* horizontalVisible
)
4888 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4889 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4891 PRUint32 scrollbarVisibility
= sf
->GetScrollbarVisibility();
4892 if (verticalVisible
)
4893 *verticalVisible
= (scrollbarVisibility
& nsIScrollableFrame::VERTICAL
) != 0;
4894 if (horizontalVisible
)
4895 *horizontalVisible
= (scrollbarVisibility
& nsIScrollableFrame::HORIZONTAL
) != 0;
4900 //*****************************************************************************
4901 // nsDocShell::nsITextScroll
4902 //*****************************************************************************
4905 nsDocShell::ScrollByLines(PRInt32 numLines
)
4907 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4908 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4910 sf
->ScrollBy(nsIntPoint(0, numLines
), nsIScrollableFrame::LINES
,
4911 nsIScrollableFrame::SMOOTH
);
4916 nsDocShell::ScrollByPages(PRInt32 numPages
)
4918 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4919 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4921 sf
->ScrollBy(nsIntPoint(0, numPages
), nsIScrollableFrame::PAGES
,
4922 nsIScrollableFrame::SMOOTH
);
4926 //*****************************************************************************
4927 // nsDocShell::nsIScriptGlobalObjectOwner
4928 //*****************************************************************************
4930 nsIScriptGlobalObject
*
4931 nsDocShell::GetScriptGlobalObject()
4933 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nsnull
);
4935 return mScriptGlobal
;
4938 //*****************************************************************************
4939 // nsDocShell::nsIRefreshURI
4940 //*****************************************************************************
4943 nsDocShell::RefreshURI(nsIURI
* aURI
, PRInt32 aDelay
, PRBool aRepeat
,
4944 PRBool aMetaRefresh
)
4946 NS_ENSURE_ARG(aURI
);
4948 /* Check if Meta refresh/redirects are permitted. Some
4949 * embedded applications may not want to do this.
4950 * Must do this before sending out NOTIFY_REFRESH events
4951 * because listeners may have side effects (e.g. displaying a
4952 * button to manually trigger the refresh later).
4954 PRBool allowRedirects
= PR_TRUE
;
4955 GetAllowMetaRedirects(&allowRedirects
);
4956 if (!allowRedirects
)
4959 // If any web progress listeners are listening for NOTIFY_REFRESH events,
4960 // give them a chance to block this refresh.
4962 nsresult rv
= aURI
->Equals(mCurrentURI
, &sameURI
);
4965 if (!RefreshAttempted(this, aURI
, aDelay
, sameURI
))
4968 nsRefreshTimer
*refreshTimer
= new nsRefreshTimer();
4969 NS_ENSURE_TRUE(refreshTimer
, NS_ERROR_OUT_OF_MEMORY
);
4970 PRUint32 busyFlags
= 0;
4971 GetBusyFlags(&busyFlags
);
4973 nsCOMPtr
<nsISupports
> dataRef
= refreshTimer
; // Get the ref count to 1
4975 refreshTimer
->mDocShell
= this;
4976 refreshTimer
->mURI
= aURI
;
4977 refreshTimer
->mDelay
= aDelay
;
4978 refreshTimer
->mRepeat
= aRepeat
;
4979 refreshTimer
->mMetaRefresh
= aMetaRefresh
;
4981 if (!mRefreshURIList
) {
4982 NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList
)),
4986 if (busyFlags
& BUSY_FLAGS_BUSY
) {
4987 // We are busy loading another page. Don't create the
4988 // timer right now. Instead queue up the request and trigger the
4989 // timer in EndPageLoad().
4990 mRefreshURIList
->AppendElement(refreshTimer
);
4993 // There is no page loading going on right now. Create the
4994 // timer and fire it right away.
4995 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance("@mozilla.org/timer;1");
4996 NS_ENSURE_TRUE(timer
, NS_ERROR_FAILURE
);
4998 mRefreshURIList
->AppendElement(timer
); // owning timer ref
4999 timer
->InitWithCallback(refreshTimer
, aDelay
, nsITimer::TYPE_ONE_SHOT
);
5005 nsDocShell::ForceRefreshURIFromTimer(nsIURI
* aURI
,
5007 PRBool aMetaRefresh
,
5010 NS_PRECONDITION(aTimer
, "Must have a timer here");
5012 // Remove aTimer from mRefreshURIList if needed
5013 if (mRefreshURIList
) {
5015 mRefreshURIList
->Count(&n
);
5017 for (PRUint32 i
= 0; i
< n
; ++i
) {
5018 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
5019 if (timer
== aTimer
) {
5020 mRefreshURIList
->RemoveElementAt(i
);
5026 return ForceRefreshURI(aURI
, aDelay
, aMetaRefresh
);
5030 nsDocShell::ForceRefreshURI(nsIURI
* aURI
,
5032 PRBool aMetaRefresh
)
5034 NS_ENSURE_ARG(aURI
);
5036 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
5037 CreateLoadInfo(getter_AddRefs(loadInfo
));
5038 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
5040 /* We do need to pass in a referrer, but we don't want it to
5041 * be sent to the server.
5043 loadInfo
->SetSendReferrer(PR_FALSE
);
5045 /* for most refreshes the current URI is an appropriate
5048 loadInfo
->SetReferrer(mCurrentURI
);
5050 /* Don't ever "guess" on which owner to use to avoid picking
5051 * the current owner.
5053 loadInfo
->SetOwnerIsExplicit(PR_TRUE
);
5055 /* Check if this META refresh causes a redirection
5058 PRBool equalUri
= PR_FALSE
;
5059 nsresult rv
= aURI
->Equals(mCurrentURI
, &equalUri
);
5060 if (NS_SUCCEEDED(rv
) && (!equalUri
) && aMetaRefresh
&&
5061 aDelay
<= REFRESH_REDIRECT_TIMER
) {
5063 /* It is a META refresh based redirection within the threshold time
5064 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
5065 * Pass a REPLACE flag to LoadURI().
5067 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace
);
5069 /* for redirects we mimic HTTP, which passes the
5072 nsCOMPtr
<nsIURI
> internalReferrer
;
5073 GetReferringURI(getter_AddRefs(internalReferrer
));
5074 if (internalReferrer
) {
5075 loadInfo
->SetReferrer(internalReferrer
);
5079 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadRefresh
);
5083 * LoadURI(...) will cancel all refresh timers... This causes the
5084 * Timer and its refreshData instance to be released...
5086 LoadURI(aURI
, loadInfo
, nsIWebNavigation::LOAD_FLAGS_NONE
, PR_TRUE
);
5092 nsDocShell::SetupRefreshURIFromHeader(nsIURI
* aBaseURI
,
5093 const nsACString
& aHeader
)
5095 // Refresh headers are parsed with the following format in mind
5096 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
5097 // By the time we are here, the following is true:
5098 // header = "REFRESH"
5099 // content = "5; URL=http://uri" // note the URL attribute is
5100 // optional, if it is absent, the currently loaded url is used.
5101 // Also note that the seconds and URL separator can be either
5102 // a ';' or a ','. The ',' separator should be illegal but CNN
5105 // We need to handle the following strings, where
5106 // - X is a set of digits
5107 // - URI is either a relative or absolute URI
5109 // Note that URI should start with "url=" but we allow omission
5112 // empty string. use the currently loaded URI
5113 // and refresh immediately.
5114 // "X" || "X;" || "X,"
5115 // Refresh the currently loaded URI in X seconds.
5116 // "X; URI" || "X, URI"
5117 // Refresh using URI as the destination in X seconds.
5118 // "URI" || "; URI" || ", URI"
5119 // Refresh immediately using URI as the destination.
5121 // Currently, anything immediately following the URI, if
5122 // separated by any char in the set "'\"\t\r\n " will be
5123 // ignored. So "10; url=go.html ; foo=bar" will work,
5124 // and so will "10; url='go.html'; foo=bar". However,
5125 // "10; url=go.html; foo=bar" will result in the uri
5126 // "go.html;" since ';' and ',' are valid uri characters.
5128 // Note that we need to remove any tokens wrapping the URI.
5129 // These tokens currently include spaces, double and single
5132 // when done, seconds is 0 or the given number of seconds
5133 // uriAttrib is empty or the URI specified
5134 nsCAutoString uriAttrib
;
5135 PRInt32 seconds
= 0;
5136 PRBool specifiesSeconds
= PR_FALSE
;
5138 nsACString::const_iterator iter
, tokenStart
, doneIterating
;
5140 aHeader
.BeginReading(iter
);
5141 aHeader
.EndReading(doneIterating
);
5143 // skip leading whitespace
5144 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5149 // skip leading + and -
5150 if (iter
!= doneIterating
&& (*iter
== '-' || *iter
== '+'))
5154 while (iter
!= doneIterating
&& (*iter
>= '0' && *iter
<= '9')) {
5155 seconds
= seconds
* 10 + (*iter
- '0');
5156 specifiesSeconds
= PR_TRUE
;
5160 if (iter
!= doneIterating
) {
5161 // if we started with a '-', number is negative
5162 if (*tokenStart
== '-')
5165 // skip to next ';' or ','
5166 nsACString::const_iterator iterAfterDigit
= iter
;
5167 while (iter
!= doneIterating
&& !(*iter
== ';' || *iter
== ','))
5169 if (specifiesSeconds
)
5171 // Non-whitespace characters here mean that the string is
5172 // malformed but tolerate sites that specify a decimal point,
5173 // even though meta refresh only works on whole seconds.
5174 if (iter
== iterAfterDigit
&&
5175 !nsCRT::IsAsciiSpace(*iter
) && *iter
!= '.')
5177 // The characters between the seconds and the next
5178 // section are just garbage!
5179 // e.g. content="2a0z+,URL=http://www.mozilla.org/"
5180 // Just ignore this redirect.
5181 return NS_ERROR_FAILURE
;
5183 else if (nsCRT::IsAsciiSpace(*iter
))
5185 // We've had at least one whitespace so tolerate the mistake
5186 // and drop through.
5187 // e.g. content="10 foo"
5195 // skip any remaining whitespace
5196 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5200 if (iter
!= doneIterating
&& (*iter
== ';' || *iter
== ',')) {
5205 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5209 // possible start of URI
5212 // skip "url = " to real start of URI
5213 if (iter
!= doneIterating
&& (*iter
== 'u' || *iter
== 'U')) {
5215 if (iter
!= doneIterating
&& (*iter
== 'r' || *iter
== 'R')) {
5217 if (iter
!= doneIterating
&& (*iter
== 'l' || *iter
== 'L')) {
5221 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5224 if (iter
!= doneIterating
&& *iter
== '=') {
5228 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5231 // found real start of URI
5238 // skip a leading '"' or '\''.
5240 PRBool isQuotedURI
= PR_FALSE
;
5241 if (tokenStart
!= doneIterating
&& (*tokenStart
== '"' || *tokenStart
== '\''))
5243 isQuotedURI
= PR_TRUE
;
5247 // set iter to start of URI
5250 // tokenStart here points to the beginning of URI
5252 // grab the rest of the URI
5253 while (iter
!= doneIterating
)
5255 if (isQuotedURI
&& (*iter
== '"' || *iter
== '\''))
5260 // move iter one back if the last character is a '"' or '\''
5261 if (iter
!= tokenStart
&& isQuotedURI
) {
5263 if (!(*iter
== '"' || *iter
== '\''))
5267 // URI is whatever's contained from tokenStart to iter.
5268 // note: if tokenStart == doneIterating, so is iter.
5270 nsresult rv
= NS_OK
;
5272 nsCOMPtr
<nsIURI
> uri
;
5273 PRBool specifiesURI
= PR_FALSE
;
5274 if (tokenStart
== iter
) {
5278 uriAttrib
= Substring(tokenStart
, iter
);
5279 // NS_NewURI takes care of any whitespace surrounding the URL
5280 rv
= NS_NewURI(getter_AddRefs(uri
), uriAttrib
, nsnull
, aBaseURI
);
5281 specifiesURI
= PR_TRUE
;
5284 // No URI or seconds were specified
5285 if (!specifiesSeconds
&& !specifiesURI
)
5287 // Do nothing because the alternative is to spin around in a refresh
5289 return NS_ERROR_FAILURE
;
5292 if (NS_SUCCEEDED(rv
)) {
5293 nsCOMPtr
<nsIScriptSecurityManager
>
5294 securityManager(do_GetService
5295 (NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
5296 if (NS_SUCCEEDED(rv
)) {
5297 rv
= securityManager
->
5298 CheckLoadURI(aBaseURI
, uri
,
5299 nsIScriptSecurityManager::
5300 LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
);
5302 if (NS_SUCCEEDED(rv
)) {
5303 PRBool isjs
= PR_TRUE
;
5304 rv
= NS_URIChainHasFlags(uri
,
5305 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT
, &isjs
);
5306 NS_ENSURE_SUCCESS(rv
, rv
);
5309 return NS_ERROR_FAILURE
;
5313 if (NS_SUCCEEDED(rv
)) {
5314 // Since we can't travel back in time yet, just pretend
5315 // negative numbers do nothing at all.
5317 return NS_ERROR_FAILURE
;
5319 rv
= RefreshURI(uri
, seconds
* 1000, PR_FALSE
, PR_TRUE
);
5326 NS_IMETHODIMP
nsDocShell::SetupRefreshURI(nsIChannel
* aChannel
)
5329 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
, &rv
));
5330 if (NS_SUCCEEDED(rv
)) {
5331 nsCAutoString refreshHeader
;
5332 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
5335 if (!refreshHeader
.IsEmpty()) {
5336 SetupReferrerFromChannel(aChannel
);
5337 rv
= SetupRefreshURIFromHeader(mCurrentURI
, refreshHeader
);
5338 if (NS_SUCCEEDED(rv
)) {
5339 return NS_REFRESHURI_HEADER_FOUND
;
5347 DoCancelRefreshURITimers(nsISupportsArray
* aTimerList
)
5353 aTimerList
->Count(&n
);
5356 nsCOMPtr
<nsITimer
> timer(do_QueryElementAt(aTimerList
, --n
));
5358 aTimerList
->RemoveElementAt(n
); // bye bye owning timer ref
5366 nsDocShell::CancelRefreshURITimers()
5368 DoCancelRefreshURITimers(mRefreshURIList
);
5369 DoCancelRefreshURITimers(mSavedRefreshURIList
);
5370 mRefreshURIList
= nsnull
;
5371 mSavedRefreshURIList
= nsnull
;
5377 nsDocShell::GetRefreshPending(PRBool
* _retval
)
5379 if (!mRefreshURIList
) {
5380 *_retval
= PR_FALSE
;
5385 nsresult rv
= mRefreshURIList
->Count(&count
);
5386 if (NS_SUCCEEDED(rv
))
5387 *_retval
= (count
!= 0);
5392 nsDocShell::SuspendRefreshURIs()
5394 if (mRefreshURIList
) {
5396 mRefreshURIList
->Count(&n
);
5398 for (PRUint32 i
= 0; i
< n
; ++i
) {
5399 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
5401 continue; // this must be a nsRefreshURI already
5403 // Replace this timer object with a nsRefreshTimer object.
5404 nsCOMPtr
<nsITimerCallback
> callback
;
5405 timer
->GetCallback(getter_AddRefs(callback
));
5409 nsCOMPtr
<nsITimerCallback
> rt
= do_QueryInterface(callback
);
5410 NS_ASSERTION(rt
, "RefreshURIList timer callbacks should only be RefreshTimer objects");
5412 mRefreshURIList
->ReplaceElementAt(rt
, i
);
5416 // Suspend refresh URIs for our child shells as well.
5417 PRInt32 n
= mChildList
.Count();
5419 for (PRInt32 i
= 0; i
< n
; ++i
) {
5420 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
5422 shell
->SuspendRefreshURIs();
5429 nsDocShell::ResumeRefreshURIs()
5431 RefreshURIFromQueue();
5433 // Resume refresh URIs for our child shells as well.
5434 PRInt32 n
= mChildList
.Count();
5436 for (PRInt32 i
= 0; i
< n
; ++i
) {
5437 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
5439 shell
->ResumeRefreshURIs();
5446 nsDocShell::RefreshURIFromQueue()
5448 if (!mRefreshURIList
)
5451 mRefreshURIList
->Count(&n
);
5454 nsCOMPtr
<nsISupports
> element
;
5455 mRefreshURIList
->GetElementAt(--n
, getter_AddRefs(element
));
5456 nsCOMPtr
<nsITimerCallback
> refreshInfo(do_QueryInterface(element
));
5459 // This is the nsRefreshTimer object, waiting to be
5460 // setup in a timer object and fired.
5461 // Create the timer and trigger it.
5462 PRUint32 delay
= static_cast<nsRefreshTimer
*>(static_cast<nsITimerCallback
*>(refreshInfo
))->GetDelay();
5463 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance("@mozilla.org/timer;1");
5465 // Replace the nsRefreshTimer element in the queue with
5466 // its corresponding timer object, so that in case another
5467 // load comes through before the timer can go off, the timer will
5468 // get cancelled in CancelRefreshURITimer()
5469 mRefreshURIList
->ReplaceElementAt(timer
, n
);
5470 timer
->InitWithCallback(refreshInfo
, delay
, nsITimer::TYPE_ONE_SHOT
);
5478 //*****************************************************************************
5479 // nsDocShell::nsIContentViewerContainer
5480 //*****************************************************************************
5483 nsDocShell::Embed(nsIContentViewer
* aContentViewer
,
5484 const char *aCommand
, nsISupports
* aExtraInfo
)
5486 // Save the LayoutHistoryState of the previous document, before
5487 // setting up new document
5488 PersistLayoutHistoryState();
5490 nsresult rv
= SetupNewViewer(aContentViewer
);
5492 // If we are loading a wyciwyg url from history, change the base URI for
5493 // the document to the original http url that created the document.write().
5494 // This makes sure that all relative urls in a document.written page loaded
5495 // via history work properly.
5497 (mLoadType
& LOAD_CMD_HISTORY
||
5498 mLoadType
== LOAD_RELOAD_NORMAL
||
5499 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
)){
5500 PRBool isWyciwyg
= PR_FALSE
;
5501 // Check if the url is wyciwyg
5502 rv
= mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
5503 if (isWyciwyg
&& NS_SUCCEEDED(rv
))
5504 SetBaseUrlForWyciwyg(aContentViewer
);
5506 // XXX What if SetupNewViewer fails?
5508 // Restore the editing state, if it's stored in session history.
5509 if (mLSHE
->HasDetachedEditor()) {
5510 ReattachEditorToWindow(mLSHE
);
5512 SetHistoryEntry(&mOSHE
, mLSHE
);
5515 PRBool updateHistory
= PR_TRUE
;
5517 // Determine if this type of load should update history
5518 switch (mLoadType
) {
5519 case LOAD_NORMAL_REPLACE
:
5520 case LOAD_STOP_CONTENT_AND_REPLACE
:
5521 case LOAD_RELOAD_BYPASS_CACHE
:
5522 case LOAD_RELOAD_BYPASS_PROXY
:
5523 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
5524 updateHistory
= PR_FALSE
;
5531 SetLayoutHistoryState(nsnull
);
5536 /* void setIsPrinting (in boolean aIsPrinting); */
5538 nsDocShell::SetIsPrinting(PRBool aIsPrinting
)
5540 mIsPrintingOrPP
= aIsPrinting
;
5544 //*****************************************************************************
5545 // nsDocShell::nsIWebProgressListener
5546 //*****************************************************************************
5549 nsDocShell::OnProgressChange(nsIWebProgress
* aProgress
,
5550 nsIRequest
* aRequest
,
5551 PRInt32 aCurSelfProgress
,
5552 PRInt32 aMaxSelfProgress
,
5553 PRInt32 aCurTotalProgress
,
5554 PRInt32 aMaxTotalProgress
)
5560 nsDocShell::OnStateChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
5561 PRUint32 aStateFlags
, nsresult aStatus
)
5565 if ((~aStateFlags
& (STATE_START
| STATE_IS_NETWORK
)) == 0) {
5566 nsCOMPtr
<nsIWyciwygChannel
> wcwgChannel(do_QueryInterface(aRequest
));
5567 nsCOMPtr
<nsIWebProgress
> webProgress
=
5568 do_QueryInterface(GetAsSupports(this));
5570 // Was the wyciwyg document loaded on this docshell?
5571 if (wcwgChannel
&& !mLSHE
&& (mItemType
== typeContent
) && aProgress
== webProgress
.get()) {
5572 nsCOMPtr
<nsIURI
> uri
;
5573 wcwgChannel
->GetURI(getter_AddRefs(uri
));
5575 PRBool equalUri
= PR_TRUE
;
5576 // Store the wyciwyg url in session history, only if it is
5577 // being loaded fresh for the first time. We don't want
5578 // multiple entries for successive loads
5580 NS_SUCCEEDED(uri
->Equals(mCurrentURI
, &equalUri
)) &&
5582 // This is a document.write(). Get the made-up url
5583 // from the channel and store it in session history.
5584 rv
= AddToSessionHistory(uri
, wcwgChannel
, nsnull
,
5585 getter_AddRefs(mLSHE
));
5586 SetCurrentURI(uri
, aRequest
, PR_TRUE
);
5587 // Save history state of the previous page
5588 rv
= PersistLayoutHistoryState();
5589 // We'll never get an Embed() for this load, so just go ahead
5590 // and SetHistoryEntry now.
5591 SetHistoryEntry(&mOSHE
, mLSHE
);
5595 // Page has begun to load
5596 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_BEFORE_PAGE_LOAD
;
5598 if ((aStateFlags
& STATE_RESTORING
) == 0) {
5599 // Show the progress cursor if the pref is set
5600 PRBool tmpBool
= PR_FALSE
;
5601 if (NS_SUCCEEDED(mPrefs
->GetBoolPref("ui.use_activity_cursor", &tmpBool
))
5603 nsCOMPtr
<nsIWidget
> mainWidget
;
5604 GetMainWidget(getter_AddRefs(mainWidget
));
5606 mainWidget
->SetCursor(eCursor_spinning
);
5611 else if ((~aStateFlags
& (STATE_TRANSFERRING
| STATE_IS_DOCUMENT
)) == 0) {
5613 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_PAGE_LOADING
;
5615 else if ((aStateFlags
& STATE_STOP
) && (aStateFlags
& STATE_IS_NETWORK
)) {
5616 // Page has finished loading
5617 mBusyFlags
= BUSY_FLAGS_NONE
;
5619 // Hide the progress cursor if the pref is set
5620 PRBool tmpBool
= PR_FALSE
;
5621 if (NS_SUCCEEDED(mPrefs
->GetBoolPref("ui.use_activity_cursor", &tmpBool
))
5623 nsCOMPtr
<nsIWidget
> mainWidget
;
5624 GetMainWidget(getter_AddRefs(mainWidget
));
5626 mainWidget
->SetCursor(eCursor_standard
);
5630 if ((~aStateFlags
& (STATE_IS_DOCUMENT
| STATE_STOP
)) == 0) {
5631 nsCOMPtr
<nsIWebProgress
> webProgress
=
5632 do_QueryInterface(GetAsSupports(this));
5633 // Is the document stop notification for this document?
5634 if (aProgress
== webProgress
.get()) {
5635 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
5636 EndPageLoad(aProgress
, channel
, aStatus
);
5639 // note that redirect state changes will go through here as well, but it
5640 // is better to handle those in OnRedirectStateChange where more
5641 // information is available.
5646 nsDocShell::OnLocationChange(nsIWebProgress
* aProgress
,
5647 nsIRequest
* aRequest
, nsIURI
* aURI
)
5649 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5654 nsDocShell::OnRedirectStateChange(nsIChannel
* aOldChannel
,
5655 nsIChannel
* aNewChannel
,
5656 PRUint32 aRedirectFlags
,
5657 PRUint32 aStateFlags
)
5659 NS_ASSERTION(aStateFlags
& STATE_REDIRECTING
,
5660 "Calling OnRedirectStateChange when there is no redirect");
5661 if (!(aStateFlags
& STATE_IS_DOCUMENT
))
5662 return; // not a toplevel document
5664 nsCOMPtr
<nsIGlobalHistory3
> history3(do_QueryInterface(mGlobalHistory
));
5665 nsresult result
= NS_ERROR_NOT_IMPLEMENTED
;
5667 // notify global history of this redirect
5668 result
= history3
->AddDocumentRedirect(aOldChannel
, aNewChannel
,
5669 aRedirectFlags
, !IsFrame());
5672 if (result
== NS_ERROR_NOT_IMPLEMENTED
) {
5673 // when there is no GlobalHistory3, or it doesn't implement
5674 // AddToplevelRedirect, we fall back to GlobalHistory2. Just notify
5675 // that the redirecting page was a rePdirect so it will be link colored
5677 nsCOMPtr
<nsIURI
> oldURI
;
5678 aOldChannel
->GetURI(getter_AddRefs(oldURI
));
5680 return; // nothing to tell anybody about
5681 AddToGlobalHistory(oldURI
, PR_TRUE
, aOldChannel
);
5684 // check if the new load should go through the application cache.
5685 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
5686 do_QueryInterface(aNewChannel
);
5687 if (appCacheChannel
) {
5688 nsCOMPtr
<nsIURI
> newURI
;
5689 aNewChannel
->GetURI(getter_AddRefs(newURI
));
5690 appCacheChannel
->SetChooseApplicationCache(ShouldCheckAppCache(newURI
));
5693 if (!(aRedirectFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
) &&
5694 mLoadType
& (LOAD_CMD_RELOAD
| LOAD_CMD_HISTORY
)) {
5695 mLoadType
= LOAD_NORMAL_REPLACE
;
5696 SetHistoryEntry(&mLSHE
, nsnull
);
5701 nsDocShell::OnStatusChange(nsIWebProgress
* aWebProgress
,
5702 nsIRequest
* aRequest
,
5703 nsresult aStatus
, const PRUnichar
* aMessage
)
5705 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5710 nsDocShell::OnSecurityChange(nsIWebProgress
* aWebProgress
,
5711 nsIRequest
* aRequest
, PRUint32 state
)
5713 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5719 nsDocShell::EndPageLoad(nsIWebProgress
* aProgress
,
5720 nsIChannel
* aChannel
, nsresult aStatus
)
5723 return NS_ERROR_NULL_POINTER
;
5725 nsCOMPtr
<nsIURI
> url
;
5726 nsresult rv
= aChannel
->GetURI(getter_AddRefs(url
));
5727 if (NS_FAILED(rv
)) return rv
;
5729 // clean up reload state for meta charset
5730 if (eCharsetReloadRequested
== mCharsetReloadState
)
5731 mCharsetReloadState
= eCharsetReloadStopOrigional
;
5733 mCharsetReloadState
= eCharsetReloadInit
;
5735 // Save a pointer to the currently-loading history entry.
5736 // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
5737 // entry further down in this method.
5738 nsCOMPtr
<nsISHEntry
> loadingSHE
= mLSHE
;
5741 // one of many safeguards that prevent death and destruction if
5742 // someone is so very very rude as to bring this window down
5743 // during this load handler.
5745 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
5747 // Notify the ContentViewer that the Document has finished loading. This
5748 // will cause any OnLoad(...) and PopState(...) handlers to fire.
5749 if (!mEODForCurrentDocument
&& mContentViewer
) {
5750 // Set the pending state object which will be returned to the page in
5751 // the popstate event.
5752 SetDocPendingStateObj(mLSHE
);
5754 mIsExecutingOnLoadHandler
= PR_TRUE
;
5755 mContentViewer
->LoadComplete(aStatus
);
5756 mIsExecutingOnLoadHandler
= PR_FALSE
;
5758 mEODForCurrentDocument
= PR_TRUE
;
5760 // If all documents have completed their loading
5761 // favor native event dispatch priorities
5763 if (--gNumberOfDocumentsLoading
== 0) {
5764 // Hint to use normal native event dispatch priorities
5765 FavorPerformanceHint(PR_FALSE
, NS_EVENT_STARVATION_DELAY_HINT
);
5768 /* Check if the httpChannel has any cache-control related response headers,
5769 * like no-store, no-cache. If so, update SHEntry so that
5770 * when a user goes back/forward to this page, we appropriately do
5771 * form value restoration or load from server.
5773 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
5774 if (!httpChannel
) // HttpChannel could be hiding underneath a Multipart channel.
5775 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
5778 // figure out if SH should be saving layout state.
5779 PRBool discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
5780 if (mLSHE
&& discardLayoutState
&& (mLoadType
& LOAD_CMD_NORMAL
) &&
5781 (mLoadType
!= LOAD_BYPASS_HISTORY
) && (mLoadType
!= LOAD_ERROR_PAGE
))
5782 mLSHE
->SetSaveLayoutStateFlag(PR_FALSE
);
5785 // Clear mLSHE after calling the onLoadHandlers. This way, if the
5786 // onLoadHandler tries to load something different in
5787 // itself or one of its children, we can deal with it appropriately.
5789 mLSHE
->SetLoadType(nsIDocShellLoadInfo::loadHistory
);
5791 // Clear the mLSHE reference to indicate document loading is done one
5793 SetHistoryEntry(&mLSHE
, nsnull
);
5795 // if there's a refresh header in the channel, this method
5796 // will set it up for us.
5797 RefreshURIFromQueue();
5799 // Test whether this is the top frame or a subframe
5800 PRBool isTopFrame
= PR_TRUE
;
5801 nsCOMPtr
<nsIDocShellTreeItem
> targetParentTreeItem
;
5802 rv
= GetSameTypeParent(getter_AddRefs(targetParentTreeItem
));
5803 if (NS_SUCCEEDED(rv
) && targetParentTreeItem
) {
5804 isTopFrame
= PR_FALSE
;
5808 // If the page load failed, then deal with the error condition...
5809 // Errors are handled as follows:
5810 // 1. Check to see if it's a file not found error or bad content
5812 // 2. Send the URI to a keyword server (if enabled)
5813 // 3. If the error was DNS failure, then add www and .com to the URI
5814 // (if appropriate).
5815 // 4. Throw an error dialog box...
5817 if (url
&& NS_FAILED(aStatus
)) {
5818 if (aStatus
== NS_ERROR_FILE_NOT_FOUND
||
5819 aStatus
== NS_ERROR_INVALID_CONTENT_ENCODING
) {
5820 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
5826 // Try and make an alternative URI from the old one
5828 nsCOMPtr
<nsIURI
> newURI
;
5830 nsCAutoString oldSpec
;
5831 url
->GetSpec(oldSpec
);
5834 // First try keyword fixup
5836 if (aStatus
== NS_ERROR_UNKNOWN_HOST
&& mAllowKeywordFixup
) {
5837 PRBool keywordsEnabled
= PR_FALSE
;
5840 NS_FAILED(mPrefs
->GetBoolPref("keyword.enabled",
5842 keywordsEnabled
= PR_FALSE
;
5847 nsCAutoString scheme
;
5848 url
->GetScheme(scheme
);
5850 PRInt32 dotLoc
= host
.FindChar('.');
5852 // we should only perform a keyword search under the following
5854 // (0) Pref keyword.enabled is true
5855 // (1) the url scheme is http (or https)
5856 // (2) the url does not have a protocol scheme
5857 // If we don't enforce such a policy, then we end up doing
5858 // keyword searchs on urls we don't intend like imap, file,
5859 // mailbox, etc. This could lead to a security problem where we
5860 // send data to the keyword server that we shouldn't be.
5861 // Someone needs to clean up keywords in general so we can
5862 // determine on a per url basis if we want keywords
5863 // enabled...this is just a bandaid...
5864 if (keywordsEnabled
&& !scheme
.IsEmpty() &&
5865 (scheme
.Find("http") != 0)) {
5866 keywordsEnabled
= PR_FALSE
;
5869 if (keywordsEnabled
&& (kNotFound
== dotLoc
)) {
5870 // only send non-qualified hosts to the keyword server
5872 // If this string was passed through nsStandardURL by
5873 // chance, then it may have been converted from UTF-8 to
5874 // ACE, which would result in a completely bogus keyword
5875 // query. Here we try to recover the original Unicode
5876 // value, but this is not 100% correct since the value may
5877 // have been normalized per the IDN normalization rules.
5879 // Since we don't have access to the exact original string
5880 // that was entered by the user, this will just have to do.
5882 nsCAutoString utf8Host
;
5883 nsCOMPtr
<nsIIDNService
> idnSrv
=
5884 do_GetService(NS_IDNSERVICE_CONTRACTID
);
5886 NS_SUCCEEDED(idnSrv
->IsACE(host
, &isACE
)) && isACE
&&
5887 NS_SUCCEEDED(idnSrv
->ConvertACEtoUTF8(host
, utf8Host
)))
5888 sURIFixup
->KeywordToURI(utf8Host
,
5889 getter_AddRefs(newURI
));
5891 sURIFixup
->KeywordToURI(host
, getter_AddRefs(newURI
));
5892 } // end keywordsEnabled
5896 // Now try change the address, e.g. turn http://foo into
5897 // http://www.foo.com
5899 if (aStatus
== NS_ERROR_UNKNOWN_HOST
||
5900 aStatus
== NS_ERROR_NET_RESET
) {
5901 PRBool doCreateAlternate
= PR_TRUE
;
5903 // Skip fixup for anything except a normal document load
5904 // operation on the topframe.
5906 if (mLoadType
!= LOAD_NORMAL
|| !isTopFrame
) {
5907 doCreateAlternate
= PR_FALSE
;
5910 // Test if keyword lookup produced a new URI or not
5912 PRBool sameURI
= PR_FALSE
;
5913 url
->Equals(newURI
, &sameURI
);
5915 // Keyword lookup made a new URI so no need to try
5916 // an alternate one.
5917 doCreateAlternate
= PR_FALSE
;
5921 if (doCreateAlternate
) {
5923 sURIFixup
->CreateFixupURI(oldSpec
,
5924 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
,
5925 getter_AddRefs(newURI
));
5929 // Did we make a new URI that is different to the old one? If so
5933 // Make sure the new URI is different from the old one,
5934 // otherwise there's little point trying to load it again.
5935 PRBool sameURI
= PR_FALSE
;
5936 url
->Equals(newURI
, &sameURI
);
5938 nsCAutoString newSpec
;
5939 newURI
->GetSpec(newSpec
);
5940 NS_ConvertUTF8toUTF16
newSpecW(newSpec
);
5942 return LoadURI(newSpecW
.get(), // URI string
5943 LOAD_FLAGS_NONE
, // Load flags
5944 nsnull
, // Referring URI
5945 nsnull
, // Post data stream
5946 nsnull
); // Headers stream
5951 // Well, fixup didn't work :-(
5952 // It is time to throw an error dialog box, and be done with it...
5954 // Errors to be shown only on top-level frames
5955 if ((aStatus
== NS_ERROR_UNKNOWN_HOST
||
5956 aStatus
== NS_ERROR_CONNECTION_REFUSED
||
5957 aStatus
== NS_ERROR_UNKNOWN_PROXY_HOST
||
5958 aStatus
== NS_ERROR_PROXY_CONNECTION_REFUSED
) &&
5959 (isTopFrame
|| mUseErrorPages
)) {
5960 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
5962 // Errors to be shown for any frame
5963 else if (aStatus
== NS_ERROR_NET_TIMEOUT
||
5964 aStatus
== NS_ERROR_REDIRECT_LOOP
||
5965 aStatus
== NS_ERROR_UNKNOWN_SOCKET_TYPE
||
5966 aStatus
== NS_ERROR_NET_INTERRUPT
||
5967 aStatus
== NS_ERROR_NET_RESET
||
5968 aStatus
== NS_ERROR_MALWARE_URI
||
5969 aStatus
== NS_ERROR_PHISHING_URI
||
5970 aStatus
== NS_ERROR_UNSAFE_CONTENT_TYPE
||
5971 NS_ERROR_GET_MODULE(aStatus
) == NS_ERROR_MODULE_SECURITY
) {
5972 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
5974 else if (aStatus
== NS_ERROR_DOCUMENT_NOT_CACHED
) {
5975 /* A document that was requested to be fetched *only* from
5976 * the cache is not in cache. May be this is one of those
5977 * postdata results. Throw a dialog to the user,
5978 * saying that the page has expired from cache and ask if
5979 * they wish to refetch the page from the net. Do this only
5980 * if the request is a form post.
5982 nsCAutoString method
;
5984 httpChannel
->GetRequestMethod(method
);
5985 if (method
.Equals("POST") && !NS_IsOffline()) {
5987 rv
= ConfirmRepost(&repost
);
5988 if (NS_FAILED(rv
)) return rv
;
5989 // If the user pressed cancel in the dialog, return. Don't try
5990 // to load the page without the post data.
5994 // The user wants to repost the data to the server.
5995 // If the page was loaded due to a back/forward/go
5996 // operation, update the session history index.
5997 // This is similar to the updating done in
5998 // nsDocShell::OnNewURI() for regular pages
5999 nsCOMPtr
<nsISHistory
> rootSH
=mSessionHistory
;
6000 if (!mSessionHistory
) {
6001 nsCOMPtr
<nsIDocShellTreeItem
> root
;
6002 //Get the root docshell
6003 GetSameTypeRootTreeItem(getter_AddRefs(root
));
6005 // QI root to nsIWebNavigation
6006 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav
=
6007 do_QueryInterface(root
);
6009 // Get the handle to SH from the root docshell
6010 rootAsWebnav
->GetSessionHistory(getter_AddRefs(rootSH
));
6013 } // mSessionHistory
6015 if (rootSH
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
6016 nsCOMPtr
<nsISHistoryInternal
> shInternal
=
6017 do_QueryInterface(rootSH
);
6019 rootSH
->GetIndex(&mPreviousTransIndex
);
6020 shInternal
->UpdateIndex();
6021 rootSH
->GetIndex(&mLoadedTransIndex
);
6022 #ifdef DEBUG_PAGE_CACHE
6023 printf("Previous index: %d, Loaded index: %d\n\n",
6024 mPreviousTransIndex
, mLoadedTransIndex
);
6029 // Make it look like we really did honestly finish loading the
6030 // history page we were loading, since the "reload" load we're
6031 // about to kick off will reload our current history entry.
6032 // This is a bit of a hack, and if the force-load fails I think
6033 // we'll end up being confused about what page we're on... but
6034 // we would anyway, since we've updated the session history
6036 SetHistoryEntry(&mOSHE
, loadingSHE
);
6038 // The user does want to repost the data to the server.
6039 // Initiate a new load again.
6041 // Get the postdata if any from the channel.
6042 nsCOMPtr
<nsIInputStream
> inputStream
;
6043 nsCOMPtr
<nsIURI
> referrer
;
6045 httpChannel
->GetReferrer(getter_AddRefs(referrer
));
6046 nsCOMPtr
<nsIUploadChannel
> uploadChannel
=
6047 do_QueryInterface(aChannel
);
6048 if (uploadChannel
) {
6049 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
6052 nsCOMPtr
<nsISeekableStream
> postDataSeekable
=
6053 do_QueryInterface(inputStream
);
6054 if (postDataSeekable
) {
6055 postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
6057 InternalLoad(url
, // URI
6058 referrer
, // Referring URI
6060 INTERNAL_LOAD_FLAGS_INHERIT_OWNER
, // Inherit owner
6061 nsnull
, // No window target
6062 nsnull
, // No type hint
6063 inputStream
, // Post data stream
6064 nsnull
, // No headers stream
6065 LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
,// Load type
6066 nsnull
, // No SHEntry
6067 PR_TRUE
, // first party site
6068 nsnull
, // No nsIDocShell
6069 nsnull
); // No nsIRequest
6072 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
6075 } // if we have a host
6081 //*****************************************************************************
6082 // nsDocShell: Content Viewer Management
6083 //*****************************************************************************
6086 nsDocShell::EnsureContentViewer()
6090 if (mIsBeingDestroyed
)
6091 return NS_ERROR_FAILURE
;
6095 nsIPrincipal
* principal
= nsnull
;
6096 nsCOMPtr
<nsIURI
> baseURI
;
6098 nsCOMPtr
<nsPIDOMWindow
> piDOMWindow(do_QueryInterface(mScriptGlobal
));
6100 principal
= piDOMWindow
->GetOpenerScriptPrincipal();
6104 principal
= GetInheritedPrincipal(PR_FALSE
);
6105 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
6106 GetSameTypeParent(getter_AddRefs(parentItem
));
6108 nsCOMPtr
<nsPIDOMWindow
> domWin
= do_GetInterface(GetAsSupports(this));
6110 nsCOMPtr
<nsIContent
> parentContent
=
6111 do_QueryInterface(domWin
->GetFrameElementInternal());
6112 if (parentContent
) {
6113 baseURI
= parentContent
->GetBaseURI();
6119 nsresult rv
= CreateAboutBlankContentViewer(principal
, baseURI
);
6121 if (NS_SUCCEEDED(rv
)) {
6122 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6123 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6124 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(domDoc
));
6126 "Should have doc if CreateAboutBlankContentViewer "
6129 doc
->SetIsInitialDocument(PR_TRUE
);
6136 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal
* aPrincipal
,
6139 nsCOMPtr
<nsIDocument
> blankDoc
;
6140 nsCOMPtr
<nsIContentViewer
> viewer
;
6141 nsresult rv
= NS_ERROR_FAILURE
;
6143 /* mCreatingDocument should never be true at this point. However, it's
6144 a theoretical possibility. We want to know about it and make it stop,
6145 and this sounds like a job for an assertion. */
6146 NS_ASSERTION(!mCreatingDocument
, "infinite(?) loop creating document averted");
6147 if (mCreatingDocument
)
6148 return NS_ERROR_FAILURE
;
6150 mCreatingDocument
= PR_TRUE
;
6152 // mContentViewer->PermitUnload may release |this| docshell.
6153 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
6155 if (mContentViewer
) {
6156 // We've got a content viewer already. Make sure the user
6157 // permits us to discard the current document and replace it
6158 // with about:blank. And also ensure we fire the unload events
6159 // in the current document.
6162 rv
= mContentViewer
->PermitUnload(PR_FALSE
, &okToUnload
);
6164 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
6165 // The user chose not to unload the page, interrupt the load.
6166 return NS_ERROR_FAILURE
;
6169 mSavingOldViewer
= CanSavePresentation(LOAD_NORMAL
, nsnull
, nsnull
);
6171 // Make sure to blow away our mLoadingURI just in case. No loads
6172 // from inside this pagehide.
6173 mLoadingURI
= nsnull
;
6175 // Notify the current document that it is about to be unloaded!!
6177 // It is important to fire the unload() notification *before* any state
6178 // is changed within the DocShell - otherwise, javascript will get the
6179 // wrong information :-(
6181 (void) FirePageHideNotification(!mSavingOldViewer
);
6184 // Now make sure we don't think we're in the middle of firing unload after
6185 // this point. This will make us fire unload when the about:blank document
6186 // unloads... but that's ok, more or less. Would be nice if it fired load
6188 mFiredUnloadEvent
= PR_FALSE
;
6190 // one helper factory, please
6191 nsCOMPtr
<nsICategoryManager
> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID
));
6193 return NS_ERROR_FAILURE
;
6195 nsXPIDLCString contractId
;
6196 rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", "text/html", getter_Copies(contractId
));
6200 nsCOMPtr
<nsIDocumentLoaderFactory
> docFactory(do_GetService(contractId
));
6202 // generate (about:blank) document to load
6203 docFactory
->CreateBlankDocument(mLoadGroup
, aPrincipal
,
6204 getter_AddRefs(blankDoc
));
6206 // Hack: set the base URI manually, since this document never
6207 // got Reset() with a channel.
6208 blankDoc
->SetBaseURI(aBaseURI
);
6210 blankDoc
->SetContainer(static_cast<nsIDocShell
*>(this));
6212 // create a content viewer for us and the new document
6213 docFactory
->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell
*, this),
6214 blankDoc
, "view", getter_AddRefs(viewer
));
6218 viewer
->SetContainer(static_cast<nsIContentViewerContainer
*>(this));
6219 nsCOMPtr
<nsIDOMDocument
> domdoc(do_QueryInterface(blankDoc
));
6220 Embed(viewer
, "", 0);
6221 viewer
->SetDOMDocument(domdoc
);
6223 SetCurrentURI(blankDoc
->GetDocumentURI(), nsnull
, PR_TRUE
);
6224 rv
= mIsBeingDestroyed
? NS_ERROR_NOT_AVAILABLE
: NS_OK
;
6228 mCreatingDocument
= PR_FALSE
;
6230 // The transient about:blank viewer doesn't have a session history entry.
6231 SetHistoryEntry(&mOSHE
, nsnull
);
6237 nsDocShell::CanSavePresentation(PRUint32 aLoadType
,
6238 nsIRequest
*aNewRequest
,
6239 nsIDocument
*aNewDocument
)
6242 return PR_FALSE
; // no entry to save into
6244 // Only save presentation for "normal" loads and link loads. Anything else
6245 // probably wants to refetch the page, so caching the old presentation
6246 // would be incorrect.
6247 if (aLoadType
!= LOAD_NORMAL
&&
6248 aLoadType
!= LOAD_HISTORY
&&
6249 aLoadType
!= LOAD_LINK
&&
6250 aLoadType
!= LOAD_STOP_CONTENT
&&
6251 aLoadType
!= LOAD_STOP_CONTENT_AND_REPLACE
&&
6252 aLoadType
!= LOAD_ERROR_PAGE
)
6255 // If the session history entry has the saveLayoutState flag set to false,
6256 // then we should not cache the presentation.
6257 PRBool canSaveState
;
6258 mOSHE
->GetSaveLayoutStateFlag(&canSaveState
);
6262 // If the document is not done loading, don't cache it.
6263 nsCOMPtr
<nsPIDOMWindow
> pWin
= do_QueryInterface(mScriptGlobal
);
6264 if (!pWin
|| pWin
->IsLoading())
6267 if (pWin
->WouldReuseInnerWindow(aNewDocument
))
6270 // Avoid doing the work of saving the presentation state in the case where
6271 // the content viewer cache is disabled.
6272 if (nsSHistory::GetMaxTotalViewers() == 0)
6275 // Don't cache the content viewer if we're in a subframe and the subframe
6276 // pref is disabled.
6277 PRBool cacheFrames
= PR_FALSE
;
6278 mPrefs
->GetBoolPref("browser.sessionhistory.cache_subframes",
6281 nsCOMPtr
<nsIDocShellTreeItem
> root
;
6282 GetSameTypeParent(getter_AddRefs(root
));
6283 if (root
&& root
!= this) {
6284 return PR_FALSE
; // this is a subframe load
6288 // If the document does not want its presentation cached, then don't.
6289 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(pWin
->GetExtantDocument());
6290 if (!doc
|| !doc
->CanSavePresentation(aNewRequest
))
6297 nsDocShell::ReattachEditorToWindow(nsISHEntry
*aSHEntry
)
6299 NS_ASSERTION(!mEditorData
,
6300 "Why reattach an editor when we already have one?");
6301 NS_ASSERTION(aSHEntry
&& aSHEntry
->HasDetachedEditor(),
6302 "Reattaching when there's not a detached editor.");
6304 if (mEditorData
|| !aSHEntry
)
6307 mEditorData
= aSHEntry
->ForgetEditorData();
6309 nsresult res
= mEditorData
->ReattachToWindow(this);
6310 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to reattach editing session");
6315 nsDocShell::DetachEditorFromWindow()
6317 if (!mEditorData
|| mEditorData
->WaitingForLoad()) {
6318 // If there's nothing to detach, or if the editor data is actually set
6319 // up for the _new_ page that's coming in, don't detach.
6323 NS_ASSERTION(!mOSHE
|| !mOSHE
->HasDetachedEditor(),
6324 "Detaching editor when it's already detached.");
6326 nsresult res
= mEditorData
->DetachFromWindow();
6327 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to detach editor");
6329 if (NS_SUCCEEDED(res
)) {
6330 // Make mOSHE hold the owning ref to the editor data.
6332 mOSHE
->SetEditorData(mEditorData
.forget());
6334 mEditorData
= nsnull
;
6340 GetEditable(&isEditable
);
6341 NS_ASSERTION(!isEditable
,
6342 "Window is still editable after detaching editor.");
6348 nsDocShell::CaptureState()
6350 if (!mOSHE
|| mOSHE
== mLSHE
) {
6351 // No entry to save into, or we're replacing the existing entry.
6352 return NS_ERROR_FAILURE
;
6355 nsCOMPtr
<nsPIDOMWindow
> privWin
= do_QueryInterface(mScriptGlobal
);
6357 return NS_ERROR_FAILURE
;
6359 nsCOMPtr
<nsISupports
> windowState
;
6360 nsresult rv
= privWin
->SaveWindowState(getter_AddRefs(windowState
));
6361 NS_ENSURE_SUCCESS(rv
, rv
);
6363 #ifdef DEBUG_PAGE_CACHE
6364 nsCOMPtr
<nsIURI
> uri
;
6365 mOSHE
->GetURI(getter_AddRefs(uri
));
6369 printf("Saving presentation into session history\n");
6370 printf(" SH URI: %s\n", spec
.get());
6373 rv
= mOSHE
->SetWindowState(windowState
);
6374 NS_ENSURE_SUCCESS(rv
, rv
);
6376 // Suspend refresh URIs and save off the timer queue
6377 rv
= mOSHE
->SetRefreshURIList(mSavedRefreshURIList
);
6378 NS_ENSURE_SUCCESS(rv
, rv
);
6380 // Capture the current content viewer bounds.
6381 if (mContentViewer
) {
6383 mContentViewer
->GetBounds(bounds
);
6384 rv
= mOSHE
->SetViewerBounds(bounds
);
6385 NS_ENSURE_SUCCESS(rv
, rv
);
6388 // Capture the docshell hierarchy.
6389 mOSHE
->ClearChildShells();
6391 PRInt32 childCount
= mChildList
.Count();
6392 for (PRInt32 i
= 0; i
< childCount
; ++i
) {
6393 nsCOMPtr
<nsIDocShellTreeItem
> childShell
= do_QueryInterface(ChildAt(i
));
6394 NS_ASSERTION(childShell
, "null child shell");
6396 mOSHE
->AddChildShell(childShell
);
6403 nsDocShell::RestorePresentationEvent::Run()
6405 if (mDocShell
&& NS_FAILED(mDocShell
->RestoreFromHistory()))
6406 NS_WARNING("RestoreFromHistory failed");
6411 nsDocShell::BeginRestore(nsIContentViewer
*aContentViewer
, PRBool aTop
)
6414 if (!aContentViewer
) {
6415 rv
= EnsureContentViewer();
6416 NS_ENSURE_SUCCESS(rv
, rv
);
6418 aContentViewer
= mContentViewer
;
6421 // Dispatch events for restoring the presentation. We try to simulate
6422 // the progress notifications loading the document would cause, so we add
6423 // the document's channel to the loadgroup to initiate stateChange
6426 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6427 aContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6428 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
6430 nsIChannel
*channel
= doc
->GetChannel();
6432 mEODForCurrentDocument
= PR_FALSE
;
6433 mIsRestoringDocument
= PR_TRUE
;
6434 mLoadGroup
->AddRequest(channel
, nsnull
);
6435 mIsRestoringDocument
= PR_FALSE
;
6440 // This point corresponds to us having gotten OnStartRequest or
6441 // STATE_START, so do the same thing that CreateContentViewer does at
6442 // this point to ensure that unload/pagehide events for this document
6443 // will fire when it's unloaded again.
6444 mFiredUnloadEvent
= PR_FALSE
;
6446 // For non-top frames, there is no notion of making sure that the
6447 // previous document is in the domwindow when STATE_START notifications
6448 // happen. We can just call BeginRestore for all of the child shells
6450 rv
= BeginRestoreChildren();
6451 NS_ENSURE_SUCCESS(rv
, rv
);
6458 nsDocShell::BeginRestoreChildren()
6460 PRInt32 n
= mChildList
.Count();
6461 for (PRInt32 i
= 0; i
< n
; ++i
) {
6462 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
6464 nsresult rv
= child
->BeginRestore(nsnull
, PR_FALSE
);
6465 NS_ENSURE_SUCCESS(rv
, rv
);
6472 nsDocShell::FinishRestore()
6474 // First we call finishRestore() on our children. In the simulated load,
6475 // all of the child frames finish loading before the main document.
6477 PRInt32 n
= mChildList
.Count();
6478 for (PRInt32 i
= 0; i
< n
; ++i
) {
6479 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
6481 child
->FinishRestore();
6485 if (mOSHE
&& mOSHE
->HasDetachedEditor()) {
6486 ReattachEditorToWindow(mOSHE
);
6489 if (mContentViewer
) {
6490 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6491 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6493 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
6495 // Finally, we remove the request from the loadgroup. This will
6496 // cause onStateChange(STATE_STOP) to fire, which will fire the
6497 // pageshow event to the chrome.
6499 nsIChannel
*channel
= doc
->GetChannel();
6501 mIsRestoringDocument
= PR_TRUE
;
6502 mLoadGroup
->RemoveRequest(channel
, nsnull
, NS_OK
);
6503 mIsRestoringDocument
= PR_FALSE
;
6512 nsDocShell::GetRestoringDocument(PRBool
*aRestoring
)
6514 *aRestoring
= mIsRestoringDocument
;
6519 nsDocShell::RestorePresentation(nsISHEntry
*aSHEntry
, PRBool
*aRestoring
)
6521 NS_ASSERTION(mLoadType
& LOAD_CMD_HISTORY
,
6522 "RestorePresentation should only be called for history loads");
6524 nsCOMPtr
<nsIContentViewer
> viewer
;
6525 aSHEntry
->GetContentViewer(getter_AddRefs(viewer
));
6527 #ifdef DEBUG_PAGE_CACHE
6528 nsCOMPtr
<nsIURI
> uri
;
6529 aSHEntry
->GetURI(getter_AddRefs(uri
));
6536 *aRestoring
= PR_FALSE
;
6539 #ifdef DEBUG_PAGE_CACHE
6540 printf("no saved presentation for uri: %s\n", spec
.get());
6545 // We need to make sure the content viewer's container is this docshell.
6546 // In subframe navigation, it's possible for the docshell that the
6547 // content viewer was originally loaded into to be replaced with a
6548 // different one. We don't currently support restoring the presentation
6551 nsCOMPtr
<nsISupports
> container
;
6552 viewer
->GetContainer(getter_AddRefs(container
));
6553 if (!::SameCOMIdentity(container
, GetAsSupports(this))) {
6554 #ifdef DEBUG_PAGE_CACHE
6555 printf("No valid container, clearing presentation\n");
6557 aSHEntry
->SetContentViewer(nsnull
);
6558 return NS_ERROR_FAILURE
;
6561 NS_ASSERTION(mContentViewer
!= viewer
, "Restoring existing presentation");
6563 #ifdef DEBUG_PAGE_CACHE
6564 printf("restoring presentation from session history: %s\n", spec
.get());
6567 SetHistoryEntry(&mLSHE
, aSHEntry
);
6569 // Add the request to our load group. We do this before swapping out
6570 // the content viewers so that consumers of STATE_START can access
6571 // the old document. We only deal with the toplevel load at this time --
6572 // to be consistent with normal document loading, subframes cannot start
6573 // loading until after data arrives, which is after STATE_START completes.
6575 BeginRestore(viewer
, PR_TRUE
);
6577 // Post an event that will remove the request after we've returned
6578 // to the event loop. This mimics the way it is called by nsIChannel
6581 // Revoke any pending restore (just in case)
6582 NS_ASSERTION(!mRestorePresentationEvent
.IsPending(),
6583 "should only have one RestorePresentationEvent");
6584 mRestorePresentationEvent
.Revoke();
6586 nsRefPtr
<RestorePresentationEvent
> evt
= new RestorePresentationEvent(this);
6587 nsresult rv
= NS_DispatchToCurrentThread(evt
);
6588 if (NS_SUCCEEDED(rv
)) {
6589 mRestorePresentationEvent
= evt
.get();
6590 // The rest of the restore processing will happen on our event
6592 *aRestoring
= PR_TRUE
;
6599 nsDocShell::RestoreFromHistory()
6601 mRestorePresentationEvent
.Forget();
6603 // This section of code follows the same ordering as CreateContentViewer.
6605 return NS_ERROR_FAILURE
;
6607 nsCOMPtr
<nsIContentViewer
> viewer
;
6608 mLSHE
->GetContentViewer(getter_AddRefs(viewer
));
6610 return NS_ERROR_FAILURE
;
6612 if (mSavingOldViewer
) {
6613 // We determined that it was safe to cache the document presentation
6614 // at the time we initiated the new load. We need to check whether
6615 // it's still safe to do so, since there may have been DOM mutations
6616 // or new requests initiated.
6617 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6618 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6619 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
6620 nsIRequest
*request
= nsnull
;
6622 request
= doc
->GetChannel();
6623 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
6626 nsCOMPtr
<nsIMarkupDocumentViewer
> oldMUDV(do_QueryInterface(mContentViewer
));
6627 nsCOMPtr
<nsIMarkupDocumentViewer
> newMUDV(do_QueryInterface(viewer
));
6628 float textZoom
= 1.0f
;
6629 float pageZoom
= 1.0f
;
6630 if (oldMUDV
&& newMUDV
) {
6631 oldMUDV
->GetTextZoom(&textZoom
);
6632 oldMUDV
->GetFullZoom(&pageZoom
);
6635 // Protect against mLSHE going away via a load triggered from
6636 // pagehide or unload.
6637 nsCOMPtr
<nsISHEntry
> origLSHE
= mLSHE
;
6639 // Make sure to blow away our mLoadingURI just in case. No loads
6640 // from inside this pagehide.
6641 mLoadingURI
= nsnull
;
6643 // Notify the old content viewer that it's being hidden.
6644 FirePageHideNotification(!mSavingOldViewer
);
6646 // If mLSHE was changed as a result of the pagehide event, then
6647 // something else was loaded. Don't finish restoring.
6648 if (mLSHE
!= origLSHE
)
6651 // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
6652 // *new* document will fire.
6653 mFiredUnloadEvent
= PR_FALSE
;
6655 mURIResultedInDocument
= PR_TRUE
;
6656 nsCOMPtr
<nsISHistory
> rootSH
;
6657 GetRootSessionHistory(getter_AddRefs(rootSH
));
6659 nsCOMPtr
<nsISHistoryInternal
> hist
= do_QueryInterface(rootSH
);
6660 rootSH
->GetIndex(&mPreviousTransIndex
);
6661 hist
->UpdateIndex();
6662 rootSH
->GetIndex(&mLoadedTransIndex
);
6663 #ifdef DEBUG_PAGE_CACHE
6664 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
6669 // Rather than call Embed(), we will retrieve the viewer from the session
6670 // history entry and swap it in.
6671 // XXX can we refactor this so that we can just call Embed()?
6672 PersistLayoutHistoryState();
6674 if (mContentViewer
) {
6675 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
6677 mOSHE
->SyncPresentationState();
6679 mSavingOldViewer
= PR_FALSE
;
6683 mSavedRefreshURIList
= nsnull
;
6685 // In cases where we use a transient about:blank viewer between loads,
6686 // we never show the transient viewer, so _its_ previous viewer is never
6687 // unhooked from the view hierarchy. Destroy any such previous viewer now,
6688 // before we grab the root view sibling, so that we don't grab a view
6689 // that's about to go away.
6691 if (mContentViewer
) {
6692 nsCOMPtr
<nsIContentViewer
> previousViewer
;
6693 mContentViewer
->GetPreviousViewer(getter_AddRefs(previousViewer
));
6694 if (previousViewer
) {
6695 mContentViewer
->SetPreviousViewer(nsnull
);
6696 previousViewer
->Destroy();
6700 // Save off the root view's parent and sibling so that we can insert the
6701 // new content viewer's root view at the same position. Also save the
6702 // bounds of the root view's widget.
6704 nsIView
*rootViewSibling
= nsnull
, *rootViewParent
= nsnull
;
6705 nsIntRect
newBounds(0, 0, 0, 0);
6707 nsCOMPtr
<nsIPresShell
> oldPresShell
;
6708 nsDocShell::GetPresShell(getter_AddRefs(oldPresShell
));
6710 nsIViewManager
*vm
= oldPresShell
->GetViewManager();
6712 nsIView
*oldRootView
= nsnull
;
6713 vm
->GetRootView(oldRootView
);
6716 rootViewSibling
= oldRootView
->GetNextSibling();
6717 rootViewParent
= oldRootView
->GetParent();
6719 mContentViewer
->GetBounds(newBounds
);
6724 // Transfer ownership to mContentViewer. By ensuring that either the
6725 // docshell or the session history, but not both, have references to the
6726 // content viewer, we prevent the viewer from being torn down after
6727 // Destroy() is called.
6729 if (mContentViewer
) {
6730 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nsnull
);
6731 viewer
->SetPreviousViewer(mContentViewer
);
6734 // Order the mContentViewer setup just like Embed does.
6735 mContentViewer
= nsnull
;
6737 // Now that we're about to switch documents, forget all of our children.
6738 // Note that we cached them as needed up in CaptureState above.
6741 mContentViewer
.swap(viewer
);
6743 // Grab all of the related presentation from the SHEntry now.
6744 // Clearing the viewer from the SHEntry will clear all of this state.
6745 nsCOMPtr
<nsISupports
> windowState
;
6746 mLSHE
->GetWindowState(getter_AddRefs(windowState
));
6747 mLSHE
->SetWindowState(nsnull
);
6750 mLSHE
->GetSticky(&sticky
);
6752 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6753 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6755 nsCOMArray
<nsIDocShellTreeItem
> childShells
;
6757 nsCOMPtr
<nsIDocShellTreeItem
> child
;
6758 while (NS_SUCCEEDED(mLSHE
->ChildShellAt(i
++, getter_AddRefs(child
))) &&
6760 childShells
.AppendObject(child
);
6763 // get the previous content viewer size
6764 nsIntRect
oldBounds(0, 0, 0, 0);
6765 mLSHE
->GetViewerBounds(oldBounds
);
6767 // Restore the refresh URI list. The refresh timers will be restarted
6768 // when EndPageLoad() is called.
6769 nsCOMPtr
<nsISupportsArray
> refreshURIList
;
6770 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIList
));
6772 // Reattach to the window object.
6773 rv
= mContentViewer
->Open(windowState
, mLSHE
);
6775 // Now remove it from the cached presentation.
6776 mLSHE
->SetContentViewer(nsnull
);
6777 mEODForCurrentDocument
= PR_FALSE
;
6781 nsCOMPtr
<nsISupportsArray
> refreshURIs
;
6782 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIs
));
6783 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
6784 mLSHE
->ChildShellAt(0, getter_AddRefs(childShell
));
6785 NS_ASSERTION(!refreshURIs
&& !childShell
,
6786 "SHEntry should have cleared presentation state");
6790 // Restore the sticky state of the viewer. The viewer has set this state
6791 // on the history entry in Destroy() just before marking itself non-sticky,
6792 // to avoid teardown of the presentation.
6793 mContentViewer
->SetSticky(sticky
);
6795 NS_ENSURE_SUCCESS(rv
, rv
);
6797 // mLSHE is now our currently-loaded document.
6798 SetHistoryEntry(&mOSHE
, mLSHE
);
6800 // XXX special wyciwyg handling in Embed()?
6802 // We aren't going to restore any items from the LayoutHistoryState,
6803 // but we don't want them to stay around in case the page is reloaded.
6804 SetLayoutHistoryState(nsnull
);
6806 // This is the end of our Embed() replacement
6808 mSavingOldViewer
= PR_FALSE
;
6809 mEODForCurrentDocument
= PR_FALSE
;
6811 // Tell the event loop to favor plevents over user events, see comments
6812 // in CreateContentViewer.
6813 if (++gNumberOfDocumentsLoading
== 1)
6814 FavorPerformanceHint(PR_TRUE
, NS_EVENT_STARVATION_DELAY_HINT
);
6817 if (oldMUDV
&& newMUDV
) {
6818 newMUDV
->SetTextZoom(textZoom
);
6819 newMUDV
->SetFullZoom(pageZoom
);
6822 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDoc
);
6823 PRUint32 parentSuspendCount
= 0;
6825 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
6826 GetParent(getter_AddRefs(parent
));
6827 nsCOMPtr
<nsIDOMDocument
> parentDoc
= do_GetInterface(parent
);
6828 nsCOMPtr
<nsIDocument
> d
= do_QueryInterface(parentDoc
);
6830 if (d
->EventHandlingSuppressed()) {
6831 document
->SuppressEventHandling(d
->EventHandlingSuppressed());
6833 nsCOMPtr
<nsPIDOMWindow
> parentWindow
= d
->GetWindow();
6835 parentSuspendCount
= parentWindow
->TimeoutSuspendCount();
6839 // Use the uri from the mLSHE we had when we entered this function
6840 // (which need not match the document's URI if anchors are involved),
6841 // since that's the history entry we're loading. Note that if we use
6842 // origLSHE we don't have to worry about whether the entry in question
6843 // is still mLSHE or whether it's now mOSHE.
6844 nsCOMPtr
<nsIURI
> uri
;
6845 origLSHE
->GetURI(getter_AddRefs(uri
));
6846 SetCurrentURI(uri
, document
->GetChannel(), PR_TRUE
);
6849 // This is the end of our CreateContentViewer() replacement.
6850 // Now we simulate a load. First, we restore the state of the javascript
6852 nsCOMPtr
<nsPIDOMWindow
> privWin
=
6853 do_GetInterface(static_cast<nsIInterfaceRequestor
*>(this));
6854 NS_ASSERTION(privWin
, "could not get nsPIDOMWindow interface");
6856 rv
= privWin
->RestoreWindowState(windowState
);
6857 NS_ENSURE_SUCCESS(rv
, rv
);
6859 // Now, dispatch a title change event which would happen as the
6860 // <head> is parsed.
6861 document
->NotifyPossibleTitleChange(PR_FALSE
);
6863 // Now we simulate appending child docshells for subframes.
6864 for (i
= 0; i
< childShells
.Count(); ++i
) {
6865 nsIDocShellTreeItem
*childItem
= childShells
.ObjectAt(i
);
6866 nsCOMPtr
<nsIDocShell
> childShell
= do_QueryInterface(childItem
);
6868 // Make sure to not clobber the state of the child. Since AddChild
6869 // always clobbers it, save it off first.
6870 PRBool allowPlugins
;
6871 childShell
->GetAllowPlugins(&allowPlugins
);
6873 PRBool allowJavascript
;
6874 childShell
->GetAllowJavascript(&allowJavascript
);
6876 PRBool allowRedirects
;
6877 childShell
->GetAllowMetaRedirects(&allowRedirects
);
6879 PRBool allowSubframes
;
6880 childShell
->GetAllowSubframes(&allowSubframes
);
6883 childShell
->GetAllowImages(&allowImages
);
6885 PRBool allowDNSPrefetch
;
6886 childShell
->GetAllowDNSPrefetch(&allowDNSPrefetch
);
6888 AddChild(childItem
);
6890 childShell
->SetAllowPlugins(allowPlugins
);
6891 childShell
->SetAllowJavascript(allowJavascript
);
6892 childShell
->SetAllowMetaRedirects(allowRedirects
);
6893 childShell
->SetAllowSubframes(allowSubframes
);
6894 childShell
->SetAllowImages(allowImages
);
6895 childShell
->SetAllowDNSPrefetch(allowDNSPrefetch
);
6897 rv
= childShell
->BeginRestore(nsnull
, PR_FALSE
);
6898 NS_ENSURE_SUCCESS(rv
, rv
);
6901 nsCOMPtr
<nsIPresShell
> shell
;
6902 nsDocShell::GetPresShell(getter_AddRefs(shell
));
6904 nsIViewManager
*newVM
= shell
? shell
->GetViewManager() : nsnull
;
6905 nsIView
*newRootView
= nsnull
;
6907 newVM
->GetRootView(newRootView
);
6909 // Insert the new root view at the correct location in the view tree.
6910 if (rootViewParent
) {
6911 nsIViewManager
*parentVM
= rootViewParent
->GetViewManager();
6913 if (parentVM
&& newRootView
) {
6914 // InsertChild(parent, child, sib, PR_TRUE) inserts the child after
6915 // sib in content order, which is before sib in view order. BUT
6916 // when sib is null it inserts at the end of the the document
6917 // order, i.e., first in view order. But when oldRootSibling is
6918 // null, the old root as at the end of the view list --- last in
6919 // content order --- and we want to call InsertChild(parent, child,
6920 // nsnull, PR_FALSE) in that case.
6921 parentVM
->InsertChild(rootViewParent
, newRootView
,
6923 rootViewSibling
? PR_TRUE
: PR_FALSE
);
6925 NS_ASSERTION(newRootView
->GetNextSibling() == rootViewSibling
,
6926 "error in InsertChild");
6930 // If parent is suspended, increase suspension count.
6931 // This can't be done as early as event suppression since this
6932 // depends on docshell tree.
6933 if (parentSuspendCount
) {
6934 privWin
->SuspendTimeouts(parentSuspendCount
, PR_FALSE
);
6937 // Now that all of the child docshells have been put into place, we can
6938 // restart the timers for the window and all of the child frames.
6939 privWin
->ResumeTimeouts();
6941 // Restore the refresh URI list. The refresh timers will be restarted
6942 // when EndPageLoad() is called.
6943 mRefreshURIList
= refreshURIList
;
6945 // Meta-refresh timers have been restarted for this shell, but not
6946 // for our children. Walk the child shells and restart their timers.
6947 PRInt32 n
= mChildList
.Count();
6948 for (i
= 0; i
< n
; ++i
) {
6949 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
6951 child
->ResumeRefreshURIs();
6954 // Make sure this presentation is the same size as the previous
6955 // presentation. If this is not the same size we showed it at last time,
6956 // then we need to resize the widget.
6958 // XXXbryner This interacts poorly with Firefox's infobar. If the old
6959 // presentation had the infobar visible, then we will resize the new
6960 // presentation to that smaller size. However, firing the locationchanged
6961 // event will hide the infobar, which will immediately resize the window
6962 // back to the larger size. A future optimization might be to restore
6963 // the presentation at the "wrong" size, then fire the locationchanged
6964 // event and check whether the docshell's new size is the same as the
6965 // cached viewer size (skipping the resize if they are equal).
6968 if (!newBounds
.IsEmpty() && newBounds
!= oldBounds
) {
6969 #ifdef DEBUG_PAGE_CACHE
6970 printf("resize widget(%d, %d, %d, %d)\n", newBounds
.x
,
6971 newBounds
.y
, newBounds
.width
, newBounds
.height
);
6973 mContentViewer
->SetBounds(newBounds
);
6975 nsIScrollableFrame
*rootScrollFrame
=
6976 shell
->GetRootScrollFrameAsScrollableExternal();
6977 if (rootScrollFrame
) {
6978 rootScrollFrame
->PostScrolledAreaEventForCurrentArea();
6983 // Simulate the completion of the load.
6984 nsDocShell::FinishRestore();
6986 // Restart plugins, and paint the content.
6990 return privWin
->FireDelayedDOMEvents();
6994 nsDocShell::CreateContentViewer(const char *aContentType
,
6995 nsIRequest
* request
,
6996 nsIStreamListener
** aContentHandler
)
6998 *aContentHandler
= nsnull
;
7000 // Can we check the content type of the current content viewer
7001 // and reuse it without destroying it and re-creating it?
7003 NS_ASSERTION(mLoadGroup
, "Someone ignored return from Init()?");
7005 // Instantiate the content viewer object
7006 nsCOMPtr
<nsIContentViewer
> viewer
;
7007 nsresult rv
= NewContentViewerObj(aContentType
, request
, mLoadGroup
,
7008 aContentHandler
, getter_AddRefs(viewer
));
7011 return NS_ERROR_FAILURE
;
7013 // Notify the current document that it is about to be unloaded!!
7015 // It is important to fire the unload() notification *before* any state
7016 // is changed within the DocShell - otherwise, javascript will get the
7017 // wrong information :-(
7020 if (mSavingOldViewer
) {
7021 // We determined that it was safe to cache the document presentation
7022 // at the time we initiated the new load. We need to check whether
7023 // it's still safe to do so, since there may have been DOM mutations
7024 // or new requests initiated.
7025 nsCOMPtr
<nsIDOMDocument
> domDoc
;
7026 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
7027 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
7028 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
7031 NS_ASSERTION(!mLoadingURI
, "Re-entering unload?");
7033 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(request
);
7034 if (aOpenedChannel
) {
7035 aOpenedChannel
->GetURI(getter_AddRefs(mLoadingURI
));
7037 FirePageHideNotification(!mSavingOldViewer
);
7038 mLoadingURI
= nsnull
;
7040 // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
7041 // *new* document will fire.
7042 mFiredUnloadEvent
= PR_FALSE
;
7044 // we've created a new document so go ahead and call
7045 // OnLoadingSite(), but don't fire OnLocationChange()
7046 // notifications before we've called Embed(). See bug 284993.
7047 mURIResultedInDocument
= PR_TRUE
;
7049 if (mLoadType
== LOAD_ERROR_PAGE
) {
7050 // We need to set the SH entry and our current URI here and not
7051 // at the moment we load the page. We want the same behavior
7052 // of Stop() as for a normal page load. See bug 514232 for details.
7054 // Revert mLoadType to load type to state the page load failed,
7055 // following function calls need it.
7056 mLoadType
= mFailedLoadType
;
7058 nsCOMPtr
<nsIChannel
> failedChannel
= mFailedChannel
;
7059 nsCOMPtr
<nsIURI
> failedURI
= mFailedURI
;
7060 mFailedChannel
= nsnull
;
7061 mFailedURI
= nsnull
;
7063 // Create an shistory entry for the old load, if we have a channel
7064 if (failedChannel
) {
7065 mURIResultedInDocument
= PR_TRUE
;
7066 OnLoadingSite(failedChannel
, PR_TRUE
, PR_FALSE
);
7067 } else if (failedURI
) {
7068 mURIResultedInDocument
= PR_TRUE
;
7069 OnNewURI(failedURI
, nsnull
, nsnull
, mLoadType
, PR_TRUE
, PR_FALSE
);
7072 // Be sure to have a correct mLSHE, it may have been cleared by
7073 // EndPageLoad. See bug 302115.
7074 if (mSessionHistory
&& !mLSHE
) {
7076 mSessionHistory
->GetRequestedIndex(&idx
);
7078 mSessionHistory
->GetIndex(&idx
);
7080 nsCOMPtr
<nsIHistoryEntry
> entry
;
7081 mSessionHistory
->GetEntryAtIndex(idx
, PR_FALSE
,
7082 getter_AddRefs(entry
));
7083 mLSHE
= do_QueryInterface(entry
);
7086 // Set our current URI
7087 SetCurrentURI(failedURI
);
7089 mLoadType
= LOAD_ERROR_PAGE
;
7092 PRBool onLocationChangeNeeded
= OnLoadingSite(aOpenedChannel
, PR_FALSE
);
7094 // let's try resetting the load group if we need to...
7095 nsCOMPtr
<nsILoadGroup
> currentLoadGroup
;
7096 NS_ENSURE_SUCCESS(aOpenedChannel
->
7097 GetLoadGroup(getter_AddRefs(currentLoadGroup
)),
7100 if (currentLoadGroup
!= mLoadGroup
) {
7101 nsLoadFlags loadFlags
= 0;
7103 //Cancel any URIs that are currently loading...
7104 /// XXX: Need to do this eventually Stop();
7106 // Retarget the document to this loadgroup...
7108 /* First attach the channel to the right loadgroup
7109 * and then remove from the old loadgroup. This
7110 * puts the notifications in the right order and
7111 * we don't null-out mLSHE in OnStateChange() for
7112 * all redirected urls
7114 aOpenedChannel
->SetLoadGroup(mLoadGroup
);
7116 // Mark the channel as being a document URI...
7117 aOpenedChannel
->GetLoadFlags(&loadFlags
);
7118 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
;
7120 aOpenedChannel
->SetLoadFlags(loadFlags
);
7122 mLoadGroup
->AddRequest(request
, nsnull
);
7123 if (currentLoadGroup
)
7124 currentLoadGroup
->RemoveRequest(request
, nsnull
,
7125 NS_BINDING_RETARGETED
);
7127 // Update the notification callbacks, so that progress and
7128 // status information are sent to the right docshell...
7129 aOpenedChannel
->SetNotificationCallbacks(this);
7132 NS_ENSURE_SUCCESS(Embed(viewer
, "", (nsISupports
*) nsnull
),
7135 mSavedRefreshURIList
= nsnull
;
7136 mSavingOldViewer
= PR_FALSE
;
7137 mEODForCurrentDocument
= PR_FALSE
;
7139 // if this document is part of a multipart document,
7140 // the ID can be used to distinguish it from the other parts.
7141 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(request
));
7142 if (multiPartChannel
) {
7143 nsCOMPtr
<nsIPresShell
> shell
;
7144 rv
= GetPresShell(getter_AddRefs(shell
));
7145 if (NS_SUCCEEDED(rv
) && shell
) {
7146 nsIDocument
*doc
= shell
->GetDocument();
7149 multiPartChannel
->GetPartID(&partID
);
7150 doc
->SetPartID(partID
);
7155 // Give hint to native plevent dispatch mechanism. If a document
7156 // is loading the native plevent dispatch mechanism should favor
7157 // performance over normal native event dispatch priorities.
7158 if (++gNumberOfDocumentsLoading
== 1) {
7159 // Hint to favor performance for the plevent notification mechanism.
7160 // We want the pages to load as fast as possible even if its means
7161 // native messages might be starved.
7162 FavorPerformanceHint(PR_TRUE
, NS_EVENT_STARVATION_DELAY_HINT
);
7165 if (onLocationChangeNeeded
) {
7166 FireOnLocationChange(this, request
, mCurrentURI
);
7173 nsDocShell::NewContentViewerObj(const char *aContentType
,
7174 nsIRequest
* request
, nsILoadGroup
* aLoadGroup
,
7175 nsIStreamListener
** aContentHandler
,
7176 nsIContentViewer
** aViewer
)
7178 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(request
);
7181 nsCOMPtr
<nsICategoryManager
> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID
, &rv
));
7185 nsXPIDLCString contractId
;
7186 rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", aContentType
, getter_Copies(contractId
));
7188 // Create an instance of the document-loader-factory
7189 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
;
7190 if (NS_SUCCEEDED(rv
))
7191 docLoaderFactory
= do_GetService(contractId
.get());
7193 if (!docLoaderFactory
) {
7194 return NS_ERROR_FAILURE
;
7197 // Now create an instance of the content viewer
7198 // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
7199 NS_ENSURE_SUCCESS(docLoaderFactory
->CreateInstance("view",
7201 aLoadGroup
, aContentType
,
7202 static_cast<nsIContentViewerContainer
*>(this),
7208 (*aViewer
)->SetContainer(static_cast<nsIContentViewerContainer
*>(this));
7213 nsDocShell::SetupNewViewer(nsIContentViewer
* aNewViewer
)
7216 // Copy content viewer state from previous or parent content viewer.
7218 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
7220 // Do NOT to maintain a reference to the old content viewer outside
7221 // of this "copying" block, or it will not be destroyed until the end of
7222 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
7224 // In this block of code, if we get an error result, we return it
7225 // but if we get a null pointer, that's perfectly legal for parent
7226 // and parentContentViewer.
7234 // This will get the size from the current content viewer or from the
7236 DoGetPositionAndSize(&x
, &y
, &cx
, &cy
);
7238 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
7239 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem
)),
7241 nsCOMPtr
<nsIDocShell
> parent(do_QueryInterface(parentAsItem
));
7243 nsCAutoString defaultCharset
;
7244 nsCAutoString forceCharset
;
7245 nsCAutoString hintCharset
;
7246 PRInt32 hintCharsetSource
;
7247 nsCAutoString prevDocCharset
;
7250 PRBool styleDisabled
;
7251 // |newMUDV| also serves as a flag to set the data from the above vars
7252 nsCOMPtr
<nsIMarkupDocumentViewer
> newMUDV
;
7254 if (mContentViewer
|| parent
) {
7255 nsCOMPtr
<nsIMarkupDocumentViewer
> oldMUDV
;
7256 if (mContentViewer
) {
7257 // Get any interesting state from old content viewer
7258 // XXX: it would be far better to just reuse the document viewer ,
7259 // since we know we're just displaying the same document as before
7260 oldMUDV
= do_QueryInterface(mContentViewer
);
7262 // Tell the old content viewer to hibernate in session history when
7265 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
7267 mOSHE
->SyncPresentationState();
7269 mSavingOldViewer
= PR_FALSE
;
7273 // No old content viewer, so get state from parent's content viewer
7274 nsCOMPtr
<nsIContentViewer
> parentContentViewer
;
7275 parent
->GetContentViewer(getter_AddRefs(parentContentViewer
));
7276 oldMUDV
= do_QueryInterface(parentContentViewer
);
7282 newMUDV
= do_QueryInterface(aNewViewer
,&rv
);
7284 NS_ENSURE_SUCCESS(oldMUDV
->
7285 GetDefaultCharacterSet(defaultCharset
),
7287 NS_ENSURE_SUCCESS(oldMUDV
->
7288 GetForceCharacterSet(forceCharset
),
7290 NS_ENSURE_SUCCESS(oldMUDV
->
7291 GetHintCharacterSet(hintCharset
),
7293 NS_ENSURE_SUCCESS(oldMUDV
->
7294 GetHintCharacterSetSource(&hintCharsetSource
),
7296 NS_ENSURE_SUCCESS(oldMUDV
->
7297 GetTextZoom(&textZoom
),
7299 NS_ENSURE_SUCCESS(oldMUDV
->
7300 GetFullZoom(&pageZoom
),
7302 NS_ENSURE_SUCCESS(oldMUDV
->
7303 GetAuthorStyleDisabled(&styleDisabled
),
7305 NS_ENSURE_SUCCESS(oldMUDV
->
7306 GetPrevDocCharacterSet(prevDocCharset
),
7312 nscolor bgcolor
= NS_RGBA(0, 0, 0, 0);
7313 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
7314 nsCOMPtr
<nsIContentViewer
> kungfuDeathGrip
= mContentViewer
;
7315 if (mContentViewer
) {
7316 // Stop any activity that may be happening in the old document before
7318 mContentViewer
->Stop();
7320 // Try to extract the canvas background color from the old
7321 // presentation shell, so we can use it for the next document.
7322 nsCOMPtr
<nsIDocumentViewer
> docviewer
=
7323 do_QueryInterface(mContentViewer
);
7326 nsCOMPtr
<nsIPresShell
> shell
;
7327 docviewer
->GetPresShell(getter_AddRefs(shell
));
7330 bgcolor
= shell
->GetCanvasBackground();
7334 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nsnull
);
7335 aNewViewer
->SetPreviousViewer(mContentViewer
);
7337 mContentViewer
= nsnull
;
7340 // Now that we're about to switch documents, forget all of our children.
7341 // Note that we cached them as needed up in CaptureState above.
7344 mContentViewer
= aNewViewer
;
7346 nsCOMPtr
<nsIWidget
> widget
;
7347 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget
)), NS_ERROR_FAILURE
);
7349 nsIntRect
bounds(x
, y
, cx
, cy
);
7351 if (NS_FAILED(mContentViewer
->Init(widget
, bounds
))) {
7352 mContentViewer
= nsnull
;
7353 NS_ERROR("ContentViewer Initialization failed");
7354 return NS_ERROR_FAILURE
;
7357 // If we have old state to copy, set the old state onto the new content
7360 NS_ENSURE_SUCCESS(newMUDV
->SetDefaultCharacterSet(defaultCharset
),
7362 NS_ENSURE_SUCCESS(newMUDV
->SetForceCharacterSet(forceCharset
),
7364 NS_ENSURE_SUCCESS(newMUDV
->SetHintCharacterSet(hintCharset
),
7366 NS_ENSURE_SUCCESS(newMUDV
->
7367 SetHintCharacterSetSource(hintCharsetSource
),
7369 NS_ENSURE_SUCCESS(newMUDV
->SetPrevDocCharacterSet(prevDocCharset
),
7371 NS_ENSURE_SUCCESS(newMUDV
->SetTextZoom(textZoom
),
7373 NS_ENSURE_SUCCESS(newMUDV
->SetFullZoom(pageZoom
),
7375 NS_ENSURE_SUCCESS(newMUDV
->SetAuthorStyleDisabled(styleDisabled
),
7379 // Stuff the bgcolor from the old pres shell into the new
7380 // pres shell. This improves page load continuity.
7381 nsCOMPtr
<nsIDocumentViewer
> docviewer
=
7382 do_QueryInterface(mContentViewer
);
7385 nsCOMPtr
<nsIPresShell
> shell
;
7386 docviewer
->GetPresShell(getter_AddRefs(shell
));
7389 shell
->SetCanvasBackground(bgcolor
);
7393 // XXX: It looks like the LayoutState gets restored again in Embed()
7394 // right after the call to SetupNewViewer(...)
7396 // We don't show the mContentViewer yet, since we want to draw the old page
7397 // until we have enough of the new page to show. Just return with the new
7398 // viewer still set to hidden.
7404 nsDocShell::SetDocPendingStateObj(nsISHEntry
*shEntry
)
7408 nsCOMPtr
<nsIDocument
> document
= do_GetInterface(GetAsSupports(this));
7409 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
7411 nsAutoString stateData
;
7413 rv
= shEntry
->GetStateData(stateData
);
7414 NS_ENSURE_SUCCESS(rv
, rv
);
7416 // if shEntry is null, we just set the pending state object to the
7420 document
->SetPendingStateObject(stateData
);
7425 nsDocShell::CheckLoadingPermissions()
7427 // This method checks whether the caller may load content into
7428 // this docshell. Even though we've done our best to hide windows
7429 // from code that doesn't have the right to access them, it's
7430 // still possible for an evil site to open a window and access
7431 // frames in the new window through window.frames[] (which is
7432 // allAccess for historic reasons), so we still need to do this
7434 nsresult rv
= NS_OK
, sameOrigin
= NS_OK
;
7436 if (!gValidateOrigin
|| !IsFrame()) {
7437 // Origin validation was turned off, or we're not a frame.
7438 // Permit all loads.
7443 // We're a frame. Check that the caller has write permission to
7444 // the parent before allowing it to load anything into this
7447 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
7448 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
7449 NS_ENSURE_SUCCESS(rv
, rv
);
7451 PRBool ubwEnabled
= PR_FALSE
;
7452 rv
= securityManager
->IsCapabilityEnabled("UniversalBrowserWrite",
7454 if (NS_FAILED(rv
) || ubwEnabled
) {
7458 nsCOMPtr
<nsIPrincipal
> subjPrincipal
;
7459 rv
= securityManager
->GetSubjectPrincipal(getter_AddRefs(subjPrincipal
));
7460 NS_ENSURE_TRUE(NS_SUCCEEDED(rv
) && subjPrincipal
, rv
);
7462 // Check if the caller is from the same origin as this docshell,
7463 // or any of its ancestors.
7464 nsCOMPtr
<nsIDocShellTreeItem
> item(this);
7466 nsCOMPtr
<nsIScriptGlobalObject
> sgo(do_GetInterface(item
));
7467 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(sgo
));
7470 if (!sop
|| !(p
= sop
->GetPrincipal())) {
7471 return NS_ERROR_UNEXPECTED
;
7476 sameOrigin
= subjPrincipal
->Equals(p
, &equal
);
7477 if (NS_SUCCEEDED(sameOrigin
)) {
7479 // Same origin, permit load
7484 sameOrigin
= NS_ERROR_DOM_PROP_ACCESS_DENIED
;
7487 nsCOMPtr
<nsIDocShellTreeItem
> tmp
;
7488 item
->GetSameTypeParent(getter_AddRefs(tmp
));
7495 //*****************************************************************************
7496 // nsDocShell: Site Loading
7497 //*****************************************************************************
7498 class InternalLoadEvent
: public nsRunnable
7501 InternalLoadEvent(nsDocShell
* aDocShell
, nsIURI
* aURI
, nsIURI
* aReferrer
,
7502 nsISupports
* aOwner
, PRUint32 aFlags
,
7503 const char* aTypeHint
, nsIInputStream
* aPostData
,
7504 nsIInputStream
* aHeadersData
, PRUint32 aLoadType
,
7505 nsISHEntry
* aSHEntry
, PRBool aFirstParty
) :
7506 mDocShell(aDocShell
),
7508 mReferrer(aReferrer
),
7510 mPostData(aPostData
),
7511 mHeadersData(aHeadersData
),
7514 mLoadType(aLoadType
),
7515 mFirstParty(aFirstParty
)
7517 // Make sure to keep null things null as needed
7519 mTypeHint
= aTypeHint
;
7524 return mDocShell
->InternalLoad(mURI
, mReferrer
, mOwner
, mFlags
,
7525 nsnull
, mTypeHint
.get(),
7526 mPostData
, mHeadersData
, mLoadType
,
7527 mSHEntry
, mFirstParty
, nsnull
, nsnull
);
7532 // Use IDL strings so .get() returns null by default
7533 nsXPIDLString mWindowTarget
;
7534 nsXPIDLCString mTypeHint
;
7536 nsRefPtr
<nsDocShell
> mDocShell
;
7537 nsCOMPtr
<nsIURI
> mURI
;
7538 nsCOMPtr
<nsIURI
> mReferrer
;
7539 nsCOMPtr
<nsISupports
> mOwner
;
7540 nsCOMPtr
<nsIInputStream
> mPostData
;
7541 nsCOMPtr
<nsIInputStream
> mHeadersData
;
7542 nsCOMPtr
<nsISHEntry
> mSHEntry
;
7549 nsDocShell::InternalLoad(nsIURI
* aURI
,
7551 nsISupports
* aOwner
,
7553 const PRUnichar
*aWindowTarget
,
7554 const char* aTypeHint
,
7555 nsIInputStream
* aPostData
,
7556 nsIInputStream
* aHeadersData
,
7558 nsISHEntry
* aSHEntry
,
7560 nsIDocShell
** aDocShell
,
7561 nsIRequest
** aRequest
)
7563 nsresult rv
= NS_OK
;
7566 if (gDocShellLeakLog
&& PR_LOG_TEST(gDocShellLeakLog
, PR_LOG_DEBUG
)) {
7569 aURI
->GetSpec(spec
);
7570 PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec
.get());
7574 // Initialize aDocShell/aRequest
7576 *aDocShell
= nsnull
;
7583 return NS_ERROR_NULL_POINTER
;
7586 NS_ENSURE_TRUE(IsValidLoadType(aLoadType
), NS_ERROR_INVALID_ARG
);
7588 NS_ENSURE_TRUE(!mIsBeingDestroyed
, NS_ERROR_NOT_AVAILABLE
);
7590 // wyciwyg urls can only be loaded through history. Any normal load of
7591 // wyciwyg through docshell is illegal. Disallow such loads.
7592 if (aLoadType
& LOAD_CMD_NORMAL
) {
7593 PRBool isWyciwyg
= PR_FALSE
;
7594 rv
= aURI
->SchemeIs("wyciwyg", &isWyciwyg
);
7595 if ((isWyciwyg
&& NS_SUCCEEDED(rv
)) || NS_FAILED(rv
))
7596 return NS_ERROR_FAILURE
;
7599 PRBool bIsJavascript
= PR_FALSE
;
7600 if (NS_FAILED(aURI
->SchemeIs("javascript", &bIsJavascript
))) {
7601 bIsJavascript
= PR_FALSE
;
7605 // First, notify any nsIContentPolicy listeners about the document load.
7606 // Only abort the load if a content policy listener explicitly vetos it!
7608 nsCOMPtr
<nsIDOMElement
> requestingElement
;
7609 // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
7610 nsCOMPtr
<nsPIDOMWindow
> privateWin(do_QueryInterface(mScriptGlobal
));
7612 requestingElement
= privateWin
->GetFrameElementInternal();
7614 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
7615 PRUint32 contentType
;
7617 NS_ASSERTION(requestingElement
, "A frame but no DOM element!?");
7618 contentType
= nsIContentPolicy::TYPE_SUBDOCUMENT
;
7620 contentType
= nsIContentPolicy::TYPE_DOCUMENT
;
7623 nsISupports
* context
= requestingElement
;
7625 context
= mScriptGlobal
;
7628 // XXXbz would be nice to know the loading principal here... but we don't
7629 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
;
7631 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
7632 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
7633 NS_ENSURE_SUCCESS(rv
, rv
);
7635 rv
= secMan
->GetCodebasePrincipal(aReferrer
,
7636 getter_AddRefs(loadingPrincipal
));
7639 rv
= NS_CheckContentLoadPolicy(contentType
,
7643 EmptyCString(), //mime guess
7647 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
)) {
7648 if (NS_SUCCEEDED(rv
) && shouldLoad
== nsIContentPolicy::REJECT_TYPE
) {
7649 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT
;
7652 return NS_ERROR_CONTENT_BLOCKED
;
7655 nsCOMPtr
<nsISupports
> owner(aOwner
);
7657 // Get an owner from the current document if necessary. Note that we only
7658 // do this for URIs that inherit a security context and local file URIs;
7659 // in particular we do NOT do this for about:blank. This way, random
7660 // about:blank loads that have no owner (which basically means they were
7661 // done by someone from chrome manually messing with our nsIWebNavigation
7662 // or by C++ setting document.location) don't get a funky principal. If
7663 // callers want something interesting to happen with the about:blank
7664 // principal in this case, they should pass an owner in.
7668 // One more twist: Don't inherit the owner for external loads.
7669 if (aLoadType
!= LOAD_NORMAL_EXTERNAL
&& !owner
&&
7670 (aFlags
& INTERNAL_LOAD_FLAGS_INHERIT_OWNER
) &&
7671 NS_SUCCEEDED(URIInheritsSecurityContext(aURI
, &inherits
)) &&
7674 // Don't allow loads that would inherit our security context
7675 // if this document came from an unsafe channel.
7676 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= this;
7678 nsCOMPtr
<nsIDocShell
> itemDocShell
=
7679 do_QueryInterface(treeItem
);
7682 NS_SUCCEEDED(itemDocShell
->GetChannelIsUnsafe(&isUnsafe
)) &&
7684 return NS_ERROR_DOM_SECURITY_ERR
;
7687 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
7688 treeItem
->GetSameTypeParent(getter_AddRefs(parent
));
7689 parent
.swap(treeItem
);
7692 owner
= GetInheritedPrincipal(PR_TRUE
);
7697 // Resolve the window target before going any further...
7698 // If the load has been targeted to another DocShell, then transfer the
7701 if (aWindowTarget
&& *aWindowTarget
) {
7702 // We've already done our owner-inheriting. Mask out that bit, so we
7703 // don't try inheriting an owner from the target window if we came up
7704 // with a null owner above.
7705 aFlags
= aFlags
& ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER
;
7707 // Locate the target DocShell.
7708 // This may involve creating a new toplevel window - if necessary.
7710 nsCOMPtr
<nsIDocShellTreeItem
> targetItem
;
7711 FindItemWithName(aWindowTarget
, nsnull
, this,
7712 getter_AddRefs(targetItem
));
7714 nsCOMPtr
<nsIDocShell
> targetDocShell
= do_QueryInterface(targetItem
);
7716 PRBool isNewWindow
= PR_FALSE
;
7717 if (!targetDocShell
) {
7718 nsCOMPtr
<nsIDOMWindowInternal
> win
=
7719 do_GetInterface(GetAsSupports(this));
7720 NS_ENSURE_TRUE(win
, NS_ERROR_NOT_AVAILABLE
);
7722 nsDependentString
name(aWindowTarget
);
7723 nsCOMPtr
<nsIDOMWindow
> newWin
;
7724 rv
= win
->Open(EmptyString(), // URL to load
7725 name
, // window name
7726 EmptyString(), // Features
7727 getter_AddRefs(newWin
));
7729 // In some cases the Open call doesn't actually result in a new
7730 // window being opened. We can detect these cases by examining the
7731 // document in |newWin|, if any.
7732 nsCOMPtr
<nsPIDOMWindow
> piNewWin
= do_QueryInterface(newWin
);
7734 nsCOMPtr
<nsIDocument
> newDoc
=
7735 do_QueryInterface(piNewWin
->GetExtantDocument());
7736 if (!newDoc
|| newDoc
->IsInitialDocument()) {
7737 isNewWindow
= PR_TRUE
;
7738 aFlags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
7742 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(newWin
);
7743 targetDocShell
= do_QueryInterface(webNav
);
7747 // Transfer the load to the target DocShell... Pass nsnull as the
7748 // window target name from to prevent recursive retargeting!
7750 if (NS_SUCCEEDED(rv
) && targetDocShell
) {
7751 rv
= targetDocShell
->InternalLoad(aURI
,
7755 nsnull
, // No window target
7764 if (rv
== NS_ERROR_NO_CONTENT
) {
7765 // XXXbz except we never reach this code!
7768 // At this point, a new window has been created, but the
7769 // URI did not have any data associated with it...
7771 // So, the best we can do, is to tear down the new window
7772 // that was just created!
7774 nsCOMPtr
<nsIDOMWindowInternal
> domWin
=
7775 do_GetInterface(targetDocShell
);
7781 // NS_ERROR_NO_CONTENT should not be returned to the
7782 // caller... This is an internal error code indicating that
7783 // the URI had no data associated with it - probably a
7784 // helper-app style protocol (ie. mailto://)
7788 else if (isNewWindow
) {
7789 // XXX: Once new windows are created hidden, the new
7790 // window will need to be made visible... For now,
7795 // Else we ran out of memory, or were a popup and got blocked,
7802 // Load is being targetted at this docshell so return an error if the
7803 // docshell is in the process of being destroyed.
7805 if (mIsBeingDestroyed
) {
7806 return NS_ERROR_FAILURE
;
7809 rv
= CheckLoadingPermissions();
7810 if (NS_FAILED(rv
)) {
7814 // If this docshell is owned by a frameloader, make sure to cancel
7815 // possible frameloader initialization before loading a new page.
7816 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
7817 GetParent(getter_AddRefs(parent
));
7819 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_GetInterface(parent
);
7820 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
7822 doc
->TryCancelFrameLoaderInitialization(this);
7826 if (mFiredUnloadEvent
) {
7827 if (IsOKToLoadURI(aURI
)) {
7828 NS_PRECONDITION(!aWindowTarget
|| !*aWindowTarget
,
7829 "Shouldn't have a window target here!");
7831 // If this is a replace load, make whatever load triggered
7832 // the unload event also a replace load, so we don't
7833 // create extra history entries.
7834 if (LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
7835 mLoadType
= LOAD_NORMAL_REPLACE
;
7838 // Do this asynchronously
7839 nsCOMPtr
<nsIRunnable
> ev
=
7840 new InternalLoadEvent(this, aURI
, aReferrer
, aOwner
, aFlags
,
7841 aTypeHint
, aPostData
, aHeadersData
,
7842 aLoadType
, aSHEntry
, aFirstParty
);
7843 return NS_DispatchToCurrentThread(ev
);
7846 // Just ignore this load attempt
7850 // Before going any further vet loads initiated by external programs.
7851 if (aLoadType
== LOAD_NORMAL_EXTERNAL
) {
7852 // Disallow external chrome: loads targetted at content windows
7853 PRBool isChrome
= PR_FALSE
;
7854 if (NS_SUCCEEDED(aURI
->SchemeIs("chrome", &isChrome
)) && isChrome
) {
7855 NS_WARNING("blocked external chrome: url -- use '-chrome' option");
7856 return NS_ERROR_FAILURE
;
7859 // clear the decks to prevent context bleed-through (bug 298255)
7860 rv
= CreateAboutBlankContentViewer(nsnull
, nsnull
);
7862 return NS_ERROR_FAILURE
;
7864 // reset loadType so we don't have to add lots of tests for
7865 // LOAD_NORMAL_EXTERNAL after this point
7866 aLoadType
= LOAD_NORMAL
;
7869 mAllowKeywordFixup
=
7870 (aFlags
& INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) != 0;
7871 mURIResultedInDocument
= PR_FALSE
; // reset the clock...
7875 // Check to see if the new URI is an anchor in the existing document.
7876 // Skip this check if we're doing some sort of abnormal load, if the
7877 // new load is a non-history load and has postdata, or if we're doing
7878 // a history load and the page identifiers of mOSHE and aSHEntry
7881 PRBool allowScroll
= PR_TRUE
;
7883 allowScroll
= (aPostData
== nsnull
);
7885 PRUint32 ourPageIdent
;
7886 mOSHE
->GetPageIdentifier(&ourPageIdent
);
7887 PRUint32 otherPageIdent
;
7888 aSHEntry
->GetPageIdentifier(&otherPageIdent
);
7889 allowScroll
= (ourPageIdent
== otherPageIdent
);
7892 nsCOMPtr
<nsIInputStream
> currentPostData
;
7893 mOSHE
->GetPostData(getter_AddRefs(currentPostData
));
7894 NS_ASSERTION(currentPostData
== aPostData
,
7895 "Different POST data for entries for the same page?");
7900 if (aLoadType
== LOAD_NORMAL
||
7901 aLoadType
== LOAD_STOP_CONTENT
||
7902 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) ||
7903 aLoadType
== LOAD_HISTORY
||
7904 aLoadType
== LOAD_LINK
) {
7906 PRBool wasAnchor
= PR_FALSE
;
7907 PRBool doHashchange
= PR_FALSE
;
7908 nscoord cx
= 0, cy
= 0;
7911 NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI
, &wasAnchor
, aLoadType
, &cx
,
7912 &cy
, &doHashchange
),
7916 // If this is a history load, aSHEntry will have document identifier X
7917 // if it was created as a result of a History.pushState() from a
7918 // SHEntry with doc ident X, or if it was created by changing the hash
7919 // of the URI corresponding to a SHEntry with doc ident X.
7920 PRBool sameDocIdent
= PR_FALSE
;
7921 if (mOSHE
&& aSHEntry
) {
7922 PRUint64 ourDocIdent
, otherDocIdent
;
7923 mOSHE
->GetDocIdentifier(&ourDocIdent
);
7924 aSHEntry
->GetDocIdentifier(&otherDocIdent
);
7925 sameDocIdent
= (ourDocIdent
== otherDocIdent
);
7928 // Do a short-circuited load if the new URI differs from the current
7929 // URI only in the hash, or if the two entries belong to the same
7930 // document and don't point to the same object.
7932 // (If we didn't check that the SHEntries are different objects,
7933 // history.go(0) would short-circuit instead of triggering a true
7934 // load, and we wouldn't dispatch an onload event to the page.)
7935 if (wasAnchor
|| (sameDocIdent
&& (mOSHE
!= aSHEntry
))) {
7936 mLoadType
= aLoadType
;
7937 mURIResultedInDocument
= PR_TRUE
;
7939 /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
7940 * SetCurrentURI() called from OnNewURI() will send proper
7941 * onLocationChange() notifications to the browser to update
7942 * back/forward buttons.
7944 SetHistoryEntry(&mLSHE
, aSHEntry
);
7946 /* This is a anchor traversal with in the same page.
7947 * call OnNewURI() so that, this traversal will be
7948 * recorded in session and global history.
7950 nsCOMPtr
<nsISupports
> owner
;
7952 mOSHE
->GetOwner(getter_AddRefs(owner
));
7954 OnNewURI(aURI
, nsnull
, owner
, mLoadType
, PR_TRUE
, PR_TRUE
);
7956 nsCOMPtr
<nsIInputStream
> postData
;
7957 PRUint32 pageIdent
= PR_UINT32_MAX
;
7958 nsCOMPtr
<nsISupports
> cacheKey
;
7961 /* save current position of scroller(s) (bug 59774) */
7962 mOSHE
->SetScrollPosition(cx
, cy
);
7963 // Get the postdata and page ident from the current page, if
7964 // the new load is being done via normal means. Note that
7965 // "normal means" can be checked for just by checking for
7966 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
7967 // above -- it filters out some LOAD_CMD_NORMAL cases that we
7968 // wouldn't want here.
7969 if (aLoadType
& LOAD_CMD_NORMAL
) {
7970 mOSHE
->GetPostData(getter_AddRefs(postData
));
7971 mOSHE
->GetPageIdentifier(&pageIdent
);
7972 mOSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
7975 if (mLSHE
&& wasAnchor
) {
7976 // If it's an anchor load, set mLSHE's doc identifier to
7977 // mOSHE's doc identifier -- These are the same documents,
7978 // as far as HTML5 is concerned.
7980 rv
= mOSHE
->GetDocIdentifier(&docIdent
);
7981 if (NS_SUCCEEDED(rv
)) {
7982 mLSHE
->SetDocIdentifier(docIdent
);
7987 /* Assign mOSHE to mLSHE. This will either be a new entry created
7988 * by OnNewURI() for normal loads or aSHEntry for history loads.
7991 SetHistoryEntry(&mOSHE
, mLSHE
);
7992 // Save the postData obtained from the previous page
7993 // in to the session history entry created for the
7994 // anchor page, so that any history load of the anchor
7995 // page will restore the appropriate postData.
7997 mOSHE
->SetPostData(postData
);
7999 // Make sure we won't just repost without hitting the
8002 mOSHE
->SetCacheKey(cacheKey
);
8004 // Propagate our page ident to the new mOSHE so that
8005 // we'll know it just differed by a scroll on the page.
8006 if (pageIdent
!= PR_UINT32_MAX
)
8007 mOSHE
->SetPageIdentifier(pageIdent
);
8010 /* restore previous position of scroller(s), if we're moving
8011 * back in history (bug 59774)
8013 if (mOSHE
&& (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
))
8016 mOSHE
->GetScrollPosition(&bx
, &by
);
8017 SetCurScrollPosEx(bx
, by
);
8020 /* Clear out mLSHE so that further anchor visits get
8021 * recorded in SH and SH won't misbehave.
8023 SetHistoryEntry(&mLSHE
, nsnull
);
8024 /* Set the title for the SH entry for this target url. so that
8025 * SH menus in go/back/forward buttons won't be empty for this.
8027 if (mSessionHistory
) {
8029 mSessionHistory
->GetIndex(&index
);
8030 nsCOMPtr
<nsIHistoryEntry
> hEntry
;
8031 mSessionHistory
->GetEntryAtIndex(index
, PR_FALSE
,
8032 getter_AddRefs(hEntry
));
8033 NS_ENSURE_TRUE(hEntry
, NS_ERROR_FAILURE
);
8034 nsCOMPtr
<nsISHEntry
> shEntry(do_QueryInterface(hEntry
));
8036 shEntry
->SetTitle(mTitle
);
8039 /* Set the title for the Global History entry for this anchor url.
8041 if (mGlobalHistory
) {
8042 mGlobalHistory
->SetPageTitle(aURI
, mTitle
);
8046 // Set the doc's URI according to the new history entry's URI
8047 nsCOMPtr
<nsIURI
> newURI
;
8048 mOSHE
->GetURI(getter_AddRefs(newURI
));
8049 NS_ENSURE_TRUE(newURI
, NS_ERROR_FAILURE
);
8050 nsCOMPtr
<nsIDocument
> doc
=
8051 do_GetInterface(GetAsSupports(this));
8052 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
8054 doc
->SetDocumentURI(newURI
);
8057 SetDocPendingStateObj(mOSHE
);
8059 // Dispatch the popstate and hashchange events, as appropriate
8060 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(mScriptGlobal
);
8062 window
->DispatchSyncPopState();
8065 window
->DispatchSyncHashchange();
8072 // mContentViewer->PermitUnload can destroy |this| docShell, which
8073 // causes the next call of CanSavePresentation to crash.
8074 // Hold onto |this| until we return, to prevent a crash from happening.
8076 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
8078 // Check if the page doesn't want to be unloaded. The javascript:
8079 // protocol handler deals with this for javascript: URLs.
8080 if (!bIsJavascript
&& mContentViewer
) {
8082 rv
= mContentViewer
->PermitUnload(PR_FALSE
, &okToUnload
);
8084 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
8085 // The user chose not to unload the page, interrupt the
8091 // Check for saving the presentation here, before calling Stop().
8092 // This is necessary so that we can catch any pending requests.
8093 // Since the new request has not been created yet, we pass null for the
8094 // new request parameter.
8095 // Also pass nsnull for the document, since it doesn't affect the return
8096 // value for our purposes here.
8097 PRBool savePresentation
= CanSavePresentation(aLoadType
, nsnull
, nsnull
);
8099 // Don't stop current network activity for javascript: URL's since
8100 // they might not result in any data, and thus nothing should be
8101 // stopped in those cases. In the case where they do result in
8102 // data, the javascript: URL channel takes care of stopping
8103 // current network activity.
8104 if (!bIsJavascript
) {
8105 // Stop any current network activity.
8106 // Also stop content if this is a zombie doc. otherwise
8107 // the onload will be delayed by other loads initiated in the
8108 // background by the first document that
8109 // didn't fully load before the next load was initiated.
8110 // If not a zombie, don't stop content until data
8111 // starts arriving from the new URI...
8113 nsCOMPtr
<nsIContentViewer
> zombieViewer
;
8114 if (mContentViewer
) {
8115 mContentViewer
->GetPreviousViewer(getter_AddRefs(zombieViewer
));
8119 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_STOP_CONTENT
)) {
8120 rv
= Stop(nsIWebNavigation::STOP_ALL
);
8122 rv
= Stop(nsIWebNavigation::STOP_NETWORK
);
8129 mLoadType
= aLoadType
;
8131 // mLSHE should be assigned to aSHEntry, only after Stop() has
8132 // been called. But when loading an error page, do not clear the
8133 // mLSHE for the real page.
8134 if (mLoadType
!= LOAD_ERROR_PAGE
)
8135 SetHistoryEntry(&mLSHE
, aSHEntry
);
8137 mSavingOldViewer
= savePresentation
;
8139 // If we have a saved content viewer in history, restore and show it now.
8140 if (aSHEntry
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
8141 // It's possible that the previous viewer of mContentViewer is the
8142 // viewer that will end up in aSHEntry when it gets closed. If that's
8143 // the case, we need to go ahead and force it into its shentry so we
8145 if (mContentViewer
) {
8146 nsCOMPtr
<nsIContentViewer
> prevViewer
;
8147 mContentViewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
8150 nsCOMPtr
<nsIContentViewer
> prevPrevViewer
;
8151 prevViewer
->GetPreviousViewer(getter_AddRefs(prevPrevViewer
));
8152 NS_ASSERTION(!prevPrevViewer
, "Should never have viewer chain here");
8154 nsCOMPtr
<nsISHEntry
> viewerEntry
;
8155 prevViewer
->GetHistoryEntry(getter_AddRefs(viewerEntry
));
8156 if (viewerEntry
== aSHEntry
) {
8157 // Make sure this viewer ends up in the right place
8158 mContentViewer
->SetPreviousViewer(nsnull
);
8159 prevViewer
->Destroy();
8163 nsCOMPtr
<nsISHEntry
> oldEntry
= mOSHE
;
8165 rv
= RestorePresentation(aSHEntry
, &restoring
);
8169 // We failed to restore the presentation, so clean up.
8170 // Both the old and new history entries could potentially be in
8171 // an inconsistent state.
8172 if (NS_FAILED(rv
)) {
8174 oldEntry
->SyncPresentationState();
8176 aSHEntry
->SyncPresentationState();
8180 nsCOMPtr
<nsIRequest
> req
;
8181 rv
= DoURILoad(aURI
, aReferrer
,
8182 !(aFlags
& INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
),
8183 owner
, aTypeHint
, aPostData
, aHeadersData
, aFirstParty
,
8184 aDocShell
, getter_AddRefs(req
),
8185 (aFlags
& INTERNAL_LOAD_FLAGS_FIRST_LOAD
) != 0,
8186 (aFlags
& INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
) != 0,
8187 (aFlags
& INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES
) != 0);
8188 if (req
&& aRequest
)
8189 NS_ADDREF(*aRequest
= req
);
8191 if (NS_FAILED(rv
)) {
8192 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(req
));
8193 DisplayLoadError(rv
, aURI
, nsnull
, chan
);
8200 nsDocShell::GetInheritedPrincipal(PRBool aConsiderCurrentDocument
)
8202 nsCOMPtr
<nsIDocument
> document
;
8204 if (aConsiderCurrentDocument
&& mContentViewer
) {
8205 document
= mContentViewer
->GetDocument();
8209 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
8210 GetSameTypeParent(getter_AddRefs(parentItem
));
8212 nsCOMPtr
<nsIDOMDocument
> parentDomDoc(do_GetInterface(parentItem
));
8213 document
= do_QueryInterface(parentDomDoc
);
8218 if (!aConsiderCurrentDocument
) {
8222 // Make sure we end up with _something_ as the principal no matter
8224 EnsureContentViewer(); // If this fails, we'll just get a null
8225 // docViewer and bail.
8227 if (!mContentViewer
)
8229 document
= mContentViewer
->GetDocument();
8232 //-- Get the document's principal
8234 return document
->NodePrincipal();
8241 nsDocShell::ShouldCheckAppCache(nsIURI
*aURI
)
8243 nsCOMPtr
<nsIOfflineCacheUpdateService
> offlineService
=
8244 do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID
);
8245 if (!offlineService
) {
8250 nsresult rv
= offlineService
->OfflineAppAllowedForURI(aURI
,
8253 return NS_SUCCEEDED(rv
) && allowed
;
8257 nsDocShell::DoURILoad(nsIURI
* aURI
,
8258 nsIURI
* aReferrerURI
,
8259 PRBool aSendReferrer
,
8260 nsISupports
* aOwner
,
8261 const char * aTypeHint
,
8262 nsIInputStream
* aPostData
,
8263 nsIInputStream
* aHeadersData
,
8265 nsIDocShell
** aDocShell
,
8266 nsIRequest
** aRequest
,
8267 PRBool aIsNewWindowTarget
,
8268 PRBool aBypassClassifier
,
8269 PRBool aForceAllowCookies
)
8272 nsCOMPtr
<nsIURILoader
> uriLoader
;
8274 uriLoader
= do_GetService(NS_URI_LOADER_CONTRACTID
, &rv
);
8275 if (NS_FAILED(rv
)) return rv
;
8277 nsLoadFlags loadFlags
= nsIRequest::LOAD_NORMAL
;
8279 // tag first party URL loads
8280 loadFlags
|= nsIChannel::LOAD_INITIAL_DOCUMENT_URI
;
8283 if (mLoadType
== LOAD_ERROR_PAGE
) {
8284 // Error pages are LOAD_BACKGROUND
8285 loadFlags
|= nsIChannel::LOAD_BACKGROUND
;
8288 // check for Content Security Policy to pass along with the
8289 // new channel we are creating
8290 nsCOMPtr
<nsIChannelPolicy
> channelPolicy
;
8292 // check the parent docshell for a CSP
8293 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
8294 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
8295 GetSameTypeParent(getter_AddRefs(parentItem
));
8296 nsCOMPtr
<nsIDOMDocument
> domDoc(do_GetInterface(parentItem
));
8297 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
8299 rv
= doc
->NodePrincipal()->GetCsp(getter_AddRefs(csp
));
8300 NS_ENSURE_SUCCESS(rv
, rv
);
8302 channelPolicy
= do_CreateInstance("@mozilla.org/nschannelpolicy;1");
8303 channelPolicy
->SetContentSecurityPolicy(csp
);
8304 channelPolicy
->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT
);
8309 // open a channel for the url
8310 nsCOMPtr
<nsIChannel
> channel
;
8312 rv
= NS_NewChannel(getter_AddRefs(channel
),
8316 static_cast<nsIInterfaceRequestor
*>(this),
8319 if (NS_FAILED(rv
)) {
8320 if (rv
== NS_ERROR_UNKNOWN_PROTOCOL
) {
8321 // This is a uri with a protocol scheme we don't know how
8322 // to handle. Embedders might still be interested in
8323 // handling the load, though, so we fire a notification
8324 // before throwing the load away.
8325 PRBool abort
= PR_FALSE
;
8326 nsresult rv2
= mContentListener
->OnStartURIOpen(aURI
, &abort
);
8327 if (NS_SUCCEEDED(rv2
) && abort
) {
8328 // Hey, they're handling the load for us! How convenient!
8336 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
8337 do_QueryInterface(channel
);
8338 if (appCacheChannel
) {
8339 // Any document load should not inherit application cache.
8340 appCacheChannel
->SetInheritApplicationCache(PR_FALSE
);
8342 // Loads with the correct permissions should check for a matching
8343 // application cache.
8344 appCacheChannel
->SetChooseApplicationCache(ShouldCheckAppCache(aURI
));
8347 // Make sure to give the caller a channel if we managed to create one
8348 // This is important for correct error page/session history interaction
8350 NS_ADDREF(*aRequest
= channel
);
8352 channel
->SetOriginalURI(aURI
);
8353 if (aTypeHint
&& *aTypeHint
) {
8354 channel
->SetContentType(nsDependentCString(aTypeHint
));
8355 mContentTypeHint
= aTypeHint
;
8358 mContentTypeHint
.Truncate();
8362 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
8363 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInternal(do_QueryInterface(channel
));
8364 if (httpChannelInternal
) {
8365 if (aForceAllowCookies
) {
8366 httpChannelInternal
->SetForceAllowThirdPartyCookie(PR_TRUE
);
8369 httpChannelInternal
->SetDocumentURI(aURI
);
8371 httpChannelInternal
->SetDocumentURI(aReferrerURI
);
8375 nsCOMPtr
<nsIWritablePropertyBag2
> props(do_QueryInterface(channel
));
8378 // save true referrer for those who need it (e.g. xpinstall whitelisting)
8379 // Currently only http and ftp channels support this.
8380 props
->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
8385 // If this is a HTTP channel, then set up the HTTP specific information
8386 // (ie. POST data, referrer, ...)
8389 nsCOMPtr
<nsICachingChannel
> cacheChannel(do_QueryInterface(httpChannel
));
8390 /* Get the cache Key from SH */
8391 nsCOMPtr
<nsISupports
> cacheKey
;
8393 mLSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
8395 else if (mOSHE
) // for reload cases
8396 mOSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
8398 // figure out if we need to set the post data stream on the channel...
8399 // right now, this is only done for http channels.....
8401 // XXX it's a bit of a hack to rewind the postdata stream here but
8402 // it has to be done in case the post data is being reused multiple
8404 nsCOMPtr
<nsISeekableStream
>
8405 postDataSeekable(do_QueryInterface(aPostData
));
8406 if (postDataSeekable
) {
8407 rv
= postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
8408 NS_ENSURE_SUCCESS(rv
, rv
);
8411 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
8412 NS_ASSERTION(uploadChannel
, "http must support nsIUploadChannel");
8414 // we really need to have a content type associated with this stream!!
8415 uploadChannel
->SetUploadStream(aPostData
, EmptyCString(), -1);
8416 /* If there is a valid postdata *and* it is a History Load,
8417 * set up the cache key on the channel, to retrieve the
8418 * data *only* from the cache. If it is a normal reload, the
8419 * cache is free to go to the server for updated postdata.
8421 if (cacheChannel
&& cacheKey
) {
8422 if (mLoadType
== LOAD_HISTORY
|| mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
8423 cacheChannel
->SetCacheKey(cacheKey
);
8425 if (NS_SUCCEEDED(channel
->GetLoadFlags(&loadFlags
)))
8426 channel
->SetLoadFlags(loadFlags
| nsICachingChannel::LOAD_ONLY_FROM_CACHE
);
8428 else if (mLoadType
== LOAD_RELOAD_NORMAL
)
8429 cacheChannel
->SetCacheKey(cacheKey
);
8433 /* If there is no postdata, set the cache key on the channel, and
8434 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
8435 * will be free to get it from net if it is not found in cache.
8436 * New cache may use it creatively on CGI pages with GET
8437 * method and even on those that say "no-cache"
8439 if (mLoadType
== LOAD_HISTORY
|| mLoadType
== LOAD_RELOAD_NORMAL
8440 || mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
8441 if (cacheChannel
&& cacheKey
)
8442 cacheChannel
->SetCacheKey(cacheKey
);
8446 rv
= AddHeadersToChannel(aHeadersData
, httpChannel
);
8448 // Set the referrer explicitly
8449 if (aReferrerURI
&& aSendReferrer
) {
8450 // Referrer is currenly only set for link clicks here.
8451 httpChannel
->SetReferrer(aReferrerURI
);
8455 // Set the owner of the channel, but only for channels that can't
8456 // provide their own security context.
8458 // XXX: Is seems wrong that the owner is ignored - even if one is
8459 // supplied) unless the URI is javascript or data or about:blank.
8460 // XXX: If this is ever changed, check all callers for what owners they're
8461 // passing in. In particular, see the code and comments in LoadURI
8462 // where we fall back on inheriting the owner if called
8463 // from chrome. That would be very wrong if this code changed
8464 // anything but channels that can't provide their own security context!
8466 // (Currently chrome URIs set the owner when they are created!
8467 // So setting a NULL owner would be bad!)
8469 // If this code ever changes, change nsObjectLoadingContent::LoadObject
8472 // We expect URIInheritsSecurityContext to return success for an
8473 // about:blank URI, so don't call IsAboutBlank() if this call fails.
8474 rv
= URIInheritsSecurityContext(aURI
, &inherit
);
8475 if (NS_SUCCEEDED(rv
) && (inherit
|| IsAboutBlank(aURI
))) {
8476 channel
->SetOwner(aOwner
);
8480 // file: uri special-casing
8482 // If this is a file: load opened from another file: then it may need
8483 // to inherit the owner from the referrer so they can script each other.
8484 // If we don't set the owner explicitly then each file: gets an owner
8485 // based on its own codebase later.
8487 nsCOMPtr
<nsIPrincipal
> ownerPrincipal(do_QueryInterface(aOwner
));
8488 if (URIIsLocalFile(aURI
) && ownerPrincipal
&&
8489 NS_SUCCEEDED(ownerPrincipal
->CheckMayLoad(aURI
, PR_FALSE
))) {
8490 // One more check here. CheckMayLoad will always return true for the
8491 // system principal, but we do NOT want to inherit in that case.
8493 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
8494 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
8496 NS_SUCCEEDED(secMan
->IsSystemPrincipal(ownerPrincipal
,
8499 channel
->SetOwner(aOwner
);
8503 nsCOMPtr
<nsIScriptChannel
> scriptChannel
= do_QueryInterface(channel
);
8504 if (scriptChannel
) {
8505 // Allow execution against our context if the principals match
8507 SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
8510 if (aIsNewWindowTarget
) {
8511 nsCOMPtr
<nsIWritablePropertyBag2
> props
= do_QueryInterface(channel
);
8513 props
->SetPropertyAsBool(
8514 NS_LITERAL_STRING("docshell.newWindowTarget"),
8519 rv
= DoChannelLoad(channel
, uriLoader
, aBypassClassifier
);
8522 // If the channel load failed, we failed and nsIWebProgress just ain't
8525 if (NS_SUCCEEDED(rv
)) {
8528 NS_ADDREF(*aDocShell
);
8536 AppendSegmentToString(nsIInputStream
*in
,
8538 const char *fromRawSegment
,
8541 PRUint32
*writeCount
)
8543 // aFromSegment now contains aCount bytes of data.
8545 nsCAutoString
*buf
= static_cast<nsCAutoString
*>(closure
);
8546 buf
->Append(fromRawSegment
, count
);
8548 // Indicate that we have consumed all of aFromSegment
8549 *writeCount
= count
;
8554 nsDocShell::AddHeadersToChannel(nsIInputStream
*aHeadersData
,
8555 nsIChannel
*aGenericChannel
)
8557 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aGenericChannel
);
8558 NS_ENSURE_STATE(httpChannel
);
8561 nsCAutoString headersString
;
8562 nsresult rv
= aHeadersData
->ReadSegments(AppendSegmentToString
,
8566 NS_ENSURE_SUCCESS(rv
, rv
);
8568 // used during the manipulation of the String from the InputStream
8569 nsCAutoString headerName
;
8570 nsCAutoString headerValue
;
8575 // Iterate over the headersString: for each "\r\n" delimited chunk,
8576 // add the value as a header to the nsIHttpChannel
8579 static const char kWhitespace
[] = "\b\t\r\n ";
8581 crlf
= headersString
.Find("\r\n");
8582 if (crlf
== kNotFound
)
8585 const nsCSubstring
&oneHeader
= StringHead(headersString
, crlf
);
8587 colon
= oneHeader
.FindChar(':');
8588 if (colon
== kNotFound
)
8589 return NS_ERROR_UNEXPECTED
;
8591 headerName
= StringHead(oneHeader
, colon
);
8592 headerValue
= Substring(oneHeader
, colon
+ 1);
8594 headerName
.Trim(kWhitespace
);
8595 headerValue
.Trim(kWhitespace
);
8597 headersString
.Cut(0, crlf
+ 2);
8600 // FINALLY: we can set the header!
8603 rv
= httpChannel
->SetRequestHeader(headerName
, headerValue
, PR_TRUE
);
8604 NS_ENSURE_SUCCESS(rv
, rv
);
8607 NS_NOTREACHED("oops");
8608 return NS_ERROR_UNEXPECTED
;
8611 nsresult
nsDocShell::DoChannelLoad(nsIChannel
* aChannel
,
8612 nsIURILoader
* aURILoader
,
8613 PRBool aBypassClassifier
)
8616 // Mark the channel as being a document URI and allow content sniffing...
8617 nsLoadFlags loadFlags
= 0;
8618 (void) aChannel
->GetLoadFlags(&loadFlags
);
8619 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
|
8620 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS
;
8622 // Load attributes depend on load type...
8623 switch (mLoadType
) {
8625 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
8628 case LOAD_RELOAD_CHARSET_CHANGE
:
8629 loadFlags
|= nsIRequest::LOAD_FROM_CACHE
;
8632 case LOAD_RELOAD_NORMAL
:
8634 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
8637 case LOAD_NORMAL_BYPASS_CACHE
:
8638 case LOAD_NORMAL_BYPASS_PROXY
:
8639 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
8640 case LOAD_RELOAD_BYPASS_CACHE
:
8641 case LOAD_RELOAD_BYPASS_PROXY
:
8642 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
8643 loadFlags
|= nsIRequest::LOAD_BYPASS_CACHE
;
8648 // Set cache checking flags
8649 PRInt32 prefSetting
;
8652 GetIntPref("browser.cache.check_doc_frequency",
8654 switch (prefSetting
) {
8656 loadFlags
|= nsIRequest::VALIDATE_ONCE_PER_SESSION
;
8659 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
8662 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
8669 if (!aBypassClassifier
) {
8670 loadFlags
|= nsIChannel::LOAD_CLASSIFY_URI
;
8673 (void) aChannel
->SetLoadFlags(loadFlags
);
8675 rv
= aURILoader
->OpenURI(aChannel
,
8676 (mLoadType
== LOAD_LINK
),
8678 NS_ENSURE_SUCCESS(rv
, rv
);
8684 nsDocShell::ScrollIfAnchor(nsIURI
* aURI
, PRBool
* aWasAnchor
,
8685 PRUint32 aLoadType
, nscoord
*cx
, nscoord
*cy
,
8686 PRBool
* aDoHashchange
)
8688 NS_ASSERTION(aURI
, "null uri arg");
8689 NS_ASSERTION(aWasAnchor
, "null anchor arg");
8690 NS_PRECONDITION(aDoHashchange
, "null hashchange arg");
8692 if (!aURI
|| !aWasAnchor
) {
8693 return NS_ERROR_FAILURE
;
8696 *aWasAnchor
= PR_FALSE
;
8697 *aDoHashchange
= PR_FALSE
;
8703 nsCOMPtr
<nsIPresShell
> shell
;
8704 nsresult rv
= GetPresShell(getter_AddRefs(shell
));
8705 if (NS_FAILED(rv
) || !shell
) {
8706 // If we failed to get the shell, or if there is no shell,
8707 // nothing left to do here.
8712 // NOTE: we assume URIs are absolute for comparison purposes
8714 nsCAutoString currentSpec
;
8715 NS_ENSURE_SUCCESS(mCurrentURI
->GetSpec(currentSpec
),
8718 nsCAutoString newSpec
;
8719 NS_ENSURE_SUCCESS(aURI
->GetSpec(newSpec
), NS_ERROR_FAILURE
);
8721 // Search for hash marks in the current URI and the new URI and
8722 // take a copy of everything to the left of the hash for
8725 const char kHash
= '#';
8727 // Split the new URI into a left and right part
8728 // (assume we're parsing it out right)
8729 nsACString::const_iterator urlStart
, urlEnd
, refStart
, refEnd
;
8730 newSpec
.BeginReading(urlStart
);
8731 newSpec
.EndReading(refEnd
);
8733 PRInt32 hashNew
= newSpec
.FindChar(kHash
);
8735 return NS_OK
; // Strange URI
8741 urlEnd
.advance(hashNew
);
8744 ++refStart
; // advanced past '#'
8749 urlEnd
= refStart
= refEnd
;
8751 const nsACString
& sNewLeft
= Substring(urlStart
, urlEnd
);
8752 const nsACString
& sNewRef
= Substring(refStart
, refEnd
);
8754 // Split the current URI in a left and right part
8755 nsACString::const_iterator currentLeftStart
, currentLeftEnd
,
8756 currentRefStart
, currentRefEnd
;
8757 currentSpec
.BeginReading(currentLeftStart
);
8758 currentSpec
.EndReading(currentRefEnd
);
8760 PRInt32 hashCurrent
= currentSpec
.FindChar(kHash
);
8761 if (hashCurrent
== 0) {
8762 return NS_OK
; // Strange URI
8765 if (hashCurrent
> 0) {
8766 currentLeftEnd
= currentLeftStart
;
8767 currentLeftEnd
.advance(hashCurrent
);
8769 currentRefStart
= currentLeftEnd
;
8770 ++currentRefStart
; // advance past '#'
8773 // no hash at all in currentSpec
8774 currentLeftEnd
= currentRefStart
= currentRefEnd
;
8777 // If we have no new anchor, we do not want to scroll, unless there is a
8778 // current anchor and we are doing a history load. So return if we have no
8779 // new anchor, and there is no current anchor or the load is not a history
8781 NS_ASSERTION(hashNew
!= 0 && hashCurrent
!= 0,
8782 "What happened to the early returns above?");
8783 if (hashNew
== kNotFound
&&
8784 (hashCurrent
== kNotFound
|| aLoadType
!= LOAD_HISTORY
)) {
8788 // Compare the URIs.
8790 // NOTE: this is a case sensitive comparison because some parts of the
8791 // URI are case sensitive, and some are not. i.e. the domain name
8792 // is case insensitive but the the paths are not.
8794 // This means that comparing "http://www.ABC.com/" to "http://www.abc.com/"
8795 // will fail this test.
8797 if (!Substring(currentLeftStart
, currentLeftEnd
).Equals(sNewLeft
)) {
8798 return NS_OK
; // URIs not the same
8801 // Now we know we are dealing with an anchor
8802 *aWasAnchor
= PR_TRUE
;
8804 // We should fire a hashchange event once we're done here if the two hashes
8806 *aDoHashchange
= !Substring(currentRefStart
, currentRefEnd
).Equals(sNewRef
);
8808 // Both the new and current URIs refer to the same page. We can now
8809 // browse to the hash stored in the new URI.
8811 // But first let's capture positions of scroller(s) that can
8812 // (and usually will) be modified by GoToAnchor() call.
8814 GetCurScrollPos(ScrollOrientation_X
, cx
);
8815 GetCurScrollPos(ScrollOrientation_Y
, cy
);
8817 if (!sNewRef
.IsEmpty()) {
8818 // anchor is there, but if it's a load from history,
8819 // we don't have any anchor jumping to do
8820 PRBool scroll
= aLoadType
!= LOAD_HISTORY
&&
8821 aLoadType
!= LOAD_RELOAD_NORMAL
;
8823 char *str
= ToNewCString(sNewRef
);
8825 return NS_ERROR_OUT_OF_MEMORY
;
8828 // nsUnescape modifies the string that is passed into it.
8831 // We assume that the bytes are in UTF-8, as it says in the
8833 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
8835 // We try the UTF-8 string first, and then try the document's
8836 // charset (see below). If the string is not UTF-8,
8837 // conversion will fail and give us an empty Unicode string.
8838 // In that case, we should just fall through to using the
8840 rv
= NS_ERROR_FAILURE
;
8841 NS_ConvertUTF8toUTF16
uStr(str
);
8842 if (!uStr
.IsEmpty()) {
8843 rv
= shell
->GoToAnchor(NS_ConvertUTF8toUTF16(str
), scroll
);
8845 nsMemory::Free(str
);
8847 // Above will fail if the anchor name is not UTF-8. Need to
8848 // convert from document charset to unicode.
8849 if (NS_FAILED(rv
)) {
8851 // Get a document charset
8852 NS_ENSURE_TRUE(mContentViewer
, NS_ERROR_FAILURE
);
8853 nsIDocument
* doc
= mContentViewer
->GetDocument();
8854 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
8855 const nsACString
&aCharset
= doc
->GetDocumentCharacterSet();
8857 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
8858 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
8859 NS_ENSURE_SUCCESS(rv
, rv
);
8861 // Unescape and convert to unicode
8864 rv
= textToSubURI
->UnEscapeAndConvert(PromiseFlatCString(aCharset
).get(),
8865 PromiseFlatCString(sNewRef
).get(),
8866 getter_Copies(uStr
));
8867 NS_ENSURE_SUCCESS(rv
, rv
);
8869 // Ignore return value of GoToAnchor, since it will return an error
8870 // if there is no such anchor in the document, which is actually a
8871 // success condition for us (we want to update the session history
8872 // with the new URI no matter whether we actually scrolled
8874 shell
->GoToAnchor(uStr
, scroll
);
8879 // Tell the shell it's at an anchor, without scrolling.
8880 shell
->GoToAnchor(EmptyString(), PR_FALSE
);
8882 // An empty anchor was found, but if it's a load from history,
8883 // we don't have to jump to the top of the page. Scrollbar
8884 // position will be restored by the caller, based on positions
8885 // stored in session history.
8886 if (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
)
8888 //An empty anchor. Scroll to the top of the page.
8889 rv
= SetCurScrollPosEx(0, 0);
8896 nsDocShell::SetupReferrerFromChannel(nsIChannel
* aChannel
)
8898 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
8900 nsCOMPtr
<nsIURI
> referrer
;
8901 nsresult rv
= httpChannel
->GetReferrer(getter_AddRefs(referrer
));
8902 if (NS_SUCCEEDED(rv
)) {
8903 SetReferrerURI(referrer
);
8909 nsDocShell::OnNewURI(nsIURI
* aURI
, nsIChannel
* aChannel
, nsISupports
* aOwner
,
8910 PRUint32 aLoadType
, PRBool aFireOnLocationChange
,
8911 PRBool aAddToGlobalHistory
)
8913 NS_PRECONDITION(aURI
, "uri is null");
8914 NS_PRECONDITION(!aChannel
|| !aOwner
, "Shouldn't have both set");
8916 #if defined(PR_LOGGING) && defined(DEBUG)
8917 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
8919 aURI
->GetSpec(spec
);
8921 nsCAutoString chanName
;
8923 aChannel
->GetName(chanName
);
8925 chanName
.AssignLiteral("<no channel>");
8927 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
8928 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec
.get(),
8929 chanName
.get(), aLoadType
));
8933 PRBool updateHistory
= PR_TRUE
;
8934 PRBool equalUri
= PR_FALSE
;
8935 PRBool shAvailable
= PR_TRUE
;
8937 // Get the post data from the channel
8938 nsCOMPtr
<nsIInputStream
> inputStream
;
8940 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
8942 // Check if the HTTPChannel is hiding under a multiPartChannel
8944 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
8948 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
8949 if (uploadChannel
) {
8950 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
8953 // If the response status indicates an error, unlink this session
8954 // history entry from any entries sharing its doc ident.
8955 PRUint32 responseStatus
;
8956 nsresult rv
= httpChannel
->GetResponseStatus(&responseStatus
);
8957 if (mLSHE
&& NS_SUCCEEDED(rv
) && responseStatus
>= 400) {
8958 mLSHE
->SetUniqueDocIdentifier();
8962 /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
8963 * the current frame or in the root docshell
8965 nsCOMPtr
<nsISHistory
> rootSH
= mSessionHistory
;
8967 // Get the handle to SH from the root docshell
8968 GetRootSessionHistory(getter_AddRefs(rootSH
));
8970 shAvailable
= PR_FALSE
;
8974 // Determine if this type of load should update history.
8975 if (aLoadType
== LOAD_BYPASS_HISTORY
||
8976 aLoadType
== LOAD_ERROR_PAGE
||
8977 aLoadType
& LOAD_CMD_HISTORY
||
8978 aLoadType
& LOAD_CMD_RELOAD
)
8979 updateHistory
= PR_FALSE
;
8981 // Check if the url to be loaded is the same as the one already loaded.
8983 aURI
->Equals(mCurrentURI
, &equalUri
);
8986 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
8987 (" shAvailable=%i updateHistory=%i equalURI=%i\n",
8988 shAvailable
, updateHistory
, equalUri
));
8991 /* If the url to be loaded is the same as the one already there,
8992 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
8993 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
8994 * AddToSessionHistory() won't mess with the current SHEntry and
8995 * if this page has any frame children, it also will be handled
8996 * properly. see bug 83684
8998 * XXX Hopefully changing the loadType at this time will not hurt
8999 * anywhere. The other way to take care of sequentially repeating
9000 * frameset pages is to add new methods to nsIDocShellTreeItem.
9001 * Hopefully I don't have to do that.
9004 (mLoadType
== LOAD_NORMAL
||
9005 mLoadType
== LOAD_LINK
||
9006 mLoadType
== LOAD_STOP_CONTENT
) &&
9009 mLoadType
= LOAD_NORMAL_REPLACE
;
9012 // If this is a refresh to the currently loaded url, we don't
9013 // have to update session or global history.
9014 if (mLoadType
== LOAD_REFRESH
&& !inputStream
&& equalUri
) {
9015 SetHistoryEntry(&mLSHE
, mOSHE
);
9018 /* If the user pressed shift-reload, cache will create a new cache key
9019 * for the page. Save the new cacheKey in Session History.
9023 (aLoadType
== LOAD_RELOAD_BYPASS_CACHE
||
9024 aLoadType
== LOAD_RELOAD_BYPASS_PROXY
||
9025 aLoadType
== LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
)) {
9026 NS_ASSERTION(!updateHistory
,
9027 "We shouldn't be updating history for forced reloads!");
9029 nsCOMPtr
<nsICachingChannel
> cacheChannel(do_QueryInterface(aChannel
));
9030 nsCOMPtr
<nsISupports
> cacheKey
;
9031 // Get the Cache Key and store it in SH.
9033 cacheChannel
->GetCacheKey(getter_AddRefs(cacheKey
));
9034 // If we already have a loading history entry, store the new cache key
9035 // in it. Otherwise, since we're doing a reload and won't be updating
9036 // our history entry, store the cache key in our current history entry.
9038 mLSHE
->SetCacheKey(cacheKey
);
9040 mOSHE
->SetCacheKey(cacheKey
);
9043 if (updateHistory
&& shAvailable
) {
9044 // Update session history if necessary...
9045 if (!mLSHE
&& (mItemType
== typeContent
) && mURIResultedInDocument
) {
9046 /* This is a fresh page getting loaded for the first time
9047 *.Create a Entry for it and add it to SH, if this is the
9050 (void) AddToSessionHistory(aURI
, aChannel
, aOwner
,
9051 getter_AddRefs(mLSHE
));
9054 // Update Global history
9055 if (aAddToGlobalHistory
) {
9056 // Get the referrer uri from the channel
9057 AddToGlobalHistory(aURI
, PR_FALSE
, aChannel
);
9061 // If this was a history load, update the index in
9063 if (rootSH
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
9064 nsCOMPtr
<nsISHistoryInternal
> shInternal(do_QueryInterface(rootSH
));
9066 rootSH
->GetIndex(&mPreviousTransIndex
);
9067 shInternal
->UpdateIndex();
9068 rootSH
->GetIndex(&mLoadedTransIndex
);
9069 #ifdef DEBUG_PAGE_CACHE
9070 printf("Previous index: %d, Loaded index: %d\n\n",
9071 mPreviousTransIndex
, mLoadedTransIndex
);
9075 PRBool onLocationChangeNeeded
= SetCurrentURI(aURI
, aChannel
,
9076 aFireOnLocationChange
);
9077 // Make sure to store the referrer from the channel, if any
9078 SetupReferrerFromChannel(aChannel
);
9079 return onLocationChangeNeeded
;
9083 nsDocShell::OnLoadingSite(nsIChannel
* aChannel
, PRBool aFireOnLocationChange
,
9084 PRBool aAddToGlobalHistory
)
9086 nsCOMPtr
<nsIURI
> uri
;
9087 // If this a redirect, use the final url (uri)
9088 // else use the original url
9090 // Note that this should match what documents do (see nsDocument::Reset).
9091 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
9092 NS_ENSURE_TRUE(uri
, PR_FALSE
);
9094 return OnNewURI(uri
, aChannel
, nsnull
, mLoadType
, aFireOnLocationChange
,
9095 aAddToGlobalHistory
);
9100 nsDocShell::SetReferrerURI(nsIURI
* aURI
)
9102 mReferrerURI
= aURI
; // This assigment addrefs
9105 //*****************************************************************************
9106 // nsDocShell: Session History
9107 //*****************************************************************************
9110 nsDocShell::StringifyJSValVariant(nsIVariant
*aData
, nsAString
&aResult
)
9115 // First, try to extract a jsval from the variant |aData|. This works only
9116 // if the variant implements GetAsJSVal.
9118 rv
= aData
->GetAsJSVal(&jsData
);
9119 NS_ENSURE_SUCCESS(rv
, NS_ERROR_UNEXPECTED
);
9121 // Now get the JSContext associated with the current document.
9122 // First get the current document.
9123 nsCOMPtr
<nsIDocument
> document
= do_GetInterface(GetAsSupports(this));
9124 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
9126 // Get the JSContext from the document, like we do in
9127 // nsContentUtils::GetContextFromDocument().
9128 nsIScriptGlobalObject
*sgo
= document
->GetScopeObject();
9129 NS_ENSURE_TRUE(sgo
, NS_ERROR_FAILURE
);
9131 nsIScriptContext
*scx
= sgo
->GetContext();
9132 NS_ENSURE_TRUE(scx
, NS_ERROR_FAILURE
);
9134 JSContext
*cx
= (JSContext
*)scx
->GetNativeContext();
9136 // If our json call triggers a JS-to-C++ call, we want that call to use cx
9137 // as the context. So we push cx onto the context stack.
9138 nsCOMPtr
<nsIJSContextStack
> contextStack
=
9139 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
9140 NS_ENSURE_SUCCESS(rv
, rv
);
9142 contextStack
->Push(cx
);
9144 nsCOMPtr
<nsIJSON
> json
= do_GetService("@mozilla.org/dom/json;1");
9147 rv
= json
->EncodeFromJSVal(&jsData
, cx
, aResult
);
9150 rv
= NS_ERROR_FAILURE
;
9153 // Always pop the stack!
9154 contextStack
->Pop(&cx
);
9160 nsDocShell::AddState(nsIVariant
*aData
, const nsAString
& aTitle
,
9161 const nsAString
& aURL
, PRBool aReplace
)
9163 // Implements History.pushState and History.replaceState
9165 // Here's what we do, roughly in the order specified by HTML5:
9166 // 1. Serialize aData to JSON.
9167 // 2. If the third argument is present,
9168 // a. Resolve the url, relative to the first script's base URL
9169 // b. If (a) fails, raise a SECURITY_ERR
9170 // c. Compare the resulting absolute URL to the document's address. If
9171 // any part of the URLs difer other than the <path>, <query>, and
9172 // <fragment> components, raise a SECURITY_ERR and abort.
9174 // Remove from the session history all entries after the current entry,
9175 // as we would after a regular navigation.
9176 // 4. As apropriate, either add a state object entry to the session history
9177 // after the current entry with the following properties, or modify the
9178 // current session history entry to set
9179 // a. cloned data as the state object,
9180 // b. the given title as the title, and,
9181 // c. if the third argument was present, the absolute URL found in
9183 // 5. If aReplace is false (i.e. we're doing a pushState instead of a
9184 // replaceState), notify bfcache that we've navigated to a new page.
9185 // 6. If the third argument is present, set the document's current address
9186 // to the absolute URL found in step 2.
9188 // It's important that this function not run arbitrary scripts after step 1
9189 // and before completing step 5. For example, if a script called
9190 // history.back() before we completed step 5, bfcache might destroy an
9191 // active content viewer. Since EvictContentViewers at the end of step 5
9192 // might run script, we can't just put a script blocker around the critical
9197 nsCOMPtr
<nsIDocument
> document
= do_GetInterface(GetAsSupports(this));
9198 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
9200 mLoadType
= LOAD_PUSHSTATE
;
9202 // Step 1: Clone aData by getting its JSON representation
9204 rv
= StringifyJSValVariant(aData
, dataStr
);
9205 NS_ENSURE_SUCCESS(rv
, rv
);
9207 // Check that the state object isn't too long.
9208 // Default max length: 640k chars.
9209 PRInt32 maxStateObjSize
= 0xA0000;
9211 mPrefs
->GetIntPref("browser.history.maxStateObjectSize",
9214 if (maxStateObjSize
< 0) {
9215 maxStateObjSize
= 0;
9217 NS_ENSURE_TRUE(dataStr
.Length() <= (PRUint32
)maxStateObjSize
,
9218 NS_ERROR_ILLEGAL_VALUE
);
9220 // Step 2: Resolve aURL
9221 PRBool equalURIs
= PR_TRUE
;
9222 nsCOMPtr
<nsIURI
> oldURI
= mCurrentURI
;
9223 nsCOMPtr
<nsIURI
> newURI
;
9224 if (aURL
.Length() == 0) {
9225 newURI
= mCurrentURI
;
9228 // 2a: Resolve aURL relative to mURI
9230 nsIURI
* docBaseURI
= document
->GetDocBaseURI();
9232 return NS_ERROR_FAILURE
;
9235 docBaseURI
->GetSpec(spec
);
9237 nsCAutoString charset
;
9238 rv
= docBaseURI
->GetOriginCharset(charset
);
9239 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
9241 rv
= NS_NewURI(getter_AddRefs(newURI
), aURL
,
9242 charset
.get(), docBaseURI
);
9244 // 2b: If 2a fails, raise a SECURITY_ERR
9245 if (NS_FAILED(rv
)) {
9246 return NS_ERROR_DOM_SECURITY_ERR
;
9249 // 2c: Same-origin check.
9250 if (!URIIsLocalFile(newURI
)) {
9251 // In addition to checking that the security manager says that
9252 // the new URI has the same origin as our current URI, we also
9253 // check that the two URIs have the same userpass. (The
9254 // security manager says that |http://foo.com| and
9255 // |http://me@foo.com| have the same origin.) mCurrentURI
9256 // won't contain the password part of the userpass, so this
9257 // means that it's never valid to specify a password in a
9258 // pushState or replaceState URI.
9260 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
9261 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
9262 NS_ENSURE_TRUE(secMan
, NS_ERROR_FAILURE
);
9264 // It's very important that we check that newURI is of the same
9265 // origin as mCurrentURI, not docBaseURI, because a page can
9266 // set docBaseURI arbitrarily to any domain.
9267 nsCAutoString currentUserPass
, newUserPass
;
9268 NS_ENSURE_SUCCESS(mCurrentURI
->GetUserPass(currentUserPass
),
9270 NS_ENSURE_SUCCESS(newURI
->GetUserPass(newUserPass
),
9272 if (NS_FAILED(secMan
->CheckSameOriginURI(mCurrentURI
,
9273 newURI
, PR_TRUE
)) ||
9274 !currentUserPass
.Equals(newUserPass
)) {
9276 return NS_ERROR_DOM_SECURITY_ERR
;
9280 // It's a file:// URI
9281 nsCOMPtr
<nsIScriptObjectPrincipal
> docScriptObj
=
9282 do_QueryInterface(document
);
9284 if (!docScriptObj
) {
9285 return NS_ERROR_DOM_SECURITY_ERR
;
9288 nsCOMPtr
<nsIPrincipal
> principal
= docScriptObj
->GetPrincipal();
9291 NS_FAILED(principal
->CheckMayLoad(newURI
, PR_TRUE
))) {
9293 return NS_ERROR_DOM_SECURITY_ERR
;
9297 mCurrentURI
->Equals(newURI
, &equalURIs
);
9299 } // end of same-origin check
9301 nsCOMPtr
<nsISHistory
> sessionHistory
= mSessionHistory
;
9302 if (!sessionHistory
) {
9303 // Get the handle to SH from the root docshell
9304 GetRootSessionHistory(getter_AddRefs(sessionHistory
));
9306 NS_ENSURE_TRUE(sessionHistory
, NS_ERROR_FAILURE
);
9308 nsCOMPtr
<nsISHistoryInternal
> shInternal
=
9309 do_QueryInterface(sessionHistory
, &rv
);
9310 NS_ENSURE_SUCCESS(rv
, rv
);
9312 // Step 3: Create a new entry in the session history; this will erase
9313 // all SHEntries after the new entry and make this entry the current
9314 // one. This operation may modify mOSHE, which we need later, so we
9315 // keep a reference here.
9316 NS_ENSURE_TRUE(mOSHE
, NS_ERROR_FAILURE
);
9317 nsCOMPtr
<nsISHEntry
> oldOSHE
= mOSHE
;
9319 nsCOMPtr
<nsISHEntry
> newSHEntry
;
9321 rv
= AddToSessionHistory(newURI
, nsnull
, nsnull
,
9322 getter_AddRefs(newSHEntry
));
9323 NS_ENSURE_SUCCESS(rv
, rv
);
9325 NS_ENSURE_TRUE(newSHEntry
, NS_ERROR_FAILURE
);
9327 // Set the new SHEntry's document identifier, if we can.
9328 PRUint64 ourDocIdent
;
9329 NS_ENSURE_SUCCESS(oldOSHE
->GetDocIdentifier(&ourDocIdent
),
9331 NS_ENSURE_SUCCESS(newSHEntry
->SetDocIdentifier(ourDocIdent
),
9334 // AddToSessionHistory may not modify mOSHE. In case it doesn't,
9335 // we'll just set mOSHE here.
9340 newSHEntry
->SetURI(newURI
);
9343 // Step 4: Modify new/original session history entry
9344 newSHEntry
->SetStateData(dataStr
);
9346 // Step 5: If aReplace is false, indicating that we're doing a pushState
9347 // rather than a replaceState, notify bfcache that we've added a page to
9348 // the history so it can evict content viewers if appropriate.
9350 nsCOMPtr
<nsISHistory
> rootSH
;
9351 GetRootSessionHistory(getter_AddRefs(rootSH
));
9352 NS_ENSURE_TRUE(rootSH
, NS_ERROR_UNEXPECTED
);
9354 nsCOMPtr
<nsISHistoryInternal
> internalSH
=
9355 do_QueryInterface(rootSH
);
9356 NS_ENSURE_TRUE(internalSH
, NS_ERROR_UNEXPECTED
);
9358 PRInt32 curIndex
= -1;
9359 rv
= rootSH
->GetIndex(&curIndex
);
9360 if (NS_SUCCEEDED(rv
) && curIndex
> -1) {
9361 internalSH
->EvictContentViewers(curIndex
- 1, curIndex
);
9365 // Step 6: If the document's URI changed, update document's URI and update
9368 // We need to call FireOnLocationChange so that the browser's address bar
9369 // gets updated and the back button is enabled, but we only need to
9370 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
9371 // since SetCurrentURI will call FireOnLocationChange for us.
9373 SetCurrentURI(newURI
, nsnull
, PR_TRUE
);
9374 document
->SetDocumentURI(newURI
);
9376 AddToGlobalHistory(newURI
, PR_FALSE
, oldURI
);
9379 FireOnLocationChange(this, nsnull
, mCurrentURI
);
9382 // Try to set the title of the current history element
9384 mOSHE
->SetTitle(aTitle
);
9390 nsDocShell::ShouldAddToSessionHistory(nsIURI
* aURI
)
9392 // I believe none of the about: urls should go in the history. But then
9393 // that could just be me... If the intent is only deny about:blank then we
9394 // should just do a spec compare, rather than two gets of the scheme and
9395 // then the path. -Gagan
9399 rv
= aURI
->GetScheme(buf
);
9403 if (buf
.Equals("about")) {
9404 rv
= aURI
->GetPath(buf
);
9408 if (buf
.Equals("blank")) {
9416 nsDocShell::AddToSessionHistory(nsIURI
* aURI
, nsIChannel
* aChannel
,
9417 nsISupports
* aOwner
, nsISHEntry
** aNewEntry
)
9419 NS_PRECONDITION(aURI
, "uri is null");
9420 NS_PRECONDITION(!aChannel
|| !aOwner
, "Shouldn't have both set");
9422 #if defined(PR_LOGGING) && defined(DEBUG)
9423 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
9425 aURI
->GetSpec(spec
);
9427 nsCAutoString chanName
;
9429 aChannel
->GetName(chanName
);
9431 chanName
.AssignLiteral("<no channel>");
9433 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9434 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec
.get(),
9439 nsresult rv
= NS_OK
;
9440 nsCOMPtr
<nsISHEntry
> entry
;
9441 PRBool shouldPersist
;
9443 shouldPersist
= ShouldAddToSessionHistory(aURI
);
9445 // Get a handle to the root docshell
9446 nsCOMPtr
<nsIDocShellTreeItem
> root
;
9447 GetSameTypeRootTreeItem(getter_AddRefs(root
));
9449 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
9450 * the existing SH entry in the page and replace the url and
9453 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) &&
9454 root
!= static_cast<nsIDocShellTreeItem
*>(this)) {
9455 // This is a subframe
9457 nsCOMPtr
<nsISHContainer
> shContainer(do_QueryInterface(entry
));
9459 PRInt32 childCount
= 0;
9460 shContainer
->GetChildCount(&childCount
);
9461 // Remove all children of this entry
9462 for (PRInt32 i
= childCount
- 1; i
>= 0; i
--) {
9463 nsCOMPtr
<nsISHEntry
> child
;
9464 shContainer
->GetChildAt(i
, getter_AddRefs(child
));
9465 shContainer
->RemoveChild(child
);
9470 // Create a new entry if necessary.
9472 entry
= do_CreateInstance(NS_SHENTRY_CONTRACTID
);
9475 return NS_ERROR_OUT_OF_MEMORY
;
9479 // Get the post data & referrer
9480 nsCOMPtr
<nsIInputStream
> inputStream
;
9481 nsCOMPtr
<nsIURI
> referrerURI
;
9482 nsCOMPtr
<nsISupports
> cacheKey
;
9483 nsCOMPtr
<nsISupports
> cacheToken
;
9484 nsCOMPtr
<nsISupports
> owner
= aOwner
;
9485 PRBool expired
= PR_FALSE
;
9486 PRBool discardLayoutState
= PR_FALSE
;
9488 nsCOMPtr
<nsICachingChannel
>
9489 cacheChannel(do_QueryInterface(aChannel
));
9490 /* If there is a caching channel, get the Cache Key and store it
9494 cacheChannel
->GetCacheKey(getter_AddRefs(cacheKey
));
9495 cacheChannel
->GetCacheToken(getter_AddRefs(cacheToken
));
9497 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
9499 // Check if the httpChannel is hiding under a multipartChannel
9501 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
9504 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
9505 if (uploadChannel
) {
9506 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
9508 httpChannel
->GetReferrer(getter_AddRefs(referrerURI
));
9510 discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
9512 aChannel
->GetOwner(getter_AddRefs(owner
));
9515 //Title is set in nsDocShell::SetTitle()
9516 entry
->Create(aURI
, // uri
9517 EmptyString(), // Title
9518 inputStream
, // Post data stream
9519 nsnull
, // LayoutHistory state
9520 cacheKey
, // CacheKey
9521 mContentTypeHint
, // Content-type
9522 owner
); // Channel or provided owner
9523 entry
->SetReferrerURI(referrerURI
);
9524 /* If cache got a 'no-store', ask SH not to store
9525 * HistoryLayoutState. By default, SH will set this
9526 * flag to PR_TRUE and save HistoryLayoutState.
9528 if (discardLayoutState
) {
9529 entry
->SetSaveLayoutStateFlag(PR_FALSE
);
9532 // Check if the page has expired from cache
9533 nsCOMPtr
<nsICacheEntryInfo
> cacheEntryInfo(do_QueryInterface(cacheToken
));
9534 if (cacheEntryInfo
) {
9536 cacheEntryInfo
->GetExpirationTime(&expTime
);
9537 PRUint32 now
= PRTimeToSeconds(PR_Now());
9544 entry
->SetExpirationStatus(PR_TRUE
);
9547 if (root
== static_cast<nsIDocShellTreeItem
*>(this) && mSessionHistory
) {
9548 // This is the root docshell
9549 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
9550 // Replace current entry in session history.
9552 mSessionHistory
->GetIndex(&index
);
9553 nsCOMPtr
<nsISHistoryInternal
> shPrivate(do_QueryInterface(mSessionHistory
));
9554 // Replace the current entry with the new entry
9556 rv
= shPrivate
->ReplaceEntry(index
, entry
);
9559 // Add to session history
9560 nsCOMPtr
<nsISHistoryInternal
>
9561 shPrivate(do_QueryInterface(mSessionHistory
));
9562 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
9563 mSessionHistory
->GetIndex(&mPreviousTransIndex
);
9564 rv
= shPrivate
->AddEntry(entry
, shouldPersist
);
9565 mSessionHistory
->GetIndex(&mLoadedTransIndex
);
9566 #ifdef DEBUG_PAGE_CACHE
9567 printf("Previous index: %d, Loaded index: %d\n\n",
9568 mPreviousTransIndex
, mLoadedTransIndex
);
9573 // This is a subframe.
9574 if (!mOSHE
|| !LOAD_TYPE_HAS_FLAGS(mLoadType
,
9575 LOAD_FLAGS_REPLACE_HISTORY
))
9576 rv
= DoAddChildSHEntry(entry
, mChildOffset
);
9579 // Return the new SH entry...
9581 *aNewEntry
= nsnull
;
9582 if (NS_SUCCEEDED(rv
)) {
9584 NS_ADDREF(*aNewEntry
);
9593 nsDocShell::LoadHistoryEntry(nsISHEntry
* aEntry
, PRUint32 aLoadType
)
9595 if (!IsNavigationAllowed()) {
9599 nsCOMPtr
<nsIURI
> uri
;
9600 nsCOMPtr
<nsIInputStream
> postData
;
9601 nsCOMPtr
<nsIURI
> referrerURI
;
9602 nsCAutoString contentType
;
9603 nsCOMPtr
<nsISupports
> owner
;
9605 NS_ENSURE_TRUE(aEntry
, NS_ERROR_FAILURE
);
9607 NS_ENSURE_SUCCESS(aEntry
->GetURI(getter_AddRefs(uri
)), NS_ERROR_FAILURE
);
9608 NS_ENSURE_SUCCESS(aEntry
->GetReferrerURI(getter_AddRefs(referrerURI
)),
9610 NS_ENSURE_SUCCESS(aEntry
->GetPostData(getter_AddRefs(postData
)),
9612 NS_ENSURE_SUCCESS(aEntry
->GetContentType(contentType
), NS_ERROR_FAILURE
);
9613 NS_ENSURE_SUCCESS(aEntry
->GetOwner(getter_AddRefs(owner
)),
9616 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
9617 // that's the only thing holding a ref to aEntry that will cause aEntry to
9618 // die while we're loading it. So hold a strong ref to aEntry here, just
9620 nsCOMPtr
<nsISHEntry
> kungFuDeathGrip(aEntry
);
9622 nsresult rv
= uri
->SchemeIs("javascript", &isJS
);
9623 if (NS_FAILED(rv
) || isJS
) {
9624 // We're loading a URL that will execute script from inside asyncOpen.
9625 // Replace the current document with about:blank now to prevent
9626 // anything from the current document from leaking into any JavaScript
9628 nsCOMPtr
<nsIPrincipal
> prin
= do_QueryInterface(owner
);
9629 rv
= CreateAboutBlankContentViewer(prin
, nsnull
);
9631 if (NS_FAILED(rv
)) {
9632 // The creation of the intermittent about:blank content
9633 // viewer failed for some reason (potentially because the
9634 // user prevented it). Interrupt the history load.
9639 // Ensure that we have an owner. Otherwise javascript: URIs will
9640 // pick it up from the about:blank page we just loaded, and we
9641 // don't really want even that in this case.
9642 owner
= do_CreateInstance("@mozilla.org/nullprincipal;1");
9643 NS_ENSURE_TRUE(owner
, NS_ERROR_OUT_OF_MEMORY
);
9647 /* If there is a valid postdata *and* the user pressed
9648 * reload or shift-reload, take user's permission before we
9649 * repost the data to the server.
9651 if ((aLoadType
& LOAD_CMD_RELOAD
) && postData
) {
9653 rv
= ConfirmRepost(&repost
);
9654 if (NS_FAILED(rv
)) return rv
;
9656 // If the user pressed cancel in the dialog, return. We're done here.
9658 return NS_BINDING_ABORTED
;
9661 rv
= InternalLoad(uri
,
9664 INTERNAL_LOAD_FLAGS_NONE
, // Do not inherit owner from document (security-critical!)
9665 nsnull
, // No window target
9666 contentType
.get(), // Type hint
9667 postData
, // Post data stream
9668 nsnull
, // No headers stream
9669 aLoadType
, // Load type
9672 nsnull
, // No nsIDocShell
9673 nsnull
); // No nsIRequest
9677 NS_IMETHODIMP
nsDocShell::GetShouldSaveLayoutState(PRBool
* aShould
)
9679 *aShould
= PR_FALSE
;
9681 // Don't capture historystate and save it in history
9682 // if the page asked not to do so.
9683 mOSHE
->GetSaveLayoutStateFlag(aShould
);
9689 NS_IMETHODIMP
nsDocShell::PersistLayoutHistoryState()
9691 nsresult rv
= NS_OK
;
9694 nsCOMPtr
<nsIPresShell
> shell
;
9695 rv
= GetPresShell(getter_AddRefs(shell
));
9696 if (NS_SUCCEEDED(rv
) && shell
) {
9697 nsCOMPtr
<nsILayoutHistoryState
> layoutState
;
9698 rv
= shell
->CaptureHistoryState(getter_AddRefs(layoutState
),
9706 /* static */ nsresult
9707 nsDocShell::WalkHistoryEntries(nsISHEntry
*aRootEntry
,
9708 nsDocShell
*aRootShell
,
9709 WalkHistoryEntriesFunc aCallback
,
9712 NS_ENSURE_TRUE(aRootEntry
, NS_ERROR_FAILURE
);
9714 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(aRootEntry
));
9716 return NS_ERROR_FAILURE
;
9719 container
->GetChildCount(&childCount
);
9720 for (PRInt32 i
= 0; i
< childCount
; i
++) {
9721 nsCOMPtr
<nsISHEntry
> childEntry
;
9722 container
->GetChildAt(i
, getter_AddRefs(childEntry
));
9724 // childEntry can be null for valid reasons, for example if the
9725 // docshell at index i never loaded anything useful.
9729 nsDocShell
*childShell
= nsnull
;
9731 // Walk the children of aRootShell and see if one of them
9732 // has srcChild as a SHEntry.
9734 PRInt32 childCount
= aRootShell
->mChildList
.Count();
9735 for (PRInt32 j
= 0; j
< childCount
; ++j
) {
9737 static_cast<nsDocShell
*>(aRootShell
->ChildAt(j
));
9739 if (child
->HasHistoryEntry(childEntry
)) {
9745 nsresult rv
= aCallback(childEntry
, childShell
, i
, aData
);
9746 NS_ENSURE_SUCCESS(rv
, rv
);
9752 // callback data for WalkHistoryEntries
9753 struct NS_STACK_CLASS CloneAndReplaceData
9755 CloneAndReplaceData(PRUint32 aCloneID
, nsISHEntry
*aReplaceEntry
,
9756 nsISHEntry
*aDestTreeParent
)
9757 : cloneID(aCloneID
),
9758 replaceEntry(aReplaceEntry
),
9759 destTreeParent(aDestTreeParent
) { }
9762 nsISHEntry
*replaceEntry
;
9763 nsISHEntry
*destTreeParent
;
9764 nsCOMPtr
<nsISHEntry
> resultEntry
;
9767 /* static */ nsresult
9768 nsDocShell::CloneAndReplaceChild(nsISHEntry
*aEntry
, nsDocShell
*aShell
,
9769 PRInt32 aEntryIndex
, void *aData
)
9771 nsresult result
= NS_OK
;
9772 nsCOMPtr
<nsISHEntry
> dest
;
9774 CloneAndReplaceData
*data
= static_cast<CloneAndReplaceData
*>(aData
);
9775 PRUint32 cloneID
= data
->cloneID
;
9776 nsISHEntry
*replaceEntry
= data
->replaceEntry
;
9779 aEntry
->GetID(&srcID
);
9781 if (srcID
== cloneID
) {
9782 // Just replace the entry, and don't walk the children.
9783 dest
= replaceEntry
;
9784 dest
->SetIsSubFrame(PR_TRUE
);
9786 // Clone the SHEntry...
9787 result
= aEntry
->Clone(getter_AddRefs(dest
));
9788 if (NS_FAILED(result
))
9791 // This entry is for a subframe navigation
9792 dest
->SetIsSubFrame(PR_TRUE
);
9794 // Walk the children
9795 CloneAndReplaceData
childData(cloneID
, replaceEntry
, dest
);
9796 result
= WalkHistoryEntries(aEntry
, aShell
,
9797 CloneAndReplaceChild
, &childData
);
9798 if (NS_FAILED(result
))
9802 aShell
->SwapHistoryEntries(aEntry
, dest
);
9805 nsCOMPtr
<nsISHContainer
> container
=
9806 do_QueryInterface(data
->destTreeParent
);
9808 container
->AddChild(dest
, aEntryIndex
);
9810 data
->resultEntry
= dest
;
9814 /* static */ nsresult
9815 nsDocShell::CloneAndReplace(nsISHEntry
*aSrcEntry
,
9816 nsDocShell
*aSrcShell
,
9818 nsISHEntry
*aReplaceEntry
,
9819 nsISHEntry
**aResultEntry
)
9821 NS_ENSURE_ARG_POINTER(aResultEntry
);
9822 NS_ENSURE_TRUE(aReplaceEntry
, NS_ERROR_FAILURE
);
9824 CloneAndReplaceData
data(aCloneID
, aReplaceEntry
, nsnull
);
9825 nsresult rv
= CloneAndReplaceChild(aSrcEntry
, aSrcShell
, 0, &data
);
9827 data
.resultEntry
.swap(*aResultEntry
);
9832 nsDocShell::SwapHistoryEntries(nsISHEntry
*aOldEntry
, nsISHEntry
*aNewEntry
)
9834 if (aOldEntry
== mOSHE
)
9837 if (aOldEntry
== mLSHE
)
9842 struct SwapEntriesData
9844 nsDocShell
*ignoreShell
; // constant; the shell to ignore
9845 nsISHEntry
*destTreeRoot
; // constant; the root of the dest tree
9846 nsISHEntry
*destTreeParent
; // constant; the node under destTreeRoot
9847 // whose children will correspond to aEntry
9852 nsDocShell::SetChildHistoryEntry(nsISHEntry
*aEntry
, nsDocShell
*aShell
,
9853 PRInt32 aEntryIndex
, void *aData
)
9855 SwapEntriesData
*data
= static_cast<SwapEntriesData
*>(aData
);
9856 nsDocShell
*ignoreShell
= data
->ignoreShell
;
9858 if (!aShell
|| aShell
== ignoreShell
)
9861 nsISHEntry
*destTreeRoot
= data
->destTreeRoot
;
9863 nsCOMPtr
<nsISHEntry
> destEntry
;
9864 nsCOMPtr
<nsISHContainer
> container
=
9865 do_QueryInterface(data
->destTreeParent
);
9868 // aEntry is a clone of some child of destTreeParent, but since the
9869 // trees aren't necessarily in sync, we'll have to locate it.
9870 // Note that we could set aShell's entry to null if we don't find a
9871 // corresponding entry under destTreeParent.
9873 PRUint32 targetID
, id
;
9874 aEntry
->GetID(&targetID
);
9876 // First look at the given index, since this is the common case.
9877 nsCOMPtr
<nsISHEntry
> entry
;
9878 container
->GetChildAt(aEntryIndex
, getter_AddRefs(entry
));
9879 if (entry
&& NS_SUCCEEDED(entry
->GetID(&id
)) && id
== targetID
) {
9880 destEntry
.swap(entry
);
9883 container
->GetChildCount(&childCount
);
9884 for (PRInt32 i
= 0; i
< childCount
; ++i
) {
9885 container
->GetChildAt(i
, getter_AddRefs(entry
));
9890 if (id
== targetID
) {
9891 destEntry
.swap(entry
);
9897 destEntry
= destTreeRoot
;
9900 aShell
->SwapHistoryEntries(aEntry
, destEntry
);
9902 // Now handle the children of aEntry.
9903 SwapEntriesData childData
= { ignoreShell
, destTreeRoot
, destEntry
};
9904 return WalkHistoryEntries(aEntry
, aShell
,
9905 SetChildHistoryEntry
, &childData
);
9910 GetRootSHEntry(nsISHEntry
*aEntry
)
9912 nsCOMPtr
<nsISHEntry
> rootEntry
= aEntry
;
9913 nsISHEntry
*result
= nsnull
;
9916 result
->GetParent(getter_AddRefs(rootEntry
));
9924 nsDocShell::SetHistoryEntry(nsCOMPtr
<nsISHEntry
> *aPtr
, nsISHEntry
*aEntry
)
9926 // We need to sync up the docshell and session history trees for
9927 // subframe navigation. If the load was in a subframe, we forward up to
9928 // the root docshell, which will then recursively sync up all docshells
9929 // to their corresponding entries in the new session history tree.
9930 // If we don't do this, then we can cache a content viewer on the wrong
9931 // cloned entry, and subsequently restore it at the wrong time.
9933 nsISHEntry
*newRootEntry
= GetRootSHEntry(aEntry
);
9935 // newRootEntry is now the new root entry.
9936 // Find the old root entry as well.
9938 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
9939 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
9940 nsCOMPtr
<nsISHEntry
> oldRootEntry
= GetRootSHEntry(*aPtr
);
9942 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
9943 GetSameTypeParent(getter_AddRefs(parentAsItem
));
9944 nsCOMPtr
<nsIDocShell
> rootShell
= do_QueryInterface(parentAsItem
);
9945 if (rootShell
) { // if we're the root just set it, nothing to swap
9946 SwapEntriesData data
= { this, newRootEntry
};
9947 nsIDocShell
*rootIDocShell
=
9948 static_cast<nsIDocShell
*>(rootShell
);
9949 nsDocShell
*rootDocShell
= static_cast<nsDocShell
*>
9955 SetChildHistoryEntry(oldRootEntry
, rootDocShell
,
9957 NS_ASSERTION(NS_SUCCEEDED(rv
), "SetChildHistoryEntry failed");
9967 nsDocShell::GetRootSessionHistory(nsISHistory
** aReturn
)
9971 nsCOMPtr
<nsIDocShellTreeItem
> root
;
9972 //Get the root docshell
9973 rv
= GetSameTypeRootTreeItem(getter_AddRefs(root
));
9974 // QI to nsIWebNavigation
9975 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav(do_QueryInterface(root
));
9977 // Get the handle to SH from the root docshell
9978 rv
= rootAsWebnav
->GetSessionHistory(aReturn
);
9984 nsDocShell::GetHttpChannel(nsIChannel
* aChannel
, nsIHttpChannel
** aReturn
)
9986 NS_ENSURE_ARG_POINTER(aReturn
);
9988 return NS_ERROR_FAILURE
;
9990 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(aChannel
));
9991 if (multiPartChannel
) {
9992 nsCOMPtr
<nsIChannel
> baseChannel
;
9993 multiPartChannel
->GetBaseChannel(getter_AddRefs(baseChannel
));
9994 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(baseChannel
));
9995 *aReturn
= httpChannel
;
9996 NS_IF_ADDREF(*aReturn
);
10002 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel
* aChannel
)
10004 // By default layout State will be saved.
10008 // figure out if SH should be saving layout state
10009 nsCOMPtr
<nsISupports
> securityInfo
;
10010 PRBool noStore
= PR_FALSE
, noCache
= PR_FALSE
;
10011 aChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
10012 aChannel
->IsNoStoreResponse(&noStore
);
10013 aChannel
->IsNoCacheResponse(&noCache
);
10015 return (noStore
|| (noCache
&& securityInfo
));
10018 //*****************************************************************************
10019 // nsDocShell: nsIEditorDocShell
10020 //*****************************************************************************
10022 NS_IMETHODIMP
nsDocShell::GetEditor(nsIEditor
* *aEditor
)
10024 NS_ENSURE_ARG_POINTER(aEditor
);
10026 if (!mEditorData
) {
10031 return mEditorData
->GetEditor(aEditor
);
10034 NS_IMETHODIMP
nsDocShell::SetEditor(nsIEditor
* aEditor
)
10036 nsresult rv
= EnsureEditorData();
10037 if (NS_FAILED(rv
)) return rv
;
10039 return mEditorData
->SetEditor(aEditor
);
10043 NS_IMETHODIMP
nsDocShell::GetEditable(PRBool
*aEditable
)
10045 NS_ENSURE_ARG_POINTER(aEditable
);
10046 *aEditable
= mEditorData
&& mEditorData
->GetEditable();
10051 NS_IMETHODIMP
nsDocShell::GetHasEditingSession(PRBool
*aHasEditingSession
)
10053 NS_ENSURE_ARG_POINTER(aHasEditingSession
);
10057 nsCOMPtr
<nsIEditingSession
> editingSession
;
10058 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
10059 *aHasEditingSession
= (editingSession
.get() != nsnull
);
10063 *aHasEditingSession
= PR_FALSE
;
10069 NS_IMETHODIMP
nsDocShell::MakeEditable(PRBool inWaitForUriLoad
)
10071 nsresult rv
= EnsureEditorData();
10072 if (NS_FAILED(rv
)) return rv
;
10074 return mEditorData
->MakeEditable(inWaitForUriLoad
);
10078 nsDocShell::AddToGlobalHistory(nsIURI
* aURI
, PRBool aRedirect
,
10079 nsIChannel
* aChannel
)
10081 // If this is a POST request, we do not want to include this in global
10082 // history, so return early.
10083 nsCOMPtr
<nsIHttpChannel
> hchan(do_QueryInterface(aChannel
));
10085 nsCAutoString type
;
10086 nsresult rv
= hchan
->GetRequestMethod(type
);
10087 if (NS_SUCCEEDED(rv
) && type
.EqualsLiteral("POST"))
10091 nsCOMPtr
<nsIURI
> referrer
;
10093 NS_GetReferrerFromChannel(aChannel
, getter_AddRefs(referrer
));
10095 return AddToGlobalHistory(aURI
, aRedirect
, referrer
);
10099 nsDocShell::AddToGlobalHistory(nsIURI
* aURI
, PRBool aRedirect
,
10100 nsIURI
* aReferrer
)
10102 if (mItemType
!= typeContent
|| !mGlobalHistory
)
10106 nsresult rv
= mGlobalHistory
->IsVisited(aURI
, &visited
);
10110 rv
= mGlobalHistory
->AddURI(aURI
, aRedirect
, !IsFrame(), aReferrer
);
10115 nsCOMPtr
<nsIObserverService
> obsService
=
10116 mozilla::services::GetObserverService();
10118 obsService
->NotifyObservers(aURI
, NS_LINK_VISITED_EVENT_TOPIC
, nsnull
);
10126 //*****************************************************************************
10127 // nsDocShell: Helper Routines
10128 //*****************************************************************************
10131 nsDocShell::SetLoadType(PRUint32 aLoadType
)
10133 mLoadType
= aLoadType
;
10138 nsDocShell::GetLoadType(PRUint32
* aLoadType
)
10140 *aLoadType
= mLoadType
;
10145 nsDocShell::ConfirmRepost(PRBool
* aRepost
)
10147 nsCOMPtr
<nsIPrompt
> prompter
;
10148 CallGetInterface(this, static_cast<nsIPrompt
**>(getter_AddRefs(prompter
)));
10150 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
10151 mozilla::services::GetStringBundleService();
10152 if (!stringBundleService
)
10153 return NS_ERROR_FAILURE
;
10155 nsCOMPtr
<nsIStringBundle
> appBundle
;
10156 nsresult rv
= stringBundleService
->CreateBundle(kAppstringsBundleURL
,
10157 getter_AddRefs(appBundle
));
10158 NS_ENSURE_SUCCESS(rv
, rv
);
10160 nsCOMPtr
<nsIStringBundle
> brandBundle
;
10161 rv
= stringBundleService
->CreateBundle(kBrandBundleURL
, getter_AddRefs(brandBundle
));
10162 NS_ENSURE_SUCCESS(rv
, rv
);
10164 NS_ASSERTION(prompter
&& brandBundle
&& appBundle
,
10165 "Unable to set up repost prompter.");
10167 nsXPIDLString brandName
;
10168 rv
= brandBundle
->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
10169 getter_Copies(brandName
));
10171 nsXPIDLString msgString
, button0Title
;
10172 if (NS_FAILED(rv
)) { // No brand, use the generic version.
10173 rv
= appBundle
->GetStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
10174 getter_Copies(msgString
));
10177 // Brand available - if the app has an override file with formatting, the app name will
10178 // be included. Without an override, the prompt will look like the generic version.
10179 const PRUnichar
*formatStrings
[] = { brandName
.get() };
10180 rv
= appBundle
->FormatStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
10181 formatStrings
, NS_ARRAY_LENGTH(formatStrings
),
10182 getter_Copies(msgString
));
10184 if (NS_FAILED(rv
)) return rv
;
10186 rv
= appBundle
->GetStringFromName(NS_LITERAL_STRING("resendButton.label").get(),
10187 getter_Copies(button0Title
));
10188 if (NS_FAILED(rv
)) return rv
;
10190 PRInt32 buttonPressed
;
10193 ConfirmEx(nsnull
, msgString
.get(),
10194 (nsIPrompt::BUTTON_POS_0
* nsIPrompt::BUTTON_TITLE_IS_STRING
) +
10195 (nsIPrompt::BUTTON_POS_1
* nsIPrompt::BUTTON_TITLE_CANCEL
),
10196 button0Title
.get(), nsnull
, nsnull
, nsnull
, &checkState
, &buttonPressed
);
10197 if (NS_FAILED(rv
)) return rv
;
10199 *aRepost
= (buttonPressed
== 0);
10204 nsDocShell::GetPromptAndStringBundle(nsIPrompt
** aPrompt
,
10205 nsIStringBundle
** aStringBundle
)
10207 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt
), (void **) aPrompt
),
10210 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
10211 mozilla::services::GetStringBundleService();
10212 NS_ENSURE_TRUE(stringBundleService
, NS_ERROR_FAILURE
);
10214 NS_ENSURE_SUCCESS(stringBundleService
->
10215 CreateBundle(kAppstringsBundleURL
,
10223 nsDocShell::GetChildOffset(nsIDOMNode
* aChild
, nsIDOMNode
* aParent
,
10226 NS_ENSURE_ARG_POINTER(aChild
|| aParent
);
10228 nsCOMPtr
<nsIDOMNodeList
> childNodes
;
10229 NS_ENSURE_SUCCESS(aParent
->GetChildNodes(getter_AddRefs(childNodes
)),
10231 NS_ENSURE_TRUE(childNodes
, NS_ERROR_FAILURE
);
10235 for (; PR_TRUE
; i
++) {
10236 nsCOMPtr
<nsIDOMNode
> childNode
;
10237 NS_ENSURE_SUCCESS(childNodes
->Item(i
, getter_AddRefs(childNode
)),
10239 NS_ENSURE_TRUE(childNode
, NS_ERROR_FAILURE
);
10241 if (childNode
.get() == aChild
) {
10247 return NS_ERROR_FAILURE
;
10250 nsIScrollableFrame
*
10251 nsDocShell::GetRootScrollFrame()
10253 nsCOMPtr
<nsIPresShell
> shell
;
10254 NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(shell
)), nsnull
);
10255 NS_ENSURE_TRUE(shell
, nsnull
);
10257 return shell
->GetRootScrollFrameAsScrollableExternal();
10261 class nsDebugAutoBoolTrueSetter
10264 nsDebugAutoBoolTrueSetter(PRPackedBool
*aBool
)
10270 ~nsDebugAutoBoolTrueSetter()
10275 PRPackedBool
*mBool
;
10280 nsDocShell::EnsureScriptEnvironment()
10285 if (mIsBeingDestroyed
) {
10286 return NS_ERROR_NOT_AVAILABLE
;
10292 NS_ASSERTION(!mInEnsureScriptEnv
,
10293 "Infinite loop! Calling EnsureScriptEnvironment() from "
10294 "within EnsureScriptEnvironment()!");
10296 // Yeah, this isn't re-entrant safe, but that's ok since if we
10297 // re-enter this method, we'll infinitely loop...
10298 nsDebugAutoBoolTrueSetter
boolSetter(&mInEnsureScriptEnv
);
10301 nsCOMPtr
<nsIDOMScriptObjectFactory
> factory
=
10302 do_GetService(kDOMScriptObjectFactoryCID
);
10303 NS_ENSURE_TRUE(factory
, NS_ERROR_FAILURE
);
10305 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
10306 NS_ENSURE_TRUE(browserChrome
, NS_ERROR_NOT_AVAILABLE
);
10308 PRUint32 chromeFlags
;
10309 browserChrome
->GetChromeFlags(&chromeFlags
);
10311 PRBool isModalContentWindow
=
10312 (chromeFlags
& nsIWebBrowserChrome::CHROME_MODAL
) &&
10313 !(chromeFlags
& nsIWebBrowserChrome::CHROME_OPENAS_CHROME
);
10315 // If our window is modal and we're not opened as chrome, make
10316 // this window a modal content window.
10317 factory
->NewScriptGlobalObject(mItemType
== typeChrome
,
10318 isModalContentWindow
,
10319 getter_AddRefs(mScriptGlobal
));
10320 NS_ENSURE_TRUE(mScriptGlobal
, NS_ERROR_FAILURE
);
10322 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
10323 win
->SetDocShell(static_cast<nsIDocShell
*>(this));
10325 // Ensure the script object is set to run javascript - other languages
10326 // setup on demand.
10327 // XXXmarkh - should this be setup to run the default language for this doc?
10329 rv
= mScriptGlobal
->EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT
);
10330 NS_ENSURE_SUCCESS(rv
, rv
);
10337 nsDocShell::EnsureEditorData()
10339 PRBool openDocHasDetachedEditor
= mOSHE
&& mOSHE
->HasDetachedEditor();
10340 if (!mEditorData
&& !mIsBeingDestroyed
&& !openDocHasDetachedEditor
) {
10341 // We shouldn't recreate the editor data if it already exists, or
10342 // we're shutting down, or we already have a detached editor data
10343 // stored in the session history. We should only have one editordata
10345 mEditorData
= new nsDocShellEditorData(this);
10348 return mEditorData
? NS_OK
: NS_ERROR_NOT_AVAILABLE
;
10352 nsDocShell::EnsureTransferableHookData()
10354 if (!mTransferableHookData
) {
10355 mTransferableHookData
= new nsTransferableHookData();
10356 if (!mTransferableHookData
) return NS_ERROR_OUT_OF_MEMORY
;
10363 NS_IMETHODIMP
nsDocShell::EnsureFind()
10368 mFind
= do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv
);
10369 if (NS_FAILED(rv
)) return rv
;
10372 // we promise that the nsIWebBrowserFind that we return has been set
10373 // up to point to the focused, or content window, so we have to
10374 // set that up each time.
10376 nsIScriptGlobalObject
* scriptGO
= GetScriptGlobalObject();
10377 NS_ENSURE_TRUE(scriptGO
, NS_ERROR_UNEXPECTED
);
10379 // default to our window
10380 nsCOMPtr
<nsIDOMWindow
> windowToSearch(do_QueryInterface(mScriptGlobal
));
10382 nsCOMPtr
<nsIDocShellTreeItem
> root
;
10383 GetRootTreeItem(getter_AddRefs(root
));
10385 // if the active window is the same window that this docshell is in,
10386 // use the currently focused frame
10387 nsCOMPtr
<nsIDOMWindow
> rootWindow
= do_GetInterface(root
);
10388 nsCOMPtr
<nsIFocusManager
> fm
= do_GetService(FOCUSMANAGER_CONTRACTID
);
10390 nsCOMPtr
<nsIDOMWindow
> activeWindow
;
10391 fm
->GetActiveWindow(getter_AddRefs(activeWindow
));
10392 if (activeWindow
== rootWindow
)
10393 fm
->GetFocusedWindow(getter_AddRefs(windowToSearch
));
10396 nsCOMPtr
<nsIWebBrowserFindInFrames
> findInFrames
= do_QueryInterface(mFind
);
10397 if (!findInFrames
) return NS_ERROR_NO_INTERFACE
;
10399 rv
= findInFrames
->SetRootSearchFrame(rootWindow
);
10400 if (NS_FAILED(rv
)) return rv
;
10401 rv
= findInFrames
->SetCurrentSearchFrame(windowToSearch
);
10402 if (NS_FAILED(rv
)) return rv
;
10408 nsDocShell::IsFrame()
10410 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
10411 do_QueryInterface(GetAsSupports(mParent
));
10413 PRInt32 parentType
= ~mItemType
; // Not us
10414 parent
->GetItemType(&parentType
);
10415 if (parentType
== mItemType
) // This is a frame
10422 /* boolean IsBeingDestroyed (); */
10424 nsDocShell::IsBeingDestroyed(PRBool
*aDoomed
)
10426 NS_ENSURE_ARG(aDoomed
);
10427 *aDoomed
= mIsBeingDestroyed
;
10433 nsDocShell::GetIsExecutingOnLoadHandler(PRBool
*aResult
)
10435 NS_ENSURE_ARG(aResult
);
10436 *aResult
= mIsExecutingOnLoadHandler
;
10441 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState
**aLayoutHistoryState
)
10444 mOSHE
->GetLayoutHistoryState(aLayoutHistoryState
);
10449 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState
*aLayoutHistoryState
)
10452 mOSHE
->SetLayoutHistoryState(aLayoutHistoryState
);
10456 //*****************************************************************************
10457 //*** nsRefreshTimer: Object Management
10458 //*****************************************************************************
10460 nsRefreshTimer::nsRefreshTimer()
10461 : mDelay(0), mRepeat(PR_FALSE
), mMetaRefresh(PR_FALSE
)
10465 nsRefreshTimer::~nsRefreshTimer()
10469 //*****************************************************************************
10470 // nsRefreshTimer::nsISupports
10471 //*****************************************************************************
10473 NS_IMPL_THREADSAFE_ADDREF(nsRefreshTimer
)
10474 NS_IMPL_THREADSAFE_RELEASE(nsRefreshTimer
)
10476 NS_INTERFACE_MAP_BEGIN(nsRefreshTimer
)
10477 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsITimerCallback
)
10478 NS_INTERFACE_MAP_ENTRY(nsITimerCallback
)
10479 NS_INTERFACE_MAP_END_THREADSAFE
10481 ///*****************************************************************************
10482 // nsRefreshTimer::nsITimerCallback
10483 //******************************************************************************
10485 nsRefreshTimer::Notify(nsITimer
* aTimer
)
10487 NS_ASSERTION(mDocShell
, "DocShell is somehow null");
10489 if (mDocShell
&& aTimer
) {
10490 // Get the delay count to determine load type
10491 PRUint32 delay
= 0;
10492 aTimer
->GetDelay(&delay
);
10493 mDocShell
->ForceRefreshURIFromTimer(mURI
, delay
, mMetaRefresh
, aTimer
);
10498 //*****************************************************************************
10499 // nsDocShell::InterfaceRequestorProxy
10500 //*****************************************************************************
10501 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor
* p
)
10504 mWeakPtr
= do_GetWeakReference(p
);
10508 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
10513 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDocShell::InterfaceRequestorProxy
, nsIInterfaceRequestor
)
10516 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID
& aIID
, void **aSink
)
10518 NS_ENSURE_ARG_POINTER(aSink
);
10519 nsCOMPtr
<nsIInterfaceRequestor
> ifReq
= do_QueryReferent(mWeakPtr
);
10521 return ifReq
->GetInterface(aIID
, aSink
);
10524 return NS_NOINTERFACE
;
10528 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer
* aContentViewer
)
10530 if (!aContentViewer
)
10531 return NS_ERROR_FAILURE
;
10533 nsCOMPtr
<nsIURI
> baseURI
;
10534 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
10537 rv
= sURIFixup
->CreateExposableURI(mCurrentURI
,
10538 getter_AddRefs(baseURI
));
10540 // Get the current document and set the base uri
10542 nsIDocument
* document
= aContentViewer
->GetDocument();
10544 rv
= document
->SetBaseURI(baseURI
);
10550 //*****************************************************************************
10551 // nsDocShell::nsIAuthPromptProvider
10552 //*****************************************************************************
10555 nsDocShell::GetAuthPrompt(PRUint32 aPromptReason
, const nsIID
& iid
,
10558 // a priority prompt request will override a false mAllowAuth setting
10559 PRBool priorityPrompt
= (aPromptReason
== PROMPT_PROXY
);
10561 if (!mAllowAuth
&& !priorityPrompt
)
10562 return NS_ERROR_NOT_AVAILABLE
;
10564 // we're either allowing auth, or it's a proxy request
10566 nsCOMPtr
<nsIPromptFactory
> wwatch
=
10567 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
10568 NS_ENSURE_SUCCESS(rv
, rv
);
10570 rv
= EnsureScriptEnvironment();
10571 NS_ENSURE_SUCCESS(rv
, rv
);
10573 nsCOMPtr
<nsIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
10575 // Get the an auth prompter for our window so that the parenting
10576 // of the dialogs works as it should when using tabs.
10578 return wwatch
->GetPrompt(window
, iid
,
10579 reinterpret_cast<void**>(aResult
));
10582 //*****************************************************************************
10583 // nsDocShell::nsIObserver
10584 //*****************************************************************************
10587 nsDocShell::Observe(nsISupports
*aSubject
, const char *aTopic
,
10588 const PRUnichar
*aData
)
10590 nsresult rv
= NS_OK
;
10591 if (mObserveErrorPages
&&
10592 !nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
) &&
10593 !nsCRT::strcmp(aData
,
10594 NS_LITERAL_STRING("browser.xul.error_pages.enabled").get())) {
10596 nsCOMPtr
<nsIPrefBranch
> prefs(do_QueryInterface(aSubject
, &rv
));
10597 NS_ENSURE_SUCCESS(rv
, rv
);
10600 rv
= prefs
->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool
);
10601 if (NS_SUCCEEDED(rv
))
10602 mUseErrorPages
= tmpbool
;
10605 rv
= NS_ERROR_UNEXPECTED
;
10610 //*****************************************************************************
10611 // nsDocShell::nsILoadContext
10612 //*****************************************************************************
10614 nsDocShell::GetAssociatedWindow(nsIDOMWindow
** aWindow
)
10616 return CallGetInterface(this, aWindow
);
10620 nsDocShell::GetTopWindow(nsIDOMWindow
** aWindow
)
10623 nsCOMPtr
<nsIDOMWindow
> win
= do_GetInterface(GetAsSupports(this), &rv
);
10624 NS_ENSURE_SUCCESS(rv
, rv
);
10625 return win
->GetTop(aWindow
);
10629 nsDocShell::IsAppOfType(PRUint32 aAppType
, PRBool
*aIsOfType
)
10631 nsCOMPtr
<nsIDocShell
> shell
= this;
10634 shell
->GetAppType(&type
);
10635 if (type
== aAppType
) {
10636 *aIsOfType
= PR_TRUE
;
10639 nsCOMPtr
<nsIDocShellTreeItem
> item
= do_QueryInterface(shell
);
10640 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
10641 item
->GetParent(getter_AddRefs(parent
));
10642 shell
= do_QueryInterface(parent
);
10645 *aIsOfType
= PR_FALSE
;
10650 nsDocShell::GetIsContent(PRBool
*aIsContent
)
10652 *aIsContent
= (mItemType
== typeContent
);
10658 nsDocShell::URIInheritsSecurityContext(nsIURI
* aURI
, PRBool
* aResult
)
10660 // Note: about:blank URIs do NOT inherit the security context from the
10661 // current document, which is what this function tests for...
10662 return NS_URIChainHasFlags(aURI
,
10663 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
,
10669 nsDocShell::URIIsLocalFile(nsIURI
*aURI
)
10672 nsCOMPtr
<nsINetUtil
> util
= do_GetNetUtil();
10674 return util
&& NS_SUCCEEDED(util
->ProtocolHasFlags(aURI
,
10675 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
10682 nsDocShell::IsAboutBlank(nsIURI
* aURI
)
10684 NS_PRECONDITION(aURI
, "Must have URI");
10686 // GetSpec can be expensive for some URIs, so check the scheme first.
10687 PRBool isAbout
= PR_FALSE
;
10688 if (NS_FAILED(aURI
->SchemeIs("about", &isAbout
)) || !isAbout
) {
10693 aURI
->GetSpec(str
);
10694 return str
.EqualsLiteral("about:blank");
10698 nsDocShell::IsOKToLoadURI(nsIURI
* aURI
)
10700 NS_PRECONDITION(aURI
, "Must have a URI!");
10702 if (!mFiredUnloadEvent
) {
10706 if (!mLoadingURI
) {
10710 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
10711 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
10714 NS_SUCCEEDED(secMan
->CheckSameOriginURI(aURI
, mLoadingURI
, PR_FALSE
));
10718 // Routines for selection and clipboard
10721 nsDocShell::GetControllerForCommand(const char * inCommand
,
10722 nsIController
** outController
)
10724 NS_ENSURE_ARG_POINTER(outController
);
10725 *outController
= nsnull
;
10727 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
10729 nsCOMPtr
<nsPIWindowRoot
> root
= window
->GetTopWindowRoot();
10731 return root
->GetControllerForCommand(inCommand
, outController
);
10735 return NS_ERROR_FAILURE
;
10739 nsDocShell::IsCommandEnabled(const char * inCommand
, PRBool
* outEnabled
)
10741 NS_ENSURE_ARG_POINTER(outEnabled
);
10742 *outEnabled
= PR_FALSE
;
10744 nsresult rv
= NS_ERROR_FAILURE
;
10746 nsCOMPtr
<nsIController
> controller
;
10747 rv
= GetControllerForCommand (inCommand
, getter_AddRefs(controller
));
10749 rv
= controller
->IsCommandEnabled(inCommand
, outEnabled
);
10755 nsDocShell::DoCommand(const char * inCommand
)
10757 nsresult rv
= NS_ERROR_FAILURE
;
10759 nsCOMPtr
<nsIController
> controller
;
10760 rv
= GetControllerForCommand(inCommand
, getter_AddRefs(controller
));
10762 rv
= controller
->DoCommand(inCommand
);
10768 nsDocShell::EnsureCommandHandler()
10770 if (!mCommandManager
)
10772 nsCOMPtr
<nsPICommandUpdater
> commandUpdater
=
10773 do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
10774 if (!commandUpdater
) return NS_ERROR_OUT_OF_MEMORY
;
10776 nsCOMPtr
<nsIDOMWindow
> domWindow
=
10777 do_GetInterface(static_cast<nsIInterfaceRequestor
*>(this));
10779 nsresult rv
= commandUpdater
->Init(domWindow
);
10780 if (NS_SUCCEEDED(rv
))
10781 mCommandManager
= do_QueryInterface(commandUpdater
);
10784 return mCommandManager
? NS_OK
: NS_ERROR_FAILURE
;
10788 nsDocShell::CanCutSelection(PRBool
* aResult
)
10790 return IsCommandEnabled("cmd_cut", aResult
);
10794 nsDocShell::CanCopySelection(PRBool
* aResult
)
10796 return IsCommandEnabled("cmd_copy", aResult
);
10800 nsDocShell::CanCopyLinkLocation(PRBool
* aResult
)
10802 return IsCommandEnabled("cmd_copyLink", aResult
);
10806 nsDocShell::CanCopyImageLocation(PRBool
* aResult
)
10808 return IsCommandEnabled("cmd_copyImageLocation",
10813 nsDocShell::CanCopyImageContents(PRBool
* aResult
)
10815 return IsCommandEnabled("cmd_copyImageContents",
10820 nsDocShell::CanPaste(PRBool
* aResult
)
10822 return IsCommandEnabled("cmd_paste", aResult
);
10826 nsDocShell::CutSelection(void)
10828 return DoCommand ( "cmd_cut" );
10832 nsDocShell::CopySelection(void)
10834 return DoCommand ( "cmd_copy" );
10838 nsDocShell::CopyLinkLocation(void)
10840 return DoCommand ( "cmd_copyLink" );
10844 nsDocShell::CopyImageLocation(void)
10846 return DoCommand ( "cmd_copyImageLocation" );
10850 nsDocShell::CopyImageContents(void)
10852 return DoCommand ( "cmd_copyImageContents" );
10856 nsDocShell::Paste(void)
10858 return DoCommand ( "cmd_paste" );
10862 nsDocShell::SelectAll(void)
10864 return DoCommand ( "cmd_selectAll" );
10870 // Collapses the current selection, insertion point ends up at beginning
10871 // of previous selection.
10874 nsDocShell::SelectNone(void)
10876 return DoCommand ( "cmd_selectNone" );
10879 //----------------------------------------------------------------------
10883 class OnLinkClickEvent
: public nsRunnable
{
10885 OnLinkClickEvent(nsDocShell
* aHandler
, nsIContent
* aContent
,
10887 const PRUnichar
* aTargetSpec
,
10888 nsIInputStream
* aPostDataStream
= 0,
10889 nsIInputStream
* aHeadersDataStream
= 0);
10892 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(mHandler
->mScriptGlobal
));
10893 nsAutoPopupStatePusher
popupStatePusher(window
, mPopupState
);
10895 mHandler
->OnLinkClickSync(mContent
, mURI
,
10896 mTargetSpec
.get(), mPostDataStream
,
10897 mHeadersDataStream
,
10903 nsRefPtr
<nsDocShell
> mHandler
;
10904 nsCOMPtr
<nsIURI
> mURI
;
10905 nsString mTargetSpec
;
10906 nsCOMPtr
<nsIInputStream
> mPostDataStream
;
10907 nsCOMPtr
<nsIInputStream
> mHeadersDataStream
;
10908 nsCOMPtr
<nsIContent
> mContent
;
10909 PopupControlState mPopupState
;
10912 OnLinkClickEvent::OnLinkClickEvent(nsDocShell
* aHandler
,
10913 nsIContent
*aContent
,
10915 const PRUnichar
* aTargetSpec
,
10916 nsIInputStream
* aPostDataStream
,
10917 nsIInputStream
* aHeadersDataStream
)
10918 : mHandler(aHandler
)
10920 , mTargetSpec(aTargetSpec
)
10921 , mPostDataStream(aPostDataStream
)
10922 , mHeadersDataStream(aHeadersDataStream
)
10923 , mContent(aContent
)
10925 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(mHandler
->mScriptGlobal
));
10927 mPopupState
= window
->GetPopupControlState();
10930 //----------------------------------------
10933 nsDocShell::OnLinkClick(nsIContent
* aContent
,
10935 const PRUnichar
* aTargetSpec
,
10936 nsIInputStream
* aPostDataStream
,
10937 nsIInputStream
* aHeadersDataStream
)
10939 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
10941 if (!IsOKToLoadURI(aURI
)) {
10945 if (aContent
->IsEditable()) {
10949 nsCOMPtr
<nsIRunnable
> ev
=
10950 new OnLinkClickEvent(this, aContent
, aURI
, aTargetSpec
,
10951 aPostDataStream
, aHeadersDataStream
);
10952 return NS_DispatchToCurrentThread(ev
);
10956 nsDocShell::OnLinkClickSync(nsIContent
*aContent
,
10958 const PRUnichar
* aTargetSpec
,
10959 nsIInputStream
* aPostDataStream
,
10960 nsIInputStream
* aHeadersDataStream
,
10961 nsIDocShell
** aDocShell
,
10962 nsIRequest
** aRequest
)
10964 // Initialize the DocShell / Request
10966 *aDocShell
= nsnull
;
10969 *aRequest
= nsnull
;
10972 if (!IsOKToLoadURI(aURI
)) {
10976 if (aContent
->IsEditable()) {
10981 // defer to an external protocol handler if necessary...
10982 nsCOMPtr
<nsIExternalProtocolService
> extProtService
=
10983 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
);
10984 if (extProtService
) {
10985 nsCAutoString scheme
;
10986 aURI
->GetScheme(scheme
);
10987 if (!scheme
.IsEmpty()) {
10988 // if the URL scheme does not correspond to an exposed protocol, then we
10989 // need to hand this link click over to the external protocol handler.
10991 nsresult rv
= extProtService
->IsExposedProtocol(scheme
.get(), &isExposed
);
10992 if (NS_SUCCEEDED(rv
) && !isExposed
) {
10993 return extProtService
->LoadURI(aURI
, this);
10999 // Get the owner document of the link that was clicked, this will be
11000 // the document that the link is in, or the last document that the
11001 // link was in. From that document, we'll get the URI to use as the
11002 // referer, since the current URI in this docshell may be a
11003 // new document that we're in the process of loading.
11004 nsCOMPtr
<nsIDocument
> refererDoc
= aContent
->GetOwnerDoc();
11005 NS_ENSURE_TRUE(refererDoc
, NS_ERROR_UNEXPECTED
);
11007 nsCOMPtr
<nsIURI
> referer
= refererDoc
->GetDocumentURI();
11009 // referer could be null here in some odd cases, but that's ok,
11010 // we'll just load the link w/o sending a referer in those cases.
11012 nsAutoString
target(aTargetSpec
);
11014 // If this is an anchor element, grab its type property to use as a hint
11015 nsAutoString typeHint
;
11016 nsCOMPtr
<nsIDOMHTMLAnchorElement
> anchor(do_QueryInterface(aContent
));
11018 anchor
->GetType(typeHint
);
11021 nsresult rv
= InternalLoad(aURI
, // New URI
11022 referer
, // Referer URI
11023 aContent
->NodePrincipal(), // Owner is our node's
11025 INTERNAL_LOAD_FLAGS_NONE
,
11026 target
.get(), // Window target
11027 NS_LossyConvertUTF16toASCII(typeHint
).get(),
11028 aPostDataStream
, // Post data stream
11029 aHeadersDataStream
, // Headers stream
11030 LOAD_LINK
, // Load type
11031 nsnull
, // No SHEntry
11032 PR_TRUE
, // first party site
11033 aDocShell
, // DocShell out-param
11034 aRequest
); // Request out-param
11035 if (NS_SUCCEEDED(rv
)) {
11036 DispatchPings(aContent
, referer
);
11042 nsDocShell::OnOverLink(nsIContent
* aContent
,
11044 const PRUnichar
* aTargetSpec
)
11046 if (aContent
->IsEditable()) {
11050 nsCOMPtr
<nsIWebBrowserChrome2
> browserChrome2
= do_GetInterface(mTreeOwner
);
11051 nsresult rv
= NS_ERROR_FAILURE
;
11053 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
;
11054 if (!browserChrome2
) {
11055 browserChrome
= do_GetInterface(mTreeOwner
);
11056 if (!browserChrome
)
11060 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
11061 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
11065 // use url origin charset to unescape the URL
11066 nsCAutoString charset
;
11067 rv
= aURI
->GetOriginCharset(charset
);
11068 NS_ENSURE_SUCCESS(rv
, rv
);
11070 nsCAutoString spec
;
11071 rv
= aURI
->GetSpec(spec
);
11072 NS_ENSURE_SUCCESS(rv
, rv
);
11075 rv
= textToSubURI
->UnEscapeURIForUI(charset
, spec
, uStr
);
11076 NS_ENSURE_SUCCESS(rv
, rv
);
11078 if (browserChrome2
) {
11079 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(aContent
);
11080 rv
= browserChrome2
->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK
,
11083 rv
= browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_LINK
, uStr
.get());
11089 nsDocShell::OnLeaveLink()
11091 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
11092 nsresult rv
= NS_ERROR_FAILURE
;
11094 if (browserChrome
) {
11095 rv
= browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_LINK
,
11096 EmptyString().get());
11101 //----------------------------------------------------------------------
11102 // Web Shell Services API
11104 //This functions is only called when a new charset is detected in loading a document.
11105 //Its name should be changed to "CharsetReloadDocument"
11107 nsDocShell::ReloadDocument(const char* aCharset
,
11111 // XXX hack. keep the aCharset and aSource wait to pick it up
11112 nsCOMPtr
<nsIContentViewer
> cv
;
11113 NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv
)), NS_ERROR_FAILURE
);
11116 nsCOMPtr
<nsIMarkupDocumentViewer
> muDV
= do_QueryInterface(cv
);
11120 muDV
->GetHintCharacterSetSource(&hint
);
11121 if (aSource
> hint
)
11123 nsCString
charset(aCharset
);
11124 muDV
->SetHintCharacterSet(charset
);
11125 muDV
->SetHintCharacterSetSource(aSource
);
11126 if(eCharsetReloadRequested
!= mCharsetReloadState
)
11128 mCharsetReloadState
= eCharsetReloadRequested
;
11129 return Reload(LOAD_FLAGS_CHARSET_CHANGE
);
11134 //return failure if this request is not accepted due to mCharsetReloadState
11135 return NS_ERROR_DOCSHELL_REQUEST_REJECTED
;
11140 nsDocShell::StopDocumentLoad(void)
11142 if(eCharsetReloadRequested
!= mCharsetReloadState
)
11144 Stop(nsIWebNavigation::STOP_ALL
);
11147 //return failer if this request is not accepted due to mCharsetReloadState
11148 return NS_ERROR_DOCSHELL_REQUEST_REJECTED
;
11152 nsDocShell::GetPrintPreview(nsIWebBrowserPrint
** aPrintPreview
)
11154 *aPrintPreview
= nsnull
;
11155 #if NS_PRINT_PREVIEW
11156 nsCOMPtr
<nsIDocumentViewerPrint
> print
= do_QueryInterface(mContentViewer
);
11157 if (!print
|| !print
->IsInitializedForPrintPreview()) {
11158 Stop(nsIWebNavigation::STOP_ALL
);
11159 nsCOMPtr
<nsIPrincipal
> principal
=
11160 do_CreateInstance("@mozilla.org/nullprincipal;1");
11161 NS_ENSURE_STATE(principal
);
11162 nsresult rv
= CreateAboutBlankContentViewer(principal
, nsnull
);
11163 NS_ENSURE_SUCCESS(rv
, rv
);
11164 print
= do_QueryInterface(mContentViewer
);
11165 NS_ENSURE_STATE(print
);
11166 print
->InitializeForPrintPreview();
11168 nsCOMPtr
<nsIWebBrowserPrint
> result
= do_QueryInterface(print
);
11169 result
.forget(aPrintPreview
);
11172 return NS_ERROR_NOT_IMPLEMENTED
;
11178 unsigned long nsDocShell::gNumberOfDocShells
= 0;