1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=4 sw=4 tw=80 et: */
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 "nsIContentUtils.h"
53 #include "mozilla/dom/Element.h"
54 #include "nsIDocument.h"
55 #include "nsIDOMDocument.h"
56 #include "nsIDOM3Document.h"
57 #include "nsIDOMNSDocument.h"
58 #include "nsIDOMElement.h"
59 #include "nsIDOMStorageObsolete.h"
60 #include "nsIDOMStorage.h"
61 #include "nsPIDOMStorage.h"
62 #include "nsIDocumentViewer.h"
63 #include "nsIDocumentLoaderFactory.h"
64 #include "nsCURILoader.h"
65 #include "nsURILoader.h"
66 #include "nsDocShellCID.h"
67 #include "nsLayoutCID.h"
69 #include "nsIDOMScriptObjectFactory.h"
70 #include "nsNetUtil.h"
73 #include "nsIMarkupDocumentViewer.h"
74 #include "nsXPIDLString.h"
75 #include "nsReadableUtils.h"
76 #include "nsIDOMEventTarget.h"
77 #include "nsIDOMChromeWindow.h"
78 #include "nsIDOMWindowInternal.h"
79 #include "nsIWebBrowserChrome.h"
81 #include "nsGfxCIID.h"
82 #include "nsIObserverService.h"
83 #include "nsIPrompt.h"
84 #include "nsIAuthPrompt.h"
85 #include "nsIAuthPrompt2.h"
86 #include "nsTextFormatter.h"
87 #include "nsIChannelEventSink.h"
88 #include "nsIAsyncVerifyRedirectCallback.h"
89 #include "nsIUploadChannel.h"
90 #include "nsISecurityEventSink.h"
91 #include "mozilla/FunctionTimer.h"
92 #include "nsIScriptSecurityManager.h"
93 #include "nsIJSContextStack.h"
94 #include "nsIScriptObjectPrincipal.h"
95 #include "nsDocumentCharsetInfoCID.h"
96 #include "nsIScrollableFrame.h"
97 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
98 #include "nsICategoryManager.h"
99 #include "nsXPCOMCID.h"
100 #include "nsISeekableStream.h"
101 #include "nsAutoPtr.h"
102 #include "nsIPrefService.h"
103 #include "nsIPrefBranch.h"
104 #include "nsIPrefBranch2.h"
105 #include "nsIWritablePropertyBag2.h"
106 #include "nsIAppShell.h"
107 #include "nsWidgetsCID.h"
108 #include "nsDOMJSUtils.h"
109 #include "nsIInterfaceRequestorUtils.h"
111 #include "nsIViewManager.h"
112 #include "nsIScriptChannel.h"
113 #include "nsIOfflineCacheUpdate.h"
114 #include "nsCPrefetchService.h"
116 #include "IHistory.h"
117 #include "mozilla/Services.h"
119 // we want to explore making the document own the load group
120 // so we can associate the document URI with the load group.
121 // until this point, we have an evil hack:
122 #include "nsIHttpChannelInternal.h"
126 #include "nsDocShell.h"
127 #include "nsDocShellLoadInfo.h"
128 #include "nsCDefaultURIFixup.h"
129 #include "nsDocShellEnumerator.h"
130 #include "nsSHistory.h"
131 #include "nsDocShellEditorData.h"
134 #include "nsDOMError.h"
135 #include "nsEscape.h"
138 #include "nsIUploadChannel.h"
139 #include "nsIProgressEventSink.h"
140 #include "nsIWebProgress.h"
141 #include "nsILayoutHistoryState.h"
142 #include "nsITimer.h"
143 #include "nsISHistoryInternal.h"
144 #include "nsIPrincipal.h"
145 #include "nsIFileURL.h"
146 #include "nsIHistoryEntry.h"
147 #include "nsISHistoryListener.h"
148 #include "nsIWindowWatcher.h"
149 #include "nsIPromptFactory.h"
150 #include "nsIObserver.h"
151 #include "nsINestedURI.h"
152 #include "nsITransportSecurityInfo.h"
153 #include "nsINSSErrorsService.h"
154 #include "nsIApplicationCache.h"
155 #include "nsIApplicationCacheChannel.h"
156 #include "nsIApplicationCacheContainer.h"
157 #include "nsIPermissionManager.h"
158 #include "nsStreamUtils.h"
159 #include "nsIController.h"
160 #include "nsPICommandUpdater.h"
161 #include "nsIDOMHTMLAnchorElement.h"
162 #include "nsIWebBrowserChrome3.h"
163 #include "nsITabChild.h"
164 #include "nsIStrictTransportSecurityService.h"
167 #include "nsIEditingSession.h"
169 #include "nsPIDOMWindow.h"
170 #include "nsPIWindowRoot.h"
171 #include "nsIDOMDocument.h"
172 #include "nsICachingChannel.h"
173 #include "nsICacheVisitor.h"
174 #include "nsICacheEntryDescriptor.h"
175 #include "nsIMultiPartChannel.h"
176 #include "nsIWyciwygChannel.h"
178 // The following are for bug #13871: Prevent frameset spoofing
179 #include "nsIHTMLDocument.h"
181 // For reporting errors with the console service.
182 // These can go away if error reporting is propagated up past nsDocShell.
183 #include "nsIConsoleService.h"
184 #include "nsIScriptError.h"
186 // used to dispatch urls to default protocol handlers
187 #include "nsCExternalHandlerService.h"
188 #include "nsIExternalProtocolService.h"
190 #include "nsFocusManager.h"
192 #include "nsITextToSubURI.h"
194 #include "nsIJARChannel.h"
199 #include "nsISelectionDisplay.h"
201 #include "nsIGlobalHistory2.h"
202 #include "nsIGlobalHistory3.h"
204 #ifdef DEBUG_DOCSHELL_FOCUS
205 #include "nsIEventStateManager.h"
208 #include "nsIFrame.h"
211 #include "nsIWebBrowserChromeFocus.h"
214 #include "nsIDocumentViewerPrint.h"
215 #include "nsIWebBrowserPrint.h"
218 #include "nsPluginError.h"
220 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID
,
221 NS_DOM_SCRIPT_OBJECT_FACTORY_CID
);
222 static NS_DEFINE_CID(kAppShellCID
, NS_APPSHELL_CID
);
224 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
225 //#define DEBUG_DOCSHELL_FOCUS
226 #define DEBUG_PAGE_CACHE
229 #include "nsContentErrors.h"
230 #include "nsIChannelPolicy.h"
231 #include "nsIContentSecurityPolicy.h"
234 #include "nsXULAppAPI.h"
237 using namespace mozilla
;
239 // Number of documents currently loading
240 static PRInt32 gNumberOfDocumentsLoading
= 0;
242 // Global count of existing docshells.
243 static PRInt32 gDocShellCount
= 0;
245 // Global reference to the URI fixup service.
246 nsIURIFixup
*nsDocShell::sURIFixup
= 0;
248 // True means we validate window targets to prevent frameset
249 // spoofing. Initialize this to a non-bolean value so we know to check
250 // the pref on the creation of the first docshell.
251 static PRBool gValidateOrigin
= (PRBool
)0xffffffff;
253 // Hint for native dispatch of events on how long to delay after
254 // all documents have loaded in milliseconds before favoring normal
255 // native event dispatch priorites over performance
256 #define NS_EVENT_STARVATION_DELAY_HINT 2000
258 // This is needed for displaying an error message
259 // when navigation is attempted on a document when printing
260 // The value arbitrary as long as it doesn't conflict with
261 // any of the other values in the errors in DisplayLoadError
262 #define NS_ERROR_DOCUMENT_IS_PRINTMODE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL,2001)
266 static PRLogModuleInfo
* gDocShellLog
;
268 static PRLogModuleInfo
* gDocShellLeakLog
;
271 const char kBrandBundleURL
[] = "chrome://branding/locale/brand.properties";
272 const char kAppstringsBundleURL
[] = "chrome://global/locale/appstrings.properties";
275 FavorPerformanceHint(PRBool perfOverStarvation
, PRUint32 starvationDelay
)
277 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(kAppShellCID
);
279 appShell
->FavorPerformanceHint(perfOverStarvation
, starvationDelay
);
282 //*****************************************************************************
284 //*****************************************************************************
286 #define PREF_PINGS_ENABLED "browser.send_pings"
287 #define PREF_PINGS_MAX_PER_LINK "browser.send_pings.max_per_link"
288 #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
290 // Check prefs to see if pings are enabled and if so what restrictions might
294 // This parameter returns the number of pings that are allowed per link click
296 // @param requireSameHost
297 // This parameter returns PR_TRUE if pings are restricted to the same host as
298 // the document in which the click occurs. If the same host restriction is
299 // imposed, then we still allow for pings to cross over to different
300 // protocols and ports for flexibility and because it is not possible to send
304 // PR_TRUE if pings are enabled and PR_FALSE otherwise.
307 PingsEnabled(PRInt32
*maxPerLink
, PRBool
*requireSameHost
)
309 PRBool allow
= PR_FALSE
;
312 *requireSameHost
= PR_TRUE
;
314 nsCOMPtr
<nsIPrefBranch
> prefs
=
315 do_GetService(NS_PREFSERVICE_CONTRACTID
);
318 if (NS_SUCCEEDED(prefs
->GetBoolPref(PREF_PINGS_ENABLED
, &val
)))
321 prefs
->GetIntPref(PREF_PINGS_MAX_PER_LINK
, maxPerLink
);
322 prefs
->GetBoolPref(PREF_PINGS_REQUIRE_SAME_HOST
, requireSameHost
);
330 CheckPingURI(nsIURI
* uri
, nsIContent
* content
)
335 // Check with nsIScriptSecurityManager
336 nsCOMPtr
<nsIScriptSecurityManager
> ssmgr
=
337 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
338 NS_ENSURE_TRUE(ssmgr
, PR_FALSE
);
341 ssmgr
->CheckLoadURIWithPrincipal(content
->NodePrincipal(), uri
,
342 nsIScriptSecurityManager::STANDARD
);
347 // Ignore non-HTTP(S)
349 if ((NS_FAILED(uri
->SchemeIs("http", &match
)) || !match
) &&
350 (NS_FAILED(uri
->SchemeIs("https", &match
)) || !match
)) {
354 // Check with contentpolicy
355 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
356 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING
,
358 content
->NodePrincipal(),
360 EmptyCString(), // mime hint
363 return NS_SUCCEEDED(rv
) && NS_CP_ACCEPTED(shouldLoad
);
366 typedef void (* ForEachPingCallback
)(void *closure
, nsIContent
*content
,
367 nsIURI
*uri
, nsIIOService
*ios
);
370 ForEachPing(nsIContent
*content
, ForEachPingCallback callback
, void *closure
)
372 // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
373 // since we'd still need to parse the resulting string. Instead, we
374 // just parse the raw attribute. It might be nice if the content node
375 // implemented an interface that exposed an enumeration of nsIURIs.
377 // Make sure we are dealing with either an <A> or <AREA> element in the HTML
378 // or XHTML namespace.
379 if (!content
->IsHTML())
381 nsIAtom
*nameAtom
= content
->Tag();
382 if (!nameAtom
->Equals(NS_LITERAL_STRING("a")) &&
383 !nameAtom
->Equals(NS_LITERAL_STRING("area")))
386 nsCOMPtr
<nsIAtom
> pingAtom
= do_GetAtom("ping");
391 content
->GetAttr(kNameSpaceID_None
, pingAtom
, value
);
395 nsCOMPtr
<nsIIOService
> ios
= do_GetIOService();
399 nsIDocument
*doc
= content
->GetOwnerDoc();
403 // value contains relative URIs split on spaces (U+0020)
404 const PRUnichar
*start
= value
.BeginReading();
405 const PRUnichar
*end
= value
.EndReading();
406 const PRUnichar
*iter
= start
;
408 if (iter
< end
&& *iter
!= ' ') {
410 } else { // iter is pointing at either end or a space
411 while (*start
== ' ' && start
< iter
)
414 nsCOMPtr
<nsIURI
> uri
, baseURI
= content
->GetBaseURI();
415 ios
->NewURI(NS_ConvertUTF16toUTF8(Substring(start
, iter
)),
416 doc
->GetDocumentCharacterSet().get(),
417 baseURI
, getter_AddRefs(uri
));
418 if (CheckPingURI(uri
, content
)) {
419 callback(closure
, content
, uri
, ios
);
422 start
= iter
= iter
+ 1;
429 //----------------------------------------------------------------------
431 // We wait this many milliseconds before killing the ping channel...
432 #define PING_TIMEOUT 10000
435 OnPingTimeout(nsITimer
*timer
, void *closure
)
437 nsILoadGroup
*loadGroup
= static_cast<nsILoadGroup
*>(closure
);
438 loadGroup
->Cancel(NS_ERROR_ABORT
);
439 loadGroup
->Release();
442 // Check to see if two URIs have the same host or not
444 IsSameHost(nsIURI
*uri1
, nsIURI
*uri2
)
446 nsCAutoString host1
, host2
;
447 uri1
->GetAsciiHost(host1
);
448 uri2
->GetAsciiHost(host2
);
449 return host1
.Equals(host2
);
452 class nsPingListener
: public nsIStreamListener
453 , public nsIInterfaceRequestor
454 , public nsIChannelEventSink
458 NS_DECL_NSIREQUESTOBSERVER
459 NS_DECL_NSISTREAMLISTENER
460 NS_DECL_NSIINTERFACEREQUESTOR
461 NS_DECL_NSICHANNELEVENTSINK
463 nsPingListener(PRBool requireSameHost
, nsIContent
* content
)
464 : mRequireSameHost(requireSameHost
),
469 PRBool mRequireSameHost
;
470 nsCOMPtr
<nsIContent
> mContent
;
473 NS_IMPL_ISUPPORTS4(nsPingListener
, nsIStreamListener
, nsIRequestObserver
,
474 nsIInterfaceRequestor
, nsIChannelEventSink
)
477 nsPingListener::OnStartRequest(nsIRequest
*request
, nsISupports
*context
)
483 nsPingListener::OnDataAvailable(nsIRequest
*request
, nsISupports
*context
,
484 nsIInputStream
*stream
, PRUint32 offset
,
488 return stream
->ReadSegments(NS_DiscardSegment
, nsnull
, count
, &result
);
492 nsPingListener::OnStopRequest(nsIRequest
*request
, nsISupports
*context
,
499 nsPingListener::GetInterface(const nsIID
&iid
, void **result
)
501 if (iid
.Equals(NS_GET_IID(nsIChannelEventSink
))) {
503 *result
= (nsIChannelEventSink
*) this;
507 return NS_ERROR_NO_INTERFACE
;
511 nsPingListener::AsyncOnChannelRedirect(nsIChannel
*oldChan
, nsIChannel
*newChan
,
513 nsIAsyncVerifyRedirectCallback
*callback
)
515 nsCOMPtr
<nsIURI
> newURI
;
516 newChan
->GetURI(getter_AddRefs(newURI
));
518 if (!CheckPingURI(newURI
, mContent
))
519 return NS_ERROR_ABORT
;
521 if (!mRequireSameHost
) {
522 callback
->OnRedirectVerifyCallback(NS_OK
);
526 // XXXbz should this be using something more like the nsContentUtils
527 // same-origin checker?
528 nsCOMPtr
<nsIURI
> oldURI
;
529 oldChan
->GetURI(getter_AddRefs(oldURI
));
530 NS_ENSURE_STATE(oldURI
&& newURI
);
532 if (!IsSameHost(oldURI
, newURI
))
533 return NS_ERROR_ABORT
;
535 callback
->OnRedirectVerifyCallback(NS_OK
);
539 struct SendPingInfo
{
542 PRBool requireSameHost
;
547 SendPing(void *closure
, nsIContent
*content
, nsIURI
*uri
, nsIIOService
*ios
)
549 SendPingInfo
*info
= static_cast<SendPingInfo
*>(closure
);
550 if (info
->numPings
>= info
->maxPings
)
553 if (info
->requireSameHost
) {
554 // Make sure the referrer and the given uri share the same origin. We
555 // only require the same hostname. The scheme and port may differ.
556 if (!IsSameHost(uri
, info
->referrer
))
560 nsIDocument
*doc
= content
->GetOwnerDoc();
564 nsCOMPtr
<nsIChannel
> chan
;
565 ios
->NewChannelFromURI(uri
, getter_AddRefs(chan
));
569 // Don't bother caching the result of this URI load.
570 chan
->SetLoadFlags(nsIRequest::INHIBIT_CACHING
);
572 nsCOMPtr
<nsIHttpChannel
> httpChan
= do_QueryInterface(chan
);
576 // This is needed in order for 3rd-party cookie blocking to work.
577 nsCOMPtr
<nsIHttpChannelInternal
> httpInternal
= do_QueryInterface(httpChan
);
579 httpInternal
->SetDocumentURI(doc
->GetDocumentURI());
582 httpChan
->SetReferrer(info
->referrer
);
584 httpChan
->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
586 // Remove extraneous request headers (to reduce request size)
587 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
588 EmptyCString(), PR_FALSE
);
589 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
590 EmptyCString(), PR_FALSE
);
591 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept-charset"),
592 EmptyCString(), PR_FALSE
);
593 httpChan
->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
594 EmptyCString(), PR_FALSE
);
596 nsCOMPtr
<nsIUploadChannel
> uploadChan
= do_QueryInterface(httpChan
);
600 // To avoid sending an unnecessary Content-Type header, we encode the
601 // closing portion of the headers in the POST body.
602 NS_NAMED_LITERAL_CSTRING(uploadData
, "Content-Length: 0\r\n\r\n");
604 nsCOMPtr
<nsIInputStream
> uploadStream
;
605 NS_NewPostDataStream(getter_AddRefs(uploadStream
), PR_FALSE
,
610 uploadChan
->SetUploadStream(uploadStream
, EmptyCString(), -1);
612 // The channel needs to have a loadgroup associated with it, so that we can
613 // cancel the channel and any redirected channels it may create.
614 nsCOMPtr
<nsILoadGroup
> loadGroup
=
615 do_CreateInstance(NS_LOADGROUP_CONTRACTID
);
618 chan
->SetLoadGroup(loadGroup
);
620 // Construct a listener that merely discards any response. If successful at
621 // opening the channel, then it is not necessary to hold a reference to the
622 // channel. The networking subsystem will take care of that for us.
623 nsCOMPtr
<nsIStreamListener
> listener
=
624 new nsPingListener(info
->requireSameHost
, content
);
628 // Observe redirects as well:
629 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
= do_QueryInterface(listener
);
630 NS_ASSERTION(callbacks
, "oops");
631 loadGroup
->SetNotificationCallbacks(callbacks
);
633 chan
->AsyncOpen(listener
, nsnull
);
635 // Even if AsyncOpen failed, we still count this as a successful ping. It's
636 // possible that AsyncOpen may have failed after triggering some background
637 // process that may have written something to the network.
640 // Prevent ping requests from stalling and never being garbage collected...
641 nsCOMPtr
<nsITimer
> timer
=
642 do_CreateInstance(NS_TIMER_CONTRACTID
);
644 nsresult rv
= timer
->InitWithFuncCallback(OnPingTimeout
, loadGroup
,
646 nsITimer::TYPE_ONE_SHOT
);
647 if (NS_SUCCEEDED(rv
)) {
648 // When the timer expires, the callback function will release this
649 // reference to the loadgroup.
650 static_cast<nsILoadGroup
*>(loadGroup
.get())->AddRef();
655 // If we failed to setup the timer, then we should just cancel the channel
656 // because we won't be able to ensure that it goes away in a timely manner.
658 chan
->Cancel(NS_ERROR_ABORT
);
661 // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
663 DispatchPings(nsIContent
*content
, nsIURI
*referrer
)
667 if (!PingsEnabled(&info
.maxPings
, &info
.requireSameHost
))
669 if (info
.maxPings
== 0)
673 info
.referrer
= referrer
;
675 ForEachPing(content
, SendPing
, &info
);
678 static nsISHEntry
* GetRootSHEntry(nsISHEntry
*entry
);
680 //*****************************************************************************
681 //*** nsDocShell: Object Management
682 //*****************************************************************************
684 static PRUint64 gDocshellIDCounter
= 0;
686 // Note: operator new zeros our memory
687 nsDocShell::nsDocShell():
689 mDefaultScrollbarPref(Scrollbar_Auto
, Scrollbar_Auto
),
691 mChromeEventHandler(nsnull
),
692 mCharsetReloadState(eCharsetReloadInit
),
694 mBusyFlags(BUSY_FLAGS_NONE
),
695 mAppType(nsIDocShell::APP_TYPE_UNKNOWN
),
698 mItemType(typeContent
),
699 mPreviousTransIndex(-1),
700 mLoadedTransIndex(-1),
701 mAllowSubframes(PR_TRUE
),
702 mAllowPlugins(PR_TRUE
),
703 mAllowJavascript(PR_TRUE
),
704 mAllowMetaRedirects(PR_TRUE
),
705 mAllowImages(PR_TRUE
),
706 mAllowDNSPrefetch(PR_TRUE
),
707 mCreatingDocument(PR_FALSE
),
708 mUseErrorPages(PR_FALSE
),
709 mObserveErrorPages(PR_TRUE
),
711 mAllowKeywordFixup(PR_FALSE
),
712 mIsOffScreenBrowser(PR_FALSE
),
715 mUseGlobalHistory(PR_FALSE
),
716 mFiredUnloadEvent(PR_FALSE
),
717 mEODForCurrentDocument(PR_FALSE
),
718 mURIResultedInDocument(PR_FALSE
),
719 mIsBeingDestroyed(PR_FALSE
),
720 mIsExecutingOnLoadHandler(PR_FALSE
),
721 mIsPrintingOrPP(PR_FALSE
),
722 mSavingOldViewer(PR_FALSE
)
724 , mInEnsureScriptEnv(PR_FALSE
)
727 mHistoryID
= ++gDocshellIDCounter
;
728 if (gDocShellCount
++ == 0) {
729 NS_ASSERTION(sURIFixup
== nsnull
,
730 "Huh, sURIFixup not null in first nsDocShell ctor!");
732 CallGetService(NS_URIFIXUP_CONTRACTID
, &sURIFixup
);
738 gDocShellLog
= PR_NewLogModule("nsDocShell");
740 if (nsnull
== gDocShellLeakLog
)
741 gDocShellLeakLog
= PR_NewLogModule("nsDocShellLeak");
742 if (gDocShellLeakLog
)
743 PR_LOG(gDocShellLeakLog
, PR_LOG_DEBUG
, ("DOCSHELL %p created\n", this));
747 // We're counting the number of |nsDocShells| to help find leaks
748 ++gNumberOfDocShells
;
751 printf("++DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells
);
755 nsDocShell::~nsDocShell()
759 nsCOMPtr
<nsISHistoryInternal
>
760 shPrivate(do_QueryInterface(mSessionHistory
));
762 shPrivate
->SetRootDocShell(nsnull
);
765 if (--gDocShellCount
== 0) {
766 NS_IF_RELEASE(sURIFixup
);
770 if (gDocShellLeakLog
)
771 PR_LOG(gDocShellLeakLog
, PR_LOG_DEBUG
, ("DOCSHELL %p destroyed\n", this));
775 // We're counting the number of |nsDocShells| to help find leaks
776 --gNumberOfDocShells
;
779 printf("--DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells
);
786 nsresult rv
= nsDocLoader::Init();
787 NS_ENSURE_SUCCESS(rv
, rv
);
789 NS_ASSERTION(mLoadGroup
, "Something went wrong!");
791 mContentListener
= new nsDSURIContentListener(this);
792 NS_ENSURE_TRUE(mContentListener
, NS_ERROR_OUT_OF_MEMORY
);
794 rv
= mContentListener
->Init();
795 NS_ENSURE_SUCCESS(rv
, rv
);
797 if (!mStorages
.Init())
798 return NS_ERROR_OUT_OF_MEMORY
;
800 // We want to hold a strong ref to the loadgroup, so it better hold a weak
801 // ref to us... use an InterfaceRequestorProxy to do this.
802 nsCOMPtr
<InterfaceRequestorProxy
> proxy
=
803 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor
*>
805 NS_ENSURE_TRUE(proxy
, NS_ERROR_OUT_OF_MEMORY
);
806 mLoadGroup
->SetNotificationCallbacks(proxy
);
808 rv
= nsDocLoader::AddDocLoaderAsChildOfRoot(this);
809 NS_ENSURE_SUCCESS(rv
, rv
);
811 // Add as |this| a progress listener to itself. A little weird, but
812 // simpler than reproducing all the listener-notification logic in
813 // overrides of the various methods via which nsDocLoader can be
814 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
815 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT
|
816 nsIWebProgress::NOTIFY_STATE_NETWORK
);
821 nsDocShell::DestroyChildren()
823 nsCOMPtr
<nsIDocShellTreeItem
> shell
;
824 PRInt32 n
= mChildList
.Count();
825 for (PRInt32 i
= 0; i
< n
; i
++) {
826 shell
= do_QueryInterface(ChildAt(i
));
827 NS_ASSERTION(shell
, "docshell has null child");
830 shell
->SetTreeOwner(nsnull
);
834 nsDocLoader::DestroyChildren();
837 //*****************************************************************************
838 // nsDocShell::nsISupports
839 //*****************************************************************************
841 NS_IMPL_ADDREF_INHERITED(nsDocShell
, nsDocLoader
)
842 NS_IMPL_RELEASE_INHERITED(nsDocShell
, nsDocLoader
)
844 NS_INTERFACE_MAP_BEGIN(nsDocShell
)
845 NS_INTERFACE_MAP_ENTRY(nsIDocShell
)
846 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem
)
847 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode
)
848 NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory
)
849 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation
)
850 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
851 NS_INTERFACE_MAP_ENTRY(nsIScrollable
)
852 NS_INTERFACE_MAP_ENTRY(nsITextScroll
)
853 NS_INTERFACE_MAP_ENTRY(nsIDocCharset
)
854 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner
)
855 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI
)
856 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
857 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
858 NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer
)
859 NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell
)
860 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor
)
861 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider
)
862 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
863 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
864 NS_INTERFACE_MAP_ENTRY(nsIWebShellServices
)
865 NS_INTERFACE_MAP_ENTRY(nsILinkHandler
)
866 NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands
)
867 NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_2_0_BRANCH
)
868 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader
)
870 ///*****************************************************************************
871 // nsDocShell::nsIInterfaceRequestor
872 //*****************************************************************************
873 NS_IMETHODIMP
nsDocShell::GetInterface(const nsIID
& aIID
, void **aSink
)
875 NS_PRECONDITION(aSink
, "null out param");
879 if (aIID
.Equals(NS_GET_IID(nsICommandManager
))) {
880 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE
);
881 *aSink
= mCommandManager
;
883 else if (aIID
.Equals(NS_GET_IID(nsIURIContentListener
))) {
884 *aSink
= mContentListener
;
886 else if (aIID
.Equals(NS_GET_IID(nsIScriptGlobalObject
)) &&
887 NS_SUCCEEDED(EnsureScriptEnvironment())) {
888 *aSink
= mScriptGlobal
;
890 else if ((aIID
.Equals(NS_GET_IID(nsIDOMWindowInternal
)) ||
891 aIID
.Equals(NS_GET_IID(nsPIDOMWindow
)) ||
892 aIID
.Equals(NS_GET_IID(nsIDOMWindow
))) &&
893 NS_SUCCEEDED(EnsureScriptEnvironment())) {
894 return mScriptGlobal
->QueryInterface(aIID
, aSink
);
896 else if (aIID
.Equals(NS_GET_IID(nsIDOMDocument
)) &&
897 NS_SUCCEEDED(EnsureContentViewer())) {
898 mContentViewer
->GetDOMDocument((nsIDOMDocument
**) aSink
);
899 return *aSink
? NS_OK
: NS_NOINTERFACE
;
901 else if (aIID
.Equals(NS_GET_IID(nsIDocument
)) &&
902 NS_SUCCEEDED(EnsureContentViewer())) {
903 nsCOMPtr
<nsIDOMDocument
> domDoc
;
904 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
906 return NS_NOINTERFACE
;
907 return domDoc
->QueryInterface(aIID
, aSink
);
909 else if (aIID
.Equals(NS_GET_IID(nsIApplicationCacheContainer
))) {
912 // Return application cache associated with this docshell, if any
914 nsCOMPtr
<nsIContentViewer
> contentViewer
;
915 GetContentViewer(getter_AddRefs(contentViewer
));
917 return NS_ERROR_NO_INTERFACE
;
919 nsCOMPtr
<nsIDOMDocument
> domDoc
;
920 contentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
921 NS_ASSERTION(domDoc
, "Should have a document.");
923 return NS_ERROR_NO_INTERFACE
;
925 #if defined(PR_LOGGING) && defined(DEBUG)
926 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
927 ("nsDocShell[%p]: returning app cache container %p",
928 this, domDoc
.get()));
930 return domDoc
->QueryInterface(aIID
, aSink
);
932 else if (aIID
.Equals(NS_GET_IID(nsIPrompt
)) &&
933 NS_SUCCEEDED(EnsureScriptEnvironment())) {
935 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
936 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
937 NS_ENSURE_SUCCESS(rv
, rv
);
939 nsCOMPtr
<nsIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
941 // Get the an auth prompter for our window so that the parenting
942 // of the dialogs works as it should when using tabs.
945 rv
= wwatch
->GetNewPrompter(window
, &prompt
);
946 NS_ENSURE_SUCCESS(rv
, rv
);
951 else if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
)) ||
952 aIID
.Equals(NS_GET_IID(nsIAuthPrompt2
))) {
954 GetAuthPrompt(PROMPT_NORMAL
, aIID
, aSink
)) ?
955 NS_OK
: NS_NOINTERFACE
;
957 else if (aIID
.Equals(NS_GET_IID(nsISHistory
))) {
958 nsCOMPtr
<nsISHistory
> shistory
;
961 GetSessionHistory(getter_AddRefs(shistory
));
962 if (NS_SUCCEEDED(rv
) && shistory
) {
964 NS_ADDREF((nsISupports
*) * aSink
);
967 return NS_NOINTERFACE
;
969 else if (aIID
.Equals(NS_GET_IID(nsIWebBrowserFind
))) {
970 nsresult rv
= EnsureFind();
971 if (NS_FAILED(rv
)) return rv
;
974 NS_ADDREF((nsISupports
*)*aSink
);
977 else if (aIID
.Equals(NS_GET_IID(nsIEditingSession
)) && NS_SUCCEEDED(EnsureEditorData())) {
978 nsCOMPtr
<nsIEditingSession
> editingSession
;
979 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
982 *aSink
= editingSession
;
983 NS_ADDREF((nsISupports
*)*aSink
);
987 return NS_NOINTERFACE
;
989 else if (aIID
.Equals(NS_GET_IID(nsIClipboardDragDropHookList
))
990 && NS_SUCCEEDED(EnsureTransferableHookData())) {
991 *aSink
= mTransferableHookData
;
992 NS_ADDREF((nsISupports
*)*aSink
);
995 else if (aIID
.Equals(NS_GET_IID(nsISelectionDisplay
))) {
996 nsCOMPtr
<nsIPresShell
> shell
;
997 nsresult rv
= GetPresShell(getter_AddRefs(shell
));
998 if (NS_SUCCEEDED(rv
) && shell
)
999 return shell
->QueryInterface(aIID
,aSink
);
1001 else if (aIID
.Equals(NS_GET_IID(nsIDocShellTreeOwner
))) {
1002 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
1003 nsresult rv
= GetTreeOwner(getter_AddRefs(treeOwner
));
1004 if (NS_SUCCEEDED(rv
) && treeOwner
)
1005 return treeOwner
->QueryInterface(aIID
, aSink
);
1007 else if (aIID
.Equals(NS_GET_IID(nsITabChild
))) {
1008 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
1009 nsresult rv
= GetTreeOwner(getter_AddRefs(treeOwner
));
1010 if (NS_SUCCEEDED(rv
) && treeOwner
) {
1011 nsCOMPtr
<nsIInterfaceRequestor
> ir
= do_QueryInterface(treeOwner
);
1013 return ir
->GetInterface(aIID
, aSink
);
1017 return nsDocLoader::GetInterface(aIID
, aSink
);
1020 NS_IF_ADDREF(((nsISupports
*) * aSink
));
1021 return *aSink
? NS_OK
: NS_NOINTERFACE
;
1026 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType
)
1028 PRUint32 loadType
= LOAD_NORMAL
;
1030 switch (aDocShellLoadType
) {
1031 case nsIDocShellLoadInfo::loadNormal
:
1032 loadType
= LOAD_NORMAL
;
1034 case nsIDocShellLoadInfo::loadNormalReplace
:
1035 loadType
= LOAD_NORMAL_REPLACE
;
1037 case nsIDocShellLoadInfo::loadNormalExternal
:
1038 loadType
= LOAD_NORMAL_EXTERNAL
;
1040 case nsIDocShellLoadInfo::loadHistory
:
1041 loadType
= LOAD_HISTORY
;
1043 case nsIDocShellLoadInfo::loadNormalBypassCache
:
1044 loadType
= LOAD_NORMAL_BYPASS_CACHE
;
1046 case nsIDocShellLoadInfo::loadNormalBypassProxy
:
1047 loadType
= LOAD_NORMAL_BYPASS_PROXY
;
1049 case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache
:
1050 loadType
= LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
;
1052 case nsIDocShellLoadInfo::loadReloadNormal
:
1053 loadType
= LOAD_RELOAD_NORMAL
;
1055 case nsIDocShellLoadInfo::loadReloadCharsetChange
:
1056 loadType
= LOAD_RELOAD_CHARSET_CHANGE
;
1058 case nsIDocShellLoadInfo::loadReloadBypassCache
:
1059 loadType
= LOAD_RELOAD_BYPASS_CACHE
;
1061 case nsIDocShellLoadInfo::loadReloadBypassProxy
:
1062 loadType
= LOAD_RELOAD_BYPASS_PROXY
;
1064 case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
:
1065 loadType
= LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
;
1067 case nsIDocShellLoadInfo::loadLink
:
1068 loadType
= LOAD_LINK
;
1070 case nsIDocShellLoadInfo::loadRefresh
:
1071 loadType
= LOAD_REFRESH
;
1073 case nsIDocShellLoadInfo::loadBypassHistory
:
1074 loadType
= LOAD_BYPASS_HISTORY
;
1076 case nsIDocShellLoadInfo::loadStopContent
:
1077 loadType
= LOAD_STOP_CONTENT
;
1079 case nsIDocShellLoadInfo::loadStopContentAndReplace
:
1080 loadType
= LOAD_STOP_CONTENT_AND_REPLACE
;
1082 case nsIDocShellLoadInfo::loadPushState
:
1083 loadType
= LOAD_PUSHSTATE
;
1086 NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
1093 nsDocShellInfoLoadType
1094 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType
)
1096 nsDocShellInfoLoadType docShellLoadType
= nsIDocShellLoadInfo::loadNormal
;
1097 switch (aLoadType
) {
1099 docShellLoadType
= nsIDocShellLoadInfo::loadNormal
;
1101 case LOAD_NORMAL_REPLACE
:
1102 docShellLoadType
= nsIDocShellLoadInfo::loadNormalReplace
;
1104 case LOAD_NORMAL_EXTERNAL
:
1105 docShellLoadType
= nsIDocShellLoadInfo::loadNormalExternal
;
1107 case LOAD_NORMAL_BYPASS_CACHE
:
1108 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassCache
;
1110 case LOAD_NORMAL_BYPASS_PROXY
:
1111 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassProxy
;
1113 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
1114 docShellLoadType
= nsIDocShellLoadInfo::loadNormalBypassProxyAndCache
;
1117 docShellLoadType
= nsIDocShellLoadInfo::loadHistory
;
1119 case LOAD_RELOAD_NORMAL
:
1120 docShellLoadType
= nsIDocShellLoadInfo::loadReloadNormal
;
1122 case LOAD_RELOAD_CHARSET_CHANGE
:
1123 docShellLoadType
= nsIDocShellLoadInfo::loadReloadCharsetChange
;
1125 case LOAD_RELOAD_BYPASS_CACHE
:
1126 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassCache
;
1128 case LOAD_RELOAD_BYPASS_PROXY
:
1129 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassProxy
;
1131 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
1132 docShellLoadType
= nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
;
1135 docShellLoadType
= nsIDocShellLoadInfo::loadLink
;
1138 docShellLoadType
= nsIDocShellLoadInfo::loadRefresh
;
1140 case LOAD_BYPASS_HISTORY
:
1141 case LOAD_ERROR_PAGE
:
1142 docShellLoadType
= nsIDocShellLoadInfo::loadBypassHistory
;
1144 case LOAD_STOP_CONTENT
:
1145 docShellLoadType
= nsIDocShellLoadInfo::loadStopContent
;
1147 case LOAD_STOP_CONTENT_AND_REPLACE
:
1148 docShellLoadType
= nsIDocShellLoadInfo::loadStopContentAndReplace
;
1150 case LOAD_PUSHSTATE
:
1151 docShellLoadType
= nsIDocShellLoadInfo::loadPushState
;
1154 NS_NOTREACHED("Unexpected load type value");
1157 return docShellLoadType
;
1160 //*****************************************************************************
1161 // nsDocShell::nsIDocShell
1162 //*****************************************************************************
1164 nsDocShell::LoadURI(nsIURI
* aURI
,
1165 nsIDocShellLoadInfo
* aLoadInfo
,
1166 PRUint32 aLoadFlags
,
1169 NS_PRECONDITION(aLoadInfo
|| (aLoadFlags
& EXTRA_LOAD_FLAGS
) == 0,
1170 "Unexpected flags");
1171 NS_PRECONDITION((aLoadFlags
& 0xf) == 0, "Should not have these flags set");
1173 // Note: we allow loads to get through here even if mFiredUnloadEvent is
1174 // true; that case will get handled in LoadInternal or LoadHistoryEntry.
1175 if (IsPrintingOrPP()) {
1176 return NS_OK
; // JS may not handle returning of an error code
1179 nsCOMPtr
<nsIURI
> referrer
;
1180 nsCOMPtr
<nsIInputStream
> postStream
;
1181 nsCOMPtr
<nsIInputStream
> headersStream
;
1182 nsCOMPtr
<nsISupports
> owner
;
1183 PRBool inheritOwner
= PR_FALSE
;
1184 PRBool ownerIsExplicit
= PR_FALSE
;
1185 PRBool sendReferrer
= PR_TRUE
;
1186 nsCOMPtr
<nsISHEntry
> shEntry
;
1187 nsXPIDLString target
;
1188 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
1190 NS_ENSURE_ARG(aURI
);
1192 // Extract the info from the DocShellLoadInfo struct...
1194 aLoadInfo
->GetReferrer(getter_AddRefs(referrer
));
1196 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
1197 aLoadInfo
->GetLoadType(<
);
1198 // Get the appropriate loadType from nsIDocShellLoadInfo type
1199 loadType
= ConvertDocShellLoadInfoToLoadType(lt
);
1201 aLoadInfo
->GetOwner(getter_AddRefs(owner
));
1202 aLoadInfo
->GetInheritOwner(&inheritOwner
);
1203 aLoadInfo
->GetOwnerIsExplicit(&ownerIsExplicit
);
1204 aLoadInfo
->GetSHEntry(getter_AddRefs(shEntry
));
1205 aLoadInfo
->GetTarget(getter_Copies(target
));
1206 aLoadInfo
->GetPostDataStream(getter_AddRefs(postStream
));
1207 aLoadInfo
->GetHeadersStream(getter_AddRefs(headersStream
));
1208 aLoadInfo
->GetSendReferrer(&sendReferrer
);
1211 #if defined(PR_LOGGING) && defined(DEBUG)
1212 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
1213 nsCAutoString uristr
;
1214 aURI
->GetAsciiSpec(uristr
);
1215 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
1216 ("nsDocShell[%p]: loading %s with flags 0x%08x",
1217 this, uristr
.get(), aLoadFlags
));
1222 !LOAD_TYPE_HAS_FLAGS(loadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
1223 // First verify if this is a subframe.
1224 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
1225 GetSameTypeParent(getter_AddRefs(parentAsItem
));
1226 nsCOMPtr
<nsIDocShell
> parentDS(do_QueryInterface(parentAsItem
));
1227 PRUint32 parentLoadType
;
1229 if (parentDS
&& parentDS
!= static_cast<nsIDocShell
*>(this)) {
1230 /* OK. It is a subframe. Checkout the
1231 * parent's loadtype. If the parent was loaded thro' a history
1232 * mechanism, then get the SH entry for the child from the parent.
1233 * This is done to restore frameset navigation while going back/forward.
1234 * If the parent was loaded through any other loadType, set the
1235 * child's loadType too accordingly, so that session history does not
1239 // Get the parent's load type
1240 parentDS
->GetLoadType(&parentLoadType
);
1242 nsCOMPtr
<nsIDocShellHistory
> parent(do_QueryInterface(parentAsItem
));
1244 // Get the ShEntry for the child from the parent
1245 nsCOMPtr
<nsISHEntry
> currentSH
;
1246 PRBool oshe
= PR_FALSE
;
1247 parent
->GetCurrentSHEntry(getter_AddRefs(currentSH
), &oshe
);
1248 PRBool dynamicallyAddedChild
= mDynamicallyCreated
;
1249 if (!dynamicallyAddedChild
&& !oshe
&& currentSH
) {
1250 currentSH
->HasDynamicallyAddedChild(&dynamicallyAddedChild
);
1252 if (!dynamicallyAddedChild
) {
1253 // Only use the old SHEntry, if we're sure enough that
1254 // it wasn't originally for some other frame.
1255 parent
->GetChildSHEntry(mChildOffset
, getter_AddRefs(shEntry
));
1258 // Make some decisions on the child frame's loadType based on the
1259 // parent's loadType.
1260 if (mCurrentURI
== nsnull
) {
1261 // This is a newly created frame. Check for exception cases first.
1262 // By default the subframe will inherit the parent's loadType.
1263 if (shEntry
&& (parentLoadType
== LOAD_NORMAL
||
1264 parentLoadType
== LOAD_LINK
||
1265 parentLoadType
== LOAD_NORMAL_EXTERNAL
)) {
1266 // The parent was loaded normally. In this case, this *brand new* child really shouldn't
1267 // have a SHEntry. If it does, it could be because the parent is replacing an
1268 // existing frame with a new frame, in the onLoadHandler. We don't want this
1269 // url to get into session history. Clear off shEntry, and set load type to
1270 // LOAD_BYPASS_HISTORY.
1271 PRBool inOnLoadHandler
=PR_FALSE
;
1272 parentDS
->GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
1273 if (inOnLoadHandler
) {
1274 loadType
= LOAD_NORMAL_REPLACE
;
1278 else if (parentLoadType
== LOAD_REFRESH
) {
1279 // Clear shEntry. For refresh loads, we have to load
1280 // what comes thro' the pipe, not what's in history.
1283 else if ((parentLoadType
== LOAD_BYPASS_HISTORY
) ||
1284 (parentLoadType
== LOAD_ERROR_PAGE
) ||
1286 ((parentLoadType
& LOAD_CMD_HISTORY
) ||
1287 (parentLoadType
== LOAD_RELOAD_NORMAL
) ||
1288 (parentLoadType
== LOAD_RELOAD_CHARSET_CHANGE
)))) {
1289 // If the parent url, bypassed history or was loaded from
1290 // history, pass on the parent's loadType to the new child
1291 // frame too, so that the child frame will also
1292 // avoid getting into history.
1293 loadType
= parentLoadType
;
1297 // This is a pre-existing subframe. If the load was not originally initiated
1298 // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
1299 // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading
1300 // a new page in this child. Check parent's and self's busy flag and if it is set,
1301 // we don't want this onLoadHandler load to get in to session history.
1302 PRUint32 parentBusy
= BUSY_FLAGS_NONE
;
1303 PRUint32 selfBusy
= BUSY_FLAGS_NONE
;
1304 parentDS
->GetBusyFlags(&parentBusy
);
1305 GetBusyFlags(&selfBusy
);
1306 if (((parentBusy
& BUSY_FLAGS_BUSY
) ||
1307 (selfBusy
& BUSY_FLAGS_BUSY
)) &&
1309 loadType
= LOAD_NORMAL_REPLACE
;
1316 // This is the root docshell. If we got here while
1317 // executing an onLoad Handler,this load will not go
1318 // into session history.
1319 PRBool inOnLoadHandler
=PR_FALSE
;
1320 GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
1321 if (inOnLoadHandler
) {
1322 loadType
= LOAD_NORMAL_REPLACE
;
1329 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
1330 ("nsDocShell[%p]: loading from session history", this));
1333 return LoadHistoryEntry(shEntry
, loadType
);
1336 // Perform the load...
1338 // We need an owner (a referring principal).
1340 // If ownerIsExplicit is not set there are 4 possibilities:
1341 // (1) If the system principal was passed in and we're a typeContent
1342 // docshell, inherit the principal from the current document
1344 // (2) In all other cases when the principal passed in is not null,
1345 // use that principal.
1346 // (3) If the caller has allowed inheriting from the current document,
1347 // or if we're being called from system code (eg chrome JS or pure
1348 // C++) then inheritOwner should be true and InternalLoad will get
1349 // an owner from the current document. If none of these things are
1351 // (4) we pass a null owner into the channel, and an owner will be
1352 // created later from the channel's internal data.
1354 // If ownerIsExplicit *is* set, there are 4 possibilities
1355 // (1) If the system principal was passed in and we're a typeContent
1356 // docshell, return an error.
1357 // (2) In all other cases when the principal passed in is not null,
1358 // use that principal.
1359 // (3) If the caller has allowed inheriting from the current document,
1360 // then inheritOwner should be true and InternalLoad will get an owner
1361 // from the current document. If none of these things are true, then
1362 // (4) we pass a null owner into the channel, and an owner will be
1363 // created later from the channel's internal data.
1365 // NOTE: This all only works because the only thing the owner is used
1366 // for in InternalLoad is data:, javascript:, and about:blank
1367 // URIs. For other URIs this would all be dead wrong!
1369 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
1370 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
1371 NS_ENSURE_SUCCESS(rv
, rv
);
1373 if (owner
&& mItemType
!= typeChrome
) {
1374 nsCOMPtr
<nsIPrincipal
> ownerPrincipal
= do_QueryInterface(owner
);
1376 rv
= secMan
->IsSystemPrincipal(ownerPrincipal
, &isSystem
);
1377 NS_ENSURE_SUCCESS(rv
, rv
);
1380 if (ownerIsExplicit
) {
1381 return NS_ERROR_DOM_SECURITY_ERR
;
1384 inheritOwner
= PR_TRUE
;
1387 if (!owner
&& !inheritOwner
&& !ownerIsExplicit
) {
1388 // See if there's system or chrome JS code running
1389 rv
= secMan
->SubjectPrincipalIsSystem(&inheritOwner
);
1390 if (NS_FAILED(rv
)) {
1391 // Set it back to false
1392 inheritOwner
= PR_FALSE
;
1399 flags
|= INTERNAL_LOAD_FLAGS_INHERIT_OWNER
;
1402 flags
|= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
;
1404 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
)
1405 flags
|= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
1407 if (aLoadFlags
& LOAD_FLAGS_FIRST_LOAD
)
1408 flags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
1410 if (aLoadFlags
& LOAD_FLAGS_BYPASS_CLASSIFIER
)
1411 flags
|= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
;
1413 if (aLoadFlags
& LOAD_FLAGS_FORCE_ALLOW_COOKIES
)
1414 flags
|= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES
;
1416 return InternalLoad(aURI
,
1421 nsnull
, // No type hint
1425 nsnull
, // No SHEntry
1427 nsnull
, // No nsIDocShell
1428 nsnull
); // No nsIRequest
1432 nsDocShell::LoadStream(nsIInputStream
*aStream
, nsIURI
* aURI
,
1433 const nsACString
&aContentType
,
1434 const nsACString
&aContentCharset
,
1435 nsIDocShellLoadInfo
* aLoadInfo
)
1437 NS_ENSURE_ARG(aStream
);
1439 mAllowKeywordFixup
= PR_FALSE
;
1441 // if the caller doesn't pass in a URI we need to create a dummy URI. necko
1442 // currently requires a URI in various places during the load. Some consumers
1444 nsCOMPtr
<nsIURI
> uri
= aURI
;
1447 nsresult rv
= NS_OK
;
1448 uri
= do_CreateInstance(NS_SIMPLEURI_CONTRACTID
, &rv
);
1451 // Make sure that the URI spec "looks" like a protocol and path...
1452 // For now, just use a bogus protocol called "internal"
1453 rv
= uri
->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
1458 PRUint32 loadType
= LOAD_NORMAL
;
1460 nsDocShellInfoLoadType lt
= nsIDocShellLoadInfo::loadNormal
;
1461 (void) aLoadInfo
->GetLoadType(<
);
1462 // Get the appropriate LoadType from nsIDocShellLoadInfo type
1463 loadType
= ConvertDocShellLoadInfoToLoadType(lt
);
1466 NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK
), NS_ERROR_FAILURE
);
1468 mLoadType
= loadType
;
1470 // build up a channel for this stream.
1471 nsCOMPtr
<nsIChannel
> channel
;
1472 NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
1473 (getter_AddRefs(channel
), uri
, aStream
,
1474 aContentType
, aContentCharset
),
1477 nsCOMPtr
<nsIURILoader
>
1478 uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID
));
1479 NS_ENSURE_TRUE(uriLoader
, NS_ERROR_FAILURE
);
1481 NS_ENSURE_SUCCESS(DoChannelLoad(channel
, uriLoader
, PR_FALSE
),
1487 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo
** aLoadInfo
)
1489 nsDocShellLoadInfo
*loadInfo
= new nsDocShellLoadInfo();
1490 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
1491 nsCOMPtr
<nsIDocShellLoadInfo
> localRef(loadInfo
);
1493 *aLoadInfo
= localRef
;
1494 NS_ADDREF(*aLoadInfo
);
1500 * Reset state to a new content model within the current document and the document
1501 * viewer. Called by the document before initiating an out of band document.write().
1504 nsDocShell::PrepareForNewContentModel()
1506 mEODForCurrentDocument
= PR_FALSE
;
1512 nsDocShell::FirePageHideNotification(PRBool aIsUnload
)
1514 if (mContentViewer
&& !mFiredUnloadEvent
) {
1515 // Keep an explicit reference since calling PageHide could release
1517 nsCOMPtr
<nsIContentViewer
> kungFuDeathGrip(mContentViewer
);
1518 mFiredUnloadEvent
= PR_TRUE
;
1520 mContentViewer
->PageHide(aIsUnload
);
1522 nsAutoTArray
<nsCOMPtr
<nsIDocShell
>, 8> kids
;
1523 PRInt32 i
, n
= mChildList
.Count();
1524 kids
.SetCapacity(n
);
1525 for (i
= 0; i
< n
; i
++) {
1526 kids
.AppendElement(do_QueryInterface(ChildAt(i
)));
1530 for (i
= 0; i
< n
; ++i
) {
1532 kids
[i
]->FirePageHideNotification(aIsUnload
);
1535 // Now make sure our editor, if any, is detached before we go
1537 DetachEditorFromWindow();
1544 // Bug 13871: Prevent frameset spoofing
1546 // This routine answers: 'Is origin's document from same domain as
1547 // target's document?'
1549 // file: uris are considered the same domain for the purpose of
1550 // frame navigation regardless of script accessibility (bug 420425)
1554 nsDocShell::ValidateOrigin(nsIDocShellTreeItem
* aOriginTreeItem
,
1555 nsIDocShellTreeItem
* aTargetTreeItem
)
1557 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
1558 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
1559 NS_ENSURE_TRUE(securityManager
, PR_FALSE
);
1561 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
;
1563 securityManager
->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal
));
1564 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
1566 if (subjectPrincipal
) {
1567 // We're called from JS, check if UniversalBrowserWrite is
1569 PRBool ubwEnabled
= PR_FALSE
;
1570 rv
= securityManager
->IsCapabilityEnabled("UniversalBrowserWrite",
1572 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
1579 // Get origin document principal
1580 nsCOMPtr
<nsIDocument
> originDocument(do_GetInterface(aOriginTreeItem
));
1581 NS_ENSURE_TRUE(originDocument
, PR_FALSE
);
1583 // Get target principal
1584 nsCOMPtr
<nsIDocument
> targetDocument(do_GetInterface(aTargetTreeItem
));
1585 NS_ENSURE_TRUE(targetDocument
, PR_FALSE
);
1588 rv
= originDocument
->NodePrincipal()->
1589 Equals(targetDocument
->NodePrincipal(), &equal
);
1590 if (NS_SUCCEEDED(rv
) && equal
) {
1594 // Not strictly equal, special case if both are file: uris
1595 PRBool originIsFile
= PR_FALSE
;
1596 PRBool targetIsFile
= PR_FALSE
;
1597 nsCOMPtr
<nsIURI
> originURI
;
1598 nsCOMPtr
<nsIURI
> targetURI
;
1599 nsCOMPtr
<nsIURI
> innerOriginURI
;
1600 nsCOMPtr
<nsIURI
> innerTargetURI
;
1602 rv
= originDocument
->NodePrincipal()->GetURI(getter_AddRefs(originURI
));
1603 if (NS_SUCCEEDED(rv
) && originURI
)
1604 innerOriginURI
= NS_GetInnermostURI(originURI
);
1606 rv
= targetDocument
->NodePrincipal()->GetURI(getter_AddRefs(targetURI
));
1607 if (NS_SUCCEEDED(rv
) && targetURI
)
1608 innerTargetURI
= NS_GetInnermostURI(targetURI
);
1610 return innerOriginURI
&& innerTargetURI
&&
1611 NS_SUCCEEDED(innerOriginURI
->SchemeIs("file", &originIsFile
)) &&
1612 NS_SUCCEEDED(innerTargetURI
->SchemeIs("file", &targetIsFile
)) &&
1613 originIsFile
&& targetIsFile
;
1617 nsDocShell::GetEldestPresContext(nsPresContext
** aPresContext
)
1619 nsresult rv
= NS_OK
;
1621 NS_ENSURE_ARG_POINTER(aPresContext
);
1622 *aPresContext
= nsnull
;
1624 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
1626 nsCOMPtr
<nsIContentViewer
> prevViewer
;
1627 viewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
1629 viewer
= prevViewer
;
1631 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(viewer
));
1633 rv
= docv
->GetPresContext(aPresContext
);
1642 nsDocShell::GetPresContext(nsPresContext
** aPresContext
)
1644 NS_ENSURE_ARG_POINTER(aPresContext
);
1645 *aPresContext
= nsnull
;
1647 if (!mContentViewer
)
1650 nsCOMPtr
<nsIDocumentViewer
> docv(do_QueryInterface(mContentViewer
));
1651 NS_ENSURE_TRUE(docv
, NS_ERROR_NO_INTERFACE
);
1653 return docv
->GetPresContext(aPresContext
);
1657 nsDocShell::GetPresShell(nsIPresShell
** aPresShell
)
1659 nsresult rv
= NS_OK
;
1661 NS_ENSURE_ARG_POINTER(aPresShell
);
1662 *aPresShell
= nsnull
;
1664 nsRefPtr
<nsPresContext
> presContext
;
1665 (void) GetPresContext(getter_AddRefs(presContext
));
1668 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1675 nsDocShell::GetEldestPresShell(nsIPresShell
** aPresShell
)
1677 nsresult rv
= NS_OK
;
1679 NS_ENSURE_ARG_POINTER(aPresShell
);
1680 *aPresShell
= nsnull
;
1682 nsRefPtr
<nsPresContext
> presContext
;
1683 (void) GetEldestPresContext(getter_AddRefs(presContext
));
1686 NS_IF_ADDREF(*aPresShell
= presContext
->GetPresShell());
1693 nsDocShell::GetContentViewer(nsIContentViewer
** aContentViewer
)
1695 NS_ENSURE_ARG_POINTER(aContentViewer
);
1697 *aContentViewer
= mContentViewer
;
1698 NS_IF_ADDREF(*aContentViewer
);
1703 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget
* aChromeEventHandler
)
1705 nsCOMPtr
<nsPIDOMEventTarget
> piTarget
=
1706 do_QueryInterface(aChromeEventHandler
);
1707 // Weak reference. Don't addref.
1708 mChromeEventHandler
= piTarget
;
1710 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
1712 win
->SetChromeEventHandler(piTarget
);
1719 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget
** aChromeEventHandler
)
1721 NS_ENSURE_ARG_POINTER(aChromeEventHandler
);
1722 nsCOMPtr
<nsIDOMEventTarget
> target
= do_QueryInterface(mChromeEventHandler
);
1723 target
.swap(*aChromeEventHandler
);
1727 /* [noscript] void setCurrentURI (in nsIURI uri); */
1729 nsDocShell::SetCurrentURI(nsIURI
*aURI
)
1731 SetCurrentURI(aURI
, nsnull
, PR_TRUE
);
1736 nsDocShell::SetCurrentURI(nsIURI
*aURI
, nsIRequest
*aRequest
,
1737 PRBool aFireOnLocationChange
)
1740 if (gDocShellLeakLog
&& PR_LOG_TEST(gDocShellLeakLog
, PR_LOG_DEBUG
)) {
1743 aURI
->GetSpec(spec
);
1744 PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec
.get());
1748 // We don't want to send a location change when we're displaying an error
1749 // page, and we don't want to change our idea of "current URI" either
1750 if (mLoadType
== LOAD_ERROR_PAGE
) {
1754 mCurrentURI
= NS_TryToMakeImmutable(aURI
);
1756 PRBool isRoot
= PR_FALSE
; // Is this the root docshell
1757 PRBool isSubFrame
= PR_FALSE
; // Is this a subframe navigation?
1759 nsCOMPtr
<nsIDocShellTreeItem
> root
;
1761 GetSameTypeRootTreeItem(getter_AddRefs(root
));
1762 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this))
1764 // This is the root docshell
1768 mLSHE
->GetIsSubFrame(&isSubFrame
);
1771 if (!isSubFrame
&& !isRoot
) {
1773 * We don't want to send OnLocationChange notifications when
1774 * a subframe is being loaded for the first time, while
1775 * visiting a frameset page
1780 if (aFireOnLocationChange
) {
1781 FireOnLocationChange(this, aRequest
, aURI
);
1783 return !aFireOnLocationChange
;
1787 nsDocShell::GetCharset(char** aCharset
)
1789 NS_ENSURE_ARG_POINTER(aCharset
);
1792 nsCOMPtr
<nsIPresShell
> presShell
;
1793 GetPresShell(getter_AddRefs(presShell
));
1794 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
1795 nsIDocument
*doc
= presShell
->GetDocument();
1796 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
1797 *aCharset
= ToNewCString(doc
->GetDocumentCharacterSet());
1799 return NS_ERROR_OUT_OF_MEMORY
;
1806 nsDocShell::SetCharset(const char* aCharset
)
1808 // set the default charset
1809 nsCOMPtr
<nsIContentViewer
> viewer
;
1810 GetContentViewer(getter_AddRefs(viewer
));
1812 nsCOMPtr
<nsIMarkupDocumentViewer
> muDV(do_QueryInterface(viewer
));
1814 nsCString
charset(aCharset
);
1815 NS_ENSURE_SUCCESS(muDV
->SetDefaultCharacterSet(charset
),
1820 // set the charset override
1821 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
;
1822 GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
1824 nsCOMPtr
<nsIAtom
> csAtom
;
1825 csAtom
= do_GetAtom(aCharset
);
1826 dcInfo
->SetForcedCharset(csAtom
);
1833 nsDocShell::GetDocumentCharsetInfo(nsIDocumentCharsetInfo
**
1834 aDocumentCharsetInfo
)
1836 NS_ENSURE_ARG_POINTER(aDocumentCharsetInfo
);
1838 // if the mDocumentCharsetInfo does not exist already, we create it now
1839 if (!mDocumentCharsetInfo
) {
1840 mDocumentCharsetInfo
= do_CreateInstance(NS_DOCUMENTCHARSETINFO_CONTRACTID
);
1841 if (!mDocumentCharsetInfo
)
1842 return NS_ERROR_FAILURE
;
1845 *aDocumentCharsetInfo
= mDocumentCharsetInfo
;
1846 NS_IF_ADDREF(*aDocumentCharsetInfo
);
1851 nsDocShell::SetDocumentCharsetInfo(nsIDocumentCharsetInfo
*
1852 aDocumentCharsetInfo
)
1854 mDocumentCharsetInfo
= aDocumentCharsetInfo
;
1859 nsDocShell::GetChannelIsUnsafe(PRBool
*aUnsafe
)
1861 *aUnsafe
= PR_FALSE
;
1863 nsIChannel
* channel
= GetCurrentDocChannel();
1868 nsCOMPtr
<nsIJARChannel
> jarChannel
= do_QueryInterface(channel
);
1873 return jarChannel
->GetIsUnsafe(aUnsafe
);
1877 nsDocShell::GetAllowPlugins(PRBool
* aAllowPlugins
)
1879 NS_ENSURE_ARG_POINTER(aAllowPlugins
);
1881 *aAllowPlugins
= mAllowPlugins
;
1882 if (!mAllowPlugins
) {
1887 *aAllowPlugins
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1892 nsDocShell::SetAllowPlugins(PRBool aAllowPlugins
)
1894 mAllowPlugins
= aAllowPlugins
;
1895 //XXX should enable or disable a plugin host
1900 nsDocShell::GetAllowJavascript(PRBool
* aAllowJavascript
)
1902 NS_ENSURE_ARG_POINTER(aAllowJavascript
);
1904 *aAllowJavascript
= mAllowJavascript
;
1905 if (!mAllowJavascript
) {
1910 *aAllowJavascript
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1915 nsDocShell::SetAllowJavascript(PRBool aAllowJavascript
)
1917 mAllowJavascript
= aAllowJavascript
;
1921 NS_IMETHODIMP
nsDocShell::GetAllowMetaRedirects(PRBool
* aReturn
)
1923 NS_ENSURE_ARG_POINTER(aReturn
);
1925 *aReturn
= mAllowMetaRedirects
;
1926 if (!mAllowMetaRedirects
) {
1931 *aReturn
= NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe
)) && !unsafe
;
1935 NS_IMETHODIMP
nsDocShell::SetAllowMetaRedirects(PRBool aValue
)
1937 mAllowMetaRedirects
= aValue
;
1941 NS_IMETHODIMP
nsDocShell::GetAllowSubframes(PRBool
* aAllowSubframes
)
1943 NS_ENSURE_ARG_POINTER(aAllowSubframes
);
1945 *aAllowSubframes
= mAllowSubframes
;
1949 NS_IMETHODIMP
nsDocShell::SetAllowSubframes(PRBool aAllowSubframes
)
1951 mAllowSubframes
= aAllowSubframes
;
1955 NS_IMETHODIMP
nsDocShell::GetAllowImages(PRBool
* aAllowImages
)
1957 NS_ENSURE_ARG_POINTER(aAllowImages
);
1959 *aAllowImages
= mAllowImages
;
1963 NS_IMETHODIMP
nsDocShell::SetAllowImages(PRBool aAllowImages
)
1965 mAllowImages
= aAllowImages
;
1969 NS_IMETHODIMP
nsDocShell::GetAllowDNSPrefetch(PRBool
* aAllowDNSPrefetch
)
1971 *aAllowDNSPrefetch
= mAllowDNSPrefetch
;
1975 NS_IMETHODIMP
nsDocShell::SetAllowDNSPrefetch(PRBool aAllowDNSPrefetch
)
1977 mAllowDNSPrefetch
= aAllowDNSPrefetch
;
1982 nsDocShell::GetDocShellEnumerator(PRInt32 aItemType
, PRInt32 aDirection
, nsISimpleEnumerator
**outEnum
)
1984 NS_ENSURE_ARG_POINTER(outEnum
);
1987 nsRefPtr
<nsDocShellEnumerator
> docShellEnum
;
1988 if (aDirection
== ENUMERATE_FORWARDS
)
1989 docShellEnum
= new nsDocShellForwardsEnumerator
;
1991 docShellEnum
= new nsDocShellBackwardsEnumerator
;
1993 if (!docShellEnum
) return NS_ERROR_OUT_OF_MEMORY
;
1995 nsresult rv
= docShellEnum
->SetEnumDocShellType(aItemType
);
1996 if (NS_FAILED(rv
)) return rv
;
1998 rv
= docShellEnum
->SetEnumerationRootItem((nsIDocShellTreeItem
*)this);
1999 if (NS_FAILED(rv
)) return rv
;
2001 rv
= docShellEnum
->First();
2002 if (NS_FAILED(rv
)) return rv
;
2004 rv
= docShellEnum
->QueryInterface(NS_GET_IID(nsISimpleEnumerator
), (void **)outEnum
);
2010 nsDocShell::GetAppType(PRUint32
* aAppType
)
2012 *aAppType
= mAppType
;
2017 nsDocShell::SetAppType(PRUint32 aAppType
)
2019 mAppType
= aAppType
;
2025 nsDocShell::GetAllowAuth(PRBool
* aAllowAuth
)
2027 *aAllowAuth
= mAllowAuth
;
2032 nsDocShell::SetAllowAuth(PRBool aAllowAuth
)
2034 mAllowAuth
= aAllowAuth
;
2039 nsDocShell::GetZoom(float *zoom
)
2041 NS_ENSURE_ARG_POINTER(zoom
);
2047 nsDocShell::SetZoom(float zoom
)
2049 return NS_ERROR_NOT_IMPLEMENTED
;
2053 nsDocShell::GetMarginWidth(PRInt32
* aWidth
)
2055 NS_ENSURE_ARG_POINTER(aWidth
);
2057 *aWidth
= mMarginWidth
;
2062 nsDocShell::SetMarginWidth(PRInt32 aWidth
)
2064 mMarginWidth
= aWidth
;
2069 nsDocShell::GetMarginHeight(PRInt32
* aHeight
)
2071 NS_ENSURE_ARG_POINTER(aHeight
);
2073 *aHeight
= mMarginHeight
;
2078 nsDocShell::SetMarginHeight(PRInt32 aHeight
)
2080 mMarginHeight
= aHeight
;
2085 nsDocShell::GetBusyFlags(PRUint32
* aBusyFlags
)
2087 NS_ENSURE_ARG_POINTER(aBusyFlags
);
2089 *aBusyFlags
= mBusyFlags
;
2094 nsDocShell::TabToTreeOwner(PRBool aForward
, PRBool
* aTookFocus
)
2096 NS_ENSURE_ARG_POINTER(aTookFocus
);
2098 nsCOMPtr
<nsIWebBrowserChromeFocus
> chromeFocus
= do_GetInterface(mTreeOwner
);
2101 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusNextElement());
2103 *aTookFocus
= NS_SUCCEEDED(chromeFocus
->FocusPrevElement());
2105 *aTookFocus
= PR_FALSE
;
2111 nsDocShell::GetSecurityUI(nsISecureBrowserUI
**aSecurityUI
)
2113 NS_IF_ADDREF(*aSecurityUI
= mSecurityUI
);
2118 nsDocShell::SetSecurityUI(nsISecureBrowserUI
*aSecurityUI
)
2120 mSecurityUI
= aSecurityUI
;
2125 nsDocShell::GetUseErrorPages(PRBool
*aUseErrorPages
)
2127 *aUseErrorPages
= mUseErrorPages
;
2132 nsDocShell::SetUseErrorPages(PRBool aUseErrorPages
)
2134 // If mUseErrorPages is set explicitly, stop observing the pref.
2135 if (mObserveErrorPages
) {
2136 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
));
2138 prefs
->RemoveObserver("browser.xul.error_pages.enabled", this);
2139 mObserveErrorPages
= PR_FALSE
;
2142 mUseErrorPages
= aUseErrorPages
;
2147 nsDocShell::GetPreviousTransIndex(PRInt32
*aPreviousTransIndex
)
2149 *aPreviousTransIndex
= mPreviousTransIndex
;
2154 nsDocShell::GetLoadedTransIndex(PRInt32
*aLoadedTransIndex
)
2156 *aLoadedTransIndex
= mLoadedTransIndex
;
2161 nsDocShell::HistoryPurged(PRInt32 aNumEntries
)
2163 // These indices are used for fastback cache eviction, to determine
2164 // which session history entries are candidates for content viewer
2165 // eviction. We need to adjust by the number of entries that we
2166 // just purged from history, so that we look at the right session history
2167 // entries during eviction.
2168 mPreviousTransIndex
= NS_MAX(-1, mPreviousTransIndex
- aNumEntries
);
2169 mLoadedTransIndex
= NS_MAX(0, mLoadedTransIndex
- aNumEntries
);
2171 PRInt32 count
= mChildList
.Count();
2172 for (PRInt32 i
= 0; i
< count
; ++i
) {
2173 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
2175 shell
->HistoryPurged(aNumEntries
);
2183 nsDocShell::HistoryTransactionRemoved(PRInt32 aIndex
)
2185 // These indices are used for fastback cache eviction, to determine
2186 // which session history entries are candidates for content viewer
2187 // eviction. We need to adjust by the number of entries that we
2188 // just purged from history, so that we look at the right session history
2189 // entries during eviction.
2190 if (aIndex
== mPreviousTransIndex
) {
2191 mPreviousTransIndex
= -1;
2192 } else if (aIndex
< mPreviousTransIndex
) {
2193 --mPreviousTransIndex
;
2195 if (mLoadedTransIndex
== aIndex
) {
2196 mLoadedTransIndex
= 0;
2197 } else if (aIndex
< mLoadedTransIndex
) {
2198 --mLoadedTransIndex
;
2201 PRInt32 count
= mChildList
.Count();
2202 for (PRInt32 i
= 0; i
< count
; ++i
) {
2203 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
2205 static_cast<nsDocShell
*>(shell
.get())->
2206 HistoryTransactionRemoved(aIndex
);
2215 GetPrincipalDomain(nsIPrincipal
* aPrincipal
, nsACString
& aDomain
)
2219 nsCOMPtr
<nsIURI
> codebaseURI
;
2220 nsresult rv
= aPrincipal
->GetDomain(getter_AddRefs(codebaseURI
));
2221 NS_ENSURE_SUCCESS(rv
, rv
);
2223 rv
= aPrincipal
->GetURI(getter_AddRefs(codebaseURI
));
2224 NS_ENSURE_SUCCESS(rv
, rv
);
2230 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(codebaseURI
);
2231 NS_ASSERTION(innerURI
, "Failed to get innermost URI");
2232 NS_ENSURE_SUCCESS(rv
, rv
);
2234 rv
= innerURI
->GetAsciiHost(aDomain
);
2242 nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal
* aPrincipal
,
2243 const nsAString
& aDocumentURI
,
2245 nsIDOMStorage
** aStorage
)
2247 NS_ENSURE_ARG_POINTER(aStorage
);
2255 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
2256 rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
2261 return NS_ERROR_FAILURE
;
2263 nsDocShell
* topDocShell
= static_cast<nsDocShell
*>(topItem
.get());
2264 if (topDocShell
!= this)
2265 return topDocShell
->GetSessionStorageForPrincipal(aPrincipal
,
2270 nsCAutoString currentDomain
;
2271 rv
= GetPrincipalDomain(aPrincipal
, currentDomain
);
2275 if (currentDomain
.IsEmpty())
2278 if (!mStorages
.Get(currentDomain
, aStorage
) && aCreate
) {
2279 nsCOMPtr
<nsIDOMStorage
> newstorage
=
2280 do_CreateInstance("@mozilla.org/dom/storage;2");
2282 return NS_ERROR_OUT_OF_MEMORY
;
2284 nsCOMPtr
<nsPIDOMStorage
> pistorage
= do_QueryInterface(newstorage
);
2286 return NS_ERROR_FAILURE
;
2287 rv
= pistorage
->InitAsSessionStorage(aPrincipal
, aDocumentURI
);
2291 if (!mStorages
.Put(currentDomain
, newstorage
))
2292 return NS_ERROR_OUT_OF_MEMORY
;
2294 newstorage
.swap(*aStorage
);
2295 #if defined(PR_LOGGING) && defined(DEBUG)
2296 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2297 ("nsDocShell[%p]: created a new sessionStorage %p",
2301 else if (*aStorage
) {
2302 nsCOMPtr
<nsPIDOMStorage
> piStorage
= do_QueryInterface(*aStorage
);
2304 PRBool canAccess
= piStorage
->CanAccess(aPrincipal
);
2305 NS_ASSERTION(canAccess
,
2306 "GetSessionStorageForPrincipal got a storage "
2307 "that could not be accessed!");
2309 NS_RELEASE(*aStorage
);
2310 return NS_ERROR_DOM_SECURITY_ERR
;
2314 #if defined(PR_LOGGING) && defined(DEBUG)
2315 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2316 ("nsDocShell[%p]: returns existing sessionStorage %p",
2322 // We are asked to create a new storage object. This indicates
2323 // that a new windows wants it. At this moment we "fork" the existing
2324 // storage object (what it means is described in the paragraph bellow).
2325 // We must create a single object per a single window to distinguish
2326 // a window originating oparations on the storage object to succesfully
2327 // prevent dispatch of a storage event to this same window that ivoked
2328 // a change in its storage. We also do this to correctly fill
2329 // documentURI property in the storage event.
2331 // The difference between clone and fork is that clone creates
2332 // a completelly new and independent storage, but fork only creates
2333 // a new object wrapping the storage implementation and data and
2334 // the forked storage then behaves completelly the same way as
2335 // the storage it has been forked of, all such forked storage objects
2336 // shares their state and data and change on one such object affects
2337 // all others the same way.
2338 nsCOMPtr
<nsPIDOMStorage
> piStorage
= do_QueryInterface(*aStorage
);
2339 nsCOMPtr
<nsIDOMStorage
> fork
= piStorage
->Fork(aDocumentURI
);
2340 #if defined(PR_LOGGING) && defined(DEBUG)
2341 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2342 ("nsDocShell[%p]: forked sessionStorage %p to %p",
2343 this, *aStorage
, fork
.get()));
2345 fork
.swap(*aStorage
);
2352 nsDocShell::GetSessionStorageForURI(nsIURI
* aURI
,
2353 const nsAString
& aDocumentURI
,
2354 nsIDOMStorage
** aStorage
)
2356 return GetSessionStorageForURI(aURI
, aDocumentURI
, PR_TRUE
, aStorage
);
2360 nsDocShell::GetSessionStorageForURI(nsIURI
* aURI
,
2361 const nsSubstring
& aDocumentURI
,
2363 nsIDOMStorage
** aStorage
)
2365 NS_ENSURE_ARG(aURI
);
2366 NS_ENSURE_ARG_POINTER(aStorage
);
2372 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
2373 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
2374 NS_ENSURE_SUCCESS(rv
, rv
);
2376 // This is terrible hack and should go away along with this whole method.
2377 nsCOMPtr
<nsIPrincipal
> principal
;
2378 rv
= securityManager
->GetCodebasePrincipal(aURI
, getter_AddRefs(principal
));
2382 return GetSessionStorageForPrincipal(principal
, aDocumentURI
, aCreate
, aStorage
);
2386 nsDocShell::AddSessionStorage(nsIPrincipal
* aPrincipal
,
2387 nsIDOMStorage
* aStorage
)
2389 NS_ENSURE_ARG_POINTER(aStorage
);
2394 nsCOMPtr
<nsIDocShellTreeItem
> topItem
;
2395 nsresult rv
= GetSameTypeRootTreeItem(getter_AddRefs(topItem
));
2400 nsCOMPtr
<nsIDocShell
> topDocShell
= do_QueryInterface(topItem
);
2401 if (topDocShell
== this) {
2402 nsCAutoString currentDomain
;
2403 rv
= GetPrincipalDomain(aPrincipal
, currentDomain
);
2407 if (currentDomain
.IsEmpty())
2408 return NS_ERROR_FAILURE
;
2410 // Do not replace an existing session storage.
2411 if (mStorages
.GetWeak(currentDomain
))
2412 return NS_ERROR_NOT_AVAILABLE
;
2414 #if defined(PR_LOGGING) && defined(DEBUG)
2415 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
2416 ("nsDocShell[%p]: was added a sessionStorage %p",
2419 if (!mStorages
.Put(currentDomain
, aStorage
))
2420 return NS_ERROR_OUT_OF_MEMORY
;
2423 return topDocShell
->AddSessionStorage(aPrincipal
, aStorage
);
2431 nsDocShell::GetCurrentDocumentChannel(nsIChannel
** aResult
)
2433 NS_IF_ADDREF(*aResult
= GetCurrentDocChannel());
2438 nsDocShell::GetCurrentDocChannel()
2440 if (mContentViewer
) {
2441 nsIDocument
* doc
= mContentViewer
->GetDocument();
2443 return doc
->GetChannel();
2449 //*****************************************************************************
2450 // nsDocShell::nsIDocShellTreeItem
2451 //*****************************************************************************
2454 nsDocShell::GetName(PRUnichar
** aName
)
2456 NS_ENSURE_ARG_POINTER(aName
);
2457 *aName
= ToNewUnicode(mName
);
2462 nsDocShell::SetName(const PRUnichar
* aName
)
2464 mName
= aName
; // this does a copy of aName
2469 nsDocShell::NameEquals(const PRUnichar
*aName
, PRBool
*_retval
)
2471 NS_ENSURE_ARG_POINTER(aName
);
2472 NS_ENSURE_ARG_POINTER(_retval
);
2473 *_retval
= mName
.Equals(aName
);
2478 nsDocShell::GetItemType(PRInt32
* aItemType
)
2480 NS_ENSURE_ARG_POINTER(aItemType
);
2482 *aItemType
= mItemType
;
2487 nsDocShell::SetItemType(PRInt32 aItemType
)
2489 NS_ENSURE_ARG((aItemType
== typeChrome
) || (typeContent
== aItemType
));
2491 // Only allow setting the type on root docshells. Those would be the ones
2492 // that have the docloader service as mParent or have no mParent at all.
2493 nsCOMPtr
<nsIDocumentLoader
> docLoaderService
=
2494 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID
);
2495 NS_ENSURE_TRUE(docLoaderService
, NS_ERROR_UNEXPECTED
);
2497 NS_ENSURE_STATE(!mParent
|| mParent
== docLoaderService
);
2499 mItemType
= aItemType
;
2501 // disable auth prompting for anything but content
2502 mAllowAuth
= mItemType
== typeContent
;
2504 nsRefPtr
<nsPresContext
> presContext
= nsnull
;
2505 GetPresContext(getter_AddRefs(presContext
));
2507 presContext
->InvalidateIsChromeCache();
2514 nsDocShell::GetParent(nsIDocShellTreeItem
** aParent
)
2519 CallQueryInterface(mParent
, aParent
);
2521 // Note that in the case when the parent is not an nsIDocShellTreeItem we
2522 // don't want to throw; we just want to return null.
2527 nsDocShell::SetDocLoaderParent(nsDocLoader
* aParent
)
2529 nsDocLoader::SetDocLoaderParent(aParent
);
2531 // Curse ambiguous nsISupports inheritance!
2532 nsISupports
* parent
= GetAsSupports(aParent
);
2534 // If parent is another docshell, we inherit all their flags for
2535 // allowing plugins, scripting etc.
2536 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(parent
));
2537 if (parentAsDocShell
)
2540 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowPlugins(&value
)))
2542 SetAllowPlugins(value
);
2544 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowJavascript(&value
)))
2546 SetAllowJavascript(value
);
2548 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowMetaRedirects(&value
)))
2550 SetAllowMetaRedirects(value
);
2552 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowSubframes(&value
)))
2554 SetAllowSubframes(value
);
2556 if (NS_SUCCEEDED(parentAsDocShell
->GetAllowImages(&value
)))
2558 SetAllowImages(value
);
2560 if (NS_SUCCEEDED(parentAsDocShell
->GetIsActive(&value
)))
2564 if (NS_FAILED(parentAsDocShell
->GetAllowDNSPrefetch(&value
))) {
2567 SetAllowDNSPrefetch(value
);
2570 nsCOMPtr
<nsIURIContentListener
> parentURIListener(do_GetInterface(parent
));
2571 if (parentURIListener
)
2572 mContentListener
->SetParentContentListener(parentURIListener
);
2577 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem
** aParent
)
2579 NS_ENSURE_ARG_POINTER(aParent
);
2582 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
2583 do_QueryInterface(GetAsSupports(mParent
));
2588 NS_ENSURE_SUCCESS(parent
->GetItemType(&parentType
), NS_ERROR_FAILURE
);
2590 if (parentType
== mItemType
) {
2591 parent
.swap(*aParent
);
2597 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
2599 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
2600 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
2602 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2603 NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent
)), NS_ERROR_FAILURE
);
2605 *aRootTreeItem
= parent
;
2606 NS_ENSURE_SUCCESS((*aRootTreeItem
)->GetParent(getter_AddRefs(parent
)),
2609 NS_ADDREF(*aRootTreeItem
);
2614 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem
** aRootTreeItem
)
2616 NS_ENSURE_ARG_POINTER(aRootTreeItem
);
2617 *aRootTreeItem
= static_cast<nsIDocShellTreeItem
*>(this);
2619 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2620 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent
)),
2623 *aRootTreeItem
= parent
;
2624 NS_ENSURE_SUCCESS((*aRootTreeItem
)->
2625 GetSameTypeParent(getter_AddRefs(parent
)),
2628 NS_ADDREF(*aRootTreeItem
);
2634 nsDocShell::CanAccessItem(nsIDocShellTreeItem
* aTargetItem
,
2635 nsIDocShellTreeItem
* aAccessingItem
,
2636 PRBool aConsiderOpener
)
2638 NS_PRECONDITION(aTargetItem
, "Must have target item!");
2640 if (!gValidateOrigin
|| !aAccessingItem
) {
2645 // XXXbz should we care if aAccessingItem or the document therein is
2646 // chrome? Should those get extra privileges?
2648 // For historical context, see:
2650 // Bug 13871: Prevent frameset spoofing
2651 // Bug 103638: Targets with same name in different windows open in wrong
2652 // window with javascript
2653 // Bug 408052: Adopt "ancestor" frame navigation policy
2655 // Now do a security check
2657 // Allow navigation if
2658 // 1) aAccessingItem can script aTargetItem or one of its ancestors in
2659 // the frame hierarchy or
2660 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
2661 // 3) aTargetItem is a top-level frame and aAccessingItem can target
2662 // its opener per rule (1) or (2).
2664 if (aTargetItem
== aAccessingItem
) {
2665 // A frame is allowed to navigate itself.
2669 nsCOMPtr
<nsIDocShellTreeItem
> accessingRoot
;
2670 aAccessingItem
->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot
));
2672 if (aTargetItem
== accessingRoot
) {
2673 // A frame can navigate its root.
2677 // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
2678 nsCOMPtr
<nsIDocShellTreeItem
> target
= aTargetItem
;
2680 if (ValidateOrigin(aAccessingItem
, target
)) {
2684 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
2685 target
->GetSameTypeParent(getter_AddRefs(parent
));
2686 parent
.swap(target
);
2689 nsCOMPtr
<nsIDocShellTreeItem
> targetRoot
;
2690 aTargetItem
->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot
));
2692 if (aTargetItem
!= targetRoot
) {
2693 // target is a subframe, not in accessor's frame hierarchy, and all its
2694 // ancestors have origins different from that of the accessor. Don't
2699 if (!aConsiderOpener
) {
2704 nsCOMPtr
<nsIDOMWindow
> targetWindow(do_GetInterface(aTargetItem
));
2705 nsCOMPtr
<nsIDOMWindowInternal
> targetInternal(do_QueryInterface(targetWindow
));
2706 if (!targetInternal
) {
2707 NS_ERROR("This should not happen, really");
2711 nsCOMPtr
<nsIDOMWindowInternal
> targetOpener
;
2712 targetInternal
->GetOpener(getter_AddRefs(targetOpener
));
2713 nsCOMPtr
<nsIWebNavigation
> openerWebNav(do_GetInterface(targetOpener
));
2714 nsCOMPtr
<nsIDocShellTreeItem
> openerItem(do_QueryInterface(openerWebNav
));
2720 return CanAccessItem(openerItem
, aAccessingItem
, PR_FALSE
);
2724 ItemIsActive(nsIDocShellTreeItem
*aItem
)
2726 nsCOMPtr
<nsIDOMWindow
> tmp(do_GetInterface(aItem
));
2727 nsCOMPtr
<nsIDOMWindowInternal
> window(do_QueryInterface(tmp
));
2732 if (NS_SUCCEEDED(window
->GetClosed(&isClosed
)) && !isClosed
) {
2741 nsDocShell::FindItemWithName(const PRUnichar
* aName
,
2742 nsISupports
* aRequestor
,
2743 nsIDocShellTreeItem
* aOriginalRequestor
,
2744 nsIDocShellTreeItem
** _retval
)
2746 NS_ENSURE_ARG(aName
);
2747 NS_ENSURE_ARG_POINTER(_retval
);
2749 // If we don't find one, we return NS_OK and a null result
2757 nsCOMPtr
<nsIDocShellTreeItem
> foundItem
;
2759 // This is the entry point into the target-finding algorithm. Check
2760 // for special names. This should only be done once, hence the check
2761 // for a null aRequestor.
2763 nsDependentString
name(aName
);
2764 if (name
.LowerCaseEqualsLiteral("_self")) {
2767 else if (name
.LowerCaseEqualsLiteral("_blank"))
2769 // Just return null. Caller must handle creating a new window with
2770 // a blank name himself.
2773 else if (name
.LowerCaseEqualsLiteral("_parent"))
2775 GetSameTypeParent(getter_AddRefs(foundItem
));
2779 else if (name
.LowerCaseEqualsLiteral("_top"))
2781 GetSameTypeRootTreeItem(getter_AddRefs(foundItem
));
2782 NS_ASSERTION(foundItem
, "Must have this; worst case it's us!");
2784 // _main is an IE target which should be case-insensitive but isn't
2785 // see bug 217886 for details
2786 else if (name
.LowerCaseEqualsLiteral("_content") ||
2787 name
.EqualsLiteral("_main"))
2789 // Must pass our same type root as requestor to the
2790 // treeowner to make sure things work right.
2791 nsCOMPtr
<nsIDocShellTreeItem
> root
;
2792 GetSameTypeRootTreeItem(getter_AddRefs(root
));
2794 NS_ASSERTION(root
, "Must have this; worst case it's us!");
2795 mTreeOwner
->FindItemWithName(aName
, root
, aOriginalRequestor
,
2796 getter_AddRefs(foundItem
));
2800 NS_ERROR("Someone isn't setting up the tree owner. "
2801 "You might like to try that. "
2802 "Things will.....you know, work.");
2803 // Note: _content should always exist. If we don't have one
2804 // hanging off the treeowner, just create a named window....
2805 // so don't return here, in case we did that and can now find
2807 // XXXbz should we be using |root| instead of creating
2813 if (foundItem
&& !CanAccessItem(foundItem
, aOriginalRequestor
)) {
2818 // We return foundItem here even if it's not an active
2819 // item since all the names we've dealt with so far are
2820 // special cases that we won't bother looking for further.
2822 foundItem
.swap(*_retval
);
2829 // First we check our name.
2830 if (mName
.Equals(aName
) && ItemIsActive(this) &&
2831 CanAccessItem(this, aOriginalRequestor
)) {
2832 NS_ADDREF(*_retval
= this);
2836 // This QI may fail, but the places where we want to compare, comparing
2837 // against nsnull serves the same purpose.
2838 nsCOMPtr
<nsIDocShellTreeItem
> reqAsTreeItem(do_QueryInterface(aRequestor
));
2840 // Second we check our children making sure not to ask a child if
2841 // it is the aRequestor.
2845 FindChildWithName(aName
, PR_TRUE
, PR_TRUE
, reqAsTreeItem
,
2846 aOriginalRequestor
, _retval
);
2847 NS_ASSERTION(NS_SUCCEEDED(rv
),
2848 "FindChildWithName should not be failing here.");
2852 // Third if we have a parent and it isn't the requestor then we
2853 // should ask it to do the search. If it is the requestor we
2854 // should just stop here and let the parent do the rest. If we
2855 // don't have a parent, then we should ask the
2856 // docShellTreeOwner to do the search.
2857 nsCOMPtr
<nsIDocShellTreeItem
> parentAsTreeItem
=
2858 do_QueryInterface(GetAsSupports(mParent
));
2859 if (parentAsTreeItem
) {
2860 if (parentAsTreeItem
== reqAsTreeItem
)
2864 parentAsTreeItem
->GetItemType(&parentType
);
2865 if (parentType
== mItemType
) {
2866 return parentAsTreeItem
->
2867 FindItemWithName(aName
,
2868 static_cast<nsIDocShellTreeItem
*>
2875 // If the parent is null or not of the same type fall through and ask tree
2878 // This may fail, but comparing against null serves the same purpose
2879 nsCOMPtr
<nsIDocShellTreeOwner
>
2880 reqAsTreeOwner(do_QueryInterface(aRequestor
));
2882 if (mTreeOwner
&& mTreeOwner
!= reqAsTreeOwner
) {
2884 FindItemWithName(aName
, this, aOriginalRequestor
, _retval
);
2891 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner
** aTreeOwner
)
2893 NS_ENSURE_ARG_POINTER(aTreeOwner
);
2895 *aTreeOwner
= mTreeOwner
;
2896 NS_IF_ADDREF(*aTreeOwner
);
2900 #ifdef DEBUG_DOCSHELL_FOCUS
2902 PrintDocTree(nsIDocShellTreeItem
* aParentNode
, int aLevel
)
2904 for (PRInt32 i
=0;i
<aLevel
;i
++) printf(" ");
2906 PRInt32 childWebshellCount
;
2907 aParentNode
->GetChildCount(&childWebshellCount
);
2908 nsCOMPtr
<nsIDocShell
> parentAsDocShell(do_QueryInterface(aParentNode
));
2910 aParentNode
->GetItemType(&type
);
2911 nsCOMPtr
<nsIPresShell
> presShell
;
2912 parentAsDocShell
->GetPresShell(getter_AddRefs(presShell
));
2913 nsRefPtr
<nsPresContext
> presContext
;
2914 parentAsDocShell
->GetPresContext(getter_AddRefs(presContext
));
2915 nsIDocument
*doc
= presShell
->GetDocument();
2917 nsCOMPtr
<nsIDOMWindowInternal
> domwin(doc
->GetWindow());
2919 nsCOMPtr
<nsIWidget
> widget
;
2920 nsIViewManager
* vm
= presShell
->GetViewManager();
2922 vm
->GetWidget(getter_AddRefs(widget
));
2924 dom::Element
* rootElement
= doc
->GetRootElement();
2926 printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
2927 (void*)parentAsDocShell
.get(),
2928 type
==nsIDocShellTreeItem::typeChrome
?"Chr":"Con",
2929 (void*)doc
, (void*)domwin
.get(),
2930 (void*)presContext
->EventStateManager(), (void*)rootElement
);
2932 if (childWebshellCount
> 0) {
2933 for (PRInt32 i
=0;i
<childWebshellCount
;i
++) {
2934 nsCOMPtr
<nsIDocShellTreeItem
> child
;
2935 aParentNode
->GetChildAt(i
, getter_AddRefs(child
));
2936 PrintDocTree(child
, aLevel
+1);
2942 PrintDocTree(nsIDocShellTreeItem
* aParentNode
)
2944 NS_ASSERTION(aParentNode
, "Pointer is null!");
2946 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
2947 aParentNode
->GetParent(getter_AddRefs(parentItem
));
2948 while (parentItem
) {
2949 nsCOMPtr
<nsIDocShellTreeItem
>tmp
;
2950 parentItem
->GetParent(getter_AddRefs(tmp
));
2958 parentItem
= aParentNode
;
2961 PrintDocTree(parentItem
, 0);
2966 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
)
2968 #ifdef DEBUG_DOCSHELL_FOCUS
2969 nsCOMPtr
<nsIDocShellTreeItem
> item(do_QueryInterface(aTreeOwner
));
2975 // Don't automatically set the progress based on the tree owner for frames
2977 nsCOMPtr
<nsIWebProgress
> webProgress
=
2978 do_QueryInterface(GetAsSupports(this));
2981 nsCOMPtr
<nsIWebProgressListener
>
2982 oldListener(do_QueryInterface(mTreeOwner
));
2983 nsCOMPtr
<nsIWebProgressListener
>
2984 newListener(do_QueryInterface(aTreeOwner
));
2987 webProgress
->RemoveProgressListener(oldListener
);
2991 webProgress
->AddProgressListener(newListener
,
2992 nsIWebProgress::NOTIFY_ALL
);
2997 mTreeOwner
= aTreeOwner
; // Weak reference per API
2999 PRInt32 i
, n
= mChildList
.Count();
3000 for (i
= 0; i
< n
; i
++) {
3001 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryInterface(ChildAt(i
));
3002 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
3003 PRInt32 childType
= ~mItemType
; // Set it to not us in case the get fails
3004 child
->GetItemType(&childType
); // We don't care if this fails, if it does we won't set the owner
3005 if (childType
== mItemType
)
3006 child
->SetTreeOwner(aTreeOwner
);
3013 nsDocShell::SetChildOffset(PRUint32 aChildOffset
)
3015 mChildOffset
= aChildOffset
;
3020 nsDocShell::GetHistoryID(PRUint64
* aID
)
3027 nsDocShell::GetIsInUnload(PRBool
* aIsInUnload
)
3029 *aIsInUnload
= mFiredUnloadEvent
;
3033 //*****************************************************************************
3034 // nsDocShell::nsIDocShellTreeNode
3035 //*****************************************************************************
3038 nsDocShell::GetChildCount(PRInt32
* aChildCount
)
3040 NS_ENSURE_ARG_POINTER(aChildCount
);
3041 *aChildCount
= mChildList
.Count();
3048 nsDocShell::AddChild(nsIDocShellTreeItem
* aChild
)
3050 NS_ENSURE_ARG_POINTER(aChild
);
3052 nsRefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
3053 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
3055 // Make sure we're not creating a loop in the docshell tree
3056 nsDocLoader
* ancestor
= this;
3058 if (childAsDocLoader
== ancestor
) {
3059 return NS_ERROR_ILLEGAL_VALUE
;
3061 ancestor
= ancestor
->GetParent();
3064 // Make sure to remove the child from its current parent.
3065 nsDocLoader
* childsParent
= childAsDocLoader
->GetParent();
3067 childsParent
->RemoveChildLoader(childAsDocLoader
);
3070 // Make sure to clear the treeowner in case this child is a different type
3072 aChild
->SetTreeOwner(nsnull
);
3074 nsresult res
= AddChildLoader(childAsDocLoader
);
3075 NS_ENSURE_SUCCESS(res
, res
);
3076 NS_ASSERTION(mChildList
.Count() > 0,
3077 "child list must not be empty after a successful add");
3079 nsCOMPtr
<nsIDocShellHistory
> docshellhistory
= do_QueryInterface(aChild
);
3080 PRBool dynamic
= PR_FALSE
;
3081 docshellhistory
->GetCreatedDynamically(&dynamic
);
3083 nsCOMPtr
<nsISHEntry
> currentSH
;
3084 PRBool oshe
= PR_FALSE
;
3085 GetCurrentSHEntry(getter_AddRefs(currentSH
), &oshe
);
3087 currentSH
->HasDynamicallyAddedChild(&dynamic
);
3090 nsCOMPtr
<nsIDocShell
> childDocShell
= do_QueryInterface(aChild
);
3091 childDocShell
->SetChildOffset(dynamic
? -1 : mChildList
.Count() - 1);
3093 /* Set the child's global history if the parent has one */
3094 if (mUseGlobalHistory
) {
3095 nsCOMPtr
<nsIDocShellHistory
>
3096 dsHistoryChild(do_QueryInterface(aChild
));
3098 dsHistoryChild
->SetUseGlobalHistory(PR_TRUE
);
3102 PRInt32 childType
= ~mItemType
; // Set it to not us in case the get fails
3103 aChild
->GetItemType(&childType
);
3104 if (childType
!= mItemType
)
3106 // Everything below here is only done when the child is the same type.
3109 aChild
->SetTreeOwner(mTreeOwner
);
3111 nsCOMPtr
<nsIDocShell
> childAsDocShell(do_QueryInterface(aChild
));
3112 if (!childAsDocShell
)
3115 // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3117 // Now take this document's charset and set the parentCharset field of the
3118 // child's DocumentCharsetInfo to it. We'll later use that field, in the
3119 // loading process, for the charset choosing algorithm.
3120 // If we fail, at any point, we just return NS_OK.
3121 // This code has some performance impact. But this will be reduced when
3122 // the current charset will finally be stored as an Atom, avoiding the
3123 // alias resolution extra look-up.
3125 // we are NOT going to propagate the charset is this Chrome's docshell
3126 if (mItemType
== nsIDocShellTreeItem::typeChrome
)
3129 // get the child's docCSInfo object
3130 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
= NULL
;
3131 res
= childAsDocShell
->GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
3132 if (NS_FAILED(res
) || (!dcInfo
))
3135 // get the parent's current charset
3136 if (!mContentViewer
)
3138 nsIDocument
* doc
= mContentViewer
->GetDocument();
3141 const nsACString
&parentCS
= doc
->GetDocumentCharacterSet();
3143 PRBool isWyciwyg
= PR_FALSE
;
3146 // Check if the url is wyciwyg
3147 mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
3151 // If this docshell is loaded from a wyciwyg: URI, don't
3152 // advertise our charset since it does not in any way reflect
3153 // the actual source charset, which is what we're trying to
3156 // set the child's parentCharset
3157 nsCOMPtr
<nsIAtom
> parentCSAtom(do_GetAtom(parentCS
));
3158 res
= dcInfo
->SetParentCharset(parentCSAtom
);
3162 PRInt32 charsetSource
= doc
->GetDocumentCharacterSetSource();
3164 // set the child's parentCharset
3165 res
= dcInfo
->SetParentCharsetSource(charsetSource
);
3170 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3176 nsDocShell::RemoveChild(nsIDocShellTreeItem
* aChild
)
3178 NS_ENSURE_ARG_POINTER(aChild
);
3180 nsRefPtr
<nsDocLoader
> childAsDocLoader
= GetAsDocLoader(aChild
);
3181 NS_ENSURE_TRUE(childAsDocLoader
, NS_ERROR_UNEXPECTED
);
3183 nsresult rv
= RemoveChildLoader(childAsDocLoader
);
3184 NS_ENSURE_SUCCESS(rv
, rv
);
3186 aChild
->SetTreeOwner(nsnull
);
3188 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader
);
3192 nsDocShell::GetChildAt(PRInt32 aIndex
, nsIDocShellTreeItem
** aChild
)
3194 NS_ENSURE_ARG_POINTER(aChild
);
3198 NS_WARNING("Negative index passed to GetChildAt");
3200 else if (aIndex
>= mChildList
.Count()) {
3201 NS_WARNING("Too large an index passed to GetChildAt");
3205 nsIDocumentLoader
* child
= SafeChildAt(aIndex
);
3206 NS_ENSURE_TRUE(child
, NS_ERROR_UNEXPECTED
);
3208 return CallQueryInterface(child
, aChild
);
3212 nsDocShell::FindChildWithName(const PRUnichar
* aName
,
3213 PRBool aRecurse
, PRBool aSameType
,
3214 nsIDocShellTreeItem
* aRequestor
,
3215 nsIDocShellTreeItem
* aOriginalRequestor
,
3216 nsIDocShellTreeItem
** _retval
)
3218 NS_ENSURE_ARG(aName
);
3219 NS_ENSURE_ARG_POINTER(_retval
);
3221 *_retval
= nsnull
; // if we don't find one, we return NS_OK and a null result
3226 nsXPIDLString childName
;
3227 PRInt32 i
, n
= mChildList
.Count();
3228 for (i
= 0; i
< n
; i
++) {
3229 nsCOMPtr
<nsIDocShellTreeItem
> child
= do_QueryInterface(ChildAt(i
));
3230 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
3232 child
->GetItemType(&childType
);
3234 if (aSameType
&& (childType
!= mItemType
))
3237 PRBool childNameEquals
= PR_FALSE
;
3238 child
->NameEquals(aName
, &childNameEquals
);
3239 if (childNameEquals
&& ItemIsActive(child
) &&
3240 CanAccessItem(child
, aOriginalRequestor
)) {
3241 child
.swap(*_retval
);
3245 if (childType
!= mItemType
) //Only ask it to check children if it is same type
3248 if (aRecurse
&& (aRequestor
!= child
)) // Only ask the child if it isn't the requestor
3250 // See if child contains the shell with the given name
3254 child
->FindChildWithName(aName
, PR_TRUE
,
3256 static_cast<nsIDocShellTreeItem
*>
3260 NS_ASSERTION(NS_SUCCEEDED(rv
),
3261 "FindChildWithName should not fail here");
3262 if (*_retval
) // found it
3269 //*****************************************************************************
3270 // nsDocShell::nsIDocShellHistory
3271 //*****************************************************************************
3273 nsDocShell::GetChildSHEntry(PRInt32 aChildOffset
, nsISHEntry
** aResult
)
3275 nsresult rv
= NS_OK
;
3277 NS_ENSURE_ARG_POINTER(aResult
);
3281 // A nsISHEntry for a child is *only* available when the parent is in
3282 // the progress of loading a document too...
3285 /* Before looking for the subframe's url, check
3286 * the expiration status of the parent. If the parent
3287 * has expired from cache, then subframes will not be
3288 * loaded from history in certain situations.
3290 PRBool parentExpired
=PR_FALSE
;
3291 mLSHE
->GetExpirationStatus(&parentExpired
);
3293 /* Get the parent's Load Type so that it can be set on the child too.
3294 * By default give a loadHistory value
3296 PRUint32 loadType
= nsIDocShellLoadInfo::loadHistory
;
3297 mLSHE
->GetLoadType(&loadType
);
3298 // If the user did a shift-reload on this frameset page,
3299 // we don't want to load the subframes from history.
3300 if (loadType
== nsIDocShellLoadInfo::loadReloadBypassCache
||
3301 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxy
||
3302 loadType
== nsIDocShellLoadInfo::loadReloadBypassProxyAndCache
||
3303 loadType
== nsIDocShellLoadInfo::loadRefresh
)
3306 /* If the user pressed reload and the parent frame has expired
3307 * from cache, we do not want to load the child frame from history.
3309 if (parentExpired
&& (loadType
== nsIDocShellLoadInfo::loadReloadNormal
)) {
3310 // The parent has expired. Return null.
3315 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
));
3317 // Get the child subframe from session history.
3318 rv
= container
->GetChildAt(aChildOffset
, aResult
);
3320 (*aResult
)->SetLoadType(loadType
);
3327 nsDocShell::AddChildSHEntry(nsISHEntry
* aCloneRef
, nsISHEntry
* aNewEntry
,
3328 PRInt32 aChildOffset
, PRUint32 loadType
)
3332 if (mLSHE
&& loadType
!= LOAD_PUSHSTATE
) {
3333 /* You get here if you are currently building a
3334 * hierarchy ie.,you just visited a frameset page
3336 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mLSHE
, &rv
));
3338 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
3341 else if (!aCloneRef
) {
3342 /* This is an initial load in some subframe. Just append it if we can */
3343 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(mOSHE
, &rv
));
3345 rv
= container
->AddChild(aNewEntry
, aChildOffset
);
3348 else if (mSessionHistory
) {
3349 /* You are currently in the rootDocShell.
3350 * You will get here when a subframe has a new url
3351 * to load and you have walked up the tree all the
3352 * way to the top to clone the current SHEntry hierarchy
3353 * and replace the subframe where a new url was loaded with
3357 nsCOMPtr
<nsIHistoryEntry
> currentHE
;
3358 mSessionHistory
->GetIndex(&index
);
3360 return NS_ERROR_FAILURE
;
3362 rv
= mSessionHistory
->GetEntryAtIndex(index
, PR_FALSE
,
3363 getter_AddRefs(currentHE
));
3364 NS_ENSURE_TRUE(currentHE
, NS_ERROR_FAILURE
);
3366 nsCOMPtr
<nsISHEntry
> currentEntry(do_QueryInterface(currentHE
));
3368 PRUint32 cloneID
= 0;
3369 nsCOMPtr
<nsISHEntry
> nextEntry
;
3370 aCloneRef
->GetID(&cloneID
);
3371 rv
= CloneAndReplace(currentEntry
, this, cloneID
, aNewEntry
,
3372 loadType
== LOAD_PUSHSTATE
,
3373 getter_AddRefs(nextEntry
));
3375 if (NS_SUCCEEDED(rv
)) {
3376 nsCOMPtr
<nsISHistoryInternal
>
3377 shPrivate(do_QueryInterface(mSessionHistory
));
3378 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
3379 rv
= shPrivate
->AddEntry(nextEntry
, PR_TRUE
);
3384 /* Just pass this along */
3385 nsCOMPtr
<nsIDocShellHistory
> parent
=
3386 do_QueryInterface(GetAsSupports(mParent
), &rv
);
3388 rv
= parent
->AddChildSHEntry(aCloneRef
, aNewEntry
, aChildOffset
,
3396 nsDocShell::DoAddChildSHEntry(nsISHEntry
* aNewEntry
, PRInt32 aChildOffset
)
3398 /* You will get here when you are in a subframe and
3399 * a new url has been loaded on you.
3400 * The mOSHE in this subframe will be the previous url's
3401 * mOSHE. This mOSHE will be used as the identification
3402 * for this subframe in the CloneAndReplace function.
3405 // In this case, we will end up calling AddEntry, which increases the
3406 // current index by 1
3407 nsCOMPtr
<nsISHistory
> rootSH
;
3408 GetRootSessionHistory(getter_AddRefs(rootSH
));
3410 rootSH
->GetIndex(&mPreviousTransIndex
);
3414 nsCOMPtr
<nsIDocShellHistory
> parent
=
3415 do_QueryInterface(GetAsSupports(mParent
), &rv
);
3417 rv
= parent
->AddChildSHEntry(mOSHE
, aNewEntry
, aChildOffset
, mLoadType
);
3422 rootSH
->GetIndex(&mLoadedTransIndex
);
3423 #ifdef DEBUG_PAGE_CACHE
3424 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
3433 nsDocShell::SetUseGlobalHistory(PRBool aUseGlobalHistory
)
3437 mUseGlobalHistory
= aUseGlobalHistory
;
3439 if (!aUseGlobalHistory
) {
3440 mGlobalHistory
= nsnull
;
3444 // No need to initialize mGlobalHistory if IHistory is available.
3445 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
3450 if (mGlobalHistory
) {
3454 mGlobalHistory
= do_GetService(NS_GLOBALHISTORY2_CONTRACTID
, &rv
);
3459 nsDocShell::GetUseGlobalHistory(PRBool
*aUseGlobalHistory
)
3461 *aUseGlobalHistory
= mUseGlobalHistory
;
3466 nsDocShell::RemoveFromSessionHistory()
3468 nsCOMPtr
<nsISHistoryInternal
> internalHistory
;
3469 nsCOMPtr
<nsISHistory
> sessionHistory
;
3470 nsCOMPtr
<nsIDocShellTreeItem
> root
;
3471 GetSameTypeRootTreeItem(getter_AddRefs(root
));
3473 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav
=
3474 do_QueryInterface(root
);
3476 rootAsWebnav
->GetSessionHistory(getter_AddRefs(sessionHistory
));
3477 internalHistory
= do_QueryInterface(sessionHistory
);
3480 if (!internalHistory
) {
3485 sessionHistory
->GetIndex(&index
);
3486 nsAutoTArray
<PRUint64
, 16> ids
;
3487 ids
.AppendElement(mHistoryID
);
3488 internalHistory
->RemoveEntries(ids
, index
);
3493 nsDocShell::SetCreatedDynamically(PRBool aDynamic
)
3495 mDynamicallyCreated
= aDynamic
;
3500 nsDocShell::GetCreatedDynamically(PRBool
* aDynamic
)
3502 *aDynamic
= mDynamicallyCreated
;
3507 nsDocShell::GetCurrentSHEntry(nsISHEntry
** aEntry
, PRBool
* aOSHE
)
3512 NS_ADDREF(*aEntry
= mLSHE
);
3514 NS_ADDREF(*aEntry
= mOSHE
);
3521 nsDocShell::ClearFrameHistory(nsISHEntry
* aEntry
)
3523 nsCOMPtr
<nsISHContainer
> shcontainer
= do_QueryInterface(aEntry
);
3524 nsCOMPtr
<nsISHistory
> rootSH
;
3525 GetRootSessionHistory(getter_AddRefs(rootSH
));
3526 nsCOMPtr
<nsISHistoryInternal
> history
= do_QueryInterface(rootSH
);
3527 if (!history
|| !shcontainer
) {
3532 shcontainer
->GetChildCount(&count
);
3533 nsAutoTArray
<PRUint64
, 16> ids
;
3534 for (PRInt32 i
= 0; i
< count
; ++i
) {
3535 nsCOMPtr
<nsISHEntry
> child
;
3536 shcontainer
->GetChildAt(i
, getter_AddRefs(child
));
3539 child
->GetDocshellID(&id
);
3540 ids
.AppendElement(id
);
3544 rootSH
->GetIndex(&index
);
3545 history
->RemoveEntries(ids
, index
);
3548 //-------------------------------------
3549 //-- Helper Method for Print discovery
3550 //-------------------------------------
3552 nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog
)
3554 if (mIsPrintingOrPP
&& aDisplayErrorDialog
) {
3555 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE
, nsnull
, nsnull
);
3558 return mIsPrintingOrPP
;
3562 nsDocShell::IsNavigationAllowed(PRBool aDisplayPrintErrorDialog
)
3564 return !IsPrintingOrPP(aDisplayPrintErrorDialog
) && !mFiredUnloadEvent
;
3567 //*****************************************************************************
3568 // nsDocShell::nsIWebNavigation
3569 //*****************************************************************************
3572 nsDocShell::GetCanGoBack(PRBool
* aCanGoBack
)
3574 if (!IsNavigationAllowed(PR_FALSE
)) {
3575 *aCanGoBack
= PR_FALSE
;
3576 return NS_OK
; // JS may not handle returning of an error code
3579 nsCOMPtr
<nsISHistory
> rootSH
;
3580 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3581 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3582 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3583 rv
= webnav
->GetCanGoBack(aCanGoBack
);
3589 nsDocShell::GetCanGoForward(PRBool
* aCanGoForward
)
3591 if (!IsNavigationAllowed(PR_FALSE
)) {
3592 *aCanGoForward
= PR_FALSE
;
3593 return NS_OK
; // JS may not handle returning of an error code
3596 nsCOMPtr
<nsISHistory
> rootSH
;
3597 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3598 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3599 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3600 rv
= webnav
->GetCanGoForward(aCanGoForward
);
3606 nsDocShell::GoBack()
3608 if (!IsNavigationAllowed()) {
3609 return NS_OK
; // JS may not handle returning of an error code
3612 nsCOMPtr
<nsISHistory
> rootSH
;
3613 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3614 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3615 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3616 rv
= webnav
->GoBack();
3622 nsDocShell::GoForward()
3624 if (!IsNavigationAllowed()) {
3625 return NS_OK
; // JS may not handle returning of an error code
3628 nsCOMPtr
<nsISHistory
> rootSH
;
3629 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3630 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3631 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3632 rv
= webnav
->GoForward();
3637 NS_IMETHODIMP
nsDocShell::GotoIndex(PRInt32 aIndex
)
3639 if (!IsNavigationAllowed()) {
3640 return NS_OK
; // JS may not handle returning of an error code
3643 nsCOMPtr
<nsISHistory
> rootSH
;
3644 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
3645 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(rootSH
));
3646 NS_ENSURE_TRUE(webnav
, NS_ERROR_FAILURE
);
3647 rv
= webnav
->GotoIndex(aIndex
);
3653 nsDocShell::LoadURI(const PRUnichar
* aURI
,
3654 PRUint32 aLoadFlags
,
3655 nsIURI
* aReferringURI
,
3656 nsIInputStream
* aPostStream
,
3657 nsIInputStream
* aHeaderStream
)
3659 NS_ASSERTION((aLoadFlags
& 0xf) == 0, "Unexpected flags");
3661 if (!IsNavigationAllowed()) {
3662 return NS_OK
; // JS may not handle returning of an error code
3664 nsCOMPtr
<nsIURI
> uri
;
3665 nsresult rv
= NS_OK
;
3667 // Create a URI from our string; if that succeeds, we want to
3668 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
3671 NS_ConvertUTF16toUTF8
uriString(aURI
);
3672 // Cleanup the empty spaces that might be on each end.
3673 uriString
.Trim(" ");
3674 // Eliminate embedded newlines, which single-line text fields now allow:
3675 uriString
.StripChars("\r\n");
3676 NS_ENSURE_TRUE(!uriString
.IsEmpty(), NS_ERROR_FAILURE
);
3678 rv
= NS_NewURI(getter_AddRefs(uri
), uriString
);
3680 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
;
3684 // Call the fixup object. This will clobber the rv from NS_NewURI
3685 // above, but that's fine with us. Note that we need to do this even
3686 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
3687 // (things like view-source:mozilla.org for example).
3688 PRUint32 fixupFlags
= 0;
3689 if (aLoadFlags
& LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) {
3690 fixupFlags
|= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
;
3692 rv
= sURIFixup
->CreateFixupURI(uriString
, fixupFlags
,
3693 getter_AddRefs(uri
));
3695 // else no fixup service so just use the URI we created and see
3698 if (NS_ERROR_MALFORMED_URI
== rv
) {
3699 DisplayLoadError(rv
, uri
, aURI
);
3702 if (NS_FAILED(rv
) || !uri
)
3703 return NS_ERROR_FAILURE
;
3705 PopupControlState popupState
;
3706 if (aLoadFlags
& LOAD_FLAGS_ALLOW_POPUPS
) {
3707 popupState
= openAllowed
;
3708 aLoadFlags
&= ~LOAD_FLAGS_ALLOW_POPUPS
;
3710 popupState
= openOverridden
;
3712 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
3713 nsAutoPopupStatePusher
statePusher(win
, popupState
);
3715 // Don't pass certain flags that aren't needed and end up confusing
3716 // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
3717 // passed to LoadURI though, since it uses them.
3718 PRUint32 extraFlags
= (aLoadFlags
& EXTRA_LOAD_FLAGS
);
3719 aLoadFlags
&= ~EXTRA_LOAD_FLAGS
;
3721 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
3722 rv
= CreateLoadInfo(getter_AddRefs(loadInfo
));
3723 if (NS_FAILED(rv
)) return rv
;
3725 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_NORMAL
, aLoadFlags
);
3726 loadInfo
->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType
));
3727 loadInfo
->SetPostDataStream(aPostStream
);
3728 loadInfo
->SetReferrer(aReferringURI
);
3729 loadInfo
->SetHeadersStream(aHeaderStream
);
3731 rv
= LoadURI(uri
, loadInfo
, extraFlags
, PR_TRUE
);
3737 nsDocShell::DisplayLoadError(nsresult aError
, nsIURI
*aURI
,
3738 const PRUnichar
*aURL
,
3739 nsIChannel
* aFailedChannel
)
3741 // Get prompt and string bundle servcies
3742 nsCOMPtr
<nsIPrompt
> prompter
;
3743 nsCOMPtr
<nsIStringBundle
> stringBundle
;
3744 GetPromptAndStringBundle(getter_AddRefs(prompter
),
3745 getter_AddRefs(stringBundle
));
3747 NS_ENSURE_TRUE(stringBundle
, NS_ERROR_FAILURE
);
3748 NS_ENSURE_TRUE(prompter
, NS_ERROR_FAILURE
);
3751 const PRUint32 kMaxFormatStrArgs
= 3;
3752 nsAutoString formatStrs
[kMaxFormatStrArgs
];
3753 PRUint32 formatStrCount
= 0;
3754 PRBool addHostPort
= PR_FALSE
;
3755 nsresult rv
= NS_OK
;
3756 nsAutoString messageStr
;
3757 nsCAutoString cssClass
;
3758 nsCAutoString errorPage
;
3760 errorPage
.AssignLiteral("neterror");
3762 // Turn the error code into a human readable error message.
3763 if (NS_ERROR_UNKNOWN_PROTOCOL
== aError
) {
3764 NS_ENSURE_ARG_POINTER(aURI
);
3765 // extract the scheme
3766 nsCAutoString scheme
;
3767 aURI
->GetScheme(scheme
);
3768 CopyASCIItoUTF16(scheme
, formatStrs
[0]);
3770 error
.AssignLiteral("protocolNotFound");
3772 else if (NS_ERROR_FILE_NOT_FOUND
== aError
) {
3773 NS_ENSURE_ARG_POINTER(aURI
);
3774 error
.AssignLiteral("fileNotFound");
3776 else if (NS_ERROR_UNKNOWN_HOST
== aError
) {
3777 NS_ENSURE_ARG_POINTER(aURI
);
3780 nsCOMPtr
<nsIURI
> innermostURI
= NS_GetInnermostURI(aURI
);
3781 innermostURI
->GetHost(host
);
3782 CopyUTF8toUTF16(host
, formatStrs
[0]);
3784 error
.AssignLiteral("dnsNotFound");
3786 else if(NS_ERROR_CONNECTION_REFUSED
== aError
) {
3787 NS_ENSURE_ARG_POINTER(aURI
);
3788 addHostPort
= PR_TRUE
;
3789 error
.AssignLiteral("connectionFailure");
3791 else if(NS_ERROR_NET_INTERRUPT
== aError
) {
3792 NS_ENSURE_ARG_POINTER(aURI
);
3793 addHostPort
= PR_TRUE
;
3794 error
.AssignLiteral("netInterrupt");
3796 else if (NS_ERROR_NET_TIMEOUT
== aError
) {
3797 NS_ENSURE_ARG_POINTER(aURI
);
3800 aURI
->GetHost(host
);
3801 CopyUTF8toUTF16(host
, formatStrs
[0]);
3803 error
.AssignLiteral("netTimeout");
3805 else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION
== aError
) {
3807 cssClass
.AssignLiteral("neterror");
3808 error
.AssignLiteral("cspFrameAncestorBlocked");
3810 else if (NS_ERROR_GET_MODULE(aError
) == NS_ERROR_MODULE_SECURITY
) {
3811 nsCOMPtr
<nsINSSErrorsService
> nsserr
=
3812 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID
);
3814 PRUint32 errorClass
;
3816 NS_FAILED(nsserr
->GetErrorClass(aError
, &errorClass
))) {
3817 errorClass
= nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL
;
3820 nsCOMPtr
<nsISupports
> securityInfo
;
3821 nsCOMPtr
<nsITransportSecurityInfo
> tsi
;
3823 aFailedChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
3824 tsi
= do_QueryInterface(securityInfo
);
3826 // Usually we should have aFailedChannel and get a detailed message
3827 tsi
->GetErrorMessage(getter_Copies(messageStr
));
3830 // No channel, let's obtain the generic error message
3832 nsserr
->GetErrorMessage(aError
, messageStr
);
3835 if (!messageStr
.IsEmpty()) {
3836 if (errorClass
== nsINSSErrorsService::ERROR_CLASS_BAD_CERT
) {
3837 error
.AssignLiteral("nssBadCert");
3839 // if this is a Strict-Transport-Security host and the cert
3840 // is bad, don't allow overrides (STS Spec section 7.3).
3841 nsCOMPtr
<nsIStrictTransportSecurityService
> stss
=
3842 do_GetService(NS_STSSERVICE_CONTRACTID
, &rv
);
3843 NS_ENSURE_SUCCESS(rv
, rv
);
3845 PRBool isStsHost
= PR_FALSE
;
3846 rv
= stss
->IsStsURI(aURI
, &isStsHost
);
3847 NS_ENSURE_SUCCESS(rv
, rv
);
3850 cssClass
.AssignLiteral("badStsCert");
3852 PRBool expert
= PR_FALSE
;
3853 mPrefs
->GetBoolPref("browser.xul.error_pages.expert_bad_cert",
3856 cssClass
.AssignLiteral("expertBadCert");
3859 // See if an alternate cert error page is registered
3860 nsXPIDLCString alternateErrorPage
;
3861 mPrefs
->GetCharPref("security.alternate_certificate_error_page",
3862 getter_Copies(alternateErrorPage
));
3863 if (alternateErrorPage
)
3864 errorPage
.Assign(alternateErrorPage
);
3866 error
.AssignLiteral("nssFailure2");
3869 } else if (NS_ERROR_PHISHING_URI
== aError
|| NS_ERROR_MALWARE_URI
== aError
) {
3871 aURI
->GetHost(host
);
3872 CopyUTF8toUTF16(host
, formatStrs
[0]);
3875 // Malware and phishing detectors may want to use an alternate error
3876 // page, but if the pref's not set, we'll fall back on the standard page
3877 nsXPIDLCString alternateErrorPage
;
3878 mPrefs
->GetCharPref("urlclassifier.alternate_error_page",
3879 getter_Copies(alternateErrorPage
));
3880 if (alternateErrorPage
)
3881 errorPage
.Assign(alternateErrorPage
);
3883 if (NS_ERROR_PHISHING_URI
== aError
)
3884 error
.AssignLiteral("phishingBlocked");
3886 error
.AssignLiteral("malwareBlocked");
3887 cssClass
.AssignLiteral("blacklist");
3890 // Errors requiring simple formatting
3892 case NS_ERROR_MALFORMED_URI
:
3894 error
.AssignLiteral("malformedURI");
3896 case NS_ERROR_REDIRECT_LOOP
:
3897 // Doc failed to load because the server generated too many redirects
3898 error
.AssignLiteral("redirectLoop");
3900 case NS_ERROR_UNKNOWN_SOCKET_TYPE
:
3901 // Doc failed to load because PSM is not installed
3902 error
.AssignLiteral("unknownSocketType");
3904 case NS_ERROR_NET_RESET
:
3905 // Doc failed to load because the server kept reseting the connection
3906 // before we could read any data from it
3907 error
.AssignLiteral("netReset");
3909 case NS_ERROR_DOCUMENT_NOT_CACHED
:
3910 // Doc failed to load because we are offline and the cache does not
3911 // contain a copy of the document.
3912 error
.AssignLiteral("netOffline");
3914 case NS_ERROR_DOCUMENT_IS_PRINTMODE
:
3915 // Doc navigation attempted while Printing or Print Preview
3916 error
.AssignLiteral("isprinting");
3918 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED
:
3919 // Port blocked for security reasons
3920 addHostPort
= PR_TRUE
;
3921 error
.AssignLiteral("deniedPortAccess");
3923 case NS_ERROR_UNKNOWN_PROXY_HOST
:
3924 // Proxy hostname could not be resolved.
3925 error
.AssignLiteral("proxyResolveFailure");
3927 case NS_ERROR_PROXY_CONNECTION_REFUSED
:
3928 // Proxy connection was refused.
3929 error
.AssignLiteral("proxyConnectFailure");
3931 case NS_ERROR_INVALID_CONTENT_ENCODING
:
3932 // Bad Content Encoding.
3933 error
.AssignLiteral("contentEncodingError");
3935 case NS_ERROR_REMOTE_XUL
:
3937 error
.AssignLiteral("remoteXUL");
3940 * We want to set an hardcoded messageStr which uses the
3943 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
3944 mozilla::services::GetStringBundleService();
3945 if (!stringBundleService
) {
3946 return NS_ERROR_FAILURE
;
3949 nsCOMPtr
<nsIStringBundle
> brandBundle
;
3950 rv
= stringBundleService
->CreateBundle(kBrandBundleURL
,
3951 getter_AddRefs(brandBundle
));
3952 NS_ENSURE_SUCCESS(rv
, rv
);
3954 nsXPIDLString brandName
;
3955 rv
= brandBundle
->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
3956 getter_Copies(brandName
));
3958 // We could use something like nsTextFormatter::smprintf.
3959 messageStr
.AssignLiteral("This page uses an unsupported technology "
3960 "that is no longer available by default in ");
3961 messageStr
.Append(brandName
);
3962 messageStr
.AppendLiteral(".");
3965 case NS_ERROR_UNSAFE_CONTENT_TYPE
:
3966 // Channel refused to load from an unrecognized content type.
3967 error
.AssignLiteral("unsafeContentType");
3972 // Test if the error should be displayed
3973 if (error
.IsEmpty()) {
3977 // Test if the error needs to be formatted
3978 if (!messageStr
.IsEmpty()) {
3979 // already obtained message
3983 // Build up the host:port string.
3984 nsCAutoString hostport
;
3986 aURI
->GetHostPort(hostport
);
3988 hostport
.AssignLiteral("?");
3990 CopyUTF8toUTF16(hostport
, formatStrs
[formatStrCount
++]);
3994 rv
= NS_ERROR_NOT_AVAILABLE
;
3996 // displaying "file://" is aesthetically unpleasing and could even be
3997 // confusing to the user
3998 PRBool isFileURI
= PR_FALSE
;
3999 rv
= aURI
->SchemeIs("file", &isFileURI
);
4000 if (NS_SUCCEEDED(rv
) && isFileURI
)
4001 aURI
->GetPath(spec
);
4003 aURI
->GetSpec(spec
);
4005 nsCAutoString charset
;
4006 // unescape and convert from origin charset
4007 aURI
->GetOriginCharset(charset
);
4008 nsCOMPtr
<nsITextToSubURI
> textToSubURI(
4009 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
));
4010 if (NS_SUCCEEDED(rv
)) {
4011 rv
= textToSubURI
->UnEscapeURIForUI(charset
, spec
, formatStrs
[formatStrCount
]);
4014 spec
.AssignLiteral("?");
4017 CopyUTF8toUTF16(spec
, formatStrs
[formatStrCount
]);
4021 const PRUnichar
*strs
[kMaxFormatStrArgs
];
4022 for (PRUint32 i
= 0; i
< formatStrCount
; i
++) {
4023 strs
[i
] = formatStrs
[i
].get();
4026 rv
= stringBundle
->FormatStringFromName(
4028 strs
, formatStrCount
, getter_Copies(str
));
4029 NS_ENSURE_SUCCESS(rv
, rv
);
4030 messageStr
.Assign(str
.get());
4033 // Display the error as a page or an alert prompt
4034 NS_ENSURE_FALSE(messageStr
.IsEmpty(), NS_ERROR_FAILURE
);
4035 // Note: For now, display an alert instead of an error page if we have no
4036 // URI object. Missing URI objects are handled badly by session history.
4037 if (mUseErrorPages
&& aURI
&& aFailedChannel
) {
4038 // Display an error page
4039 LoadErrorPage(aURI
, aURL
, errorPage
.get(), error
.get(),
4040 messageStr
.get(), cssClass
.get(), aFailedChannel
);
4044 // The prompter reqires that our private window has a document (or it
4045 // asserts). Satisfy that assertion now since GetDocument will force
4046 // creation of one if it hasn't already been created.
4047 nsCOMPtr
<nsPIDOMWindow
> pwin(do_QueryInterface(mScriptGlobal
));
4049 nsCOMPtr
<nsIDOMDocument
> doc
;
4050 pwin
->GetDocument(getter_AddRefs(doc
));
4053 // Display a message box
4054 prompter
->Alert(nsnull
, messageStr
.get());
4062 nsDocShell::LoadErrorPage(nsIURI
*aURI
, const PRUnichar
*aURL
,
4063 const char *aErrorPage
,
4064 const PRUnichar
*aErrorType
,
4065 const PRUnichar
*aDescription
,
4066 const char *aCSSClass
,
4067 nsIChannel
* aFailedChannel
)
4069 #if defined(PR_LOGGING) && defined(DEBUG)
4070 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
4072 aURI
->GetSpec(spec
);
4074 nsCAutoString chanName
;
4076 aFailedChannel
->GetName(chanName
);
4078 chanName
.AssignLiteral("<no channel>");
4080 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
4081 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
4082 spec
.get(), NS_ConvertUTF16toUTF8(aURL
).get(), chanName
.get()));
4085 mFailedChannel
= aFailedChannel
;
4087 mFailedLoadType
= mLoadType
;
4090 // If we don't give mLSHE a new doc identifier here, when we go back or
4091 // forward to another SHEntry with the same doc identifier, the error
4092 // page will persist.
4093 mLSHE
->SetUniqueDocIdentifier();
4097 nsCAutoString charset
;
4100 nsresult rv
= aURI
->GetSpec(url
);
4101 rv
|= aURI
->GetOriginCharset(charset
);
4102 NS_ENSURE_SUCCESS(rv
, rv
);
4106 CopyUTF16toUTF8(aURL
, url
);
4110 return NS_ERROR_INVALID_POINTER
;
4113 // Create a URL to pass all the error information through to the page.
4116 #define SAFE_ESCAPE(cstring, escArg1, escArg2) \
4118 char* s = nsEscape(escArg1, escArg2); \
4120 return NS_ERROR_OUT_OF_MEMORY; \
4123 nsCString escapedUrl
, escapedCharset
, escapedError
, escapedDescription
,
4125 SAFE_ESCAPE(escapedUrl
, url
.get(), url_Path
);
4126 SAFE_ESCAPE(escapedCharset
, charset
.get(), url_Path
);
4127 SAFE_ESCAPE(escapedError
,
4128 NS_ConvertUTF16toUTF8(aErrorType
).get(), url_Path
);
4129 SAFE_ESCAPE(escapedDescription
,
4130 NS_ConvertUTF16toUTF8(aDescription
).get(), url_Path
);
4132 SAFE_ESCAPE(escapedCSSClass
, aCSSClass
, url_Path
);
4134 nsCString
errorPageUrl("about:");
4135 errorPageUrl
.AppendASCII(aErrorPage
);
4136 errorPageUrl
.AppendLiteral("?e=");
4138 errorPageUrl
.AppendASCII(escapedError
.get());
4139 errorPageUrl
.AppendLiteral("&u=");
4140 errorPageUrl
.AppendASCII(escapedUrl
.get());
4141 if (!escapedCSSClass
.IsEmpty()) {
4142 errorPageUrl
.AppendASCII("&s=");
4143 errorPageUrl
.AppendASCII(escapedCSSClass
.get());
4145 errorPageUrl
.AppendLiteral("&c=");
4146 errorPageUrl
.AppendASCII(escapedCharset
.get());
4147 errorPageUrl
.AppendLiteral("&d=");
4148 errorPageUrl
.AppendASCII(escapedDescription
.get());
4150 nsCOMPtr
<nsIURI
> errorPageURI
;
4151 nsresult rv
= NS_NewURI(getter_AddRefs(errorPageURI
), errorPageUrl
);
4152 NS_ENSURE_SUCCESS(rv
, rv
);
4154 return InternalLoad(errorPageURI
, nsnull
, nsnull
,
4155 INTERNAL_LOAD_FLAGS_INHERIT_OWNER
, nsnull
, nsnull
,
4156 nsnull
, nsnull
, LOAD_ERROR_PAGE
,
4157 nsnull
, PR_TRUE
, nsnull
, nsnull
);
4162 nsDocShell::Reload(PRUint32 aReloadFlags
)
4164 if (!IsNavigationAllowed()) {
4165 return NS_OK
; // JS may not handle returning of an error code
4168 NS_ASSERTION(((aReloadFlags
& 0xf) == 0),
4169 "Reload command not updated to use load flags!");
4170 NS_ASSERTION((aReloadFlags
& EXTRA_LOAD_FLAGS
) == 0,
4171 "Don't pass these flags to Reload");
4173 PRUint32 loadType
= MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL
, aReloadFlags
);
4174 NS_ENSURE_TRUE(IsValidLoadType(loadType
), NS_ERROR_INVALID_ARG
);
4176 // Send notifications to the HistoryListener if any, about the impending reload
4177 nsCOMPtr
<nsISHistory
> rootSH
;
4178 rv
= GetRootSessionHistory(getter_AddRefs(rootSH
));
4179 nsCOMPtr
<nsISHistoryInternal
> shistInt(do_QueryInterface(rootSH
));
4180 PRBool canReload
= PR_TRUE
;
4182 nsCOMPtr
<nsISHistoryListener
> listener
;
4183 shistInt
->GetListener(getter_AddRefs(listener
));
4185 listener
->OnHistoryReload(mCurrentURI
, aReloadFlags
, &canReload
);
4192 /* If you change this part of code, make sure bug 45297 does not re-occur */
4194 rv
= LoadHistoryEntry(mOSHE
, loadType
);
4196 else if (mLSHE
) { // In case a reload happened before the current load is done
4197 rv
= LoadHistoryEntry(mLSHE
, loadType
);
4200 nsCOMPtr
<nsIDocument
> doc(do_GetInterface(GetAsSupports(this)));
4202 nsIPrincipal
* principal
= nsnull
;
4203 nsAutoString contentTypeHint
;
4205 principal
= doc
->NodePrincipal();
4206 doc
->GetContentType(contentTypeHint
);
4209 rv
= InternalLoad(mCurrentURI
,
4212 INTERNAL_LOAD_FLAGS_NONE
, // Do not inherit owner from document
4213 nsnull
, // No window target
4214 NS_LossyConvertUTF16toASCII(contentTypeHint
).get(),
4215 nsnull
, // No post data
4216 nsnull
, // No headers data
4217 loadType
, // Load type
4218 nsnull
, // No SHEntry
4220 nsnull
, // No nsIDocShell
4221 nsnull
); // No nsIRequest
4229 nsDocShell::Stop(PRUint32 aStopFlags
)
4231 // Revoke any pending event related to content viewer restoration
4232 mRestorePresentationEvent
.Revoke();
4234 if (mLoadType
== LOAD_ERROR_PAGE
) {
4236 // Since error page loads never unset mLSHE, do so now
4237 SetHistoryEntry(&mOSHE
, mLSHE
);
4238 SetHistoryEntry(&mLSHE
, nsnull
);
4241 mFailedChannel
= nsnull
;
4242 mFailedURI
= nsnull
;
4245 if (nsIWebNavigation::STOP_CONTENT
& aStopFlags
) {
4246 // Stop the document loading
4248 mContentViewer
->Stop();
4251 if (nsIWebNavigation::STOP_NETWORK
& aStopFlags
) {
4252 // Suspend any timers that were set for this loader. We'll clear
4253 // them out for good in CreateContentViewer.
4254 if (mRefreshURIList
) {
4255 SuspendRefreshURIs();
4256 mSavedRefreshURIList
.swap(mRefreshURIList
);
4257 mRefreshURIList
= nsnull
;
4260 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
4261 // just call Stop() on us as an nsIDocumentLoader... We need fewer
4267 PRInt32 count
= mChildList
.Count();
4268 for (n
= 0; n
< count
; n
++) {
4269 nsCOMPtr
<nsIWebNavigation
> shellAsNav(do_QueryInterface(ChildAt(n
)));
4271 shellAsNav
->Stop(aStopFlags
);
4278 nsDocShell::GetDocument(nsIDOMDocument
** aDocument
)
4280 NS_ENSURE_ARG_POINTER(aDocument
);
4281 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE
);
4283 return mContentViewer
->GetDOMDocument(aDocument
);
4287 nsDocShell::GetCurrentURI(nsIURI
** aURI
)
4289 NS_ENSURE_ARG_POINTER(aURI
);
4292 return NS_EnsureSafeToReturn(mCurrentURI
, aURI
);
4300 nsDocShell::GetReferringURI(nsIURI
** aURI
)
4302 NS_ENSURE_ARG_POINTER(aURI
);
4304 *aURI
= mReferrerURI
;
4305 NS_IF_ADDREF(*aURI
);
4311 nsDocShell::SetSessionHistory(nsISHistory
* aSessionHistory
)
4314 NS_ENSURE_TRUE(aSessionHistory
, NS_ERROR_FAILURE
);
4315 // make sure that we are the root docshell and
4316 // set a handle to root docshell in SH.
4318 nsCOMPtr
<nsIDocShellTreeItem
> root
;
4319 /* Get the root docshell. If *this* is the root docshell
4320 * then save a handle to *this* in SH. SH needs it to do
4321 * traversions thro' its entries
4323 GetSameTypeRootTreeItem(getter_AddRefs(root
));
4324 NS_ENSURE_TRUE(root
, NS_ERROR_FAILURE
);
4325 if (root
.get() == static_cast<nsIDocShellTreeItem
*>(this)) {
4326 mSessionHistory
= aSessionHistory
;
4327 nsCOMPtr
<nsISHistoryInternal
>
4328 shPrivate(do_QueryInterface(mSessionHistory
));
4329 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
4330 shPrivate
->SetRootDocShell(this);
4333 return NS_ERROR_FAILURE
;
4339 nsDocShell::GetSessionHistory(nsISHistory
** aSessionHistory
)
4341 NS_ENSURE_ARG_POINTER(aSessionHistory
);
4342 *aSessionHistory
= mSessionHistory
;
4343 NS_IF_ADDREF(*aSessionHistory
);
4347 //*****************************************************************************
4348 // nsDocShell::nsIWebPageDescriptor
4349 //*****************************************************************************
4351 nsDocShell::LoadPage(nsISupports
*aPageDescriptor
, PRUint32 aDisplayType
)
4353 nsCOMPtr
<nsISHEntry
> shEntryIn(do_QueryInterface(aPageDescriptor
));
4355 // Currently, the opaque 'page descriptor' is an nsISHEntry...
4357 return NS_ERROR_INVALID_POINTER
;
4360 // Now clone shEntryIn, since we might end up modifying it later on, and we
4361 // want a page descriptor to be reusable.
4362 nsCOMPtr
<nsISHEntry
> shEntry
;
4363 nsresult rv
= shEntryIn
->Clone(getter_AddRefs(shEntry
));
4364 NS_ENSURE_SUCCESS(rv
, rv
);
4366 // Give our cloned shEntry a new document identifier so this load is
4367 // independent of all other loads. (This is important, in particular,
4368 // for bugs 582795 and 585298.)
4369 rv
= shEntry
->SetUniqueDocIdentifier();
4370 NS_ENSURE_SUCCESS(rv
, rv
);
4373 // load the page as view-source
4375 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE
== aDisplayType
) {
4376 nsCOMPtr
<nsIURI
> oldUri
, newUri
;
4377 nsCString spec
, newSpec
;
4379 // Create a new view-source URI and replace the original.
4380 rv
= shEntry
->GetURI(getter_AddRefs(oldUri
));
4384 oldUri
->GetSpec(spec
);
4385 newSpec
.AppendLiteral("view-source:");
4386 newSpec
.Append(spec
);
4388 rv
= NS_NewURI(getter_AddRefs(newUri
), newSpec
);
4389 if (NS_FAILED(rv
)) {
4392 shEntry
->SetURI(newUri
);
4395 rv
= LoadHistoryEntry(shEntry
, LOAD_HISTORY
);
4400 nsDocShell::GetCurrentDescriptor(nsISupports
**aPageDescriptor
)
4402 NS_PRECONDITION(aPageDescriptor
, "Null out param?");
4404 *aPageDescriptor
= nsnull
;
4406 nsISHEntry
* src
= mOSHE
? mOSHE
: mLSHE
;
4408 nsCOMPtr
<nsISHEntry
> dest
;
4410 nsresult rv
= src
->Clone(getter_AddRefs(dest
));
4411 if (NS_FAILED(rv
)) {
4415 // null out inappropriate cloned attributes...
4416 dest
->SetParent(nsnull
);
4417 dest
->SetIsSubFrame(PR_FALSE
);
4419 return CallQueryInterface(dest
, aPageDescriptor
);
4422 return NS_ERROR_NOT_AVAILABLE
;
4426 //*****************************************************************************
4427 // nsDocShell::nsIBaseWindow
4428 //*****************************************************************************
4431 nsDocShell::InitWindow(nativeWindow parentNativeWindow
,
4432 nsIWidget
* parentWidget
, PRInt32 x
, PRInt32 y
,
4433 PRInt32 cx
, PRInt32 cy
)
4435 SetParentWidget(parentWidget
);
4436 SetPositionAndSize(x
, y
, cx
, cy
, PR_FALSE
);
4442 nsDocShell::Create()
4445 // We've already been created
4449 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
4450 "Unexpected item type in docshell");
4452 nsresult rv
= NS_ERROR_FAILURE
;
4453 mPrefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
);
4454 NS_ENSURE_SUCCESS(rv
, rv
);
4458 rv
= mPrefs
->GetBoolPref("browser.frames.enabled", &tmpbool
);
4459 if (NS_SUCCEEDED(rv
))
4460 mAllowSubframes
= tmpbool
;
4462 if (gValidateOrigin
== (PRBool
)0xffffffff) {
4463 // Check pref to see if we should prevent frameset spoofing
4464 rv
= mPrefs
->GetBoolPref("browser.frame.validate_origin", &tmpbool
);
4465 if (NS_SUCCEEDED(rv
)) {
4466 gValidateOrigin
= tmpbool
;
4468 gValidateOrigin
= PR_TRUE
;
4472 // Should we use XUL error pages instead of alerts if possible?
4473 rv
= mPrefs
->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool
);
4474 if (NS_SUCCEEDED(rv
))
4475 mUseErrorPages
= tmpbool
;
4477 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
, &rv
));
4478 if (NS_SUCCEEDED(rv
) && mObserveErrorPages
) {
4479 prefs
->AddObserver("browser.xul.error_pages.enabled", this, PR_FALSE
);
4482 nsCOMPtr
<nsIObserverService
> serv
= do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
4484 const char* msg
= mItemType
== typeContent
?
4485 NS_WEBNAVIGATION_CREATE
: NS_CHROME_WEBNAVIGATION_CREATE
;
4486 serv
->NotifyObservers(GetAsSupports(this), msg
, nsnull
);
4493 nsDocShell::Destroy()
4495 NS_ASSERTION(mItemType
== typeContent
|| mItemType
== typeChrome
,
4496 "Unexpected item type in docshell");
4498 if (!mIsBeingDestroyed
) {
4499 nsCOMPtr
<nsIObserverService
> serv
=
4500 do_GetService(NS_OBSERVERSERVICE_CONTRACTID
);
4502 const char* msg
= mItemType
== typeContent
?
4503 NS_WEBNAVIGATION_DESTROY
: NS_CHROME_WEBNAVIGATION_DESTROY
;
4504 serv
->NotifyObservers(GetAsSupports(this), msg
, nsnull
);
4508 mIsBeingDestroyed
= PR_TRUE
;
4510 // Remove our pref observers
4511 if (mObserveErrorPages
) {
4512 nsCOMPtr
<nsIPrefBranch2
> prefs(do_QueryInterface(mPrefs
));
4514 prefs
->RemoveObserver("browser.xul.error_pages.enabled", this);
4515 mObserveErrorPages
= PR_FALSE
;
4519 // Make sure to blow away our mLoadingURI just in case. No loads
4520 // from inside this pagehide.
4521 mLoadingURI
= nsnull
;
4523 // Fire unload event before we blow anything away.
4524 (void) FirePageHideNotification(PR_TRUE
);
4526 // Clear pointers to any detached nsEditorData that's lying
4527 // around in shistory entries. Breaks cycle. See bug 430921.
4529 mOSHE
->SetEditorData(nsnull
);
4531 mLSHE
->SetEditorData(nsnull
);
4533 // Note: mContentListener can be null if Init() failed and we're being
4534 // called from the destructor.
4535 if (mContentListener
) {
4536 mContentListener
->DropDocShellreference();
4537 mContentListener
->SetParentContentListener(nsnull
);
4538 // Note that we do NOT set mContentListener to null here; that
4539 // way if someone tries to do a load in us after this point
4540 // the nsDSURIContentListener will block it. All of which
4541 // means that we should do this before calling Stop(), of
4545 // Stop any URLs that are currently being loaded...
4546 Stop(nsIWebNavigation::STOP_ALL
);
4548 mEditorData
= nsnull
;
4550 mTransferableHookData
= nsnull
;
4552 // Save the state of the current document, before destroying the window.
4553 // This is needed to capture the state of a frameset when the new document
4554 // causes the frameset to be destroyed...
4555 PersistLayoutHistoryState();
4557 // Remove this docshell from its parent's child list
4558 nsCOMPtr
<nsIDocShellTreeItem
> docShellParentAsItem
=
4559 do_QueryInterface(GetAsSupports(mParent
));
4560 if (docShellParentAsItem
)
4561 docShellParentAsItem
->RemoveChild(this);
4563 if (mContentViewer
) {
4564 mContentViewer
->Close(nsnull
);
4565 mContentViewer
->Destroy();
4566 mContentViewer
= nsnull
;
4569 nsDocLoader::Destroy();
4571 mParentWidget
= nsnull
;
4572 mCurrentURI
= nsnull
;
4574 if (mScriptGlobal
) {
4575 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
4576 win
->SetDocShell(nsnull
);
4578 mScriptGlobal
= nsnull
;
4581 if (mSessionHistory
) {
4582 // We want to destroy these content viewers now rather than
4583 // letting their destruction wait for the session history
4584 // entries to get garbage collected. (Bug 488394)
4585 nsCOMPtr
<nsISHistoryInternal
> shPrivate
=
4586 do_QueryInterface(mSessionHistory
);
4588 shPrivate
->EvictAllContentViewers();
4590 mSessionHistory
= nsnull
;
4593 SetTreeOwner(nsnull
);
4595 // required to break ref cycle
4596 mSecurityUI
= nsnull
;
4598 // Cancel any timers that were set for this docshell; this is needed
4599 // to break the cycle between us and the timers.
4600 CancelRefreshURITimers();
4605 nsDocShell::SetPosition(PRInt32 x
, PRInt32 y
)
4611 NS_ENSURE_SUCCESS(mContentViewer
->Move(x
, y
), NS_ERROR_FAILURE
);
4617 nsDocShell::GetPosition(PRInt32
* aX
, PRInt32
* aY
)
4619 PRInt32 dummyHolder
;
4620 return GetPositionAndSize(aX
, aY
, &dummyHolder
, &dummyHolder
);
4624 nsDocShell::SetSize(PRInt32 aCX
, PRInt32 aCY
, PRBool aRepaint
)
4626 PRInt32 x
= 0, y
= 0;
4627 GetPosition(&x
, &y
);
4628 return SetPositionAndSize(x
, y
, aCX
, aCY
, aRepaint
);
4632 nsDocShell::GetSize(PRInt32
* aCX
, PRInt32
* aCY
)
4634 PRInt32 dummyHolder
;
4635 return GetPositionAndSize(&dummyHolder
, &dummyHolder
, aCX
, aCY
);
4639 nsDocShell::SetPositionAndSize(PRInt32 x
, PRInt32 y
, PRInt32 cx
,
4640 PRInt32 cy
, PRBool fRepaint
)
4645 mBounds
.height
= cy
;
4647 // Hold strong ref, since SetBounds can make us null out mContentViewer
4648 nsCOMPtr
<nsIContentViewer
> viewer
= mContentViewer
;
4650 //XXX Border figured in here or is that handled elsewhere?
4651 NS_ENSURE_SUCCESS(viewer
->SetBounds(mBounds
), NS_ERROR_FAILURE
);
4658 nsDocShell::GetPositionAndSize(PRInt32
* x
, PRInt32
* y
, PRInt32
* cx
,
4661 // We should really consider just getting this information from
4662 // our window instead of duplicating the storage and code...
4664 // Caller wants to know our size; make sure to give them up to
4665 // date information.
4666 nsCOMPtr
<nsIDocument
> doc(do_GetInterface(GetAsSupports(mParent
)));
4668 doc
->FlushPendingNotifications(Flush_Layout
);
4672 DoGetPositionAndSize(x
, y
, cx
, cy
);
4677 nsDocShell::DoGetPositionAndSize(PRInt32
* x
, PRInt32
* y
, PRInt32
* cx
,
4685 *cx
= mBounds
.width
;
4687 *cy
= mBounds
.height
;
4691 nsDocShell::Repaint(PRBool aForce
)
4693 nsCOMPtr
<nsIPresShell
> presShell
;
4694 GetPresShell(getter_AddRefs(presShell
));
4695 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
4697 nsIViewManager
* viewManager
= presShell
->GetViewManager();
4698 NS_ENSURE_TRUE(viewManager
, NS_ERROR_FAILURE
);
4700 // what about aForce ?
4701 NS_ENSURE_SUCCESS(viewManager
->UpdateAllViews(0), NS_ERROR_FAILURE
);
4706 nsDocShell::GetParentWidget(nsIWidget
** parentWidget
)
4708 NS_ENSURE_ARG_POINTER(parentWidget
);
4710 *parentWidget
= mParentWidget
;
4711 NS_IF_ADDREF(*parentWidget
);
4717 nsDocShell::SetParentWidget(nsIWidget
* aParentWidget
)
4719 mParentWidget
= aParentWidget
;
4725 nsDocShell::GetParentNativeWindow(nativeWindow
* parentNativeWindow
)
4727 NS_ENSURE_ARG_POINTER(parentNativeWindow
);
4730 *parentNativeWindow
= mParentWidget
->GetNativeData(NS_NATIVE_WIDGET
);
4732 *parentNativeWindow
= nsnull
;
4738 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow
)
4740 return NS_ERROR_NOT_IMPLEMENTED
;
4744 nsDocShell::GetVisibility(PRBool
* aVisibility
)
4746 NS_ENSURE_ARG_POINTER(aVisibility
);
4748 *aVisibility
= PR_FALSE
;
4750 if (!mContentViewer
)
4753 nsCOMPtr
<nsIPresShell
> presShell
;
4754 GetPresShell(getter_AddRefs(presShell
));
4758 // get the view manager
4759 nsIViewManager
* vm
= presShell
->GetViewManager();
4760 NS_ENSURE_TRUE(vm
, NS_ERROR_FAILURE
);
4762 // get the root view
4763 nsIView
*view
= nsnull
; // views are not ref counted
4764 NS_ENSURE_SUCCESS(vm
->GetRootView(view
), NS_ERROR_FAILURE
);
4765 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
4767 // if our root view is hidden, we are not visible
4768 if (view
->GetVisibility() == nsViewVisibility_kHide
)
4771 // otherwise, we must walk up the document and view trees checking
4772 // for a hidden view, unless we're an off screen browser, which
4773 // would make this test meaningless.
4775 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= this;
4776 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
4777 treeItem
->GetParent(getter_AddRefs(parentItem
));
4778 while (parentItem
) {
4779 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(treeItem
));
4780 docShell
->GetPresShell(getter_AddRefs(presShell
));
4782 nsCOMPtr
<nsIDocShell
> parentDS
= do_QueryInterface(parentItem
);
4783 nsCOMPtr
<nsIPresShell
> pPresShell
;
4784 parentDS
->GetPresShell(getter_AddRefs(pPresShell
));
4786 // Null-check for crash in bug 267804
4788 NS_NOTREACHED("parent docshell has null pres shell");
4792 nsIContent
*shellContent
=
4793 pPresShell
->GetDocument()->FindContentForSubDocument(presShell
->GetDocument());
4794 NS_ASSERTION(shellContent
, "subshell not in the map");
4796 nsIFrame
* frame
= shellContent
? shellContent
->GetPrimaryFrame() : nsnull
;
4797 PRBool isDocShellOffScreen
= PR_FALSE
;
4798 docShell
->GetIsOffScreenBrowser(&isDocShellOffScreen
);
4799 if (frame
&& !frame
->AreAncestorViewsVisible() && !isDocShellOffScreen
)
4802 treeItem
= parentItem
;
4803 treeItem
->GetParent(getter_AddRefs(parentItem
));
4806 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
4807 if (!treeOwnerAsWin
) {
4808 *aVisibility
= PR_TRUE
;
4812 // Check with the tree owner as well to give embedders a chance to
4813 // expose visibility as well.
4814 return treeOwnerAsWin
->GetVisibility(aVisibility
);
4818 nsDocShell::SetIsOffScreenBrowser(PRBool aIsOffScreen
)
4820 mIsOffScreenBrowser
= aIsOffScreen
;
4825 nsDocShell::GetIsOffScreenBrowser(PRBool
*aIsOffScreen
)
4827 *aIsOffScreen
= mIsOffScreenBrowser
;
4832 nsDocShell::SetIsActive(PRBool aIsActive
)
4834 // We disallow setting active on chrome docshells.
4835 if (mItemType
== nsIDocShellTreeItem::typeChrome
)
4836 return NS_ERROR_INVALID_ARG
;
4838 // Keep track ourselves.
4839 mIsActive
= aIsActive
;
4841 // Tell the PresShell about it.
4842 nsCOMPtr
<nsIPresShell
> pshell
;
4843 GetPresShell(getter_AddRefs(pshell
));
4845 pshell
->SetIsActive(aIsActive
);
4847 // Recursively tell all of our children
4848 PRInt32 n
= mChildList
.Count();
4849 for (PRInt32 i
= 0; i
< n
; ++i
) {
4850 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryInterface(ChildAt(i
));
4852 docshell
->SetIsActive(aIsActive
);
4859 nsDocShell::GetIsActive(PRBool
*aIsActive
)
4861 *aIsActive
= mIsActive
;
4866 nsDocShell::SetIsAppTab(PRBool aIsAppTab
)
4868 mIsAppTab
= aIsAppTab
;
4873 nsDocShell::GetIsAppTab(PRBool
*aIsAppTab
)
4875 *aIsAppTab
= mIsAppTab
;
4880 nsDocShell::SetVisibility(PRBool aVisibility
)
4882 if (!mContentViewer
)
4885 mContentViewer
->Show();
4888 mContentViewer
->Hide();
4895 nsDocShell::GetEnabled(PRBool
*aEnabled
)
4897 NS_ENSURE_ARG_POINTER(aEnabled
);
4898 *aEnabled
= PR_TRUE
;
4899 return NS_ERROR_NOT_IMPLEMENTED
;
4903 nsDocShell::SetEnabled(PRBool aEnabled
)
4905 return NS_ERROR_NOT_IMPLEMENTED
;
4909 nsDocShell::GetBlurSuppression(PRBool
*aBlurSuppression
)
4911 NS_ENSURE_ARG_POINTER(aBlurSuppression
);
4912 *aBlurSuppression
= PR_FALSE
;
4913 return NS_ERROR_NOT_IMPLEMENTED
;
4917 nsDocShell::SetBlurSuppression(PRBool aBlurSuppression
)
4919 return NS_ERROR_NOT_IMPLEMENTED
;
4923 nsDocShell::SetFocus()
4929 nsDocShell::GetMainWidget(nsIWidget
** aMainWidget
)
4931 // We don't create our own widget, so simply return the parent one.
4932 return GetParentWidget(aMainWidget
);
4936 nsDocShell::GetTitle(PRUnichar
** aTitle
)
4938 NS_ENSURE_ARG_POINTER(aTitle
);
4940 *aTitle
= ToNewUnicode(mTitle
);
4945 nsDocShell::SetTitle(const PRUnichar
* aTitle
)
4947 // Store local title
4950 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
4951 GetSameTypeParent(getter_AddRefs(parent
));
4953 // When title is set on the top object it should then be passed to the
4956 nsCOMPtr
<nsIBaseWindow
>
4957 treeOwnerAsWin(do_QueryInterface(mTreeOwner
));
4959 treeOwnerAsWin
->SetTitle(aTitle
);
4962 if (mCurrentURI
&& mLoadType
!= LOAD_ERROR_PAGE
&& mUseGlobalHistory
) {
4963 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
4965 history
->SetURITitle(mCurrentURI
, mTitle
);
4967 else if (mGlobalHistory
) {
4968 mGlobalHistory
->SetPageTitle(mCurrentURI
, nsString(mTitle
));
4972 // Update SessionHistory with the document's title.
4973 if (mOSHE
&& mLoadType
!= LOAD_BYPASS_HISTORY
&&
4974 mLoadType
!= LOAD_ERROR_PAGE
) {
4976 mOSHE
->SetTitle(mTitle
);
4982 //*****************************************************************************
4983 // nsDocShell::nsIScrollable
4984 //*****************************************************************************
4987 nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation
, PRInt32
* curPos
)
4989 NS_ENSURE_ARG_POINTER(curPos
);
4991 nsIScrollableFrame
* sf
= GetRootScrollFrame();
4992 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
4994 nsPoint pt
= sf
->GetScrollPosition();
4996 switch (scrollOrientation
) {
4997 case ScrollOrientation_X
:
5001 case ScrollOrientation_Y
:
5006 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
5011 nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation
, PRInt32 curPos
)
5013 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5014 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5016 nsPoint pt
= sf
->GetScrollPosition();
5018 switch (scrollOrientation
) {
5019 case ScrollOrientation_X
:
5023 case ScrollOrientation_Y
:
5028 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
5031 sf
->ScrollTo(pt
, nsIScrollableFrame::INSTANT
);
5036 nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos
, PRInt32 curVerticalPos
)
5038 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5039 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5041 sf
->ScrollTo(nsPoint(curHorizontalPos
, curVerticalPos
),
5042 nsIScrollableFrame::INSTANT
);
5046 // XXX This is wrong
5048 nsDocShell::GetScrollRange(PRInt32 scrollOrientation
,
5049 PRInt32
* minPos
, PRInt32
* maxPos
)
5051 NS_ENSURE_ARG_POINTER(minPos
&& maxPos
);
5053 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5054 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5056 nsSize portSize
= sf
->GetScrollPortRect().Size();
5057 nsRect range
= sf
->GetScrollRange();
5059 switch (scrollOrientation
) {
5060 case ScrollOrientation_X
:
5062 *maxPos
= range
.XMost() + portSize
.width
;
5065 case ScrollOrientation_Y
:
5067 *maxPos
= range
.YMost() + portSize
.height
;
5071 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
5076 nsDocShell::SetScrollRange(PRInt32 scrollOrientation
,
5077 PRInt32 minPos
, PRInt32 maxPos
)
5081 Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
5082 something less than the current thumb position, curPos is set = to maxPos.
5084 @return NS_OK - Setting or Getting completed successfully.
5085 NS_ERROR_INVALID_ARG - returned when curPos is not within the
5088 return NS_ERROR_FAILURE
;
5092 nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos
,
5093 PRInt32 maxHorizontalPos
, PRInt32 minVerticalPos
,
5094 PRInt32 maxVerticalPos
)
5098 Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
5099 something less than the current thumb position, curPos is set = to maxPos.
5101 @return NS_OK - Setting or Getting completed successfully.
5102 NS_ERROR_INVALID_ARG - returned when curPos is not within the
5105 return NS_ERROR_FAILURE
;
5108 // This returns setting for all documents in this docshell
5110 nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation
,
5111 PRInt32
* scrollbarPref
)
5113 NS_ENSURE_ARG_POINTER(scrollbarPref
);
5114 switch (scrollOrientation
) {
5115 case ScrollOrientation_X
:
5116 *scrollbarPref
= mDefaultScrollbarPref
.x
;
5119 case ScrollOrientation_Y
:
5120 *scrollbarPref
= mDefaultScrollbarPref
.y
;
5124 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
5126 return NS_ERROR_FAILURE
;
5129 // Set scrolling preference for all documents in this shell
5131 // There are three possible values stored in the shell:
5132 // 1) nsIScrollable::Scrollbar_Never = no scrollbar
5133 // 2) nsIScrollable::Scrollbar_Auto = scrollbar appears if the document
5134 // being displayed would normally have scrollbar
5135 // 3) nsIScrollable::Scrollbar_Always = scrollbar always appears
5137 // One important client is nsHTMLFrameInnerFrame::CreateWebShell()
5139 nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation
,
5140 PRInt32 scrollbarPref
)
5142 switch (scrollOrientation
) {
5143 case ScrollOrientation_X
:
5144 mDefaultScrollbarPref
.x
= scrollbarPref
;
5147 case ScrollOrientation_Y
:
5148 mDefaultScrollbarPref
.y
= scrollbarPref
;
5152 NS_ENSURE_TRUE(PR_FALSE
, NS_ERROR_INVALID_ARG
);
5154 return NS_ERROR_FAILURE
;
5158 nsDocShell::GetScrollbarVisibility(PRBool
* verticalVisible
,
5159 PRBool
* horizontalVisible
)
5161 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5162 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5164 PRUint32 scrollbarVisibility
= sf
->GetScrollbarVisibility();
5165 if (verticalVisible
)
5166 *verticalVisible
= (scrollbarVisibility
& nsIScrollableFrame::VERTICAL
) != 0;
5167 if (horizontalVisible
)
5168 *horizontalVisible
= (scrollbarVisibility
& nsIScrollableFrame::HORIZONTAL
) != 0;
5173 //*****************************************************************************
5174 // nsDocShell::nsITextScroll
5175 //*****************************************************************************
5178 nsDocShell::ScrollByLines(PRInt32 numLines
)
5180 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5181 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5183 sf
->ScrollBy(nsIntPoint(0, numLines
), nsIScrollableFrame::LINES
,
5184 nsIScrollableFrame::SMOOTH
);
5189 nsDocShell::ScrollByPages(PRInt32 numPages
)
5191 nsIScrollableFrame
* sf
= GetRootScrollFrame();
5192 NS_ENSURE_TRUE(sf
, NS_ERROR_FAILURE
);
5194 sf
->ScrollBy(nsIntPoint(0, numPages
), nsIScrollableFrame::PAGES
,
5195 nsIScrollableFrame::SMOOTH
);
5199 //*****************************************************************************
5200 // nsDocShell::nsIScriptGlobalObjectOwner
5201 //*****************************************************************************
5203 nsIScriptGlobalObject
*
5204 nsDocShell::GetScriptGlobalObject()
5206 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nsnull
);
5208 return mScriptGlobal
;
5211 //*****************************************************************************
5212 // nsDocShell::nsIRefreshURI
5213 //*****************************************************************************
5216 nsDocShell::RefreshURI(nsIURI
* aURI
, PRInt32 aDelay
, PRBool aRepeat
,
5217 PRBool aMetaRefresh
)
5219 NS_ENSURE_ARG(aURI
);
5221 /* Check if Meta refresh/redirects are permitted. Some
5222 * embedded applications may not want to do this.
5223 * Must do this before sending out NOTIFY_REFRESH events
5224 * because listeners may have side effects (e.g. displaying a
5225 * button to manually trigger the refresh later).
5227 PRBool allowRedirects
= PR_TRUE
;
5228 GetAllowMetaRedirects(&allowRedirects
);
5229 if (!allowRedirects
)
5232 // If any web progress listeners are listening for NOTIFY_REFRESH events,
5233 // give them a chance to block this refresh.
5235 nsresult rv
= aURI
->Equals(mCurrentURI
, &sameURI
);
5238 if (!RefreshAttempted(this, aURI
, aDelay
, sameURI
))
5241 nsRefreshTimer
*refreshTimer
= new nsRefreshTimer();
5242 NS_ENSURE_TRUE(refreshTimer
, NS_ERROR_OUT_OF_MEMORY
);
5243 PRUint32 busyFlags
= 0;
5244 GetBusyFlags(&busyFlags
);
5246 nsCOMPtr
<nsISupports
> dataRef
= refreshTimer
; // Get the ref count to 1
5248 refreshTimer
->mDocShell
= this;
5249 refreshTimer
->mURI
= aURI
;
5250 refreshTimer
->mDelay
= aDelay
;
5251 refreshTimer
->mRepeat
= aRepeat
;
5252 refreshTimer
->mMetaRefresh
= aMetaRefresh
;
5254 if (!mRefreshURIList
) {
5255 NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList
)),
5259 if (busyFlags
& BUSY_FLAGS_BUSY
) {
5260 // We are busy loading another page. Don't create the
5261 // timer right now. Instead queue up the request and trigger the
5262 // timer in EndPageLoad().
5263 mRefreshURIList
->AppendElement(refreshTimer
);
5266 // There is no page loading going on right now. Create the
5267 // timer and fire it right away.
5268 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance("@mozilla.org/timer;1");
5269 NS_ENSURE_TRUE(timer
, NS_ERROR_FAILURE
);
5271 mRefreshURIList
->AppendElement(timer
); // owning timer ref
5272 timer
->InitWithCallback(refreshTimer
, aDelay
, nsITimer::TYPE_ONE_SHOT
);
5278 nsDocShell::ForceRefreshURIFromTimer(nsIURI
* aURI
,
5280 PRBool aMetaRefresh
,
5283 NS_PRECONDITION(aTimer
, "Must have a timer here");
5285 // Remove aTimer from mRefreshURIList if needed
5286 if (mRefreshURIList
) {
5288 mRefreshURIList
->Count(&n
);
5290 for (PRUint32 i
= 0; i
< n
; ++i
) {
5291 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
5292 if (timer
== aTimer
) {
5293 mRefreshURIList
->RemoveElementAt(i
);
5299 return ForceRefreshURI(aURI
, aDelay
, aMetaRefresh
);
5303 nsDocShell::ForceRefreshURI(nsIURI
* aURI
,
5305 PRBool aMetaRefresh
)
5307 NS_ENSURE_ARG(aURI
);
5309 nsCOMPtr
<nsIDocShellLoadInfo
> loadInfo
;
5310 CreateLoadInfo(getter_AddRefs(loadInfo
));
5311 NS_ENSURE_TRUE(loadInfo
, NS_ERROR_OUT_OF_MEMORY
);
5313 /* We do need to pass in a referrer, but we don't want it to
5314 * be sent to the server.
5316 loadInfo
->SetSendReferrer(PR_FALSE
);
5318 /* for most refreshes the current URI is an appropriate
5321 loadInfo
->SetReferrer(mCurrentURI
);
5323 /* Don't ever "guess" on which owner to use to avoid picking
5324 * the current owner.
5326 loadInfo
->SetOwnerIsExplicit(PR_TRUE
);
5328 /* Check if this META refresh causes a redirection
5331 PRBool equalUri
= PR_FALSE
;
5332 nsresult rv
= aURI
->Equals(mCurrentURI
, &equalUri
);
5333 if (NS_SUCCEEDED(rv
) && (!equalUri
) && aMetaRefresh
&&
5334 aDelay
<= REFRESH_REDIRECT_TIMER
) {
5336 /* It is a META refresh based redirection within the threshold time
5337 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
5338 * Pass a REPLACE flag to LoadURI().
5340 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace
);
5342 /* for redirects we mimic HTTP, which passes the
5345 nsCOMPtr
<nsIURI
> internalReferrer
;
5346 GetReferringURI(getter_AddRefs(internalReferrer
));
5347 if (internalReferrer
) {
5348 loadInfo
->SetReferrer(internalReferrer
);
5352 loadInfo
->SetLoadType(nsIDocShellLoadInfo::loadRefresh
);
5356 * LoadURI(...) will cancel all refresh timers... This causes the
5357 * Timer and its refreshData instance to be released...
5359 LoadURI(aURI
, loadInfo
, nsIWebNavigation::LOAD_FLAGS_NONE
, PR_TRUE
);
5365 nsDocShell::SetupRefreshURIFromHeader(nsIURI
* aBaseURI
,
5366 const nsACString
& aHeader
)
5368 // Refresh headers are parsed with the following format in mind
5369 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
5370 // By the time we are here, the following is true:
5371 // header = "REFRESH"
5372 // content = "5; URL=http://uri" // note the URL attribute is
5373 // optional, if it is absent, the currently loaded url is used.
5374 // Also note that the seconds and URL separator can be either
5375 // a ';' or a ','. The ',' separator should be illegal but CNN
5378 // We need to handle the following strings, where
5379 // - X is a set of digits
5380 // - URI is either a relative or absolute URI
5382 // Note that URI should start with "url=" but we allow omission
5385 // empty string. use the currently loaded URI
5386 // and refresh immediately.
5387 // "X" || "X;" || "X,"
5388 // Refresh the currently loaded URI in X seconds.
5389 // "X; URI" || "X, URI"
5390 // Refresh using URI as the destination in X seconds.
5391 // "URI" || "; URI" || ", URI"
5392 // Refresh immediately using URI as the destination.
5394 // Currently, anything immediately following the URI, if
5395 // separated by any char in the set "'\"\t\r\n " will be
5396 // ignored. So "10; url=go.html ; foo=bar" will work,
5397 // and so will "10; url='go.html'; foo=bar". However,
5398 // "10; url=go.html; foo=bar" will result in the uri
5399 // "go.html;" since ';' and ',' are valid uri characters.
5401 // Note that we need to remove any tokens wrapping the URI.
5402 // These tokens currently include spaces, double and single
5405 // when done, seconds is 0 or the given number of seconds
5406 // uriAttrib is empty or the URI specified
5407 nsCAutoString uriAttrib
;
5408 PRInt32 seconds
= 0;
5409 PRBool specifiesSeconds
= PR_FALSE
;
5411 nsACString::const_iterator iter
, tokenStart
, doneIterating
;
5413 aHeader
.BeginReading(iter
);
5414 aHeader
.EndReading(doneIterating
);
5416 // skip leading whitespace
5417 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5422 // skip leading + and -
5423 if (iter
!= doneIterating
&& (*iter
== '-' || *iter
== '+'))
5427 while (iter
!= doneIterating
&& (*iter
>= '0' && *iter
<= '9')) {
5428 seconds
= seconds
* 10 + (*iter
- '0');
5429 specifiesSeconds
= PR_TRUE
;
5433 if (iter
!= doneIterating
) {
5434 // if we started with a '-', number is negative
5435 if (*tokenStart
== '-')
5438 // skip to next ';' or ','
5439 nsACString::const_iterator iterAfterDigit
= iter
;
5440 while (iter
!= doneIterating
&& !(*iter
== ';' || *iter
== ','))
5442 if (specifiesSeconds
)
5444 // Non-whitespace characters here mean that the string is
5445 // malformed but tolerate sites that specify a decimal point,
5446 // even though meta refresh only works on whole seconds.
5447 if (iter
== iterAfterDigit
&&
5448 !nsCRT::IsAsciiSpace(*iter
) && *iter
!= '.')
5450 // The characters between the seconds and the next
5451 // section are just garbage!
5452 // e.g. content="2a0z+,URL=http://www.mozilla.org/"
5453 // Just ignore this redirect.
5454 return NS_ERROR_FAILURE
;
5456 else if (nsCRT::IsAsciiSpace(*iter
))
5458 // We've had at least one whitespace so tolerate the mistake
5459 // and drop through.
5460 // e.g. content="10 foo"
5468 // skip any remaining whitespace
5469 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5473 if (iter
!= doneIterating
&& (*iter
== ';' || *iter
== ',')) {
5478 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5482 // possible start of URI
5485 // skip "url = " to real start of URI
5486 if (iter
!= doneIterating
&& (*iter
== 'u' || *iter
== 'U')) {
5488 if (iter
!= doneIterating
&& (*iter
== 'r' || *iter
== 'R')) {
5490 if (iter
!= doneIterating
&& (*iter
== 'l' || *iter
== 'L')) {
5494 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5497 if (iter
!= doneIterating
&& *iter
== '=') {
5501 while (iter
!= doneIterating
&& nsCRT::IsAsciiSpace(*iter
))
5504 // found real start of URI
5511 // skip a leading '"' or '\''.
5513 PRBool isQuotedURI
= PR_FALSE
;
5514 if (tokenStart
!= doneIterating
&& (*tokenStart
== '"' || *tokenStart
== '\''))
5516 isQuotedURI
= PR_TRUE
;
5520 // set iter to start of URI
5523 // tokenStart here points to the beginning of URI
5525 // grab the rest of the URI
5526 while (iter
!= doneIterating
)
5528 if (isQuotedURI
&& (*iter
== '"' || *iter
== '\''))
5533 // move iter one back if the last character is a '"' or '\''
5534 if (iter
!= tokenStart
&& isQuotedURI
) {
5536 if (!(*iter
== '"' || *iter
== '\''))
5540 // URI is whatever's contained from tokenStart to iter.
5541 // note: if tokenStart == doneIterating, so is iter.
5543 nsresult rv
= NS_OK
;
5545 nsCOMPtr
<nsIURI
> uri
;
5546 PRBool specifiesURI
= PR_FALSE
;
5547 if (tokenStart
== iter
) {
5551 uriAttrib
= Substring(tokenStart
, iter
);
5552 // NS_NewURI takes care of any whitespace surrounding the URL
5553 rv
= NS_NewURI(getter_AddRefs(uri
), uriAttrib
, nsnull
, aBaseURI
);
5554 specifiesURI
= PR_TRUE
;
5557 // No URI or seconds were specified
5558 if (!specifiesSeconds
&& !specifiesURI
)
5560 // Do nothing because the alternative is to spin around in a refresh
5562 return NS_ERROR_FAILURE
;
5565 if (NS_SUCCEEDED(rv
)) {
5566 nsCOMPtr
<nsIScriptSecurityManager
>
5567 securityManager(do_GetService
5568 (NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
5569 if (NS_SUCCEEDED(rv
)) {
5570 rv
= securityManager
->
5571 CheckLoadURI(aBaseURI
, uri
,
5572 nsIScriptSecurityManager::
5573 LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
);
5575 if (NS_SUCCEEDED(rv
)) {
5576 PRBool isjs
= PR_TRUE
;
5577 rv
= NS_URIChainHasFlags(uri
,
5578 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT
, &isjs
);
5579 NS_ENSURE_SUCCESS(rv
, rv
);
5582 return NS_ERROR_FAILURE
;
5586 if (NS_SUCCEEDED(rv
)) {
5587 // Since we can't travel back in time yet, just pretend
5588 // negative numbers do nothing at all.
5590 return NS_ERROR_FAILURE
;
5592 rv
= RefreshURI(uri
, seconds
* 1000, PR_FALSE
, PR_TRUE
);
5599 NS_IMETHODIMP
nsDocShell::SetupRefreshURI(nsIChannel
* aChannel
)
5602 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
, &rv
));
5603 if (NS_SUCCEEDED(rv
)) {
5604 nsCAutoString refreshHeader
;
5605 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
5608 if (!refreshHeader
.IsEmpty()) {
5609 SetupReferrerFromChannel(aChannel
);
5610 rv
= SetupRefreshURIFromHeader(mCurrentURI
, refreshHeader
);
5611 if (NS_SUCCEEDED(rv
)) {
5612 return NS_REFRESHURI_HEADER_FOUND
;
5620 DoCancelRefreshURITimers(nsISupportsArray
* aTimerList
)
5626 aTimerList
->Count(&n
);
5629 nsCOMPtr
<nsITimer
> timer(do_QueryElementAt(aTimerList
, --n
));
5631 aTimerList
->RemoveElementAt(n
); // bye bye owning timer ref
5639 nsDocShell::CancelRefreshURITimers()
5641 DoCancelRefreshURITimers(mRefreshURIList
);
5642 DoCancelRefreshURITimers(mSavedRefreshURIList
);
5643 mRefreshURIList
= nsnull
;
5644 mSavedRefreshURIList
= nsnull
;
5650 nsDocShell::GetRefreshPending(PRBool
* _retval
)
5652 if (!mRefreshURIList
) {
5653 *_retval
= PR_FALSE
;
5658 nsresult rv
= mRefreshURIList
->Count(&count
);
5659 if (NS_SUCCEEDED(rv
))
5660 *_retval
= (count
!= 0);
5665 nsDocShell::SuspendRefreshURIs()
5667 if (mRefreshURIList
) {
5669 mRefreshURIList
->Count(&n
);
5671 for (PRUint32 i
= 0; i
< n
; ++i
) {
5672 nsCOMPtr
<nsITimer
> timer
= do_QueryElementAt(mRefreshURIList
, i
);
5674 continue; // this must be a nsRefreshURI already
5676 // Replace this timer object with a nsRefreshTimer object.
5677 nsCOMPtr
<nsITimerCallback
> callback
;
5678 timer
->GetCallback(getter_AddRefs(callback
));
5682 nsCOMPtr
<nsITimerCallback
> rt
= do_QueryInterface(callback
);
5683 NS_ASSERTION(rt
, "RefreshURIList timer callbacks should only be RefreshTimer objects");
5685 mRefreshURIList
->ReplaceElementAt(rt
, i
);
5689 // Suspend refresh URIs for our child shells as well.
5690 PRInt32 n
= mChildList
.Count();
5692 for (PRInt32 i
= 0; i
< n
; ++i
) {
5693 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
5695 shell
->SuspendRefreshURIs();
5702 nsDocShell::ResumeRefreshURIs()
5704 RefreshURIFromQueue();
5706 // Resume refresh URIs for our child shells as well.
5707 PRInt32 n
= mChildList
.Count();
5709 for (PRInt32 i
= 0; i
< n
; ++i
) {
5710 nsCOMPtr
<nsIDocShell
> shell
= do_QueryInterface(ChildAt(i
));
5712 shell
->ResumeRefreshURIs();
5719 nsDocShell::RefreshURIFromQueue()
5721 if (!mRefreshURIList
)
5724 mRefreshURIList
->Count(&n
);
5727 nsCOMPtr
<nsISupports
> element
;
5728 mRefreshURIList
->GetElementAt(--n
, getter_AddRefs(element
));
5729 nsCOMPtr
<nsITimerCallback
> refreshInfo(do_QueryInterface(element
));
5732 // This is the nsRefreshTimer object, waiting to be
5733 // setup in a timer object and fired.
5734 // Create the timer and trigger it.
5735 PRUint32 delay
= static_cast<nsRefreshTimer
*>(static_cast<nsITimerCallback
*>(refreshInfo
))->GetDelay();
5736 nsCOMPtr
<nsITimer
> timer
= do_CreateInstance("@mozilla.org/timer;1");
5738 // Replace the nsRefreshTimer element in the queue with
5739 // its corresponding timer object, so that in case another
5740 // load comes through before the timer can go off, the timer will
5741 // get cancelled in CancelRefreshURITimer()
5742 mRefreshURIList
->ReplaceElementAt(timer
, n
);
5743 timer
->InitWithCallback(refreshInfo
, delay
, nsITimer::TYPE_ONE_SHOT
);
5751 //*****************************************************************************
5752 // nsDocShell::nsIContentViewerContainer
5753 //*****************************************************************************
5756 nsDocShell::Embed(nsIContentViewer
* aContentViewer
,
5757 const char *aCommand
, nsISupports
* aExtraInfo
)
5759 // Save the LayoutHistoryState of the previous document, before
5760 // setting up new document
5761 PersistLayoutHistoryState();
5763 nsresult rv
= SetupNewViewer(aContentViewer
);
5765 // If we are loading a wyciwyg url from history, change the base URI for
5766 // the document to the original http url that created the document.write().
5767 // This makes sure that all relative urls in a document.written page loaded
5768 // via history work properly.
5770 (mLoadType
& LOAD_CMD_HISTORY
||
5771 mLoadType
== LOAD_RELOAD_NORMAL
||
5772 mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
)){
5773 PRBool isWyciwyg
= PR_FALSE
;
5774 // Check if the url is wyciwyg
5775 rv
= mCurrentURI
->SchemeIs("wyciwyg", &isWyciwyg
);
5776 if (isWyciwyg
&& NS_SUCCEEDED(rv
))
5777 SetBaseUrlForWyciwyg(aContentViewer
);
5779 // XXX What if SetupNewViewer fails?
5781 // Restore the editing state, if it's stored in session history.
5782 if (mLSHE
->HasDetachedEditor()) {
5783 ReattachEditorToWindow(mLSHE
);
5785 SetHistoryEntry(&mOSHE
, mLSHE
);
5788 PRBool updateHistory
= PR_TRUE
;
5790 // Determine if this type of load should update history
5791 switch (mLoadType
) {
5792 case LOAD_NORMAL_REPLACE
:
5793 case LOAD_STOP_CONTENT_AND_REPLACE
:
5794 case LOAD_RELOAD_BYPASS_CACHE
:
5795 case LOAD_RELOAD_BYPASS_PROXY
:
5796 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
5797 updateHistory
= PR_FALSE
;
5804 SetLayoutHistoryState(nsnull
);
5809 /* void setIsPrinting (in boolean aIsPrinting); */
5811 nsDocShell::SetIsPrinting(PRBool aIsPrinting
)
5813 mIsPrintingOrPP
= aIsPrinting
;
5817 //*****************************************************************************
5818 // nsDocShell::nsIWebProgressListener
5819 //*****************************************************************************
5822 nsDocShell::OnProgressChange(nsIWebProgress
* aProgress
,
5823 nsIRequest
* aRequest
,
5824 PRInt32 aCurSelfProgress
,
5825 PRInt32 aMaxSelfProgress
,
5826 PRInt32 aCurTotalProgress
,
5827 PRInt32 aMaxTotalProgress
)
5833 nsDocShell::OnStateChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
5834 PRUint32 aStateFlags
, nsresult aStatus
)
5838 if ((~aStateFlags
& (STATE_START
| STATE_IS_NETWORK
)) == 0) {
5839 nsCOMPtr
<nsIWyciwygChannel
> wcwgChannel(do_QueryInterface(aRequest
));
5840 nsCOMPtr
<nsIWebProgress
> webProgress
=
5841 do_QueryInterface(GetAsSupports(this));
5843 // Was the wyciwyg document loaded on this docshell?
5844 if (wcwgChannel
&& !mLSHE
&& (mItemType
== typeContent
) && aProgress
== webProgress
.get()) {
5845 nsCOMPtr
<nsIURI
> uri
;
5846 wcwgChannel
->GetURI(getter_AddRefs(uri
));
5848 PRBool equalUri
= PR_TRUE
;
5849 // Store the wyciwyg url in session history, only if it is
5850 // being loaded fresh for the first time. We don't want
5851 // multiple entries for successive loads
5853 NS_SUCCEEDED(uri
->Equals(mCurrentURI
, &equalUri
)) &&
5856 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
5857 GetSameTypeParent(getter_AddRefs(parentAsItem
));
5858 nsCOMPtr
<nsIDocShell
> parentDS(do_QueryInterface(parentAsItem
));
5859 PRBool inOnLoadHandler
= PR_FALSE
;
5861 parentDS
->GetIsExecutingOnLoadHandler(&inOnLoadHandler
);
5863 if (inOnLoadHandler
) {
5864 // We're handling parent's load event listener, which causes
5865 // document.write in a subdocument.
5866 // Need to clear the session history for all child
5867 // docshells so that we can handle them like they would
5868 // all be added dynamically.
5869 nsCOMPtr
<nsIDocShellHistory
> parent
=
5870 do_QueryInterface(parentAsItem
);
5872 PRBool oshe
= PR_FALSE
;
5873 nsCOMPtr
<nsISHEntry
> entry
;
5874 parent
->GetCurrentSHEntry(getter_AddRefs(entry
), &oshe
);
5875 static_cast<nsDocShell
*>(parent
.get())->
5876 ClearFrameHistory(entry
);
5880 // This is a document.write(). Get the made-up url
5881 // from the channel and store it in session history.
5882 rv
= AddToSessionHistory(uri
, wcwgChannel
, nsnull
,
5883 getter_AddRefs(mLSHE
));
5884 SetCurrentURI(uri
, aRequest
, PR_TRUE
);
5885 // Save history state of the previous page
5886 rv
= PersistLayoutHistoryState();
5887 // We'll never get an Embed() for this load, so just go ahead
5888 // and SetHistoryEntry now.
5889 SetHistoryEntry(&mOSHE
, mLSHE
);
5893 // Page has begun to load
5894 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_BEFORE_PAGE_LOAD
;
5896 if ((aStateFlags
& STATE_RESTORING
) == 0) {
5897 // Show the progress cursor if the pref is set
5898 PRBool tmpBool
= PR_FALSE
;
5899 if (NS_SUCCEEDED(mPrefs
->GetBoolPref("ui.use_activity_cursor", &tmpBool
))
5901 nsCOMPtr
<nsIWidget
> mainWidget
;
5902 GetMainWidget(getter_AddRefs(mainWidget
));
5904 mainWidget
->SetCursor(eCursor_spinning
);
5909 else if ((~aStateFlags
& (STATE_TRANSFERRING
| STATE_IS_DOCUMENT
)) == 0) {
5911 mBusyFlags
= BUSY_FLAGS_BUSY
| BUSY_FLAGS_PAGE_LOADING
;
5913 else if ((aStateFlags
& STATE_STOP
) && (aStateFlags
& STATE_IS_NETWORK
)) {
5914 // Page has finished loading
5915 mBusyFlags
= BUSY_FLAGS_NONE
;
5917 // Hide the progress cursor if the pref is set
5918 PRBool tmpBool
= PR_FALSE
;
5919 if (NS_SUCCEEDED(mPrefs
->GetBoolPref("ui.use_activity_cursor", &tmpBool
))
5921 nsCOMPtr
<nsIWidget
> mainWidget
;
5922 GetMainWidget(getter_AddRefs(mainWidget
));
5924 mainWidget
->SetCursor(eCursor_standard
);
5928 if ((~aStateFlags
& (STATE_IS_DOCUMENT
| STATE_STOP
)) == 0) {
5929 nsCOMPtr
<nsIWebProgress
> webProgress
=
5930 do_QueryInterface(GetAsSupports(this));
5931 // Is the document stop notification for this document?
5932 if (aProgress
== webProgress
.get()) {
5933 nsCOMPtr
<nsIChannel
> channel(do_QueryInterface(aRequest
));
5934 EndPageLoad(aProgress
, channel
, aStatus
);
5937 // note that redirect state changes will go through here as well, but it
5938 // is better to handle those in OnRedirectStateChange where more
5939 // information is available.
5944 nsDocShell::OnLocationChange(nsIWebProgress
* aProgress
,
5945 nsIRequest
* aRequest
, nsIURI
* aURI
)
5947 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
5952 nsDocShell::OnRedirectStateChange(nsIChannel
* aOldChannel
,
5953 nsIChannel
* aNewChannel
,
5954 PRUint32 aRedirectFlags
,
5955 PRUint32 aStateFlags
)
5957 NS_ASSERTION(aStateFlags
& STATE_REDIRECTING
,
5958 "Calling OnRedirectStateChange when there is no redirect");
5959 if (!(aStateFlags
& STATE_IS_DOCUMENT
))
5960 return; // not a toplevel document
5962 nsCOMPtr
<nsIURI
> oldURI
, newURI
;
5963 aOldChannel
->GetURI(getter_AddRefs(oldURI
));
5964 aNewChannel
->GetURI(getter_AddRefs(newURI
));
5965 if (!oldURI
|| !newURI
) {
5969 // Below a URI visit is saved (see AddURIVisit method doc).
5970 // The visit chain looks something like:
5974 // (redirect to =>) Site N + 1 (we are here!)
5976 // Get N - 1 and transition type
5977 nsCOMPtr
<nsIURI
> previousURI
;
5978 PRUint32 previousFlags
= 0;
5979 ExtractLastVisit(aOldChannel
, getter_AddRefs(previousURI
), &previousFlags
);
5981 if (aRedirectFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
||
5982 ChannelIsPost(aOldChannel
)) {
5983 // 1. Internal redirects are ignored because they are specific to the
5984 // channel implementation.
5985 // 2. POSTs are not saved by global history.
5987 // Regardless, we need to propagate the previous visit to the new
5989 SaveLastVisit(aNewChannel
, previousURI
, previousFlags
);
5992 nsCOMPtr
<nsIURI
> referrer
;
5993 // Treat referrer as null if there is an error getting it.
5994 (void)NS_GetReferrerFromChannel(aOldChannel
,
5995 getter_AddRefs(referrer
));
5997 // Add visit N -1 => N
5998 AddURIVisit(oldURI
, referrer
, previousURI
, previousFlags
);
6000 // Since N + 1 could be the final destination, we will not save N => N + 1
6001 // here. OnNewURI will do that, so we will cache it.
6002 SaveLastVisit(aNewChannel
, oldURI
, aRedirectFlags
);
6005 // check if the new load should go through the application cache.
6006 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
6007 do_QueryInterface(aNewChannel
);
6008 if (appCacheChannel
) {
6010 // Permission will be checked in the parent process.
6011 if (GeckoProcessType_Default
!= XRE_GetProcessType())
6012 appCacheChannel
->SetChooseApplicationCache(PR_TRUE
);
6015 appCacheChannel
->SetChooseApplicationCache(ShouldCheckAppCache(newURI
));
6018 if (!(aRedirectFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
) &&
6019 mLoadType
& (LOAD_CMD_RELOAD
| LOAD_CMD_HISTORY
)) {
6020 mLoadType
= LOAD_NORMAL_REPLACE
;
6021 SetHistoryEntry(&mLSHE
, nsnull
);
6026 nsDocShell::OnStatusChange(nsIWebProgress
* aWebProgress
,
6027 nsIRequest
* aRequest
,
6028 nsresult aStatus
, const PRUnichar
* aMessage
)
6030 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6035 nsDocShell::OnSecurityChange(nsIWebProgress
* aWebProgress
,
6036 nsIRequest
* aRequest
, PRUint32 state
)
6038 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6044 nsDocShell::EndPageLoad(nsIWebProgress
* aProgress
,
6045 nsIChannel
* aChannel
, nsresult aStatus
)
6048 return NS_ERROR_NULL_POINTER
;
6050 nsCOMPtr
<nsIURI
> url
;
6051 nsresult rv
= aChannel
->GetURI(getter_AddRefs(url
));
6052 if (NS_FAILED(rv
)) return rv
;
6054 // clean up reload state for meta charset
6055 if (eCharsetReloadRequested
== mCharsetReloadState
)
6056 mCharsetReloadState
= eCharsetReloadStopOrigional
;
6058 mCharsetReloadState
= eCharsetReloadInit
;
6060 // Save a pointer to the currently-loading history entry.
6061 // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
6062 // entry further down in this method.
6063 nsCOMPtr
<nsISHEntry
> loadingSHE
= mLSHE
;
6066 // one of many safeguards that prevent death and destruction if
6067 // someone is so very very rude as to bring this window down
6068 // during this load handler.
6070 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
6072 // Notify the ContentViewer that the Document has finished loading. This
6073 // will cause any OnLoad(...) and PopState(...) handlers to fire.
6074 if (!mEODForCurrentDocument
&& mContentViewer
) {
6075 // Set the pending state object which will be returned to the page in
6076 // the popstate event.
6077 SetDocCurrentStateObj(mLSHE
);
6079 mIsExecutingOnLoadHandler
= PR_TRUE
;
6080 rv
= mContentViewer
->LoadComplete(aStatus
);
6082 // If the load wasn't stopped during LoadComplete, fire the popstate
6083 // event, if we're not suppressing it.
6084 if (NS_SUCCEEDED(rv
) && rv
!= NS_SUCCESS_LOAD_STOPPED
&&
6085 !mSuppressPopstate
) {
6087 // XXX should I get the window via mScriptGlobal? This is tricky
6088 // since we're near onload and things might be changing. But I
6089 // think mContentViewer has the right view of the world.
6090 nsCOMPtr
<nsIDocument
> document
= mContentViewer
->GetDocument();
6092 nsCOMPtr
<nsPIDOMWindow
> window
= document
->GetWindow();
6094 // Dispatch the popstate event , passing PR_TRUE to indicate
6095 // that this is an "initial" (i.e. after-onload) popstate.
6096 window
->DispatchSyncPopState(PR_TRUE
);
6101 mIsExecutingOnLoadHandler
= PR_FALSE
;
6103 mEODForCurrentDocument
= PR_TRUE
;
6105 // If all documents have completed their loading
6106 // favor native event dispatch priorities
6108 if (--gNumberOfDocumentsLoading
== 0) {
6109 // Hint to use normal native event dispatch priorities
6110 FavorPerformanceHint(PR_FALSE
, NS_EVENT_STARVATION_DELAY_HINT
);
6113 /* Check if the httpChannel has any cache-control related response headers,
6114 * like no-store, no-cache. If so, update SHEntry so that
6115 * when a user goes back/forward to this page, we appropriately do
6116 * form value restoration or load from server.
6118 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
6119 if (!httpChannel
) // HttpChannel could be hiding underneath a Multipart channel.
6120 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
6123 // figure out if SH should be saving layout state.
6124 PRBool discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
6125 if (mLSHE
&& discardLayoutState
&& (mLoadType
& LOAD_CMD_NORMAL
) &&
6126 (mLoadType
!= LOAD_BYPASS_HISTORY
) && (mLoadType
!= LOAD_ERROR_PAGE
))
6127 mLSHE
->SetSaveLayoutStateFlag(PR_FALSE
);
6130 // Clear mLSHE after calling the onLoadHandlers. This way, if the
6131 // onLoadHandler tries to load something different in
6132 // itself or one of its children, we can deal with it appropriately.
6134 mLSHE
->SetLoadType(nsIDocShellLoadInfo::loadHistory
);
6136 // Clear the mLSHE reference to indicate document loading is done one
6138 SetHistoryEntry(&mLSHE
, nsnull
);
6140 // if there's a refresh header in the channel, this method
6141 // will set it up for us.
6142 RefreshURIFromQueue();
6144 // Test whether this is the top frame or a subframe
6145 PRBool isTopFrame
= PR_TRUE
;
6146 nsCOMPtr
<nsIDocShellTreeItem
> targetParentTreeItem
;
6147 rv
= GetSameTypeParent(getter_AddRefs(targetParentTreeItem
));
6148 if (NS_SUCCEEDED(rv
) && targetParentTreeItem
) {
6149 isTopFrame
= PR_FALSE
;
6153 // If the page load failed, then deal with the error condition...
6154 // Errors are handled as follows:
6155 // 1. Check to see if it's a file not found error or bad content
6157 // 2. Send the URI to a keyword server (if enabled)
6158 // 3. If the error was DNS failure, then add www and .com to the URI
6159 // (if appropriate).
6160 // 4. Throw an error dialog box...
6162 if (url
&& NS_FAILED(aStatus
)) {
6163 if (aStatus
== NS_ERROR_FILE_NOT_FOUND
||
6164 aStatus
== NS_ERROR_INVALID_CONTENT_ENCODING
) {
6165 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
6171 // Try and make an alternative URI from the old one
6173 nsCOMPtr
<nsIURI
> newURI
;
6175 nsCAutoString oldSpec
;
6176 url
->GetSpec(oldSpec
);
6179 // First try keyword fixup
6181 if (aStatus
== NS_ERROR_UNKNOWN_HOST
&& mAllowKeywordFixup
) {
6182 PRBool keywordsEnabled
= PR_FALSE
;
6185 NS_FAILED(mPrefs
->GetBoolPref("keyword.enabled",
6187 keywordsEnabled
= PR_FALSE
;
6192 nsCAutoString scheme
;
6193 url
->GetScheme(scheme
);
6195 PRInt32 dotLoc
= host
.FindChar('.');
6197 // we should only perform a keyword search under the following
6199 // (0) Pref keyword.enabled is true
6200 // (1) the url scheme is http (or https)
6201 // (2) the url does not have a protocol scheme
6202 // If we don't enforce such a policy, then we end up doing
6203 // keyword searchs on urls we don't intend like imap, file,
6204 // mailbox, etc. This could lead to a security problem where we
6205 // send data to the keyword server that we shouldn't be.
6206 // Someone needs to clean up keywords in general so we can
6207 // determine on a per url basis if we want keywords
6208 // enabled...this is just a bandaid...
6209 if (keywordsEnabled
&& !scheme
.IsEmpty() &&
6210 (scheme
.Find("http") != 0)) {
6211 keywordsEnabled
= PR_FALSE
;
6214 if (keywordsEnabled
&& (kNotFound
== dotLoc
)) {
6215 // only send non-qualified hosts to the keyword server
6217 // If this string was passed through nsStandardURL by
6218 // chance, then it may have been converted from UTF-8 to
6219 // ACE, which would result in a completely bogus keyword
6220 // query. Here we try to recover the original Unicode
6221 // value, but this is not 100% correct since the value may
6222 // have been normalized per the IDN normalization rules.
6224 // Since we don't have access to the exact original string
6225 // that was entered by the user, this will just have to do.
6227 nsCAutoString utf8Host
;
6228 nsCOMPtr
<nsIIDNService
> idnSrv
=
6229 do_GetService(NS_IDNSERVICE_CONTRACTID
);
6231 NS_SUCCEEDED(idnSrv
->IsACE(host
, &isACE
)) && isACE
&&
6232 NS_SUCCEEDED(idnSrv
->ConvertACEtoUTF8(host
, utf8Host
)))
6233 sURIFixup
->KeywordToURI(utf8Host
,
6234 getter_AddRefs(newURI
));
6236 sURIFixup
->KeywordToURI(host
, getter_AddRefs(newURI
));
6237 } // end keywordsEnabled
6241 // Now try change the address, e.g. turn http://foo into
6242 // http://www.foo.com
6244 if (aStatus
== NS_ERROR_UNKNOWN_HOST
||
6245 aStatus
== NS_ERROR_NET_RESET
) {
6246 PRBool doCreateAlternate
= PR_TRUE
;
6248 // Skip fixup for anything except a normal document load
6249 // operation on the topframe.
6251 if (mLoadType
!= LOAD_NORMAL
|| !isTopFrame
) {
6252 doCreateAlternate
= PR_FALSE
;
6255 // Test if keyword lookup produced a new URI or not
6257 PRBool sameURI
= PR_FALSE
;
6258 url
->Equals(newURI
, &sameURI
);
6260 // Keyword lookup made a new URI so no need to try
6261 // an alternate one.
6262 doCreateAlternate
= PR_FALSE
;
6266 if (doCreateAlternate
) {
6268 sURIFixup
->CreateFixupURI(oldSpec
,
6269 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
,
6270 getter_AddRefs(newURI
));
6274 // Did we make a new URI that is different to the old one? If so
6278 // Make sure the new URI is different from the old one,
6279 // otherwise there's little point trying to load it again.
6280 PRBool sameURI
= PR_FALSE
;
6281 url
->Equals(newURI
, &sameURI
);
6283 nsCAutoString newSpec
;
6284 newURI
->GetSpec(newSpec
);
6285 NS_ConvertUTF8toUTF16
newSpecW(newSpec
);
6287 return LoadURI(newSpecW
.get(), // URI string
6288 LOAD_FLAGS_NONE
, // Load flags
6289 nsnull
, // Referring URI
6290 nsnull
, // Post data stream
6291 nsnull
); // Headers stream
6296 // Well, fixup didn't work :-(
6297 // It is time to throw an error dialog box, and be done with it...
6299 // Errors to be shown only on top-level frames
6300 if ((aStatus
== NS_ERROR_UNKNOWN_HOST
||
6301 aStatus
== NS_ERROR_CONNECTION_REFUSED
||
6302 aStatus
== NS_ERROR_UNKNOWN_PROXY_HOST
||
6303 aStatus
== NS_ERROR_PROXY_CONNECTION_REFUSED
) &&
6304 (isTopFrame
|| mUseErrorPages
)) {
6305 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
6307 // Errors to be shown for any frame
6308 else if (aStatus
== NS_ERROR_NET_TIMEOUT
||
6309 aStatus
== NS_ERROR_REDIRECT_LOOP
||
6310 aStatus
== NS_ERROR_UNKNOWN_SOCKET_TYPE
||
6311 aStatus
== NS_ERROR_NET_INTERRUPT
||
6312 aStatus
== NS_ERROR_NET_RESET
||
6313 aStatus
== NS_ERROR_MALWARE_URI
||
6314 aStatus
== NS_ERROR_PHISHING_URI
||
6315 aStatus
== NS_ERROR_UNSAFE_CONTENT_TYPE
||
6316 aStatus
== NS_ERROR_REMOTE_XUL
||
6317 NS_ERROR_GET_MODULE(aStatus
) == NS_ERROR_MODULE_SECURITY
) {
6318 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
6320 else if (aStatus
== NS_ERROR_DOCUMENT_NOT_CACHED
) {
6321 /* A document that was requested to be fetched *only* from
6322 * the cache is not in cache. May be this is one of those
6323 * postdata results. Throw a dialog to the user,
6324 * saying that the page has expired from cache and ask if
6325 * they wish to refetch the page from the net. Do this only
6326 * if the request is a form post.
6328 nsCAutoString method
;
6330 httpChannel
->GetRequestMethod(method
);
6331 if (method
.Equals("POST") && !NS_IsOffline()) {
6333 rv
= ConfirmRepost(&repost
);
6334 if (NS_FAILED(rv
)) return rv
;
6335 // If the user pressed cancel in the dialog, return. Don't try
6336 // to load the page without the post data.
6340 // The user wants to repost the data to the server.
6341 // If the page was loaded due to a back/forward/go
6342 // operation, update the session history index.
6343 // This is similar to the updating done in
6344 // nsDocShell::OnNewURI() for regular pages
6345 nsCOMPtr
<nsISHistory
> rootSH
=mSessionHistory
;
6346 if (!mSessionHistory
) {
6347 nsCOMPtr
<nsIDocShellTreeItem
> root
;
6348 //Get the root docshell
6349 GetSameTypeRootTreeItem(getter_AddRefs(root
));
6351 // QI root to nsIWebNavigation
6352 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav
=
6353 do_QueryInterface(root
);
6355 // Get the handle to SH from the root docshell
6356 rootAsWebnav
->GetSessionHistory(getter_AddRefs(rootSH
));
6359 } // mSessionHistory
6361 if (rootSH
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
6362 nsCOMPtr
<nsISHistoryInternal
> shInternal
=
6363 do_QueryInterface(rootSH
);
6365 rootSH
->GetIndex(&mPreviousTransIndex
);
6366 shInternal
->UpdateIndex();
6367 rootSH
->GetIndex(&mLoadedTransIndex
);
6368 #ifdef DEBUG_PAGE_CACHE
6369 printf("Previous index: %d, Loaded index: %d\n\n",
6370 mPreviousTransIndex
, mLoadedTransIndex
);
6375 // Make it look like we really did honestly finish loading the
6376 // history page we were loading, since the "reload" load we're
6377 // about to kick off will reload our current history entry.
6378 // This is a bit of a hack, and if the force-load fails I think
6379 // we'll end up being confused about what page we're on... but
6380 // we would anyway, since we've updated the session history
6382 SetHistoryEntry(&mOSHE
, loadingSHE
);
6384 // The user does want to repost the data to the server.
6385 // Initiate a new load again.
6387 // Get the postdata if any from the channel.
6388 nsCOMPtr
<nsIInputStream
> inputStream
;
6389 nsCOMPtr
<nsIURI
> referrer
;
6391 httpChannel
->GetReferrer(getter_AddRefs(referrer
));
6392 nsCOMPtr
<nsIUploadChannel
> uploadChannel
=
6393 do_QueryInterface(aChannel
);
6394 if (uploadChannel
) {
6395 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
6398 nsCOMPtr
<nsISeekableStream
> postDataSeekable
=
6399 do_QueryInterface(inputStream
);
6400 if (postDataSeekable
) {
6401 postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
6403 InternalLoad(url
, // URI
6404 referrer
, // Referring URI
6406 INTERNAL_LOAD_FLAGS_INHERIT_OWNER
, // Inherit owner
6407 nsnull
, // No window target
6408 nsnull
, // No type hint
6409 inputStream
, // Post data stream
6410 nsnull
, // No headers stream
6411 LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
,// Load type
6412 nsnull
, // No SHEntry
6413 PR_TRUE
, // first party site
6414 nsnull
, // No nsIDocShell
6415 nsnull
); // No nsIRequest
6418 DisplayLoadError(aStatus
, url
, nsnull
, aChannel
);
6421 } // if we have a host
6427 //*****************************************************************************
6428 // nsDocShell: Content Viewer Management
6429 //*****************************************************************************
6432 nsDocShell::EnsureContentViewer()
6436 if (mIsBeingDestroyed
)
6437 return NS_ERROR_FAILURE
;
6441 nsIPrincipal
* principal
= nsnull
;
6442 nsCOMPtr
<nsIURI
> baseURI
;
6444 nsCOMPtr
<nsPIDOMWindow
> piDOMWindow(do_QueryInterface(mScriptGlobal
));
6446 principal
= piDOMWindow
->GetOpenerScriptPrincipal();
6450 principal
= GetInheritedPrincipal(PR_FALSE
);
6451 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
6452 GetSameTypeParent(getter_AddRefs(parentItem
));
6454 nsCOMPtr
<nsPIDOMWindow
> domWin
= do_GetInterface(GetAsSupports(this));
6456 nsCOMPtr
<nsIContent
> parentContent
=
6457 do_QueryInterface(domWin
->GetFrameElementInternal());
6458 if (parentContent
) {
6459 baseURI
= parentContent
->GetBaseURI();
6465 nsresult rv
= CreateAboutBlankContentViewer(principal
, baseURI
);
6467 if (NS_SUCCEEDED(rv
)) {
6468 nsCOMPtr
<nsIDocument
> doc(do_GetInterface(GetAsSupports(this)));
6470 "Should have doc if CreateAboutBlankContentViewer "
6473 doc
->SetIsInitialDocument(PR_TRUE
);
6480 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal
* aPrincipal
,
6482 PRBool aTryToSaveOldPresentation
)
6484 nsCOMPtr
<nsIDocument
> blankDoc
;
6485 nsCOMPtr
<nsIContentViewer
> viewer
;
6486 nsresult rv
= NS_ERROR_FAILURE
;
6488 /* mCreatingDocument should never be true at this point. However, it's
6489 a theoretical possibility. We want to know about it and make it stop,
6490 and this sounds like a job for an assertion. */
6491 NS_ASSERTION(!mCreatingDocument
, "infinite(?) loop creating document averted");
6492 if (mCreatingDocument
)
6493 return NS_ERROR_FAILURE
;
6495 mCreatingDocument
= PR_TRUE
;
6497 // mContentViewer->PermitUnload may release |this| docshell.
6498 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
6500 if (mContentViewer
) {
6501 // We've got a content viewer already. Make sure the user
6502 // permits us to discard the current document and replace it
6503 // with about:blank. And also ensure we fire the unload events
6504 // in the current document.
6507 rv
= mContentViewer
->PermitUnload(PR_FALSE
, &okToUnload
);
6509 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
6510 // The user chose not to unload the page, interrupt the load.
6511 return NS_ERROR_FAILURE
;
6514 mSavingOldViewer
= aTryToSaveOldPresentation
&&
6515 CanSavePresentation(LOAD_NORMAL
, nsnull
, nsnull
);
6517 // Make sure to blow away our mLoadingURI just in case. No loads
6518 // from inside this pagehide.
6519 mLoadingURI
= nsnull
;
6521 // Notify the current document that it is about to be unloaded!!
6523 // It is important to fire the unload() notification *before* any state
6524 // is changed within the DocShell - otherwise, javascript will get the
6525 // wrong information :-(
6527 (void) FirePageHideNotification(!mSavingOldViewer
);
6530 // Now make sure we don't think we're in the middle of firing unload after
6531 // this point. This will make us fire unload when the about:blank document
6532 // unloads... but that's ok, more or less. Would be nice if it fired load
6534 mFiredUnloadEvent
= PR_FALSE
;
6536 nsCOMPtr
<nsIContentUtils
> cutils
= do_GetService("@mozilla.org/content/contentutils;1");
6538 return NS_ERROR_FAILURE
;
6540 nsCOMPtr
<nsIDocumentLoaderFactory
> docFactory
= cutils
->FindInternalContentViewer("text/html");
6542 // generate (about:blank) document to load
6543 docFactory
->CreateBlankDocument(mLoadGroup
, aPrincipal
,
6544 getter_AddRefs(blankDoc
));
6546 // Hack: set the base URI manually, since this document never
6547 // got Reset() with a channel.
6548 blankDoc
->SetBaseURI(aBaseURI
);
6550 blankDoc
->SetContainer(static_cast<nsIDocShell
*>(this));
6552 // create a content viewer for us and the new document
6553 docFactory
->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell
*, this),
6554 blankDoc
, "view", getter_AddRefs(viewer
));
6558 viewer
->SetContainer(static_cast<nsIContentViewerContainer
*>(this));
6559 Embed(viewer
, "", 0);
6561 SetCurrentURI(blankDoc
->GetDocumentURI(), nsnull
, PR_TRUE
);
6562 rv
= mIsBeingDestroyed
? NS_ERROR_NOT_AVAILABLE
: NS_OK
;
6566 mCreatingDocument
= PR_FALSE
;
6568 // The transient about:blank viewer doesn't have a session history entry.
6569 SetHistoryEntry(&mOSHE
, nsnull
);
6575 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal
*aPrincipal
)
6577 return CreateAboutBlankContentViewer(aPrincipal
, nsnull
);
6581 nsDocShell::CanSavePresentation(PRUint32 aLoadType
,
6582 nsIRequest
*aNewRequest
,
6583 nsIDocument
*aNewDocument
)
6586 return PR_FALSE
; // no entry to save into
6588 nsCOMPtr
<nsIContentViewer
> viewer
;
6589 mOSHE
->GetContentViewer(getter_AddRefs(viewer
));
6591 NS_WARNING("mOSHE already has a content viewer!");
6595 // Only save presentation for "normal" loads and link loads. Anything else
6596 // probably wants to refetch the page, so caching the old presentation
6597 // would be incorrect.
6598 if (aLoadType
!= LOAD_NORMAL
&&
6599 aLoadType
!= LOAD_HISTORY
&&
6600 aLoadType
!= LOAD_LINK
&&
6601 aLoadType
!= LOAD_STOP_CONTENT
&&
6602 aLoadType
!= LOAD_STOP_CONTENT_AND_REPLACE
&&
6603 aLoadType
!= LOAD_ERROR_PAGE
)
6606 // If the session history entry has the saveLayoutState flag set to false,
6607 // then we should not cache the presentation.
6608 PRBool canSaveState
;
6609 mOSHE
->GetSaveLayoutStateFlag(&canSaveState
);
6613 // If the document is not done loading, don't cache it.
6614 nsCOMPtr
<nsPIDOMWindow
> pWin
= do_QueryInterface(mScriptGlobal
);
6615 if (!pWin
|| pWin
->IsLoading())
6618 if (pWin
->WouldReuseInnerWindow(aNewDocument
))
6621 // Avoid doing the work of saving the presentation state in the case where
6622 // the content viewer cache is disabled.
6623 if (nsSHistory::GetMaxTotalViewers() == 0)
6626 // Don't cache the content viewer if we're in a subframe and the subframe
6627 // pref is disabled.
6628 PRBool cacheFrames
= PR_FALSE
;
6629 mPrefs
->GetBoolPref("browser.sessionhistory.cache_subframes",
6632 nsCOMPtr
<nsIDocShellTreeItem
> root
;
6633 GetSameTypeParent(getter_AddRefs(root
));
6634 if (root
&& root
!= this) {
6635 return PR_FALSE
; // this is a subframe load
6639 // If the document does not want its presentation cached, then don't.
6640 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(pWin
->GetExtantDocument());
6641 if (!doc
|| !doc
->CanSavePresentation(aNewRequest
))
6648 nsDocShell::ReattachEditorToWindow(nsISHEntry
*aSHEntry
)
6650 NS_ASSERTION(!mEditorData
,
6651 "Why reattach an editor when we already have one?");
6652 NS_ASSERTION(aSHEntry
&& aSHEntry
->HasDetachedEditor(),
6653 "Reattaching when there's not a detached editor.");
6655 if (mEditorData
|| !aSHEntry
)
6658 mEditorData
= aSHEntry
->ForgetEditorData();
6663 mEditorData
->ReattachToWindow(this);
6664 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to reattach editing session");
6669 nsDocShell::DetachEditorFromWindow()
6671 if (!mEditorData
|| mEditorData
->WaitingForLoad()) {
6672 // If there's nothing to detach, or if the editor data is actually set
6673 // up for the _new_ page that's coming in, don't detach.
6677 NS_ASSERTION(!mOSHE
|| !mOSHE
->HasDetachedEditor(),
6678 "Detaching editor when it's already detached.");
6680 nsresult res
= mEditorData
->DetachFromWindow();
6681 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to detach editor");
6683 if (NS_SUCCEEDED(res
)) {
6684 // Make mOSHE hold the owning ref to the editor data.
6686 mOSHE
->SetEditorData(mEditorData
.forget());
6688 mEditorData
= nsnull
;
6694 GetEditable(&isEditable
);
6695 NS_ASSERTION(!isEditable
,
6696 "Window is still editable after detaching editor.");
6702 nsDocShell::CaptureState()
6704 if (!mOSHE
|| mOSHE
== mLSHE
) {
6705 // No entry to save into, or we're replacing the existing entry.
6706 return NS_ERROR_FAILURE
;
6709 nsCOMPtr
<nsPIDOMWindow
> privWin
= do_QueryInterface(mScriptGlobal
);
6711 return NS_ERROR_FAILURE
;
6713 nsCOMPtr
<nsISupports
> windowState
;
6714 nsresult rv
= privWin
->SaveWindowState(getter_AddRefs(windowState
));
6715 NS_ENSURE_SUCCESS(rv
, rv
);
6717 #ifdef DEBUG_PAGE_CACHE
6718 nsCOMPtr
<nsIURI
> uri
;
6719 mOSHE
->GetURI(getter_AddRefs(uri
));
6723 printf("Saving presentation into session history\n");
6724 printf(" SH URI: %s\n", spec
.get());
6727 rv
= mOSHE
->SetWindowState(windowState
);
6728 NS_ENSURE_SUCCESS(rv
, rv
);
6730 // Suspend refresh URIs and save off the timer queue
6731 rv
= mOSHE
->SetRefreshURIList(mSavedRefreshURIList
);
6732 NS_ENSURE_SUCCESS(rv
, rv
);
6734 // Capture the current content viewer bounds.
6735 if (mContentViewer
) {
6737 mContentViewer
->GetBounds(bounds
);
6738 rv
= mOSHE
->SetViewerBounds(bounds
);
6739 NS_ENSURE_SUCCESS(rv
, rv
);
6742 // Capture the docshell hierarchy.
6743 mOSHE
->ClearChildShells();
6745 PRInt32 childCount
= mChildList
.Count();
6746 for (PRInt32 i
= 0; i
< childCount
; ++i
) {
6747 nsCOMPtr
<nsIDocShellTreeItem
> childShell
= do_QueryInterface(ChildAt(i
));
6748 NS_ASSERTION(childShell
, "null child shell");
6750 mOSHE
->AddChildShell(childShell
);
6757 nsDocShell::RestorePresentationEvent::Run()
6759 if (mDocShell
&& NS_FAILED(mDocShell
->RestoreFromHistory()))
6760 NS_WARNING("RestoreFromHistory failed");
6765 nsDocShell::BeginRestore(nsIContentViewer
*aContentViewer
, PRBool aTop
)
6768 if (!aContentViewer
) {
6769 rv
= EnsureContentViewer();
6770 NS_ENSURE_SUCCESS(rv
, rv
);
6772 aContentViewer
= mContentViewer
;
6775 // Dispatch events for restoring the presentation. We try to simulate
6776 // the progress notifications loading the document would cause, so we add
6777 // the document's channel to the loadgroup to initiate stateChange
6780 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6781 aContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6782 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
6784 nsIChannel
*channel
= doc
->GetChannel();
6786 mEODForCurrentDocument
= PR_FALSE
;
6787 mIsRestoringDocument
= PR_TRUE
;
6788 mLoadGroup
->AddRequest(channel
, nsnull
);
6789 mIsRestoringDocument
= PR_FALSE
;
6794 // This point corresponds to us having gotten OnStartRequest or
6795 // STATE_START, so do the same thing that CreateContentViewer does at
6796 // this point to ensure that unload/pagehide events for this document
6797 // will fire when it's unloaded again.
6798 mFiredUnloadEvent
= PR_FALSE
;
6800 // For non-top frames, there is no notion of making sure that the
6801 // previous document is in the domwindow when STATE_START notifications
6802 // happen. We can just call BeginRestore for all of the child shells
6804 rv
= BeginRestoreChildren();
6805 NS_ENSURE_SUCCESS(rv
, rv
);
6812 nsDocShell::BeginRestoreChildren()
6814 PRInt32 n
= mChildList
.Count();
6815 for (PRInt32 i
= 0; i
< n
; ++i
) {
6816 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
6818 nsresult rv
= child
->BeginRestore(nsnull
, PR_FALSE
);
6819 NS_ENSURE_SUCCESS(rv
, rv
);
6826 nsDocShell::FinishRestore()
6828 // First we call finishRestore() on our children. In the simulated load,
6829 // all of the child frames finish loading before the main document.
6831 PRInt32 n
= mChildList
.Count();
6832 for (PRInt32 i
= 0; i
< n
; ++i
) {
6833 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
6835 child
->FinishRestore();
6839 if (mOSHE
&& mOSHE
->HasDetachedEditor()) {
6840 ReattachEditorToWindow(mOSHE
);
6843 nsCOMPtr
<nsIDocument
> doc
= do_GetInterface(GetAsSupports(this));
6845 // Finally, we remove the request from the loadgroup. This will
6846 // cause onStateChange(STATE_STOP) to fire, which will fire the
6847 // pageshow event to the chrome.
6849 nsIChannel
*channel
= doc
->GetChannel();
6851 mIsRestoringDocument
= PR_TRUE
;
6852 mLoadGroup
->RemoveRequest(channel
, nsnull
, NS_OK
);
6853 mIsRestoringDocument
= PR_FALSE
;
6861 nsDocShell::GetRestoringDocument(PRBool
*aRestoring
)
6863 *aRestoring
= mIsRestoringDocument
;
6868 nsDocShell::RestorePresentation(nsISHEntry
*aSHEntry
, PRBool
*aRestoring
)
6870 NS_ASSERTION(mLoadType
& LOAD_CMD_HISTORY
,
6871 "RestorePresentation should only be called for history loads");
6873 nsCOMPtr
<nsIContentViewer
> viewer
;
6874 aSHEntry
->GetContentViewer(getter_AddRefs(viewer
));
6876 #ifdef DEBUG_PAGE_CACHE
6877 nsCOMPtr
<nsIURI
> uri
;
6878 aSHEntry
->GetURI(getter_AddRefs(uri
));
6885 *aRestoring
= PR_FALSE
;
6888 #ifdef DEBUG_PAGE_CACHE
6889 printf("no saved presentation for uri: %s\n", spec
.get());
6894 // We need to make sure the content viewer's container is this docshell.
6895 // In subframe navigation, it's possible for the docshell that the
6896 // content viewer was originally loaded into to be replaced with a
6897 // different one. We don't currently support restoring the presentation
6900 nsCOMPtr
<nsISupports
> container
;
6901 viewer
->GetContainer(getter_AddRefs(container
));
6902 if (!::SameCOMIdentity(container
, GetAsSupports(this))) {
6903 #ifdef DEBUG_PAGE_CACHE
6904 printf("No valid container, clearing presentation\n");
6906 aSHEntry
->SetContentViewer(nsnull
);
6907 return NS_ERROR_FAILURE
;
6910 NS_ASSERTION(mContentViewer
!= viewer
, "Restoring existing presentation");
6912 #ifdef DEBUG_PAGE_CACHE
6913 printf("restoring presentation from session history: %s\n", spec
.get());
6916 SetHistoryEntry(&mLSHE
, aSHEntry
);
6918 // Add the request to our load group. We do this before swapping out
6919 // the content viewers so that consumers of STATE_START can access
6920 // the old document. We only deal with the toplevel load at this time --
6921 // to be consistent with normal document loading, subframes cannot start
6922 // loading until after data arrives, which is after STATE_START completes.
6924 BeginRestore(viewer
, PR_TRUE
);
6926 // Post an event that will remove the request after we've returned
6927 // to the event loop. This mimics the way it is called by nsIChannel
6930 // Revoke any pending restore (just in case)
6931 NS_ASSERTION(!mRestorePresentationEvent
.IsPending(),
6932 "should only have one RestorePresentationEvent");
6933 mRestorePresentationEvent
.Revoke();
6935 nsRefPtr
<RestorePresentationEvent
> evt
= new RestorePresentationEvent(this);
6936 nsresult rv
= NS_DispatchToCurrentThread(evt
);
6937 if (NS_SUCCEEDED(rv
)) {
6938 mRestorePresentationEvent
= evt
.get();
6939 // The rest of the restore processing will happen on our event
6941 *aRestoring
= PR_TRUE
;
6948 nsDocShell::RestoreFromHistory()
6950 mRestorePresentationEvent
.Forget();
6952 // This section of code follows the same ordering as CreateContentViewer.
6954 return NS_ERROR_FAILURE
;
6956 nsCOMPtr
<nsIContentViewer
> viewer
;
6957 mLSHE
->GetContentViewer(getter_AddRefs(viewer
));
6959 return NS_ERROR_FAILURE
;
6961 if (mSavingOldViewer
) {
6962 // We determined that it was safe to cache the document presentation
6963 // at the time we initiated the new load. We need to check whether
6964 // it's still safe to do so, since there may have been DOM mutations
6965 // or new requests initiated.
6966 nsCOMPtr
<nsIDOMDocument
> domDoc
;
6967 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
6968 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
6969 nsIRequest
*request
= nsnull
;
6971 request
= doc
->GetChannel();
6972 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
6975 nsCOMPtr
<nsIMarkupDocumentViewer
> oldMUDV(do_QueryInterface(mContentViewer
));
6976 nsCOMPtr
<nsIMarkupDocumentViewer
> newMUDV(do_QueryInterface(viewer
));
6977 float textZoom
= 1.0f
;
6978 float pageZoom
= 1.0f
;
6979 PRBool styleDisabled
= PR_FALSE
;
6980 if (oldMUDV
&& newMUDV
) {
6981 oldMUDV
->GetTextZoom(&textZoom
);
6982 oldMUDV
->GetFullZoom(&pageZoom
);
6983 oldMUDV
->GetAuthorStyleDisabled(&styleDisabled
);
6986 // Protect against mLSHE going away via a load triggered from
6987 // pagehide or unload.
6988 nsCOMPtr
<nsISHEntry
> origLSHE
= mLSHE
;
6990 // Make sure to blow away our mLoadingURI just in case. No loads
6991 // from inside this pagehide.
6992 mLoadingURI
= nsnull
;
6994 // Notify the old content viewer that it's being hidden.
6995 FirePageHideNotification(!mSavingOldViewer
);
6997 // If mLSHE was changed as a result of the pagehide event, then
6998 // something else was loaded. Don't finish restoring.
6999 if (mLSHE
!= origLSHE
)
7002 // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
7003 // *new* document will fire.
7004 mFiredUnloadEvent
= PR_FALSE
;
7006 mURIResultedInDocument
= PR_TRUE
;
7007 nsCOMPtr
<nsISHistory
> rootSH
;
7008 GetRootSessionHistory(getter_AddRefs(rootSH
));
7010 nsCOMPtr
<nsISHistoryInternal
> hist
= do_QueryInterface(rootSH
);
7011 rootSH
->GetIndex(&mPreviousTransIndex
);
7012 hist
->UpdateIndex();
7013 rootSH
->GetIndex(&mLoadedTransIndex
);
7014 #ifdef DEBUG_PAGE_CACHE
7015 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex
,
7020 // Rather than call Embed(), we will retrieve the viewer from the session
7021 // history entry and swap it in.
7022 // XXX can we refactor this so that we can just call Embed()?
7023 PersistLayoutHistoryState();
7025 if (mContentViewer
) {
7026 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
7028 mOSHE
->SyncPresentationState();
7030 mSavingOldViewer
= PR_FALSE
;
7034 mSavedRefreshURIList
= nsnull
;
7036 // In cases where we use a transient about:blank viewer between loads,
7037 // we never show the transient viewer, so _its_ previous viewer is never
7038 // unhooked from the view hierarchy. Destroy any such previous viewer now,
7039 // before we grab the root view sibling, so that we don't grab a view
7040 // that's about to go away.
7042 if (mContentViewer
) {
7043 nsCOMPtr
<nsIContentViewer
> previousViewer
;
7044 mContentViewer
->GetPreviousViewer(getter_AddRefs(previousViewer
));
7045 if (previousViewer
) {
7046 mContentViewer
->SetPreviousViewer(nsnull
);
7047 previousViewer
->Destroy();
7051 // Save off the root view's parent and sibling so that we can insert the
7052 // new content viewer's root view at the same position. Also save the
7053 // bounds of the root view's widget.
7055 nsIView
*rootViewSibling
= nsnull
, *rootViewParent
= nsnull
;
7056 nsIntRect
newBounds(0, 0, 0, 0);
7058 nsCOMPtr
<nsIPresShell
> oldPresShell
;
7059 nsDocShell::GetPresShell(getter_AddRefs(oldPresShell
));
7061 nsIViewManager
*vm
= oldPresShell
->GetViewManager();
7063 nsIView
*oldRootView
= nsnull
;
7064 vm
->GetRootView(oldRootView
);
7067 rootViewSibling
= oldRootView
->GetNextSibling();
7068 rootViewParent
= oldRootView
->GetParent();
7070 mContentViewer
->GetBounds(newBounds
);
7075 // Transfer ownership to mContentViewer. By ensuring that either the
7076 // docshell or the session history, but not both, have references to the
7077 // content viewer, we prevent the viewer from being torn down after
7078 // Destroy() is called.
7080 if (mContentViewer
) {
7081 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nsnull
);
7082 viewer
->SetPreviousViewer(mContentViewer
);
7085 // Order the mContentViewer setup just like Embed does.
7086 mContentViewer
= nsnull
;
7088 // Now that we're about to switch documents, forget all of our children.
7089 // Note that we cached them as needed up in CaptureState above.
7092 mContentViewer
.swap(viewer
);
7094 // Grab all of the related presentation from the SHEntry now.
7095 // Clearing the viewer from the SHEntry will clear all of this state.
7096 nsCOMPtr
<nsISupports
> windowState
;
7097 mLSHE
->GetWindowState(getter_AddRefs(windowState
));
7098 mLSHE
->SetWindowState(nsnull
);
7101 mLSHE
->GetSticky(&sticky
);
7103 nsCOMPtr
<nsIDOMDocument
> domDoc
;
7104 mContentViewer
->GetDOMDocument(getter_AddRefs(domDoc
));
7106 nsCOMArray
<nsIDocShellTreeItem
> childShells
;
7108 nsCOMPtr
<nsIDocShellTreeItem
> child
;
7109 while (NS_SUCCEEDED(mLSHE
->ChildShellAt(i
++, getter_AddRefs(child
))) &&
7111 childShells
.AppendObject(child
);
7114 // get the previous content viewer size
7115 nsIntRect
oldBounds(0, 0, 0, 0);
7116 mLSHE
->GetViewerBounds(oldBounds
);
7118 // Restore the refresh URI list. The refresh timers will be restarted
7119 // when EndPageLoad() is called.
7120 nsCOMPtr
<nsISupportsArray
> refreshURIList
;
7121 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIList
));
7123 // Reattach to the window object.
7124 rv
= mContentViewer
->Open(windowState
, mLSHE
);
7126 // Now remove it from the cached presentation.
7127 mLSHE
->SetContentViewer(nsnull
);
7128 mEODForCurrentDocument
= PR_FALSE
;
7132 nsCOMPtr
<nsISupportsArray
> refreshURIs
;
7133 mLSHE
->GetRefreshURIList(getter_AddRefs(refreshURIs
));
7134 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
7135 mLSHE
->ChildShellAt(0, getter_AddRefs(childShell
));
7136 NS_ASSERTION(!refreshURIs
&& !childShell
,
7137 "SHEntry should have cleared presentation state");
7141 // Restore the sticky state of the viewer. The viewer has set this state
7142 // on the history entry in Destroy() just before marking itself non-sticky,
7143 // to avoid teardown of the presentation.
7144 mContentViewer
->SetSticky(sticky
);
7146 NS_ENSURE_SUCCESS(rv
, rv
);
7148 // mLSHE is now our currently-loaded document.
7149 SetHistoryEntry(&mOSHE
, mLSHE
);
7151 // XXX special wyciwyg handling in Embed()?
7153 // We aren't going to restore any items from the LayoutHistoryState,
7154 // but we don't want them to stay around in case the page is reloaded.
7155 SetLayoutHistoryState(nsnull
);
7157 // This is the end of our Embed() replacement
7159 mSavingOldViewer
= PR_FALSE
;
7160 mEODForCurrentDocument
= PR_FALSE
;
7162 // Tell the event loop to favor plevents over user events, see comments
7163 // in CreateContentViewer.
7164 if (++gNumberOfDocumentsLoading
== 1)
7165 FavorPerformanceHint(PR_TRUE
, NS_EVENT_STARVATION_DELAY_HINT
);
7168 if (oldMUDV
&& newMUDV
) {
7169 newMUDV
->SetTextZoom(textZoom
);
7170 newMUDV
->SetFullZoom(pageZoom
);
7171 newMUDV
->SetAuthorStyleDisabled(styleDisabled
);
7174 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDoc
);
7175 PRUint32 parentSuspendCount
= 0;
7177 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
7178 GetParent(getter_AddRefs(parent
));
7179 nsCOMPtr
<nsIDocument
> d
= do_GetInterface(parent
);
7181 if (d
->EventHandlingSuppressed()) {
7182 document
->SuppressEventHandling(d
->EventHandlingSuppressed());
7184 nsCOMPtr
<nsPIDOMWindow
> parentWindow
= d
->GetWindow();
7186 parentSuspendCount
= parentWindow
->TimeoutSuspendCount();
7190 // Use the uri from the mLSHE we had when we entered this function
7191 // (which need not match the document's URI if anchors are involved),
7192 // since that's the history entry we're loading. Note that if we use
7193 // origLSHE we don't have to worry about whether the entry in question
7194 // is still mLSHE or whether it's now mOSHE.
7195 nsCOMPtr
<nsIURI
> uri
;
7196 origLSHE
->GetURI(getter_AddRefs(uri
));
7197 SetCurrentURI(uri
, document
->GetChannel(), PR_TRUE
);
7200 // This is the end of our CreateContentViewer() replacement.
7201 // Now we simulate a load. First, we restore the state of the javascript
7203 nsCOMPtr
<nsPIDOMWindow
> privWin
=
7204 do_GetInterface(static_cast<nsIInterfaceRequestor
*>(this));
7205 NS_ASSERTION(privWin
, "could not get nsPIDOMWindow interface");
7207 rv
= privWin
->RestoreWindowState(windowState
);
7208 NS_ENSURE_SUCCESS(rv
, rv
);
7210 // Now, dispatch a title change event which would happen as the
7211 // <head> is parsed.
7212 document
->NotifyPossibleTitleChange(PR_FALSE
);
7214 // Now we simulate appending child docshells for subframes.
7215 for (i
= 0; i
< childShells
.Count(); ++i
) {
7216 nsIDocShellTreeItem
*childItem
= childShells
.ObjectAt(i
);
7217 nsCOMPtr
<nsIDocShell
> childShell
= do_QueryInterface(childItem
);
7219 // Make sure to not clobber the state of the child. Since AddChild
7220 // always clobbers it, save it off first.
7221 PRBool allowPlugins
;
7222 childShell
->GetAllowPlugins(&allowPlugins
);
7224 PRBool allowJavascript
;
7225 childShell
->GetAllowJavascript(&allowJavascript
);
7227 PRBool allowRedirects
;
7228 childShell
->GetAllowMetaRedirects(&allowRedirects
);
7230 PRBool allowSubframes
;
7231 childShell
->GetAllowSubframes(&allowSubframes
);
7234 childShell
->GetAllowImages(&allowImages
);
7236 PRBool allowDNSPrefetch
;
7237 childShell
->GetAllowDNSPrefetch(&allowDNSPrefetch
);
7239 // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
7240 // that the child inherits our state. Among other things, this means
7241 // that the child inherits our mIsActive, which is what we want.
7242 AddChild(childItem
);
7244 childShell
->SetAllowPlugins(allowPlugins
);
7245 childShell
->SetAllowJavascript(allowJavascript
);
7246 childShell
->SetAllowMetaRedirects(allowRedirects
);
7247 childShell
->SetAllowSubframes(allowSubframes
);
7248 childShell
->SetAllowImages(allowImages
);
7249 childShell
->SetAllowDNSPrefetch(allowDNSPrefetch
);
7251 rv
= childShell
->BeginRestore(nsnull
, PR_FALSE
);
7252 NS_ENSURE_SUCCESS(rv
, rv
);
7255 nsCOMPtr
<nsIPresShell
> shell
;
7256 nsDocShell::GetPresShell(getter_AddRefs(shell
));
7258 nsIViewManager
*newVM
= shell
? shell
->GetViewManager() : nsnull
;
7259 nsIView
*newRootView
= nsnull
;
7261 newVM
->GetRootView(newRootView
);
7263 // Insert the new root view at the correct location in the view tree.
7264 if (rootViewParent
) {
7265 nsIViewManager
*parentVM
= rootViewParent
->GetViewManager();
7267 if (parentVM
&& newRootView
) {
7268 // InsertChild(parent, child, sib, PR_TRUE) inserts the child after
7269 // sib in content order, which is before sib in view order. BUT
7270 // when sib is null it inserts at the end of the the document
7271 // order, i.e., first in view order. But when oldRootSibling is
7272 // null, the old root as at the end of the view list --- last in
7273 // content order --- and we want to call InsertChild(parent, child,
7274 // nsnull, PR_FALSE) in that case.
7275 parentVM
->InsertChild(rootViewParent
, newRootView
,
7277 rootViewSibling
? PR_TRUE
: PR_FALSE
);
7279 NS_ASSERTION(newRootView
->GetNextSibling() == rootViewSibling
,
7280 "error in InsertChild");
7284 // If parent is suspended, increase suspension count.
7285 // This can't be done as early as event suppression since this
7286 // depends on docshell tree.
7287 if (parentSuspendCount
) {
7288 privWin
->SuspendTimeouts(parentSuspendCount
, PR_FALSE
);
7291 // Now that all of the child docshells have been put into place, we can
7292 // restart the timers for the window and all of the child frames.
7293 privWin
->ResumeTimeouts();
7295 // Restore the refresh URI list. The refresh timers will be restarted
7296 // when EndPageLoad() is called.
7297 mRefreshURIList
= refreshURIList
;
7299 // Meta-refresh timers have been restarted for this shell, but not
7300 // for our children. Walk the child shells and restart their timers.
7301 PRInt32 n
= mChildList
.Count();
7302 for (i
= 0; i
< n
; ++i
) {
7303 nsCOMPtr
<nsIDocShell
> child
= do_QueryInterface(ChildAt(i
));
7305 child
->ResumeRefreshURIs();
7308 // Make sure this presentation is the same size as the previous
7309 // presentation. If this is not the same size we showed it at last time,
7310 // then we need to resize the widget.
7312 // XXXbryner This interacts poorly with Firefox's infobar. If the old
7313 // presentation had the infobar visible, then we will resize the new
7314 // presentation to that smaller size. However, firing the locationchanged
7315 // event will hide the infobar, which will immediately resize the window
7316 // back to the larger size. A future optimization might be to restore
7317 // the presentation at the "wrong" size, then fire the locationchanged
7318 // event and check whether the docshell's new size is the same as the
7319 // cached viewer size (skipping the resize if they are equal).
7322 if (!newBounds
.IsEmpty() && newBounds
!= oldBounds
) {
7323 #ifdef DEBUG_PAGE_CACHE
7324 printf("resize widget(%d, %d, %d, %d)\n", newBounds
.x
,
7325 newBounds
.y
, newBounds
.width
, newBounds
.height
);
7327 mContentViewer
->SetBounds(newBounds
);
7329 nsIScrollableFrame
*rootScrollFrame
=
7330 shell
->GetRootScrollFrameAsScrollableExternal();
7331 if (rootScrollFrame
) {
7332 rootScrollFrame
->PostScrolledAreaEventForCurrentArea();
7337 // The FinishRestore call below can kill these, null them out so we don't
7338 // have invalid pointer lying around.
7339 newRootView
= rootViewSibling
= rootViewParent
= nsnull
;
7342 // Simulate the completion of the load.
7343 nsDocShell::FinishRestore();
7345 // Restart plugins, and paint the content.
7349 newVM
= shell
->GetViewManager();
7351 // When we insert the root view above the resulting invalidate is
7352 // dropped because painting is suppressed in the presshell until we
7353 // call Thaw. So we issue the invalidate here.
7354 newVM
->GetRootView(newRootView
);
7356 newVM
->UpdateView(newRootView
, NS_VMREFRESH_NO_SYNC
);
7361 return privWin
->FireDelayedDOMEvents();
7365 nsDocShell::CreateContentViewer(const char *aContentType
,
7366 nsIRequest
* request
,
7367 nsIStreamListener
** aContentHandler
)
7369 *aContentHandler
= nsnull
;
7371 // Can we check the content type of the current content viewer
7372 // and reuse it without destroying it and re-creating it?
7374 NS_ASSERTION(mLoadGroup
, "Someone ignored return from Init()?");
7376 // Instantiate the content viewer object
7377 nsCOMPtr
<nsIContentViewer
> viewer
;
7378 nsresult rv
= NewContentViewerObj(aContentType
, request
, mLoadGroup
,
7379 aContentHandler
, getter_AddRefs(viewer
));
7384 // Notify the current document that it is about to be unloaded!!
7386 // It is important to fire the unload() notification *before* any state
7387 // is changed within the DocShell - otherwise, javascript will get the
7388 // wrong information :-(
7391 if (mSavingOldViewer
) {
7392 // We determined that it was safe to cache the document presentation
7393 // at the time we initiated the new load. We need to check whether
7394 // it's still safe to do so, since there may have been DOM mutations
7395 // or new requests initiated.
7396 nsCOMPtr
<nsIDOMDocument
> domDoc
;
7397 viewer
->GetDOMDocument(getter_AddRefs(domDoc
));
7398 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domDoc
);
7399 mSavingOldViewer
= CanSavePresentation(mLoadType
, request
, doc
);
7402 NS_ASSERTION(!mLoadingURI
, "Re-entering unload?");
7404 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(request
);
7405 if (aOpenedChannel
) {
7406 aOpenedChannel
->GetURI(getter_AddRefs(mLoadingURI
));
7408 FirePageHideNotification(!mSavingOldViewer
);
7409 mLoadingURI
= nsnull
;
7411 // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
7412 // *new* document will fire.
7413 mFiredUnloadEvent
= PR_FALSE
;
7415 // we've created a new document so go ahead and call
7416 // OnLoadingSite(), but don't fire OnLocationChange()
7417 // notifications before we've called Embed(). See bug 284993.
7418 mURIResultedInDocument
= PR_TRUE
;
7420 if (mLoadType
== LOAD_ERROR_PAGE
) {
7421 // We need to set the SH entry and our current URI here and not
7422 // at the moment we load the page. We want the same behavior
7423 // of Stop() as for a normal page load. See bug 514232 for details.
7425 // Revert mLoadType to load type to state the page load failed,
7426 // following function calls need it.
7427 mLoadType
= mFailedLoadType
;
7429 nsCOMPtr
<nsIChannel
> failedChannel
= mFailedChannel
;
7430 nsCOMPtr
<nsIURI
> failedURI
= mFailedURI
;
7431 mFailedChannel
= nsnull
;
7432 mFailedURI
= nsnull
;
7434 // Create an shistory entry for the old load, if we have a channel
7435 if (failedChannel
) {
7436 mURIResultedInDocument
= PR_TRUE
;
7437 OnLoadingSite(failedChannel
, PR_TRUE
, PR_FALSE
);
7438 } else if (failedURI
) {
7439 mURIResultedInDocument
= PR_TRUE
;
7440 OnNewURI(failedURI
, nsnull
, nsnull
, mLoadType
, PR_TRUE
, PR_FALSE
);
7443 // Be sure to have a correct mLSHE, it may have been cleared by
7444 // EndPageLoad. See bug 302115.
7445 if (mSessionHistory
&& !mLSHE
) {
7447 mSessionHistory
->GetRequestedIndex(&idx
);
7449 mSessionHistory
->GetIndex(&idx
);
7451 nsCOMPtr
<nsIHistoryEntry
> entry
;
7452 mSessionHistory
->GetEntryAtIndex(idx
, PR_FALSE
,
7453 getter_AddRefs(entry
));
7454 mLSHE
= do_QueryInterface(entry
);
7457 // Set our current URI
7458 SetCurrentURI(failedURI
);
7460 mLoadType
= LOAD_ERROR_PAGE
;
7463 PRBool onLocationChangeNeeded
= OnLoadingSite(aOpenedChannel
, PR_FALSE
);
7465 // let's try resetting the load group if we need to...
7466 nsCOMPtr
<nsILoadGroup
> currentLoadGroup
;
7467 NS_ENSURE_SUCCESS(aOpenedChannel
->
7468 GetLoadGroup(getter_AddRefs(currentLoadGroup
)),
7471 if (currentLoadGroup
!= mLoadGroup
) {
7472 nsLoadFlags loadFlags
= 0;
7474 //Cancel any URIs that are currently loading...
7475 /// XXX: Need to do this eventually Stop();
7477 // Retarget the document to this loadgroup...
7479 /* First attach the channel to the right loadgroup
7480 * and then remove from the old loadgroup. This
7481 * puts the notifications in the right order and
7482 * we don't null-out mLSHE in OnStateChange() for
7483 * all redirected urls
7485 aOpenedChannel
->SetLoadGroup(mLoadGroup
);
7487 // Mark the channel as being a document URI...
7488 aOpenedChannel
->GetLoadFlags(&loadFlags
);
7489 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
;
7491 aOpenedChannel
->SetLoadFlags(loadFlags
);
7493 mLoadGroup
->AddRequest(request
, nsnull
);
7494 if (currentLoadGroup
)
7495 currentLoadGroup
->RemoveRequest(request
, nsnull
,
7496 NS_BINDING_RETARGETED
);
7498 // Update the notification callbacks, so that progress and
7499 // status information are sent to the right docshell...
7500 aOpenedChannel
->SetNotificationCallbacks(this);
7503 NS_ENSURE_SUCCESS(Embed(viewer
, "", (nsISupports
*) nsnull
),
7506 mSavedRefreshURIList
= nsnull
;
7507 mSavingOldViewer
= PR_FALSE
;
7508 mEODForCurrentDocument
= PR_FALSE
;
7510 // if this document is part of a multipart document,
7511 // the ID can be used to distinguish it from the other parts.
7512 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(request
));
7513 if (multiPartChannel
) {
7514 nsCOMPtr
<nsIPresShell
> shell
;
7515 rv
= GetPresShell(getter_AddRefs(shell
));
7516 if (NS_SUCCEEDED(rv
) && shell
) {
7517 nsIDocument
*doc
= shell
->GetDocument();
7520 multiPartChannel
->GetPartID(&partID
);
7521 doc
->SetPartID(partID
);
7526 // Give hint to native plevent dispatch mechanism. If a document
7527 // is loading the native plevent dispatch mechanism should favor
7528 // performance over normal native event dispatch priorities.
7529 if (++gNumberOfDocumentsLoading
== 1) {
7530 // Hint to favor performance for the plevent notification mechanism.
7531 // We want the pages to load as fast as possible even if its means
7532 // native messages might be starved.
7533 FavorPerformanceHint(PR_TRUE
, NS_EVENT_STARVATION_DELAY_HINT
);
7536 if (onLocationChangeNeeded
) {
7537 FireOnLocationChange(this, request
, mCurrentURI
);
7544 nsDocShell::NewContentViewerObj(const char *aContentType
,
7545 nsIRequest
* request
, nsILoadGroup
* aLoadGroup
,
7546 nsIStreamListener
** aContentHandler
,
7547 nsIContentViewer
** aViewer
)
7549 nsCOMPtr
<nsIChannel
> aOpenedChannel
= do_QueryInterface(request
);
7551 nsCOMPtr
<nsIContentUtils
> cutils
= do_GetService("@mozilla.org/content/contentutils;1");
7553 return NS_ERROR_FAILURE
;
7556 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
=
7557 cutils
->FindInternalContentViewer(aContentType
);
7558 if (!docLoaderFactory
) {
7559 return NS_ERROR_FAILURE
;
7562 // Now create an instance of the content viewer
7563 // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
7564 nsresult rv
= docLoaderFactory
->CreateInstance("view",
7566 aLoadGroup
, aContentType
,
7567 static_cast<nsIContentViewerContainer
*>(this),
7571 NS_ENSURE_SUCCESS(rv
, rv
);
7573 (*aViewer
)->SetContainer(static_cast<nsIContentViewerContainer
*>(this));
7578 nsDocShell::SetupNewViewer(nsIContentViewer
* aNewViewer
)
7581 // Copy content viewer state from previous or parent content viewer.
7583 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
7585 // Do NOT to maintain a reference to the old content viewer outside
7586 // of this "copying" block, or it will not be destroyed until the end of
7587 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
7589 // In this block of code, if we get an error result, we return it
7590 // but if we get a null pointer, that's perfectly legal for parent
7591 // and parentContentViewer.
7599 // This will get the size from the current content viewer or from the
7601 DoGetPositionAndSize(&x
, &y
, &cx
, &cy
);
7603 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
7604 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem
)),
7606 nsCOMPtr
<nsIDocShell
> parent(do_QueryInterface(parentAsItem
));
7608 nsCAutoString defaultCharset
;
7609 nsCAutoString forceCharset
;
7610 nsCAutoString hintCharset
;
7611 PRInt32 hintCharsetSource
;
7612 nsCAutoString prevDocCharset
;
7615 PRBool styleDisabled
;
7616 // |newMUDV| also serves as a flag to set the data from the above vars
7617 nsCOMPtr
<nsIMarkupDocumentViewer
> newMUDV
;
7619 if (mContentViewer
|| parent
) {
7620 nsCOMPtr
<nsIMarkupDocumentViewer
> oldMUDV
;
7621 if (mContentViewer
) {
7622 // Get any interesting state from old content viewer
7623 // XXX: it would be far better to just reuse the document viewer ,
7624 // since we know we're just displaying the same document as before
7625 oldMUDV
= do_QueryInterface(mContentViewer
);
7627 // Tell the old content viewer to hibernate in session history when
7630 if (mSavingOldViewer
&& NS_FAILED(CaptureState())) {
7632 mOSHE
->SyncPresentationState();
7634 mSavingOldViewer
= PR_FALSE
;
7638 // No old content viewer, so get state from parent's content viewer
7639 nsCOMPtr
<nsIContentViewer
> parentContentViewer
;
7640 parent
->GetContentViewer(getter_AddRefs(parentContentViewer
));
7641 oldMUDV
= do_QueryInterface(parentContentViewer
);
7647 newMUDV
= do_QueryInterface(aNewViewer
,&rv
);
7649 NS_ENSURE_SUCCESS(oldMUDV
->
7650 GetDefaultCharacterSet(defaultCharset
),
7652 NS_ENSURE_SUCCESS(oldMUDV
->
7653 GetForceCharacterSet(forceCharset
),
7655 NS_ENSURE_SUCCESS(oldMUDV
->
7656 GetHintCharacterSet(hintCharset
),
7658 NS_ENSURE_SUCCESS(oldMUDV
->
7659 GetHintCharacterSetSource(&hintCharsetSource
),
7661 NS_ENSURE_SUCCESS(oldMUDV
->
7662 GetTextZoom(&textZoom
),
7664 NS_ENSURE_SUCCESS(oldMUDV
->
7665 GetFullZoom(&pageZoom
),
7667 NS_ENSURE_SUCCESS(oldMUDV
->
7668 GetAuthorStyleDisabled(&styleDisabled
),
7670 NS_ENSURE_SUCCESS(oldMUDV
->
7671 GetPrevDocCharacterSet(prevDocCharset
),
7677 nscolor bgcolor
= NS_RGBA(0, 0, 0, 0);
7678 // Ensure that the content viewer is destroyed *after* the GC - bug 71515
7679 nsCOMPtr
<nsIContentViewer
> kungfuDeathGrip
= mContentViewer
;
7680 if (mContentViewer
) {
7681 // Stop any activity that may be happening in the old document before
7683 mContentViewer
->Stop();
7685 // Try to extract the canvas background color from the old
7686 // presentation shell, so we can use it for the next document.
7687 nsCOMPtr
<nsIDocumentViewer
> docviewer
=
7688 do_QueryInterface(mContentViewer
);
7691 nsCOMPtr
<nsIPresShell
> shell
;
7692 docviewer
->GetPresShell(getter_AddRefs(shell
));
7695 bgcolor
= shell
->GetCanvasBackground();
7699 mContentViewer
->Close(mSavingOldViewer
? mOSHE
.get() : nsnull
);
7700 aNewViewer
->SetPreviousViewer(mContentViewer
);
7702 mContentViewer
= nsnull
;
7705 // Now that we're about to switch documents, forget all of our children.
7706 // Note that we cached them as needed up in CaptureState above.
7709 mContentViewer
= aNewViewer
;
7711 nsCOMPtr
<nsIWidget
> widget
;
7712 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget
)), NS_ERROR_FAILURE
);
7714 nsIntRect
bounds(x
, y
, cx
, cy
);
7716 if (NS_FAILED(mContentViewer
->Init(widget
, bounds
))) {
7717 mContentViewer
= nsnull
;
7718 NS_ERROR("ContentViewer Initialization failed");
7719 return NS_ERROR_FAILURE
;
7722 // If we have old state to copy, set the old state onto the new content
7725 NS_ENSURE_SUCCESS(newMUDV
->SetDefaultCharacterSet(defaultCharset
),
7727 NS_ENSURE_SUCCESS(newMUDV
->SetForceCharacterSet(forceCharset
),
7729 NS_ENSURE_SUCCESS(newMUDV
->SetHintCharacterSet(hintCharset
),
7731 NS_ENSURE_SUCCESS(newMUDV
->
7732 SetHintCharacterSetSource(hintCharsetSource
),
7734 NS_ENSURE_SUCCESS(newMUDV
->SetPrevDocCharacterSet(prevDocCharset
),
7736 NS_ENSURE_SUCCESS(newMUDV
->SetTextZoom(textZoom
),
7738 NS_ENSURE_SUCCESS(newMUDV
->SetFullZoom(pageZoom
),
7740 NS_ENSURE_SUCCESS(newMUDV
->SetAuthorStyleDisabled(styleDisabled
),
7744 // Stuff the bgcolor from the old pres shell into the new
7745 // pres shell. This improves page load continuity.
7746 nsCOMPtr
<nsIDocumentViewer
> docviewer
=
7747 do_QueryInterface(mContentViewer
);
7750 nsCOMPtr
<nsIPresShell
> shell
;
7751 docviewer
->GetPresShell(getter_AddRefs(shell
));
7754 shell
->SetCanvasBackground(bgcolor
);
7758 // XXX: It looks like the LayoutState gets restored again in Embed()
7759 // right after the call to SetupNewViewer(...)
7761 // We don't show the mContentViewer yet, since we want to draw the old page
7762 // until we have enough of the new page to show. Just return with the new
7763 // viewer still set to hidden.
7769 nsDocShell::SetDocCurrentStateObj(nsISHEntry
*shEntry
)
7773 nsCOMPtr
<nsIDocument
> document
= do_GetInterface(GetAsSupports(this));
7774 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
7776 nsAutoString stateData
;
7778 rv
= shEntry
->GetStateData(stateData
);
7779 NS_ENSURE_SUCCESS(rv
, rv
);
7781 // if shEntry is null, we just set the pending state object to the
7785 document
->SetCurrentStateObject(stateData
);
7790 nsDocShell::CheckLoadingPermissions()
7792 // This method checks whether the caller may load content into
7793 // this docshell. Even though we've done our best to hide windows
7794 // from code that doesn't have the right to access them, it's
7795 // still possible for an evil site to open a window and access
7796 // frames in the new window through window.frames[] (which is
7797 // allAccess for historic reasons), so we still need to do this
7799 nsresult rv
= NS_OK
, sameOrigin
= NS_OK
;
7801 if (!gValidateOrigin
|| !IsFrame()) {
7802 // Origin validation was turned off, or we're not a frame.
7803 // Permit all loads.
7808 // We're a frame. Check that the caller has write permission to
7809 // the parent before allowing it to load anything into this
7812 nsCOMPtr
<nsIScriptSecurityManager
> securityManager
=
7813 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
7814 NS_ENSURE_SUCCESS(rv
, rv
);
7816 PRBool ubwEnabled
= PR_FALSE
;
7817 rv
= securityManager
->IsCapabilityEnabled("UniversalBrowserWrite",
7819 if (NS_FAILED(rv
) || ubwEnabled
) {
7823 nsCOMPtr
<nsIPrincipal
> subjPrincipal
;
7824 rv
= securityManager
->GetSubjectPrincipal(getter_AddRefs(subjPrincipal
));
7825 NS_ENSURE_TRUE(NS_SUCCEEDED(rv
) && subjPrincipal
, rv
);
7827 // Check if the caller is from the same origin as this docshell,
7828 // or any of its ancestors.
7829 nsCOMPtr
<nsIDocShellTreeItem
> item(this);
7831 nsCOMPtr
<nsIScriptGlobalObject
> sgo(do_GetInterface(item
));
7832 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(sgo
));
7835 if (!sop
|| !(p
= sop
->GetPrincipal())) {
7836 return NS_ERROR_UNEXPECTED
;
7841 sameOrigin
= subjPrincipal
->Equals(p
, &equal
);
7842 if (NS_SUCCEEDED(sameOrigin
)) {
7844 // Same origin, permit load
7849 sameOrigin
= NS_ERROR_DOM_PROP_ACCESS_DENIED
;
7852 nsCOMPtr
<nsIDocShellTreeItem
> tmp
;
7853 item
->GetSameTypeParent(getter_AddRefs(tmp
));
7860 //*****************************************************************************
7861 // nsDocShell: Site Loading
7862 //*****************************************************************************
7863 class InternalLoadEvent
: public nsRunnable
7866 InternalLoadEvent(nsDocShell
* aDocShell
, nsIURI
* aURI
, nsIURI
* aReferrer
,
7867 nsISupports
* aOwner
, PRUint32 aFlags
,
7868 const char* aTypeHint
, nsIInputStream
* aPostData
,
7869 nsIInputStream
* aHeadersData
, PRUint32 aLoadType
,
7870 nsISHEntry
* aSHEntry
, PRBool aFirstParty
) :
7871 mDocShell(aDocShell
),
7873 mReferrer(aReferrer
),
7875 mPostData(aPostData
),
7876 mHeadersData(aHeadersData
),
7879 mLoadType(aLoadType
),
7880 mFirstParty(aFirstParty
)
7882 // Make sure to keep null things null as needed
7884 mTypeHint
= aTypeHint
;
7889 return mDocShell
->InternalLoad(mURI
, mReferrer
, mOwner
, mFlags
,
7890 nsnull
, mTypeHint
.get(),
7891 mPostData
, mHeadersData
, mLoadType
,
7892 mSHEntry
, mFirstParty
, nsnull
, nsnull
);
7897 // Use IDL strings so .get() returns null by default
7898 nsXPIDLString mWindowTarget
;
7899 nsXPIDLCString mTypeHint
;
7901 nsRefPtr
<nsDocShell
> mDocShell
;
7902 nsCOMPtr
<nsIURI
> mURI
;
7903 nsCOMPtr
<nsIURI
> mReferrer
;
7904 nsCOMPtr
<nsISupports
> mOwner
;
7905 nsCOMPtr
<nsIInputStream
> mPostData
;
7906 nsCOMPtr
<nsIInputStream
> mHeadersData
;
7907 nsCOMPtr
<nsISHEntry
> mSHEntry
;
7914 nsDocShell::InternalLoad(nsIURI
* aURI
,
7916 nsISupports
* aOwner
,
7918 const PRUnichar
*aWindowTarget
,
7919 const char* aTypeHint
,
7920 nsIInputStream
* aPostData
,
7921 nsIInputStream
* aHeadersData
,
7923 nsISHEntry
* aSHEntry
,
7925 nsIDocShell
** aDocShell
,
7926 nsIRequest
** aRequest
)
7928 nsresult rv
= NS_OK
;
7931 if (gDocShellLeakLog
&& PR_LOG_TEST(gDocShellLeakLog
, PR_LOG_DEBUG
)) {
7934 aURI
->GetSpec(spec
);
7935 PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec
.get());
7939 // Initialize aDocShell/aRequest
7941 *aDocShell
= nsnull
;
7948 return NS_ERROR_NULL_POINTER
;
7951 NS_ENSURE_TRUE(IsValidLoadType(aLoadType
), NS_ERROR_INVALID_ARG
);
7953 NS_ENSURE_TRUE(!mIsBeingDestroyed
, NS_ERROR_NOT_AVAILABLE
);
7955 // wyciwyg urls can only be loaded through history. Any normal load of
7956 // wyciwyg through docshell is illegal. Disallow such loads.
7957 if (aLoadType
& LOAD_CMD_NORMAL
) {
7958 PRBool isWyciwyg
= PR_FALSE
;
7959 rv
= aURI
->SchemeIs("wyciwyg", &isWyciwyg
);
7960 if ((isWyciwyg
&& NS_SUCCEEDED(rv
)) || NS_FAILED(rv
))
7961 return NS_ERROR_FAILURE
;
7964 PRBool bIsJavascript
= PR_FALSE
;
7965 if (NS_FAILED(aURI
->SchemeIs("javascript", &bIsJavascript
))) {
7966 bIsJavascript
= PR_FALSE
;
7970 // First, notify any nsIContentPolicy listeners about the document load.
7971 // Only abort the load if a content policy listener explicitly vetos it!
7973 nsCOMPtr
<nsIDOMElement
> requestingElement
;
7974 // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
7975 nsCOMPtr
<nsPIDOMWindow
> privateWin(do_QueryInterface(mScriptGlobal
));
7977 requestingElement
= privateWin
->GetFrameElementInternal();
7979 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
7980 PRUint32 contentType
;
7982 NS_ASSERTION(requestingElement
, "A frame but no DOM element!?");
7983 contentType
= nsIContentPolicy::TYPE_SUBDOCUMENT
;
7985 contentType
= nsIContentPolicy::TYPE_DOCUMENT
;
7988 nsISupports
* context
= requestingElement
;
7990 context
= mScriptGlobal
;
7993 // XXXbz would be nice to know the loading principal here... but we don't
7994 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
;
7996 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
7997 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
7998 NS_ENSURE_SUCCESS(rv
, rv
);
8000 rv
= secMan
->GetCodebasePrincipal(aReferrer
,
8001 getter_AddRefs(loadingPrincipal
));
8004 rv
= NS_CheckContentLoadPolicy(contentType
,
8008 EmptyCString(), //mime guess
8012 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
)) {
8013 if (NS_SUCCEEDED(rv
) && shouldLoad
== nsIContentPolicy::REJECT_TYPE
) {
8014 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT
;
8017 return NS_ERROR_CONTENT_BLOCKED
;
8020 nsCOMPtr
<nsISupports
> owner(aOwner
);
8022 // Get an owner from the current document if necessary. Note that we only
8023 // do this for URIs that inherit a security context and local file URIs;
8024 // in particular we do NOT do this for about:blank. This way, random
8025 // about:blank loads that have no owner (which basically means they were
8026 // done by someone from chrome manually messing with our nsIWebNavigation
8027 // or by C++ setting document.location) don't get a funky principal. If
8028 // callers want something interesting to happen with the about:blank
8029 // principal in this case, they should pass an owner in.
8033 // One more twist: Don't inherit the owner for external loads.
8034 if (aLoadType
!= LOAD_NORMAL_EXTERNAL
&& !owner
&&
8035 (aFlags
& INTERNAL_LOAD_FLAGS_INHERIT_OWNER
) &&
8036 NS_SUCCEEDED(URIInheritsSecurityContext(aURI
, &inherits
)) &&
8039 // Don't allow loads that would inherit our security context
8040 // if this document came from an unsafe channel.
8041 nsCOMPtr
<nsIDocShellTreeItem
> treeItem
= this;
8043 nsCOMPtr
<nsIDocShell
> itemDocShell
=
8044 do_QueryInterface(treeItem
);
8047 NS_SUCCEEDED(itemDocShell
->GetChannelIsUnsafe(&isUnsafe
)) &&
8049 return NS_ERROR_DOM_SECURITY_ERR
;
8052 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
8053 treeItem
->GetSameTypeParent(getter_AddRefs(parent
));
8054 parent
.swap(treeItem
);
8057 owner
= GetInheritedPrincipal(PR_TRUE
);
8062 // Resolve the window target before going any further...
8063 // If the load has been targeted to another DocShell, then transfer the
8066 if (aWindowTarget
&& *aWindowTarget
) {
8067 // We've already done our owner-inheriting. Mask out that bit, so we
8068 // don't try inheriting an owner from the target window if we came up
8069 // with a null owner above.
8070 aFlags
= aFlags
& ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER
;
8072 // Locate the target DocShell.
8073 // This may involve creating a new toplevel window - if necessary.
8075 nsCOMPtr
<nsIDocShellTreeItem
> targetItem
;
8076 FindItemWithName(aWindowTarget
, nsnull
, this,
8077 getter_AddRefs(targetItem
));
8079 nsCOMPtr
<nsIDocShell
> targetDocShell
= do_QueryInterface(targetItem
);
8081 PRBool isNewWindow
= PR_FALSE
;
8082 if (!targetDocShell
) {
8083 nsCOMPtr
<nsIDOMWindowInternal
> win
=
8084 do_GetInterface(GetAsSupports(this));
8085 NS_ENSURE_TRUE(win
, NS_ERROR_NOT_AVAILABLE
);
8087 nsDependentString
name(aWindowTarget
);
8088 nsCOMPtr
<nsIDOMWindow
> newWin
;
8089 rv
= win
->Open(EmptyString(), // URL to load
8090 name
, // window name
8091 EmptyString(), // Features
8092 getter_AddRefs(newWin
));
8094 // In some cases the Open call doesn't actually result in a new
8095 // window being opened. We can detect these cases by examining the
8096 // document in |newWin|, if any.
8097 nsCOMPtr
<nsPIDOMWindow
> piNewWin
= do_QueryInterface(newWin
);
8099 nsCOMPtr
<nsIDocument
> newDoc
=
8100 do_QueryInterface(piNewWin
->GetExtantDocument());
8101 if (!newDoc
|| newDoc
->IsInitialDocument()) {
8102 isNewWindow
= PR_TRUE
;
8103 aFlags
|= INTERNAL_LOAD_FLAGS_FIRST_LOAD
;
8107 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(newWin
);
8108 targetDocShell
= do_QueryInterface(webNav
);
8112 // Transfer the load to the target DocShell... Pass nsnull as the
8113 // window target name from to prevent recursive retargeting!
8115 if (NS_SUCCEEDED(rv
) && targetDocShell
) {
8116 rv
= targetDocShell
->InternalLoad(aURI
,
8120 nsnull
, // No window target
8129 if (rv
== NS_ERROR_NO_CONTENT
) {
8130 // XXXbz except we never reach this code!
8133 // At this point, a new window has been created, but the
8134 // URI did not have any data associated with it...
8136 // So, the best we can do, is to tear down the new window
8137 // that was just created!
8139 nsCOMPtr
<nsIDOMWindowInternal
> domWin
=
8140 do_GetInterface(targetDocShell
);
8146 // NS_ERROR_NO_CONTENT should not be returned to the
8147 // caller... This is an internal error code indicating that
8148 // the URI had no data associated with it - probably a
8149 // helper-app style protocol (ie. mailto://)
8153 else if (isNewWindow
) {
8154 // XXX: Once new windows are created hidden, the new
8155 // window will need to be made visible... For now,
8160 // Else we ran out of memory, or were a popup and got blocked,
8167 // Load is being targetted at this docshell so return an error if the
8168 // docshell is in the process of being destroyed.
8170 if (mIsBeingDestroyed
) {
8171 return NS_ERROR_FAILURE
;
8174 rv
= CheckLoadingPermissions();
8175 if (NS_FAILED(rv
)) {
8179 // If this docshell is owned by a frameloader, make sure to cancel
8180 // possible frameloader initialization before loading a new page.
8181 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
8182 GetParent(getter_AddRefs(parent
));
8184 nsCOMPtr
<nsIDocument
> doc
= do_GetInterface(parent
);
8186 doc
->TryCancelFrameLoaderInitialization(this);
8190 if (mFiredUnloadEvent
) {
8191 if (IsOKToLoadURI(aURI
)) {
8192 NS_PRECONDITION(!aWindowTarget
|| !*aWindowTarget
,
8193 "Shouldn't have a window target here!");
8195 // If this is a replace load, make whatever load triggered
8196 // the unload event also a replace load, so we don't
8197 // create extra history entries.
8198 if (LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
8199 mLoadType
= LOAD_NORMAL_REPLACE
;
8202 // Do this asynchronously
8203 nsCOMPtr
<nsIRunnable
> ev
=
8204 new InternalLoadEvent(this, aURI
, aReferrer
, aOwner
, aFlags
,
8205 aTypeHint
, aPostData
, aHeadersData
,
8206 aLoadType
, aSHEntry
, aFirstParty
);
8207 return NS_DispatchToCurrentThread(ev
);
8210 // Just ignore this load attempt
8214 // Before going any further vet loads initiated by external programs.
8215 if (aLoadType
== LOAD_NORMAL_EXTERNAL
) {
8216 // Disallow external chrome: loads targetted at content windows
8217 PRBool isChrome
= PR_FALSE
;
8218 if (NS_SUCCEEDED(aURI
->SchemeIs("chrome", &isChrome
)) && isChrome
) {
8219 NS_WARNING("blocked external chrome: url -- use '-chrome' option");
8220 return NS_ERROR_FAILURE
;
8223 // clear the decks to prevent context bleed-through (bug 298255)
8224 rv
= CreateAboutBlankContentViewer(nsnull
, nsnull
);
8226 return NS_ERROR_FAILURE
;
8228 // reset loadType so we don't have to add lots of tests for
8229 // LOAD_NORMAL_EXTERNAL after this point
8230 aLoadType
= LOAD_NORMAL
;
8233 mAllowKeywordFixup
=
8234 (aFlags
& INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
) != 0;
8235 mURIResultedInDocument
= PR_FALSE
; // reset the clock...
8237 // If we've gotten this far, reset our "don't fire a popState" flag. This
8238 // will get set to true the next time someone calls push/replaceState.
8239 mSuppressPopstate
= PR_FALSE
;
8243 // Check to see if the new URI is an anchor in the existing document.
8244 // Skip this check if we're doing some sort of abnormal load, if the
8245 // new load is a non-history load and has postdata, or if we're doing
8246 // a history load and the page identifiers of mOSHE and aSHEntry
8249 PRBool allowScroll
= PR_TRUE
;
8251 allowScroll
= (aPostData
== nsnull
);
8253 PRUint32 ourPageIdent
;
8254 mOSHE
->GetPageIdentifier(&ourPageIdent
);
8255 PRUint32 otherPageIdent
;
8256 aSHEntry
->GetPageIdentifier(&otherPageIdent
);
8257 allowScroll
= (ourPageIdent
== otherPageIdent
);
8260 nsCOMPtr
<nsIInputStream
> currentPostData
;
8261 mOSHE
->GetPostData(getter_AddRefs(currentPostData
));
8262 NS_ASSERTION(currentPostData
== aPostData
,
8263 "Different POST data for entries for the same page?");
8268 if (aLoadType
== LOAD_NORMAL
||
8269 aLoadType
== LOAD_STOP_CONTENT
||
8270 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) ||
8271 aLoadType
== LOAD_HISTORY
||
8272 aLoadType
== LOAD_LINK
) {
8274 PRBool wasAnchor
= PR_FALSE
;
8275 PRBool doHashchange
= PR_FALSE
;
8277 // Get the position of the scrollers.
8278 nscoord cx
= 0, cy
= 0;
8279 GetCurScrollPos(ScrollOrientation_X
, &cx
);
8280 GetCurScrollPos(ScrollOrientation_Y
, &cy
);
8283 NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI
, &wasAnchor
, aLoadType
,
8288 // If this is a history load, aSHEntry will have document identifier X
8289 // if it was created as a result of a History.pushState() from a
8290 // SHEntry with doc ident X, or if it was created by changing the hash
8291 // of the URI corresponding to a SHEntry with doc ident X.
8292 PRBool sameDocIdent
= PR_FALSE
;
8293 if (mOSHE
&& aSHEntry
) {
8294 PRUint64 ourDocIdent
, otherDocIdent
;
8295 mOSHE
->GetDocIdentifier(&ourDocIdent
);
8296 aSHEntry
->GetDocIdentifier(&otherDocIdent
);
8297 sameDocIdent
= (ourDocIdent
== otherDocIdent
);
8300 // Do a short-circuited load if the new URI differs from the current
8301 // URI only in the hash, or if the two entries belong to the same
8302 // document and don't point to the same object.
8304 // (If we didn't check that the SHEntries are different objects,
8305 // history.go(0) would short-circuit instead of triggering a true
8306 // load, and we wouldn't dispatch an onload event to the page.)
8307 if (wasAnchor
|| (sameDocIdent
&& (mOSHE
!= aSHEntry
))) {
8308 mLoadType
= aLoadType
;
8309 mURIResultedInDocument
= PR_TRUE
;
8311 /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
8312 * SetCurrentURI() called from OnNewURI() will send proper
8313 * onLocationChange() notifications to the browser to update
8314 * back/forward buttons.
8316 SetHistoryEntry(&mLSHE
, aSHEntry
);
8318 /* This is a anchor traversal with in the same page.
8319 * call OnNewURI() so that, this traversal will be
8320 * recorded in session and global history.
8322 nsCOMPtr
<nsISupports
> owner
;
8324 mOSHE
->GetOwner(getter_AddRefs(owner
));
8326 OnNewURI(aURI
, nsnull
, owner
, mLoadType
, PR_TRUE
, PR_TRUE
);
8328 nsCOMPtr
<nsIInputStream
> postData
;
8329 PRUint32 pageIdent
= PR_UINT32_MAX
;
8330 nsCOMPtr
<nsISupports
> cacheKey
;
8333 /* save current position of scroller(s) (bug 59774) */
8334 mOSHE
->SetScrollPosition(cx
, cy
);
8335 // Get the postdata and page ident from the current page, if
8336 // the new load is being done via normal means. Note that
8337 // "normal means" can be checked for just by checking for
8338 // LOAD_CMD_NORMAL, given the loadType and allowScroll check
8339 // above -- it filters out some LOAD_CMD_NORMAL cases that we
8340 // wouldn't want here.
8341 if (aLoadType
& LOAD_CMD_NORMAL
) {
8342 mOSHE
->GetPostData(getter_AddRefs(postData
));
8343 mOSHE
->GetPageIdentifier(&pageIdent
);
8344 mOSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
8347 if (mLSHE
&& wasAnchor
) {
8348 // If it's an anchor load, set mLSHE's doc identifier to
8349 // mOSHE's doc identifier -- These are the same documents,
8350 // as far as HTML5 is concerned.
8352 rv
= mOSHE
->GetDocIdentifier(&docIdent
);
8353 if (NS_SUCCEEDED(rv
)) {
8354 mLSHE
->SetDocIdentifier(docIdent
);
8359 /* Assign mOSHE to mLSHE. This will either be a new entry created
8360 * by OnNewURI() for normal loads or aSHEntry for history loads.
8363 SetHistoryEntry(&mOSHE
, mLSHE
);
8364 // Save the postData obtained from the previous page
8365 // in to the session history entry created for the
8366 // anchor page, so that any history load of the anchor
8367 // page will restore the appropriate postData.
8369 mOSHE
->SetPostData(postData
);
8371 // Make sure we won't just repost without hitting the
8374 mOSHE
->SetCacheKey(cacheKey
);
8376 // Propagate our page ident to the new mOSHE so that
8377 // we'll know it just differed by a scroll on the page.
8378 if (pageIdent
!= PR_UINT32_MAX
)
8379 mOSHE
->SetPageIdentifier(pageIdent
);
8382 /* restore previous position of scroller(s), if we're moving
8383 * back in history (bug 59774)
8385 if (mOSHE
&& (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
))
8388 mOSHE
->GetScrollPosition(&bx
, &by
);
8389 SetCurScrollPosEx(bx
, by
);
8392 /* Clear out mLSHE so that further anchor visits get
8393 * recorded in SH and SH won't misbehave.
8395 SetHistoryEntry(&mLSHE
, nsnull
);
8396 /* Set the title for the SH entry for this target url. so that
8397 * SH menus in go/back/forward buttons won't be empty for this.
8399 if (mSessionHistory
) {
8401 mSessionHistory
->GetIndex(&index
);
8402 nsCOMPtr
<nsIHistoryEntry
> hEntry
;
8403 mSessionHistory
->GetEntryAtIndex(index
, PR_FALSE
,
8404 getter_AddRefs(hEntry
));
8405 NS_ENSURE_TRUE(hEntry
, NS_ERROR_FAILURE
);
8406 nsCOMPtr
<nsISHEntry
> shEntry(do_QueryInterface(hEntry
));
8408 shEntry
->SetTitle(mTitle
);
8411 /* Set the title for the Global History entry for this anchor url.
8413 if (mUseGlobalHistory
) {
8414 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
8416 history
->SetURITitle(aURI
, mTitle
);
8418 else if (mGlobalHistory
) {
8419 mGlobalHistory
->SetPageTitle(aURI
, mTitle
);
8424 // Set the doc's URI according to the new history entry's URI
8425 nsCOMPtr
<nsIURI
> newURI
;
8426 mOSHE
->GetURI(getter_AddRefs(newURI
));
8427 NS_ENSURE_TRUE(newURI
, NS_ERROR_FAILURE
);
8428 nsCOMPtr
<nsIDocument
> doc
=
8429 do_GetInterface(GetAsSupports(this));
8430 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
8432 doc
->SetDocumentURI(newURI
);
8435 SetDocCurrentStateObj(mOSHE
);
8437 // Dispatch the popstate and hashchange events, as appropriate.
8438 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(mScriptGlobal
);
8440 NS_ASSERTION(!mSuppressPopstate
,
8441 "Popstate shouldn't be suppressed here.");
8443 // Pass PR_FALSE to indicate that this is not an "initial" (i.e.
8444 // after-onload) popstate.
8445 window
->DispatchSyncPopState(PR_FALSE
);
8448 window
->DispatchAsyncHashchange();
8455 // mContentViewer->PermitUnload can destroy |this| docShell, which
8456 // causes the next call of CanSavePresentation to crash.
8457 // Hold onto |this| until we return, to prevent a crash from happening.
8459 nsCOMPtr
<nsIDocShell
> kungFuDeathGrip(this);
8461 // Check if the page doesn't want to be unloaded. The javascript:
8462 // protocol handler deals with this for javascript: URLs.
8463 if (!bIsJavascript
&& mContentViewer
) {
8465 rv
= mContentViewer
->PermitUnload(PR_FALSE
, &okToUnload
);
8467 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
8468 // The user chose not to unload the page, interrupt the
8474 // Check for saving the presentation here, before calling Stop().
8475 // This is necessary so that we can catch any pending requests.
8476 // Since the new request has not been created yet, we pass null for the
8477 // new request parameter.
8478 // Also pass nsnull for the document, since it doesn't affect the return
8479 // value for our purposes here.
8480 PRBool savePresentation
= CanSavePresentation(aLoadType
, nsnull
, nsnull
);
8482 // Don't stop current network activity for javascript: URL's since
8483 // they might not result in any data, and thus nothing should be
8484 // stopped in those cases. In the case where they do result in
8485 // data, the javascript: URL channel takes care of stopping
8486 // current network activity.
8487 if (!bIsJavascript
) {
8488 // Stop any current network activity.
8489 // Also stop content if this is a zombie doc. otherwise
8490 // the onload will be delayed by other loads initiated in the
8491 // background by the first document that
8492 // didn't fully load before the next load was initiated.
8493 // If not a zombie, don't stop content until data
8494 // starts arriving from the new URI...
8496 nsCOMPtr
<nsIContentViewer
> zombieViewer
;
8497 if (mContentViewer
) {
8498 mContentViewer
->GetPreviousViewer(getter_AddRefs(zombieViewer
));
8502 LOAD_TYPE_HAS_FLAGS(aLoadType
, LOAD_FLAGS_STOP_CONTENT
)) {
8503 rv
= Stop(nsIWebNavigation::STOP_ALL
);
8505 rv
= Stop(nsIWebNavigation::STOP_NETWORK
);
8512 mLoadType
= aLoadType
;
8514 // mLSHE should be assigned to aSHEntry, only after Stop() has
8515 // been called. But when loading an error page, do not clear the
8516 // mLSHE for the real page.
8517 if (mLoadType
!= LOAD_ERROR_PAGE
)
8518 SetHistoryEntry(&mLSHE
, aSHEntry
);
8520 mSavingOldViewer
= savePresentation
;
8522 // If we have a saved content viewer in history, restore and show it now.
8523 if (aSHEntry
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
8524 // Make sure our history ID points to the same ID as
8525 // SHEntry's docshell ID.
8526 aSHEntry
->GetDocshellID(&mHistoryID
);
8528 // It's possible that the previous viewer of mContentViewer is the
8529 // viewer that will end up in aSHEntry when it gets closed. If that's
8530 // the case, we need to go ahead and force it into its shentry so we
8532 if (mContentViewer
) {
8533 nsCOMPtr
<nsIContentViewer
> prevViewer
;
8534 mContentViewer
->GetPreviousViewer(getter_AddRefs(prevViewer
));
8537 nsCOMPtr
<nsIContentViewer
> prevPrevViewer
;
8538 prevViewer
->GetPreviousViewer(getter_AddRefs(prevPrevViewer
));
8539 NS_ASSERTION(!prevPrevViewer
, "Should never have viewer chain here");
8541 nsCOMPtr
<nsISHEntry
> viewerEntry
;
8542 prevViewer
->GetHistoryEntry(getter_AddRefs(viewerEntry
));
8543 if (viewerEntry
== aSHEntry
) {
8544 // Make sure this viewer ends up in the right place
8545 mContentViewer
->SetPreviousViewer(nsnull
);
8546 prevViewer
->Destroy();
8550 nsCOMPtr
<nsISHEntry
> oldEntry
= mOSHE
;
8552 rv
= RestorePresentation(aSHEntry
, &restoring
);
8556 // We failed to restore the presentation, so clean up.
8557 // Both the old and new history entries could potentially be in
8558 // an inconsistent state.
8559 if (NS_FAILED(rv
)) {
8561 oldEntry
->SyncPresentationState();
8563 aSHEntry
->SyncPresentationState();
8567 nsCOMPtr
<nsIRequest
> req
;
8568 rv
= DoURILoad(aURI
, aReferrer
,
8569 !(aFlags
& INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER
),
8570 owner
, aTypeHint
, aPostData
, aHeadersData
, aFirstParty
,
8571 aDocShell
, getter_AddRefs(req
),
8572 (aFlags
& INTERNAL_LOAD_FLAGS_FIRST_LOAD
) != 0,
8573 (aFlags
& INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER
) != 0,
8574 (aFlags
& INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES
) != 0);
8575 if (req
&& aRequest
)
8576 NS_ADDREF(*aRequest
= req
);
8578 if (NS_FAILED(rv
)) {
8579 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(req
));
8580 DisplayLoadError(rv
, aURI
, nsnull
, chan
);
8587 nsDocShell::GetInheritedPrincipal(PRBool aConsiderCurrentDocument
)
8589 nsCOMPtr
<nsIDocument
> document
;
8591 if (aConsiderCurrentDocument
&& mContentViewer
) {
8592 document
= mContentViewer
->GetDocument();
8596 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
8597 GetSameTypeParent(getter_AddRefs(parentItem
));
8599 document
= do_GetInterface(parentItem
);
8604 if (!aConsiderCurrentDocument
) {
8608 // Make sure we end up with _something_ as the principal no matter
8610 EnsureContentViewer(); // If this fails, we'll just get a null
8611 // docViewer and bail.
8613 if (!mContentViewer
)
8615 document
= mContentViewer
->GetDocument();
8618 //-- Get the document's principal
8620 return document
->NodePrincipal();
8627 nsDocShell::ShouldCheckAppCache(nsIURI
*aURI
)
8629 nsCOMPtr
<nsIOfflineCacheUpdateService
> offlineService
=
8630 do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID
);
8631 if (!offlineService
) {
8636 nsresult rv
= offlineService
->OfflineAppAllowedForURI(aURI
,
8639 return NS_SUCCEEDED(rv
) && allowed
;
8643 nsDocShell::DoURILoad(nsIURI
* aURI
,
8644 nsIURI
* aReferrerURI
,
8645 PRBool aSendReferrer
,
8646 nsISupports
* aOwner
,
8647 const char * aTypeHint
,
8648 nsIInputStream
* aPostData
,
8649 nsIInputStream
* aHeadersData
,
8651 nsIDocShell
** aDocShell
,
8652 nsIRequest
** aRequest
,
8653 PRBool aIsNewWindowTarget
,
8654 PRBool aBypassClassifier
,
8655 PRBool aForceAllowCookies
)
8658 nsCOMPtr
<nsIURILoader
> uriLoader
;
8660 uriLoader
= do_GetService(NS_URI_LOADER_CONTRACTID
, &rv
);
8661 if (NS_FAILED(rv
)) return rv
;
8663 nsLoadFlags loadFlags
= nsIRequest::LOAD_NORMAL
;
8665 // tag first party URL loads
8666 loadFlags
|= nsIChannel::LOAD_INITIAL_DOCUMENT_URI
;
8669 if (mLoadType
== LOAD_ERROR_PAGE
) {
8670 // Error pages are LOAD_BACKGROUND
8671 loadFlags
|= nsIChannel::LOAD_BACKGROUND
;
8674 // check for Content Security Policy to pass along with the
8675 // new channel we are creating
8676 nsCOMPtr
<nsIChannelPolicy
> channelPolicy
;
8678 // check the parent docshell for a CSP
8679 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
8680 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
8681 GetSameTypeParent(getter_AddRefs(parentItem
));
8682 nsCOMPtr
<nsIDocument
> doc
= do_GetInterface(parentItem
);
8684 rv
= doc
->NodePrincipal()->GetCsp(getter_AddRefs(csp
));
8685 NS_ENSURE_SUCCESS(rv
, rv
);
8687 channelPolicy
= do_CreateInstance("@mozilla.org/nschannelpolicy;1");
8688 channelPolicy
->SetContentSecurityPolicy(csp
);
8689 channelPolicy
->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT
);
8694 // open a channel for the url
8695 nsCOMPtr
<nsIChannel
> channel
;
8697 rv
= NS_NewChannel(getter_AddRefs(channel
),
8701 static_cast<nsIInterfaceRequestor
*>(this),
8704 if (NS_FAILED(rv
)) {
8705 if (rv
== NS_ERROR_UNKNOWN_PROTOCOL
) {
8706 // This is a uri with a protocol scheme we don't know how
8707 // to handle. Embedders might still be interested in
8708 // handling the load, though, so we fire a notification
8709 // before throwing the load away.
8710 PRBool abort
= PR_FALSE
;
8711 nsresult rv2
= mContentListener
->OnStartURIOpen(aURI
, &abort
);
8712 if (NS_SUCCEEDED(rv2
) && abort
) {
8713 // Hey, they're handling the load for us! How convenient!
8721 nsCOMPtr
<nsIApplicationCacheChannel
> appCacheChannel
=
8722 do_QueryInterface(channel
);
8723 if (appCacheChannel
) {
8724 // Any document load should not inherit application cache.
8725 appCacheChannel
->SetInheritApplicationCache(PR_FALSE
);
8727 // Loads with the correct permissions should check for a matching
8728 // application cache.
8730 // Permission will be checked in the parent process
8731 if (GeckoProcessType_Default
!= XRE_GetProcessType())
8732 appCacheChannel
->SetChooseApplicationCache(PR_TRUE
);
8735 appCacheChannel
->SetChooseApplicationCache(
8736 ShouldCheckAppCache(aURI
));
8739 // Make sure to give the caller a channel if we managed to create one
8740 // This is important for correct error page/session history interaction
8742 NS_ADDREF(*aRequest
= channel
);
8744 channel
->SetOriginalURI(aURI
);
8745 if (aTypeHint
&& *aTypeHint
) {
8746 channel
->SetContentType(nsDependentCString(aTypeHint
));
8747 mContentTypeHint
= aTypeHint
;
8750 mContentTypeHint
.Truncate();
8754 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
8755 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInternal(do_QueryInterface(channel
));
8756 if (httpChannelInternal
) {
8757 if (aForceAllowCookies
) {
8758 httpChannelInternal
->SetForceAllowThirdPartyCookie(PR_TRUE
);
8761 httpChannelInternal
->SetDocumentURI(aURI
);
8763 httpChannelInternal
->SetDocumentURI(aReferrerURI
);
8767 nsCOMPtr
<nsIWritablePropertyBag2
> props(do_QueryInterface(channel
));
8770 // save true referrer for those who need it (e.g. xpinstall whitelisting)
8771 // Currently only http and ftp channels support this.
8772 props
->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
8777 // If this is a HTTP channel, then set up the HTTP specific information
8778 // (ie. POST data, referrer, ...)
8781 nsCOMPtr
<nsICachingChannel
> cacheChannel(do_QueryInterface(httpChannel
));
8782 /* Get the cache Key from SH */
8783 nsCOMPtr
<nsISupports
> cacheKey
;
8785 mLSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
8787 else if (mOSHE
) // for reload cases
8788 mOSHE
->GetCacheKey(getter_AddRefs(cacheKey
));
8790 // figure out if we need to set the post data stream on the channel...
8791 // right now, this is only done for http channels.....
8793 // XXX it's a bit of a hack to rewind the postdata stream here but
8794 // it has to be done in case the post data is being reused multiple
8796 nsCOMPtr
<nsISeekableStream
>
8797 postDataSeekable(do_QueryInterface(aPostData
));
8798 if (postDataSeekable
) {
8799 rv
= postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
8800 NS_ENSURE_SUCCESS(rv
, rv
);
8803 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
8804 NS_ASSERTION(uploadChannel
, "http must support nsIUploadChannel");
8806 // we really need to have a content type associated with this stream!!
8807 uploadChannel
->SetUploadStream(aPostData
, EmptyCString(), -1);
8808 /* If there is a valid postdata *and* it is a History Load,
8809 * set up the cache key on the channel, to retrieve the
8810 * data *only* from the cache. If it is a normal reload, the
8811 * cache is free to go to the server for updated postdata.
8813 if (cacheChannel
&& cacheKey
) {
8814 if (mLoadType
== LOAD_HISTORY
|| mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
8815 cacheChannel
->SetCacheKey(cacheKey
);
8817 if (NS_SUCCEEDED(channel
->GetLoadFlags(&loadFlags
)))
8818 channel
->SetLoadFlags(loadFlags
| nsICachingChannel::LOAD_ONLY_FROM_CACHE
);
8820 else if (mLoadType
== LOAD_RELOAD_NORMAL
)
8821 cacheChannel
->SetCacheKey(cacheKey
);
8825 /* If there is no postdata, set the cache key on the channel, and
8826 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
8827 * will be free to get it from net if it is not found in cache.
8828 * New cache may use it creatively on CGI pages with GET
8829 * method and even on those that say "no-cache"
8831 if (mLoadType
== LOAD_HISTORY
|| mLoadType
== LOAD_RELOAD_NORMAL
8832 || mLoadType
== LOAD_RELOAD_CHARSET_CHANGE
) {
8833 if (cacheChannel
&& cacheKey
)
8834 cacheChannel
->SetCacheKey(cacheKey
);
8838 rv
= AddHeadersToChannel(aHeadersData
, httpChannel
);
8840 // Set the referrer explicitly
8841 if (aReferrerURI
&& aSendReferrer
) {
8842 // Referrer is currenly only set for link clicks here.
8843 httpChannel
->SetReferrer(aReferrerURI
);
8847 // Set the owner of the channel, but only for channels that can't
8848 // provide their own security context.
8850 // XXX: Is seems wrong that the owner is ignored - even if one is
8851 // supplied) unless the URI is javascript or data or about:blank.
8852 // XXX: If this is ever changed, check all callers for what owners they're
8853 // passing in. In particular, see the code and comments in LoadURI
8854 // where we fall back on inheriting the owner if called
8855 // from chrome. That would be very wrong if this code changed
8856 // anything but channels that can't provide their own security context!
8858 // (Currently chrome URIs set the owner when they are created!
8859 // So setting a NULL owner would be bad!)
8861 // If this code ever changes, change nsObjectLoadingContent::LoadObject
8864 // We expect URIInheritsSecurityContext to return success for an
8865 // about:blank URI, so don't call IsAboutBlank() if this call fails.
8866 rv
= URIInheritsSecurityContext(aURI
, &inherit
);
8867 if (NS_SUCCEEDED(rv
) && (inherit
|| IsAboutBlank(aURI
))) {
8868 channel
->SetOwner(aOwner
);
8872 // file: uri special-casing
8874 // If this is a file: load opened from another file: then it may need
8875 // to inherit the owner from the referrer so they can script each other.
8876 // If we don't set the owner explicitly then each file: gets an owner
8877 // based on its own codebase later.
8879 nsCOMPtr
<nsIPrincipal
> ownerPrincipal(do_QueryInterface(aOwner
));
8880 if (URIIsLocalFile(aURI
) && ownerPrincipal
&&
8881 NS_SUCCEEDED(ownerPrincipal
->CheckMayLoad(aURI
, PR_FALSE
))) {
8882 // One more check here. CheckMayLoad will always return true for the
8883 // system principal, but we do NOT want to inherit in that case.
8885 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
8886 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
8888 NS_SUCCEEDED(secMan
->IsSystemPrincipal(ownerPrincipal
,
8891 channel
->SetOwner(aOwner
);
8895 nsCOMPtr
<nsIScriptChannel
> scriptChannel
= do_QueryInterface(channel
);
8896 if (scriptChannel
) {
8897 // Allow execution against our context if the principals match
8899 SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
8902 if (aIsNewWindowTarget
) {
8903 nsCOMPtr
<nsIWritablePropertyBag2
> props
= do_QueryInterface(channel
);
8905 props
->SetPropertyAsBool(
8906 NS_LITERAL_STRING("docshell.newWindowTarget"),
8911 rv
= DoChannelLoad(channel
, uriLoader
, aBypassClassifier
);
8914 // If the channel load failed, we failed and nsIWebProgress just ain't
8917 if (NS_SUCCEEDED(rv
)) {
8920 NS_ADDREF(*aDocShell
);
8928 AppendSegmentToString(nsIInputStream
*in
,
8930 const char *fromRawSegment
,
8933 PRUint32
*writeCount
)
8935 // aFromSegment now contains aCount bytes of data.
8937 nsCAutoString
*buf
= static_cast<nsCAutoString
*>(closure
);
8938 buf
->Append(fromRawSegment
, count
);
8940 // Indicate that we have consumed all of aFromSegment
8941 *writeCount
= count
;
8946 nsDocShell::AddHeadersToChannel(nsIInputStream
*aHeadersData
,
8947 nsIChannel
*aGenericChannel
)
8949 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aGenericChannel
);
8950 NS_ENSURE_STATE(httpChannel
);
8953 nsCAutoString headersString
;
8954 nsresult rv
= aHeadersData
->ReadSegments(AppendSegmentToString
,
8958 NS_ENSURE_SUCCESS(rv
, rv
);
8960 // used during the manipulation of the String from the InputStream
8961 nsCAutoString headerName
;
8962 nsCAutoString headerValue
;
8967 // Iterate over the headersString: for each "\r\n" delimited chunk,
8968 // add the value as a header to the nsIHttpChannel
8971 static const char kWhitespace
[] = "\b\t\r\n ";
8973 crlf
= headersString
.Find("\r\n");
8974 if (crlf
== kNotFound
)
8977 const nsCSubstring
&oneHeader
= StringHead(headersString
, crlf
);
8979 colon
= oneHeader
.FindChar(':');
8980 if (colon
== kNotFound
)
8981 return NS_ERROR_UNEXPECTED
;
8983 headerName
= StringHead(oneHeader
, colon
);
8984 headerValue
= Substring(oneHeader
, colon
+ 1);
8986 headerName
.Trim(kWhitespace
);
8987 headerValue
.Trim(kWhitespace
);
8989 headersString
.Cut(0, crlf
+ 2);
8992 // FINALLY: we can set the header!
8995 rv
= httpChannel
->SetRequestHeader(headerName
, headerValue
, PR_TRUE
);
8996 NS_ENSURE_SUCCESS(rv
, rv
);
8999 NS_NOTREACHED("oops");
9000 return NS_ERROR_UNEXPECTED
;
9003 nsresult
nsDocShell::DoChannelLoad(nsIChannel
* aChannel
,
9004 nsIURILoader
* aURILoader
,
9005 PRBool aBypassClassifier
)
9008 // Mark the channel as being a document URI and allow content sniffing...
9009 nsLoadFlags loadFlags
= 0;
9010 (void) aChannel
->GetLoadFlags(&loadFlags
);
9011 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
|
9012 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS
;
9014 // Load attributes depend on load type...
9015 switch (mLoadType
) {
9017 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
9020 case LOAD_RELOAD_CHARSET_CHANGE
:
9021 loadFlags
|= nsIRequest::LOAD_FROM_CACHE
;
9024 case LOAD_RELOAD_NORMAL
:
9026 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
9029 case LOAD_NORMAL_BYPASS_CACHE
:
9030 case LOAD_NORMAL_BYPASS_PROXY
:
9031 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
9032 case LOAD_RELOAD_BYPASS_CACHE
:
9033 case LOAD_RELOAD_BYPASS_PROXY
:
9034 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
9035 loadFlags
|= nsIRequest::LOAD_BYPASS_CACHE
;
9040 // Set cache checking flags
9041 PRInt32 prefSetting
;
9044 GetIntPref("browser.cache.check_doc_frequency",
9046 switch (prefSetting
) {
9048 loadFlags
|= nsIRequest::VALIDATE_ONCE_PER_SESSION
;
9051 loadFlags
|= nsIRequest::VALIDATE_ALWAYS
;
9054 loadFlags
|= nsIRequest::VALIDATE_NEVER
;
9061 if (!aBypassClassifier
) {
9062 loadFlags
|= nsIChannel::LOAD_CLASSIFY_URI
;
9065 (void) aChannel
->SetLoadFlags(loadFlags
);
9067 rv
= aURILoader
->OpenURI(aChannel
,
9068 (mLoadType
== LOAD_LINK
),
9070 NS_ENSURE_SUCCESS(rv
, rv
);
9076 nsDocShell::ScrollIfAnchor(nsIURI
* aURI
, PRBool
* aWasAnchor
,
9077 PRUint32 aLoadType
, PRBool
* aDoHashchange
)
9079 NS_ASSERTION(aURI
, "null uri arg");
9080 NS_ASSERTION(aWasAnchor
, "null anchor arg");
9081 NS_PRECONDITION(aDoHashchange
, "null hashchange arg");
9083 if (!aURI
|| !aWasAnchor
) {
9084 return NS_ERROR_FAILURE
;
9087 *aWasAnchor
= PR_FALSE
;
9088 *aDoHashchange
= PR_FALSE
;
9094 nsCOMPtr
<nsIPresShell
> shell
;
9095 nsresult rv
= GetPresShell(getter_AddRefs(shell
));
9096 if (NS_FAILED(rv
) || !shell
) {
9097 // If we failed to get the shell, or if there is no shell,
9098 // nothing left to do here.
9103 // NOTE: we assume URIs are absolute for comparison purposes
9105 nsCAutoString currentSpec
;
9106 NS_ENSURE_SUCCESS(mCurrentURI
->GetSpec(currentSpec
),
9109 nsCAutoString newSpec
;
9110 NS_ENSURE_SUCCESS(aURI
->GetSpec(newSpec
), NS_ERROR_FAILURE
);
9112 // Search for hash marks in the current URI and the new URI and
9113 // take a copy of everything to the left of the hash for
9116 const char kHash
= '#';
9118 // Split the new URI into a left and right part
9119 // (assume we're parsing it out right)
9120 nsACString::const_iterator urlStart
, urlEnd
, refStart
, refEnd
;
9121 newSpec
.BeginReading(urlStart
);
9122 newSpec
.EndReading(refEnd
);
9124 PRInt32 hashNew
= newSpec
.FindChar(kHash
);
9126 return NS_OK
; // Strange URI
9132 urlEnd
.advance(hashNew
);
9135 ++refStart
; // advanced past '#'
9140 urlEnd
= refStart
= refEnd
;
9142 const nsACString
& sNewLeft
= Substring(urlStart
, urlEnd
);
9143 const nsACString
& sNewRef
= Substring(refStart
, refEnd
);
9145 // Split the current URI in a left and right part
9146 nsACString::const_iterator currentLeftStart
, currentLeftEnd
,
9147 currentRefStart
, currentRefEnd
;
9148 currentSpec
.BeginReading(currentLeftStart
);
9149 currentSpec
.EndReading(currentRefEnd
);
9151 PRInt32 hashCurrent
= currentSpec
.FindChar(kHash
);
9152 if (hashCurrent
== 0) {
9153 return NS_OK
; // Strange URI
9156 if (hashCurrent
> 0) {
9157 currentLeftEnd
= currentLeftStart
;
9158 currentLeftEnd
.advance(hashCurrent
);
9160 currentRefStart
= currentLeftEnd
;
9161 ++currentRefStart
; // advance past '#'
9164 // no hash at all in currentSpec
9165 currentLeftEnd
= currentRefStart
= currentRefEnd
;
9168 // If we have no new anchor, we do not want to scroll, unless there is a
9169 // current anchor and we are doing a history load. So return if we have no
9170 // new anchor, and there is no current anchor or the load is not a history
9172 NS_ASSERTION(hashNew
!= 0 && hashCurrent
!= 0,
9173 "What happened to the early returns above?");
9174 if (hashNew
== kNotFound
&&
9175 (hashCurrent
== kNotFound
|| aLoadType
!= LOAD_HISTORY
)) {
9179 // Compare the URIs.
9181 // NOTE: this is a case sensitive comparison because some parts of the
9182 // URI are case sensitive, and some are not. i.e. the domain name
9183 // is case insensitive but the the paths are not.
9185 // This means that comparing "http://www.ABC.com/" to "http://www.abc.com/"
9186 // will fail this test.
9188 if (!Substring(currentLeftStart
, currentLeftEnd
).Equals(sNewLeft
)) {
9189 return NS_OK
; // URIs not the same
9192 // Now we know we are dealing with an anchor
9193 *aWasAnchor
= PR_TRUE
;
9195 // We should fire a hashchange event once we're done here if the two hashes
9197 *aDoHashchange
= !Substring(currentRefStart
, currentRefEnd
).Equals(sNewRef
);
9199 // Both the new and current URIs refer to the same page. We can now
9200 // browse to the hash stored in the new URI.
9202 if (!sNewRef
.IsEmpty()) {
9203 // anchor is there, but if it's a load from history,
9204 // we don't have any anchor jumping to do
9205 PRBool scroll
= aLoadType
!= LOAD_HISTORY
&&
9206 aLoadType
!= LOAD_RELOAD_NORMAL
;
9208 char *str
= ToNewCString(sNewRef
);
9210 return NS_ERROR_OUT_OF_MEMORY
;
9213 // nsUnescape modifies the string that is passed into it.
9216 // We assume that the bytes are in UTF-8, as it says in the
9218 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
9220 // We try the UTF-8 string first, and then try the document's
9221 // charset (see below). If the string is not UTF-8,
9222 // conversion will fail and give us an empty Unicode string.
9223 // In that case, we should just fall through to using the
9225 rv
= NS_ERROR_FAILURE
;
9226 NS_ConvertUTF8toUTF16
uStr(str
);
9227 if (!uStr
.IsEmpty()) {
9228 rv
= shell
->GoToAnchor(NS_ConvertUTF8toUTF16(str
), scroll
);
9230 nsMemory::Free(str
);
9232 // Above will fail if the anchor name is not UTF-8. Need to
9233 // convert from document charset to unicode.
9234 if (NS_FAILED(rv
)) {
9236 // Get a document charset
9237 NS_ENSURE_TRUE(mContentViewer
, NS_ERROR_FAILURE
);
9238 nsIDocument
* doc
= mContentViewer
->GetDocument();
9239 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
9240 const nsACString
&aCharset
= doc
->GetDocumentCharacterSet();
9242 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
9243 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
9244 NS_ENSURE_SUCCESS(rv
, rv
);
9246 // Unescape and convert to unicode
9249 rv
= textToSubURI
->UnEscapeAndConvert(PromiseFlatCString(aCharset
).get(),
9250 PromiseFlatCString(sNewRef
).get(),
9251 getter_Copies(uStr
));
9252 NS_ENSURE_SUCCESS(rv
, rv
);
9254 // Ignore return value of GoToAnchor, since it will return an error
9255 // if there is no such anchor in the document, which is actually a
9256 // success condition for us (we want to update the session history
9257 // with the new URI no matter whether we actually scrolled
9259 shell
->GoToAnchor(uStr
, scroll
);
9264 // Tell the shell it's at an anchor, without scrolling.
9265 shell
->GoToAnchor(EmptyString(), PR_FALSE
);
9267 // An empty anchor was found, but if it's a load from history,
9268 // we don't have to jump to the top of the page. Scrollbar
9269 // position will be restored by the caller, based on positions
9270 // stored in session history.
9271 if (aLoadType
== LOAD_HISTORY
|| aLoadType
== LOAD_RELOAD_NORMAL
)
9273 //An empty anchor. Scroll to the top of the page.
9274 rv
= SetCurScrollPosEx(0, 0);
9281 nsDocShell::SetupReferrerFromChannel(nsIChannel
* aChannel
)
9283 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
9285 nsCOMPtr
<nsIURI
> referrer
;
9286 nsresult rv
= httpChannel
->GetReferrer(getter_AddRefs(referrer
));
9287 if (NS_SUCCEEDED(rv
)) {
9288 SetReferrerURI(referrer
);
9294 nsDocShell::OnNewURI(nsIURI
* aURI
, nsIChannel
* aChannel
, nsISupports
* aOwner
,
9295 PRUint32 aLoadType
, PRBool aFireOnLocationChange
,
9296 PRBool aAddToGlobalHistory
)
9298 NS_PRECONDITION(aURI
, "uri is null");
9299 NS_PRECONDITION(!aChannel
|| !aOwner
, "Shouldn't have both set");
9301 #if defined(PR_LOGGING) && defined(DEBUG)
9302 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
9304 aURI
->GetSpec(spec
);
9306 nsCAutoString chanName
;
9308 aChannel
->GetName(chanName
);
9310 chanName
.AssignLiteral("<no channel>");
9312 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9313 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec
.get(),
9314 chanName
.get(), aLoadType
));
9318 PRBool updateHistory
= PR_TRUE
;
9319 PRBool equalUri
= PR_FALSE
;
9320 PRBool shAvailable
= PR_TRUE
;
9322 // Get the post data from the channel
9323 nsCOMPtr
<nsIInputStream
> inputStream
;
9325 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
9327 // Check if the HTTPChannel is hiding under a multiPartChannel
9329 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
9333 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
9334 if (uploadChannel
) {
9335 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
9338 // If the response status indicates an error, unlink this session
9339 // history entry from any entries sharing its doc ident.
9340 PRUint32 responseStatus
;
9341 nsresult rv
= httpChannel
->GetResponseStatus(&responseStatus
);
9342 if (mLSHE
&& NS_SUCCEEDED(rv
) && responseStatus
>= 400) {
9343 mLSHE
->SetUniqueDocIdentifier();
9347 /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
9348 * the current frame or in the root docshell
9350 nsCOMPtr
<nsISHistory
> rootSH
= mSessionHistory
;
9352 // Get the handle to SH from the root docshell
9353 GetRootSessionHistory(getter_AddRefs(rootSH
));
9355 shAvailable
= PR_FALSE
;
9359 // Determine if this type of load should update history.
9360 if (aLoadType
== LOAD_BYPASS_HISTORY
||
9361 aLoadType
== LOAD_ERROR_PAGE
||
9362 aLoadType
& LOAD_CMD_HISTORY
||
9363 aLoadType
& LOAD_CMD_RELOAD
)
9364 updateHistory
= PR_FALSE
;
9366 // Check if the url to be loaded is the same as the one already loaded.
9368 aURI
->Equals(mCurrentURI
, &equalUri
);
9371 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9372 (" shAvailable=%i updateHistory=%i equalURI=%i\n",
9373 shAvailable
, updateHistory
, equalUri
));
9375 if (shAvailable
&& mCurrentURI
&& !mOSHE
&& aLoadType
!= LOAD_ERROR_PAGE
) {
9376 NS_ASSERTION(IsAboutBlank(mCurrentURI
), "no SHEntry for a non-transient viewer?");
9380 /* If the url to be loaded is the same as the one already there,
9381 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
9382 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
9383 * AddToSessionHistory() won't mess with the current SHEntry and
9384 * if this page has any frame children, it also will be handled
9385 * properly. see bug 83684
9387 * NB: If mOSHE is null but we have a current URI, then it means
9388 * that we must be at the transient about:blank content viewer
9389 * (asserted above) and we should let the normal load continue,
9390 * since there's nothing to replace.
9392 * XXX Hopefully changing the loadType at this time will not hurt
9393 * anywhere. The other way to take care of sequentially repeating
9394 * frameset pages is to add new methods to nsIDocShellTreeItem.
9395 * Hopefully I don't have to do that.
9399 (mLoadType
== LOAD_NORMAL
||
9400 mLoadType
== LOAD_LINK
||
9401 mLoadType
== LOAD_STOP_CONTENT
) &&
9404 mLoadType
= LOAD_NORMAL_REPLACE
;
9407 // If this is a refresh to the currently loaded url, we don't
9408 // have to update session or global history.
9409 if (mLoadType
== LOAD_REFRESH
&& !inputStream
&& equalUri
) {
9410 SetHistoryEntry(&mLSHE
, mOSHE
);
9413 /* If the user pressed shift-reload, cache will create a new cache key
9414 * for the page. Save the new cacheKey in Session History.
9418 (aLoadType
== LOAD_RELOAD_BYPASS_CACHE
||
9419 aLoadType
== LOAD_RELOAD_BYPASS_PROXY
||
9420 aLoadType
== LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
)) {
9421 NS_ASSERTION(!updateHistory
,
9422 "We shouldn't be updating history for forced reloads!");
9424 nsCOMPtr
<nsICachingChannel
> cacheChannel(do_QueryInterface(aChannel
));
9425 nsCOMPtr
<nsISupports
> cacheKey
;
9426 // Get the Cache Key and store it in SH.
9428 cacheChannel
->GetCacheKey(getter_AddRefs(cacheKey
));
9429 // If we already have a loading history entry, store the new cache key
9430 // in it. Otherwise, since we're doing a reload and won't be updating
9431 // our history entry, store the cache key in our current history entry.
9433 mLSHE
->SetCacheKey(cacheKey
);
9435 mOSHE
->SetCacheKey(cacheKey
);
9437 // Since we're force-reloading, clear all the sub frame history.
9438 ClearFrameHistory(mLSHE
);
9439 ClearFrameHistory(mOSHE
);
9442 if (aLoadType
== LOAD_RELOAD_NORMAL
) {
9443 nsCOMPtr
<nsISHEntry
> currentSH
;
9444 PRBool oshe
= PR_FALSE
;
9445 GetCurrentSHEntry(getter_AddRefs(currentSH
), &oshe
);
9446 PRBool dynamicallyAddedChild
= PR_FALSE
;
9448 currentSH
->HasDynamicallyAddedChild(&dynamicallyAddedChild
);
9450 if (dynamicallyAddedChild
) {
9451 ClearFrameHistory(currentSH
);
9455 if (aLoadType
== LOAD_REFRESH
) {
9456 ClearFrameHistory(mLSHE
);
9457 ClearFrameHistory(mOSHE
);
9460 if (updateHistory
&& shAvailable
) {
9461 // Update session history if necessary...
9462 if (!mLSHE
&& (mItemType
== typeContent
) && mURIResultedInDocument
) {
9463 /* This is a fresh page getting loaded for the first time
9464 *.Create a Entry for it and add it to SH, if this is the
9467 (void) AddToSessionHistory(aURI
, aChannel
, aOwner
,
9468 getter_AddRefs(mLSHE
));
9471 if (aAddToGlobalHistory
) {
9472 // If this is a POST request, we do not want to include this in global
9474 if (!ChannelIsPost(aChannel
)) {
9475 nsCOMPtr
<nsIURI
> previousURI
;
9476 PRUint32 previousFlags
= 0;
9477 ExtractLastVisit(aChannel
, getter_AddRefs(previousURI
),
9480 nsCOMPtr
<nsIURI
> referrer
;
9481 // Treat referrer as null if there is an error getting it.
9482 (void)NS_GetReferrerFromChannel(aChannel
,
9483 getter_AddRefs(referrer
));
9485 AddURIVisit(aURI
, referrer
, previousURI
, previousFlags
);
9490 // If this was a history load, update the index in
9492 if (rootSH
&& (mLoadType
& LOAD_CMD_HISTORY
)) {
9493 nsCOMPtr
<nsISHistoryInternal
> shInternal(do_QueryInterface(rootSH
));
9495 rootSH
->GetIndex(&mPreviousTransIndex
);
9496 shInternal
->UpdateIndex();
9497 rootSH
->GetIndex(&mLoadedTransIndex
);
9498 #ifdef DEBUG_PAGE_CACHE
9499 printf("Previous index: %d, Loaded index: %d\n\n",
9500 mPreviousTransIndex
, mLoadedTransIndex
);
9504 PRBool onLocationChangeNeeded
= SetCurrentURI(aURI
, aChannel
,
9505 aFireOnLocationChange
);
9506 // Make sure to store the referrer from the channel, if any
9507 SetupReferrerFromChannel(aChannel
);
9508 return onLocationChangeNeeded
;
9512 nsDocShell::OnLoadingSite(nsIChannel
* aChannel
, PRBool aFireOnLocationChange
,
9513 PRBool aAddToGlobalHistory
)
9515 nsCOMPtr
<nsIURI
> uri
;
9516 // If this a redirect, use the final url (uri)
9517 // else use the original url
9519 // Note that this should match what documents do (see nsDocument::Reset).
9520 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
9521 NS_ENSURE_TRUE(uri
, PR_FALSE
);
9523 return OnNewURI(uri
, aChannel
, nsnull
, mLoadType
, aFireOnLocationChange
,
9524 aAddToGlobalHistory
);
9529 nsDocShell::SetReferrerURI(nsIURI
* aURI
)
9531 mReferrerURI
= aURI
; // This assigment addrefs
9534 //*****************************************************************************
9535 // nsDocShell: Session History
9536 //*****************************************************************************
9539 nsDocShell::StringifyJSValVariant(nsIVariant
*aData
, nsAString
&aResult
)
9544 // First, try to extract a jsval from the variant |aData|. This works only
9545 // if the variant implements GetAsJSVal.
9547 rv
= aData
->GetAsJSVal(&jsData
);
9548 NS_ENSURE_SUCCESS(rv
, NS_ERROR_UNEXPECTED
);
9550 // Now get the JSContext associated with the current document.
9551 // First get the current document.
9552 nsCOMPtr
<nsIDocument
> document
= do_GetInterface(GetAsSupports(this));
9553 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
9555 // Get the JSContext from the document, like we do in
9556 // nsContentUtils::GetContextFromDocument().
9557 nsIScriptGlobalObject
*sgo
= document
->GetScopeObject();
9558 NS_ENSURE_TRUE(sgo
, NS_ERROR_FAILURE
);
9560 nsIScriptContext
*scx
= sgo
->GetContext();
9561 NS_ENSURE_TRUE(scx
, NS_ERROR_FAILURE
);
9563 JSContext
*cx
= (JSContext
*)scx
->GetNativeContext();
9565 // If our json call triggers a JS-to-C++ call, we want that call to use cx
9566 // as the context. So we push cx onto the context stack.
9567 nsCOMPtr
<nsIJSContextStack
> contextStack
=
9568 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
9569 NS_ENSURE_SUCCESS(rv
, rv
);
9571 contextStack
->Push(cx
);
9573 nsCOMPtr
<nsIJSON
> json
= do_GetService("@mozilla.org/dom/json;1");
9576 rv
= json
->EncodeFromJSVal(&jsData
, cx
, aResult
);
9579 rv
= NS_ERROR_FAILURE
;
9582 // Always pop the stack!
9583 contextStack
->Pop(&cx
);
9589 nsDocShell::AddState(nsIVariant
*aData
, const nsAString
& aTitle
,
9590 const nsAString
& aURL
, PRBool aReplace
)
9592 // Implements History.pushState and History.replaceState
9594 // Here's what we do, roughly in the order specified by HTML5:
9595 // 1. Serialize aData to JSON.
9596 // 2. If the third argument is present,
9597 // a. Resolve the url, relative to the first script's base URL
9598 // b. If (a) fails, raise a SECURITY_ERR
9599 // c. Compare the resulting absolute URL to the document's address. If
9600 // any part of the URLs difer other than the <path>, <query>, and
9601 // <fragment> components, raise a SECURITY_ERR and abort.
9603 // Remove from the session history all entries after the current entry,
9604 // as we would after a regular navigation, and save the current
9605 // entry's scroll position (bug 590573).
9606 // 4. As apropriate, either add a state object entry to the session history
9607 // after the current entry with the following properties, or modify the
9608 // current session history entry to set
9609 // a. cloned data as the state object,
9610 // b. if the third argument was present, the absolute URL found in
9612 // Also clear the new history entry's POST data (see bug 580069).
9613 // 5. If aReplace is false (i.e. we're doing a pushState instead of a
9614 // replaceState), notify bfcache that we've navigated to a new page.
9615 // 6. If the third argument is present, set the document's current address
9616 // to the absolute URL found in step 2.
9618 // It's important that this function not run arbitrary scripts after step 1
9619 // and before completing step 5. For example, if a script called
9620 // history.back() before we completed step 5, bfcache might destroy an
9621 // active content viewer. Since EvictContentViewers at the end of step 5
9622 // might run script, we can't just put a script blocker around the critical
9625 // Note that we completely ignore the aTitle parameter.
9629 nsCOMPtr
<nsIDocument
> document
= do_GetInterface(GetAsSupports(this));
9630 NS_ENSURE_TRUE(document
, NS_ERROR_FAILURE
);
9632 // Step 1: Clone aData by getting its JSON representation
9634 rv
= StringifyJSValVariant(aData
, dataStr
);
9635 NS_ENSURE_SUCCESS(rv
, rv
);
9637 // Check that the state object isn't too long.
9638 // Default max length: 640k chars.
9639 PRInt32 maxStateObjSize
= 0xA0000;
9641 mPrefs
->GetIntPref("browser.history.maxStateObjectSize",
9644 if (maxStateObjSize
< 0) {
9645 maxStateObjSize
= 0;
9647 NS_ENSURE_TRUE(dataStr
.Length() <= (PRUint32
)maxStateObjSize
,
9648 NS_ERROR_ILLEGAL_VALUE
);
9650 // Step 2: Resolve aURL
9651 PRBool equalURIs
= PR_TRUE
;
9652 nsCOMPtr
<nsIURI
> oldURI
= mCurrentURI
;
9653 nsCOMPtr
<nsIURI
> newURI
;
9654 if (aURL
.Length() == 0) {
9655 newURI
= mCurrentURI
;
9658 // 2a: Resolve aURL relative to mURI
9660 nsIURI
* docBaseURI
= document
->GetDocBaseURI();
9662 return NS_ERROR_FAILURE
;
9665 docBaseURI
->GetSpec(spec
);
9667 nsCAutoString charset
;
9668 rv
= docBaseURI
->GetOriginCharset(charset
);
9669 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
);
9671 rv
= NS_NewURI(getter_AddRefs(newURI
), aURL
,
9672 charset
.get(), docBaseURI
);
9674 // 2b: If 2a fails, raise a SECURITY_ERR
9675 if (NS_FAILED(rv
)) {
9676 return NS_ERROR_DOM_SECURITY_ERR
;
9679 // 2c: Same-origin check.
9680 if (!URIIsLocalFile(newURI
)) {
9681 // In addition to checking that the security manager says that
9682 // the new URI has the same origin as our current URI, we also
9683 // check that the two URIs have the same userpass. (The
9684 // security manager says that |http://foo.com| and
9685 // |http://me@foo.com| have the same origin.) mCurrentURI
9686 // won't contain the password part of the userpass, so this
9687 // means that it's never valid to specify a password in a
9688 // pushState or replaceState URI.
9690 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
9691 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
9692 NS_ENSURE_TRUE(secMan
, NS_ERROR_FAILURE
);
9694 // It's very important that we check that newURI is of the same
9695 // origin as mCurrentURI, not docBaseURI, because a page can
9696 // set docBaseURI arbitrarily to any domain.
9697 nsCAutoString currentUserPass
, newUserPass
;
9698 NS_ENSURE_SUCCESS(mCurrentURI
->GetUserPass(currentUserPass
),
9700 NS_ENSURE_SUCCESS(newURI
->GetUserPass(newUserPass
),
9702 if (NS_FAILED(secMan
->CheckSameOriginURI(mCurrentURI
,
9703 newURI
, PR_TRUE
)) ||
9704 !currentUserPass
.Equals(newUserPass
)) {
9706 return NS_ERROR_DOM_SECURITY_ERR
;
9710 // It's a file:// URI
9711 nsCOMPtr
<nsIScriptObjectPrincipal
> docScriptObj
=
9712 do_QueryInterface(document
);
9714 if (!docScriptObj
) {
9715 return NS_ERROR_DOM_SECURITY_ERR
;
9718 nsCOMPtr
<nsIPrincipal
> principal
= docScriptObj
->GetPrincipal();
9721 NS_FAILED(principal
->CheckMayLoad(newURI
, PR_TRUE
))) {
9723 return NS_ERROR_DOM_SECURITY_ERR
;
9727 mCurrentURI
->Equals(newURI
, &equalURIs
);
9729 } // end of same-origin check
9731 nsCOMPtr
<nsISHistory
> sessionHistory
= mSessionHistory
;
9732 if (!sessionHistory
) {
9733 // Get the handle to SH from the root docshell
9734 GetRootSessionHistory(getter_AddRefs(sessionHistory
));
9736 NS_ENSURE_TRUE(sessionHistory
, NS_ERROR_FAILURE
);
9738 nsCOMPtr
<nsISHistoryInternal
> shInternal
=
9739 do_QueryInterface(sessionHistory
, &rv
);
9740 NS_ENSURE_SUCCESS(rv
, rv
);
9742 // Step 3: Create a new entry in the session history. This will erase
9743 // all SHEntries after the new entry and make this entry the current
9744 // one. This operation may modify mOSHE, which we need later, so we
9745 // keep a reference here.
9746 NS_ENSURE_TRUE(mOSHE
, NS_ERROR_FAILURE
);
9747 nsCOMPtr
<nsISHEntry
> oldOSHE
= mOSHE
;
9749 mLoadType
= LOAD_PUSHSTATE
;
9751 nsCOMPtr
<nsISHEntry
> newSHEntry
;
9753 // Save the current scroll position (bug 590573).
9754 nscoord cx
= 0, cy
= 0;
9755 GetCurScrollPos(ScrollOrientation_X
, &cx
);
9756 GetCurScrollPos(ScrollOrientation_Y
, &cy
);
9757 mOSHE
->SetScrollPosition(cx
, cy
);
9759 rv
= AddToSessionHistory(newURI
, nsnull
, nsnull
,
9760 getter_AddRefs(newSHEntry
));
9761 NS_ENSURE_SUCCESS(rv
, rv
);
9763 NS_ENSURE_TRUE(newSHEntry
, NS_ERROR_FAILURE
);
9765 // Set the new SHEntry's document identifier, if we can.
9766 PRUint64 ourDocIdent
;
9767 NS_ENSURE_SUCCESS(oldOSHE
->GetDocIdentifier(&ourDocIdent
),
9769 NS_ENSURE_SUCCESS(newSHEntry
->SetDocIdentifier(ourDocIdent
),
9772 // AddToSessionHistory may not modify mOSHE. In case it doesn't,
9773 // we'll just set mOSHE here.
9778 newSHEntry
->SetURI(newURI
);
9781 // Step 4: Modify new/original session history entry and clear its POST
9782 // data, if there is any.
9783 newSHEntry
->SetStateData(dataStr
);
9784 newSHEntry
->SetPostData(nsnull
);
9786 // Step 5: If aReplace is false, indicating that we're doing a pushState
9787 // rather than a replaceState, notify bfcache that we've added a page to
9788 // the history so it can evict content viewers if appropriate.
9790 nsCOMPtr
<nsISHistory
> rootSH
;
9791 GetRootSessionHistory(getter_AddRefs(rootSH
));
9792 NS_ENSURE_TRUE(rootSH
, NS_ERROR_UNEXPECTED
);
9794 nsCOMPtr
<nsISHistoryInternal
> internalSH
=
9795 do_QueryInterface(rootSH
);
9796 NS_ENSURE_TRUE(internalSH
, NS_ERROR_UNEXPECTED
);
9798 PRInt32 curIndex
= -1;
9799 rv
= rootSH
->GetIndex(&curIndex
);
9800 if (NS_SUCCEEDED(rv
) && curIndex
> -1) {
9801 internalSH
->EvictContentViewers(curIndex
- 1, curIndex
);
9805 // Step 6: If the document's URI changed, update document's URI and update
9808 // We need to call FireOnLocationChange so that the browser's address bar
9809 // gets updated and the back button is enabled, but we only need to
9810 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
9811 // since SetCurrentURI will call FireOnLocationChange for us.
9813 SetCurrentURI(newURI
, nsnull
, PR_TRUE
);
9814 document
->SetDocumentURI(newURI
);
9816 AddURIVisit(newURI
, oldURI
, oldURI
, 0);
9819 FireDummyOnLocationChange();
9822 // A call to push/replaceState prevents popstate events from firing until
9823 // the next time we call InternalLoad.
9824 mSuppressPopstate
= PR_TRUE
;
9830 nsDocShell::ShouldAddToSessionHistory(nsIURI
* aURI
)
9832 // I believe none of the about: urls should go in the history. But then
9833 // that could just be me... If the intent is only deny about:blank then we
9834 // should just do a spec compare, rather than two gets of the scheme and
9835 // then the path. -Gagan
9839 rv
= aURI
->GetScheme(buf
);
9843 if (buf
.Equals("about")) {
9844 rv
= aURI
->GetPath(buf
);
9848 if (buf
.Equals("blank")) {
9856 nsDocShell::AddToSessionHistory(nsIURI
* aURI
, nsIChannel
* aChannel
,
9857 nsISupports
* aOwner
, nsISHEntry
** aNewEntry
)
9859 NS_PRECONDITION(aURI
, "uri is null");
9860 NS_PRECONDITION(!aChannel
|| !aOwner
, "Shouldn't have both set");
9862 #if defined(PR_LOGGING) && defined(DEBUG)
9863 if (PR_LOG_TEST(gDocShellLog
, PR_LOG_DEBUG
)) {
9865 aURI
->GetSpec(spec
);
9867 nsCAutoString chanName
;
9869 aChannel
->GetName(chanName
);
9871 chanName
.AssignLiteral("<no channel>");
9873 PR_LOG(gDocShellLog
, PR_LOG_DEBUG
,
9874 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec
.get(),
9879 nsresult rv
= NS_OK
;
9880 nsCOMPtr
<nsISHEntry
> entry
;
9881 PRBool shouldPersist
;
9883 shouldPersist
= ShouldAddToSessionHistory(aURI
);
9885 // Get a handle to the root docshell
9886 nsCOMPtr
<nsIDocShellTreeItem
> root
;
9887 GetSameTypeRootTreeItem(getter_AddRefs(root
));
9889 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
9890 * the existing SH entry in the page and replace the url and
9893 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
) &&
9894 root
!= static_cast<nsIDocShellTreeItem
*>(this)) {
9895 // This is a subframe
9897 nsCOMPtr
<nsISHContainer
> shContainer(do_QueryInterface(entry
));
9899 PRInt32 childCount
= 0;
9900 shContainer
->GetChildCount(&childCount
);
9901 // Remove all children of this entry
9902 for (PRInt32 i
= childCount
- 1; i
>= 0; i
--) {
9903 nsCOMPtr
<nsISHEntry
> child
;
9904 shContainer
->GetChildAt(i
, getter_AddRefs(child
));
9905 shContainer
->RemoveChild(child
);
9910 // Create a new entry if necessary.
9912 entry
= do_CreateInstance(NS_SHENTRY_CONTRACTID
);
9915 return NS_ERROR_OUT_OF_MEMORY
;
9919 // Get the post data & referrer
9920 nsCOMPtr
<nsIInputStream
> inputStream
;
9921 nsCOMPtr
<nsIURI
> referrerURI
;
9922 nsCOMPtr
<nsISupports
> cacheKey
;
9923 nsCOMPtr
<nsISupports
> owner
= aOwner
;
9924 PRBool expired
= PR_FALSE
;
9925 PRBool discardLayoutState
= PR_FALSE
;
9926 nsCOMPtr
<nsICachingChannel
> cacheChannel
;
9928 cacheChannel
= do_QueryInterface(aChannel
);
9930 /* If there is a caching channel, get the Cache Key and store it
9934 cacheChannel
->GetCacheKey(getter_AddRefs(cacheKey
));
9936 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
9938 // Check if the httpChannel is hiding under a multipartChannel
9940 GetHttpChannel(aChannel
, getter_AddRefs(httpChannel
));
9943 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
9944 if (uploadChannel
) {
9945 uploadChannel
->GetUploadStream(getter_AddRefs(inputStream
));
9947 httpChannel
->GetReferrer(getter_AddRefs(referrerURI
));
9949 discardLayoutState
= ShouldDiscardLayoutState(httpChannel
);
9951 aChannel
->GetOwner(getter_AddRefs(owner
));
9954 //Title is set in nsDocShell::SetTitle()
9955 entry
->Create(aURI
, // uri
9956 EmptyString(), // Title
9957 inputStream
, // Post data stream
9958 nsnull
, // LayoutHistory state
9959 cacheKey
, // CacheKey
9960 mContentTypeHint
, // Content-type
9961 owner
, // Channel or provided owner
9963 mDynamicallyCreated
);
9964 entry
->SetReferrerURI(referrerURI
);
9965 /* If cache got a 'no-store', ask SH not to store
9966 * HistoryLayoutState. By default, SH will set this
9967 * flag to PR_TRUE and save HistoryLayoutState.
9969 if (discardLayoutState
) {
9970 entry
->SetSaveLayoutStateFlag(PR_FALSE
);
9973 // Check if the page has expired from cache
9974 PRUint32 expTime
= 0;
9975 cacheChannel
->GetCacheTokenExpirationTime(&expTime
);
9976 PRUint32 now
= PRTimeToSeconds(PR_Now());
9981 entry
->SetExpirationStatus(PR_TRUE
);
9984 if (root
== static_cast<nsIDocShellTreeItem
*>(this) && mSessionHistory
) {
9985 // Bug 629559: Detect if this is an anchor navigation and clone the
9986 // session history in that case too
9987 if (mLoadType
== LOAD_PUSHSTATE
&& mOSHE
) {
9989 mOSHE
->GetID(&cloneID
);
9990 nsCOMPtr
<nsISHEntry
> newEntry
;
9991 CloneAndReplace(mOSHE
, this, cloneID
, entry
, PR_TRUE
, getter_AddRefs(newEntry
));
9992 NS_ASSERTION(entry
== newEntry
, "The new session history should be in the new entry");
9995 // This is the root docshell
9996 if (LOAD_TYPE_HAS_FLAGS(mLoadType
, LOAD_FLAGS_REPLACE_HISTORY
)) {
9997 // Replace current entry in session history.
9999 mSessionHistory
->GetIndex(&index
);
10000 nsCOMPtr
<nsISHistoryInternal
> shPrivate(do_QueryInterface(mSessionHistory
));
10001 // Replace the current entry with the new entry
10003 rv
= shPrivate
->ReplaceEntry(index
, entry
);
10006 // Add to session history
10007 nsCOMPtr
<nsISHistoryInternal
>
10008 shPrivate(do_QueryInterface(mSessionHistory
));
10009 NS_ENSURE_TRUE(shPrivate
, NS_ERROR_FAILURE
);
10010 mSessionHistory
->GetIndex(&mPreviousTransIndex
);
10011 rv
= shPrivate
->AddEntry(entry
, shouldPersist
);
10012 mSessionHistory
->GetIndex(&mLoadedTransIndex
);
10013 #ifdef DEBUG_PAGE_CACHE
10014 printf("Previous index: %d, Loaded index: %d\n\n",
10015 mPreviousTransIndex
, mLoadedTransIndex
);
10020 // This is a subframe.
10021 if (!mOSHE
|| !LOAD_TYPE_HAS_FLAGS(mLoadType
,
10022 LOAD_FLAGS_REPLACE_HISTORY
))
10023 rv
= DoAddChildSHEntry(entry
, mChildOffset
);
10026 // Return the new SH entry...
10028 *aNewEntry
= nsnull
;
10029 if (NS_SUCCEEDED(rv
)) {
10030 *aNewEntry
= entry
;
10031 NS_ADDREF(*aNewEntry
);
10040 nsDocShell::LoadHistoryEntry(nsISHEntry
* aEntry
, PRUint32 aLoadType
)
10042 if (!IsNavigationAllowed()) {
10046 nsCOMPtr
<nsIURI
> uri
;
10047 nsCOMPtr
<nsIInputStream
> postData
;
10048 nsCOMPtr
<nsIURI
> referrerURI
;
10049 nsCAutoString contentType
;
10050 nsCOMPtr
<nsISupports
> owner
;
10052 NS_ENSURE_TRUE(aEntry
, NS_ERROR_FAILURE
);
10054 NS_ENSURE_SUCCESS(aEntry
->GetURI(getter_AddRefs(uri
)), NS_ERROR_FAILURE
);
10055 NS_ENSURE_SUCCESS(aEntry
->GetReferrerURI(getter_AddRefs(referrerURI
)),
10057 NS_ENSURE_SUCCESS(aEntry
->GetPostData(getter_AddRefs(postData
)),
10059 NS_ENSURE_SUCCESS(aEntry
->GetContentType(contentType
), NS_ERROR_FAILURE
);
10060 NS_ENSURE_SUCCESS(aEntry
->GetOwner(getter_AddRefs(owner
)),
10063 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
10064 // that's the only thing holding a ref to aEntry that will cause aEntry to
10065 // die while we're loading it. So hold a strong ref to aEntry here, just
10067 nsCOMPtr
<nsISHEntry
> kungFuDeathGrip(aEntry
);
10069 nsresult rv
= uri
->SchemeIs("javascript", &isJS
);
10070 if (NS_FAILED(rv
) || isJS
) {
10071 // We're loading a URL that will execute script from inside asyncOpen.
10072 // Replace the current document with about:blank now to prevent
10073 // anything from the current document from leaking into any JavaScript
10074 // code in the URL.
10075 nsCOMPtr
<nsIPrincipal
> prin
= do_QueryInterface(owner
);
10076 // Don't cache the presentation if we're going to just reload the
10077 // current entry. Caching would lead to trying to save the different
10078 // content viewers in the same nsISHEntry object.
10079 rv
= CreateAboutBlankContentViewer(prin
, nsnull
, aEntry
!= mOSHE
);
10081 if (NS_FAILED(rv
)) {
10082 // The creation of the intermittent about:blank content
10083 // viewer failed for some reason (potentially because the
10084 // user prevented it). Interrupt the history load.
10089 // Ensure that we have an owner. Otherwise javascript: URIs will
10090 // pick it up from the about:blank page we just loaded, and we
10091 // don't really want even that in this case.
10092 owner
= do_CreateInstance("@mozilla.org/nullprincipal;1");
10093 NS_ENSURE_TRUE(owner
, NS_ERROR_OUT_OF_MEMORY
);
10097 /* If there is a valid postdata *and* the user pressed
10098 * reload or shift-reload, take user's permission before we
10099 * repost the data to the server.
10101 if ((aLoadType
& LOAD_CMD_RELOAD
) && postData
) {
10103 rv
= ConfirmRepost(&repost
);
10104 if (NS_FAILED(rv
)) return rv
;
10106 // If the user pressed cancel in the dialog, return. We're done here.
10108 return NS_BINDING_ABORTED
;
10111 rv
= InternalLoad(uri
,
10114 INTERNAL_LOAD_FLAGS_NONE
, // Do not inherit owner from document (security-critical!)
10115 nsnull
, // No window target
10116 contentType
.get(), // Type hint
10117 postData
, // Post data stream
10118 nsnull
, // No headers stream
10119 aLoadType
, // Load type
10122 nsnull
, // No nsIDocShell
10123 nsnull
); // No nsIRequest
10127 NS_IMETHODIMP
nsDocShell::GetShouldSaveLayoutState(PRBool
* aShould
)
10129 *aShould
= PR_FALSE
;
10131 // Don't capture historystate and save it in history
10132 // if the page asked not to do so.
10133 mOSHE
->GetSaveLayoutStateFlag(aShould
);
10139 NS_IMETHODIMP
nsDocShell::PersistLayoutHistoryState()
10141 nsresult rv
= NS_OK
;
10144 nsCOMPtr
<nsIPresShell
> shell
;
10145 rv
= GetPresShell(getter_AddRefs(shell
));
10146 if (NS_SUCCEEDED(rv
) && shell
) {
10147 nsCOMPtr
<nsILayoutHistoryState
> layoutState
;
10148 rv
= shell
->CaptureHistoryState(getter_AddRefs(layoutState
),
10156 /* static */ nsresult
10157 nsDocShell::WalkHistoryEntries(nsISHEntry
*aRootEntry
,
10158 nsDocShell
*aRootShell
,
10159 WalkHistoryEntriesFunc aCallback
,
10162 NS_ENSURE_TRUE(aRootEntry
, NS_ERROR_FAILURE
);
10164 nsCOMPtr
<nsISHContainer
> container(do_QueryInterface(aRootEntry
));
10166 return NS_ERROR_FAILURE
;
10168 PRInt32 childCount
;
10169 container
->GetChildCount(&childCount
);
10170 for (PRInt32 i
= 0; i
< childCount
; i
++) {
10171 nsCOMPtr
<nsISHEntry
> childEntry
;
10172 container
->GetChildAt(i
, getter_AddRefs(childEntry
));
10174 // childEntry can be null for valid reasons, for example if the
10175 // docshell at index i never loaded anything useful.
10176 // Remember to clone also nulls in the child array (bug 464064).
10177 aCallback(nsnull
, nsnull
, i
, aData
);
10181 nsDocShell
*childShell
= nsnull
;
10183 // Walk the children of aRootShell and see if one of them
10184 // has srcChild as a SHEntry.
10186 PRInt32 childCount
= aRootShell
->mChildList
.Count();
10187 for (PRInt32 j
= 0; j
< childCount
; ++j
) {
10188 nsDocShell
*child
=
10189 static_cast<nsDocShell
*>(aRootShell
->ChildAt(j
));
10191 if (child
->HasHistoryEntry(childEntry
)) {
10192 childShell
= child
;
10197 nsresult rv
= aCallback(childEntry
, childShell
, i
, aData
);
10198 NS_ENSURE_SUCCESS(rv
, rv
);
10204 // callback data for WalkHistoryEntries
10205 struct NS_STACK_CLASS CloneAndReplaceData
10207 CloneAndReplaceData(PRUint32 aCloneID
, nsISHEntry
*aReplaceEntry
,
10208 PRBool aCloneChildren
, nsISHEntry
*aDestTreeParent
)
10209 : cloneID(aCloneID
),
10210 cloneChildren(aCloneChildren
),
10211 replaceEntry(aReplaceEntry
),
10212 destTreeParent(aDestTreeParent
) { }
10215 PRBool cloneChildren
;
10216 nsISHEntry
*replaceEntry
;
10217 nsISHEntry
*destTreeParent
;
10218 nsCOMPtr
<nsISHEntry
> resultEntry
;
10221 /* static */ nsresult
10222 nsDocShell::CloneAndReplaceChild(nsISHEntry
*aEntry
, nsDocShell
*aShell
,
10223 PRInt32 aEntryIndex
, void *aData
)
10225 nsresult result
= NS_OK
;
10226 nsCOMPtr
<nsISHEntry
> dest
;
10228 CloneAndReplaceData
*data
= static_cast<CloneAndReplaceData
*>(aData
);
10229 PRUint32 cloneID
= data
->cloneID
;
10230 nsISHEntry
*replaceEntry
= data
->replaceEntry
;
10232 nsCOMPtr
<nsISHContainer
> container
=
10233 do_QueryInterface(data
->destTreeParent
);
10236 container
->AddChild(nsnull
, aEntryIndex
);
10242 aEntry
->GetID(&srcID
);
10244 if (srcID
== cloneID
) {
10245 // Replace the entry
10246 dest
= replaceEntry
;
10247 dest
->SetIsSubFrame(PR_TRUE
);
10249 if (data
->cloneChildren
) {
10250 // Walk the children
10251 CloneAndReplaceData
childData(cloneID
, replaceEntry
,
10252 data
->cloneChildren
, dest
);
10253 result
= WalkHistoryEntries(aEntry
, aShell
,
10254 CloneAndReplaceChild
, &childData
);
10255 if (NS_FAILED(result
))
10259 // Clone the SHEntry...
10260 result
= aEntry
->Clone(getter_AddRefs(dest
));
10261 if (NS_FAILED(result
))
10264 // This entry is for a subframe navigation
10265 dest
->SetIsSubFrame(PR_TRUE
);
10267 // Walk the children
10268 CloneAndReplaceData
childData(cloneID
, replaceEntry
,
10269 data
->cloneChildren
, dest
);
10270 result
= WalkHistoryEntries(aEntry
, aShell
,
10271 CloneAndReplaceChild
, &childData
);
10272 if (NS_FAILED(result
))
10276 aShell
->SwapHistoryEntries(aEntry
, dest
);
10280 container
->AddChild(dest
, aEntryIndex
);
10282 data
->resultEntry
= dest
;
10286 /* static */ nsresult
10287 nsDocShell::CloneAndReplace(nsISHEntry
*aSrcEntry
,
10288 nsDocShell
*aSrcShell
,
10290 nsISHEntry
*aReplaceEntry
,
10291 PRBool aCloneChildren
,
10292 nsISHEntry
**aResultEntry
)
10294 NS_ENSURE_ARG_POINTER(aResultEntry
);
10295 NS_ENSURE_TRUE(aReplaceEntry
, NS_ERROR_FAILURE
);
10297 CloneAndReplaceData
data(aCloneID
, aReplaceEntry
, aCloneChildren
, nsnull
);
10298 nsresult rv
= CloneAndReplaceChild(aSrcEntry
, aSrcShell
, 0, &data
);
10300 data
.resultEntry
.swap(*aResultEntry
);
10305 nsDocShell::SwapHistoryEntries(nsISHEntry
*aOldEntry
, nsISHEntry
*aNewEntry
)
10307 if (aOldEntry
== mOSHE
)
10310 if (aOldEntry
== mLSHE
)
10315 struct SwapEntriesData
10317 nsDocShell
*ignoreShell
; // constant; the shell to ignore
10318 nsISHEntry
*destTreeRoot
; // constant; the root of the dest tree
10319 nsISHEntry
*destTreeParent
; // constant; the node under destTreeRoot
10320 // whose children will correspond to aEntry
10325 nsDocShell::SetChildHistoryEntry(nsISHEntry
*aEntry
, nsDocShell
*aShell
,
10326 PRInt32 aEntryIndex
, void *aData
)
10328 SwapEntriesData
*data
= static_cast<SwapEntriesData
*>(aData
);
10329 nsDocShell
*ignoreShell
= data
->ignoreShell
;
10331 if (!aShell
|| aShell
== ignoreShell
)
10334 nsISHEntry
*destTreeRoot
= data
->destTreeRoot
;
10336 nsCOMPtr
<nsISHEntry
> destEntry
;
10337 nsCOMPtr
<nsISHContainer
> container
=
10338 do_QueryInterface(data
->destTreeParent
);
10341 // aEntry is a clone of some child of destTreeParent, but since the
10342 // trees aren't necessarily in sync, we'll have to locate it.
10343 // Note that we could set aShell's entry to null if we don't find a
10344 // corresponding entry under destTreeParent.
10346 PRUint32 targetID
, id
;
10347 aEntry
->GetID(&targetID
);
10349 // First look at the given index, since this is the common case.
10350 nsCOMPtr
<nsISHEntry
> entry
;
10351 container
->GetChildAt(aEntryIndex
, getter_AddRefs(entry
));
10352 if (entry
&& NS_SUCCEEDED(entry
->GetID(&id
)) && id
== targetID
) {
10353 destEntry
.swap(entry
);
10355 PRInt32 childCount
;
10356 container
->GetChildCount(&childCount
);
10357 for (PRInt32 i
= 0; i
< childCount
; ++i
) {
10358 container
->GetChildAt(i
, getter_AddRefs(entry
));
10363 if (id
== targetID
) {
10364 destEntry
.swap(entry
);
10370 destEntry
= destTreeRoot
;
10373 aShell
->SwapHistoryEntries(aEntry
, destEntry
);
10375 // Now handle the children of aEntry.
10376 SwapEntriesData childData
= { ignoreShell
, destTreeRoot
, destEntry
};
10377 return WalkHistoryEntries(aEntry
, aShell
,
10378 SetChildHistoryEntry
, &childData
);
10383 GetRootSHEntry(nsISHEntry
*aEntry
)
10385 nsCOMPtr
<nsISHEntry
> rootEntry
= aEntry
;
10386 nsISHEntry
*result
= nsnull
;
10387 while (rootEntry
) {
10388 result
= rootEntry
;
10389 result
->GetParent(getter_AddRefs(rootEntry
));
10397 nsDocShell::SetHistoryEntry(nsCOMPtr
<nsISHEntry
> *aPtr
, nsISHEntry
*aEntry
)
10399 // We need to sync up the docshell and session history trees for
10400 // subframe navigation. If the load was in a subframe, we forward up to
10401 // the root docshell, which will then recursively sync up all docshells
10402 // to their corresponding entries in the new session history tree.
10403 // If we don't do this, then we can cache a content viewer on the wrong
10404 // cloned entry, and subsequently restore it at the wrong time.
10406 nsISHEntry
*newRootEntry
= GetRootSHEntry(aEntry
);
10407 if (newRootEntry
) {
10408 // newRootEntry is now the new root entry.
10409 // Find the old root entry as well.
10411 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
10412 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
10413 nsCOMPtr
<nsISHEntry
> oldRootEntry
= GetRootSHEntry(*aPtr
);
10414 if (oldRootEntry
) {
10415 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
10416 GetSameTypeParent(getter_AddRefs(parentAsItem
));
10417 nsCOMPtr
<nsIDocShell
> rootShell
= do_QueryInterface(parentAsItem
);
10418 if (rootShell
) { // if we're the root just set it, nothing to swap
10419 SwapEntriesData data
= { this, newRootEntry
};
10420 nsIDocShell
*rootIDocShell
=
10421 static_cast<nsIDocShell
*>(rootShell
);
10422 nsDocShell
*rootDocShell
= static_cast<nsDocShell
*>
10428 SetChildHistoryEntry(oldRootEntry
, rootDocShell
,
10430 NS_ASSERTION(NS_SUCCEEDED(rv
), "SetChildHistoryEntry failed");
10440 nsDocShell::GetRootSessionHistory(nsISHistory
** aReturn
)
10444 nsCOMPtr
<nsIDocShellTreeItem
> root
;
10445 //Get the root docshell
10446 rv
= GetSameTypeRootTreeItem(getter_AddRefs(root
));
10447 // QI to nsIWebNavigation
10448 nsCOMPtr
<nsIWebNavigation
> rootAsWebnav(do_QueryInterface(root
));
10449 if (rootAsWebnav
) {
10450 // Get the handle to SH from the root docshell
10451 rv
= rootAsWebnav
->GetSessionHistory(aReturn
);
10457 nsDocShell::GetHttpChannel(nsIChannel
* aChannel
, nsIHttpChannel
** aReturn
)
10459 NS_ENSURE_ARG_POINTER(aReturn
);
10461 return NS_ERROR_FAILURE
;
10463 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel(do_QueryInterface(aChannel
));
10464 if (multiPartChannel
) {
10465 nsCOMPtr
<nsIChannel
> baseChannel
;
10466 multiPartChannel
->GetBaseChannel(getter_AddRefs(baseChannel
));
10467 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(baseChannel
));
10468 *aReturn
= httpChannel
;
10469 NS_IF_ADDREF(*aReturn
);
10475 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel
* aChannel
)
10477 // By default layout State will be saved.
10481 // figure out if SH should be saving layout state
10482 nsCOMPtr
<nsISupports
> securityInfo
;
10483 PRBool noStore
= PR_FALSE
, noCache
= PR_FALSE
;
10484 aChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
10485 aChannel
->IsNoStoreResponse(&noStore
);
10486 aChannel
->IsNoCacheResponse(&noCache
);
10488 return (noStore
|| (noCache
&& securityInfo
));
10491 //*****************************************************************************
10492 // nsDocShell: nsIEditorDocShell
10493 //*****************************************************************************
10495 NS_IMETHODIMP
nsDocShell::GetEditor(nsIEditor
* *aEditor
)
10497 NS_ENSURE_ARG_POINTER(aEditor
);
10499 if (!mEditorData
) {
10504 return mEditorData
->GetEditor(aEditor
);
10507 NS_IMETHODIMP
nsDocShell::SetEditor(nsIEditor
* aEditor
)
10509 nsresult rv
= EnsureEditorData();
10510 if (NS_FAILED(rv
)) return rv
;
10512 return mEditorData
->SetEditor(aEditor
);
10516 NS_IMETHODIMP
nsDocShell::GetEditable(PRBool
*aEditable
)
10518 NS_ENSURE_ARG_POINTER(aEditable
);
10519 *aEditable
= mEditorData
&& mEditorData
->GetEditable();
10524 NS_IMETHODIMP
nsDocShell::GetHasEditingSession(PRBool
*aHasEditingSession
)
10526 NS_ENSURE_ARG_POINTER(aHasEditingSession
);
10530 nsCOMPtr
<nsIEditingSession
> editingSession
;
10531 mEditorData
->GetEditingSession(getter_AddRefs(editingSession
));
10532 *aHasEditingSession
= (editingSession
.get() != nsnull
);
10536 *aHasEditingSession
= PR_FALSE
;
10542 NS_IMETHODIMP
nsDocShell::MakeEditable(PRBool inWaitForUriLoad
)
10544 nsresult rv
= EnsureEditorData();
10545 if (NS_FAILED(rv
)) return rv
;
10547 return mEditorData
->MakeEditable(inWaitForUriLoad
);
10551 nsDocShell::ChannelIsPost(nsIChannel
* aChannel
)
10553 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
10554 if (!httpChannel
) {
10558 nsCAutoString method
;
10559 httpChannel
->GetRequestMethod(method
);
10560 return method
.Equals("POST");
10564 nsDocShell::ExtractLastVisit(nsIChannel
* aChannel
,
10566 PRUint32
* aChannelRedirectFlags
)
10568 nsCOMPtr
<nsIPropertyBag2
> props(do_QueryInterface(aChannel
));
10573 nsresult rv
= props
->GetPropertyAsInterface(
10574 NS_LITERAL_STRING("docshell.previousURI"),
10575 NS_GET_IID(nsIURI
),
10576 reinterpret_cast<void**>(aURI
)
10579 if (NS_FAILED(rv
)) {
10580 // There is no last visit for this channel, so this must be the first
10581 // link. Link the visit to the referrer of this request, if any.
10582 // Treat referrer as null if there is an error getting it.
10583 (void)NS_GetReferrerFromChannel(aChannel
, aURI
);
10586 rv
= props
->GetPropertyAsUint32(
10587 NS_LITERAL_STRING("docshell.previousFlags"),
10588 aChannelRedirectFlags
10593 "Could not fetch previous flags, URI will be treated like referrer"
10599 nsDocShell::SaveLastVisit(nsIChannel
* aChannel
,
10601 PRUint32 aChannelRedirectFlags
)
10603 nsCOMPtr
<nsIWritablePropertyBag2
> props(do_QueryInterface(aChannel
));
10604 if (!props
|| !aURI
) {
10608 props
->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
10610 props
->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
10611 aChannelRedirectFlags
);
10615 nsDocShell::AddURIVisit(nsIURI
* aURI
,
10616 nsIURI
* aReferrerURI
,
10617 nsIURI
* aPreviousURI
,
10618 PRUint32 aChannelRedirectFlags
)
10620 NS_ASSERTION(aURI
, "Visited URI is null!");
10622 // Only content-type docshells save URI visits. Also don't do
10623 // anything here if we're not supposed to use global history.
10624 if (mItemType
!= typeContent
|| !mUseGlobalHistory
) {
10628 nsCOMPtr
<IHistory
> history
= services::GetHistoryService();
10631 PRUint32 visitURIFlags
= 0;
10634 visitURIFlags
|= IHistory::TOP_LEVEL
;
10637 if (aChannelRedirectFlags
& nsIChannelEventSink::REDIRECT_TEMPORARY
) {
10638 visitURIFlags
|= IHistory::REDIRECT_TEMPORARY
;
10640 else if (aChannelRedirectFlags
&
10641 nsIChannelEventSink::REDIRECT_PERMANENT
) {
10642 visitURIFlags
|= IHistory::REDIRECT_PERMANENT
;
10645 (void)history
->VisitURI(aURI
, aPreviousURI
, visitURIFlags
);
10647 else if (mGlobalHistory
) {
10648 // Falls back to sync global history interface.
10649 (void)mGlobalHistory
->AddURI(aURI
,
10650 !!aChannelRedirectFlags
,
10656 //*****************************************************************************
10657 // nsDocShell: Helper Routines
10658 //*****************************************************************************
10661 nsDocShell::SetLoadType(PRUint32 aLoadType
)
10663 mLoadType
= aLoadType
;
10668 nsDocShell::GetLoadType(PRUint32
* aLoadType
)
10670 *aLoadType
= mLoadType
;
10675 nsDocShell::ConfirmRepost(PRBool
* aRepost
)
10677 nsCOMPtr
<nsIPrompt
> prompter
;
10678 CallGetInterface(this, static_cast<nsIPrompt
**>(getter_AddRefs(prompter
)));
10680 return NS_ERROR_NOT_AVAILABLE
;
10683 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
10684 mozilla::services::GetStringBundleService();
10685 if (!stringBundleService
)
10686 return NS_ERROR_FAILURE
;
10688 nsCOMPtr
<nsIStringBundle
> appBundle
;
10689 nsresult rv
= stringBundleService
->CreateBundle(kAppstringsBundleURL
,
10690 getter_AddRefs(appBundle
));
10691 NS_ENSURE_SUCCESS(rv
, rv
);
10693 nsCOMPtr
<nsIStringBundle
> brandBundle
;
10694 rv
= stringBundleService
->CreateBundle(kBrandBundleURL
, getter_AddRefs(brandBundle
));
10695 NS_ENSURE_SUCCESS(rv
, rv
);
10697 NS_ASSERTION(prompter
&& brandBundle
&& appBundle
,
10698 "Unable to set up repost prompter.");
10700 nsXPIDLString brandName
;
10701 rv
= brandBundle
->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
10702 getter_Copies(brandName
));
10704 nsXPIDLString msgString
, button0Title
;
10705 if (NS_FAILED(rv
)) { // No brand, use the generic version.
10706 rv
= appBundle
->GetStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
10707 getter_Copies(msgString
));
10710 // Brand available - if the app has an override file with formatting, the app name will
10711 // be included. Without an override, the prompt will look like the generic version.
10712 const PRUnichar
*formatStrings
[] = { brandName
.get() };
10713 rv
= appBundle
->FormatStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
10714 formatStrings
, NS_ARRAY_LENGTH(formatStrings
),
10715 getter_Copies(msgString
));
10717 if (NS_FAILED(rv
)) return rv
;
10719 rv
= appBundle
->GetStringFromName(NS_LITERAL_STRING("resendButton.label").get(),
10720 getter_Copies(button0Title
));
10721 if (NS_FAILED(rv
)) return rv
;
10723 PRInt32 buttonPressed
;
10726 ConfirmEx(nsnull
, msgString
.get(),
10727 (nsIPrompt::BUTTON_POS_0
* nsIPrompt::BUTTON_TITLE_IS_STRING
) +
10728 (nsIPrompt::BUTTON_POS_1
* nsIPrompt::BUTTON_TITLE_CANCEL
),
10729 button0Title
.get(), nsnull
, nsnull
, nsnull
, &checkState
, &buttonPressed
);
10730 if (NS_FAILED(rv
)) return rv
;
10732 *aRepost
= (buttonPressed
== 0);
10737 nsDocShell::GetPromptAndStringBundle(nsIPrompt
** aPrompt
,
10738 nsIStringBundle
** aStringBundle
)
10740 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt
), (void **) aPrompt
),
10743 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
10744 mozilla::services::GetStringBundleService();
10745 NS_ENSURE_TRUE(stringBundleService
, NS_ERROR_FAILURE
);
10747 NS_ENSURE_SUCCESS(stringBundleService
->
10748 CreateBundle(kAppstringsBundleURL
,
10756 nsDocShell::GetChildOffset(nsIDOMNode
* aChild
, nsIDOMNode
* aParent
,
10759 NS_ENSURE_ARG_POINTER(aChild
|| aParent
);
10761 nsCOMPtr
<nsIDOMNodeList
> childNodes
;
10762 NS_ENSURE_SUCCESS(aParent
->GetChildNodes(getter_AddRefs(childNodes
)),
10764 NS_ENSURE_TRUE(childNodes
, NS_ERROR_FAILURE
);
10768 for (; PR_TRUE
; i
++) {
10769 nsCOMPtr
<nsIDOMNode
> childNode
;
10770 NS_ENSURE_SUCCESS(childNodes
->Item(i
, getter_AddRefs(childNode
)),
10772 NS_ENSURE_TRUE(childNode
, NS_ERROR_FAILURE
);
10774 if (childNode
.get() == aChild
) {
10780 return NS_ERROR_FAILURE
;
10783 nsIScrollableFrame
*
10784 nsDocShell::GetRootScrollFrame()
10786 nsCOMPtr
<nsIPresShell
> shell
;
10787 NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(shell
)), nsnull
);
10788 NS_ENSURE_TRUE(shell
, nsnull
);
10790 return shell
->GetRootScrollFrameAsScrollableExternal();
10794 class nsDebugAutoBoolTrueSetter
10797 nsDebugAutoBoolTrueSetter(PRPackedBool
*aBool
)
10803 ~nsDebugAutoBoolTrueSetter()
10808 PRPackedBool
*mBool
;
10813 nsDocShell::EnsureScriptEnvironment()
10818 if (mIsBeingDestroyed
) {
10819 return NS_ERROR_NOT_AVAILABLE
;
10825 NS_ASSERTION(!mInEnsureScriptEnv
,
10826 "Infinite loop! Calling EnsureScriptEnvironment() from "
10827 "within EnsureScriptEnvironment()!");
10829 // Yeah, this isn't re-entrant safe, but that's ok since if we
10830 // re-enter this method, we'll infinitely loop...
10831 nsDebugAutoBoolTrueSetter
boolSetter(&mInEnsureScriptEnv
);
10834 nsCOMPtr
<nsIDOMScriptObjectFactory
> factory
=
10835 do_GetService(kDOMScriptObjectFactoryCID
);
10836 NS_ENSURE_TRUE(factory
, NS_ERROR_FAILURE
);
10838 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
10839 NS_ENSURE_TRUE(browserChrome
, NS_ERROR_NOT_AVAILABLE
);
10841 PRUint32 chromeFlags
;
10842 browserChrome
->GetChromeFlags(&chromeFlags
);
10844 PRBool isModalContentWindow
=
10845 (chromeFlags
& nsIWebBrowserChrome::CHROME_MODAL
) &&
10846 !(chromeFlags
& nsIWebBrowserChrome::CHROME_OPENAS_CHROME
);
10848 // If our window is modal and we're not opened as chrome, make
10849 // this window a modal content window.
10850 factory
->NewScriptGlobalObject(mItemType
== typeChrome
,
10851 isModalContentWindow
,
10852 getter_AddRefs(mScriptGlobal
));
10853 NS_ENSURE_TRUE(mScriptGlobal
, NS_ERROR_FAILURE
);
10855 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
10856 win
->SetDocShell(static_cast<nsIDocShell
*>(this));
10858 // Ensure the script object is set to run javascript - other languages
10859 // setup on demand.
10860 // XXXmarkh - should this be setup to run the default language for this doc?
10862 rv
= mScriptGlobal
->EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT
);
10863 NS_ENSURE_SUCCESS(rv
, rv
);
10870 nsDocShell::EnsureEditorData()
10872 PRBool openDocHasDetachedEditor
= mOSHE
&& mOSHE
->HasDetachedEditor();
10873 if (!mEditorData
&& !mIsBeingDestroyed
&& !openDocHasDetachedEditor
) {
10874 // We shouldn't recreate the editor data if it already exists, or
10875 // we're shutting down, or we already have a detached editor data
10876 // stored in the session history. We should only have one editordata
10878 mEditorData
= new nsDocShellEditorData(this);
10881 return mEditorData
? NS_OK
: NS_ERROR_NOT_AVAILABLE
;
10885 nsDocShell::EnsureTransferableHookData()
10887 if (!mTransferableHookData
) {
10888 mTransferableHookData
= new nsTransferableHookData();
10889 if (!mTransferableHookData
) return NS_ERROR_OUT_OF_MEMORY
;
10896 NS_IMETHODIMP
nsDocShell::EnsureFind()
10901 mFind
= do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv
);
10902 if (NS_FAILED(rv
)) return rv
;
10905 // we promise that the nsIWebBrowserFind that we return has been set
10906 // up to point to the focused, or content window, so we have to
10907 // set that up each time.
10909 nsIScriptGlobalObject
* scriptGO
= GetScriptGlobalObject();
10910 NS_ENSURE_TRUE(scriptGO
, NS_ERROR_UNEXPECTED
);
10912 // default to our window
10913 nsCOMPtr
<nsIDOMWindow
> windowToSearch(do_QueryInterface(mScriptGlobal
));
10915 nsCOMPtr
<nsIDocShellTreeItem
> root
;
10916 GetRootTreeItem(getter_AddRefs(root
));
10918 // if the active window is the same window that this docshell is in,
10919 // use the currently focused frame
10920 nsCOMPtr
<nsIDOMWindow
> rootWindow
= do_GetInterface(root
);
10921 nsCOMPtr
<nsIFocusManager
> fm
= do_GetService(FOCUSMANAGER_CONTRACTID
);
10923 nsCOMPtr
<nsIDOMWindow
> activeWindow
;
10924 fm
->GetActiveWindow(getter_AddRefs(activeWindow
));
10925 if (activeWindow
== rootWindow
)
10926 fm
->GetFocusedWindow(getter_AddRefs(windowToSearch
));
10929 nsCOMPtr
<nsIWebBrowserFindInFrames
> findInFrames
= do_QueryInterface(mFind
);
10930 if (!findInFrames
) return NS_ERROR_NO_INTERFACE
;
10932 rv
= findInFrames
->SetRootSearchFrame(rootWindow
);
10933 if (NS_FAILED(rv
)) return rv
;
10934 rv
= findInFrames
->SetCurrentSearchFrame(windowToSearch
);
10935 if (NS_FAILED(rv
)) return rv
;
10941 nsDocShell::IsFrame()
10943 nsCOMPtr
<nsIDocShellTreeItem
> parent
=
10944 do_QueryInterface(GetAsSupports(mParent
));
10946 PRInt32 parentType
= ~mItemType
; // Not us
10947 parent
->GetItemType(&parentType
);
10948 if (parentType
== mItemType
) // This is a frame
10955 /* boolean IsBeingDestroyed (); */
10957 nsDocShell::IsBeingDestroyed(PRBool
*aDoomed
)
10959 NS_ENSURE_ARG(aDoomed
);
10960 *aDoomed
= mIsBeingDestroyed
;
10966 nsDocShell::GetIsExecutingOnLoadHandler(PRBool
*aResult
)
10968 NS_ENSURE_ARG(aResult
);
10969 *aResult
= mIsExecutingOnLoadHandler
;
10974 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState
**aLayoutHistoryState
)
10977 mOSHE
->GetLayoutHistoryState(aLayoutHistoryState
);
10982 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState
*aLayoutHistoryState
)
10985 mOSHE
->SetLayoutHistoryState(aLayoutHistoryState
);
10989 //*****************************************************************************
10990 //*** nsRefreshTimer: Object Management
10991 //*****************************************************************************
10993 nsRefreshTimer::nsRefreshTimer()
10994 : mDelay(0), mRepeat(PR_FALSE
), mMetaRefresh(PR_FALSE
)
10998 nsRefreshTimer::~nsRefreshTimer()
11002 //*****************************************************************************
11003 // nsRefreshTimer::nsISupports
11004 //*****************************************************************************
11006 NS_IMPL_THREADSAFE_ADDREF(nsRefreshTimer
)
11007 NS_IMPL_THREADSAFE_RELEASE(nsRefreshTimer
)
11009 NS_INTERFACE_MAP_BEGIN(nsRefreshTimer
)
11010 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsITimerCallback
)
11011 NS_INTERFACE_MAP_ENTRY(nsITimerCallback
)
11012 NS_INTERFACE_MAP_END_THREADSAFE
11014 ///*****************************************************************************
11015 // nsRefreshTimer::nsITimerCallback
11016 //******************************************************************************
11018 nsRefreshTimer::Notify(nsITimer
* aTimer
)
11020 NS_ASSERTION(mDocShell
, "DocShell is somehow null");
11022 if (mDocShell
&& aTimer
) {
11023 // Get the delay count to determine load type
11024 PRUint32 delay
= 0;
11025 aTimer
->GetDelay(&delay
);
11026 mDocShell
->ForceRefreshURIFromTimer(mURI
, delay
, mMetaRefresh
, aTimer
);
11031 //*****************************************************************************
11032 // nsDocShell::InterfaceRequestorProxy
11033 //*****************************************************************************
11034 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor
* p
)
11037 mWeakPtr
= do_GetWeakReference(p
);
11041 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
11046 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDocShell::InterfaceRequestorProxy
, nsIInterfaceRequestor
)
11049 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID
& aIID
, void **aSink
)
11051 NS_ENSURE_ARG_POINTER(aSink
);
11052 nsCOMPtr
<nsIInterfaceRequestor
> ifReq
= do_QueryReferent(mWeakPtr
);
11054 return ifReq
->GetInterface(aIID
, aSink
);
11057 return NS_NOINTERFACE
;
11061 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer
* aContentViewer
)
11063 if (!aContentViewer
)
11064 return NS_ERROR_FAILURE
;
11066 nsCOMPtr
<nsIURI
> baseURI
;
11067 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
11070 rv
= sURIFixup
->CreateExposableURI(mCurrentURI
,
11071 getter_AddRefs(baseURI
));
11073 // Get the current document and set the base uri
11075 nsIDocument
* document
= aContentViewer
->GetDocument();
11077 rv
= document
->SetBaseURI(baseURI
);
11083 //*****************************************************************************
11084 // nsDocShell::nsIAuthPromptProvider
11085 //*****************************************************************************
11088 nsDocShell::GetAuthPrompt(PRUint32 aPromptReason
, const nsIID
& iid
,
11091 // a priority prompt request will override a false mAllowAuth setting
11092 PRBool priorityPrompt
= (aPromptReason
== PROMPT_PROXY
);
11094 if (!mAllowAuth
&& !priorityPrompt
)
11095 return NS_ERROR_NOT_AVAILABLE
;
11097 // we're either allowing auth, or it's a proxy request
11099 nsCOMPtr
<nsIPromptFactory
> wwatch
=
11100 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
11101 NS_ENSURE_SUCCESS(rv
, rv
);
11103 rv
= EnsureScriptEnvironment();
11104 NS_ENSURE_SUCCESS(rv
, rv
);
11106 nsCOMPtr
<nsIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
11108 // Get the an auth prompter for our window so that the parenting
11109 // of the dialogs works as it should when using tabs.
11111 return wwatch
->GetPrompt(window
, iid
,
11112 reinterpret_cast<void**>(aResult
));
11115 //*****************************************************************************
11116 // nsDocShell::nsIObserver
11117 //*****************************************************************************
11120 nsDocShell::Observe(nsISupports
*aSubject
, const char *aTopic
,
11121 const PRUnichar
*aData
)
11123 nsresult rv
= NS_OK
;
11124 if (mObserveErrorPages
&&
11125 !nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
) &&
11126 !nsCRT::strcmp(aData
,
11127 NS_LITERAL_STRING("browser.xul.error_pages.enabled").get())) {
11129 nsCOMPtr
<nsIPrefBranch
> prefs(do_QueryInterface(aSubject
, &rv
));
11130 NS_ENSURE_SUCCESS(rv
, rv
);
11133 rv
= prefs
->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool
);
11134 if (NS_SUCCEEDED(rv
))
11135 mUseErrorPages
= tmpbool
;
11138 rv
= NS_ERROR_UNEXPECTED
;
11143 //*****************************************************************************
11144 // nsDocShell::nsILoadContext
11145 //*****************************************************************************
11147 nsDocShell::GetAssociatedWindow(nsIDOMWindow
** aWindow
)
11149 CallGetInterface(this, aWindow
);
11154 nsDocShell::GetTopWindow(nsIDOMWindow
** aWindow
)
11156 nsCOMPtr
<nsIDOMWindow
> win
= do_GetInterface(GetAsSupports(this));
11158 win
->GetTop(aWindow
);
11164 nsDocShell::IsAppOfType(PRUint32 aAppType
, PRBool
*aIsOfType
)
11166 nsCOMPtr
<nsIDocShell
> shell
= this;
11169 shell
->GetAppType(&type
);
11170 if (type
== aAppType
) {
11171 *aIsOfType
= PR_TRUE
;
11174 nsCOMPtr
<nsIDocShellTreeItem
> item
= do_QueryInterface(shell
);
11175 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
11176 item
->GetParent(getter_AddRefs(parent
));
11177 shell
= do_QueryInterface(parent
);
11180 *aIsOfType
= PR_FALSE
;
11185 nsDocShell::GetIsContent(PRBool
*aIsContent
)
11187 *aIsContent
= (mItemType
== typeContent
);
11193 nsDocShell::URIInheritsSecurityContext(nsIURI
* aURI
, PRBool
* aResult
)
11195 // Note: about:blank URIs do NOT inherit the security context from the
11196 // current document, which is what this function tests for...
11197 return NS_URIChainHasFlags(aURI
,
11198 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
,
11204 nsDocShell::URIIsLocalFile(nsIURI
*aURI
)
11207 nsCOMPtr
<nsINetUtil
> util
= do_GetNetUtil();
11209 return util
&& NS_SUCCEEDED(util
->ProtocolHasFlags(aURI
,
11210 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
11217 nsDocShell::IsAboutBlank(nsIURI
* aURI
)
11219 NS_PRECONDITION(aURI
, "Must have URI");
11221 // GetSpec can be expensive for some URIs, so check the scheme first.
11222 PRBool isAbout
= PR_FALSE
;
11223 if (NS_FAILED(aURI
->SchemeIs("about", &isAbout
)) || !isAbout
) {
11228 aURI
->GetSpec(str
);
11229 return str
.EqualsLiteral("about:blank");
11233 nsDocShell::IsOKToLoadURI(nsIURI
* aURI
)
11235 NS_PRECONDITION(aURI
, "Must have a URI!");
11237 if (!mFiredUnloadEvent
) {
11241 if (!mLoadingURI
) {
11245 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
11246 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
11249 NS_SUCCEEDED(secMan
->CheckSameOriginURI(aURI
, mLoadingURI
, PR_FALSE
));
11253 // Routines for selection and clipboard
11256 nsDocShell::GetControllerForCommand(const char * inCommand
,
11257 nsIController
** outController
)
11259 NS_ENSURE_ARG_POINTER(outController
);
11260 *outController
= nsnull
;
11262 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(mScriptGlobal
));
11264 nsCOMPtr
<nsPIWindowRoot
> root
= window
->GetTopWindowRoot();
11266 return root
->GetControllerForCommand(inCommand
, outController
);
11270 return NS_ERROR_FAILURE
;
11274 nsDocShell::IsCommandEnabled(const char * inCommand
, PRBool
* outEnabled
)
11276 NS_ENSURE_ARG_POINTER(outEnabled
);
11277 *outEnabled
= PR_FALSE
;
11279 nsresult rv
= NS_ERROR_FAILURE
;
11281 nsCOMPtr
<nsIController
> controller
;
11282 rv
= GetControllerForCommand (inCommand
, getter_AddRefs(controller
));
11284 rv
= controller
->IsCommandEnabled(inCommand
, outEnabled
);
11290 nsDocShell::DoCommand(const char * inCommand
)
11292 nsresult rv
= NS_ERROR_FAILURE
;
11294 nsCOMPtr
<nsIController
> controller
;
11295 rv
= GetControllerForCommand(inCommand
, getter_AddRefs(controller
));
11297 rv
= controller
->DoCommand(inCommand
);
11303 nsDocShell::EnsureCommandHandler()
11305 if (!mCommandManager
)
11307 nsCOMPtr
<nsPICommandUpdater
> commandUpdater
=
11308 do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
11309 if (!commandUpdater
) return NS_ERROR_OUT_OF_MEMORY
;
11311 nsCOMPtr
<nsIDOMWindow
> domWindow
=
11312 do_GetInterface(static_cast<nsIInterfaceRequestor
*>(this));
11314 nsresult rv
= commandUpdater
->Init(domWindow
);
11315 if (NS_SUCCEEDED(rv
))
11316 mCommandManager
= do_QueryInterface(commandUpdater
);
11319 return mCommandManager
? NS_OK
: NS_ERROR_FAILURE
;
11323 nsDocShell::CanCutSelection(PRBool
* aResult
)
11325 return IsCommandEnabled("cmd_cut", aResult
);
11329 nsDocShell::CanCopySelection(PRBool
* aResult
)
11331 return IsCommandEnabled("cmd_copy", aResult
);
11335 nsDocShell::CanCopyLinkLocation(PRBool
* aResult
)
11337 return IsCommandEnabled("cmd_copyLink", aResult
);
11341 nsDocShell::CanCopyImageLocation(PRBool
* aResult
)
11343 return IsCommandEnabled("cmd_copyImageLocation",
11348 nsDocShell::CanCopyImageContents(PRBool
* aResult
)
11350 return IsCommandEnabled("cmd_copyImageContents",
11355 nsDocShell::CanPaste(PRBool
* aResult
)
11357 return IsCommandEnabled("cmd_paste", aResult
);
11361 nsDocShell::CutSelection(void)
11363 return DoCommand ( "cmd_cut" );
11367 nsDocShell::CopySelection(void)
11369 return DoCommand ( "cmd_copy" );
11373 nsDocShell::CopyLinkLocation(void)
11375 return DoCommand ( "cmd_copyLink" );
11379 nsDocShell::CopyImageLocation(void)
11381 return DoCommand ( "cmd_copyImageLocation" );
11385 nsDocShell::CopyImageContents(void)
11387 return DoCommand ( "cmd_copyImageContents" );
11391 nsDocShell::Paste(void)
11393 return DoCommand ( "cmd_paste" );
11397 nsDocShell::SelectAll(void)
11399 return DoCommand ( "cmd_selectAll" );
11405 // Collapses the current selection, insertion point ends up at beginning
11406 // of previous selection.
11409 nsDocShell::SelectNone(void)
11411 return DoCommand ( "cmd_selectNone" );
11414 //----------------------------------------------------------------------
11418 class OnLinkClickEvent
: public nsRunnable
{
11420 OnLinkClickEvent(nsDocShell
* aHandler
, nsIContent
* aContent
,
11422 const PRUnichar
* aTargetSpec
,
11423 nsIInputStream
* aPostDataStream
= 0,
11424 nsIInputStream
* aHeadersDataStream
= 0);
11427 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(mHandler
->mScriptGlobal
));
11428 nsAutoPopupStatePusher
popupStatePusher(window
, mPopupState
);
11430 mHandler
->OnLinkClickSync(mContent
, mURI
,
11431 mTargetSpec
.get(), mPostDataStream
,
11432 mHeadersDataStream
,
11438 nsRefPtr
<nsDocShell
> mHandler
;
11439 nsCOMPtr
<nsIURI
> mURI
;
11440 nsString mTargetSpec
;
11441 nsCOMPtr
<nsIInputStream
> mPostDataStream
;
11442 nsCOMPtr
<nsIInputStream
> mHeadersDataStream
;
11443 nsCOMPtr
<nsIContent
> mContent
;
11444 PopupControlState mPopupState
;
11447 OnLinkClickEvent::OnLinkClickEvent(nsDocShell
* aHandler
,
11448 nsIContent
*aContent
,
11450 const PRUnichar
* aTargetSpec
,
11451 nsIInputStream
* aPostDataStream
,
11452 nsIInputStream
* aHeadersDataStream
)
11453 : mHandler(aHandler
)
11455 , mTargetSpec(aTargetSpec
)
11456 , mPostDataStream(aPostDataStream
)
11457 , mHeadersDataStream(aHeadersDataStream
)
11458 , mContent(aContent
)
11460 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(mHandler
->mScriptGlobal
));
11462 mPopupState
= window
->GetPopupControlState();
11465 //----------------------------------------
11468 nsDocShell::OnLinkClick(nsIContent
* aContent
,
11470 const PRUnichar
* aTargetSpec
,
11471 nsIInputStream
* aPostDataStream
,
11472 nsIInputStream
* aHeadersDataStream
)
11474 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
11476 if (!IsOKToLoadURI(aURI
)) {
11480 if (aContent
->IsEditable()) {
11484 nsresult rv
= NS_ERROR_FAILURE
;
11485 nsAutoString target
;
11487 nsCOMPtr
<nsIWebBrowserChrome3
> browserChrome3
= do_GetInterface(mTreeOwner
);
11488 if (browserChrome3
) {
11489 nsCOMPtr
<nsIDOMNode
> linkNode
= do_QueryInterface(aContent
);
11490 nsAutoString
oldTarget(aTargetSpec
);
11491 rv
= browserChrome3
->OnBeforeLinkTraversal(oldTarget
, aURI
,
11492 linkNode
, mIsAppTab
, target
);
11496 target
= aTargetSpec
;
11498 nsCOMPtr
<nsIRunnable
> ev
=
11499 new OnLinkClickEvent(this, aContent
, aURI
, target
.get(),
11500 aPostDataStream
, aHeadersDataStream
);
11501 return NS_DispatchToCurrentThread(ev
);
11505 nsDocShell::OnLinkClickSync(nsIContent
*aContent
,
11507 const PRUnichar
* aTargetSpec
,
11508 nsIInputStream
* aPostDataStream
,
11509 nsIInputStream
* aHeadersDataStream
,
11510 nsIDocShell
** aDocShell
,
11511 nsIRequest
** aRequest
)
11513 // Initialize the DocShell / Request
11515 *aDocShell
= nsnull
;
11518 *aRequest
= nsnull
;
11521 if (!IsOKToLoadURI(aURI
)) {
11525 if (aContent
->IsEditable()) {
11530 // defer to an external protocol handler if necessary...
11531 nsCOMPtr
<nsIExternalProtocolService
> extProtService
=
11532 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
);
11533 if (extProtService
) {
11534 nsCAutoString scheme
;
11535 aURI
->GetScheme(scheme
);
11536 if (!scheme
.IsEmpty()) {
11537 // if the URL scheme does not correspond to an exposed protocol, then we
11538 // need to hand this link click over to the external protocol handler.
11540 nsresult rv
= extProtService
->IsExposedProtocol(scheme
.get(), &isExposed
);
11541 if (NS_SUCCEEDED(rv
) && !isExposed
) {
11542 return extProtService
->LoadURI(aURI
, this);
11548 // Get the owner document of the link that was clicked, this will be
11549 // the document that the link is in, or the last document that the
11550 // link was in. From that document, we'll get the URI to use as the
11551 // referer, since the current URI in this docshell may be a
11552 // new document that we're in the process of loading.
11553 nsCOMPtr
<nsIDocument
> refererDoc
= aContent
->GetOwnerDoc();
11554 NS_ENSURE_TRUE(refererDoc
, NS_ERROR_UNEXPECTED
);
11556 nsCOMPtr
<nsIURI
> referer
= refererDoc
->GetDocumentURI();
11558 // referer could be null here in some odd cases, but that's ok,
11559 // we'll just load the link w/o sending a referer in those cases.
11561 nsAutoString
target(aTargetSpec
);
11563 // If this is an anchor element, grab its type property to use as a hint
11564 nsAutoString typeHint
;
11565 nsCOMPtr
<nsIDOMHTMLAnchorElement
> anchor(do_QueryInterface(aContent
));
11567 anchor
->GetType(typeHint
);
11568 NS_ConvertUTF16toUTF8
utf8Hint(typeHint
);
11569 nsCAutoString type
, dummy
;
11570 NS_ParseContentType(utf8Hint
, type
, dummy
);
11571 CopyUTF8toUTF16(type
, typeHint
);
11574 nsresult rv
= InternalLoad(aURI
, // New URI
11575 referer
, // Referer URI
11576 aContent
->NodePrincipal(), // Owner is our node's
11578 INTERNAL_LOAD_FLAGS_NONE
,
11579 target
.get(), // Window target
11580 NS_LossyConvertUTF16toASCII(typeHint
).get(),
11581 aPostDataStream
, // Post data stream
11582 aHeadersDataStream
, // Headers stream
11583 LOAD_LINK
, // Load type
11584 nsnull
, // No SHEntry
11585 PR_TRUE
, // first party site
11586 aDocShell
, // DocShell out-param
11587 aRequest
); // Request out-param
11588 if (NS_SUCCEEDED(rv
)) {
11589 DispatchPings(aContent
, referer
);
11595 nsDocShell::OnOverLink(nsIContent
* aContent
,
11597 const PRUnichar
* aTargetSpec
)
11599 if (aContent
->IsEditable()) {
11603 nsCOMPtr
<nsIWebBrowserChrome2
> browserChrome2
= do_GetInterface(mTreeOwner
);
11604 nsresult rv
= NS_ERROR_FAILURE
;
11606 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
;
11607 if (!browserChrome2
) {
11608 browserChrome
= do_GetInterface(mTreeOwner
);
11609 if (!browserChrome
)
11613 nsCOMPtr
<nsITextToSubURI
> textToSubURI
=
11614 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID
, &rv
);
11618 // use url origin charset to unescape the URL
11619 nsCAutoString charset
;
11620 rv
= aURI
->GetOriginCharset(charset
);
11621 NS_ENSURE_SUCCESS(rv
, rv
);
11623 nsCAutoString spec
;
11624 rv
= aURI
->GetSpec(spec
);
11625 NS_ENSURE_SUCCESS(rv
, rv
);
11628 rv
= textToSubURI
->UnEscapeURIForUI(charset
, spec
, uStr
);
11629 NS_ENSURE_SUCCESS(rv
, rv
);
11631 if (browserChrome2
) {
11632 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(aContent
);
11633 rv
= browserChrome2
->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK
,
11636 rv
= browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_LINK
, uStr
.get());
11642 nsDocShell::OnLeaveLink()
11644 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome(do_GetInterface(mTreeOwner
));
11645 nsresult rv
= NS_ERROR_FAILURE
;
11647 if (browserChrome
) {
11648 rv
= browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_LINK
,
11649 EmptyString().get());
11654 //----------------------------------------------------------------------
11655 // Web Shell Services API
11657 //This functions is only called when a new charset is detected in loading a document.
11658 //Its name should be changed to "CharsetReloadDocument"
11660 nsDocShell::ReloadDocument(const char* aCharset
,
11664 // XXX hack. keep the aCharset and aSource wait to pick it up
11665 nsCOMPtr
<nsIContentViewer
> cv
;
11666 NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv
)), NS_ERROR_FAILURE
);
11669 nsCOMPtr
<nsIMarkupDocumentViewer
> muDV
= do_QueryInterface(cv
);
11673 muDV
->GetHintCharacterSetSource(&hint
);
11674 if (aSource
> hint
)
11676 nsCString
charset(aCharset
);
11677 muDV
->SetHintCharacterSet(charset
);
11678 muDV
->SetHintCharacterSetSource(aSource
);
11679 if(eCharsetReloadRequested
!= mCharsetReloadState
)
11681 mCharsetReloadState
= eCharsetReloadRequested
;
11682 return Reload(LOAD_FLAGS_CHARSET_CHANGE
);
11687 //return failure if this request is not accepted due to mCharsetReloadState
11688 return NS_ERROR_DOCSHELL_REQUEST_REJECTED
;
11693 nsDocShell::StopDocumentLoad(void)
11695 if(eCharsetReloadRequested
!= mCharsetReloadState
)
11697 Stop(nsIWebNavigation::STOP_ALL
);
11700 //return failer if this request is not accepted due to mCharsetReloadState
11701 return NS_ERROR_DOCSHELL_REQUEST_REJECTED
;
11705 nsDocShell::GetPrintPreview(nsIWebBrowserPrint
** aPrintPreview
)
11707 *aPrintPreview
= nsnull
;
11708 #if NS_PRINT_PREVIEW
11709 nsCOMPtr
<nsIDocumentViewerPrint
> print
= do_QueryInterface(mContentViewer
);
11710 if (!print
|| !print
->IsInitializedForPrintPreview()) {
11711 Stop(nsIWebNavigation::STOP_ALL
);
11712 nsCOMPtr
<nsIPrincipal
> principal
=
11713 do_CreateInstance("@mozilla.org/nullprincipal;1");
11714 NS_ENSURE_STATE(principal
);
11715 nsresult rv
= CreateAboutBlankContentViewer(principal
, nsnull
);
11716 NS_ENSURE_SUCCESS(rv
, rv
);
11717 print
= do_QueryInterface(mContentViewer
);
11718 NS_ENSURE_STATE(print
);
11719 print
->InitializeForPrintPreview();
11721 nsCOMPtr
<nsIWebBrowserPrint
> result
= do_QueryInterface(print
);
11722 result
.forget(aPrintPreview
);
11725 return NS_ERROR_NOT_IMPLEMENTED
;
11731 unsigned long nsDocShell::gNumberOfDocShells
= 0;
11735 nsDocShell::GetCanExecuteScripts(PRBool
*aResult
)
11737 NS_ENSURE_ARG_POINTER(aResult
);
11738 *aResult
= PR_FALSE
; // disallow by default
11740 nsCOMPtr
<nsIDocShell
> docshell
= this;
11741 nsCOMPtr
<nsIDocShellTreeItem
> globalObjTreeItem
=
11742 do_QueryInterface(docshell
);
11744 if (globalObjTreeItem
)
11746 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(globalObjTreeItem
);
11747 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
11748 PRBool firstPass
= PR_TRUE
;
11749 PRBool lookForParents
= PR_FALSE
;
11751 // Walk up the docshell tree to see if any containing docshell disallows scripts
11754 nsresult rv
= docshell
->GetAllowJavascript(aResult
);
11755 if (NS_FAILED(rv
)) return rv
;
11757 nsDocShell
* realDocshell
= static_cast<nsDocShell
*>(docshell
.get());
11758 if (realDocshell
->mContentViewer
) {
11759 nsIDocument
* doc
= realDocshell
->mContentViewer
->GetDocument();
11760 if (doc
&& doc
->HasFlag(NODE_IS_EDITABLE
) &&
11761 realDocshell
->mEditorData
) {
11762 nsCOMPtr
<nsIEditingSession
> editSession
;
11763 realDocshell
->mEditorData
->GetEditingSession(getter_AddRefs(editSession
));
11764 PRBool jsDisabled
= PR_FALSE
;
11766 NS_SUCCEEDED(rv
= editSession
->GetJsAndPluginsDisabled(&jsDisabled
))) {
11769 // We have a docshell which has been explicitly set
11770 // to design mode, so we disallow scripts.
11773 // The docshell was not explicitly set to design mode,
11774 // so it must be so because a parent was explicitly
11775 // set to design mode. We don't need to look at higher
11777 *aResult
= PR_TRUE
;
11779 } else if (lookForParents
&& jsDisabled
) {
11780 // If a parent was explicitly set to design mode,
11781 // we should allow script execution on the child.
11782 *aResult
= PR_TRUE
;
11785 // If the child docshell allows scripting, and the
11786 // parent is inside design mode, we don't need to look
11788 *aResult
= PR_TRUE
;
11791 NS_WARNING("The editing session does not work?");
11792 return NS_FAILED(rv
) ? rv
: NS_ERROR_FAILURE
;
11795 // Don't be too hard on docshells on the first pass.
11796 // There may be a parent docshell which has been set
11797 // to design mode, so look for it.
11798 lookForParents
= PR_TRUE
;
11800 // We have a docshell which disallows scripts
11801 // and is not editable, so we shouldn't allow
11806 } else if (lookForParents
) {
11807 // The parent docshell was not explicitly set to design
11808 // mode, so js on the child docshell was disabled for
11809 // another reason. Therefore, we need to disable js.
11810 *aResult
= PR_FALSE
;
11813 firstPass
= PR_FALSE
;
11815 treeItem
->GetParent(getter_AddRefs(parentItem
));
11816 treeItem
.swap(parentItem
);
11817 docshell
= do_QueryInterface(treeItem
);
11819 if (treeItem
&& !docshell
) {
11820 NS_ERROR("cannot get a docshell from a treeItem!");
11823 } while (treeItem
&& docshell
);