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
5 : *
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/
10 : *
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
14 : * License.
15 : *
16 : * The Original Code is the Mozilla browser.
17 : *
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.
22 : *
23 : * Contributor(s):
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>
29 : *
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.
41 : *
42 : * ***** END LICENSE BLOCK ***** */
43 :
44 : #include "mozilla/Util.h"
45 :
46 : #ifdef MOZ_LOGGING
47 : // so we can get logging even in release builds (but only for some things)
48 : #define FORCE_PR_LOG 1
49 : #endif
50 :
51 : #include "nsIBrowserDOMWindow.h"
52 : #include "nsIComponentManager.h"
53 : #include "nsIContent.h"
54 : #include "mozilla/dom/Element.h"
55 : #include "nsIDocument.h"
56 : #include "nsIDOMDocument.h"
57 : #include "nsIDOMElement.h"
58 : #include "nsIDOMStorage.h"
59 : #include "nsPIDOMStorage.h"
60 : #include "nsIContentViewer.h"
61 : #include "nsIDocumentLoaderFactory.h"
62 : #include "nsCURILoader.h"
63 : #include "nsURILoader.h"
64 : #include "nsDocShellCID.h"
65 : #include "nsLayoutCID.h"
66 : #include "nsDOMCID.h"
67 : #include "nsIDOMScriptObjectFactory.h"
68 : #include "nsNetUtil.h"
69 : #include "nsRect.h"
70 : #include "prprf.h"
71 : #include "prenv.h"
72 : #include "nsIMarkupDocumentViewer.h"
73 : #include "nsXPIDLString.h"
74 : #include "nsReadableUtils.h"
75 : #include "nsIDOMChromeWindow.h"
76 : #include "nsIDOMWindow.h"
77 : #include "nsIWebBrowserChrome.h"
78 : #include "nsPoint.h"
79 : #include "nsGfxCIID.h"
80 : #include "nsIObserverService.h"
81 : #include "nsIPrompt.h"
82 : #include "nsIAuthPrompt.h"
83 : #include "nsIAuthPrompt2.h"
84 : #include "nsTextFormatter.h"
85 : #include "nsIChannelEventSink.h"
86 : #include "nsIAsyncVerifyRedirectCallback.h"
87 : #include "nsIUploadChannel.h"
88 : #include "nsISecurityEventSink.h"
89 : #include "mozilla/FunctionTimer.h"
90 : #include "nsIScriptSecurityManager.h"
91 : #include "nsIJSContextStack.h"
92 : #include "nsIScriptObjectPrincipal.h"
93 : #include "nsIScrollableFrame.h"
94 : #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
95 : #include "nsICategoryManager.h"
96 : #include "nsXPCOMCID.h"
97 : #include "nsISeekableStream.h"
98 : #include "nsAutoPtr.h"
99 : #include "nsIWritablePropertyBag2.h"
100 : #include "nsIAppShell.h"
101 : #include "nsWidgetsCID.h"
102 : #include "nsDOMJSUtils.h"
103 : #include "nsIInterfaceRequestorUtils.h"
104 : #include "nsIView.h"
105 : #include "nsIViewManager.h"
106 : #include "nsIScriptChannel.h"
107 : #include "nsIOfflineCacheUpdate.h"
108 : #include "nsITimedChannel.h"
109 : #include "nsCPrefetchService.h"
110 : #include "nsJSON.h"
111 : #include "IHistory.h"
112 : #include "mozilla/Services.h"
113 : #include "mozilla/Preferences.h"
114 : #include "mozilla/Telemetry.h"
115 : #include "mozilla/AutoRestore.h"
116 :
117 : // we want to explore making the document own the load group
118 : // so we can associate the document URI with the load group.
119 : // until this point, we have an evil hack:
120 : #include "nsIHttpChannelInternal.h"
121 :
122 :
123 : // Local Includes
124 : #include "nsDocShell.h"
125 : #include "nsDocShellLoadInfo.h"
126 : #include "nsCDefaultURIFixup.h"
127 : #include "nsDocShellEnumerator.h"
128 : #include "nsSHistory.h"
129 : #include "nsDocShellEditorData.h"
130 :
131 : // Helper Classes
132 : #include "nsDOMError.h"
133 : #include "nsEscape.h"
134 :
135 : // Interfaces Needed
136 : #include "nsIUploadChannel.h"
137 : #include "nsIProgressEventSink.h"
138 : #include "nsIWebProgress.h"
139 : #include "nsILayoutHistoryState.h"
140 : #include "nsITimer.h"
141 : #include "nsISHistoryInternal.h"
142 : #include "nsIPrincipal.h"
143 : #include "nsIFileURL.h"
144 : #include "nsIHistoryEntry.h"
145 : #include "nsISHistoryListener.h"
146 : #include "nsIWindowWatcher.h"
147 : #include "nsIPromptFactory.h"
148 : #include "nsIObserver.h"
149 : #include "nsINestedURI.h"
150 : #include "nsITransportSecurityInfo.h"
151 : #include "nsINSSErrorsService.h"
152 : #include "nsIApplicationCache.h"
153 : #include "nsIApplicationCacheChannel.h"
154 : #include "nsIApplicationCacheContainer.h"
155 : #include "nsIPermissionManager.h"
156 : #include "nsStreamUtils.h"
157 : #include "nsIController.h"
158 : #include "nsPICommandUpdater.h"
159 : #include "nsIDOMHTMLAnchorElement.h"
160 : #include "nsIWebBrowserChrome3.h"
161 : #include "nsITabChild.h"
162 : #include "nsIStrictTransportSecurityService.h"
163 : #include "nsStructuredCloneContainer.h"
164 : #include "nsIStructuredCloneContainer.h"
165 : #include "nsIFaviconService.h"
166 : #include "mozIAsyncFavicons.h"
167 :
168 : // Editor-related
169 : #include "nsIEditingSession.h"
170 :
171 : #include "nsPIDOMWindow.h"
172 : #include "nsPIWindowRoot.h"
173 : #include "nsIDOMDocument.h"
174 : #include "nsICachingChannel.h"
175 : #include "nsICacheVisitor.h"
176 : #include "nsICacheEntryDescriptor.h"
177 : #include "nsIMultiPartChannel.h"
178 : #include "nsIWyciwygChannel.h"
179 :
180 : // For reporting errors with the console service.
181 : // These can go away if error reporting is propagated up past nsDocShell.
182 : #include "nsIConsoleService.h"
183 : #include "nsIScriptError.h"
184 :
185 : // used to dispatch urls to default protocol handlers
186 : #include "nsCExternalHandlerService.h"
187 : #include "nsIExternalProtocolService.h"
188 :
189 : #include "nsFocusManager.h"
190 :
191 : #include "nsITextToSubURI.h"
192 :
193 : #include "nsIJARChannel.h"
194 :
195 : #include "prlog.h"
196 : #include "prmem.h"
197 :
198 : #include "nsISelectionDisplay.h"
199 :
200 : #include "nsIGlobalHistory2.h"
201 :
202 : #ifdef DEBUG_DOCSHELL_FOCUS
203 : #include "nsEventStateManager.h"
204 : #endif
205 :
206 : #include "nsIFrame.h"
207 :
208 : // for embedding
209 : #include "nsIWebBrowserChromeFocus.h"
210 :
211 : #if NS_PRINT_PREVIEW
212 : #include "nsIDocumentViewerPrint.h"
213 : #include "nsIWebBrowserPrint.h"
214 : #endif
215 :
216 : #include "nsPluginError.h"
217 : #include "nsContentUtils.h"
218 : #include "nsContentErrors.h"
219 : #include "nsIChannelPolicy.h"
220 : #include "nsIContentSecurityPolicy.h"
221 :
222 : #include "nsXULAppAPI.h"
223 :
224 : #include "nsDOMNavigationTiming.h"
225 : #include "nsITimedChannel.h"
226 : #include "mozilla/StartupTimeline.h"
227 :
228 : static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
229 : NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
230 : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
231 :
232 : #if defined(DEBUG_bryner) || defined(DEBUG_chb)
233 : //#define DEBUG_DOCSHELL_FOCUS
234 : #define DEBUG_PAGE_CACHE
235 : #endif
236 :
237 : using namespace mozilla;
238 :
239 : // Number of documents currently loading
240 : static PRInt32 gNumberOfDocumentsLoading = 0;
241 :
242 : // Global count of existing docshells.
243 : static PRInt32 gDocShellCount = 0;
244 :
245 : // Global reference to the URI fixup service.
246 : nsIURIFixup *nsDocShell::sURIFixup = 0;
247 :
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 PRUint32 gValidateOrigin = 0xffffffff;
252 :
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
257 :
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)
263 :
264 : #ifdef PR_LOGGING
265 : #ifdef DEBUG
266 : static PRLogModuleInfo* gDocShellLog;
267 : #endif
268 : static PRLogModuleInfo* gDocShellLeakLog;
269 : #endif
270 :
271 : const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
272 : const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
273 :
274 : static void
275 0 : FavorPerformanceHint(bool perfOverStarvation, PRUint32 starvationDelay)
276 : {
277 0 : nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
278 0 : if (appShell)
279 0 : appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
280 0 : }
281 :
282 : //*****************************************************************************
283 : // <a ping> support
284 : //*****************************************************************************
285 :
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"
289 :
290 : // Check prefs to see if pings are enabled and if so what restrictions might
291 : // be applied.
292 : //
293 : // @param maxPerLink
294 : // This parameter returns the number of pings that are allowed per link click
295 : //
296 : // @param requireSameHost
297 : // This parameter returns 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
301 : // a ping via FTP.
302 : //
303 : // @returns
304 : // true if pings are enabled and false otherwise.
305 : //
306 : static bool
307 0 : PingsEnabled(PRInt32 *maxPerLink, bool *requireSameHost)
308 : {
309 0 : bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false);
310 :
311 0 : *maxPerLink = 1;
312 0 : *requireSameHost = true;
313 :
314 0 : if (allow) {
315 0 : Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, maxPerLink);
316 0 : Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost);
317 : }
318 :
319 0 : return allow;
320 : }
321 :
322 : static bool
323 0 : CheckPingURI(nsIURI* uri, nsIContent* content)
324 : {
325 0 : if (!uri)
326 0 : return false;
327 :
328 : // Check with nsIScriptSecurityManager
329 : nsCOMPtr<nsIScriptSecurityManager> ssmgr =
330 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
331 0 : NS_ENSURE_TRUE(ssmgr, false);
332 :
333 : nsresult rv =
334 0 : ssmgr->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri,
335 0 : nsIScriptSecurityManager::STANDARD);
336 0 : if (NS_FAILED(rv)) {
337 0 : return false;
338 : }
339 :
340 : // Ignore non-HTTP(S)
341 : bool match;
342 0 : if ((NS_FAILED(uri->SchemeIs("http", &match)) || !match) &&
343 0 : (NS_FAILED(uri->SchemeIs("https", &match)) || !match)) {
344 0 : return false;
345 : }
346 :
347 : // Check with contentpolicy
348 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
349 : rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING,
350 : uri,
351 : content->NodePrincipal(),
352 : content,
353 0 : EmptyCString(), // mime hint
354 : nsnull, //extra
355 0 : &shouldLoad);
356 0 : return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
357 : }
358 :
359 : typedef void (* ForEachPingCallback)(void *closure, nsIContent *content,
360 : nsIURI *uri, nsIIOService *ios);
361 :
362 : static void
363 0 : ForEachPing(nsIContent *content, ForEachPingCallback callback, void *closure)
364 : {
365 : // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
366 : // since we'd still need to parse the resulting string. Instead, we
367 : // just parse the raw attribute. It might be nice if the content node
368 : // implemented an interface that exposed an enumeration of nsIURIs.
369 :
370 : // Make sure we are dealing with either an <A> or <AREA> element in the HTML
371 : // or XHTML namespace.
372 0 : if (!content->IsHTML())
373 0 : return;
374 0 : nsIAtom *nameAtom = content->Tag();
375 0 : if (!nameAtom->Equals(NS_LITERAL_STRING("a")) &&
376 0 : !nameAtom->Equals(NS_LITERAL_STRING("area")))
377 0 : return;
378 :
379 0 : nsCOMPtr<nsIAtom> pingAtom = do_GetAtom("ping");
380 0 : if (!pingAtom)
381 : return;
382 :
383 0 : nsAutoString value;
384 0 : content->GetAttr(kNameSpaceID_None, pingAtom, value);
385 0 : if (value.IsEmpty())
386 : return;
387 :
388 0 : nsCOMPtr<nsIIOService> ios = do_GetIOService();
389 0 : if (!ios)
390 : return;
391 :
392 0 : nsIDocument *doc = content->OwnerDoc();
393 :
394 : // value contains relative URIs split on spaces (U+0020)
395 0 : const PRUnichar *start = value.BeginReading();
396 0 : const PRUnichar *end = value.EndReading();
397 0 : const PRUnichar *iter = start;
398 0 : for (;;) {
399 0 : if (iter < end && *iter != ' ') {
400 0 : ++iter;
401 : } else { // iter is pointing at either end or a space
402 0 : while (*start == ' ' && start < iter)
403 0 : ++start;
404 0 : if (iter != start) {
405 0 : nsCOMPtr<nsIURI> uri, baseURI = content->GetBaseURI();
406 0 : ios->NewURI(NS_ConvertUTF16toUTF8(Substring(start, iter)),
407 0 : doc->GetDocumentCharacterSet().get(),
408 0 : baseURI, getter_AddRefs(uri));
409 0 : if (CheckPingURI(uri, content)) {
410 0 : callback(closure, content, uri, ios);
411 : }
412 : }
413 0 : start = iter = iter + 1;
414 0 : if (iter >= end)
415 : break;
416 : }
417 : }
418 : }
419 :
420 : //----------------------------------------------------------------------
421 :
422 : // We wait this many milliseconds before killing the ping channel...
423 : #define PING_TIMEOUT 10000
424 :
425 : static void
426 0 : OnPingTimeout(nsITimer *timer, void *closure)
427 : {
428 0 : nsILoadGroup *loadGroup = static_cast<nsILoadGroup *>(closure);
429 0 : loadGroup->Cancel(NS_ERROR_ABORT);
430 0 : loadGroup->Release();
431 0 : }
432 :
433 : // Check to see if two URIs have the same host or not
434 : static bool
435 0 : IsSameHost(nsIURI *uri1, nsIURI *uri2)
436 : {
437 0 : nsCAutoString host1, host2;
438 0 : uri1->GetAsciiHost(host1);
439 0 : uri2->GetAsciiHost(host2);
440 0 : return host1.Equals(host2);
441 : }
442 :
443 : class nsPingListener : public nsIStreamListener
444 : , public nsIInterfaceRequestor
445 : , public nsIChannelEventSink
446 0 : {
447 : public:
448 : NS_DECL_ISUPPORTS
449 : NS_DECL_NSIREQUESTOBSERVER
450 : NS_DECL_NSISTREAMLISTENER
451 : NS_DECL_NSIINTERFACEREQUESTOR
452 : NS_DECL_NSICHANNELEVENTSINK
453 :
454 0 : nsPingListener(bool requireSameHost, nsIContent* content)
455 : : mRequireSameHost(requireSameHost),
456 0 : mContent(content)
457 0 : {}
458 :
459 : private:
460 : bool mRequireSameHost;
461 : nsCOMPtr<nsIContent> mContent;
462 : };
463 :
464 0 : NS_IMPL_ISUPPORTS4(nsPingListener, nsIStreamListener, nsIRequestObserver,
465 : nsIInterfaceRequestor, nsIChannelEventSink)
466 :
467 : NS_IMETHODIMP
468 0 : nsPingListener::OnStartRequest(nsIRequest *request, nsISupports *context)
469 : {
470 0 : return NS_OK;
471 : }
472 :
473 : NS_IMETHODIMP
474 0 : nsPingListener::OnDataAvailable(nsIRequest *request, nsISupports *context,
475 : nsIInputStream *stream, PRUint32 offset,
476 : PRUint32 count)
477 : {
478 : PRUint32 result;
479 0 : return stream->ReadSegments(NS_DiscardSegment, nsnull, count, &result);
480 : }
481 :
482 : NS_IMETHODIMP
483 0 : nsPingListener::OnStopRequest(nsIRequest *request, nsISupports *context,
484 : nsresult status)
485 : {
486 0 : return NS_OK;
487 : }
488 :
489 : NS_IMETHODIMP
490 0 : nsPingListener::GetInterface(const nsIID &iid, void **result)
491 : {
492 0 : if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
493 0 : NS_ADDREF_THIS();
494 0 : *result = (nsIChannelEventSink *) this;
495 0 : return NS_OK;
496 : }
497 :
498 0 : return NS_ERROR_NO_INTERFACE;
499 : }
500 :
501 : NS_IMETHODIMP
502 0 : nsPingListener::AsyncOnChannelRedirect(nsIChannel *oldChan, nsIChannel *newChan,
503 : PRUint32 flags,
504 : nsIAsyncVerifyRedirectCallback *callback)
505 : {
506 0 : nsCOMPtr<nsIURI> newURI;
507 0 : newChan->GetURI(getter_AddRefs(newURI));
508 :
509 0 : if (!CheckPingURI(newURI, mContent))
510 0 : return NS_ERROR_ABORT;
511 :
512 0 : if (!mRequireSameHost) {
513 0 : callback->OnRedirectVerifyCallback(NS_OK);
514 0 : return NS_OK;
515 : }
516 :
517 : // XXXbz should this be using something more like the nsContentUtils
518 : // same-origin checker?
519 0 : nsCOMPtr<nsIURI> oldURI;
520 0 : oldChan->GetURI(getter_AddRefs(oldURI));
521 0 : NS_ENSURE_STATE(oldURI && newURI);
522 :
523 0 : if (!IsSameHost(oldURI, newURI))
524 0 : return NS_ERROR_ABORT;
525 :
526 0 : callback->OnRedirectVerifyCallback(NS_OK);
527 0 : return NS_OK;
528 : }
529 :
530 : struct SendPingInfo {
531 : PRInt32 numPings;
532 : PRInt32 maxPings;
533 : bool requireSameHost;
534 : nsIURI *referrer;
535 : };
536 :
537 : static void
538 0 : SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios)
539 : {
540 0 : SendPingInfo *info = static_cast<SendPingInfo *>(closure);
541 0 : if (info->numPings >= info->maxPings)
542 0 : return;
543 :
544 0 : if (info->requireSameHost) {
545 : // Make sure the referrer and the given uri share the same origin. We
546 : // only require the same hostname. The scheme and port may differ.
547 0 : if (!IsSameHost(uri, info->referrer))
548 0 : return;
549 : }
550 :
551 0 : nsIDocument *doc = content->OwnerDoc();
552 :
553 0 : nsCOMPtr<nsIChannel> chan;
554 0 : ios->NewChannelFromURI(uri, getter_AddRefs(chan));
555 0 : if (!chan)
556 : return;
557 :
558 : // Don't bother caching the result of this URI load.
559 0 : chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING);
560 :
561 0 : nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
562 0 : if (!httpChan)
563 : return;
564 :
565 : // This is needed in order for 3rd-party cookie blocking to work.
566 0 : nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
567 0 : if (httpInternal)
568 0 : httpInternal->SetDocumentURI(doc->GetDocumentURI());
569 :
570 0 : if (info->referrer)
571 0 : httpChan->SetReferrer(info->referrer);
572 :
573 0 : httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
574 :
575 : // Remove extraneous request headers (to reduce request size)
576 0 : httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
577 0 : EmptyCString(), false);
578 0 : httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
579 0 : EmptyCString(), false);
580 0 : httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
581 0 : EmptyCString(), false);
582 :
583 0 : nsCOMPtr<nsIUploadChannel> uploadChan = do_QueryInterface(httpChan);
584 0 : if (!uploadChan)
585 : return;
586 :
587 : // To avoid sending an unnecessary Content-Type header, we encode the
588 : // closing portion of the headers in the POST body.
589 0 : NS_NAMED_LITERAL_CSTRING(uploadData, "Content-Length: 0\r\n\r\n");
590 :
591 0 : nsCOMPtr<nsIInputStream> uploadStream;
592 0 : NS_NewPostDataStream(getter_AddRefs(uploadStream), false,
593 0 : uploadData, 0);
594 0 : if (!uploadStream)
595 : return;
596 :
597 0 : uploadChan->SetUploadStream(uploadStream, EmptyCString(), -1);
598 :
599 : // The channel needs to have a loadgroup associated with it, so that we can
600 : // cancel the channel and any redirected channels it may create.
601 : nsCOMPtr<nsILoadGroup> loadGroup =
602 0 : do_CreateInstance(NS_LOADGROUP_CONTRACTID);
603 0 : if (!loadGroup)
604 : return;
605 0 : chan->SetLoadGroup(loadGroup);
606 :
607 : // Construct a listener that merely discards any response. If successful at
608 : // opening the channel, then it is not necessary to hold a reference to the
609 : // channel. The networking subsystem will take care of that for us.
610 : nsCOMPtr<nsIStreamListener> listener =
611 0 : new nsPingListener(info->requireSameHost, content);
612 0 : if (!listener)
613 : return;
614 :
615 : // Observe redirects as well:
616 0 : nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(listener);
617 0 : NS_ASSERTION(callbacks, "oops");
618 0 : loadGroup->SetNotificationCallbacks(callbacks);
619 :
620 0 : chan->AsyncOpen(listener, nsnull);
621 :
622 : // Even if AsyncOpen failed, we still count this as a successful ping. It's
623 : // possible that AsyncOpen may have failed after triggering some background
624 : // process that may have written something to the network.
625 0 : info->numPings++;
626 :
627 : // Prevent ping requests from stalling and never being garbage collected...
628 : nsCOMPtr<nsITimer> timer =
629 0 : do_CreateInstance(NS_TIMER_CONTRACTID);
630 0 : if (timer) {
631 0 : nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, loadGroup,
632 : PING_TIMEOUT,
633 0 : nsITimer::TYPE_ONE_SHOT);
634 0 : if (NS_SUCCEEDED(rv)) {
635 : // When the timer expires, the callback function will release this
636 : // reference to the loadgroup.
637 0 : static_cast<nsILoadGroup *>(loadGroup.get())->AddRef();
638 0 : loadGroup = 0;
639 : }
640 : }
641 :
642 : // If we failed to setup the timer, then we should just cancel the channel
643 : // because we won't be able to ensure that it goes away in a timely manner.
644 0 : if (loadGroup)
645 0 : chan->Cancel(NS_ERROR_ABORT);
646 : }
647 :
648 : // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
649 : static void
650 0 : DispatchPings(nsIContent *content, nsIURI *referrer)
651 : {
652 : SendPingInfo info;
653 :
654 0 : if (!PingsEnabled(&info.maxPings, &info.requireSameHost))
655 0 : return;
656 0 : if (info.maxPings == 0)
657 0 : return;
658 :
659 0 : info.numPings = 0;
660 0 : info.referrer = referrer;
661 :
662 0 : ForEachPing(content, SendPing, &info);
663 : }
664 :
665 : static nsDOMPerformanceNavigationType
666 0 : ConvertLoadTypeToNavigationType(PRUint32 aLoadType)
667 : {
668 : // Not initialized, assume it's normal load.
669 0 : if (aLoadType == 0) {
670 0 : aLoadType = LOAD_NORMAL;
671 : }
672 :
673 0 : nsDOMPerformanceNavigationType result = nsIDOMPerformanceNavigation::TYPE_RESERVED;
674 0 : switch (aLoadType) {
675 : case LOAD_NORMAL:
676 : case LOAD_NORMAL_EXTERNAL:
677 : case LOAD_NORMAL_BYPASS_CACHE:
678 : case LOAD_NORMAL_BYPASS_PROXY:
679 : case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
680 : case LOAD_NORMAL_REPLACE:
681 : case LOAD_LINK:
682 : case LOAD_STOP_CONTENT:
683 0 : result = nsIDOMPerformanceNavigation::TYPE_NAVIGATE;
684 0 : break;
685 : case LOAD_HISTORY:
686 0 : result = nsIDOMPerformanceNavigation::TYPE_BACK_FORWARD;
687 0 : break;
688 : case LOAD_RELOAD_NORMAL:
689 : case LOAD_RELOAD_CHARSET_CHANGE:
690 : case LOAD_RELOAD_BYPASS_CACHE:
691 : case LOAD_RELOAD_BYPASS_PROXY:
692 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
693 0 : result = nsIDOMPerformanceNavigation::TYPE_RELOAD;
694 0 : break;
695 : case LOAD_STOP_CONTENT_AND_REPLACE:
696 : case LOAD_REFRESH:
697 : case LOAD_BYPASS_HISTORY:
698 : case LOAD_ERROR_PAGE:
699 : case LOAD_PUSHSTATE:
700 0 : result = nsIDOMPerformanceNavigation::TYPE_RESERVED;
701 0 : break;
702 : default:
703 : // NS_NOTREACHED("Unexpected load type value");
704 0 : result = nsIDOMPerformanceNavigation::TYPE_RESERVED;
705 0 : break;
706 : }
707 :
708 0 : return result;
709 : }
710 :
711 : static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
712 :
713 : //*****************************************************************************
714 : //*** nsDocShell: Object Management
715 : //*****************************************************************************
716 :
717 : static PRUint64 gDocshellIDCounter = 0;
718 :
719 : // Note: operator new zeros our memory
720 0 : nsDocShell::nsDocShell():
721 : nsDocLoader(),
722 : mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
723 : mTreeOwner(nsnull),
724 : mChromeEventHandler(nsnull),
725 : mCharsetReloadState(eCharsetReloadInit),
726 : mChildOffset(0),
727 : mBusyFlags(BUSY_FLAGS_NONE),
728 : mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
729 : mLoadType(0),
730 : mMarginWidth(-1),
731 : mMarginHeight(-1),
732 : mItemType(typeContent),
733 : mPreviousTransIndex(-1),
734 : mLoadedTransIndex(-1),
735 : mCreated(false),
736 : mAllowSubframes(true),
737 : mAllowPlugins(true),
738 : mAllowJavascript(true),
739 : mAllowMetaRedirects(true),
740 : mAllowImages(true),
741 : mAllowDNSPrefetch(true),
742 : mAllowWindowControl(true),
743 : mCreatingDocument(false),
744 : mUseErrorPages(false),
745 : mObserveErrorPages(true),
746 : mAllowAuth(true),
747 : mAllowKeywordFixup(false),
748 : mIsOffScreenBrowser(false),
749 : mIsActive(true),
750 : mIsAppTab(false),
751 : mUseGlobalHistory(false),
752 : mInPrivateBrowsing(false),
753 : mFiredUnloadEvent(false),
754 : mEODForCurrentDocument(false),
755 : mURIResultedInDocument(false),
756 : mIsBeingDestroyed(false),
757 : mIsExecutingOnLoadHandler(false),
758 : mIsPrintingOrPP(false),
759 : mSavingOldViewer(false),
760 : #ifdef DEBUG
761 : mInEnsureScriptEnv(false),
762 : #endif
763 0 : mParentCharsetSource(0)
764 : {
765 0 : mHistoryID = ++gDocshellIDCounter;
766 0 : if (gDocShellCount++ == 0) {
767 0 : NS_ASSERTION(sURIFixup == nsnull,
768 : "Huh, sURIFixup not null in first nsDocShell ctor!");
769 :
770 0 : CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
771 : }
772 :
773 : #ifdef PR_LOGGING
774 : #ifdef DEBUG
775 0 : if (! gDocShellLog)
776 0 : gDocShellLog = PR_NewLogModule("nsDocShell");
777 : #endif
778 0 : if (nsnull == gDocShellLeakLog)
779 0 : gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
780 0 : if (gDocShellLeakLog)
781 0 : PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this));
782 : #endif
783 :
784 : #ifdef DEBUG
785 : // We're counting the number of |nsDocShells| to help find leaks
786 0 : ++gNumberOfDocShells;
787 0 : if (!PR_GetEnv("MOZ_QUIET")) {
788 : printf("++DOCSHELL %p == %ld [id = %ld]\n", (void*) this,
789 0 : gNumberOfDocShells, mHistoryID);
790 : }
791 : #endif
792 0 : }
793 :
794 0 : nsDocShell::~nsDocShell()
795 : {
796 0 : Destroy();
797 :
798 : nsCOMPtr<nsISHistoryInternal>
799 0 : shPrivate(do_QueryInterface(mSessionHistory));
800 0 : if (shPrivate) {
801 0 : shPrivate->SetRootDocShell(nsnull);
802 : }
803 :
804 0 : if (--gDocShellCount == 0) {
805 0 : NS_IF_RELEASE(sURIFixup);
806 : }
807 :
808 : #ifdef PR_LOGGING
809 0 : if (gDocShellLeakLog)
810 0 : PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this));
811 : #endif
812 :
813 : #ifdef DEBUG
814 : // We're counting the number of |nsDocShells| to help find leaks
815 0 : --gNumberOfDocShells;
816 0 : if (!PR_GetEnv("MOZ_QUIET")) {
817 : printf("--DOCSHELL %p == %ld [id = %ld]\n", (void*) this,
818 0 : gNumberOfDocShells, mHistoryID);
819 : }
820 : #endif
821 0 : }
822 :
823 : nsresult
824 0 : nsDocShell::Init()
825 : {
826 0 : nsresult rv = nsDocLoader::Init();
827 0 : NS_ENSURE_SUCCESS(rv, rv);
828 :
829 0 : NS_ASSERTION(mLoadGroup, "Something went wrong!");
830 :
831 0 : mContentListener = new nsDSURIContentListener(this);
832 0 : NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
833 :
834 0 : rv = mContentListener->Init();
835 0 : NS_ENSURE_SUCCESS(rv, rv);
836 :
837 0 : if (!mStorages.Init())
838 0 : return NS_ERROR_OUT_OF_MEMORY;
839 :
840 : // We want to hold a strong ref to the loadgroup, so it better hold a weak
841 : // ref to us... use an InterfaceRequestorProxy to do this.
842 : nsCOMPtr<InterfaceRequestorProxy> proxy =
843 : new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>
844 0 : (this));
845 0 : NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
846 0 : mLoadGroup->SetNotificationCallbacks(proxy);
847 :
848 0 : rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
849 0 : NS_ENSURE_SUCCESS(rv, rv);
850 :
851 : // Add as |this| a progress listener to itself. A little weird, but
852 : // simpler than reproducing all the listener-notification logic in
853 : // overrides of the various methods via which nsDocLoader can be
854 : // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
855 : return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
856 0 : nsIWebProgress::NOTIFY_STATE_NETWORK);
857 :
858 : }
859 :
860 : void
861 0 : nsDocShell::DestroyChildren()
862 : {
863 0 : nsCOMPtr<nsIDocShellTreeItem> shell;
864 0 : PRInt32 n = mChildList.Count();
865 0 : for (PRInt32 i = 0; i < n; i++) {
866 0 : shell = do_QueryInterface(ChildAt(i));
867 0 : NS_ASSERTION(shell, "docshell has null child");
868 :
869 0 : if (shell) {
870 0 : shell->SetTreeOwner(nsnull);
871 : }
872 : }
873 :
874 0 : nsDocLoader::DestroyChildren();
875 0 : }
876 :
877 : //*****************************************************************************
878 : // nsDocShell::nsISupports
879 : //*****************************************************************************
880 :
881 0 : NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
882 0 : NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
883 :
884 0 : NS_INTERFACE_MAP_BEGIN(nsDocShell)
885 0 : NS_INTERFACE_MAP_ENTRY(nsIDocShell)
886 0 : NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
887 0 : NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
888 0 : NS_INTERFACE_MAP_ENTRY(nsIDocShellHistory)
889 0 : NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
890 0 : NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
891 0 : NS_INTERFACE_MAP_ENTRY(nsIScrollable)
892 0 : NS_INTERFACE_MAP_ENTRY(nsITextScroll)
893 0 : NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
894 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
895 0 : NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
896 0 : NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
897 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
898 0 : NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
899 0 : NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell)
900 0 : NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
901 0 : NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
902 0 : NS_INTERFACE_MAP_ENTRY(nsIObserver)
903 0 : NS_INTERFACE_MAP_ENTRY(nsILoadContext)
904 0 : NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
905 0 : NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
906 0 : NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
907 0 : NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
908 :
909 : ///*****************************************************************************
910 : // nsDocShell::nsIInterfaceRequestor
911 : //*****************************************************************************
912 0 : NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
913 : {
914 0 : NS_PRECONDITION(aSink, "null out param");
915 :
916 0 : *aSink = nsnull;
917 :
918 0 : if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
919 0 : NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
920 0 : *aSink = mCommandManager;
921 : }
922 0 : else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
923 0 : *aSink = mContentListener;
924 : }
925 0 : else if (aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) &&
926 0 : NS_SUCCEEDED(EnsureScriptEnvironment())) {
927 0 : *aSink = mScriptGlobal;
928 : }
929 0 : else if ((aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||
930 0 : aIID.Equals(NS_GET_IID(nsIDOMWindow)) ||
931 0 : aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) &&
932 0 : NS_SUCCEEDED(EnsureScriptEnvironment())) {
933 0 : return mScriptGlobal->QueryInterface(aIID, aSink);
934 : }
935 0 : else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
936 0 : NS_SUCCEEDED(EnsureContentViewer())) {
937 0 : mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
938 0 : return *aSink ? NS_OK : NS_NOINTERFACE;
939 : }
940 0 : else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
941 0 : NS_SUCCEEDED(EnsureContentViewer())) {
942 0 : nsCOMPtr<nsIDOMDocument> domDoc;
943 0 : mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
944 0 : if (!domDoc)
945 0 : return NS_NOINTERFACE;
946 0 : return domDoc->QueryInterface(aIID, aSink);
947 : }
948 0 : else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
949 0 : *aSink = nsnull;
950 :
951 : // Return application cache associated with this docshell, if any
952 :
953 0 : nsCOMPtr<nsIContentViewer> contentViewer;
954 0 : GetContentViewer(getter_AddRefs(contentViewer));
955 0 : if (!contentViewer)
956 0 : return NS_ERROR_NO_INTERFACE;
957 :
958 0 : nsCOMPtr<nsIDOMDocument> domDoc;
959 0 : contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
960 0 : NS_ASSERTION(domDoc, "Should have a document.");
961 0 : if (!domDoc)
962 0 : return NS_ERROR_NO_INTERFACE;
963 :
964 : #if defined(PR_LOGGING) && defined(DEBUG)
965 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
966 : ("nsDocShell[%p]: returning app cache container %p",
967 : this, domDoc.get()));
968 : #endif
969 0 : return domDoc->QueryInterface(aIID, aSink);
970 : }
971 0 : else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
972 0 : NS_SUCCEEDED(EnsureScriptEnvironment())) {
973 : nsresult rv;
974 : nsCOMPtr<nsIWindowWatcher> wwatch =
975 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
976 0 : NS_ENSURE_SUCCESS(rv, rv);
977 :
978 0 : nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(mScriptGlobal));
979 :
980 : // Get the an auth prompter for our window so that the parenting
981 : // of the dialogs works as it should when using tabs.
982 :
983 : nsIPrompt *prompt;
984 0 : rv = wwatch->GetNewPrompter(window, &prompt);
985 0 : NS_ENSURE_SUCCESS(rv, rv);
986 :
987 0 : *aSink = prompt;
988 0 : return NS_OK;
989 : }
990 0 : else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
991 0 : aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
992 0 : return NS_SUCCEEDED(
993 : GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
994 0 : NS_OK : NS_NOINTERFACE;
995 : }
996 0 : else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
997 0 : nsCOMPtr<nsISHistory> shistory;
998 : nsresult
999 : rv =
1000 0 : GetSessionHistory(getter_AddRefs(shistory));
1001 0 : if (NS_SUCCEEDED(rv) && shistory) {
1002 0 : *aSink = shistory;
1003 0 : NS_ADDREF((nsISupports *) * aSink);
1004 0 : return NS_OK;
1005 : }
1006 0 : return NS_NOINTERFACE;
1007 : }
1008 0 : else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
1009 0 : nsresult rv = EnsureFind();
1010 0 : if (NS_FAILED(rv)) return rv;
1011 :
1012 0 : *aSink = mFind;
1013 0 : NS_ADDREF((nsISupports*)*aSink);
1014 0 : return NS_OK;
1015 : }
1016 0 : else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) {
1017 0 : nsCOMPtr<nsIEditingSession> editingSession;
1018 0 : mEditorData->GetEditingSession(getter_AddRefs(editingSession));
1019 0 : if (editingSession)
1020 : {
1021 0 : *aSink = editingSession;
1022 0 : NS_ADDREF((nsISupports *)*aSink);
1023 0 : return NS_OK;
1024 : }
1025 :
1026 0 : return NS_NOINTERFACE;
1027 : }
1028 0 : else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList))
1029 0 : && NS_SUCCEEDED(EnsureTransferableHookData())) {
1030 0 : *aSink = mTransferableHookData;
1031 0 : NS_ADDREF((nsISupports *)*aSink);
1032 0 : return NS_OK;
1033 : }
1034 0 : else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
1035 0 : nsCOMPtr<nsIPresShell> shell;
1036 0 : nsresult rv = GetPresShell(getter_AddRefs(shell));
1037 0 : if (NS_SUCCEEDED(rv) && shell)
1038 0 : return shell->QueryInterface(aIID,aSink);
1039 : }
1040 0 : else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
1041 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1042 0 : nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
1043 0 : if (NS_SUCCEEDED(rv) && treeOwner)
1044 0 : return treeOwner->QueryInterface(aIID, aSink);
1045 : }
1046 0 : else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
1047 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1048 0 : nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
1049 0 : if (NS_SUCCEEDED(rv) && treeOwner) {
1050 0 : nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(treeOwner);
1051 0 : if (ir)
1052 0 : return ir->GetInterface(aIID, aSink);
1053 : }
1054 : }
1055 : else {
1056 0 : return nsDocLoader::GetInterface(aIID, aSink);
1057 : }
1058 :
1059 0 : NS_IF_ADDREF(((nsISupports *) * aSink));
1060 0 : return *aSink ? NS_OK : NS_NOINTERFACE;
1061 : }
1062 :
1063 : PRUint32
1064 0 : nsDocShell::
1065 : ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType)
1066 : {
1067 0 : PRUint32 loadType = LOAD_NORMAL;
1068 :
1069 0 : switch (aDocShellLoadType) {
1070 : case nsIDocShellLoadInfo::loadNormal:
1071 0 : loadType = LOAD_NORMAL;
1072 0 : break;
1073 : case nsIDocShellLoadInfo::loadNormalReplace:
1074 0 : loadType = LOAD_NORMAL_REPLACE;
1075 0 : break;
1076 : case nsIDocShellLoadInfo::loadNormalExternal:
1077 0 : loadType = LOAD_NORMAL_EXTERNAL;
1078 0 : break;
1079 : case nsIDocShellLoadInfo::loadHistory:
1080 0 : loadType = LOAD_HISTORY;
1081 0 : break;
1082 : case nsIDocShellLoadInfo::loadNormalBypassCache:
1083 0 : loadType = LOAD_NORMAL_BYPASS_CACHE;
1084 0 : break;
1085 : case nsIDocShellLoadInfo::loadNormalBypassProxy:
1086 0 : loadType = LOAD_NORMAL_BYPASS_PROXY;
1087 0 : break;
1088 : case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
1089 0 : loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
1090 0 : break;
1091 : case nsIDocShellLoadInfo::loadReloadNormal:
1092 0 : loadType = LOAD_RELOAD_NORMAL;
1093 0 : break;
1094 : case nsIDocShellLoadInfo::loadReloadCharsetChange:
1095 0 : loadType = LOAD_RELOAD_CHARSET_CHANGE;
1096 0 : break;
1097 : case nsIDocShellLoadInfo::loadReloadBypassCache:
1098 0 : loadType = LOAD_RELOAD_BYPASS_CACHE;
1099 0 : break;
1100 : case nsIDocShellLoadInfo::loadReloadBypassProxy:
1101 0 : loadType = LOAD_RELOAD_BYPASS_PROXY;
1102 0 : break;
1103 : case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
1104 0 : loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
1105 0 : break;
1106 : case nsIDocShellLoadInfo::loadLink:
1107 0 : loadType = LOAD_LINK;
1108 0 : break;
1109 : case nsIDocShellLoadInfo::loadRefresh:
1110 0 : loadType = LOAD_REFRESH;
1111 0 : break;
1112 : case nsIDocShellLoadInfo::loadBypassHistory:
1113 0 : loadType = LOAD_BYPASS_HISTORY;
1114 0 : break;
1115 : case nsIDocShellLoadInfo::loadStopContent:
1116 0 : loadType = LOAD_STOP_CONTENT;
1117 0 : break;
1118 : case nsIDocShellLoadInfo::loadStopContentAndReplace:
1119 0 : loadType = LOAD_STOP_CONTENT_AND_REPLACE;
1120 0 : break;
1121 : case nsIDocShellLoadInfo::loadPushState:
1122 0 : loadType = LOAD_PUSHSTATE;
1123 0 : break;
1124 : default:
1125 0 : NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
1126 : }
1127 :
1128 0 : return loadType;
1129 : }
1130 :
1131 :
1132 : nsDocShellInfoLoadType
1133 0 : nsDocShell::ConvertLoadTypeToDocShellLoadInfo(PRUint32 aLoadType)
1134 : {
1135 0 : nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
1136 0 : switch (aLoadType) {
1137 : case LOAD_NORMAL:
1138 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormal;
1139 0 : break;
1140 : case LOAD_NORMAL_REPLACE:
1141 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
1142 0 : break;
1143 : case LOAD_NORMAL_EXTERNAL:
1144 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
1145 0 : break;
1146 : case LOAD_NORMAL_BYPASS_CACHE:
1147 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
1148 0 : break;
1149 : case LOAD_NORMAL_BYPASS_PROXY:
1150 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
1151 0 : break;
1152 : case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
1153 0 : docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
1154 0 : break;
1155 : case LOAD_HISTORY:
1156 0 : docShellLoadType = nsIDocShellLoadInfo::loadHistory;
1157 0 : break;
1158 : case LOAD_RELOAD_NORMAL:
1159 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
1160 0 : break;
1161 : case LOAD_RELOAD_CHARSET_CHANGE:
1162 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
1163 0 : break;
1164 : case LOAD_RELOAD_BYPASS_CACHE:
1165 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
1166 0 : break;
1167 : case LOAD_RELOAD_BYPASS_PROXY:
1168 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
1169 0 : break;
1170 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
1171 0 : docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
1172 0 : break;
1173 : case LOAD_LINK:
1174 0 : docShellLoadType = nsIDocShellLoadInfo::loadLink;
1175 0 : break;
1176 : case LOAD_REFRESH:
1177 0 : docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
1178 0 : break;
1179 : case LOAD_BYPASS_HISTORY:
1180 : case LOAD_ERROR_PAGE:
1181 0 : docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
1182 0 : break;
1183 : case LOAD_STOP_CONTENT:
1184 0 : docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
1185 0 : break;
1186 : case LOAD_STOP_CONTENT_AND_REPLACE:
1187 0 : docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
1188 0 : break;
1189 : case LOAD_PUSHSTATE:
1190 0 : docShellLoadType = nsIDocShellLoadInfo::loadPushState;
1191 0 : break;
1192 : default:
1193 0 : NS_NOTREACHED("Unexpected load type value");
1194 : }
1195 :
1196 0 : return docShellLoadType;
1197 : }
1198 :
1199 : //*****************************************************************************
1200 : // nsDocShell::nsIDocShell
1201 : //*****************************************************************************
1202 : NS_IMETHODIMP
1203 0 : nsDocShell::LoadURI(nsIURI * aURI,
1204 : nsIDocShellLoadInfo * aLoadInfo,
1205 : PRUint32 aLoadFlags,
1206 : bool aFirstParty)
1207 : {
1208 0 : NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
1209 : "Unexpected flags");
1210 0 : NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
1211 :
1212 : // Note: we allow loads to get through here even if mFiredUnloadEvent is
1213 : // true; that case will get handled in LoadInternal or LoadHistoryEntry.
1214 0 : if (IsPrintingOrPP()) {
1215 0 : return NS_OK; // JS may not handle returning of an error code
1216 : }
1217 : nsresult rv;
1218 0 : nsCOMPtr<nsIURI> referrer;
1219 0 : nsCOMPtr<nsIInputStream> postStream;
1220 0 : nsCOMPtr<nsIInputStream> headersStream;
1221 0 : nsCOMPtr<nsISupports> owner;
1222 0 : bool inheritOwner = false;
1223 0 : bool ownerIsExplicit = false;
1224 0 : bool sendReferrer = true;
1225 0 : nsCOMPtr<nsISHEntry> shEntry;
1226 0 : nsXPIDLString target;
1227 0 : PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
1228 :
1229 0 : NS_ENSURE_ARG(aURI);
1230 :
1231 0 : if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
1232 0 : mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
1233 0 : StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
1234 : }
1235 :
1236 : // Extract the info from the DocShellLoadInfo struct...
1237 0 : if (aLoadInfo) {
1238 0 : aLoadInfo->GetReferrer(getter_AddRefs(referrer));
1239 :
1240 0 : nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
1241 0 : aLoadInfo->GetLoadType(<);
1242 : // Get the appropriate loadType from nsIDocShellLoadInfo type
1243 0 : loadType = ConvertDocShellLoadInfoToLoadType(lt);
1244 :
1245 0 : aLoadInfo->GetOwner(getter_AddRefs(owner));
1246 0 : aLoadInfo->GetInheritOwner(&inheritOwner);
1247 0 : aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
1248 0 : aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
1249 0 : aLoadInfo->GetTarget(getter_Copies(target));
1250 0 : aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
1251 0 : aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
1252 0 : aLoadInfo->GetSendReferrer(&sendReferrer);
1253 : }
1254 :
1255 : #if defined(PR_LOGGING) && defined(DEBUG)
1256 0 : if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
1257 0 : nsCAutoString uristr;
1258 0 : aURI->GetAsciiSpec(uristr);
1259 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
1260 : ("nsDocShell[%p]: loading %s with flags 0x%08x",
1261 : this, uristr.get(), aLoadFlags));
1262 : }
1263 : #endif
1264 :
1265 0 : if (!shEntry &&
1266 0 : !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
1267 : // First verify if this is a subframe.
1268 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
1269 0 : GetSameTypeParent(getter_AddRefs(parentAsItem));
1270 0 : nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
1271 : PRUint32 parentLoadType;
1272 :
1273 0 : if (parentDS && parentDS != static_cast<nsIDocShell *>(this)) {
1274 : /* OK. It is a subframe. Checkout the
1275 : * parent's loadtype. If the parent was loaded thro' a history
1276 : * mechanism, then get the SH entry for the child from the parent.
1277 : * This is done to restore frameset navigation while going back/forward.
1278 : * If the parent was loaded through any other loadType, set the
1279 : * child's loadType too accordingly, so that session history does not
1280 : * get confused.
1281 : */
1282 :
1283 : // Get the parent's load type
1284 0 : parentDS->GetLoadType(&parentLoadType);
1285 :
1286 0 : nsCOMPtr<nsIDocShellHistory> parent(do_QueryInterface(parentAsItem));
1287 0 : if (parent) {
1288 : // Get the ShEntry for the child from the parent
1289 0 : nsCOMPtr<nsISHEntry> currentSH;
1290 0 : bool oshe = false;
1291 0 : parent->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
1292 0 : bool dynamicallyAddedChild = mDynamicallyCreated;
1293 0 : if (!dynamicallyAddedChild && !oshe && currentSH) {
1294 0 : currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
1295 : }
1296 0 : if (!dynamicallyAddedChild) {
1297 : // Only use the old SHEntry, if we're sure enough that
1298 : // it wasn't originally for some other frame.
1299 0 : parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
1300 : }
1301 :
1302 : // Make some decisions on the child frame's loadType based on the
1303 : // parent's loadType.
1304 0 : if (mCurrentURI == nsnull) {
1305 : // This is a newly created frame. Check for exception cases first.
1306 : // By default the subframe will inherit the parent's loadType.
1307 0 : if (shEntry && (parentLoadType == LOAD_NORMAL ||
1308 : parentLoadType == LOAD_LINK ||
1309 0 : parentLoadType == LOAD_NORMAL_EXTERNAL)) {
1310 : // The parent was loaded normally. In this case, this *brand new* child really shouldn't
1311 : // have a SHEntry. If it does, it could be because the parent is replacing an
1312 : // existing frame with a new frame, in the onLoadHandler. We don't want this
1313 : // url to get into session history. Clear off shEntry, and set load type to
1314 : // LOAD_BYPASS_HISTORY.
1315 0 : bool inOnLoadHandler=false;
1316 0 : parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
1317 0 : if (inOnLoadHandler) {
1318 0 : loadType = LOAD_NORMAL_REPLACE;
1319 0 : shEntry = nsnull;
1320 : }
1321 : }
1322 0 : else if (parentLoadType == LOAD_REFRESH) {
1323 : // Clear shEntry. For refresh loads, we have to load
1324 : // what comes thro' the pipe, not what's in history.
1325 0 : shEntry = nsnull;
1326 : }
1327 0 : else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
1328 : (parentLoadType == LOAD_ERROR_PAGE) ||
1329 : (shEntry &&
1330 : ((parentLoadType & LOAD_CMD_HISTORY) ||
1331 : (parentLoadType == LOAD_RELOAD_NORMAL) ||
1332 0 : (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
1333 : // If the parent url, bypassed history or was loaded from
1334 : // history, pass on the parent's loadType to the new child
1335 : // frame too, so that the child frame will also
1336 : // avoid getting into history.
1337 0 : loadType = parentLoadType;
1338 : }
1339 : }
1340 : else {
1341 : // This is a pre-existing subframe. If the load was not originally initiated
1342 : // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null,
1343 : // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading
1344 : // a new page in this child. Check parent's and self's busy flag and if it is set,
1345 : // we don't want this onLoadHandler load to get in to session history.
1346 0 : PRUint32 parentBusy = BUSY_FLAGS_NONE;
1347 0 : PRUint32 selfBusy = BUSY_FLAGS_NONE;
1348 0 : parentDS->GetBusyFlags(&parentBusy);
1349 0 : GetBusyFlags(&selfBusy);
1350 0 : if (parentBusy & BUSY_FLAGS_BUSY ||
1351 : selfBusy & BUSY_FLAGS_BUSY) {
1352 0 : loadType = LOAD_NORMAL_REPLACE;
1353 0 : shEntry = nsnull;
1354 : }
1355 : }
1356 : } // parent
1357 : } //parentDS
1358 : else {
1359 : // This is the root docshell. If we got here while
1360 : // executing an onLoad Handler,this load will not go
1361 : // into session history.
1362 0 : bool inOnLoadHandler=false;
1363 0 : GetIsExecutingOnLoadHandler(&inOnLoadHandler);
1364 0 : if (inOnLoadHandler) {
1365 0 : loadType = LOAD_NORMAL_REPLACE;
1366 : }
1367 : }
1368 : } // !shEntry
1369 :
1370 0 : if (shEntry) {
1371 : #ifdef DEBUG
1372 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
1373 : ("nsDocShell[%p]: loading from session history", this));
1374 : #endif
1375 :
1376 0 : return LoadHistoryEntry(shEntry, loadType);
1377 : }
1378 :
1379 : // Perform the load...
1380 :
1381 : // We need an owner (a referring principal).
1382 : //
1383 : // If ownerIsExplicit is not set there are 4 possibilities:
1384 : // (1) If the system principal was passed in and we're a typeContent
1385 : // docshell, inherit the principal from the current document
1386 : // instead.
1387 : // (2) In all other cases when the principal passed in is not null,
1388 : // use that principal.
1389 : // (3) If the caller has allowed inheriting from the current document,
1390 : // or if we're being called from system code (eg chrome JS or pure
1391 : // C++) then inheritOwner should be true and InternalLoad will get
1392 : // an owner from the current document. If none of these things are
1393 : // true, then
1394 : // (4) we pass a null owner into the channel, and an owner will be
1395 : // created later from the channel's internal data.
1396 : //
1397 : // If ownerIsExplicit *is* set, there are 4 possibilities
1398 : // (1) If the system principal was passed in and we're a typeContent
1399 : // docshell, return an error.
1400 : // (2) In all other cases when the principal passed in is not null,
1401 : // use that principal.
1402 : // (3) If the caller has allowed inheriting from the current document,
1403 : // then inheritOwner should be true and InternalLoad will get an owner
1404 : // from the current document. If none of these things are true, then
1405 : // (4) we pass a null owner into the channel, and an owner will be
1406 : // created later from the channel's internal data.
1407 : //
1408 : // NOTE: This all only works because the only thing the owner is used
1409 : // for in InternalLoad is data:, javascript:, and about:blank
1410 : // URIs. For other URIs this would all be dead wrong!
1411 :
1412 : nsCOMPtr<nsIScriptSecurityManager> secMan =
1413 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1414 0 : NS_ENSURE_SUCCESS(rv, rv);
1415 :
1416 0 : if (owner && mItemType != typeChrome) {
1417 0 : nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
1418 : bool isSystem;
1419 0 : rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem);
1420 0 : NS_ENSURE_SUCCESS(rv, rv);
1421 :
1422 0 : if (isSystem) {
1423 0 : if (ownerIsExplicit) {
1424 0 : return NS_ERROR_DOM_SECURITY_ERR;
1425 : }
1426 0 : owner = nsnull;
1427 0 : inheritOwner = true;
1428 : }
1429 : }
1430 0 : if (!owner && !inheritOwner && !ownerIsExplicit) {
1431 : // See if there's system or chrome JS code running
1432 0 : rv = secMan->SubjectPrincipalIsSystem(&inheritOwner);
1433 0 : if (NS_FAILED(rv)) {
1434 : // Set it back to false
1435 0 : inheritOwner = false;
1436 : }
1437 : }
1438 :
1439 0 : if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
1440 0 : inheritOwner = false;
1441 0 : owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
1442 : }
1443 :
1444 0 : PRUint32 flags = 0;
1445 :
1446 0 : if (inheritOwner)
1447 0 : flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
1448 :
1449 0 : if (!sendReferrer)
1450 0 : flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
1451 :
1452 0 : if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
1453 0 : flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
1454 :
1455 0 : if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
1456 0 : flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
1457 :
1458 0 : if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
1459 0 : flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
1460 :
1461 0 : if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES)
1462 0 : flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
1463 :
1464 : return InternalLoad(aURI,
1465 : referrer,
1466 : owner,
1467 : flags,
1468 : target.get(),
1469 : nsnull, // No type hint
1470 : postStream,
1471 : headersStream,
1472 : loadType,
1473 : nsnull, // No SHEntry
1474 : aFirstParty,
1475 : nsnull, // No nsIDocShell
1476 0 : nsnull); // No nsIRequest
1477 : }
1478 :
1479 : NS_IMETHODIMP
1480 0 : nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
1481 : const nsACString &aContentType,
1482 : const nsACString &aContentCharset,
1483 : nsIDocShellLoadInfo * aLoadInfo)
1484 : {
1485 0 : NS_ENSURE_ARG(aStream);
1486 :
1487 0 : mAllowKeywordFixup = false;
1488 :
1489 : // if the caller doesn't pass in a URI we need to create a dummy URI. necko
1490 : // currently requires a URI in various places during the load. Some consumers
1491 : // do as well.
1492 0 : nsCOMPtr<nsIURI> uri = aURI;
1493 0 : if (!uri) {
1494 : // HACK ALERT
1495 0 : nsresult rv = NS_OK;
1496 0 : uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
1497 0 : if (NS_FAILED(rv))
1498 0 : return rv;
1499 : // Make sure that the URI spec "looks" like a protocol and path...
1500 : // For now, just use a bogus protocol called "internal"
1501 0 : rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
1502 0 : if (NS_FAILED(rv))
1503 0 : return rv;
1504 : }
1505 :
1506 0 : PRUint32 loadType = LOAD_NORMAL;
1507 0 : if (aLoadInfo) {
1508 0 : nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
1509 0 : (void) aLoadInfo->GetLoadType(<);
1510 : // Get the appropriate LoadType from nsIDocShellLoadInfo type
1511 0 : loadType = ConvertDocShellLoadInfoToLoadType(lt);
1512 : }
1513 :
1514 0 : NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
1515 :
1516 0 : mLoadType = loadType;
1517 :
1518 : // build up a channel for this stream.
1519 0 : nsCOMPtr<nsIChannel> channel;
1520 0 : NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
1521 : (getter_AddRefs(channel), uri, aStream,
1522 : aContentType, aContentCharset),
1523 : NS_ERROR_FAILURE);
1524 :
1525 : nsCOMPtr<nsIURILoader>
1526 0 : uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
1527 0 : NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
1528 :
1529 0 : NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
1530 : NS_ERROR_FAILURE);
1531 0 : return NS_OK;
1532 : }
1533 :
1534 : NS_IMETHODIMP
1535 0 : nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo)
1536 : {
1537 0 : nsDocShellLoadInfo *loadInfo = new nsDocShellLoadInfo();
1538 0 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
1539 0 : nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
1540 :
1541 0 : *aLoadInfo = localRef;
1542 0 : NS_ADDREF(*aLoadInfo);
1543 0 : return NS_OK;
1544 : }
1545 :
1546 :
1547 : /*
1548 : * Reset state to a new content model within the current document and the document
1549 : * viewer. Called by the document before initiating an out of band document.write().
1550 : */
1551 : NS_IMETHODIMP
1552 0 : nsDocShell::PrepareForNewContentModel()
1553 : {
1554 0 : mEODForCurrentDocument = false;
1555 0 : return NS_OK;
1556 : }
1557 :
1558 :
1559 : NS_IMETHODIMP
1560 0 : nsDocShell::FirePageHideNotification(bool aIsUnload)
1561 : {
1562 0 : if (mContentViewer && !mFiredUnloadEvent) {
1563 : // Keep an explicit reference since calling PageHide could release
1564 : // mContentViewer
1565 0 : nsCOMPtr<nsIContentViewer> kungFuDeathGrip(mContentViewer);
1566 0 : mFiredUnloadEvent = true;
1567 :
1568 0 : if (mTiming) {
1569 0 : mTiming->NotifyUnloadEventStart();
1570 : }
1571 :
1572 0 : mContentViewer->PageHide(aIsUnload);
1573 :
1574 0 : if (mTiming) {
1575 0 : mTiming->NotifyUnloadEventEnd();
1576 : }
1577 :
1578 0 : nsAutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
1579 0 : PRInt32 i, n = mChildList.Count();
1580 0 : kids.SetCapacity(n);
1581 0 : for (i = 0; i < n; i++) {
1582 0 : kids.AppendElement(do_QueryInterface(ChildAt(i)));
1583 : }
1584 :
1585 0 : n = kids.Length();
1586 0 : for (i = 0; i < n; ++i) {
1587 0 : if (kids[i]) {
1588 0 : kids[i]->FirePageHideNotification(aIsUnload);
1589 : }
1590 : }
1591 : // Now make sure our editor, if any, is detached before we go
1592 : // any farther.
1593 0 : DetachEditorFromWindow();
1594 : }
1595 :
1596 0 : return NS_OK;
1597 : }
1598 :
1599 : nsresult
1600 0 : nsDocShell::MaybeInitTiming()
1601 : {
1602 0 : if (mTiming) {
1603 0 : return NS_OK;
1604 : }
1605 :
1606 0 : if (Preferences::GetBool("dom.enable_performance", false)) {
1607 0 : mTiming = new nsDOMNavigationTiming();
1608 0 : mTiming->NotifyNavigationStart();
1609 : }
1610 0 : return NS_OK;
1611 : }
1612 :
1613 :
1614 : //
1615 : // Bug 13871: Prevent frameset spoofing
1616 : //
1617 : // This routine answers: 'Is origin's document from same domain as
1618 : // target's document?'
1619 : //
1620 : // file: uris are considered the same domain for the purpose of
1621 : // frame navigation regardless of script accessibility (bug 420425)
1622 : //
1623 : /* static */
1624 : bool
1625 0 : nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
1626 : nsIDocShellTreeItem* aTargetTreeItem)
1627 : {
1628 : nsCOMPtr<nsIScriptSecurityManager> securityManager =
1629 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
1630 0 : NS_ENSURE_TRUE(securityManager, false);
1631 :
1632 0 : nsCOMPtr<nsIPrincipal> subjectPrincipal;
1633 : nsresult rv =
1634 0 : securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1635 0 : NS_ENSURE_SUCCESS(rv, false);
1636 :
1637 0 : if (subjectPrincipal) {
1638 : // We're called from JS, check if UniversalXPConnect is
1639 : // enabled.
1640 0 : bool ubwEnabled = false;
1641 0 : rv = securityManager->IsCapabilityEnabled("UniversalXPConnect",
1642 0 : &ubwEnabled);
1643 0 : NS_ENSURE_SUCCESS(rv, false);
1644 :
1645 0 : if (ubwEnabled) {
1646 0 : return true;
1647 : }
1648 : }
1649 :
1650 : // Get origin document principal
1651 0 : nsCOMPtr<nsIDocument> originDocument(do_GetInterface(aOriginTreeItem));
1652 0 : NS_ENSURE_TRUE(originDocument, false);
1653 :
1654 : // Get target principal
1655 0 : nsCOMPtr<nsIDocument> targetDocument(do_GetInterface(aTargetTreeItem));
1656 0 : NS_ENSURE_TRUE(targetDocument, false);
1657 :
1658 : bool equal;
1659 0 : rv = originDocument->NodePrincipal()->
1660 0 : Equals(targetDocument->NodePrincipal(), &equal);
1661 0 : if (NS_SUCCEEDED(rv) && equal) {
1662 0 : return true;
1663 : }
1664 :
1665 : // Not strictly equal, special case if both are file: uris
1666 0 : bool originIsFile = false;
1667 0 : bool targetIsFile = false;
1668 0 : nsCOMPtr<nsIURI> originURI;
1669 0 : nsCOMPtr<nsIURI> targetURI;
1670 0 : nsCOMPtr<nsIURI> innerOriginURI;
1671 0 : nsCOMPtr<nsIURI> innerTargetURI;
1672 :
1673 0 : rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
1674 0 : if (NS_SUCCEEDED(rv) && originURI)
1675 0 : innerOriginURI = NS_GetInnermostURI(originURI);
1676 :
1677 0 : rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
1678 0 : if (NS_SUCCEEDED(rv) && targetURI)
1679 0 : innerTargetURI = NS_GetInnermostURI(targetURI);
1680 :
1681 0 : return innerOriginURI && innerTargetURI &&
1682 0 : NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
1683 0 : NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
1684 0 : originIsFile && targetIsFile;
1685 : }
1686 :
1687 : NS_IMETHODIMP
1688 0 : nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
1689 : {
1690 0 : NS_ENSURE_ARG_POINTER(aPresContext);
1691 0 : *aPresContext = nsnull;
1692 :
1693 0 : nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
1694 0 : while (viewer) {
1695 0 : nsCOMPtr<nsIContentViewer> prevViewer;
1696 0 : viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
1697 0 : if (!prevViewer) {
1698 0 : return viewer->GetPresContext(aPresContext);
1699 : }
1700 0 : viewer = prevViewer;
1701 : }
1702 :
1703 0 : return NS_OK;
1704 : }
1705 :
1706 : NS_IMETHODIMP
1707 0 : nsDocShell::GetPresContext(nsPresContext ** aPresContext)
1708 : {
1709 0 : NS_ENSURE_ARG_POINTER(aPresContext);
1710 0 : *aPresContext = nsnull;
1711 :
1712 0 : if (!mContentViewer)
1713 0 : return NS_OK;
1714 :
1715 0 : return mContentViewer->GetPresContext(aPresContext);
1716 : }
1717 :
1718 : NS_IMETHODIMP
1719 0 : nsDocShell::GetPresShell(nsIPresShell ** aPresShell)
1720 : {
1721 0 : nsresult rv = NS_OK;
1722 :
1723 0 : NS_ENSURE_ARG_POINTER(aPresShell);
1724 0 : *aPresShell = nsnull;
1725 :
1726 0 : nsRefPtr<nsPresContext> presContext;
1727 0 : (void) GetPresContext(getter_AddRefs(presContext));
1728 :
1729 0 : if (presContext) {
1730 0 : NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
1731 : }
1732 :
1733 0 : return rv;
1734 : }
1735 :
1736 : NS_IMETHODIMP
1737 0 : nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
1738 : {
1739 0 : nsresult rv = NS_OK;
1740 :
1741 0 : NS_ENSURE_ARG_POINTER(aPresShell);
1742 0 : *aPresShell = nsnull;
1743 :
1744 0 : nsRefPtr<nsPresContext> presContext;
1745 0 : (void) GetEldestPresContext(getter_AddRefs(presContext));
1746 :
1747 0 : if (presContext) {
1748 0 : NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
1749 : }
1750 :
1751 0 : return rv;
1752 : }
1753 :
1754 : NS_IMETHODIMP
1755 0 : nsDocShell::GetContentViewer(nsIContentViewer ** aContentViewer)
1756 : {
1757 0 : NS_ENSURE_ARG_POINTER(aContentViewer);
1758 :
1759 0 : *aContentViewer = mContentViewer;
1760 0 : NS_IF_ADDREF(*aContentViewer);
1761 0 : return NS_OK;
1762 : }
1763 :
1764 : NS_IMETHODIMP
1765 0 : nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
1766 : {
1767 : // Weak reference. Don't addref.
1768 0 : mChromeEventHandler = aChromeEventHandler;
1769 :
1770 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
1771 0 : if (win) {
1772 0 : win->SetChromeEventHandler(aChromeEventHandler);
1773 : }
1774 :
1775 0 : return NS_OK;
1776 : }
1777 :
1778 : NS_IMETHODIMP
1779 0 : nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
1780 : {
1781 0 : NS_ENSURE_ARG_POINTER(aChromeEventHandler);
1782 0 : nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mChromeEventHandler);
1783 0 : target.swap(*aChromeEventHandler);
1784 0 : return NS_OK;
1785 : }
1786 :
1787 : /* void setCurrentURI (in nsIURI uri); */
1788 : NS_IMETHODIMP
1789 0 : nsDocShell::SetCurrentURI(nsIURI *aURI)
1790 : {
1791 : // Note that securityUI will set STATE_IS_INSECURE, even if
1792 : // the scheme of |aURI| is "https".
1793 0 : SetCurrentURI(aURI, nsnull, true, 0);
1794 0 : return NS_OK;
1795 : }
1796 :
1797 : bool
1798 0 : nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
1799 : bool aFireOnLocationChange, PRUint32 aLocationFlags)
1800 : {
1801 : #ifdef PR_LOGGING
1802 0 : if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
1803 0 : nsCAutoString spec;
1804 0 : if (aURI)
1805 0 : aURI->GetSpec(spec);
1806 0 : PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
1807 : }
1808 : #endif
1809 :
1810 : // We don't want to send a location change when we're displaying an error
1811 : // page, and we don't want to change our idea of "current URI" either
1812 0 : if (mLoadType == LOAD_ERROR_PAGE) {
1813 0 : return false;
1814 : }
1815 :
1816 0 : mCurrentURI = NS_TryToMakeImmutable(aURI);
1817 :
1818 0 : bool isRoot = false; // Is this the root docshell
1819 0 : bool isSubFrame = false; // Is this a subframe navigation?
1820 :
1821 0 : nsCOMPtr<nsIDocShellTreeItem> root;
1822 :
1823 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
1824 0 : if (root.get() == static_cast<nsIDocShellTreeItem *>(this))
1825 : {
1826 : // This is the root docshell
1827 0 : isRoot = true;
1828 : }
1829 0 : if (mLSHE) {
1830 0 : mLSHE->GetIsSubFrame(&isSubFrame);
1831 : }
1832 :
1833 0 : if (!isSubFrame && !isRoot) {
1834 : /*
1835 : * We don't want to send OnLocationChange notifications when
1836 : * a subframe is being loaded for the first time, while
1837 : * visiting a frameset page
1838 : */
1839 0 : return false;
1840 : }
1841 :
1842 0 : if (aFireOnLocationChange) {
1843 0 : FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
1844 : }
1845 0 : return !aFireOnLocationChange;
1846 : }
1847 :
1848 : NS_IMETHODIMP
1849 0 : nsDocShell::GetCharset(char** aCharset)
1850 : {
1851 0 : NS_ENSURE_ARG_POINTER(aCharset);
1852 0 : *aCharset = nsnull;
1853 :
1854 0 : nsCOMPtr<nsIPresShell> presShell;
1855 0 : GetPresShell(getter_AddRefs(presShell));
1856 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
1857 0 : nsIDocument *doc = presShell->GetDocument();
1858 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
1859 0 : *aCharset = ToNewCString(doc->GetDocumentCharacterSet());
1860 0 : if (!*aCharset) {
1861 0 : return NS_ERROR_OUT_OF_MEMORY;
1862 : }
1863 :
1864 0 : return NS_OK;
1865 : }
1866 :
1867 : NS_IMETHODIMP
1868 0 : nsDocShell::SetCharset(const char* aCharset)
1869 : {
1870 : // set the default charset
1871 0 : nsCOMPtr<nsIContentViewer> viewer;
1872 0 : GetContentViewer(getter_AddRefs(viewer));
1873 0 : if (viewer) {
1874 0 : nsCOMPtr<nsIMarkupDocumentViewer> muDV(do_QueryInterface(viewer));
1875 0 : if (muDV) {
1876 0 : nsCString charset(aCharset);
1877 0 : NS_ENSURE_SUCCESS(muDV->SetDefaultCharacterSet(charset),
1878 : NS_ERROR_FAILURE);
1879 : }
1880 : }
1881 :
1882 : // set the charset override
1883 0 : nsCOMPtr<nsIAtom> csAtom = do_GetAtom(aCharset);
1884 0 : SetForcedCharset(csAtom);
1885 :
1886 0 : return NS_OK;
1887 : }
1888 :
1889 0 : NS_IMETHODIMP nsDocShell::SetForcedCharset(nsIAtom * aCharset)
1890 : {
1891 0 : mForcedCharset = aCharset;
1892 0 : return NS_OK;
1893 : }
1894 :
1895 0 : NS_IMETHODIMP nsDocShell::GetForcedCharset(nsIAtom ** aResult)
1896 : {
1897 0 : *aResult = mForcedCharset;
1898 0 : if (mForcedCharset) NS_ADDREF(*aResult);
1899 0 : return NS_OK;
1900 : }
1901 :
1902 0 : NS_IMETHODIMP nsDocShell::SetParentCharset(nsIAtom * aCharset)
1903 : {
1904 0 : mParentCharset = aCharset;
1905 0 : return NS_OK;
1906 : }
1907 :
1908 0 : NS_IMETHODIMP nsDocShell::GetParentCharset(nsIAtom ** aResult)
1909 : {
1910 0 : *aResult = mParentCharset;
1911 0 : if (mParentCharset) NS_ADDREF(*aResult);
1912 0 : return NS_OK;
1913 : }
1914 :
1915 0 : NS_IMETHODIMP nsDocShell::SetParentCharsetSource(PRInt32 aCharsetSource)
1916 : {
1917 0 : mParentCharsetSource = aCharsetSource;
1918 0 : return NS_OK;
1919 : }
1920 :
1921 0 : NS_IMETHODIMP nsDocShell::GetParentCharsetSource(PRInt32 * aParentCharsetSource)
1922 : {
1923 0 : *aParentCharsetSource = mParentCharsetSource;
1924 0 : return NS_OK;
1925 : }
1926 :
1927 : NS_IMETHODIMP
1928 0 : nsDocShell::GetChannelIsUnsafe(bool *aUnsafe)
1929 : {
1930 0 : *aUnsafe = false;
1931 :
1932 0 : nsIChannel* channel = GetCurrentDocChannel();
1933 0 : if (!channel) {
1934 0 : return NS_OK;
1935 : }
1936 :
1937 0 : nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
1938 0 : if (!jarChannel) {
1939 0 : return NS_OK;
1940 : }
1941 :
1942 0 : return jarChannel->GetIsUnsafe(aUnsafe);
1943 : }
1944 :
1945 : NS_IMETHODIMP
1946 0 : nsDocShell::GetAllowPlugins(bool * aAllowPlugins)
1947 : {
1948 0 : NS_ENSURE_ARG_POINTER(aAllowPlugins);
1949 :
1950 0 : *aAllowPlugins = mAllowPlugins;
1951 0 : if (!mAllowPlugins) {
1952 0 : return NS_OK;
1953 : }
1954 :
1955 : bool unsafe;
1956 0 : *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
1957 0 : return NS_OK;
1958 : }
1959 :
1960 : NS_IMETHODIMP
1961 0 : nsDocShell::SetAllowPlugins(bool aAllowPlugins)
1962 : {
1963 0 : mAllowPlugins = aAllowPlugins;
1964 : //XXX should enable or disable a plugin host
1965 0 : return NS_OK;
1966 : }
1967 :
1968 : NS_IMETHODIMP
1969 0 : nsDocShell::GetAllowJavascript(bool * aAllowJavascript)
1970 : {
1971 0 : NS_ENSURE_ARG_POINTER(aAllowJavascript);
1972 :
1973 0 : *aAllowJavascript = mAllowJavascript;
1974 0 : if (!mAllowJavascript) {
1975 0 : return NS_OK;
1976 : }
1977 :
1978 : bool unsafe;
1979 0 : *aAllowJavascript = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
1980 0 : return NS_OK;
1981 : }
1982 :
1983 : NS_IMETHODIMP
1984 0 : nsDocShell::SetAllowJavascript(bool aAllowJavascript)
1985 : {
1986 0 : mAllowJavascript = aAllowJavascript;
1987 0 : return NS_OK;
1988 : }
1989 :
1990 : NS_IMETHODIMP
1991 0 : nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
1992 : {
1993 0 : NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
1994 :
1995 0 : *aUsePrivateBrowsing = mInPrivateBrowsing;
1996 0 : return NS_OK;
1997 : }
1998 :
1999 : NS_IMETHODIMP
2000 0 : nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
2001 : {
2002 0 : mInPrivateBrowsing = aUsePrivateBrowsing;
2003 :
2004 0 : PRInt32 count = mChildList.Count();
2005 0 : for (PRInt32 i = 0; i < count; ++i) {
2006 0 : nsCOMPtr<nsILoadContext> shell = do_QueryInterface(ChildAt(i));
2007 0 : if (shell) {
2008 0 : shell->SetUsePrivateBrowsing(aUsePrivateBrowsing);
2009 : }
2010 : }
2011 0 : return NS_OK;
2012 : }
2013 :
2014 0 : NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(bool * aReturn)
2015 : {
2016 0 : NS_ENSURE_ARG_POINTER(aReturn);
2017 :
2018 0 : *aReturn = mAllowMetaRedirects;
2019 0 : if (!mAllowMetaRedirects) {
2020 0 : return NS_OK;
2021 : }
2022 :
2023 : bool unsafe;
2024 0 : *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
2025 0 : return NS_OK;
2026 : }
2027 :
2028 0 : NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(bool aValue)
2029 : {
2030 0 : mAllowMetaRedirects = aValue;
2031 0 : return NS_OK;
2032 : }
2033 :
2034 0 : NS_IMETHODIMP nsDocShell::GetAllowSubframes(bool * aAllowSubframes)
2035 : {
2036 0 : NS_ENSURE_ARG_POINTER(aAllowSubframes);
2037 :
2038 0 : *aAllowSubframes = mAllowSubframes;
2039 0 : return NS_OK;
2040 : }
2041 :
2042 0 : NS_IMETHODIMP nsDocShell::SetAllowSubframes(bool aAllowSubframes)
2043 : {
2044 0 : mAllowSubframes = aAllowSubframes;
2045 0 : return NS_OK;
2046 : }
2047 :
2048 0 : NS_IMETHODIMP nsDocShell::GetAllowImages(bool * aAllowImages)
2049 : {
2050 0 : NS_ENSURE_ARG_POINTER(aAllowImages);
2051 :
2052 0 : *aAllowImages = mAllowImages;
2053 0 : return NS_OK;
2054 : }
2055 :
2056 0 : NS_IMETHODIMP nsDocShell::SetAllowImages(bool aAllowImages)
2057 : {
2058 0 : mAllowImages = aAllowImages;
2059 0 : return NS_OK;
2060 : }
2061 :
2062 0 : NS_IMETHODIMP nsDocShell::GetAllowDNSPrefetch(bool * aAllowDNSPrefetch)
2063 : {
2064 0 : *aAllowDNSPrefetch = mAllowDNSPrefetch;
2065 0 : return NS_OK;
2066 : }
2067 :
2068 0 : NS_IMETHODIMP nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
2069 : {
2070 0 : mAllowDNSPrefetch = aAllowDNSPrefetch;
2071 0 : return NS_OK;
2072 : }
2073 :
2074 0 : NS_IMETHODIMP nsDocShell::GetAllowWindowControl(bool * aAllowWindowControl)
2075 : {
2076 0 : *aAllowWindowControl = mAllowWindowControl;
2077 0 : return NS_OK;
2078 : }
2079 :
2080 0 : NS_IMETHODIMP nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
2081 : {
2082 0 : mAllowWindowControl = aAllowWindowControl;
2083 0 : return NS_OK;
2084 : }
2085 :
2086 : NS_IMETHODIMP
2087 0 : nsDocShell::GetDocShellEnumerator(PRInt32 aItemType, PRInt32 aDirection, nsISimpleEnumerator **outEnum)
2088 : {
2089 0 : NS_ENSURE_ARG_POINTER(outEnum);
2090 0 : *outEnum = nsnull;
2091 :
2092 0 : nsRefPtr<nsDocShellEnumerator> docShellEnum;
2093 0 : if (aDirection == ENUMERATE_FORWARDS)
2094 0 : docShellEnum = new nsDocShellForwardsEnumerator;
2095 : else
2096 0 : docShellEnum = new nsDocShellBackwardsEnumerator;
2097 :
2098 0 : if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY;
2099 :
2100 0 : nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
2101 0 : if (NS_FAILED(rv)) return rv;
2102 :
2103 0 : rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this);
2104 0 : if (NS_FAILED(rv)) return rv;
2105 :
2106 0 : rv = docShellEnum->First();
2107 0 : if (NS_FAILED(rv)) return rv;
2108 :
2109 0 : rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum);
2110 :
2111 0 : return rv;
2112 : }
2113 :
2114 : NS_IMETHODIMP
2115 0 : nsDocShell::GetAppType(PRUint32 * aAppType)
2116 : {
2117 0 : *aAppType = mAppType;
2118 0 : return NS_OK;
2119 : }
2120 :
2121 : NS_IMETHODIMP
2122 0 : nsDocShell::SetAppType(PRUint32 aAppType)
2123 : {
2124 0 : mAppType = aAppType;
2125 0 : return NS_OK;
2126 : }
2127 :
2128 :
2129 : NS_IMETHODIMP
2130 0 : nsDocShell::GetAllowAuth(bool * aAllowAuth)
2131 : {
2132 0 : *aAllowAuth = mAllowAuth;
2133 0 : return NS_OK;
2134 : }
2135 :
2136 : NS_IMETHODIMP
2137 0 : nsDocShell::SetAllowAuth(bool aAllowAuth)
2138 : {
2139 0 : mAllowAuth = aAllowAuth;
2140 0 : return NS_OK;
2141 : }
2142 :
2143 : NS_IMETHODIMP
2144 0 : nsDocShell::GetZoom(float *zoom)
2145 : {
2146 0 : NS_ENSURE_ARG_POINTER(zoom);
2147 0 : *zoom = 1.0f;
2148 0 : return NS_OK;
2149 : }
2150 :
2151 : NS_IMETHODIMP
2152 0 : nsDocShell::SetZoom(float zoom)
2153 : {
2154 0 : return NS_ERROR_NOT_IMPLEMENTED;
2155 : }
2156 :
2157 : NS_IMETHODIMP
2158 0 : nsDocShell::GetMarginWidth(PRInt32 * aWidth)
2159 : {
2160 0 : NS_ENSURE_ARG_POINTER(aWidth);
2161 :
2162 0 : *aWidth = mMarginWidth;
2163 0 : return NS_OK;
2164 : }
2165 :
2166 : NS_IMETHODIMP
2167 0 : nsDocShell::SetMarginWidth(PRInt32 aWidth)
2168 : {
2169 0 : mMarginWidth = aWidth;
2170 0 : return NS_OK;
2171 : }
2172 :
2173 : NS_IMETHODIMP
2174 0 : nsDocShell::GetMarginHeight(PRInt32 * aHeight)
2175 : {
2176 0 : NS_ENSURE_ARG_POINTER(aHeight);
2177 :
2178 0 : *aHeight = mMarginHeight;
2179 0 : return NS_OK;
2180 : }
2181 :
2182 : NS_IMETHODIMP
2183 0 : nsDocShell::SetMarginHeight(PRInt32 aHeight)
2184 : {
2185 0 : mMarginHeight = aHeight;
2186 0 : return NS_OK;
2187 : }
2188 :
2189 : NS_IMETHODIMP
2190 0 : nsDocShell::GetBusyFlags(PRUint32 * aBusyFlags)
2191 : {
2192 0 : NS_ENSURE_ARG_POINTER(aBusyFlags);
2193 :
2194 0 : *aBusyFlags = mBusyFlags;
2195 0 : return NS_OK;
2196 : }
2197 :
2198 : NS_IMETHODIMP
2199 0 : nsDocShell::TabToTreeOwner(bool aForward, bool* aTookFocus)
2200 : {
2201 0 : NS_ENSURE_ARG_POINTER(aTookFocus);
2202 :
2203 0 : nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
2204 0 : if (chromeFocus) {
2205 0 : if (aForward)
2206 0 : *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement());
2207 : else
2208 0 : *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement());
2209 : } else
2210 0 : *aTookFocus = false;
2211 :
2212 0 : return NS_OK;
2213 : }
2214 :
2215 : NS_IMETHODIMP
2216 0 : nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI)
2217 : {
2218 0 : NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
2219 0 : return NS_OK;
2220 : }
2221 :
2222 : NS_IMETHODIMP
2223 0 : nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI)
2224 : {
2225 0 : mSecurityUI = aSecurityUI;
2226 0 : return NS_OK;
2227 : }
2228 :
2229 : NS_IMETHODIMP
2230 0 : nsDocShell::GetUseErrorPages(bool *aUseErrorPages)
2231 : {
2232 0 : *aUseErrorPages = mUseErrorPages;
2233 0 : return NS_OK;
2234 : }
2235 :
2236 : NS_IMETHODIMP
2237 0 : nsDocShell::SetUseErrorPages(bool aUseErrorPages)
2238 : {
2239 : // If mUseErrorPages is set explicitly, stop observing the pref.
2240 0 : if (mObserveErrorPages) {
2241 0 : Preferences::RemoveObserver(this, "browser.xul.error_pages.enabled");
2242 0 : mObserveErrorPages = false;
2243 : }
2244 0 : mUseErrorPages = aUseErrorPages;
2245 0 : return NS_OK;
2246 : }
2247 :
2248 : NS_IMETHODIMP
2249 0 : nsDocShell::GetPreviousTransIndex(PRInt32 *aPreviousTransIndex)
2250 : {
2251 0 : *aPreviousTransIndex = mPreviousTransIndex;
2252 0 : return NS_OK;
2253 : }
2254 :
2255 : NS_IMETHODIMP
2256 0 : nsDocShell::GetLoadedTransIndex(PRInt32 *aLoadedTransIndex)
2257 : {
2258 0 : *aLoadedTransIndex = mLoadedTransIndex;
2259 0 : return NS_OK;
2260 : }
2261 :
2262 : NS_IMETHODIMP
2263 0 : nsDocShell::HistoryPurged(PRInt32 aNumEntries)
2264 : {
2265 : // These indices are used for fastback cache eviction, to determine
2266 : // which session history entries are candidates for content viewer
2267 : // eviction. We need to adjust by the number of entries that we
2268 : // just purged from history, so that we look at the right session history
2269 : // entries during eviction.
2270 0 : mPreviousTransIndex = NS_MAX(-1, mPreviousTransIndex - aNumEntries);
2271 0 : mLoadedTransIndex = NS_MAX(0, mLoadedTransIndex - aNumEntries);
2272 :
2273 0 : PRInt32 count = mChildList.Count();
2274 0 : for (PRInt32 i = 0; i < count; ++i) {
2275 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
2276 0 : if (shell) {
2277 0 : shell->HistoryPurged(aNumEntries);
2278 : }
2279 : }
2280 :
2281 0 : return NS_OK;
2282 : }
2283 :
2284 : nsresult
2285 0 : nsDocShell::HistoryTransactionRemoved(PRInt32 aIndex)
2286 : {
2287 : // These indices are used for fastback cache eviction, to determine
2288 : // which session history entries are candidates for content viewer
2289 : // eviction. We need to adjust by the number of entries that we
2290 : // just purged from history, so that we look at the right session history
2291 : // entries during eviction.
2292 0 : if (aIndex == mPreviousTransIndex) {
2293 0 : mPreviousTransIndex = -1;
2294 0 : } else if (aIndex < mPreviousTransIndex) {
2295 0 : --mPreviousTransIndex;
2296 : }
2297 0 : if (mLoadedTransIndex == aIndex) {
2298 0 : mLoadedTransIndex = 0;
2299 0 : } else if (aIndex < mLoadedTransIndex) {
2300 0 : --mLoadedTransIndex;
2301 : }
2302 :
2303 0 : PRInt32 count = mChildList.Count();
2304 0 : for (PRInt32 i = 0; i < count; ++i) {
2305 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
2306 0 : if (shell) {
2307 0 : static_cast<nsDocShell*>(shell.get())->
2308 0 : HistoryTransactionRemoved(aIndex);
2309 : }
2310 : }
2311 :
2312 0 : return NS_OK;
2313 : }
2314 :
2315 : NS_IMETHODIMP
2316 0 : nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
2317 : const nsAString& aDocumentURI,
2318 : bool aCreate,
2319 : nsIDOMStorage** aStorage)
2320 : {
2321 0 : NS_ENSURE_ARG_POINTER(aStorage);
2322 0 : *aStorage = nsnull;
2323 :
2324 0 : if (!aPrincipal)
2325 0 : return NS_OK;
2326 :
2327 : nsresult rv;
2328 :
2329 0 : nsCOMPtr<nsIDocShellTreeItem> topItem;
2330 0 : rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
2331 0 : if (NS_FAILED(rv))
2332 0 : return rv;
2333 :
2334 0 : if (!topItem)
2335 0 : return NS_ERROR_FAILURE;
2336 :
2337 0 : nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
2338 0 : if (topDocShell != this)
2339 : return topDocShell->GetSessionStorageForPrincipal(aPrincipal,
2340 : aDocumentURI,
2341 : aCreate,
2342 0 : aStorage);
2343 :
2344 0 : nsXPIDLCString origin;
2345 0 : rv = aPrincipal->GetOrigin(getter_Copies(origin));
2346 0 : if (NS_FAILED(rv))
2347 0 : return rv;
2348 :
2349 0 : if (origin.IsEmpty())
2350 0 : return NS_OK;
2351 :
2352 0 : if (!mStorages.Get(origin, aStorage) && aCreate) {
2353 : nsCOMPtr<nsIDOMStorage> newstorage =
2354 0 : do_CreateInstance("@mozilla.org/dom/storage;2");
2355 0 : if (!newstorage)
2356 0 : return NS_ERROR_OUT_OF_MEMORY;
2357 :
2358 0 : nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
2359 0 : if (!pistorage)
2360 0 : return NS_ERROR_FAILURE;
2361 :
2362 0 : rv = pistorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
2363 0 : if (NS_FAILED(rv))
2364 0 : return rv;
2365 :
2366 0 : if (!mStorages.Put(origin, newstorage))
2367 0 : return NS_ERROR_OUT_OF_MEMORY;
2368 :
2369 0 : newstorage.swap(*aStorage);
2370 : #if defined(PR_LOGGING) && defined(DEBUG)
2371 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
2372 : ("nsDocShell[%p]: created a new sessionStorage %p",
2373 : this, *aStorage));
2374 : #endif
2375 : }
2376 0 : else if (*aStorage) {
2377 0 : nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
2378 0 : if (piStorage) {
2379 0 : nsCOMPtr<nsIPrincipal> storagePrincipal = piStorage->Principal();
2380 :
2381 : // The origin string used to map items in the hash table is
2382 : // an implicit security check. That check is double-confirmed
2383 : // by checking the principal a storage was demanded for
2384 : // really is the principal for which that storage was originally
2385 : // created. Originally, the check was hidden in the CanAccess
2386 : // method but it's implementation has changed.
2387 : bool equals;
2388 0 : nsresult rv = aPrincipal->EqualsIgnoringDomain(storagePrincipal, &equals);
2389 0 : NS_ASSERTION(NS_SUCCEEDED(rv) && equals,
2390 : "GetSessionStorageForPrincipal got a storage "
2391 : "that could not be accessed!");
2392 :
2393 0 : if (NS_FAILED(rv) || !equals) {
2394 0 : NS_RELEASE(*aStorage);
2395 0 : return NS_ERROR_DOM_SECURITY_ERR;
2396 : }
2397 : }
2398 :
2399 : #if defined(PR_LOGGING) && defined(DEBUG)
2400 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
2401 : ("nsDocShell[%p]: returns existing sessionStorage %p",
2402 : this, *aStorage));
2403 : #endif
2404 : }
2405 :
2406 0 : if (aCreate) {
2407 : // We are asked to create a new storage object. This indicates
2408 : // that a new windows wants it. At this moment we "fork" the existing
2409 : // storage object (what it means is described in the paragraph bellow).
2410 : // We must create a single object per a single window to distinguish
2411 : // a window originating oparations on the storage object to succesfully
2412 : // prevent dispatch of a storage event to this same window that ivoked
2413 : // a change in its storage. We also do this to correctly fill
2414 : // documentURI property in the storage event.
2415 : //
2416 : // The difference between clone and fork is that clone creates
2417 : // a completelly new and independent storage, but fork only creates
2418 : // a new object wrapping the storage implementation and data and
2419 : // the forked storage then behaves completelly the same way as
2420 : // the storage it has been forked of, all such forked storage objects
2421 : // shares their state and data and change on one such object affects
2422 : // all others the same way.
2423 0 : nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
2424 0 : nsCOMPtr<nsIDOMStorage> fork = piStorage->Fork(aDocumentURI);
2425 : #if defined(PR_LOGGING) && defined(DEBUG)
2426 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
2427 : ("nsDocShell[%p]: forked sessionStorage %p to %p",
2428 : this, *aStorage, fork.get()));
2429 : #endif
2430 0 : fork.swap(*aStorage);
2431 : }
2432 :
2433 0 : return NS_OK;
2434 : }
2435 :
2436 : NS_IMETHODIMP
2437 0 : nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
2438 : const nsAString& aDocumentURI,
2439 : nsIDOMStorage** aStorage)
2440 : {
2441 0 : return GetSessionStorageForURI(aURI, aDocumentURI, true, aStorage);
2442 : }
2443 :
2444 : nsresult
2445 0 : nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
2446 : const nsSubstring& aDocumentURI,
2447 : bool aCreate,
2448 : nsIDOMStorage** aStorage)
2449 : {
2450 0 : NS_ENSURE_ARG(aURI);
2451 0 : NS_ENSURE_ARG_POINTER(aStorage);
2452 :
2453 0 : *aStorage = nsnull;
2454 :
2455 : nsresult rv;
2456 :
2457 : nsCOMPtr<nsIScriptSecurityManager> securityManager =
2458 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
2459 0 : NS_ENSURE_SUCCESS(rv, rv);
2460 :
2461 : // This is terrible hack and should go away along with this whole method.
2462 0 : nsCOMPtr<nsIPrincipal> principal;
2463 0 : rv = securityManager->GetCodebasePrincipal(aURI, getter_AddRefs(principal));
2464 0 : if (NS_FAILED(rv))
2465 0 : return rv;
2466 :
2467 0 : return GetSessionStorageForPrincipal(principal, aDocumentURI, aCreate, aStorage);
2468 : }
2469 :
2470 : nsresult
2471 0 : nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
2472 : nsIDOMStorage* aStorage)
2473 : {
2474 0 : NS_ENSURE_ARG_POINTER(aStorage);
2475 :
2476 0 : if (!aPrincipal)
2477 0 : return NS_OK;
2478 :
2479 0 : nsCOMPtr<nsIDocShellTreeItem> topItem;
2480 0 : nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
2481 0 : if (NS_FAILED(rv))
2482 0 : return rv;
2483 :
2484 0 : if (topItem) {
2485 0 : nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
2486 0 : if (topDocShell == this) {
2487 0 : nsXPIDLCString origin;
2488 0 : rv = aPrincipal->GetOrigin(getter_Copies(origin));
2489 0 : if (NS_FAILED(rv))
2490 0 : return rv;
2491 :
2492 0 : if (origin.IsEmpty())
2493 0 : return NS_ERROR_FAILURE;
2494 :
2495 : // Do not replace an existing session storage.
2496 0 : if (mStorages.GetWeak(origin))
2497 0 : return NS_ERROR_NOT_AVAILABLE;
2498 :
2499 : #if defined(PR_LOGGING) && defined(DEBUG)
2500 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
2501 : ("nsDocShell[%p]: was added a sessionStorage %p",
2502 : this, aStorage));
2503 : #endif
2504 0 : if (!mStorages.Put(origin, aStorage))
2505 0 : return NS_ERROR_OUT_OF_MEMORY;
2506 : }
2507 : else {
2508 0 : return topDocShell->AddSessionStorage(aPrincipal, aStorage);
2509 : }
2510 : }
2511 :
2512 0 : return NS_OK;
2513 : }
2514 :
2515 : NS_IMETHODIMP
2516 0 : nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
2517 : {
2518 0 : NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
2519 0 : return NS_OK;
2520 : }
2521 :
2522 : nsIChannel*
2523 0 : nsDocShell::GetCurrentDocChannel()
2524 : {
2525 0 : if (mContentViewer) {
2526 0 : nsIDocument* doc = mContentViewer->GetDocument();
2527 0 : if (doc) {
2528 0 : return doc->GetChannel();
2529 : }
2530 : }
2531 0 : return nsnull;
2532 : }
2533 :
2534 : //*****************************************************************************
2535 : // nsDocShell::nsIDocShellTreeItem
2536 : //*****************************************************************************
2537 :
2538 : NS_IMETHODIMP
2539 0 : nsDocShell::GetName(PRUnichar ** aName)
2540 : {
2541 0 : NS_ENSURE_ARG_POINTER(aName);
2542 0 : *aName = ToNewUnicode(mName);
2543 0 : return NS_OK;
2544 : }
2545 :
2546 : NS_IMETHODIMP
2547 0 : nsDocShell::SetName(const PRUnichar * aName)
2548 : {
2549 0 : mName = aName; // this does a copy of aName
2550 0 : return NS_OK;
2551 : }
2552 :
2553 : NS_IMETHODIMP
2554 0 : nsDocShell::NameEquals(const PRUnichar *aName, bool *_retval)
2555 : {
2556 0 : NS_ENSURE_ARG_POINTER(aName);
2557 0 : NS_ENSURE_ARG_POINTER(_retval);
2558 0 : *_retval = mName.Equals(aName);
2559 0 : return NS_OK;
2560 : }
2561 :
2562 : NS_IMETHODIMP
2563 0 : nsDocShell::GetItemType(PRInt32 * aItemType)
2564 : {
2565 0 : NS_ENSURE_ARG_POINTER(aItemType);
2566 :
2567 0 : *aItemType = mItemType;
2568 0 : return NS_OK;
2569 : }
2570 :
2571 : NS_IMETHODIMP
2572 0 : nsDocShell::SetItemType(PRInt32 aItemType)
2573 : {
2574 0 : NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
2575 :
2576 : // Only allow setting the type on root docshells. Those would be the ones
2577 : // that have the docloader service as mParent or have no mParent at all.
2578 : nsCOMPtr<nsIDocumentLoader> docLoaderService =
2579 0 : do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
2580 0 : NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
2581 :
2582 0 : NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
2583 :
2584 0 : mItemType = aItemType;
2585 :
2586 : // disable auth prompting for anything but content
2587 0 : mAllowAuth = mItemType == typeContent;
2588 :
2589 0 : nsRefPtr<nsPresContext> presContext = nsnull;
2590 0 : GetPresContext(getter_AddRefs(presContext));
2591 0 : if (presContext) {
2592 0 : presContext->InvalidateIsChromeCache();
2593 : }
2594 :
2595 0 : return NS_OK;
2596 : }
2597 :
2598 : NS_IMETHODIMP
2599 0 : nsDocShell::GetParent(nsIDocShellTreeItem ** aParent)
2600 : {
2601 0 : if (!mParent) {
2602 0 : *aParent = nsnull;
2603 : } else {
2604 0 : CallQueryInterface(mParent, aParent);
2605 : }
2606 : // Note that in the case when the parent is not an nsIDocShellTreeItem we
2607 : // don't want to throw; we just want to return null.
2608 0 : return NS_OK;
2609 : }
2610 :
2611 : nsresult
2612 0 : nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
2613 : {
2614 0 : nsDocLoader::SetDocLoaderParent(aParent);
2615 :
2616 : // Curse ambiguous nsISupports inheritance!
2617 0 : nsISupports* parent = GetAsSupports(aParent);
2618 :
2619 : // If parent is another docshell, we inherit all their flags for
2620 : // allowing plugins, scripting etc.
2621 : bool value;
2622 0 : nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
2623 0 : if (parentAsDocShell)
2624 : {
2625 0 : if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value)))
2626 : {
2627 0 : SetAllowPlugins(value);
2628 : }
2629 0 : if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value)))
2630 : {
2631 0 : SetAllowJavascript(value);
2632 : }
2633 0 : if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value)))
2634 : {
2635 0 : SetAllowMetaRedirects(value);
2636 : }
2637 0 : if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value)))
2638 : {
2639 0 : SetAllowSubframes(value);
2640 : }
2641 0 : if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value)))
2642 : {
2643 0 : SetAllowImages(value);
2644 : }
2645 0 : if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value)))
2646 : {
2647 0 : SetAllowWindowControl(value);
2648 : }
2649 0 : if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value)))
2650 : {
2651 0 : SetIsActive(value);
2652 : }
2653 0 : if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
2654 0 : value = false;
2655 : }
2656 0 : SetAllowDNSPrefetch(value);
2657 : }
2658 0 : nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
2659 0 : if (parentAsLoadContext &&
2660 0 : NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value)))
2661 : {
2662 0 : SetUsePrivateBrowsing(value);
2663 : }
2664 :
2665 0 : nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
2666 0 : if (parentURIListener)
2667 0 : mContentListener->SetParentContentListener(parentURIListener);
2668 0 : return NS_OK;
2669 : }
2670 :
2671 : NS_IMETHODIMP
2672 0 : nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
2673 : {
2674 0 : NS_ENSURE_ARG_POINTER(aParent);
2675 0 : *aParent = nsnull;
2676 :
2677 : nsCOMPtr<nsIDocShellTreeItem> parent =
2678 0 : do_QueryInterface(GetAsSupports(mParent));
2679 0 : if (!parent)
2680 0 : return NS_OK;
2681 :
2682 : PRInt32 parentType;
2683 0 : NS_ENSURE_SUCCESS(parent->GetItemType(&parentType), NS_ERROR_FAILURE);
2684 :
2685 0 : if (parentType == mItemType) {
2686 0 : parent.swap(*aParent);
2687 : }
2688 0 : return NS_OK;
2689 : }
2690 :
2691 : NS_IMETHODIMP
2692 0 : nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
2693 : {
2694 0 : NS_ENSURE_ARG_POINTER(aRootTreeItem);
2695 0 : *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
2696 :
2697 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
2698 0 : NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE);
2699 0 : while (parent) {
2700 0 : *aRootTreeItem = parent;
2701 0 : NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)),
2702 : NS_ERROR_FAILURE);
2703 : }
2704 0 : NS_ADDREF(*aRootTreeItem);
2705 0 : return NS_OK;
2706 : }
2707 :
2708 : NS_IMETHODIMP
2709 0 : nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem)
2710 : {
2711 0 : NS_ENSURE_ARG_POINTER(aRootTreeItem);
2712 0 : *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this);
2713 :
2714 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
2715 0 : NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
2716 : NS_ERROR_FAILURE);
2717 0 : while (parent) {
2718 0 : *aRootTreeItem = parent;
2719 0 : NS_ENSURE_SUCCESS((*aRootTreeItem)->
2720 : GetSameTypeParent(getter_AddRefs(parent)),
2721 : NS_ERROR_FAILURE);
2722 : }
2723 0 : NS_ADDREF(*aRootTreeItem);
2724 0 : return NS_OK;
2725 : }
2726 :
2727 : /* static */
2728 : bool
2729 0 : nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
2730 : nsIDocShellTreeItem* aAccessingItem,
2731 : bool aConsiderOpener)
2732 : {
2733 0 : NS_PRECONDITION(aTargetItem, "Must have target item!");
2734 :
2735 0 : if (!gValidateOrigin || !aAccessingItem) {
2736 : // Good to go
2737 0 : return true;
2738 : }
2739 :
2740 : // XXXbz should we care if aAccessingItem or the document therein is
2741 : // chrome? Should those get extra privileges?
2742 :
2743 : // For historical context, see:
2744 : //
2745 : // Bug 13871: Prevent frameset spoofing
2746 : // Bug 103638: Targets with same name in different windows open in wrong
2747 : // window with javascript
2748 : // Bug 408052: Adopt "ancestor" frame navigation policy
2749 :
2750 : // Now do a security check
2751 : //
2752 : // Allow navigation if
2753 : // 1) aAccessingItem can script aTargetItem or one of its ancestors in
2754 : // the frame hierarchy or
2755 : // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
2756 : // 3) aTargetItem is a top-level frame and aAccessingItem can target
2757 : // its opener per rule (1) or (2).
2758 :
2759 0 : if (aTargetItem == aAccessingItem) {
2760 : // A frame is allowed to navigate itself.
2761 0 : return true;
2762 : }
2763 :
2764 0 : nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
2765 0 : aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
2766 :
2767 0 : if (aTargetItem == accessingRoot) {
2768 : // A frame can navigate its root.
2769 0 : return true;
2770 : }
2771 :
2772 : // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
2773 0 : nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
2774 0 : do {
2775 0 : if (ValidateOrigin(aAccessingItem, target)) {
2776 0 : return true;
2777 : }
2778 :
2779 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
2780 0 : target->GetSameTypeParent(getter_AddRefs(parent));
2781 0 : parent.swap(target);
2782 0 : } while (target);
2783 :
2784 0 : nsCOMPtr<nsIDocShellTreeItem> targetRoot;
2785 0 : aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
2786 :
2787 0 : if (aTargetItem != targetRoot) {
2788 : // target is a subframe, not in accessor's frame hierarchy, and all its
2789 : // ancestors have origins different from that of the accessor. Don't
2790 : // allow access.
2791 0 : return false;
2792 : }
2793 :
2794 0 : if (!aConsiderOpener) {
2795 : // All done here
2796 0 : return false;
2797 : }
2798 :
2799 0 : nsCOMPtr<nsIDOMWindow> targetWindow = do_GetInterface(aTargetItem);
2800 0 : if (!targetWindow) {
2801 0 : NS_ERROR("This should not happen, really");
2802 0 : return false;
2803 : }
2804 :
2805 0 : nsCOMPtr<nsIDOMWindow> targetOpener;
2806 0 : targetWindow->GetOpener(getter_AddRefs(targetOpener));
2807 0 : nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
2808 0 : nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
2809 :
2810 0 : if (!openerItem) {
2811 0 : return false;
2812 : }
2813 :
2814 0 : return CanAccessItem(openerItem, aAccessingItem, false);
2815 : }
2816 :
2817 : static bool
2818 0 : ItemIsActive(nsIDocShellTreeItem *aItem)
2819 : {
2820 0 : nsCOMPtr<nsIDOMWindow> window(do_GetInterface(aItem));
2821 :
2822 0 : if (window) {
2823 : bool isClosed;
2824 :
2825 0 : if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) {
2826 0 : return true;
2827 : }
2828 : }
2829 :
2830 0 : return false;
2831 : }
2832 :
2833 : NS_IMETHODIMP
2834 0 : nsDocShell::FindItemWithName(const PRUnichar * aName,
2835 : nsISupports * aRequestor,
2836 : nsIDocShellTreeItem * aOriginalRequestor,
2837 : nsIDocShellTreeItem ** _retval)
2838 : {
2839 0 : NS_ENSURE_ARG(aName);
2840 0 : NS_ENSURE_ARG_POINTER(_retval);
2841 :
2842 : // If we don't find one, we return NS_OK and a null result
2843 0 : *_retval = nsnull;
2844 :
2845 0 : if (!*aName)
2846 0 : return NS_OK;
2847 :
2848 0 : if (!aRequestor)
2849 : {
2850 0 : nsCOMPtr<nsIDocShellTreeItem> foundItem;
2851 :
2852 : // This is the entry point into the target-finding algorithm. Check
2853 : // for special names. This should only be done once, hence the check
2854 : // for a null aRequestor.
2855 :
2856 0 : nsDependentString name(aName);
2857 0 : if (name.LowerCaseEqualsLiteral("_self")) {
2858 0 : foundItem = this;
2859 : }
2860 0 : else if (name.LowerCaseEqualsLiteral("_blank"))
2861 : {
2862 : // Just return null. Caller must handle creating a new window with
2863 : // a blank name himself.
2864 0 : return NS_OK;
2865 : }
2866 0 : else if (name.LowerCaseEqualsLiteral("_parent"))
2867 : {
2868 0 : GetSameTypeParent(getter_AddRefs(foundItem));
2869 0 : if(!foundItem)
2870 0 : foundItem = this;
2871 : }
2872 0 : else if (name.LowerCaseEqualsLiteral("_top"))
2873 : {
2874 0 : GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
2875 0 : NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
2876 : }
2877 : // _main is an IE target which should be case-insensitive but isn't
2878 : // see bug 217886 for details
2879 0 : else if (name.LowerCaseEqualsLiteral("_content") ||
2880 0 : name.EqualsLiteral("_main"))
2881 : {
2882 : // Must pass our same type root as requestor to the
2883 : // treeowner to make sure things work right.
2884 0 : nsCOMPtr<nsIDocShellTreeItem> root;
2885 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
2886 0 : if (mTreeOwner) {
2887 0 : NS_ASSERTION(root, "Must have this; worst case it's us!");
2888 : mTreeOwner->FindItemWithName(aName, root, aOriginalRequestor,
2889 0 : getter_AddRefs(foundItem));
2890 : }
2891 : #ifdef DEBUG
2892 : else {
2893 : NS_ERROR("Someone isn't setting up the tree owner. "
2894 : "You might like to try that. "
2895 0 : "Things will.....you know, work.");
2896 : // Note: _content should always exist. If we don't have one
2897 : // hanging off the treeowner, just create a named window....
2898 : // so don't return here, in case we did that and can now find
2899 : // it.
2900 : // XXXbz should we be using |root| instead of creating
2901 : // a new window?
2902 : }
2903 : #endif
2904 : }
2905 :
2906 0 : if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
2907 0 : foundItem = nsnull;
2908 : }
2909 :
2910 0 : if (foundItem) {
2911 : // We return foundItem here even if it's not an active
2912 : // item since all the names we've dealt with so far are
2913 : // special cases that we won't bother looking for further.
2914 :
2915 0 : foundItem.swap(*_retval);
2916 0 : return NS_OK;
2917 : }
2918 : }
2919 :
2920 : // Keep looking
2921 :
2922 : // First we check our name.
2923 0 : if (mName.Equals(aName) && ItemIsActive(this) &&
2924 0 : CanAccessItem(this, aOriginalRequestor)) {
2925 0 : NS_ADDREF(*_retval = this);
2926 0 : return NS_OK;
2927 : }
2928 :
2929 : // This QI may fail, but the places where we want to compare, comparing
2930 : // against nsnull serves the same purpose.
2931 0 : nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
2932 :
2933 : // Second we check our children making sure not to ask a child if
2934 : // it is the aRequestor.
2935 : #ifdef DEBUG
2936 : nsresult rv =
2937 : #endif
2938 : FindChildWithName(aName, true, true, reqAsTreeItem,
2939 0 : aOriginalRequestor, _retval);
2940 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
2941 : "FindChildWithName should not be failing here.");
2942 0 : if (*_retval)
2943 0 : return NS_OK;
2944 :
2945 : // Third if we have a parent and it isn't the requestor then we
2946 : // should ask it to do the search. If it is the requestor we
2947 : // should just stop here and let the parent do the rest. If we
2948 : // don't have a parent, then we should ask the
2949 : // docShellTreeOwner to do the search.
2950 : nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
2951 0 : do_QueryInterface(GetAsSupports(mParent));
2952 0 : if (parentAsTreeItem) {
2953 0 : if (parentAsTreeItem == reqAsTreeItem)
2954 0 : return NS_OK;
2955 :
2956 : PRInt32 parentType;
2957 0 : parentAsTreeItem->GetItemType(&parentType);
2958 0 : if (parentType == mItemType) {
2959 0 : return parentAsTreeItem->
2960 : FindItemWithName(aName,
2961 : static_cast<nsIDocShellTreeItem*>
2962 : (this),
2963 : aOriginalRequestor,
2964 0 : _retval);
2965 : }
2966 : }
2967 :
2968 : // If the parent is null or not of the same type fall through and ask tree
2969 : // owner.
2970 :
2971 : // This may fail, but comparing against null serves the same purpose
2972 : nsCOMPtr<nsIDocShellTreeOwner>
2973 0 : reqAsTreeOwner(do_QueryInterface(aRequestor));
2974 :
2975 0 : if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
2976 : return mTreeOwner->
2977 0 : FindItemWithName(aName, this, aOriginalRequestor, _retval);
2978 : }
2979 :
2980 0 : return NS_OK;
2981 : }
2982 :
2983 : NS_IMETHODIMP
2984 0 : nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)
2985 : {
2986 0 : NS_ENSURE_ARG_POINTER(aTreeOwner);
2987 :
2988 0 : *aTreeOwner = mTreeOwner;
2989 0 : NS_IF_ADDREF(*aTreeOwner);
2990 0 : return NS_OK;
2991 : }
2992 :
2993 : #ifdef DEBUG_DOCSHELL_FOCUS
2994 : static void
2995 : PrintDocTree(nsIDocShellTreeItem * aParentNode, int aLevel)
2996 : {
2997 : for (PRInt32 i=0;i<aLevel;i++) printf(" ");
2998 :
2999 : PRInt32 childWebshellCount;
3000 : aParentNode->GetChildCount(&childWebshellCount);
3001 : nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
3002 : PRInt32 type;
3003 : aParentNode->GetItemType(&type);
3004 : nsCOMPtr<nsIPresShell> presShell;
3005 : parentAsDocShell->GetPresShell(getter_AddRefs(presShell));
3006 : nsRefPtr<nsPresContext> presContext;
3007 : parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
3008 : nsIDocument *doc = presShell->GetDocument();
3009 :
3010 : nsCOMPtr<nsIDOMWindow> domwin(doc->GetWindow());
3011 :
3012 : nsCOMPtr<nsIWidget> widget;
3013 : nsIViewManager* vm = presShell->GetViewManager();
3014 : if (vm) {
3015 : vm->GetWidget(getter_AddRefs(widget));
3016 : }
3017 : dom::Element* rootElement = doc->GetRootElement();
3018 :
3019 : printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
3020 : (void*)parentAsDocShell.get(),
3021 : type==nsIDocShellTreeItem::typeChrome?"Chr":"Con",
3022 : (void*)doc, (void*)domwin.get(),
3023 : (void*)presContext->EventStateManager(), (void*)rootElement);
3024 :
3025 : if (childWebshellCount > 0) {
3026 : for (PRInt32 i=0;i<childWebshellCount;i++) {
3027 : nsCOMPtr<nsIDocShellTreeItem> child;
3028 : aParentNode->GetChildAt(i, getter_AddRefs(child));
3029 : PrintDocTree(child, aLevel+1);
3030 : }
3031 : }
3032 : }
3033 :
3034 : static void
3035 : PrintDocTree(nsIDocShellTreeItem * aParentNode)
3036 : {
3037 : NS_ASSERTION(aParentNode, "Pointer is null!");
3038 :
3039 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
3040 : aParentNode->GetParent(getter_AddRefs(parentItem));
3041 : while (parentItem) {
3042 : nsCOMPtr<nsIDocShellTreeItem>tmp;
3043 : parentItem->GetParent(getter_AddRefs(tmp));
3044 : if (!tmp) {
3045 : break;
3046 : }
3047 : parentItem = tmp;
3048 : }
3049 :
3050 : if (!parentItem) {
3051 : parentItem = aParentNode;
3052 : }
3053 :
3054 : PrintDocTree(parentItem, 0);
3055 : }
3056 : #endif
3057 :
3058 : NS_IMETHODIMP
3059 0 : nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
3060 : {
3061 : #ifdef DEBUG_DOCSHELL_FOCUS
3062 : nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
3063 : if (item) {
3064 : PrintDocTree(item);
3065 : }
3066 : #endif
3067 :
3068 : // Don't automatically set the progress based on the tree owner for frames
3069 0 : if (!IsFrame()) {
3070 : nsCOMPtr<nsIWebProgress> webProgress =
3071 0 : do_QueryInterface(GetAsSupports(this));
3072 :
3073 0 : if (webProgress) {
3074 : nsCOMPtr<nsIWebProgressListener>
3075 0 : oldListener(do_QueryInterface(mTreeOwner));
3076 : nsCOMPtr<nsIWebProgressListener>
3077 0 : newListener(do_QueryInterface(aTreeOwner));
3078 :
3079 0 : if (oldListener) {
3080 0 : webProgress->RemoveProgressListener(oldListener);
3081 : }
3082 :
3083 0 : if (newListener) {
3084 0 : webProgress->AddProgressListener(newListener,
3085 0 : nsIWebProgress::NOTIFY_ALL);
3086 : }
3087 : }
3088 : }
3089 :
3090 0 : mTreeOwner = aTreeOwner; // Weak reference per API
3091 :
3092 0 : PRInt32 i, n = mChildList.Count();
3093 0 : for (i = 0; i < n; i++) {
3094 0 : nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
3095 0 : NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
3096 0 : PRInt32 childType = ~mItemType; // Set it to not us in case the get fails
3097 0 : child->GetItemType(&childType); // We don't care if this fails, if it does we won't set the owner
3098 0 : if (childType == mItemType)
3099 0 : child->SetTreeOwner(aTreeOwner);
3100 : }
3101 :
3102 0 : return NS_OK;
3103 : }
3104 :
3105 : NS_IMETHODIMP
3106 0 : nsDocShell::SetChildOffset(PRUint32 aChildOffset)
3107 : {
3108 0 : mChildOffset = aChildOffset;
3109 0 : return NS_OK;
3110 : }
3111 :
3112 : NS_IMETHODIMP
3113 0 : nsDocShell::GetHistoryID(PRUint64* aID)
3114 : {
3115 0 : *aID = mHistoryID;
3116 0 : return NS_OK;
3117 : }
3118 :
3119 : NS_IMETHODIMP
3120 0 : nsDocShell::GetIsInUnload(bool* aIsInUnload)
3121 : {
3122 0 : *aIsInUnload = mFiredUnloadEvent;
3123 0 : return NS_OK;
3124 : }
3125 :
3126 : //*****************************************************************************
3127 : // nsDocShell::nsIDocShellTreeNode
3128 : //*****************************************************************************
3129 :
3130 : NS_IMETHODIMP
3131 0 : nsDocShell::GetChildCount(PRInt32 * aChildCount)
3132 : {
3133 0 : NS_ENSURE_ARG_POINTER(aChildCount);
3134 0 : *aChildCount = mChildList.Count();
3135 0 : return NS_OK;
3136 : }
3137 :
3138 :
3139 :
3140 : NS_IMETHODIMP
3141 0 : nsDocShell::AddChild(nsIDocShellTreeItem * aChild)
3142 : {
3143 0 : NS_ENSURE_ARG_POINTER(aChild);
3144 :
3145 0 : nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3146 0 : NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
3147 :
3148 : // Make sure we're not creating a loop in the docshell tree
3149 0 : nsDocLoader* ancestor = this;
3150 0 : do {
3151 0 : if (childAsDocLoader == ancestor) {
3152 0 : return NS_ERROR_ILLEGAL_VALUE;
3153 : }
3154 0 : ancestor = ancestor->GetParent();
3155 : } while (ancestor);
3156 :
3157 : // Make sure to remove the child from its current parent.
3158 0 : nsDocLoader* childsParent = childAsDocLoader->GetParent();
3159 0 : if (childsParent) {
3160 0 : childsParent->RemoveChildLoader(childAsDocLoader);
3161 : }
3162 :
3163 : // Make sure to clear the treeowner in case this child is a different type
3164 : // from us.
3165 0 : aChild->SetTreeOwner(nsnull);
3166 :
3167 0 : nsresult res = AddChildLoader(childAsDocLoader);
3168 0 : NS_ENSURE_SUCCESS(res, res);
3169 0 : NS_ASSERTION(mChildList.Count() > 0,
3170 : "child list must not be empty after a successful add");
3171 :
3172 0 : nsCOMPtr<nsIDocShellHistory> docshellhistory = do_QueryInterface(aChild);
3173 0 : bool dynamic = false;
3174 0 : docshellhistory->GetCreatedDynamically(&dynamic);
3175 0 : if (!dynamic) {
3176 0 : nsCOMPtr<nsISHEntry> currentSH;
3177 0 : bool oshe = false;
3178 0 : GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
3179 0 : if (currentSH) {
3180 0 : currentSH->HasDynamicallyAddedChild(&dynamic);
3181 : }
3182 : }
3183 0 : nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
3184 0 : childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Count() - 1);
3185 :
3186 : /* Set the child's global history if the parent has one */
3187 0 : if (mUseGlobalHistory) {
3188 : nsCOMPtr<nsIDocShellHistory>
3189 0 : dsHistoryChild(do_QueryInterface(aChild));
3190 0 : if (dsHistoryChild)
3191 0 : dsHistoryChild->SetUseGlobalHistory(true);
3192 : }
3193 :
3194 :
3195 0 : PRInt32 childType = ~mItemType; // Set it to not us in case the get fails
3196 0 : aChild->GetItemType(&childType);
3197 0 : if (childType != mItemType)
3198 0 : return NS_OK;
3199 : // Everything below here is only done when the child is the same type.
3200 :
3201 :
3202 0 : aChild->SetTreeOwner(mTreeOwner);
3203 :
3204 0 : nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
3205 0 : if (!childAsDocShell)
3206 0 : return NS_OK;
3207 :
3208 : // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
3209 :
3210 : // Now take this document's charset and set the child's parentCharset field
3211 : // to it. We'll later use that field, in the loading process, for the
3212 : // charset choosing algorithm.
3213 : // If we fail, at any point, we just return NS_OK.
3214 : // This code has some performance impact. But this will be reduced when
3215 : // the current charset will finally be stored as an Atom, avoiding the
3216 : // alias resolution extra look-up.
3217 :
3218 : // we are NOT going to propagate the charset is this Chrome's docshell
3219 0 : if (mItemType == nsIDocShellTreeItem::typeChrome)
3220 0 : return NS_OK;
3221 :
3222 : // get the parent's current charset
3223 0 : if (!mContentViewer)
3224 0 : return NS_OK;
3225 0 : nsIDocument* doc = mContentViewer->GetDocument();
3226 0 : if (!doc)
3227 0 : return NS_OK;
3228 0 : const nsACString &parentCS = doc->GetDocumentCharacterSet();
3229 :
3230 0 : bool isWyciwyg = false;
3231 :
3232 0 : if (mCurrentURI) {
3233 : // Check if the url is wyciwyg
3234 0 : mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
3235 : }
3236 :
3237 0 : if (!isWyciwyg) {
3238 : // If this docshell is loaded from a wyciwyg: URI, don't
3239 : // advertise our charset since it does not in any way reflect
3240 : // the actual source charset, which is what we're trying to
3241 : // expose here.
3242 :
3243 : // set the child's parentCharset
3244 0 : nsCOMPtr<nsIAtom> parentCSAtom(do_GetAtom(parentCS));
3245 0 : res = childAsDocShell->SetParentCharset(parentCSAtom);
3246 0 : if (NS_FAILED(res))
3247 0 : return NS_OK;
3248 :
3249 0 : PRInt32 charsetSource = doc->GetDocumentCharacterSetSource();
3250 :
3251 : // set the child's parentCharset
3252 0 : res = childAsDocShell->SetParentCharsetSource(charsetSource);
3253 0 : if (NS_FAILED(res))
3254 0 : return NS_OK;
3255 : }
3256 :
3257 : // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
3258 :
3259 0 : return NS_OK;
3260 : }
3261 :
3262 : NS_IMETHODIMP
3263 0 : nsDocShell::RemoveChild(nsIDocShellTreeItem * aChild)
3264 : {
3265 0 : NS_ENSURE_ARG_POINTER(aChild);
3266 :
3267 0 : nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
3268 0 : NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
3269 :
3270 0 : nsresult rv = RemoveChildLoader(childAsDocLoader);
3271 0 : NS_ENSURE_SUCCESS(rv, rv);
3272 :
3273 0 : aChild->SetTreeOwner(nsnull);
3274 :
3275 0 : return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
3276 : }
3277 :
3278 : NS_IMETHODIMP
3279 0 : nsDocShell::GetChildAt(PRInt32 aIndex, nsIDocShellTreeItem ** aChild)
3280 : {
3281 0 : NS_ENSURE_ARG_POINTER(aChild);
3282 :
3283 : #ifdef DEBUG
3284 0 : if (aIndex < 0) {
3285 0 : NS_WARNING("Negative index passed to GetChildAt");
3286 : }
3287 0 : else if (aIndex >= mChildList.Count()) {
3288 0 : NS_WARNING("Too large an index passed to GetChildAt");
3289 : }
3290 : #endif
3291 :
3292 0 : nsIDocumentLoader* child = SafeChildAt(aIndex);
3293 0 : NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
3294 :
3295 0 : return CallQueryInterface(child, aChild);
3296 : }
3297 :
3298 : NS_IMETHODIMP
3299 0 : nsDocShell::FindChildWithName(const PRUnichar * aName,
3300 : bool aRecurse, bool aSameType,
3301 : nsIDocShellTreeItem * aRequestor,
3302 : nsIDocShellTreeItem * aOriginalRequestor,
3303 : nsIDocShellTreeItem ** _retval)
3304 : {
3305 0 : NS_ENSURE_ARG(aName);
3306 0 : NS_ENSURE_ARG_POINTER(_retval);
3307 :
3308 0 : *_retval = nsnull; // if we don't find one, we return NS_OK and a null result
3309 :
3310 0 : if (!*aName)
3311 0 : return NS_OK;
3312 :
3313 0 : nsXPIDLString childName;
3314 0 : PRInt32 i, n = mChildList.Count();
3315 0 : for (i = 0; i < n; i++) {
3316 0 : nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
3317 0 : NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
3318 : PRInt32 childType;
3319 0 : child->GetItemType(&childType);
3320 :
3321 0 : if (aSameType && (childType != mItemType))
3322 0 : continue;
3323 :
3324 0 : bool childNameEquals = false;
3325 0 : child->NameEquals(aName, &childNameEquals);
3326 0 : if (childNameEquals && ItemIsActive(child) &&
3327 0 : CanAccessItem(child, aOriginalRequestor)) {
3328 0 : child.swap(*_retval);
3329 : break;
3330 : }
3331 :
3332 0 : if (childType != mItemType) //Only ask it to check children if it is same type
3333 0 : continue;
3334 :
3335 0 : if (aRecurse && (aRequestor != child)) // Only ask the child if it isn't the requestor
3336 : {
3337 : // See if child contains the shell with the given name
3338 : #ifdef DEBUG
3339 : nsresult rv =
3340 : #endif
3341 0 : child->FindChildWithName(aName, true,
3342 : aSameType,
3343 : static_cast<nsIDocShellTreeItem*>
3344 : (this),
3345 : aOriginalRequestor,
3346 0 : _retval);
3347 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
3348 : "FindChildWithName should not fail here");
3349 0 : if (*_retval) // found it
3350 0 : return NS_OK;
3351 : }
3352 : }
3353 0 : return NS_OK;
3354 : }
3355 :
3356 : //*****************************************************************************
3357 : // nsDocShell::nsIDocShellHistory
3358 : //*****************************************************************************
3359 : NS_IMETHODIMP
3360 0 : nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
3361 : {
3362 0 : nsresult rv = NS_OK;
3363 :
3364 0 : NS_ENSURE_ARG_POINTER(aResult);
3365 0 : *aResult = nsnull;
3366 :
3367 :
3368 : // A nsISHEntry for a child is *only* available when the parent is in
3369 : // the progress of loading a document too...
3370 :
3371 0 : if (mLSHE) {
3372 : /* Before looking for the subframe's url, check
3373 : * the expiration status of the parent. If the parent
3374 : * has expired from cache, then subframes will not be
3375 : * loaded from history in certain situations.
3376 : */
3377 0 : bool parentExpired=false;
3378 0 : mLSHE->GetExpirationStatus(&parentExpired);
3379 :
3380 : /* Get the parent's Load Type so that it can be set on the child too.
3381 : * By default give a loadHistory value
3382 : */
3383 0 : PRUint32 loadType = nsIDocShellLoadInfo::loadHistory;
3384 0 : mLSHE->GetLoadType(&loadType);
3385 : // If the user did a shift-reload on this frameset page,
3386 : // we don't want to load the subframes from history.
3387 0 : if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
3388 : loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
3389 : loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
3390 : loadType == nsIDocShellLoadInfo::loadRefresh)
3391 0 : return rv;
3392 :
3393 : /* If the user pressed reload and the parent frame has expired
3394 : * from cache, we do not want to load the child frame from history.
3395 : */
3396 0 : if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
3397 : // The parent has expired. Return null.
3398 0 : *aResult = nsnull;
3399 0 : return rv;
3400 : }
3401 :
3402 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
3403 0 : if (container) {
3404 : // Get the child subframe from session history.
3405 0 : rv = container->GetChildAt(aChildOffset, aResult);
3406 0 : if (*aResult)
3407 0 : (*aResult)->SetLoadType(loadType);
3408 : }
3409 : }
3410 0 : return rv;
3411 : }
3412 :
3413 : NS_IMETHODIMP
3414 0 : nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
3415 : PRInt32 aChildOffset, PRUint32 loadType,
3416 : bool aCloneChildren)
3417 : {
3418 : nsresult rv;
3419 :
3420 0 : if (mLSHE && loadType != LOAD_PUSHSTATE) {
3421 : /* You get here if you are currently building a
3422 : * hierarchy ie.,you just visited a frameset page
3423 : */
3424 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
3425 0 : if (container) {
3426 0 : rv = container->AddChild(aNewEntry, aChildOffset);
3427 : }
3428 : }
3429 0 : else if (!aCloneRef) {
3430 : /* This is an initial load in some subframe. Just append it if we can */
3431 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
3432 0 : if (container) {
3433 0 : rv = container->AddChild(aNewEntry, aChildOffset);
3434 : }
3435 : }
3436 0 : else if (mSessionHistory) {
3437 : /* You are currently in the rootDocShell.
3438 : * You will get here when a subframe has a new url
3439 : * to load and you have walked up the tree all the
3440 : * way to the top to clone the current SHEntry hierarchy
3441 : * and replace the subframe where a new url was loaded with
3442 : * a new entry.
3443 : */
3444 0 : PRInt32 index = -1;
3445 0 : nsCOMPtr<nsIHistoryEntry> currentHE;
3446 0 : mSessionHistory->GetIndex(&index);
3447 0 : if (index < 0)
3448 0 : return NS_ERROR_FAILURE;
3449 :
3450 0 : rv = mSessionHistory->GetEntryAtIndex(index, false,
3451 0 : getter_AddRefs(currentHE));
3452 0 : NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
3453 :
3454 0 : nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
3455 0 : if (currentEntry) {
3456 0 : PRUint32 cloneID = 0;
3457 0 : nsCOMPtr<nsISHEntry> nextEntry;
3458 0 : aCloneRef->GetID(&cloneID);
3459 : rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
3460 0 : aCloneChildren, getter_AddRefs(nextEntry));
3461 :
3462 0 : if (NS_SUCCEEDED(rv)) {
3463 : nsCOMPtr<nsISHistoryInternal>
3464 0 : shPrivate(do_QueryInterface(mSessionHistory));
3465 0 : NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
3466 0 : rv = shPrivate->AddEntry(nextEntry, true);
3467 : }
3468 : }
3469 : }
3470 : else {
3471 : /* Just pass this along */
3472 : nsCOMPtr<nsIDocShellHistory> parent =
3473 0 : do_QueryInterface(GetAsSupports(mParent), &rv);
3474 0 : if (parent) {
3475 0 : rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
3476 0 : loadType, aCloneChildren);
3477 : }
3478 : }
3479 0 : return rv;
3480 : }
3481 :
3482 : nsresult
3483 0 : nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset,
3484 : bool aCloneChildren)
3485 : {
3486 : /* You will get here when you are in a subframe and
3487 : * a new url has been loaded on you.
3488 : * The mOSHE in this subframe will be the previous url's
3489 : * mOSHE. This mOSHE will be used as the identification
3490 : * for this subframe in the CloneAndReplace function.
3491 : */
3492 :
3493 : // In this case, we will end up calling AddEntry, which increases the
3494 : // current index by 1
3495 0 : nsCOMPtr<nsISHistory> rootSH;
3496 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
3497 0 : if (rootSH) {
3498 0 : rootSH->GetIndex(&mPreviousTransIndex);
3499 : }
3500 :
3501 : nsresult rv;
3502 : nsCOMPtr<nsIDocShellHistory> parent =
3503 0 : do_QueryInterface(GetAsSupports(mParent), &rv);
3504 0 : if (parent) {
3505 0 : rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
3506 0 : aCloneChildren);
3507 : }
3508 :
3509 :
3510 0 : if (rootSH) {
3511 0 : rootSH->GetIndex(&mLoadedTransIndex);
3512 : #ifdef DEBUG_PAGE_CACHE
3513 : printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
3514 : mLoadedTransIndex);
3515 : #endif
3516 : }
3517 :
3518 0 : return rv;
3519 : }
3520 :
3521 : NS_IMETHODIMP
3522 0 : nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
3523 : {
3524 : nsresult rv;
3525 :
3526 0 : mUseGlobalHistory = aUseGlobalHistory;
3527 :
3528 0 : if (!aUseGlobalHistory) {
3529 0 : mGlobalHistory = nsnull;
3530 0 : return NS_OK;
3531 : }
3532 :
3533 : // No need to initialize mGlobalHistory if IHistory is available.
3534 0 : nsCOMPtr<IHistory> history = services::GetHistoryService();
3535 0 : if (history) {
3536 0 : return NS_OK;
3537 : }
3538 :
3539 0 : if (mGlobalHistory) {
3540 0 : return NS_OK;
3541 : }
3542 :
3543 0 : mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
3544 0 : return rv;
3545 : }
3546 :
3547 : NS_IMETHODIMP
3548 0 : nsDocShell::GetUseGlobalHistory(bool *aUseGlobalHistory)
3549 : {
3550 0 : *aUseGlobalHistory = mUseGlobalHistory;
3551 0 : return NS_OK;
3552 : }
3553 :
3554 : NS_IMETHODIMP
3555 0 : nsDocShell::RemoveFromSessionHistory()
3556 : {
3557 0 : nsCOMPtr<nsISHistoryInternal> internalHistory;
3558 0 : nsCOMPtr<nsISHistory> sessionHistory;
3559 0 : nsCOMPtr<nsIDocShellTreeItem> root;
3560 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
3561 0 : if (root) {
3562 : nsCOMPtr<nsIWebNavigation> rootAsWebnav =
3563 0 : do_QueryInterface(root);
3564 0 : if (rootAsWebnav) {
3565 0 : rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
3566 0 : internalHistory = do_QueryInterface(sessionHistory);
3567 : }
3568 : }
3569 0 : if (!internalHistory) {
3570 0 : return NS_OK;
3571 : }
3572 :
3573 0 : PRInt32 index = 0;
3574 0 : sessionHistory->GetIndex(&index);
3575 0 : nsAutoTArray<PRUint64, 16> ids;
3576 0 : ids.AppendElement(mHistoryID);
3577 0 : internalHistory->RemoveEntries(ids, index);
3578 0 : return NS_OK;
3579 : }
3580 :
3581 : NS_IMETHODIMP
3582 0 : nsDocShell::SetCreatedDynamically(bool aDynamic)
3583 : {
3584 0 : mDynamicallyCreated = aDynamic;
3585 0 : return NS_OK;
3586 : }
3587 :
3588 : NS_IMETHODIMP
3589 0 : nsDocShell::GetCreatedDynamically(bool* aDynamic)
3590 : {
3591 0 : *aDynamic = mDynamicallyCreated;
3592 0 : return NS_OK;
3593 : }
3594 :
3595 : NS_IMETHODIMP
3596 0 : nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
3597 : {
3598 0 : *aOSHE = false;
3599 0 : *aEntry = nsnull;
3600 0 : if (mLSHE) {
3601 0 : NS_ADDREF(*aEntry = mLSHE);
3602 0 : } else if (mOSHE) {
3603 0 : NS_ADDREF(*aEntry = mOSHE);
3604 0 : *aOSHE = true;
3605 : }
3606 0 : return NS_OK;
3607 : }
3608 :
3609 : void
3610 0 : nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
3611 : {
3612 0 : nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
3613 0 : nsCOMPtr<nsISHistory> rootSH;
3614 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
3615 0 : nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
3616 0 : if (!history || !shcontainer) {
3617 : return;
3618 : }
3619 :
3620 0 : PRInt32 count = 0;
3621 0 : shcontainer->GetChildCount(&count);
3622 0 : nsAutoTArray<PRUint64, 16> ids;
3623 0 : for (PRInt32 i = 0; i < count; ++i) {
3624 0 : nsCOMPtr<nsISHEntry> child;
3625 0 : shcontainer->GetChildAt(i, getter_AddRefs(child));
3626 0 : if (child) {
3627 0 : PRUint64 id = 0;
3628 0 : child->GetDocshellID(&id);
3629 0 : ids.AppendElement(id);
3630 : }
3631 : }
3632 0 : PRInt32 index = 0;
3633 0 : rootSH->GetIndex(&index);
3634 0 : history->RemoveEntries(ids, index);
3635 : }
3636 :
3637 : //-------------------------------------
3638 : //-- Helper Method for Print discovery
3639 : //-------------------------------------
3640 : bool
3641 0 : nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
3642 : {
3643 0 : if (mIsPrintingOrPP && aDisplayErrorDialog) {
3644 0 : DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nsnull, nsnull);
3645 : }
3646 :
3647 0 : return mIsPrintingOrPP;
3648 : }
3649 :
3650 : bool
3651 0 : nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog)
3652 : {
3653 0 : return !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
3654 : }
3655 :
3656 : //*****************************************************************************
3657 : // nsDocShell::nsIWebNavigation
3658 : //*****************************************************************************
3659 :
3660 : NS_IMETHODIMP
3661 0 : nsDocShell::GetCanGoBack(bool * aCanGoBack)
3662 : {
3663 0 : if (!IsNavigationAllowed(false)) {
3664 0 : *aCanGoBack = false;
3665 0 : return NS_OK; // JS may not handle returning of an error code
3666 : }
3667 : nsresult rv;
3668 0 : nsCOMPtr<nsISHistory> rootSH;
3669 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
3670 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
3671 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
3672 0 : rv = webnav->GetCanGoBack(aCanGoBack);
3673 0 : return rv;
3674 :
3675 : }
3676 :
3677 : NS_IMETHODIMP
3678 0 : nsDocShell::GetCanGoForward(bool * aCanGoForward)
3679 : {
3680 0 : if (!IsNavigationAllowed(false)) {
3681 0 : *aCanGoForward = false;
3682 0 : return NS_OK; // JS may not handle returning of an error code
3683 : }
3684 : nsresult rv;
3685 0 : nsCOMPtr<nsISHistory> rootSH;
3686 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
3687 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
3688 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
3689 0 : rv = webnav->GetCanGoForward(aCanGoForward);
3690 0 : return rv;
3691 :
3692 : }
3693 :
3694 : NS_IMETHODIMP
3695 0 : nsDocShell::GoBack()
3696 : {
3697 0 : if (!IsNavigationAllowed()) {
3698 0 : return NS_OK; // JS may not handle returning of an error code
3699 : }
3700 : nsresult rv;
3701 0 : nsCOMPtr<nsISHistory> rootSH;
3702 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
3703 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
3704 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
3705 0 : rv = webnav->GoBack();
3706 0 : return rv;
3707 :
3708 : }
3709 :
3710 : NS_IMETHODIMP
3711 0 : nsDocShell::GoForward()
3712 : {
3713 0 : if (!IsNavigationAllowed()) {
3714 0 : return NS_OK; // JS may not handle returning of an error code
3715 : }
3716 : nsresult rv;
3717 0 : nsCOMPtr<nsISHistory> rootSH;
3718 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
3719 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
3720 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
3721 0 : rv = webnav->GoForward();
3722 0 : return rv;
3723 :
3724 : }
3725 :
3726 0 : NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex)
3727 : {
3728 0 : if (!IsNavigationAllowed()) {
3729 0 : return NS_OK; // JS may not handle returning of an error code
3730 : }
3731 : nsresult rv;
3732 0 : nsCOMPtr<nsISHistory> rootSH;
3733 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
3734 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
3735 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
3736 0 : rv = webnav->GotoIndex(aIndex);
3737 0 : return rv;
3738 :
3739 : }
3740 :
3741 : NS_IMETHODIMP
3742 0 : nsDocShell::LoadURI(const PRUnichar * aURI,
3743 : PRUint32 aLoadFlags,
3744 : nsIURI * aReferringURI,
3745 : nsIInputStream * aPostStream,
3746 : nsIInputStream * aHeaderStream)
3747 : {
3748 0 : NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
3749 :
3750 0 : if (!IsNavigationAllowed()) {
3751 0 : return NS_OK; // JS may not handle returning of an error code
3752 : }
3753 0 : nsCOMPtr<nsIURI> uri;
3754 0 : nsresult rv = NS_OK;
3755 :
3756 : // Create a URI from our string; if that succeeds, we want to
3757 : // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
3758 : // flag.
3759 :
3760 0 : NS_ConvertUTF16toUTF8 uriString(aURI);
3761 : // Cleanup the empty spaces that might be on each end.
3762 0 : uriString.Trim(" ");
3763 : // Eliminate embedded newlines, which single-line text fields now allow:
3764 0 : uriString.StripChars("\r\n");
3765 0 : NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
3766 :
3767 0 : rv = NS_NewURI(getter_AddRefs(uri), uriString);
3768 0 : if (uri) {
3769 0 : aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
3770 : }
3771 :
3772 0 : if (sURIFixup) {
3773 : // Call the fixup object. This will clobber the rv from NS_NewURI
3774 : // above, but that's fine with us. Note that we need to do this even
3775 : // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
3776 : // (things like view-source:mozilla.org for example).
3777 0 : PRUint32 fixupFlags = 0;
3778 0 : if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
3779 0 : fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
3780 : }
3781 0 : if (aLoadFlags & LOAD_FLAGS_URI_IS_UTF8) {
3782 0 : fixupFlags |= nsIURIFixup::FIXUP_FLAG_USE_UTF8;
3783 : }
3784 : rv = sURIFixup->CreateFixupURI(uriString, fixupFlags,
3785 0 : getter_AddRefs(uri));
3786 : }
3787 : // else no fixup service so just use the URI we created and see
3788 : // what happens
3789 :
3790 0 : if (NS_ERROR_MALFORMED_URI == rv) {
3791 0 : DisplayLoadError(rv, uri, aURI);
3792 : }
3793 :
3794 0 : if (NS_FAILED(rv) || !uri)
3795 0 : return NS_ERROR_FAILURE;
3796 :
3797 : PopupControlState popupState;
3798 0 : if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
3799 0 : popupState = openAllowed;
3800 0 : aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
3801 : } else {
3802 0 : popupState = openOverridden;
3803 : }
3804 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
3805 0 : nsAutoPopupStatePusher statePusher(win, popupState);
3806 :
3807 : // Don't pass certain flags that aren't needed and end up confusing
3808 : // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
3809 : // passed to LoadURI though, since it uses them.
3810 0 : PRUint32 extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
3811 0 : aLoadFlags &= ~EXTRA_LOAD_FLAGS;
3812 :
3813 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
3814 0 : rv = CreateLoadInfo(getter_AddRefs(loadInfo));
3815 0 : if (NS_FAILED(rv)) return rv;
3816 :
3817 0 : PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
3818 0 : loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
3819 0 : loadInfo->SetPostDataStream(aPostStream);
3820 0 : loadInfo->SetReferrer(aReferringURI);
3821 0 : loadInfo->SetHeadersStream(aHeaderStream);
3822 :
3823 0 : rv = LoadURI(uri, loadInfo, extraFlags, true);
3824 :
3825 0 : return rv;
3826 : }
3827 :
3828 : NS_IMETHODIMP
3829 0 : nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
3830 : const PRUnichar *aURL,
3831 : nsIChannel* aFailedChannel)
3832 : {
3833 : // Get prompt and string bundle servcies
3834 0 : nsCOMPtr<nsIPrompt> prompter;
3835 0 : nsCOMPtr<nsIStringBundle> stringBundle;
3836 0 : GetPromptAndStringBundle(getter_AddRefs(prompter),
3837 0 : getter_AddRefs(stringBundle));
3838 :
3839 0 : NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
3840 0 : NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
3841 :
3842 0 : nsAutoString error;
3843 0 : const PRUint32 kMaxFormatStrArgs = 3;
3844 0 : nsAutoString formatStrs[kMaxFormatStrArgs];
3845 0 : PRUint32 formatStrCount = 0;
3846 0 : bool addHostPort = false;
3847 0 : nsresult rv = NS_OK;
3848 0 : nsAutoString messageStr;
3849 0 : nsCAutoString cssClass;
3850 0 : nsCAutoString errorPage;
3851 :
3852 0 : errorPage.AssignLiteral("neterror");
3853 :
3854 : // Turn the error code into a human readable error message.
3855 0 : if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
3856 0 : NS_ENSURE_ARG_POINTER(aURI);
3857 : // extract the scheme
3858 0 : nsCAutoString scheme;
3859 0 : aURI->GetScheme(scheme);
3860 0 : CopyASCIItoUTF16(scheme, formatStrs[0]);
3861 0 : formatStrCount = 1;
3862 0 : error.AssignLiteral("protocolNotFound");
3863 : }
3864 0 : else if (NS_ERROR_FILE_NOT_FOUND == aError) {
3865 0 : NS_ENSURE_ARG_POINTER(aURI);
3866 0 : error.AssignLiteral("fileNotFound");
3867 : }
3868 0 : else if (NS_ERROR_UNKNOWN_HOST == aError) {
3869 0 : NS_ENSURE_ARG_POINTER(aURI);
3870 : // Get the host
3871 0 : nsCAutoString host;
3872 0 : nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
3873 0 : innermostURI->GetHost(host);
3874 0 : CopyUTF8toUTF16(host, formatStrs[0]);
3875 0 : formatStrCount = 1;
3876 0 : error.AssignLiteral("dnsNotFound");
3877 : }
3878 0 : else if(NS_ERROR_CONNECTION_REFUSED == aError) {
3879 0 : NS_ENSURE_ARG_POINTER(aURI);
3880 0 : addHostPort = true;
3881 0 : error.AssignLiteral("connectionFailure");
3882 : }
3883 0 : else if(NS_ERROR_NET_INTERRUPT == aError) {
3884 0 : NS_ENSURE_ARG_POINTER(aURI);
3885 0 : addHostPort = true;
3886 0 : error.AssignLiteral("netInterrupt");
3887 : }
3888 0 : else if (NS_ERROR_NET_TIMEOUT == aError) {
3889 0 : NS_ENSURE_ARG_POINTER(aURI);
3890 : // Get the host
3891 0 : nsCAutoString host;
3892 0 : aURI->GetHost(host);
3893 0 : CopyUTF8toUTF16(host, formatStrs[0]);
3894 0 : formatStrCount = 1;
3895 0 : error.AssignLiteral("netTimeout");
3896 : }
3897 0 : else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError) {
3898 : // CSP error
3899 0 : cssClass.AssignLiteral("neterror");
3900 0 : error.AssignLiteral("cspFrameAncestorBlocked");
3901 : }
3902 0 : else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
3903 : nsCOMPtr<nsINSSErrorsService> nsserr =
3904 0 : do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
3905 :
3906 : PRUint32 errorClass;
3907 0 : if (!nsserr ||
3908 0 : NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
3909 0 : errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
3910 : }
3911 :
3912 0 : nsCOMPtr<nsISupports> securityInfo;
3913 0 : nsCOMPtr<nsITransportSecurityInfo> tsi;
3914 0 : if (aFailedChannel)
3915 0 : aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
3916 0 : tsi = do_QueryInterface(securityInfo);
3917 0 : if (tsi) {
3918 : // Usually we should have aFailedChannel and get a detailed message
3919 0 : tsi->GetErrorMessage(getter_Copies(messageStr));
3920 : }
3921 : else {
3922 : // No channel, let's obtain the generic error message
3923 0 : if (nsserr) {
3924 0 : nsserr->GetErrorMessage(aError, messageStr);
3925 : }
3926 : }
3927 0 : if (!messageStr.IsEmpty()) {
3928 0 : if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
3929 0 : error.AssignLiteral("nssBadCert");
3930 :
3931 : // if this is a Strict-Transport-Security host and the cert
3932 : // is bad, don't allow overrides (STS Spec section 7.3).
3933 : nsCOMPtr<nsIStrictTransportSecurityService> stss =
3934 0 : do_GetService(NS_STSSERVICE_CONTRACTID, &rv);
3935 0 : NS_ENSURE_SUCCESS(rv, rv);
3936 :
3937 0 : bool isStsHost = false;
3938 0 : rv = stss->IsStsURI(aURI, &isStsHost);
3939 0 : NS_ENSURE_SUCCESS(rv, rv);
3940 :
3941 0 : if (isStsHost)
3942 0 : cssClass.AssignLiteral("badStsCert");
3943 :
3944 0 : if (Preferences::GetBool(
3945 : "browser.xul.error_pages.expert_bad_cert", false)) {
3946 0 : cssClass.AssignLiteral("expertBadCert");
3947 : }
3948 :
3949 : // See if an alternate cert error page is registered
3950 : nsAdoptingCString alternateErrorPage =
3951 : Preferences::GetCString(
3952 0 : "security.alternate_certificate_error_page");
3953 0 : if (alternateErrorPage)
3954 0 : errorPage.Assign(alternateErrorPage);
3955 : } else {
3956 0 : error.AssignLiteral("nssFailure2");
3957 : }
3958 : }
3959 0 : } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError) {
3960 0 : nsCAutoString host;
3961 0 : aURI->GetHost(host);
3962 0 : CopyUTF8toUTF16(host, formatStrs[0]);
3963 0 : formatStrCount = 1;
3964 :
3965 : // Malware and phishing detectors may want to use an alternate error
3966 : // page, but if the pref's not set, we'll fall back on the standard page
3967 : nsAdoptingCString alternateErrorPage =
3968 0 : Preferences::GetCString("urlclassifier.alternate_error_page");
3969 0 : if (alternateErrorPage)
3970 0 : errorPage.Assign(alternateErrorPage);
3971 :
3972 0 : if (NS_ERROR_PHISHING_URI == aError)
3973 0 : error.AssignLiteral("phishingBlocked");
3974 : else
3975 0 : error.AssignLiteral("malwareBlocked");
3976 0 : cssClass.AssignLiteral("blacklist");
3977 : }
3978 : else {
3979 : // Errors requiring simple formatting
3980 0 : switch (aError) {
3981 : case NS_ERROR_MALFORMED_URI:
3982 : // URI is malformed
3983 0 : error.AssignLiteral("malformedURI");
3984 0 : break;
3985 : case NS_ERROR_REDIRECT_LOOP:
3986 : // Doc failed to load because the server generated too many redirects
3987 0 : error.AssignLiteral("redirectLoop");
3988 0 : break;
3989 : case NS_ERROR_UNKNOWN_SOCKET_TYPE:
3990 : // Doc failed to load because PSM is not installed
3991 0 : error.AssignLiteral("unknownSocketType");
3992 0 : break;
3993 : case NS_ERROR_NET_RESET:
3994 : // Doc failed to load because the server kept reseting the connection
3995 : // before we could read any data from it
3996 0 : error.AssignLiteral("netReset");
3997 0 : break;
3998 : case NS_ERROR_DOCUMENT_NOT_CACHED:
3999 : // Doc failed to load because the cache does not contain a copy of
4000 : // the document.
4001 0 : error.AssignLiteral("notCached");
4002 0 : break;
4003 : case NS_ERROR_OFFLINE:
4004 : // Doc failed to load because we are offline.
4005 0 : error.AssignLiteral("netOffline");
4006 0 : break;
4007 : case NS_ERROR_DOCUMENT_IS_PRINTMODE:
4008 : // Doc navigation attempted while Printing or Print Preview
4009 0 : error.AssignLiteral("isprinting");
4010 0 : break;
4011 : case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
4012 : // Port blocked for security reasons
4013 0 : addHostPort = true;
4014 0 : error.AssignLiteral("deniedPortAccess");
4015 0 : break;
4016 : case NS_ERROR_UNKNOWN_PROXY_HOST:
4017 : // Proxy hostname could not be resolved.
4018 0 : error.AssignLiteral("proxyResolveFailure");
4019 0 : break;
4020 : case NS_ERROR_PROXY_CONNECTION_REFUSED:
4021 : // Proxy connection was refused.
4022 0 : error.AssignLiteral("proxyConnectFailure");
4023 0 : break;
4024 : case NS_ERROR_INVALID_CONTENT_ENCODING:
4025 : // Bad Content Encoding.
4026 0 : error.AssignLiteral("contentEncodingError");
4027 0 : break;
4028 : case NS_ERROR_REMOTE_XUL:
4029 : {
4030 0 : error.AssignLiteral("remoteXUL");
4031 0 : break;
4032 : }
4033 : case NS_ERROR_UNSAFE_CONTENT_TYPE:
4034 : // Channel refused to load from an unrecognized content type.
4035 0 : error.AssignLiteral("unsafeContentType");
4036 0 : break;
4037 : case NS_ERROR_CORRUPTED_CONTENT:
4038 : // Broken Content Detected. e.g. Content-MD5 check failure.
4039 0 : error.AssignLiteral("corruptedContentError");
4040 0 : break;
4041 : }
4042 : }
4043 :
4044 : // Test if the error should be displayed
4045 0 : if (error.IsEmpty()) {
4046 0 : return NS_OK;
4047 : }
4048 :
4049 : // Test if the error needs to be formatted
4050 0 : if (!messageStr.IsEmpty()) {
4051 : // already obtained message
4052 : }
4053 : else {
4054 0 : if (addHostPort) {
4055 : // Build up the host:port string.
4056 0 : nsCAutoString hostport;
4057 0 : if (aURI) {
4058 0 : aURI->GetHostPort(hostport);
4059 : } else {
4060 0 : hostport.AssignLiteral("?");
4061 : }
4062 0 : CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
4063 : }
4064 :
4065 0 : nsCAutoString spec;
4066 0 : rv = NS_ERROR_NOT_AVAILABLE;
4067 0 : if (aURI) {
4068 : // displaying "file://" is aesthetically unpleasing and could even be
4069 : // confusing to the user
4070 0 : bool isFileURI = false;
4071 0 : rv = aURI->SchemeIs("file", &isFileURI);
4072 0 : if (NS_SUCCEEDED(rv) && isFileURI)
4073 0 : aURI->GetPath(spec);
4074 : else
4075 0 : aURI->GetSpec(spec);
4076 :
4077 0 : nsCAutoString charset;
4078 : // unescape and convert from origin charset
4079 0 : aURI->GetOriginCharset(charset);
4080 : nsCOMPtr<nsITextToSubURI> textToSubURI(
4081 0 : do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
4082 0 : if (NS_SUCCEEDED(rv)) {
4083 0 : rv = textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[formatStrCount]);
4084 : }
4085 : } else {
4086 0 : spec.AssignLiteral("?");
4087 : }
4088 0 : if (NS_FAILED(rv))
4089 0 : CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
4090 0 : rv = NS_OK;
4091 0 : ++formatStrCount;
4092 :
4093 : const PRUnichar *strs[kMaxFormatStrArgs];
4094 0 : for (PRUint32 i = 0; i < formatStrCount; i++) {
4095 0 : strs[i] = formatStrs[i].get();
4096 : }
4097 0 : nsXPIDLString str;
4098 0 : rv = stringBundle->FormatStringFromName(
4099 : error.get(),
4100 0 : strs, formatStrCount, getter_Copies(str));
4101 0 : NS_ENSURE_SUCCESS(rv, rv);
4102 0 : messageStr.Assign(str.get());
4103 : }
4104 :
4105 : // Display the error as a page or an alert prompt
4106 0 : NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
4107 0 : if (mUseErrorPages) {
4108 : // Display an error page
4109 : LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
4110 0 : messageStr.get(), cssClass.get(), aFailedChannel);
4111 : }
4112 : else
4113 : {
4114 : // The prompter reqires that our private window has a document (or it
4115 : // asserts). Satisfy that assertion now since GetDocument will force
4116 : // creation of one if it hasn't already been created.
4117 0 : nsCOMPtr<nsPIDOMWindow> pwin(do_QueryInterface(mScriptGlobal));
4118 0 : if (pwin) {
4119 0 : nsCOMPtr<nsIDOMDocument> doc;
4120 0 : pwin->GetDocument(getter_AddRefs(doc));
4121 : }
4122 :
4123 : // Display a message box
4124 0 : prompter->Alert(nsnull, messageStr.get());
4125 : }
4126 :
4127 0 : return NS_OK;
4128 : }
4129 :
4130 :
4131 : NS_IMETHODIMP
4132 0 : nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
4133 : const char *aErrorPage,
4134 : const PRUnichar *aErrorType,
4135 : const PRUnichar *aDescription,
4136 : const char *aCSSClass,
4137 : nsIChannel* aFailedChannel)
4138 : {
4139 : #if defined(PR_LOGGING) && defined(DEBUG)
4140 0 : if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
4141 0 : nsCAutoString spec;
4142 0 : aURI->GetSpec(spec);
4143 :
4144 0 : nsCAutoString chanName;
4145 0 : if (aFailedChannel)
4146 0 : aFailedChannel->GetName(chanName);
4147 : else
4148 0 : chanName.AssignLiteral("<no channel>");
4149 :
4150 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
4151 : ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
4152 : spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get()));
4153 : }
4154 : #endif
4155 0 : mFailedChannel = aFailedChannel;
4156 0 : mFailedURI = aURI;
4157 0 : mFailedLoadType = mLoadType;
4158 :
4159 0 : if (mLSHE) {
4160 : // Abandon mLSHE's BFCache entry and create a new one. This way, if
4161 : // we go back or forward to another SHEntry with the same doc
4162 : // identifier, the error page won't persist.
4163 0 : mLSHE->AbandonBFCacheEntry();
4164 : }
4165 :
4166 0 : nsCAutoString url;
4167 0 : nsCAutoString charset;
4168 0 : if (aURI)
4169 : {
4170 0 : nsresult rv = aURI->GetSpec(url);
4171 0 : rv |= aURI->GetOriginCharset(charset);
4172 0 : NS_ENSURE_SUCCESS(rv, rv);
4173 : }
4174 0 : else if (aURL)
4175 : {
4176 : // We need a URI object to store a session history entry, so make up a URI
4177 0 : nsresult rv = NS_NewURI(getter_AddRefs(mFailedURI), "about:blank");
4178 0 : NS_ENSURE_SUCCESS(rv, rv);
4179 :
4180 0 : CopyUTF16toUTF8(aURL, url);
4181 : }
4182 : else
4183 : {
4184 0 : return NS_ERROR_INVALID_POINTER;
4185 : }
4186 :
4187 : // Create a URL to pass all the error information through to the page.
4188 :
4189 : #undef SAFE_ESCAPE
4190 : #define SAFE_ESCAPE(cstring, escArg1, escArg2) \
4191 : { \
4192 : char* s = nsEscape(escArg1, escArg2); \
4193 : if (!s) \
4194 : return NS_ERROR_OUT_OF_MEMORY; \
4195 : cstring.Adopt(s); \
4196 : }
4197 0 : nsCString escapedUrl, escapedCharset, escapedError, escapedDescription,
4198 0 : escapedCSSClass;
4199 0 : SAFE_ESCAPE(escapedUrl, url.get(), url_Path);
4200 0 : SAFE_ESCAPE(escapedCharset, charset.get(), url_Path);
4201 0 : SAFE_ESCAPE(escapedError,
4202 : NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path);
4203 0 : SAFE_ESCAPE(escapedDescription,
4204 : NS_ConvertUTF16toUTF8(aDescription).get(), url_Path);
4205 0 : if (aCSSClass) {
4206 0 : SAFE_ESCAPE(escapedCSSClass, aCSSClass, url_Path);
4207 : }
4208 0 : nsCString errorPageUrl("about:");
4209 0 : errorPageUrl.AppendASCII(aErrorPage);
4210 0 : errorPageUrl.AppendLiteral("?e=");
4211 :
4212 0 : errorPageUrl.AppendASCII(escapedError.get());
4213 0 : errorPageUrl.AppendLiteral("&u=");
4214 0 : errorPageUrl.AppendASCII(escapedUrl.get());
4215 0 : if (!escapedCSSClass.IsEmpty()) {
4216 0 : errorPageUrl.AppendASCII("&s=");
4217 0 : errorPageUrl.AppendASCII(escapedCSSClass.get());
4218 : }
4219 0 : errorPageUrl.AppendLiteral("&c=");
4220 0 : errorPageUrl.AppendASCII(escapedCharset.get());
4221 0 : errorPageUrl.AppendLiteral("&d=");
4222 0 : errorPageUrl.AppendASCII(escapedDescription.get());
4223 :
4224 0 : nsCOMPtr<nsIURI> errorPageURI;
4225 0 : nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
4226 0 : NS_ENSURE_SUCCESS(rv, rv);
4227 :
4228 : return InternalLoad(errorPageURI, nsnull, nsnull,
4229 : INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nsnull, nsnull,
4230 : nsnull, nsnull, LOAD_ERROR_PAGE,
4231 0 : nsnull, true, nsnull, nsnull);
4232 : }
4233 :
4234 :
4235 : NS_IMETHODIMP
4236 0 : nsDocShell::Reload(PRUint32 aReloadFlags)
4237 : {
4238 0 : if (!IsNavigationAllowed()) {
4239 0 : return NS_OK; // JS may not handle returning of an error code
4240 : }
4241 : nsresult rv;
4242 0 : NS_ASSERTION(((aReloadFlags & 0xf) == 0),
4243 : "Reload command not updated to use load flags!");
4244 0 : NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
4245 : "Don't pass these flags to Reload");
4246 :
4247 0 : PRUint32 loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
4248 0 : NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
4249 :
4250 : // Send notifications to the HistoryListener if any, about the impending reload
4251 0 : nsCOMPtr<nsISHistory> rootSH;
4252 0 : rv = GetRootSessionHistory(getter_AddRefs(rootSH));
4253 0 : nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
4254 0 : bool canReload = true;
4255 0 : if (rootSH) {
4256 0 : nsCOMPtr<nsISHistoryListener> listener;
4257 0 : shistInt->GetListener(getter_AddRefs(listener));
4258 0 : if (listener) {
4259 0 : listener->OnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
4260 : }
4261 : }
4262 :
4263 0 : if (!canReload)
4264 0 : return NS_OK;
4265 :
4266 : /* If you change this part of code, make sure bug 45297 does not re-occur */
4267 0 : if (mOSHE) {
4268 0 : rv = LoadHistoryEntry(mOSHE, loadType);
4269 : }
4270 0 : else if (mLSHE) { // In case a reload happened before the current load is done
4271 0 : rv = LoadHistoryEntry(mLSHE, loadType);
4272 : }
4273 : else {
4274 0 : nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
4275 :
4276 0 : nsIPrincipal* principal = nsnull;
4277 0 : nsAutoString contentTypeHint;
4278 0 : if (doc) {
4279 0 : principal = doc->NodePrincipal();
4280 0 : doc->GetContentType(contentTypeHint);
4281 : }
4282 :
4283 : rv = InternalLoad(mCurrentURI,
4284 : mReferrerURI,
4285 : principal,
4286 : INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document
4287 : nsnull, // No window target
4288 0 : NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
4289 : nsnull, // No post data
4290 : nsnull, // No headers data
4291 : loadType, // Load type
4292 : nsnull, // No SHEntry
4293 : true,
4294 : nsnull, // No nsIDocShell
4295 0 : nsnull); // No nsIRequest
4296 : }
4297 :
4298 :
4299 0 : return rv;
4300 : }
4301 :
4302 : NS_IMETHODIMP
4303 0 : nsDocShell::Stop(PRUint32 aStopFlags)
4304 : {
4305 : // Revoke any pending event related to content viewer restoration
4306 0 : mRestorePresentationEvent.Revoke();
4307 :
4308 0 : if (mLoadType == LOAD_ERROR_PAGE) {
4309 0 : if (mLSHE) {
4310 : // Since error page loads never unset mLSHE, do so now
4311 0 : SetHistoryEntry(&mOSHE, mLSHE);
4312 0 : SetHistoryEntry(&mLSHE, nsnull);
4313 : }
4314 :
4315 0 : mFailedChannel = nsnull;
4316 0 : mFailedURI = nsnull;
4317 : }
4318 :
4319 0 : if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
4320 : // Stop the document loading
4321 0 : if (mContentViewer)
4322 0 : mContentViewer->Stop();
4323 : }
4324 :
4325 0 : if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
4326 : // Suspend any timers that were set for this loader. We'll clear
4327 : // them out for good in CreateContentViewer.
4328 0 : if (mRefreshURIList) {
4329 0 : SuspendRefreshURIs();
4330 0 : mSavedRefreshURIList.swap(mRefreshURIList);
4331 0 : mRefreshURIList = nsnull;
4332 : }
4333 :
4334 : // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
4335 : // just call Stop() on us as an nsIDocumentLoader... We need fewer
4336 : // redundant apis!
4337 0 : Stop();
4338 : }
4339 :
4340 : PRInt32 n;
4341 0 : PRInt32 count = mChildList.Count();
4342 0 : for (n = 0; n < count; n++) {
4343 0 : nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryInterface(ChildAt(n)));
4344 0 : if (shellAsNav)
4345 0 : shellAsNav->Stop(aStopFlags);
4346 : }
4347 :
4348 0 : return NS_OK;
4349 : }
4350 :
4351 : NS_IMETHODIMP
4352 0 : nsDocShell::GetDocument(nsIDOMDocument ** aDocument)
4353 : {
4354 0 : NS_ENSURE_ARG_POINTER(aDocument);
4355 0 : NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
4356 :
4357 0 : return mContentViewer->GetDOMDocument(aDocument);
4358 : }
4359 :
4360 : NS_IMETHODIMP
4361 0 : nsDocShell::GetCurrentURI(nsIURI ** aURI)
4362 : {
4363 0 : NS_ENSURE_ARG_POINTER(aURI);
4364 :
4365 0 : if (mCurrentURI) {
4366 0 : return NS_EnsureSafeToReturn(mCurrentURI, aURI);
4367 : }
4368 :
4369 0 : *aURI = nsnull;
4370 0 : return NS_OK;
4371 : }
4372 :
4373 : NS_IMETHODIMP
4374 0 : nsDocShell::GetReferringURI(nsIURI ** aURI)
4375 : {
4376 0 : NS_ENSURE_ARG_POINTER(aURI);
4377 :
4378 0 : *aURI = mReferrerURI;
4379 0 : NS_IF_ADDREF(*aURI);
4380 :
4381 0 : return NS_OK;
4382 : }
4383 :
4384 : NS_IMETHODIMP
4385 0 : nsDocShell::SetSessionHistory(nsISHistory * aSessionHistory)
4386 : {
4387 :
4388 0 : NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
4389 : // make sure that we are the root docshell and
4390 : // set a handle to root docshell in SH.
4391 :
4392 0 : nsCOMPtr<nsIDocShellTreeItem> root;
4393 : /* Get the root docshell. If *this* is the root docshell
4394 : * then save a handle to *this* in SH. SH needs it to do
4395 : * traversions thro' its entries
4396 : */
4397 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
4398 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
4399 0 : if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) {
4400 0 : mSessionHistory = aSessionHistory;
4401 : nsCOMPtr<nsISHistoryInternal>
4402 0 : shPrivate(do_QueryInterface(mSessionHistory));
4403 0 : NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
4404 0 : shPrivate->SetRootDocShell(this);
4405 0 : return NS_OK;
4406 : }
4407 0 : return NS_ERROR_FAILURE;
4408 :
4409 : }
4410 :
4411 :
4412 : NS_IMETHODIMP
4413 0 : nsDocShell::GetSessionHistory(nsISHistory ** aSessionHistory)
4414 : {
4415 0 : NS_ENSURE_ARG_POINTER(aSessionHistory);
4416 0 : *aSessionHistory = mSessionHistory;
4417 0 : NS_IF_ADDREF(*aSessionHistory);
4418 0 : return NS_OK;
4419 : }
4420 :
4421 : //*****************************************************************************
4422 : // nsDocShell::nsIWebPageDescriptor
4423 : //*****************************************************************************
4424 : NS_IMETHODIMP
4425 0 : nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType)
4426 : {
4427 0 : nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
4428 :
4429 : // Currently, the opaque 'page descriptor' is an nsISHEntry...
4430 0 : if (!shEntryIn) {
4431 0 : return NS_ERROR_INVALID_POINTER;
4432 : }
4433 :
4434 : // Now clone shEntryIn, since we might end up modifying it later on, and we
4435 : // want a page descriptor to be reusable.
4436 0 : nsCOMPtr<nsISHEntry> shEntry;
4437 0 : nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
4438 0 : NS_ENSURE_SUCCESS(rv, rv);
4439 :
4440 : // Give our cloned shEntry a new bfcache entry so this load is independent
4441 : // of all other loads. (This is important, in particular, for bugs 582795
4442 : // and 585298.)
4443 0 : rv = shEntry->AbandonBFCacheEntry();
4444 0 : NS_ENSURE_SUCCESS(rv, rv);
4445 :
4446 : //
4447 : // load the page as view-source
4448 : //
4449 0 : if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
4450 0 : nsCOMPtr<nsIURI> oldUri, newUri;
4451 0 : nsCString spec, newSpec;
4452 :
4453 : // Create a new view-source URI and replace the original.
4454 0 : rv = shEntry->GetURI(getter_AddRefs(oldUri));
4455 0 : if (NS_FAILED(rv))
4456 0 : return rv;
4457 :
4458 0 : oldUri->GetSpec(spec);
4459 0 : newSpec.AppendLiteral("view-source:");
4460 0 : newSpec.Append(spec);
4461 :
4462 0 : rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
4463 0 : if (NS_FAILED(rv)) {
4464 0 : return rv;
4465 : }
4466 0 : shEntry->SetURI(newUri);
4467 : }
4468 :
4469 0 : rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
4470 0 : return rv;
4471 : }
4472 :
4473 : NS_IMETHODIMP
4474 0 : nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor)
4475 : {
4476 0 : NS_PRECONDITION(aPageDescriptor, "Null out param?");
4477 :
4478 0 : *aPageDescriptor = nsnull;
4479 :
4480 0 : nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
4481 0 : if (src) {
4482 0 : nsCOMPtr<nsISHEntry> dest;
4483 :
4484 0 : nsresult rv = src->Clone(getter_AddRefs(dest));
4485 0 : if (NS_FAILED(rv)) {
4486 0 : return rv;
4487 : }
4488 :
4489 : // null out inappropriate cloned attributes...
4490 0 : dest->SetParent(nsnull);
4491 0 : dest->SetIsSubFrame(false);
4492 :
4493 0 : return CallQueryInterface(dest, aPageDescriptor);
4494 : }
4495 :
4496 0 : return NS_ERROR_NOT_AVAILABLE;
4497 : }
4498 :
4499 :
4500 : //*****************************************************************************
4501 : // nsDocShell::nsIBaseWindow
4502 : //*****************************************************************************
4503 :
4504 : NS_IMETHODIMP
4505 0 : nsDocShell::InitWindow(nativeWindow parentNativeWindow,
4506 : nsIWidget * parentWidget, PRInt32 x, PRInt32 y,
4507 : PRInt32 cx, PRInt32 cy)
4508 : {
4509 0 : SetParentWidget(parentWidget);
4510 0 : SetPositionAndSize(x, y, cx, cy, false);
4511 :
4512 0 : return NS_OK;
4513 : }
4514 :
4515 : NS_IMETHODIMP
4516 0 : nsDocShell::Create()
4517 : {
4518 0 : if (mCreated) {
4519 : // We've already been created
4520 0 : return NS_OK;
4521 : }
4522 :
4523 0 : NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
4524 : "Unexpected item type in docshell");
4525 :
4526 0 : NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
4527 0 : mCreated = true;
4528 :
4529 : mAllowSubframes =
4530 0 : Preferences::GetBool("browser.frames.enabled", mAllowSubframes);
4531 :
4532 0 : if (gValidateOrigin == 0xffffffff) {
4533 : // Check pref to see if we should prevent frameset spoofing
4534 : gValidateOrigin =
4535 0 : Preferences::GetBool("browser.frame.validate_origin", true);
4536 : }
4537 :
4538 : // Should we use XUL error pages instead of alerts if possible?
4539 : mUseErrorPages =
4540 0 : Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
4541 :
4542 0 : if (mObserveErrorPages) {
4543 0 : Preferences::AddStrongObserver(this, "browser.xul.error_pages.enabled");
4544 : }
4545 :
4546 0 : nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
4547 0 : if (serv) {
4548 : const char* msg = mItemType == typeContent ?
4549 0 : NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
4550 0 : serv->NotifyObservers(GetAsSupports(this), msg, nsnull);
4551 : }
4552 :
4553 0 : return NS_OK;
4554 : }
4555 :
4556 : NS_IMETHODIMP
4557 0 : nsDocShell::Destroy()
4558 : {
4559 0 : NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
4560 : "Unexpected item type in docshell");
4561 :
4562 0 : if (!mIsBeingDestroyed) {
4563 0 : nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
4564 0 : if (serv) {
4565 : const char* msg = mItemType == typeContent ?
4566 0 : NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
4567 0 : serv->NotifyObservers(GetAsSupports(this), msg, nsnull);
4568 : }
4569 : }
4570 :
4571 0 : mIsBeingDestroyed = true;
4572 :
4573 : // Remove our pref observers
4574 0 : if (mObserveErrorPages) {
4575 0 : Preferences::RemoveObserver(this, "browser.xul.error_pages.enabled");
4576 0 : mObserveErrorPages = false;
4577 : }
4578 :
4579 : // Make sure to blow away our mLoadingURI just in case. No loads
4580 : // from inside this pagehide.
4581 0 : mLoadingURI = nsnull;
4582 :
4583 : // Fire unload event before we blow anything away.
4584 0 : (void) FirePageHideNotification(true);
4585 :
4586 : // Clear pointers to any detached nsEditorData that's lying
4587 : // around in shistory entries. Breaks cycle. See bug 430921.
4588 0 : if (mOSHE)
4589 0 : mOSHE->SetEditorData(nsnull);
4590 0 : if (mLSHE)
4591 0 : mLSHE->SetEditorData(nsnull);
4592 :
4593 : // Note: mContentListener can be null if Init() failed and we're being
4594 : // called from the destructor.
4595 0 : if (mContentListener) {
4596 0 : mContentListener->DropDocShellreference();
4597 0 : mContentListener->SetParentContentListener(nsnull);
4598 : // Note that we do NOT set mContentListener to null here; that
4599 : // way if someone tries to do a load in us after this point
4600 : // the nsDSURIContentListener will block it. All of which
4601 : // means that we should do this before calling Stop(), of
4602 : // course.
4603 : }
4604 :
4605 : // Stop any URLs that are currently being loaded...
4606 0 : Stop(nsIWebNavigation::STOP_ALL);
4607 :
4608 0 : mEditorData = nsnull;
4609 :
4610 0 : mTransferableHookData = nsnull;
4611 :
4612 : // Save the state of the current document, before destroying the window.
4613 : // This is needed to capture the state of a frameset when the new document
4614 : // causes the frameset to be destroyed...
4615 0 : PersistLayoutHistoryState();
4616 :
4617 : // Remove this docshell from its parent's child list
4618 : nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
4619 0 : do_QueryInterface(GetAsSupports(mParent));
4620 0 : if (docShellParentAsItem)
4621 0 : docShellParentAsItem->RemoveChild(this);
4622 :
4623 0 : if (mContentViewer) {
4624 0 : mContentViewer->Close(nsnull);
4625 0 : mContentViewer->Destroy();
4626 0 : mContentViewer = nsnull;
4627 : }
4628 :
4629 0 : nsDocLoader::Destroy();
4630 :
4631 0 : mParentWidget = nsnull;
4632 0 : mCurrentURI = nsnull;
4633 :
4634 0 : if (mScriptGlobal) {
4635 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
4636 0 : win->SetDocShell(nsnull);
4637 :
4638 0 : mScriptGlobal = nsnull;
4639 : }
4640 :
4641 0 : if (mSessionHistory) {
4642 : // We want to destroy these content viewers now rather than
4643 : // letting their destruction wait for the session history
4644 : // entries to get garbage collected. (Bug 488394)
4645 : nsCOMPtr<nsISHistoryInternal> shPrivate =
4646 0 : do_QueryInterface(mSessionHistory);
4647 0 : if (shPrivate) {
4648 0 : shPrivate->EvictAllContentViewers();
4649 : }
4650 0 : mSessionHistory = nsnull;
4651 : }
4652 :
4653 0 : SetTreeOwner(nsnull);
4654 :
4655 : // required to break ref cycle
4656 0 : mSecurityUI = nsnull;
4657 :
4658 : // Cancel any timers that were set for this docshell; this is needed
4659 : // to break the cycle between us and the timers.
4660 0 : CancelRefreshURITimers();
4661 0 : return NS_OK;
4662 : }
4663 :
4664 : NS_IMETHODIMP
4665 0 : nsDocShell::SetPosition(PRInt32 x, PRInt32 y)
4666 : {
4667 0 : mBounds.x = x;
4668 0 : mBounds.y = y;
4669 :
4670 0 : if (mContentViewer)
4671 0 : NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE);
4672 :
4673 0 : return NS_OK;
4674 : }
4675 :
4676 : NS_IMETHODIMP
4677 0 : nsDocShell::GetPosition(PRInt32 * aX, PRInt32 * aY)
4678 : {
4679 : PRInt32 dummyHolder;
4680 0 : return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder);
4681 : }
4682 :
4683 : NS_IMETHODIMP
4684 0 : nsDocShell::SetSize(PRInt32 aCX, PRInt32 aCY, bool aRepaint)
4685 : {
4686 0 : PRInt32 x = 0, y = 0;
4687 0 : GetPosition(&x, &y);
4688 0 : return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
4689 : }
4690 :
4691 : NS_IMETHODIMP
4692 0 : nsDocShell::GetSize(PRInt32 * aCX, PRInt32 * aCY)
4693 : {
4694 : PRInt32 dummyHolder;
4695 0 : return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY);
4696 : }
4697 :
4698 : NS_IMETHODIMP
4699 0 : nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
4700 : PRInt32 cy, bool fRepaint)
4701 : {
4702 0 : mBounds.x = x;
4703 0 : mBounds.y = y;
4704 0 : mBounds.width = cx;
4705 0 : mBounds.height = cy;
4706 :
4707 : // Hold strong ref, since SetBounds can make us null out mContentViewer
4708 0 : nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
4709 0 : if (viewer) {
4710 : //XXX Border figured in here or is that handled elsewhere?
4711 0 : NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE);
4712 : }
4713 :
4714 0 : return NS_OK;
4715 : }
4716 :
4717 : NS_IMETHODIMP
4718 0 : nsDocShell::GetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
4719 : PRInt32 * cy)
4720 : {
4721 : // We should really consider just getting this information from
4722 : // our window instead of duplicating the storage and code...
4723 0 : if (cx || cy) {
4724 : // Caller wants to know our size; make sure to give them up to
4725 : // date information.
4726 0 : nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
4727 0 : if (doc) {
4728 0 : doc->FlushPendingNotifications(Flush_Layout);
4729 : }
4730 : }
4731 :
4732 0 : DoGetPositionAndSize(x, y, cx, cy);
4733 0 : return NS_OK;
4734 : }
4735 :
4736 : void
4737 0 : nsDocShell::DoGetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
4738 : PRInt32 * cy)
4739 : {
4740 0 : if (x)
4741 0 : *x = mBounds.x;
4742 0 : if (y)
4743 0 : *y = mBounds.y;
4744 0 : if (cx)
4745 0 : *cx = mBounds.width;
4746 0 : if (cy)
4747 0 : *cy = mBounds.height;
4748 0 : }
4749 :
4750 : NS_IMETHODIMP
4751 0 : nsDocShell::Repaint(bool aForce)
4752 : {
4753 0 : nsCOMPtr<nsIPresShell> presShell;
4754 0 : GetPresShell(getter_AddRefs(presShell));
4755 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
4756 :
4757 0 : nsIViewManager* viewManager = presShell->GetViewManager();
4758 0 : NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
4759 :
4760 0 : NS_ENSURE_SUCCESS(viewManager->InvalidateAllViews(), NS_ERROR_FAILURE);
4761 0 : return NS_OK;
4762 : }
4763 :
4764 : NS_IMETHODIMP
4765 0 : nsDocShell::GetParentWidget(nsIWidget ** parentWidget)
4766 : {
4767 0 : NS_ENSURE_ARG_POINTER(parentWidget);
4768 :
4769 0 : *parentWidget = mParentWidget;
4770 0 : NS_IF_ADDREF(*parentWidget);
4771 :
4772 0 : return NS_OK;
4773 : }
4774 :
4775 : NS_IMETHODIMP
4776 0 : nsDocShell::SetParentWidget(nsIWidget * aParentWidget)
4777 : {
4778 0 : mParentWidget = aParentWidget;
4779 :
4780 0 : return NS_OK;
4781 : }
4782 :
4783 : NS_IMETHODIMP
4784 0 : nsDocShell::GetParentNativeWindow(nativeWindow * parentNativeWindow)
4785 : {
4786 0 : NS_ENSURE_ARG_POINTER(parentNativeWindow);
4787 :
4788 0 : if (mParentWidget)
4789 0 : *parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
4790 : else
4791 0 : *parentNativeWindow = nsnull;
4792 :
4793 0 : return NS_OK;
4794 : }
4795 :
4796 : NS_IMETHODIMP
4797 0 : nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
4798 : {
4799 0 : return NS_ERROR_NOT_IMPLEMENTED;
4800 : }
4801 :
4802 : NS_IMETHODIMP
4803 0 : nsDocShell::GetVisibility(bool * aVisibility)
4804 : {
4805 0 : NS_ENSURE_ARG_POINTER(aVisibility);
4806 :
4807 0 : *aVisibility = false;
4808 :
4809 0 : if (!mContentViewer)
4810 0 : return NS_OK;
4811 :
4812 0 : nsCOMPtr<nsIPresShell> presShell;
4813 0 : GetPresShell(getter_AddRefs(presShell));
4814 0 : if (!presShell)
4815 0 : return NS_OK;
4816 :
4817 : // get the view manager
4818 0 : nsIViewManager* vm = presShell->GetViewManager();
4819 0 : NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
4820 :
4821 : // get the root view
4822 0 : nsIView *view = vm->GetRootView(); // views are not ref counted
4823 0 : NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
4824 :
4825 : // if our root view is hidden, we are not visible
4826 0 : if (view->GetVisibility() == nsViewVisibility_kHide)
4827 0 : return NS_OK;
4828 :
4829 : // otherwise, we must walk up the document and view trees checking
4830 : // for a hidden view, unless we're an off screen browser, which
4831 : // would make this test meaningless.
4832 :
4833 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
4834 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
4835 0 : treeItem->GetParent(getter_AddRefs(parentItem));
4836 0 : while (parentItem) {
4837 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem));
4838 0 : docShell->GetPresShell(getter_AddRefs(presShell));
4839 :
4840 0 : nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem);
4841 0 : nsCOMPtr<nsIPresShell> pPresShell;
4842 0 : parentDS->GetPresShell(getter_AddRefs(pPresShell));
4843 :
4844 : // Null-check for crash in bug 267804
4845 0 : if (!pPresShell) {
4846 0 : NS_NOTREACHED("parent docshell has null pres shell");
4847 0 : return NS_OK;
4848 : }
4849 :
4850 : nsIContent *shellContent =
4851 0 : pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument());
4852 0 : NS_ASSERTION(shellContent, "subshell not in the map");
4853 :
4854 0 : nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nsnull;
4855 0 : bool isDocShellOffScreen = false;
4856 0 : docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
4857 0 : if (frame &&
4858 0 : !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
4859 0 : !isDocShellOffScreen) {
4860 0 : return NS_OK;
4861 : }
4862 :
4863 0 : treeItem = parentItem;
4864 0 : treeItem->GetParent(getter_AddRefs(parentItem));
4865 : }
4866 :
4867 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
4868 0 : if (!treeOwnerAsWin) {
4869 0 : *aVisibility = true;
4870 0 : return NS_OK;
4871 : }
4872 :
4873 : // Check with the tree owner as well to give embedders a chance to
4874 : // expose visibility as well.
4875 0 : return treeOwnerAsWin->GetVisibility(aVisibility);
4876 : }
4877 :
4878 : NS_IMETHODIMP
4879 0 : nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen)
4880 : {
4881 0 : mIsOffScreenBrowser = aIsOffScreen;
4882 0 : return NS_OK;
4883 : }
4884 :
4885 : NS_IMETHODIMP
4886 0 : nsDocShell::GetIsOffScreenBrowser(bool *aIsOffScreen)
4887 : {
4888 0 : *aIsOffScreen = mIsOffScreenBrowser;
4889 0 : return NS_OK;
4890 : }
4891 :
4892 : NS_IMETHODIMP
4893 0 : nsDocShell::SetIsActive(bool aIsActive)
4894 : {
4895 : // We disallow setting active on chrome docshells.
4896 0 : if (mItemType == nsIDocShellTreeItem::typeChrome)
4897 0 : return NS_ERROR_INVALID_ARG;
4898 :
4899 : // Keep track ourselves.
4900 0 : mIsActive = aIsActive;
4901 :
4902 : // Tell the PresShell about it.
4903 0 : nsCOMPtr<nsIPresShell> pshell;
4904 0 : GetPresShell(getter_AddRefs(pshell));
4905 0 : if (pshell)
4906 0 : pshell->SetIsActive(aIsActive);
4907 :
4908 : // Tell the window about it
4909 0 : nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mScriptGlobal);
4910 0 : if (win) {
4911 0 : win->SetIsBackground(!aIsActive);
4912 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
4913 0 : if (doc) {
4914 0 : doc->PostVisibilityUpdateEvent();
4915 : }
4916 : }
4917 :
4918 : // Recursively tell all of our children
4919 0 : PRInt32 n = mChildList.Count();
4920 0 : for (PRInt32 i = 0; i < n; ++i) {
4921 0 : nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(ChildAt(i));
4922 0 : if (docshell)
4923 0 : docshell->SetIsActive(aIsActive);
4924 : }
4925 :
4926 0 : return NS_OK;
4927 : }
4928 :
4929 : NS_IMETHODIMP
4930 0 : nsDocShell::GetIsActive(bool *aIsActive)
4931 : {
4932 0 : *aIsActive = mIsActive;
4933 0 : return NS_OK;
4934 : }
4935 :
4936 : NS_IMETHODIMP
4937 0 : nsDocShell::SetIsAppTab(bool aIsAppTab)
4938 : {
4939 0 : mIsAppTab = aIsAppTab;
4940 0 : return NS_OK;
4941 : }
4942 :
4943 : NS_IMETHODIMP
4944 0 : nsDocShell::GetIsAppTab(bool *aIsAppTab)
4945 : {
4946 0 : *aIsAppTab = mIsAppTab;
4947 0 : return NS_OK;
4948 : }
4949 :
4950 : NS_IMETHODIMP
4951 0 : nsDocShell::SetVisibility(bool aVisibility)
4952 : {
4953 0 : if (!mContentViewer)
4954 0 : return NS_OK;
4955 0 : if (aVisibility) {
4956 0 : mContentViewer->Show();
4957 : }
4958 : else {
4959 0 : mContentViewer->Hide();
4960 : }
4961 :
4962 0 : return NS_OK;
4963 : }
4964 :
4965 : NS_IMETHODIMP
4966 0 : nsDocShell::GetEnabled(bool *aEnabled)
4967 : {
4968 0 : NS_ENSURE_ARG_POINTER(aEnabled);
4969 0 : *aEnabled = true;
4970 0 : return NS_ERROR_NOT_IMPLEMENTED;
4971 : }
4972 :
4973 : NS_IMETHODIMP
4974 0 : nsDocShell::SetEnabled(bool aEnabled)
4975 : {
4976 0 : return NS_ERROR_NOT_IMPLEMENTED;
4977 : }
4978 :
4979 : NS_IMETHODIMP
4980 0 : nsDocShell::SetFocus()
4981 : {
4982 0 : return NS_OK;
4983 : }
4984 :
4985 : NS_IMETHODIMP
4986 0 : nsDocShell::GetMainWidget(nsIWidget ** aMainWidget)
4987 : {
4988 : // We don't create our own widget, so simply return the parent one.
4989 0 : return GetParentWidget(aMainWidget);
4990 : }
4991 :
4992 : NS_IMETHODIMP
4993 0 : nsDocShell::GetTitle(PRUnichar ** aTitle)
4994 : {
4995 0 : NS_ENSURE_ARG_POINTER(aTitle);
4996 :
4997 0 : *aTitle = ToNewUnicode(mTitle);
4998 0 : return NS_OK;
4999 : }
5000 :
5001 : NS_IMETHODIMP
5002 0 : nsDocShell::SetTitle(const PRUnichar * aTitle)
5003 : {
5004 : // Store local title
5005 0 : mTitle = aTitle;
5006 :
5007 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
5008 0 : GetSameTypeParent(getter_AddRefs(parent));
5009 :
5010 : // When title is set on the top object it should then be passed to the
5011 : // tree owner.
5012 0 : if (!parent) {
5013 : nsCOMPtr<nsIBaseWindow>
5014 0 : treeOwnerAsWin(do_QueryInterface(mTreeOwner));
5015 0 : if (treeOwnerAsWin)
5016 0 : treeOwnerAsWin->SetTitle(aTitle);
5017 : }
5018 :
5019 0 : if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE && mUseGlobalHistory) {
5020 0 : nsCOMPtr<IHistory> history = services::GetHistoryService();
5021 0 : if (history) {
5022 0 : history->SetURITitle(mCurrentURI, mTitle);
5023 : }
5024 0 : else if (mGlobalHistory) {
5025 0 : mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
5026 : }
5027 : }
5028 :
5029 : // Update SessionHistory with the document's title.
5030 0 : if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
5031 : mLoadType != LOAD_ERROR_PAGE) {
5032 :
5033 0 : mOSHE->SetTitle(mTitle);
5034 : }
5035 :
5036 0 : return NS_OK;
5037 : }
5038 :
5039 : //*****************************************************************************
5040 : // nsDocShell::nsIScrollable
5041 : //*****************************************************************************
5042 :
5043 : NS_IMETHODIMP
5044 0 : nsDocShell::GetCurScrollPos(PRInt32 scrollOrientation, PRInt32 * curPos)
5045 : {
5046 0 : NS_ENSURE_ARG_POINTER(curPos);
5047 :
5048 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5049 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5050 :
5051 0 : nsPoint pt = sf->GetScrollPosition();
5052 :
5053 0 : switch (scrollOrientation) {
5054 : case ScrollOrientation_X:
5055 0 : *curPos = pt.x;
5056 0 : return NS_OK;
5057 :
5058 : case ScrollOrientation_Y:
5059 0 : *curPos = pt.y;
5060 0 : return NS_OK;
5061 :
5062 : default:
5063 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5064 : }
5065 : }
5066 :
5067 : NS_IMETHODIMP
5068 0 : nsDocShell::SetCurScrollPos(PRInt32 scrollOrientation, PRInt32 curPos)
5069 : {
5070 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5071 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5072 :
5073 0 : nsPoint pt = sf->GetScrollPosition();
5074 :
5075 0 : switch (scrollOrientation) {
5076 : case ScrollOrientation_X:
5077 0 : pt.x = curPos;
5078 0 : break;
5079 :
5080 : case ScrollOrientation_Y:
5081 0 : pt.y = curPos;
5082 0 : break;
5083 :
5084 : default:
5085 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5086 : }
5087 :
5088 0 : sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
5089 0 : return NS_OK;
5090 : }
5091 :
5092 : NS_IMETHODIMP
5093 0 : nsDocShell::SetCurScrollPosEx(PRInt32 curHorizontalPos, PRInt32 curVerticalPos)
5094 : {
5095 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5096 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5097 :
5098 : sf->ScrollTo(nsPoint(curHorizontalPos, curVerticalPos),
5099 0 : nsIScrollableFrame::INSTANT);
5100 0 : return NS_OK;
5101 : }
5102 :
5103 : // XXX This is wrong
5104 : NS_IMETHODIMP
5105 0 : nsDocShell::GetScrollRange(PRInt32 scrollOrientation,
5106 : PRInt32 * minPos, PRInt32 * maxPos)
5107 : {
5108 0 : NS_ENSURE_ARG_POINTER(minPos && maxPos);
5109 :
5110 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5111 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5112 :
5113 0 : nsSize portSize = sf->GetScrollPortRect().Size();
5114 0 : nsRect range = sf->GetScrollRange();
5115 :
5116 0 : switch (scrollOrientation) {
5117 : case ScrollOrientation_X:
5118 0 : *minPos = range.x;
5119 0 : *maxPos = range.XMost() + portSize.width;
5120 0 : return NS_OK;
5121 :
5122 : case ScrollOrientation_Y:
5123 0 : *minPos = range.y;
5124 0 : *maxPos = range.YMost() + portSize.height;
5125 0 : return NS_OK;
5126 :
5127 : default:
5128 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5129 : }
5130 : }
5131 :
5132 : NS_IMETHODIMP
5133 0 : nsDocShell::SetScrollRange(PRInt32 scrollOrientation,
5134 : PRInt32 minPos, PRInt32 maxPos)
5135 : {
5136 : //XXX First Check
5137 : /*
5138 : Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
5139 : something less than the current thumb position, curPos is set = to maxPos.
5140 :
5141 : @return NS_OK - Setting or Getting completed successfully.
5142 : NS_ERROR_INVALID_ARG - returned when curPos is not within the
5143 : minPos and maxPos.
5144 : */
5145 0 : return NS_ERROR_FAILURE;
5146 : }
5147 :
5148 : NS_IMETHODIMP
5149 0 : nsDocShell::SetScrollRangeEx(PRInt32 minHorizontalPos,
5150 : PRInt32 maxHorizontalPos, PRInt32 minVerticalPos,
5151 : PRInt32 maxVerticalPos)
5152 : {
5153 : //XXX First Check
5154 : /*
5155 : Retrieves or Sets the valid ranges for the thumb. When maxPos is set to
5156 : something less than the current thumb position, curPos is set = to maxPos.
5157 :
5158 : @return NS_OK - Setting or Getting completed successfully.
5159 : NS_ERROR_INVALID_ARG - returned when curPos is not within the
5160 : minPos and maxPos.
5161 : */
5162 0 : return NS_ERROR_FAILURE;
5163 : }
5164 :
5165 : // This returns setting for all documents in this docshell
5166 : NS_IMETHODIMP
5167 0 : nsDocShell::GetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
5168 : PRInt32 * scrollbarPref)
5169 : {
5170 0 : NS_ENSURE_ARG_POINTER(scrollbarPref);
5171 0 : switch (scrollOrientation) {
5172 : case ScrollOrientation_X:
5173 0 : *scrollbarPref = mDefaultScrollbarPref.x;
5174 0 : return NS_OK;
5175 :
5176 : case ScrollOrientation_Y:
5177 0 : *scrollbarPref = mDefaultScrollbarPref.y;
5178 0 : return NS_OK;
5179 :
5180 : default:
5181 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5182 : }
5183 : return NS_ERROR_FAILURE;
5184 : }
5185 :
5186 : // Set scrolling preference for all documents in this shell
5187 : //
5188 : // There are three possible values stored in the shell:
5189 : // 1) nsIScrollable::Scrollbar_Never = no scrollbar
5190 : // 2) nsIScrollable::Scrollbar_Auto = scrollbar appears if the document
5191 : // being displayed would normally have scrollbar
5192 : // 3) nsIScrollable::Scrollbar_Always = scrollbar always appears
5193 : //
5194 : // One important client is nsHTMLFrameInnerFrame::CreateWebShell()
5195 : NS_IMETHODIMP
5196 0 : nsDocShell::SetDefaultScrollbarPreferences(PRInt32 scrollOrientation,
5197 : PRInt32 scrollbarPref)
5198 : {
5199 0 : switch (scrollOrientation) {
5200 : case ScrollOrientation_X:
5201 0 : mDefaultScrollbarPref.x = scrollbarPref;
5202 0 : return NS_OK;
5203 :
5204 : case ScrollOrientation_Y:
5205 0 : mDefaultScrollbarPref.y = scrollbarPref;
5206 0 : return NS_OK;
5207 :
5208 : default:
5209 0 : NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
5210 : }
5211 : return NS_ERROR_FAILURE;
5212 : }
5213 :
5214 : NS_IMETHODIMP
5215 0 : nsDocShell::GetScrollbarVisibility(bool * verticalVisible,
5216 : bool * horizontalVisible)
5217 : {
5218 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5219 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5220 :
5221 0 : PRUint32 scrollbarVisibility = sf->GetScrollbarVisibility();
5222 0 : if (verticalVisible)
5223 0 : *verticalVisible = (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
5224 0 : if (horizontalVisible)
5225 0 : *horizontalVisible = (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
5226 :
5227 0 : return NS_OK;
5228 : }
5229 :
5230 : //*****************************************************************************
5231 : // nsDocShell::nsITextScroll
5232 : //*****************************************************************************
5233 :
5234 : NS_IMETHODIMP
5235 0 : nsDocShell::ScrollByLines(PRInt32 numLines)
5236 : {
5237 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5238 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5239 :
5240 : sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
5241 0 : nsIScrollableFrame::SMOOTH);
5242 0 : return NS_OK;
5243 : }
5244 :
5245 : NS_IMETHODIMP
5246 0 : nsDocShell::ScrollByPages(PRInt32 numPages)
5247 : {
5248 0 : nsIScrollableFrame* sf = GetRootScrollFrame();
5249 0 : NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
5250 :
5251 : sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
5252 0 : nsIScrollableFrame::SMOOTH);
5253 0 : return NS_OK;
5254 : }
5255 :
5256 : //*****************************************************************************
5257 : // nsDocShell::nsIScriptGlobalObjectOwner
5258 : //*****************************************************************************
5259 :
5260 : nsIScriptGlobalObject*
5261 0 : nsDocShell::GetScriptGlobalObject()
5262 : {
5263 0 : NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nsnull);
5264 :
5265 0 : return mScriptGlobal;
5266 : }
5267 :
5268 : //*****************************************************************************
5269 : // nsDocShell::nsIRefreshURI
5270 : //*****************************************************************************
5271 :
5272 : NS_IMETHODIMP
5273 0 : nsDocShell::RefreshURI(nsIURI * aURI, PRInt32 aDelay, bool aRepeat,
5274 : bool aMetaRefresh)
5275 : {
5276 0 : NS_ENSURE_ARG(aURI);
5277 :
5278 : /* Check if Meta refresh/redirects are permitted. Some
5279 : * embedded applications may not want to do this.
5280 : * Must do this before sending out NOTIFY_REFRESH events
5281 : * because listeners may have side effects (e.g. displaying a
5282 : * button to manually trigger the refresh later).
5283 : */
5284 0 : bool allowRedirects = true;
5285 0 : GetAllowMetaRedirects(&allowRedirects);
5286 0 : if (!allowRedirects)
5287 0 : return NS_OK;
5288 :
5289 : // If any web progress listeners are listening for NOTIFY_REFRESH events,
5290 : // give them a chance to block this refresh.
5291 : bool sameURI;
5292 0 : nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
5293 0 : if (NS_FAILED(rv))
5294 0 : sameURI = false;
5295 0 : if (!RefreshAttempted(this, aURI, aDelay, sameURI))
5296 0 : return NS_OK;
5297 :
5298 0 : nsRefreshTimer *refreshTimer = new nsRefreshTimer();
5299 0 : NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
5300 0 : PRUint32 busyFlags = 0;
5301 0 : GetBusyFlags(&busyFlags);
5302 :
5303 0 : nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1
5304 :
5305 0 : refreshTimer->mDocShell = this;
5306 0 : refreshTimer->mURI = aURI;
5307 0 : refreshTimer->mDelay = aDelay;
5308 0 : refreshTimer->mRepeat = aRepeat;
5309 0 : refreshTimer->mMetaRefresh = aMetaRefresh;
5310 :
5311 0 : if (!mRefreshURIList) {
5312 0 : NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
5313 : NS_ERROR_FAILURE);
5314 : }
5315 :
5316 0 : if (busyFlags & BUSY_FLAGS_BUSY) {
5317 : // We are busy loading another page. Don't create the
5318 : // timer right now. Instead queue up the request and trigger the
5319 : // timer in EndPageLoad().
5320 0 : mRefreshURIList->AppendElement(refreshTimer);
5321 : }
5322 : else {
5323 : // There is no page loading going on right now. Create the
5324 : // timer and fire it right away.
5325 0 : nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
5326 0 : NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
5327 :
5328 0 : mRefreshURIList->AppendElement(timer); // owning timer ref
5329 0 : timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
5330 : }
5331 0 : return NS_OK;
5332 : }
5333 :
5334 : nsresult
5335 0 : nsDocShell::ForceRefreshURIFromTimer(nsIURI * aURI,
5336 : PRInt32 aDelay,
5337 : bool aMetaRefresh,
5338 : nsITimer* aTimer)
5339 : {
5340 0 : NS_PRECONDITION(aTimer, "Must have a timer here");
5341 :
5342 : // Remove aTimer from mRefreshURIList if needed
5343 0 : if (mRefreshURIList) {
5344 0 : PRUint32 n = 0;
5345 0 : mRefreshURIList->Count(&n);
5346 :
5347 0 : for (PRUint32 i = 0; i < n; ++i) {
5348 0 : nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
5349 0 : if (timer == aTimer) {
5350 0 : mRefreshURIList->RemoveElementAt(i);
5351 : break;
5352 : }
5353 : }
5354 : }
5355 :
5356 0 : return ForceRefreshURI(aURI, aDelay, aMetaRefresh);
5357 : }
5358 :
5359 : NS_IMETHODIMP
5360 0 : nsDocShell::ForceRefreshURI(nsIURI * aURI,
5361 : PRInt32 aDelay,
5362 : bool aMetaRefresh)
5363 : {
5364 0 : NS_ENSURE_ARG(aURI);
5365 :
5366 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
5367 0 : CreateLoadInfo(getter_AddRefs(loadInfo));
5368 0 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
5369 :
5370 : /* We do need to pass in a referrer, but we don't want it to
5371 : * be sent to the server.
5372 : */
5373 0 : loadInfo->SetSendReferrer(false);
5374 :
5375 : /* for most refreshes the current URI is an appropriate
5376 : * internal referrer
5377 : */
5378 0 : loadInfo->SetReferrer(mCurrentURI);
5379 :
5380 : /* Don't ever "guess" on which owner to use to avoid picking
5381 : * the current owner.
5382 : */
5383 0 : loadInfo->SetOwnerIsExplicit(true);
5384 :
5385 : /* Check if this META refresh causes a redirection
5386 : * to another site.
5387 : */
5388 0 : bool equalUri = false;
5389 0 : nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
5390 0 : if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
5391 : aDelay <= REFRESH_REDIRECT_TIMER) {
5392 :
5393 : /* It is a META refresh based redirection within the threshold time
5394 : * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
5395 : * Pass a REPLACE flag to LoadURI().
5396 : */
5397 0 : loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
5398 :
5399 : /* for redirects we mimic HTTP, which passes the
5400 : * original referrer
5401 : */
5402 0 : nsCOMPtr<nsIURI> internalReferrer;
5403 0 : GetReferringURI(getter_AddRefs(internalReferrer));
5404 0 : if (internalReferrer) {
5405 0 : loadInfo->SetReferrer(internalReferrer);
5406 0 : }
5407 : }
5408 : else {
5409 0 : loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
5410 : }
5411 :
5412 : /*
5413 : * LoadURI(...) will cancel all refresh timers... This causes the
5414 : * Timer and its refreshData instance to be released...
5415 : */
5416 0 : LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
5417 :
5418 0 : return NS_OK;
5419 : }
5420 :
5421 : nsresult
5422 0 : nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
5423 : const nsACString & aHeader)
5424 : {
5425 : // Refresh headers are parsed with the following format in mind
5426 : // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
5427 : // By the time we are here, the following is true:
5428 : // header = "REFRESH"
5429 : // content = "5; URL=http://uri" // note the URL attribute is
5430 : // optional, if it is absent, the currently loaded url is used.
5431 : // Also note that the seconds and URL separator can be either
5432 : // a ';' or a ','. The ',' separator should be illegal but CNN
5433 : // is using it.
5434 : //
5435 : // We need to handle the following strings, where
5436 : // - X is a set of digits
5437 : // - URI is either a relative or absolute URI
5438 : //
5439 : // Note that URI should start with "url=" but we allow omission
5440 : //
5441 : // "" || ";" || ","
5442 : // empty string. use the currently loaded URI
5443 : // and refresh immediately.
5444 : // "X" || "X;" || "X,"
5445 : // Refresh the currently loaded URI in X seconds.
5446 : // "X; URI" || "X, URI"
5447 : // Refresh using URI as the destination in X seconds.
5448 : // "URI" || "; URI" || ", URI"
5449 : // Refresh immediately using URI as the destination.
5450 : //
5451 : // Currently, anything immediately following the URI, if
5452 : // separated by any char in the set "'\"\t\r\n " will be
5453 : // ignored. So "10; url=go.html ; foo=bar" will work,
5454 : // and so will "10; url='go.html'; foo=bar". However,
5455 : // "10; url=go.html; foo=bar" will result in the uri
5456 : // "go.html;" since ';' and ',' are valid uri characters.
5457 : //
5458 : // Note that we need to remove any tokens wrapping the URI.
5459 : // These tokens currently include spaces, double and single
5460 : // quotes.
5461 :
5462 : // when done, seconds is 0 or the given number of seconds
5463 : // uriAttrib is empty or the URI specified
5464 0 : nsCAutoString uriAttrib;
5465 0 : PRInt32 seconds = 0;
5466 0 : bool specifiesSeconds = false;
5467 :
5468 0 : nsACString::const_iterator iter, tokenStart, doneIterating;
5469 :
5470 0 : aHeader.BeginReading(iter);
5471 0 : aHeader.EndReading(doneIterating);
5472 :
5473 : // skip leading whitespace
5474 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
5475 0 : ++iter;
5476 :
5477 0 : tokenStart = iter;
5478 :
5479 : // skip leading + and -
5480 0 : if (iter != doneIterating && (*iter == '-' || *iter == '+'))
5481 0 : ++iter;
5482 :
5483 : // parse number
5484 0 : while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
5485 0 : seconds = seconds * 10 + (*iter - '0');
5486 0 : specifiesSeconds = true;
5487 0 : ++iter;
5488 : }
5489 :
5490 0 : if (iter != doneIterating) {
5491 : // if we started with a '-', number is negative
5492 0 : if (*tokenStart == '-')
5493 0 : seconds = -seconds;
5494 :
5495 : // skip to next ';' or ','
5496 0 : nsACString::const_iterator iterAfterDigit = iter;
5497 0 : while (iter != doneIterating && !(*iter == ';' || *iter == ','))
5498 : {
5499 0 : if (specifiesSeconds)
5500 : {
5501 : // Non-whitespace characters here mean that the string is
5502 : // malformed but tolerate sites that specify a decimal point,
5503 : // even though meta refresh only works on whole seconds.
5504 0 : if (iter == iterAfterDigit &&
5505 0 : !nsCRT::IsAsciiSpace(*iter) && *iter != '.')
5506 : {
5507 : // The characters between the seconds and the next
5508 : // section are just garbage!
5509 : // e.g. content="2a0z+,URL=http://www.mozilla.org/"
5510 : // Just ignore this redirect.
5511 0 : return NS_ERROR_FAILURE;
5512 : }
5513 0 : else if (nsCRT::IsAsciiSpace(*iter))
5514 : {
5515 : // We've had at least one whitespace so tolerate the mistake
5516 : // and drop through.
5517 : // e.g. content="10 foo"
5518 0 : ++iter;
5519 0 : break;
5520 : }
5521 : }
5522 0 : ++iter;
5523 : }
5524 :
5525 : // skip any remaining whitespace
5526 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
5527 0 : ++iter;
5528 :
5529 : // skip ';' or ','
5530 0 : if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
5531 0 : ++iter;
5532 : }
5533 :
5534 : // skip whitespace
5535 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
5536 0 : ++iter;
5537 : }
5538 :
5539 : // possible start of URI
5540 0 : tokenStart = iter;
5541 :
5542 : // skip "url = " to real start of URI
5543 0 : if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
5544 0 : ++iter;
5545 0 : if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
5546 0 : ++iter;
5547 0 : if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
5548 0 : ++iter;
5549 :
5550 : // skip whitespace
5551 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
5552 0 : ++iter;
5553 :
5554 0 : if (iter != doneIterating && *iter == '=') {
5555 0 : ++iter;
5556 :
5557 : // skip whitespace
5558 0 : while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter))
5559 0 : ++iter;
5560 :
5561 : // found real start of URI
5562 0 : tokenStart = iter;
5563 : }
5564 : }
5565 : }
5566 : }
5567 :
5568 : // skip a leading '"' or '\''.
5569 :
5570 0 : bool isQuotedURI = false;
5571 0 : if (tokenStart != doneIterating && (*tokenStart == '"' || *tokenStart == '\''))
5572 : {
5573 0 : isQuotedURI = true;
5574 0 : ++tokenStart;
5575 : }
5576 :
5577 : // set iter to start of URI
5578 0 : iter = tokenStart;
5579 :
5580 : // tokenStart here points to the beginning of URI
5581 :
5582 : // grab the rest of the URI
5583 0 : while (iter != doneIterating)
5584 : {
5585 0 : if (isQuotedURI && (*iter == '"' || *iter == '\''))
5586 0 : break;
5587 0 : ++iter;
5588 : }
5589 :
5590 : // move iter one back if the last character is a '"' or '\''
5591 0 : if (iter != tokenStart && isQuotedURI) {
5592 0 : --iter;
5593 0 : if (!(*iter == '"' || *iter == '\''))
5594 0 : ++iter;
5595 : }
5596 :
5597 : // URI is whatever's contained from tokenStart to iter.
5598 : // note: if tokenStart == doneIterating, so is iter.
5599 :
5600 0 : nsresult rv = NS_OK;
5601 :
5602 0 : nsCOMPtr<nsIURI> uri;
5603 0 : bool specifiesURI = false;
5604 0 : if (tokenStart == iter) {
5605 0 : uri = aBaseURI;
5606 : }
5607 : else {
5608 0 : uriAttrib = Substring(tokenStart, iter);
5609 : // NS_NewURI takes care of any whitespace surrounding the URL
5610 0 : rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nsnull, aBaseURI);
5611 0 : specifiesURI = true;
5612 : }
5613 :
5614 : // No URI or seconds were specified
5615 0 : if (!specifiesSeconds && !specifiesURI)
5616 : {
5617 : // Do nothing because the alternative is to spin around in a refresh
5618 : // loop forever!
5619 0 : return NS_ERROR_FAILURE;
5620 : }
5621 :
5622 0 : if (NS_SUCCEEDED(rv)) {
5623 : nsCOMPtr<nsIScriptSecurityManager>
5624 : securityManager(do_GetService
5625 0 : (NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
5626 0 : if (NS_SUCCEEDED(rv)) {
5627 0 : rv = securityManager->
5628 : CheckLoadURI(aBaseURI, uri,
5629 : nsIScriptSecurityManager::
5630 0 : LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
5631 :
5632 0 : if (NS_SUCCEEDED(rv)) {
5633 0 : bool isjs = true;
5634 : rv = NS_URIChainHasFlags(uri,
5635 0 : nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
5636 0 : NS_ENSURE_SUCCESS(rv, rv);
5637 :
5638 0 : if (isjs) {
5639 0 : return NS_ERROR_FAILURE;
5640 : }
5641 : }
5642 :
5643 0 : if (NS_SUCCEEDED(rv)) {
5644 : // Since we can't travel back in time yet, just pretend
5645 : // negative numbers do nothing at all.
5646 0 : if (seconds < 0)
5647 0 : return NS_ERROR_FAILURE;
5648 :
5649 0 : rv = RefreshURI(uri, seconds * 1000, false, true);
5650 : }
5651 : }
5652 : }
5653 0 : return rv;
5654 : }
5655 :
5656 0 : NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel)
5657 : {
5658 : nsresult rv;
5659 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
5660 0 : if (NS_SUCCEEDED(rv)) {
5661 0 : nsCAutoString refreshHeader;
5662 0 : rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
5663 0 : refreshHeader);
5664 :
5665 0 : if (!refreshHeader.IsEmpty()) {
5666 0 : SetupReferrerFromChannel(aChannel);
5667 0 : rv = SetupRefreshURIFromHeader(mCurrentURI, refreshHeader);
5668 0 : if (NS_SUCCEEDED(rv)) {
5669 0 : return NS_REFRESHURI_HEADER_FOUND;
5670 : }
5671 : }
5672 : }
5673 0 : return rv;
5674 : }
5675 :
5676 : static void
5677 0 : DoCancelRefreshURITimers(nsISupportsArray* aTimerList)
5678 : {
5679 0 : if (!aTimerList)
5680 0 : return;
5681 :
5682 0 : PRUint32 n=0;
5683 0 : aTimerList->Count(&n);
5684 :
5685 0 : while (n) {
5686 0 : nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
5687 :
5688 0 : aTimerList->RemoveElementAt(n); // bye bye owning timer ref
5689 :
5690 0 : if (timer)
5691 0 : timer->Cancel();
5692 : }
5693 : }
5694 :
5695 : NS_IMETHODIMP
5696 0 : nsDocShell::CancelRefreshURITimers()
5697 : {
5698 0 : DoCancelRefreshURITimers(mRefreshURIList);
5699 0 : DoCancelRefreshURITimers(mSavedRefreshURIList);
5700 0 : mRefreshURIList = nsnull;
5701 0 : mSavedRefreshURIList = nsnull;
5702 :
5703 0 : return NS_OK;
5704 : }
5705 :
5706 : NS_IMETHODIMP
5707 0 : nsDocShell::GetRefreshPending(bool* _retval)
5708 : {
5709 0 : if (!mRefreshURIList) {
5710 0 : *_retval = false;
5711 0 : return NS_OK;
5712 : }
5713 :
5714 : PRUint32 count;
5715 0 : nsresult rv = mRefreshURIList->Count(&count);
5716 0 : if (NS_SUCCEEDED(rv))
5717 0 : *_retval = (count != 0);
5718 0 : return rv;
5719 : }
5720 :
5721 : NS_IMETHODIMP
5722 0 : nsDocShell::SuspendRefreshURIs()
5723 : {
5724 0 : if (mRefreshURIList) {
5725 0 : PRUint32 n = 0;
5726 0 : mRefreshURIList->Count(&n);
5727 :
5728 0 : for (PRUint32 i = 0; i < n; ++i) {
5729 0 : nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
5730 0 : if (!timer)
5731 0 : continue; // this must be a nsRefreshURI already
5732 :
5733 : // Replace this timer object with a nsRefreshTimer object.
5734 0 : nsCOMPtr<nsITimerCallback> callback;
5735 0 : timer->GetCallback(getter_AddRefs(callback));
5736 :
5737 0 : timer->Cancel();
5738 :
5739 0 : nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
5740 0 : NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects");
5741 :
5742 0 : mRefreshURIList->ReplaceElementAt(rt, i);
5743 : }
5744 : }
5745 :
5746 : // Suspend refresh URIs for our child shells as well.
5747 0 : PRInt32 n = mChildList.Count();
5748 :
5749 0 : for (PRInt32 i = 0; i < n; ++i) {
5750 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
5751 0 : if (shell)
5752 0 : shell->SuspendRefreshURIs();
5753 : }
5754 :
5755 0 : return NS_OK;
5756 : }
5757 :
5758 : NS_IMETHODIMP
5759 0 : nsDocShell::ResumeRefreshURIs()
5760 : {
5761 0 : RefreshURIFromQueue();
5762 :
5763 : // Resume refresh URIs for our child shells as well.
5764 0 : PRInt32 n = mChildList.Count();
5765 :
5766 0 : for (PRInt32 i = 0; i < n; ++i) {
5767 0 : nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
5768 0 : if (shell)
5769 0 : shell->ResumeRefreshURIs();
5770 : }
5771 :
5772 0 : return NS_OK;
5773 : }
5774 :
5775 : nsresult
5776 0 : nsDocShell::RefreshURIFromQueue()
5777 : {
5778 0 : if (!mRefreshURIList)
5779 0 : return NS_OK;
5780 0 : PRUint32 n = 0;
5781 0 : mRefreshURIList->Count(&n);
5782 :
5783 0 : while (n) {
5784 0 : nsCOMPtr<nsISupports> element;
5785 0 : mRefreshURIList->GetElementAt(--n, getter_AddRefs(element));
5786 0 : nsCOMPtr<nsITimerCallback> refreshInfo(do_QueryInterface(element));
5787 :
5788 0 : if (refreshInfo) {
5789 : // This is the nsRefreshTimer object, waiting to be
5790 : // setup in a timer object and fired.
5791 : // Create the timer and trigger it.
5792 0 : PRUint32 delay = static_cast<nsRefreshTimer*>(static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
5793 0 : nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
5794 0 : if (timer) {
5795 : // Replace the nsRefreshTimer element in the queue with
5796 : // its corresponding timer object, so that in case another
5797 : // load comes through before the timer can go off, the timer will
5798 : // get cancelled in CancelRefreshURITimer()
5799 0 : mRefreshURIList->ReplaceElementAt(timer, n);
5800 0 : timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
5801 : }
5802 : }
5803 : } // while
5804 :
5805 0 : return NS_OK;
5806 : }
5807 :
5808 : //*****************************************************************************
5809 : // nsDocShell::nsIContentViewerContainer
5810 : //*****************************************************************************
5811 :
5812 : NS_IMETHODIMP
5813 0 : nsDocShell::Embed(nsIContentViewer * aContentViewer,
5814 : const char *aCommand, nsISupports * aExtraInfo)
5815 : {
5816 : // Save the LayoutHistoryState of the previous document, before
5817 : // setting up new document
5818 0 : PersistLayoutHistoryState();
5819 :
5820 0 : nsresult rv = SetupNewViewer(aContentViewer);
5821 :
5822 : // If we are loading a wyciwyg url from history, change the base URI for
5823 : // the document to the original http url that created the document.write().
5824 : // This makes sure that all relative urls in a document.written page loaded
5825 : // via history work properly.
5826 0 : if (mCurrentURI &&
5827 : (mLoadType & LOAD_CMD_HISTORY ||
5828 : mLoadType == LOAD_RELOAD_NORMAL ||
5829 0 : mLoadType == LOAD_RELOAD_CHARSET_CHANGE)){
5830 0 : bool isWyciwyg = false;
5831 : // Check if the url is wyciwyg
5832 0 : rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
5833 0 : if (isWyciwyg && NS_SUCCEEDED(rv))
5834 0 : SetBaseUrlForWyciwyg(aContentViewer);
5835 : }
5836 : // XXX What if SetupNewViewer fails?
5837 0 : if (mLSHE) {
5838 : // Restore the editing state, if it's stored in session history.
5839 0 : if (mLSHE->HasDetachedEditor()) {
5840 0 : ReattachEditorToWindow(mLSHE);
5841 : }
5842 : // Set history.state
5843 0 : SetDocCurrentStateObj(mLSHE);
5844 :
5845 0 : SetHistoryEntry(&mOSHE, mLSHE);
5846 : }
5847 :
5848 0 : bool updateHistory = true;
5849 :
5850 : // Determine if this type of load should update history
5851 0 : switch (mLoadType) {
5852 : case LOAD_NORMAL_REPLACE:
5853 : case LOAD_STOP_CONTENT_AND_REPLACE:
5854 : case LOAD_RELOAD_BYPASS_CACHE:
5855 : case LOAD_RELOAD_BYPASS_PROXY:
5856 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
5857 0 : updateHistory = false;
5858 0 : break;
5859 : default:
5860 0 : break;
5861 : }
5862 :
5863 0 : if (!updateHistory)
5864 0 : SetLayoutHistoryState(nsnull);
5865 :
5866 0 : return NS_OK;
5867 : }
5868 :
5869 : /* void setIsPrinting (in boolean aIsPrinting); */
5870 : NS_IMETHODIMP
5871 0 : nsDocShell::SetIsPrinting(bool aIsPrinting)
5872 : {
5873 0 : mIsPrintingOrPP = aIsPrinting;
5874 0 : return NS_OK;
5875 : }
5876 :
5877 : //*****************************************************************************
5878 : // nsDocShell::nsIWebProgressListener
5879 : //*****************************************************************************
5880 :
5881 : NS_IMETHODIMP
5882 0 : nsDocShell::OnProgressChange(nsIWebProgress * aProgress,
5883 : nsIRequest * aRequest,
5884 : PRInt32 aCurSelfProgress,
5885 : PRInt32 aMaxSelfProgress,
5886 : PRInt32 aCurTotalProgress,
5887 : PRInt32 aMaxTotalProgress)
5888 : {
5889 0 : return NS_OK;
5890 : }
5891 :
5892 : NS_IMETHODIMP
5893 0 : nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
5894 : PRUint32 aStateFlags, nsresult aStatus)
5895 : {
5896 : nsresult rv;
5897 :
5898 0 : if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
5899 : // Save timing statistics.
5900 0 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
5901 0 : nsCOMPtr<nsIURI> uri;
5902 0 : channel->GetURI(getter_AddRefs(uri));
5903 0 : nsCAutoString aURI;
5904 0 : uri->GetAsciiSpec(aURI);
5905 0 : if (this == aProgress){
5906 0 : rv = MaybeInitTiming();
5907 0 : if (mTiming) {
5908 0 : mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType));
5909 : }
5910 : }
5911 :
5912 0 : nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
5913 : nsCOMPtr<nsIWebProgress> webProgress =
5914 0 : do_QueryInterface(GetAsSupports(this));
5915 :
5916 : // Was the wyciwyg document loaded on this docshell?
5917 0 : if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
5918 0 : bool equalUri = true;
5919 : // Store the wyciwyg url in session history, only if it is
5920 : // being loaded fresh for the first time. We don't want
5921 : // multiple entries for successive loads
5922 0 : if (mCurrentURI &&
5923 0 : NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
5924 0 : !equalUri) {
5925 :
5926 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
5927 0 : GetSameTypeParent(getter_AddRefs(parentAsItem));
5928 0 : nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
5929 0 : bool inOnLoadHandler = false;
5930 0 : if (parentDS) {
5931 0 : parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
5932 : }
5933 0 : if (inOnLoadHandler) {
5934 : // We're handling parent's load event listener, which causes
5935 : // document.write in a subdocument.
5936 : // Need to clear the session history for all child
5937 : // docshells so that we can handle them like they would
5938 : // all be added dynamically.
5939 : nsCOMPtr<nsIDocShellHistory> parent =
5940 0 : do_QueryInterface(parentAsItem);
5941 0 : if (parent) {
5942 0 : bool oshe = false;
5943 0 : nsCOMPtr<nsISHEntry> entry;
5944 0 : parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
5945 0 : static_cast<nsDocShell*>(parent.get())->
5946 0 : ClearFrameHistory(entry);
5947 : }
5948 : }
5949 :
5950 : // This is a document.write(). Get the made-up url
5951 : // from the channel and store it in session history.
5952 : // Pass false for aCloneChildren, since we're creating
5953 : // a new DOM here.
5954 : rv = AddToSessionHistory(uri, wcwgChannel, nsnull, false,
5955 0 : getter_AddRefs(mLSHE));
5956 0 : SetCurrentURI(uri, aRequest, true, 0);
5957 : // Save history state of the previous page
5958 0 : rv = PersistLayoutHistoryState();
5959 : // We'll never get an Embed() for this load, so just go ahead
5960 : // and SetHistoryEntry now.
5961 0 : SetHistoryEntry(&mOSHE, mLSHE);
5962 : }
5963 :
5964 : }
5965 : // Page has begun to load
5966 0 : mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
5967 :
5968 0 : if ((aStateFlags & STATE_RESTORING) == 0) {
5969 : // Show the progress cursor if the pref is set
5970 0 : if (Preferences::GetBool("ui.use_activity_cursor", false)) {
5971 0 : nsCOMPtr<nsIWidget> mainWidget;
5972 0 : GetMainWidget(getter_AddRefs(mainWidget));
5973 0 : if (mainWidget) {
5974 0 : mainWidget->SetCursor(eCursor_spinning);
5975 : }
5976 : }
5977 : }
5978 : }
5979 0 : else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
5980 : // Page is loading
5981 0 : mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
5982 : }
5983 0 : else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
5984 : // Page has finished loading
5985 0 : mBusyFlags = BUSY_FLAGS_NONE;
5986 :
5987 : // Hide the progress cursor if the pref is set
5988 0 : if (Preferences::GetBool("ui.use_activity_cursor", false)) {
5989 0 : nsCOMPtr<nsIWidget> mainWidget;
5990 0 : GetMainWidget(getter_AddRefs(mainWidget));
5991 0 : if (mainWidget) {
5992 0 : mainWidget->SetCursor(eCursor_standard);
5993 : }
5994 : }
5995 : }
5996 0 : if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
5997 : nsCOMPtr<nsIWebProgress> webProgress =
5998 0 : do_QueryInterface(GetAsSupports(this));
5999 : // Is the document stop notification for this document?
6000 0 : if (aProgress == webProgress.get()) {
6001 0 : nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
6002 0 : EndPageLoad(aProgress, channel, aStatus);
6003 : }
6004 : }
6005 : // note that redirect state changes will go through here as well, but it
6006 : // is better to handle those in OnRedirectStateChange where more
6007 : // information is available.
6008 0 : return NS_OK;
6009 : }
6010 :
6011 : NS_IMETHODIMP
6012 0 : nsDocShell::OnLocationChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
6013 : nsIURI * aURI, PRUint32 aFlags)
6014 : {
6015 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6016 0 : return NS_OK;
6017 : }
6018 :
6019 : void
6020 0 : nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
6021 : nsIChannel* aNewChannel,
6022 : PRUint32 aRedirectFlags,
6023 : PRUint32 aStateFlags)
6024 : {
6025 0 : NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
6026 : "Calling OnRedirectStateChange when there is no redirect");
6027 0 : if (!(aStateFlags & STATE_IS_DOCUMENT))
6028 0 : return; // not a toplevel document
6029 :
6030 0 : nsCOMPtr<nsIURI> oldURI, newURI;
6031 0 : aOldChannel->GetURI(getter_AddRefs(oldURI));
6032 0 : aNewChannel->GetURI(getter_AddRefs(newURI));
6033 0 : if (!oldURI || !newURI) {
6034 : return;
6035 : }
6036 : // On session restore we get a redirect from page to itself. Don't count it.
6037 0 : bool equals = false;
6038 0 : if (mTiming &&
6039 : !(mLoadType == LOAD_HISTORY &&
6040 0 : NS_SUCCEEDED(newURI->Equals(oldURI, &equals)) && equals)) {
6041 0 : mTiming->NotifyRedirect(oldURI, newURI);
6042 : }
6043 :
6044 : // Below a URI visit is saved (see AddURIVisit method doc).
6045 : // The visit chain looks something like:
6046 : // ...
6047 : // Site N - 1
6048 : // => Site N
6049 : // (redirect to =>) Site N + 1 (we are here!)
6050 :
6051 : // Get N - 1 and transition type
6052 0 : nsCOMPtr<nsIURI> previousURI;
6053 0 : PRUint32 previousFlags = 0;
6054 0 : ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
6055 :
6056 0 : if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
6057 0 : ChannelIsPost(aOldChannel)) {
6058 : // 1. Internal redirects are ignored because they are specific to the
6059 : // channel implementation.
6060 : // 2. POSTs are not saved by global history.
6061 : //
6062 : // Regardless, we need to propagate the previous visit to the new
6063 : // channel.
6064 0 : SaveLastVisit(aNewChannel, previousURI, previousFlags);
6065 : }
6066 : else {
6067 0 : nsCOMPtr<nsIURI> referrer;
6068 : // Treat referrer as null if there is an error getting it.
6069 : (void)NS_GetReferrerFromChannel(aOldChannel,
6070 0 : getter_AddRefs(referrer));
6071 :
6072 : // Add visit N -1 => N
6073 0 : AddURIVisit(oldURI, referrer, previousURI, previousFlags);
6074 :
6075 : // Since N + 1 could be the final destination, we will not save N => N + 1
6076 : // here. OnNewURI will do that, so we will cache it.
6077 0 : SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
6078 : }
6079 :
6080 : // check if the new load should go through the application cache.
6081 : nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
6082 0 : do_QueryInterface(aNewChannel);
6083 0 : if (appCacheChannel) {
6084 : // Permission will be checked in the parent process.
6085 0 : if (GeckoProcessType_Default != XRE_GetProcessType())
6086 0 : appCacheChannel->SetChooseApplicationCache(true);
6087 : else
6088 0 : appCacheChannel->SetChooseApplicationCache(ShouldCheckAppCache(newURI));
6089 : }
6090 :
6091 0 : if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
6092 : mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
6093 0 : mLoadType = LOAD_NORMAL_REPLACE;
6094 0 : SetHistoryEntry(&mLSHE, nsnull);
6095 : }
6096 : }
6097 :
6098 : NS_IMETHODIMP
6099 0 : nsDocShell::OnStatusChange(nsIWebProgress * aWebProgress,
6100 : nsIRequest * aRequest,
6101 : nsresult aStatus, const PRUnichar * aMessage)
6102 : {
6103 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6104 0 : return NS_OK;
6105 : }
6106 :
6107 : NS_IMETHODIMP
6108 0 : nsDocShell::OnSecurityChange(nsIWebProgress * aWebProgress,
6109 : nsIRequest * aRequest, PRUint32 state)
6110 : {
6111 0 : NS_NOTREACHED("notification excluded in AddProgressListener(...)");
6112 0 : return NS_OK;
6113 : }
6114 :
6115 :
6116 : nsresult
6117 0 : nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
6118 : nsIChannel * aChannel, nsresult aStatus)
6119 : {
6120 0 : if(!aChannel)
6121 0 : return NS_ERROR_NULL_POINTER;
6122 :
6123 0 : nsCOMPtr<nsIURI> url;
6124 0 : nsresult rv = aChannel->GetURI(getter_AddRefs(url));
6125 0 : if (NS_FAILED(rv)) return rv;
6126 :
6127 : nsCOMPtr<nsITimedChannel> timingChannel =
6128 0 : do_QueryInterface(aChannel);
6129 0 : if (timingChannel) {
6130 0 : TimeStamp channelCreationTime;
6131 0 : rv = timingChannel->GetChannelCreation(&channelCreationTime);
6132 0 : if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull())
6133 : Telemetry::AccumulateTimeDelta(
6134 : Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME,
6135 0 : channelCreationTime);
6136 : }
6137 :
6138 : // Timing is picked up by the window, we don't need it anymore
6139 0 : mTiming = nsnull;
6140 :
6141 : // clean up reload state for meta charset
6142 0 : if (eCharsetReloadRequested == mCharsetReloadState)
6143 0 : mCharsetReloadState = eCharsetReloadStopOrigional;
6144 : else
6145 0 : mCharsetReloadState = eCharsetReloadInit;
6146 :
6147 : // Save a pointer to the currently-loading history entry.
6148 : // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
6149 : // entry further down in this method.
6150 0 : nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
6151 :
6152 : //
6153 : // one of many safeguards that prevent death and destruction if
6154 : // someone is so very very rude as to bring this window down
6155 : // during this load handler.
6156 : //
6157 0 : nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
6158 :
6159 : // Notify the ContentViewer that the Document has finished loading. This
6160 : // will cause any OnLoad(...) and PopState(...) handlers to fire.
6161 0 : if (!mEODForCurrentDocument && mContentViewer) {
6162 0 : mIsExecutingOnLoadHandler = true;
6163 0 : mContentViewer->LoadComplete(aStatus);
6164 0 : mIsExecutingOnLoadHandler = false;
6165 :
6166 0 : mEODForCurrentDocument = true;
6167 :
6168 : // If all documents have completed their loading
6169 : // favor native event dispatch priorities
6170 : // over performance
6171 0 : if (--gNumberOfDocumentsLoading == 0) {
6172 : // Hint to use normal native event dispatch priorities
6173 0 : FavorPerformanceHint(false, NS_EVENT_STARVATION_DELAY_HINT);
6174 : }
6175 : }
6176 : /* Check if the httpChannel has any cache-control related response headers,
6177 : * like no-store, no-cache. If so, update SHEntry so that
6178 : * when a user goes back/forward to this page, we appropriately do
6179 : * form value restoration or load from server.
6180 : */
6181 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
6182 0 : if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel.
6183 0 : GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
6184 :
6185 0 : if (httpChannel) {
6186 : // figure out if SH should be saving layout state.
6187 0 : bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
6188 0 : if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
6189 : (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE))
6190 0 : mLSHE->SetSaveLayoutStateFlag(false);
6191 : }
6192 :
6193 : // Clear mLSHE after calling the onLoadHandlers. This way, if the
6194 : // onLoadHandler tries to load something different in
6195 : // itself or one of its children, we can deal with it appropriately.
6196 0 : if (mLSHE) {
6197 0 : mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
6198 :
6199 : // Clear the mLSHE reference to indicate document loading is done one
6200 : // way or another.
6201 0 : SetHistoryEntry(&mLSHE, nsnull);
6202 : }
6203 : // if there's a refresh header in the channel, this method
6204 : // will set it up for us.
6205 0 : RefreshURIFromQueue();
6206 :
6207 : // Test whether this is the top frame or a subframe
6208 0 : bool isTopFrame = true;
6209 0 : nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
6210 0 : rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
6211 0 : if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
6212 0 : isTopFrame = false;
6213 : }
6214 :
6215 : //
6216 : // If the page load failed, then deal with the error condition...
6217 : // Errors are handled as follows:
6218 : // 1. Check to see if it's a file not found error or bad content
6219 : // encoding error.
6220 : // 2. Send the URI to a keyword server (if enabled)
6221 : // 3. If the error was DNS failure, then add www and .com to the URI
6222 : // (if appropriate).
6223 : // 4. Throw an error dialog box...
6224 : //
6225 0 : if (url && NS_FAILED(aStatus)) {
6226 0 : if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
6227 : aStatus == NS_ERROR_CORRUPTED_CONTENT ||
6228 : aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
6229 0 : DisplayLoadError(aStatus, url, nsnull, aChannel);
6230 0 : return NS_OK;
6231 : }
6232 :
6233 0 : if (sURIFixup) {
6234 : //
6235 : // Try and make an alternative URI from the old one
6236 : //
6237 0 : nsCOMPtr<nsIURI> newURI;
6238 :
6239 0 : nsCAutoString oldSpec;
6240 0 : url->GetSpec(oldSpec);
6241 :
6242 : //
6243 : // First try keyword fixup
6244 : //
6245 0 : if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
6246 : bool keywordsEnabled =
6247 0 : Preferences::GetBool("keyword.enabled", false);
6248 :
6249 0 : nsCAutoString host;
6250 0 : url->GetHost(host);
6251 :
6252 0 : nsCAutoString scheme;
6253 0 : url->GetScheme(scheme);
6254 :
6255 0 : PRInt32 dotLoc = host.FindChar('.');
6256 :
6257 : // we should only perform a keyword search under the following
6258 : // conditions:
6259 : // (0) Pref keyword.enabled is true
6260 : // (1) the url scheme is http (or https)
6261 : // (2) the url does not have a protocol scheme
6262 : // If we don't enforce such a policy, then we end up doing
6263 : // keyword searchs on urls we don't intend like imap, file,
6264 : // mailbox, etc. This could lead to a security problem where we
6265 : // send data to the keyword server that we shouldn't be.
6266 : // Someone needs to clean up keywords in general so we can
6267 : // determine on a per url basis if we want keywords
6268 : // enabled...this is just a bandaid...
6269 0 : if (keywordsEnabled && !scheme.IsEmpty() &&
6270 0 : (scheme.Find("http") != 0)) {
6271 0 : keywordsEnabled = false;
6272 : }
6273 :
6274 0 : if (keywordsEnabled && (kNotFound == dotLoc)) {
6275 : // only send non-qualified hosts to the keyword server
6276 : //
6277 : // If this string was passed through nsStandardURL by
6278 : // chance, then it may have been converted from UTF-8 to
6279 : // ACE, which would result in a completely bogus keyword
6280 : // query. Here we try to recover the original Unicode
6281 : // value, but this is not 100% correct since the value may
6282 : // have been normalized per the IDN normalization rules.
6283 : //
6284 : // Since we don't have access to the exact original string
6285 : // that was entered by the user, this will just have to do.
6286 : bool isACE;
6287 0 : nsCAutoString utf8Host;
6288 : nsCOMPtr<nsIIDNService> idnSrv =
6289 0 : do_GetService(NS_IDNSERVICE_CONTRACTID);
6290 0 : if (idnSrv &&
6291 0 : NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
6292 0 : NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host)))
6293 : sURIFixup->KeywordToURI(utf8Host,
6294 0 : getter_AddRefs(newURI));
6295 : else
6296 0 : sURIFixup->KeywordToURI(host, getter_AddRefs(newURI));
6297 : } // end keywordsEnabled
6298 : }
6299 :
6300 : //
6301 : // Now try change the address, e.g. turn http://foo into
6302 : // http://www.foo.com
6303 : //
6304 0 : if (aStatus == NS_ERROR_UNKNOWN_HOST ||
6305 : aStatus == NS_ERROR_NET_RESET) {
6306 0 : bool doCreateAlternate = true;
6307 :
6308 : // Skip fixup for anything except a normal document load
6309 : // operation on the topframe.
6310 :
6311 0 : if (mLoadType != LOAD_NORMAL || !isTopFrame) {
6312 0 : doCreateAlternate = false;
6313 : }
6314 : else {
6315 : // Test if keyword lookup produced a new URI or not
6316 0 : if (newURI) {
6317 0 : bool sameURI = false;
6318 0 : url->Equals(newURI, &sameURI);
6319 0 : if (!sameURI) {
6320 : // Keyword lookup made a new URI so no need to try
6321 : // an alternate one.
6322 0 : doCreateAlternate = false;
6323 : }
6324 : }
6325 : }
6326 0 : if (doCreateAlternate) {
6327 0 : newURI = nsnull;
6328 : sURIFixup->CreateFixupURI(oldSpec,
6329 : nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
6330 0 : getter_AddRefs(newURI));
6331 : }
6332 : }
6333 :
6334 : // Did we make a new URI that is different to the old one? If so
6335 : // load it.
6336 : //
6337 0 : if (newURI) {
6338 : // Make sure the new URI is different from the old one,
6339 : // otherwise there's little point trying to load it again.
6340 0 : bool sameURI = false;
6341 0 : url->Equals(newURI, &sameURI);
6342 0 : if (!sameURI) {
6343 0 : nsCAutoString newSpec;
6344 0 : newURI->GetSpec(newSpec);
6345 0 : NS_ConvertUTF8toUTF16 newSpecW(newSpec);
6346 :
6347 : return LoadURI(newSpecW.get(), // URI string
6348 : LOAD_FLAGS_NONE, // Load flags
6349 : nsnull, // Referring URI
6350 : nsnull, // Post data stream
6351 0 : nsnull); // Headers stream
6352 : }
6353 : }
6354 : }
6355 :
6356 : // Well, fixup didn't work :-(
6357 : // It is time to throw an error dialog box, and be done with it...
6358 :
6359 : // Errors to be shown only on top-level frames
6360 0 : if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
6361 : aStatus == NS_ERROR_CONNECTION_REFUSED ||
6362 : aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
6363 : aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
6364 : (isTopFrame || mUseErrorPages)) {
6365 0 : DisplayLoadError(aStatus, url, nsnull, aChannel);
6366 : }
6367 : // Errors to be shown for any frame
6368 0 : else if (aStatus == NS_ERROR_NET_TIMEOUT ||
6369 : aStatus == NS_ERROR_REDIRECT_LOOP ||
6370 : aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
6371 : aStatus == NS_ERROR_NET_INTERRUPT ||
6372 : aStatus == NS_ERROR_NET_RESET ||
6373 : aStatus == NS_ERROR_OFFLINE ||
6374 : aStatus == NS_ERROR_MALWARE_URI ||
6375 : aStatus == NS_ERROR_PHISHING_URI ||
6376 : aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
6377 : aStatus == NS_ERROR_REMOTE_XUL ||
6378 : aStatus == NS_ERROR_OFFLINE ||
6379 : NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
6380 0 : DisplayLoadError(aStatus, url, nsnull, aChannel);
6381 : }
6382 0 : else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
6383 : // Non-caching channels will simply return NS_ERROR_OFFLINE.
6384 : // Caching channels would have to look at their flags to work
6385 : // out which error to return. Or we can fix up the error here.
6386 0 : if (!(mLoadType & LOAD_CMD_HISTORY))
6387 0 : aStatus = NS_ERROR_OFFLINE;
6388 0 : DisplayLoadError(aStatus, url, nsnull, aChannel);
6389 : }
6390 : } // if we have a host
6391 :
6392 0 : return NS_OK;
6393 : }
6394 :
6395 :
6396 : //*****************************************************************************
6397 : // nsDocShell: Content Viewer Management
6398 : //*****************************************************************************
6399 :
6400 : NS_IMETHODIMP
6401 0 : nsDocShell::EnsureContentViewer()
6402 : {
6403 0 : if (mContentViewer)
6404 0 : return NS_OK;
6405 0 : if (mIsBeingDestroyed)
6406 0 : return NS_ERROR_FAILURE;
6407 :
6408 : NS_TIME_FUNCTION;
6409 :
6410 0 : nsIPrincipal* principal = nsnull;
6411 0 : nsCOMPtr<nsIURI> baseURI;
6412 :
6413 0 : nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(mScriptGlobal));
6414 0 : if (piDOMWindow) {
6415 0 : principal = piDOMWindow->GetOpenerScriptPrincipal();
6416 : }
6417 :
6418 0 : if (!principal) {
6419 0 : principal = GetInheritedPrincipal(false);
6420 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
6421 0 : GetSameTypeParent(getter_AddRefs(parentItem));
6422 0 : if (parentItem) {
6423 0 : nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
6424 0 : if (domWin) {
6425 : nsCOMPtr<nsIContent> parentContent =
6426 0 : do_QueryInterface(domWin->GetFrameElementInternal());
6427 0 : if (parentContent) {
6428 0 : baseURI = parentContent->GetBaseURI();
6429 : }
6430 : }
6431 : }
6432 : }
6433 :
6434 0 : nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
6435 :
6436 0 : if (NS_SUCCEEDED(rv)) {
6437 0 : nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
6438 0 : NS_ASSERTION(doc,
6439 : "Should have doc if CreateAboutBlankContentViewer "
6440 : "succeeded!");
6441 :
6442 0 : doc->SetIsInitialDocument(true);
6443 : }
6444 :
6445 0 : return rv;
6446 : }
6447 :
6448 : nsresult
6449 0 : nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
6450 : nsIURI* aBaseURI,
6451 : bool aTryToSaveOldPresentation)
6452 : {
6453 0 : nsCOMPtr<nsIDocument> blankDoc;
6454 0 : nsCOMPtr<nsIContentViewer> viewer;
6455 0 : nsresult rv = NS_ERROR_FAILURE;
6456 :
6457 : /* mCreatingDocument should never be true at this point. However, it's
6458 : a theoretical possibility. We want to know about it and make it stop,
6459 : and this sounds like a job for an assertion. */
6460 0 : NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted");
6461 0 : if (mCreatingDocument)
6462 0 : return NS_ERROR_FAILURE;
6463 :
6464 0 : mCreatingDocument = true;
6465 :
6466 : // mContentViewer->PermitUnload may release |this| docshell.
6467 0 : nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
6468 :
6469 0 : if (mContentViewer) {
6470 : // We've got a content viewer already. Make sure the user
6471 : // permits us to discard the current document and replace it
6472 : // with about:blank. And also ensure we fire the unload events
6473 : // in the current document.
6474 :
6475 : // Make sure timing is created. Unload gets fired first for
6476 : // document loaded from the session history.
6477 0 : rv = MaybeInitTiming();
6478 0 : if (mTiming) {
6479 0 : mTiming->NotifyBeforeUnload();
6480 : }
6481 :
6482 : bool okToUnload;
6483 0 : rv = mContentViewer->PermitUnload(false, &okToUnload);
6484 :
6485 0 : if (NS_SUCCEEDED(rv) && !okToUnload) {
6486 : // The user chose not to unload the page, interrupt the load.
6487 0 : return NS_ERROR_FAILURE;
6488 : }
6489 :
6490 : mSavingOldViewer = aTryToSaveOldPresentation &&
6491 0 : CanSavePresentation(LOAD_NORMAL, nsnull, nsnull);
6492 :
6493 0 : if (mTiming) {
6494 0 : mTiming->NotifyUnloadAccepted(mCurrentURI);
6495 : }
6496 :
6497 : // Make sure to blow away our mLoadingURI just in case. No loads
6498 : // from inside this pagehide.
6499 0 : mLoadingURI = nsnull;
6500 :
6501 : // Stop any in-progress loading, so that we don't accidentally trigger any
6502 : // PageShow notifications from Embed() interrupting our loading below.
6503 0 : Stop();
6504 :
6505 : // Notify the current document that it is about to be unloaded!!
6506 : //
6507 : // It is important to fire the unload() notification *before* any state
6508 : // is changed within the DocShell - otherwise, javascript will get the
6509 : // wrong information :-(
6510 : //
6511 0 : (void) FirePageHideNotification(!mSavingOldViewer);
6512 : }
6513 :
6514 : // Now make sure we don't think we're in the middle of firing unload after
6515 : // this point. This will make us fire unload when the about:blank document
6516 : // unloads... but that's ok, more or less. Would be nice if it fired load
6517 : // too, of course.
6518 0 : mFiredUnloadEvent = false;
6519 :
6520 : nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
6521 0 : nsContentUtils::FindInternalContentViewer("text/html");
6522 :
6523 0 : if (docFactory) {
6524 : // generate (about:blank) document to load
6525 0 : docFactory->CreateBlankDocument(mLoadGroup, aPrincipal,
6526 0 : getter_AddRefs(blankDoc));
6527 0 : if (blankDoc) {
6528 : // Hack: set the base URI manually, since this document never
6529 : // got Reset() with a channel.
6530 0 : blankDoc->SetBaseURI(aBaseURI);
6531 :
6532 0 : blankDoc->SetContainer(static_cast<nsIDocShell *>(this));
6533 :
6534 : // create a content viewer for us and the new document
6535 0 : docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
6536 0 : blankDoc, "view", getter_AddRefs(viewer));
6537 :
6538 : // hook 'em up
6539 0 : if (viewer) {
6540 0 : viewer->SetContainer(static_cast<nsIContentViewerContainer *>(this));
6541 0 : Embed(viewer, "", 0);
6542 :
6543 0 : SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, true, 0);
6544 0 : rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
6545 : }
6546 : }
6547 : }
6548 0 : mCreatingDocument = false;
6549 :
6550 : // The transient about:blank viewer doesn't have a session history entry.
6551 0 : SetHistoryEntry(&mOSHE, nsnull);
6552 :
6553 0 : return rv;
6554 : }
6555 :
6556 : NS_IMETHODIMP
6557 0 : nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal)
6558 : {
6559 0 : return CreateAboutBlankContentViewer(aPrincipal, nsnull);
6560 : }
6561 :
6562 : bool
6563 0 : nsDocShell::CanSavePresentation(PRUint32 aLoadType,
6564 : nsIRequest *aNewRequest,
6565 : nsIDocument *aNewDocument)
6566 : {
6567 0 : if (!mOSHE)
6568 0 : return false; // no entry to save into
6569 :
6570 0 : nsCOMPtr<nsIContentViewer> viewer;
6571 0 : mOSHE->GetContentViewer(getter_AddRefs(viewer));
6572 0 : if (viewer) {
6573 0 : NS_WARNING("mOSHE already has a content viewer!");
6574 0 : return false;
6575 : }
6576 :
6577 : // Only save presentation for "normal" loads and link loads. Anything else
6578 : // probably wants to refetch the page, so caching the old presentation
6579 : // would be incorrect.
6580 0 : if (aLoadType != LOAD_NORMAL &&
6581 : aLoadType != LOAD_HISTORY &&
6582 : aLoadType != LOAD_LINK &&
6583 : aLoadType != LOAD_STOP_CONTENT &&
6584 : aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
6585 : aLoadType != LOAD_ERROR_PAGE)
6586 0 : return false;
6587 :
6588 : // If the session history entry has the saveLayoutState flag set to false,
6589 : // then we should not cache the presentation.
6590 : bool canSaveState;
6591 0 : mOSHE->GetSaveLayoutStateFlag(&canSaveState);
6592 0 : if (!canSaveState)
6593 0 : return false;
6594 :
6595 : // If the document is not done loading, don't cache it.
6596 0 : nsCOMPtr<nsPIDOMWindow> pWin = do_QueryInterface(mScriptGlobal);
6597 0 : if (!pWin || pWin->IsLoading())
6598 0 : return false;
6599 :
6600 0 : if (pWin->WouldReuseInnerWindow(aNewDocument))
6601 0 : return false;
6602 :
6603 : // Avoid doing the work of saving the presentation state in the case where
6604 : // the content viewer cache is disabled.
6605 0 : if (nsSHistory::GetMaxTotalViewers() == 0)
6606 0 : return false;
6607 :
6608 : // Don't cache the content viewer if we're in a subframe and the subframe
6609 : // pref is disabled.
6610 : bool cacheFrames =
6611 : Preferences::GetBool("browser.sessionhistory.cache_subframes",
6612 0 : false);
6613 0 : if (!cacheFrames) {
6614 0 : nsCOMPtr<nsIDocShellTreeItem> root;
6615 0 : GetSameTypeParent(getter_AddRefs(root));
6616 0 : if (root && root != this) {
6617 0 : return false; // this is a subframe load
6618 : }
6619 : }
6620 :
6621 : // If the document does not want its presentation cached, then don't.
6622 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(pWin->GetExtantDocument());
6623 0 : if (!doc || !doc->CanSavePresentation(aNewRequest))
6624 0 : return false;
6625 :
6626 0 : return true;
6627 : }
6628 :
6629 : void
6630 0 : nsDocShell::ReattachEditorToWindow(nsISHEntry *aSHEntry)
6631 : {
6632 0 : NS_ASSERTION(!mEditorData,
6633 : "Why reattach an editor when we already have one?");
6634 0 : NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
6635 : "Reattaching when there's not a detached editor.");
6636 :
6637 0 : if (mEditorData || !aSHEntry)
6638 0 : return;
6639 :
6640 0 : mEditorData = aSHEntry->ForgetEditorData();
6641 0 : if (mEditorData) {
6642 : #ifdef DEBUG
6643 : nsresult rv =
6644 : #endif
6645 0 : mEditorData->ReattachToWindow(this);
6646 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
6647 : }
6648 : }
6649 :
6650 : void
6651 0 : nsDocShell::DetachEditorFromWindow()
6652 : {
6653 0 : if (!mEditorData || mEditorData->WaitingForLoad()) {
6654 : // If there's nothing to detach, or if the editor data is actually set
6655 : // up for the _new_ page that's coming in, don't detach.
6656 0 : return;
6657 : }
6658 :
6659 0 : NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
6660 : "Detaching editor when it's already detached.");
6661 :
6662 0 : nsresult res = mEditorData->DetachFromWindow();
6663 0 : NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
6664 :
6665 0 : if (NS_SUCCEEDED(res)) {
6666 : // Make mOSHE hold the owning ref to the editor data.
6667 0 : if (mOSHE)
6668 0 : mOSHE->SetEditorData(mEditorData.forget());
6669 : else
6670 0 : mEditorData = nsnull;
6671 : }
6672 :
6673 : #ifdef DEBUG
6674 : {
6675 : bool isEditable;
6676 0 : GetEditable(&isEditable);
6677 0 : NS_ASSERTION(!isEditable,
6678 : "Window is still editable after detaching editor.");
6679 : }
6680 : #endif // DEBUG
6681 : }
6682 :
6683 : nsresult
6684 0 : nsDocShell::CaptureState()
6685 : {
6686 0 : if (!mOSHE || mOSHE == mLSHE) {
6687 : // No entry to save into, or we're replacing the existing entry.
6688 0 : return NS_ERROR_FAILURE;
6689 : }
6690 :
6691 0 : nsCOMPtr<nsPIDOMWindow> privWin = do_QueryInterface(mScriptGlobal);
6692 0 : if (!privWin)
6693 0 : return NS_ERROR_FAILURE;
6694 :
6695 0 : nsCOMPtr<nsISupports> windowState;
6696 0 : nsresult rv = privWin->SaveWindowState(getter_AddRefs(windowState));
6697 0 : NS_ENSURE_SUCCESS(rv, rv);
6698 :
6699 : #ifdef DEBUG_PAGE_CACHE
6700 : nsCOMPtr<nsIURI> uri;
6701 : mOSHE->GetURI(getter_AddRefs(uri));
6702 : nsCAutoString spec;
6703 : if (uri)
6704 : uri->GetSpec(spec);
6705 : printf("Saving presentation into session history\n");
6706 : printf(" SH URI: %s\n", spec.get());
6707 : #endif
6708 :
6709 0 : rv = mOSHE->SetWindowState(windowState);
6710 0 : NS_ENSURE_SUCCESS(rv, rv);
6711 :
6712 : // Suspend refresh URIs and save off the timer queue
6713 0 : rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
6714 0 : NS_ENSURE_SUCCESS(rv, rv);
6715 :
6716 : // Capture the current content viewer bounds.
6717 0 : if (mContentViewer) {
6718 0 : nsIntRect bounds;
6719 0 : mContentViewer->GetBounds(bounds);
6720 0 : rv = mOSHE->SetViewerBounds(bounds);
6721 0 : NS_ENSURE_SUCCESS(rv, rv);
6722 : }
6723 :
6724 : // Capture the docshell hierarchy.
6725 0 : mOSHE->ClearChildShells();
6726 :
6727 0 : PRInt32 childCount = mChildList.Count();
6728 0 : for (PRInt32 i = 0; i < childCount; ++i) {
6729 0 : nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
6730 0 : NS_ASSERTION(childShell, "null child shell");
6731 :
6732 0 : mOSHE->AddChildShell(childShell);
6733 : }
6734 :
6735 0 : return NS_OK;
6736 : }
6737 :
6738 : NS_IMETHODIMP
6739 0 : nsDocShell::RestorePresentationEvent::Run()
6740 : {
6741 0 : if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory()))
6742 0 : NS_WARNING("RestoreFromHistory failed");
6743 0 : return NS_OK;
6744 : }
6745 :
6746 : NS_IMETHODIMP
6747 0 : nsDocShell::BeginRestore(nsIContentViewer *aContentViewer, bool aTop)
6748 : {
6749 : nsresult rv;
6750 0 : if (!aContentViewer) {
6751 0 : rv = EnsureContentViewer();
6752 0 : NS_ENSURE_SUCCESS(rv, rv);
6753 :
6754 0 : aContentViewer = mContentViewer;
6755 : }
6756 :
6757 : // Dispatch events for restoring the presentation. We try to simulate
6758 : // the progress notifications loading the document would cause, so we add
6759 : // the document's channel to the loadgroup to initiate stateChange
6760 : // notifications.
6761 :
6762 0 : nsCOMPtr<nsIDOMDocument> domDoc;
6763 0 : aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
6764 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
6765 0 : if (doc) {
6766 0 : nsIChannel *channel = doc->GetChannel();
6767 0 : if (channel) {
6768 0 : mEODForCurrentDocument = false;
6769 0 : mIsRestoringDocument = true;
6770 0 : mLoadGroup->AddRequest(channel, nsnull);
6771 0 : mIsRestoringDocument = false;
6772 : }
6773 : }
6774 :
6775 0 : if (!aTop) {
6776 : // This point corresponds to us having gotten OnStartRequest or
6777 : // STATE_START, so do the same thing that CreateContentViewer does at
6778 : // this point to ensure that unload/pagehide events for this document
6779 : // will fire when it's unloaded again.
6780 0 : mFiredUnloadEvent = false;
6781 :
6782 : // For non-top frames, there is no notion of making sure that the
6783 : // previous document is in the domwindow when STATE_START notifications
6784 : // happen. We can just call BeginRestore for all of the child shells
6785 : // now.
6786 0 : rv = BeginRestoreChildren();
6787 0 : NS_ENSURE_SUCCESS(rv, rv);
6788 : }
6789 :
6790 0 : return NS_OK;
6791 : }
6792 :
6793 : nsresult
6794 0 : nsDocShell::BeginRestoreChildren()
6795 : {
6796 0 : PRInt32 n = mChildList.Count();
6797 0 : for (PRInt32 i = 0; i < n; ++i) {
6798 0 : nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
6799 0 : if (child) {
6800 0 : nsresult rv = child->BeginRestore(nsnull, false);
6801 0 : NS_ENSURE_SUCCESS(rv, rv);
6802 : }
6803 : }
6804 0 : return NS_OK;
6805 : }
6806 :
6807 : NS_IMETHODIMP
6808 0 : nsDocShell::FinishRestore()
6809 : {
6810 : // First we call finishRestore() on our children. In the simulated load,
6811 : // all of the child frames finish loading before the main document.
6812 :
6813 0 : PRInt32 n = mChildList.Count();
6814 0 : for (PRInt32 i = 0; i < n; ++i) {
6815 0 : nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
6816 0 : if (child) {
6817 0 : child->FinishRestore();
6818 : }
6819 : }
6820 :
6821 0 : if (mOSHE && mOSHE->HasDetachedEditor()) {
6822 0 : ReattachEditorToWindow(mOSHE);
6823 : }
6824 :
6825 0 : nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
6826 0 : if (doc) {
6827 : // Finally, we remove the request from the loadgroup. This will
6828 : // cause onStateChange(STATE_STOP) to fire, which will fire the
6829 : // pageshow event to the chrome.
6830 :
6831 0 : nsIChannel *channel = doc->GetChannel();
6832 0 : if (channel) {
6833 0 : mIsRestoringDocument = true;
6834 0 : mLoadGroup->RemoveRequest(channel, nsnull, NS_OK);
6835 0 : mIsRestoringDocument = false;
6836 : }
6837 : }
6838 :
6839 0 : return NS_OK;
6840 : }
6841 :
6842 : NS_IMETHODIMP
6843 0 : nsDocShell::GetRestoringDocument(bool *aRestoring)
6844 : {
6845 0 : *aRestoring = mIsRestoringDocument;
6846 0 : return NS_OK;
6847 : }
6848 :
6849 : nsresult
6850 0 : nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, bool *aRestoring)
6851 : {
6852 0 : NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
6853 : "RestorePresentation should only be called for history loads");
6854 :
6855 0 : nsCOMPtr<nsIContentViewer> viewer;
6856 0 : aSHEntry->GetContentViewer(getter_AddRefs(viewer));
6857 :
6858 : #ifdef DEBUG_PAGE_CACHE
6859 : nsCOMPtr<nsIURI> uri;
6860 : aSHEntry->GetURI(getter_AddRefs(uri));
6861 :
6862 : nsCAutoString spec;
6863 : if (uri)
6864 : uri->GetSpec(spec);
6865 : #endif
6866 :
6867 0 : *aRestoring = false;
6868 :
6869 0 : if (!viewer) {
6870 : #ifdef DEBUG_PAGE_CACHE
6871 : printf("no saved presentation for uri: %s\n", spec.get());
6872 : #endif
6873 0 : return NS_OK;
6874 : }
6875 :
6876 : // We need to make sure the content viewer's container is this docshell.
6877 : // In subframe navigation, it's possible for the docshell that the
6878 : // content viewer was originally loaded into to be replaced with a
6879 : // different one. We don't currently support restoring the presentation
6880 : // in that case.
6881 :
6882 0 : nsCOMPtr<nsISupports> container;
6883 0 : viewer->GetContainer(getter_AddRefs(container));
6884 0 : if (!::SameCOMIdentity(container, GetAsSupports(this))) {
6885 : #ifdef DEBUG_PAGE_CACHE
6886 : printf("No valid container, clearing presentation\n");
6887 : #endif
6888 0 : aSHEntry->SetContentViewer(nsnull);
6889 0 : return NS_ERROR_FAILURE;
6890 : }
6891 :
6892 0 : NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
6893 :
6894 : #ifdef DEBUG_PAGE_CACHE
6895 : printf("restoring presentation from session history: %s\n", spec.get());
6896 : #endif
6897 :
6898 0 : SetHistoryEntry(&mLSHE, aSHEntry);
6899 :
6900 : // Add the request to our load group. We do this before swapping out
6901 : // the content viewers so that consumers of STATE_START can access
6902 : // the old document. We only deal with the toplevel load at this time --
6903 : // to be consistent with normal document loading, subframes cannot start
6904 : // loading until after data arrives, which is after STATE_START completes.
6905 :
6906 0 : BeginRestore(viewer, true);
6907 :
6908 : // Post an event that will remove the request after we've returned
6909 : // to the event loop. This mimics the way it is called by nsIChannel
6910 : // implementations.
6911 :
6912 : // Revoke any pending restore (just in case)
6913 0 : NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
6914 : "should only have one RestorePresentationEvent");
6915 0 : mRestorePresentationEvent.Revoke();
6916 :
6917 0 : nsRefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
6918 0 : nsresult rv = NS_DispatchToCurrentThread(evt);
6919 0 : if (NS_SUCCEEDED(rv)) {
6920 0 : mRestorePresentationEvent = evt.get();
6921 : // The rest of the restore processing will happen on our event
6922 : // callback.
6923 0 : *aRestoring = true;
6924 : }
6925 :
6926 0 : return rv;
6927 : }
6928 :
6929 : nsresult
6930 0 : nsDocShell::RestoreFromHistory()
6931 : {
6932 0 : mRestorePresentationEvent.Forget();
6933 :
6934 : // This section of code follows the same ordering as CreateContentViewer.
6935 0 : if (!mLSHE)
6936 0 : return NS_ERROR_FAILURE;
6937 :
6938 0 : nsCOMPtr<nsIContentViewer> viewer;
6939 0 : mLSHE->GetContentViewer(getter_AddRefs(viewer));
6940 0 : if (!viewer)
6941 0 : return NS_ERROR_FAILURE;
6942 :
6943 0 : if (mSavingOldViewer) {
6944 : // We determined that it was safe to cache the document presentation
6945 : // at the time we initiated the new load. We need to check whether
6946 : // it's still safe to do so, since there may have been DOM mutations
6947 : // or new requests initiated.
6948 0 : nsCOMPtr<nsIDOMDocument> domDoc;
6949 0 : viewer->GetDOMDocument(getter_AddRefs(domDoc));
6950 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
6951 0 : nsIRequest *request = nsnull;
6952 0 : if (doc)
6953 0 : request = doc->GetChannel();
6954 0 : mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
6955 : }
6956 :
6957 : nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV(
6958 0 : do_QueryInterface(mContentViewer));
6959 : nsCOMPtr<nsIMarkupDocumentViewer> newMUDV(
6960 0 : do_QueryInterface(viewer));
6961 0 : PRInt32 minFontSize = 0;
6962 0 : float textZoom = 1.0f;
6963 0 : float pageZoom = 1.0f;
6964 0 : bool styleDisabled = false;
6965 0 : if (oldMUDV && newMUDV) {
6966 0 : oldMUDV->GetMinFontSize(&minFontSize);
6967 0 : oldMUDV->GetTextZoom(&textZoom);
6968 0 : oldMUDV->GetFullZoom(&pageZoom);
6969 0 : oldMUDV->GetAuthorStyleDisabled(&styleDisabled);
6970 : }
6971 :
6972 : // Protect against mLSHE going away via a load triggered from
6973 : // pagehide or unload.
6974 0 : nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
6975 :
6976 : // Make sure to blow away our mLoadingURI just in case. No loads
6977 : // from inside this pagehide.
6978 0 : mLoadingURI = nsnull;
6979 :
6980 : // Notify the old content viewer that it's being hidden.
6981 0 : FirePageHideNotification(!mSavingOldViewer);
6982 :
6983 : // If mLSHE was changed as a result of the pagehide event, then
6984 : // something else was loaded. Don't finish restoring.
6985 0 : if (mLSHE != origLSHE)
6986 0 : return NS_OK;
6987 :
6988 : // Set mFiredUnloadEvent = false so that the unload handler for the
6989 : // *new* document will fire.
6990 0 : mFiredUnloadEvent = false;
6991 :
6992 0 : mURIResultedInDocument = true;
6993 0 : nsCOMPtr<nsISHistory> rootSH;
6994 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
6995 0 : if (rootSH) {
6996 0 : nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
6997 0 : rootSH->GetIndex(&mPreviousTransIndex);
6998 0 : hist->UpdateIndex();
6999 0 : rootSH->GetIndex(&mLoadedTransIndex);
7000 : #ifdef DEBUG_PAGE_CACHE
7001 : printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
7002 : mLoadedTransIndex);
7003 : #endif
7004 : }
7005 :
7006 : // Rather than call Embed(), we will retrieve the viewer from the session
7007 : // history entry and swap it in.
7008 : // XXX can we refactor this so that we can just call Embed()?
7009 0 : PersistLayoutHistoryState();
7010 : nsresult rv;
7011 0 : if (mContentViewer) {
7012 0 : if (mSavingOldViewer && NS_FAILED(CaptureState())) {
7013 0 : if (mOSHE) {
7014 0 : mOSHE->SyncPresentationState();
7015 : }
7016 0 : mSavingOldViewer = false;
7017 : }
7018 : }
7019 :
7020 0 : mSavedRefreshURIList = nsnull;
7021 :
7022 : // In cases where we use a transient about:blank viewer between loads,
7023 : // we never show the transient viewer, so _its_ previous viewer is never
7024 : // unhooked from the view hierarchy. Destroy any such previous viewer now,
7025 : // before we grab the root view sibling, so that we don't grab a view
7026 : // that's about to go away.
7027 :
7028 0 : if (mContentViewer) {
7029 0 : nsCOMPtr<nsIContentViewer> previousViewer;
7030 0 : mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
7031 0 : if (previousViewer) {
7032 0 : mContentViewer->SetPreviousViewer(nsnull);
7033 0 : previousViewer->Destroy();
7034 : }
7035 : }
7036 :
7037 : // Save off the root view's parent and sibling so that we can insert the
7038 : // new content viewer's root view at the same position. Also save the
7039 : // bounds of the root view's widget.
7040 :
7041 0 : nsIView *rootViewSibling = nsnull, *rootViewParent = nsnull;
7042 0 : nsIntRect newBounds(0, 0, 0, 0);
7043 :
7044 0 : nsCOMPtr<nsIPresShell> oldPresShell;
7045 0 : nsDocShell::GetPresShell(getter_AddRefs(oldPresShell));
7046 0 : if (oldPresShell) {
7047 0 : nsIViewManager *vm = oldPresShell->GetViewManager();
7048 0 : if (vm) {
7049 0 : nsIView *oldRootView = vm->GetRootView();
7050 :
7051 0 : if (oldRootView) {
7052 0 : rootViewSibling = oldRootView->GetNextSibling();
7053 0 : rootViewParent = oldRootView->GetParent();
7054 :
7055 0 : mContentViewer->GetBounds(newBounds);
7056 : }
7057 : }
7058 : }
7059 :
7060 : // Transfer ownership to mContentViewer. By ensuring that either the
7061 : // docshell or the session history, but not both, have references to the
7062 : // content viewer, we prevent the viewer from being torn down after
7063 : // Destroy() is called.
7064 :
7065 0 : if (mContentViewer) {
7066 0 : mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull);
7067 0 : viewer->SetPreviousViewer(mContentViewer);
7068 : }
7069 0 : if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
7070 : // We don't plan to save a viewer in mOSHE; tell it to drop
7071 : // any other state it's holding.
7072 0 : mOSHE->SyncPresentationState();
7073 : }
7074 :
7075 : // Order the mContentViewer setup just like Embed does.
7076 0 : mContentViewer = nsnull;
7077 :
7078 : // Now that we're about to switch documents, forget all of our children.
7079 : // Note that we cached them as needed up in CaptureState above.
7080 0 : DestroyChildren();
7081 :
7082 0 : mContentViewer.swap(viewer);
7083 :
7084 : // Grab all of the related presentation from the SHEntry now.
7085 : // Clearing the viewer from the SHEntry will clear all of this state.
7086 0 : nsCOMPtr<nsISupports> windowState;
7087 0 : mLSHE->GetWindowState(getter_AddRefs(windowState));
7088 0 : mLSHE->SetWindowState(nsnull);
7089 :
7090 : bool sticky;
7091 0 : mLSHE->GetSticky(&sticky);
7092 :
7093 0 : nsCOMPtr<nsIDOMDocument> domDoc;
7094 0 : mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
7095 :
7096 0 : nsCOMArray<nsIDocShellTreeItem> childShells;
7097 0 : PRInt32 i = 0;
7098 0 : nsCOMPtr<nsIDocShellTreeItem> child;
7099 0 : while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
7100 0 : child) {
7101 0 : childShells.AppendObject(child);
7102 : }
7103 :
7104 : // get the previous content viewer size
7105 0 : nsIntRect oldBounds(0, 0, 0, 0);
7106 0 : mLSHE->GetViewerBounds(oldBounds);
7107 :
7108 : // Restore the refresh URI list. The refresh timers will be restarted
7109 : // when EndPageLoad() is called.
7110 0 : nsCOMPtr<nsISupportsArray> refreshURIList;
7111 0 : mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
7112 :
7113 : // Reattach to the window object.
7114 0 : rv = mContentViewer->Open(windowState, mLSHE);
7115 :
7116 : // Hack to keep nsDocShellEditorData alive across the
7117 : // SetContentViewer(nsnull) call below.
7118 0 : nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
7119 :
7120 : // Now remove it from the cached presentation.
7121 0 : mLSHE->SetContentViewer(nsnull);
7122 0 : mEODForCurrentDocument = false;
7123 :
7124 0 : mLSHE->SetEditorData(data.forget());
7125 :
7126 : #ifdef DEBUG
7127 : {
7128 0 : nsCOMPtr<nsISupportsArray> refreshURIs;
7129 0 : mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
7130 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
7131 0 : mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
7132 0 : NS_ASSERTION(!refreshURIs && !childShell,
7133 : "SHEntry should have cleared presentation state");
7134 : }
7135 : #endif
7136 :
7137 : // Restore the sticky state of the viewer. The viewer has set this state
7138 : // on the history entry in Destroy() just before marking itself non-sticky,
7139 : // to avoid teardown of the presentation.
7140 0 : mContentViewer->SetSticky(sticky);
7141 :
7142 0 : NS_ENSURE_SUCCESS(rv, rv);
7143 :
7144 : // mLSHE is now our currently-loaded document.
7145 0 : SetHistoryEntry(&mOSHE, mLSHE);
7146 :
7147 : // XXX special wyciwyg handling in Embed()?
7148 :
7149 : // We aren't going to restore any items from the LayoutHistoryState,
7150 : // but we don't want them to stay around in case the page is reloaded.
7151 0 : SetLayoutHistoryState(nsnull);
7152 :
7153 : // This is the end of our Embed() replacement
7154 :
7155 0 : mSavingOldViewer = false;
7156 0 : mEODForCurrentDocument = false;
7157 :
7158 : // Tell the event loop to favor plevents over user events, see comments
7159 : // in CreateContentViewer.
7160 0 : if (++gNumberOfDocumentsLoading == 1)
7161 0 : FavorPerformanceHint(true, NS_EVENT_STARVATION_DELAY_HINT);
7162 :
7163 :
7164 0 : if (oldMUDV && newMUDV) {
7165 0 : newMUDV->SetMinFontSize(minFontSize);
7166 0 : newMUDV->SetTextZoom(textZoom);
7167 0 : newMUDV->SetFullZoom(pageZoom);
7168 0 : newMUDV->SetAuthorStyleDisabled(styleDisabled);
7169 : }
7170 :
7171 0 : nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
7172 0 : PRUint32 parentSuspendCount = 0;
7173 0 : if (document) {
7174 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
7175 0 : GetParent(getter_AddRefs(parent));
7176 0 : nsCOMPtr<nsIDocument> d = do_GetInterface(parent);
7177 0 : if (d) {
7178 0 : if (d->EventHandlingSuppressed()) {
7179 0 : document->SuppressEventHandling(d->EventHandlingSuppressed());
7180 : }
7181 0 : nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
7182 0 : if (parentWindow) {
7183 0 : parentSuspendCount = parentWindow->TimeoutSuspendCount();
7184 : }
7185 : }
7186 :
7187 : // Use the uri from the mLSHE we had when we entered this function
7188 : // (which need not match the document's URI if anchors are involved),
7189 : // since that's the history entry we're loading. Note that if we use
7190 : // origLSHE we don't have to worry about whether the entry in question
7191 : // is still mLSHE or whether it's now mOSHE.
7192 0 : nsCOMPtr<nsIURI> uri;
7193 0 : origLSHE->GetURI(getter_AddRefs(uri));
7194 0 : SetCurrentURI(uri, document->GetChannel(), true, 0);
7195 : }
7196 :
7197 : // This is the end of our CreateContentViewer() replacement.
7198 : // Now we simulate a load. First, we restore the state of the javascript
7199 : // window object.
7200 : nsCOMPtr<nsPIDOMWindow> privWin =
7201 0 : do_GetInterface(static_cast<nsIInterfaceRequestor*>(this));
7202 0 : NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
7203 :
7204 0 : rv = privWin->RestoreWindowState(windowState);
7205 0 : NS_ENSURE_SUCCESS(rv, rv);
7206 :
7207 : // Now, dispatch a title change event which would happen as the
7208 : // <head> is parsed.
7209 0 : document->NotifyPossibleTitleChange(false);
7210 :
7211 : // Now we simulate appending child docshells for subframes.
7212 0 : for (i = 0; i < childShells.Count(); ++i) {
7213 0 : nsIDocShellTreeItem *childItem = childShells.ObjectAt(i);
7214 0 : nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
7215 :
7216 : // Make sure to not clobber the state of the child. Since AddChild
7217 : // always clobbers it, save it off first.
7218 : bool allowPlugins;
7219 0 : childShell->GetAllowPlugins(&allowPlugins);
7220 :
7221 : bool allowJavascript;
7222 0 : childShell->GetAllowJavascript(&allowJavascript);
7223 :
7224 : bool allowRedirects;
7225 0 : childShell->GetAllowMetaRedirects(&allowRedirects);
7226 :
7227 : bool allowSubframes;
7228 0 : childShell->GetAllowSubframes(&allowSubframes);
7229 :
7230 : bool allowImages;
7231 0 : childShell->GetAllowImages(&allowImages);
7232 :
7233 : bool allowDNSPrefetch;
7234 0 : childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
7235 :
7236 : // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
7237 : // that the child inherits our state. Among other things, this means
7238 : // that the child inherits our mIsActive and mInPrivateBrowsing, which
7239 : // is what we want.
7240 0 : AddChild(childItem);
7241 :
7242 0 : childShell->SetAllowPlugins(allowPlugins);
7243 0 : childShell->SetAllowJavascript(allowJavascript);
7244 0 : childShell->SetAllowMetaRedirects(allowRedirects);
7245 0 : childShell->SetAllowSubframes(allowSubframes);
7246 0 : childShell->SetAllowImages(allowImages);
7247 0 : childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
7248 :
7249 0 : rv = childShell->BeginRestore(nsnull, false);
7250 0 : NS_ENSURE_SUCCESS(rv, rv);
7251 : }
7252 :
7253 0 : nsCOMPtr<nsIPresShell> shell;
7254 0 : nsDocShell::GetPresShell(getter_AddRefs(shell));
7255 :
7256 0 : nsIViewManager *newVM = shell ? shell->GetViewManager() : nsnull;
7257 0 : nsIView *newRootView = newVM ? newVM->GetRootView() : nsnull;
7258 :
7259 : // Insert the new root view at the correct location in the view tree.
7260 0 : if (rootViewParent) {
7261 0 : nsIViewManager *parentVM = rootViewParent->GetViewManager();
7262 :
7263 0 : if (parentVM && newRootView) {
7264 : // InsertChild(parent, child, sib, true) inserts the child after
7265 : // sib in content order, which is before sib in view order. BUT
7266 : // when sib is null it inserts at the end of the the document
7267 : // order, i.e., first in view order. But when oldRootSibling is
7268 : // null, the old root as at the end of the view list --- last in
7269 : // content order --- and we want to call InsertChild(parent, child,
7270 : // nsnull, false) in that case.
7271 : parentVM->InsertChild(rootViewParent, newRootView,
7272 : rootViewSibling,
7273 0 : rootViewSibling ? true : false);
7274 :
7275 0 : NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
7276 : "error in InsertChild");
7277 : }
7278 : }
7279 :
7280 : // If parent is suspended, increase suspension count.
7281 : // This can't be done as early as event suppression since this
7282 : // depends on docshell tree.
7283 0 : if (parentSuspendCount) {
7284 0 : privWin->SuspendTimeouts(parentSuspendCount, false);
7285 : }
7286 :
7287 : // Now that all of the child docshells have been put into place, we can
7288 : // restart the timers for the window and all of the child frames.
7289 0 : privWin->ResumeTimeouts();
7290 :
7291 : // Restore the refresh URI list. The refresh timers will be restarted
7292 : // when EndPageLoad() is called.
7293 0 : mRefreshURIList = refreshURIList;
7294 :
7295 : // Meta-refresh timers have been restarted for this shell, but not
7296 : // for our children. Walk the child shells and restart their timers.
7297 0 : PRInt32 n = mChildList.Count();
7298 0 : for (i = 0; i < n; ++i) {
7299 0 : nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
7300 0 : if (child)
7301 0 : child->ResumeRefreshURIs();
7302 : }
7303 :
7304 : // Make sure this presentation is the same size as the previous
7305 : // presentation. If this is not the same size we showed it at last time,
7306 : // then we need to resize the widget.
7307 :
7308 : // XXXbryner This interacts poorly with Firefox's infobar. If the old
7309 : // presentation had the infobar visible, then we will resize the new
7310 : // presentation to that smaller size. However, firing the locationchanged
7311 : // event will hide the infobar, which will immediately resize the window
7312 : // back to the larger size. A future optimization might be to restore
7313 : // the presentation at the "wrong" size, then fire the locationchanged
7314 : // event and check whether the docshell's new size is the same as the
7315 : // cached viewer size (skipping the resize if they are equal).
7316 :
7317 0 : if (newRootView) {
7318 0 : if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
7319 : #ifdef DEBUG_PAGE_CACHE
7320 : printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
7321 : newBounds.y, newBounds.width, newBounds.height);
7322 : #endif
7323 0 : mContentViewer->SetBounds(newBounds);
7324 : } else {
7325 : nsIScrollableFrame *rootScrollFrame =
7326 0 : shell->GetRootScrollFrameAsScrollableExternal();
7327 0 : if (rootScrollFrame) {
7328 0 : rootScrollFrame->PostScrolledAreaEventForCurrentArea();
7329 : }
7330 : }
7331 : }
7332 :
7333 : // The FinishRestore call below can kill these, null them out so we don't
7334 : // have invalid pointer lying around.
7335 0 : newRootView = rootViewSibling = rootViewParent = nsnull;
7336 0 : newVM = nsnull;
7337 :
7338 : // Simulate the completion of the load.
7339 0 : nsDocShell::FinishRestore();
7340 :
7341 : // Restart plugins, and paint the content.
7342 0 : if (shell) {
7343 0 : shell->Thaw();
7344 :
7345 0 : newVM = shell->GetViewManager();
7346 0 : if (newVM) {
7347 : // When we insert the root view above the resulting invalidate is
7348 : // dropped because painting is suppressed in the presshell until we
7349 : // call Thaw. So we issue the invalidate here.
7350 0 : newRootView = newVM->GetRootView();
7351 0 : if (newRootView) {
7352 0 : newVM->InvalidateView(newRootView);
7353 : }
7354 : }
7355 : }
7356 :
7357 0 : return privWin->FireDelayedDOMEvents();
7358 : }
7359 :
7360 : NS_IMETHODIMP
7361 0 : nsDocShell::CreateContentViewer(const char *aContentType,
7362 : nsIRequest * request,
7363 : nsIStreamListener ** aContentHandler)
7364 : {
7365 0 : *aContentHandler = nsnull;
7366 :
7367 : // Can we check the content type of the current content viewer
7368 : // and reuse it without destroying it and re-creating it?
7369 :
7370 0 : NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
7371 :
7372 : // Instantiate the content viewer object
7373 0 : nsCOMPtr<nsIContentViewer> viewer;
7374 : nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup,
7375 0 : aContentHandler, getter_AddRefs(viewer));
7376 :
7377 0 : if (NS_FAILED(rv))
7378 0 : return rv;
7379 :
7380 : // Notify the current document that it is about to be unloaded!!
7381 : //
7382 : // It is important to fire the unload() notification *before* any state
7383 : // is changed within the DocShell - otherwise, javascript will get the
7384 : // wrong information :-(
7385 : //
7386 :
7387 0 : if (mSavingOldViewer) {
7388 : // We determined that it was safe to cache the document presentation
7389 : // at the time we initiated the new load. We need to check whether
7390 : // it's still safe to do so, since there may have been DOM mutations
7391 : // or new requests initiated.
7392 0 : nsCOMPtr<nsIDOMDocument> domDoc;
7393 0 : viewer->GetDOMDocument(getter_AddRefs(domDoc));
7394 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
7395 0 : mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
7396 : }
7397 :
7398 0 : NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
7399 :
7400 0 : nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
7401 0 : if (aOpenedChannel) {
7402 0 : aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
7403 : }
7404 0 : FirePageHideNotification(!mSavingOldViewer);
7405 0 : mLoadingURI = nsnull;
7406 :
7407 : // Set mFiredUnloadEvent = false so that the unload handler for the
7408 : // *new* document will fire.
7409 0 : mFiredUnloadEvent = false;
7410 :
7411 : // we've created a new document so go ahead and call
7412 : // OnLoadingSite(), but don't fire OnLocationChange()
7413 : // notifications before we've called Embed(). See bug 284993.
7414 0 : mURIResultedInDocument = true;
7415 :
7416 0 : if (mLoadType == LOAD_ERROR_PAGE) {
7417 : // We need to set the SH entry and our current URI here and not
7418 : // at the moment we load the page. We want the same behavior
7419 : // of Stop() as for a normal page load. See bug 514232 for details.
7420 :
7421 : // Revert mLoadType to load type to state the page load failed,
7422 : // following function calls need it.
7423 0 : mLoadType = mFailedLoadType;
7424 :
7425 0 : nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
7426 0 : nsCOMPtr<nsIURI> failedURI = mFailedURI;
7427 0 : mFailedChannel = nsnull;
7428 0 : mFailedURI = nsnull;
7429 :
7430 : // Create an shistory entry for the old load, if we have a channel
7431 0 : if (failedChannel) {
7432 0 : mURIResultedInDocument = true;
7433 0 : OnLoadingSite(failedChannel, true, false);
7434 0 : } else if (failedURI) {
7435 0 : mURIResultedInDocument = true;
7436 : OnNewURI(failedURI, nsnull, nsnull, mLoadType, true, false,
7437 0 : false);
7438 : }
7439 :
7440 : // Be sure to have a correct mLSHE, it may have been cleared by
7441 : // EndPageLoad. See bug 302115.
7442 0 : if (mSessionHistory && !mLSHE) {
7443 : PRInt32 idx;
7444 0 : mSessionHistory->GetRequestedIndex(&idx);
7445 0 : if (idx == -1)
7446 0 : mSessionHistory->GetIndex(&idx);
7447 :
7448 0 : nsCOMPtr<nsIHistoryEntry> entry;
7449 0 : mSessionHistory->GetEntryAtIndex(idx, false,
7450 0 : getter_AddRefs(entry));
7451 0 : mLSHE = do_QueryInterface(entry);
7452 : }
7453 :
7454 : // Set our current URI
7455 0 : SetCurrentURI(failedURI);
7456 :
7457 0 : mLoadType = LOAD_ERROR_PAGE;
7458 : }
7459 :
7460 0 : bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
7461 :
7462 : // let's try resetting the load group if we need to...
7463 0 : nsCOMPtr<nsILoadGroup> currentLoadGroup;
7464 0 : NS_ENSURE_SUCCESS(aOpenedChannel->
7465 : GetLoadGroup(getter_AddRefs(currentLoadGroup)),
7466 : NS_ERROR_FAILURE);
7467 :
7468 0 : if (currentLoadGroup != mLoadGroup) {
7469 0 : nsLoadFlags loadFlags = 0;
7470 :
7471 : //Cancel any URIs that are currently loading...
7472 : /// XXX: Need to do this eventually Stop();
7473 : //
7474 : // Retarget the document to this loadgroup...
7475 : //
7476 : /* First attach the channel to the right loadgroup
7477 : * and then remove from the old loadgroup. This
7478 : * puts the notifications in the right order and
7479 : * we don't null-out mLSHE in OnStateChange() for
7480 : * all redirected urls
7481 : */
7482 0 : aOpenedChannel->SetLoadGroup(mLoadGroup);
7483 :
7484 : // Mark the channel as being a document URI...
7485 0 : aOpenedChannel->GetLoadFlags(&loadFlags);
7486 0 : loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
7487 :
7488 0 : aOpenedChannel->SetLoadFlags(loadFlags);
7489 :
7490 0 : mLoadGroup->AddRequest(request, nsnull);
7491 0 : if (currentLoadGroup)
7492 0 : currentLoadGroup->RemoveRequest(request, nsnull,
7493 0 : NS_BINDING_RETARGETED);
7494 :
7495 : // Update the notification callbacks, so that progress and
7496 : // status information are sent to the right docshell...
7497 0 : aOpenedChannel->SetNotificationCallbacks(this);
7498 : }
7499 :
7500 0 : NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull),
7501 : NS_ERROR_FAILURE);
7502 :
7503 0 : mSavedRefreshURIList = nsnull;
7504 0 : mSavingOldViewer = false;
7505 0 : mEODForCurrentDocument = false;
7506 :
7507 : // if this document is part of a multipart document,
7508 : // the ID can be used to distinguish it from the other parts.
7509 0 : nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(request));
7510 0 : if (multiPartChannel) {
7511 0 : nsCOMPtr<nsIPresShell> shell;
7512 0 : rv = GetPresShell(getter_AddRefs(shell));
7513 0 : if (NS_SUCCEEDED(rv) && shell) {
7514 0 : nsIDocument *doc = shell->GetDocument();
7515 0 : if (doc) {
7516 : PRUint32 partID;
7517 0 : multiPartChannel->GetPartID(&partID);
7518 0 : doc->SetPartID(partID);
7519 : }
7520 : }
7521 : }
7522 :
7523 : // Give hint to native plevent dispatch mechanism. If a document
7524 : // is loading the native plevent dispatch mechanism should favor
7525 : // performance over normal native event dispatch priorities.
7526 0 : if (++gNumberOfDocumentsLoading == 1) {
7527 : // Hint to favor performance for the plevent notification mechanism.
7528 : // We want the pages to load as fast as possible even if its means
7529 : // native messages might be starved.
7530 0 : FavorPerformanceHint(true, NS_EVENT_STARVATION_DELAY_HINT);
7531 : }
7532 :
7533 0 : if (onLocationChangeNeeded) {
7534 0 : FireOnLocationChange(this, request, mCurrentURI, 0);
7535 : }
7536 :
7537 0 : return NS_OK;
7538 : }
7539 :
7540 : nsresult
7541 0 : nsDocShell::NewContentViewerObj(const char *aContentType,
7542 : nsIRequest * request, nsILoadGroup * aLoadGroup,
7543 : nsIStreamListener ** aContentHandler,
7544 : nsIContentViewer ** aViewer)
7545 : {
7546 0 : nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
7547 :
7548 : nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
7549 0 : nsContentUtils::FindInternalContentViewer(aContentType);
7550 0 : if (!docLoaderFactory) {
7551 0 : return NS_ERROR_FAILURE;
7552 : }
7553 :
7554 : // Now create an instance of the content viewer
7555 : // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"
7556 0 : nsresult rv = docLoaderFactory->CreateInstance("view",
7557 : aOpenedChannel,
7558 : aLoadGroup, aContentType,
7559 : static_cast<nsIContentViewerContainer*>(this),
7560 : nsnull,
7561 : aContentHandler,
7562 0 : aViewer);
7563 0 : NS_ENSURE_SUCCESS(rv, rv);
7564 :
7565 0 : (*aViewer)->SetContainer(static_cast<nsIContentViewerContainer *>(this));
7566 0 : return NS_OK;
7567 : }
7568 :
7569 : NS_IMETHODIMP
7570 0 : nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
7571 : {
7572 : //
7573 : // Copy content viewer state from previous or parent content viewer.
7574 : //
7575 : // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
7576 : //
7577 : // Do NOT to maintain a reference to the old content viewer outside
7578 : // of this "copying" block, or it will not be destroyed until the end of
7579 : // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
7580 : //
7581 : // In this block of code, if we get an error result, we return it
7582 : // but if we get a null pointer, that's perfectly legal for parent
7583 : // and parentContentViewer.
7584 : //
7585 :
7586 0 : PRInt32 x = 0;
7587 0 : PRInt32 y = 0;
7588 0 : PRInt32 cx = 0;
7589 0 : PRInt32 cy = 0;
7590 :
7591 : // This will get the size from the current content viewer or from the
7592 : // Init settings
7593 0 : DoGetPositionAndSize(&x, &y, &cx, &cy);
7594 :
7595 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
7596 0 : NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
7597 : NS_ERROR_FAILURE);
7598 0 : nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
7599 :
7600 0 : nsCAutoString defaultCharset;
7601 0 : nsCAutoString forceCharset;
7602 0 : nsCAutoString hintCharset;
7603 : PRInt32 hintCharsetSource;
7604 0 : nsCAutoString prevDocCharset;
7605 : PRInt32 minFontSize;
7606 : float textZoom;
7607 : float pageZoom;
7608 : bool styleDisabled;
7609 : // |newMUDV| also serves as a flag to set the data from the above vars
7610 0 : nsCOMPtr<nsIMarkupDocumentViewer> newMUDV;
7611 :
7612 0 : if (mContentViewer || parent) {
7613 0 : nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV;
7614 0 : if (mContentViewer) {
7615 : // Get any interesting state from old content viewer
7616 : // XXX: it would be far better to just reuse the document viewer ,
7617 : // since we know we're just displaying the same document as before
7618 0 : oldMUDV = do_QueryInterface(mContentViewer);
7619 :
7620 : // Tell the old content viewer to hibernate in session history when
7621 : // it is destroyed.
7622 :
7623 0 : if (mSavingOldViewer && NS_FAILED(CaptureState())) {
7624 0 : if (mOSHE) {
7625 0 : mOSHE->SyncPresentationState();
7626 : }
7627 0 : mSavingOldViewer = false;
7628 : }
7629 : }
7630 : else {
7631 : // No old content viewer, so get state from parent's content viewer
7632 0 : nsCOMPtr<nsIContentViewer> parentContentViewer;
7633 0 : parent->GetContentViewer(getter_AddRefs(parentContentViewer));
7634 0 : oldMUDV = do_QueryInterface(parentContentViewer);
7635 : }
7636 :
7637 0 : if (oldMUDV) {
7638 : nsresult rv;
7639 :
7640 0 : newMUDV = do_QueryInterface(aNewViewer,&rv);
7641 0 : if (newMUDV) {
7642 0 : NS_ENSURE_SUCCESS(oldMUDV->
7643 : GetDefaultCharacterSet(defaultCharset),
7644 : NS_ERROR_FAILURE);
7645 0 : NS_ENSURE_SUCCESS(oldMUDV->
7646 : GetForceCharacterSet(forceCharset),
7647 : NS_ERROR_FAILURE);
7648 0 : NS_ENSURE_SUCCESS(oldMUDV->
7649 : GetHintCharacterSet(hintCharset),
7650 : NS_ERROR_FAILURE);
7651 0 : NS_ENSURE_SUCCESS(oldMUDV->
7652 : GetHintCharacterSetSource(&hintCharsetSource),
7653 : NS_ERROR_FAILURE);
7654 0 : NS_ENSURE_SUCCESS(oldMUDV->
7655 : GetMinFontSize(&minFontSize),
7656 : NS_ERROR_FAILURE);
7657 0 : NS_ENSURE_SUCCESS(oldMUDV->
7658 : GetTextZoom(&textZoom),
7659 : NS_ERROR_FAILURE);
7660 0 : NS_ENSURE_SUCCESS(oldMUDV->
7661 : GetFullZoom(&pageZoom),
7662 : NS_ERROR_FAILURE);
7663 0 : NS_ENSURE_SUCCESS(oldMUDV->
7664 : GetAuthorStyleDisabled(&styleDisabled),
7665 : NS_ERROR_FAILURE);
7666 0 : NS_ENSURE_SUCCESS(oldMUDV->
7667 : GetPrevDocCharacterSet(prevDocCharset),
7668 : NS_ERROR_FAILURE);
7669 : }
7670 : }
7671 : }
7672 :
7673 0 : nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
7674 : // Ensure that the content viewer is destroyed *after* the GC - bug 71515
7675 0 : nsCOMPtr<nsIContentViewer> kungfuDeathGrip = mContentViewer;
7676 0 : if (mContentViewer) {
7677 : // Stop any activity that may be happening in the old document before
7678 : // releasing it...
7679 0 : mContentViewer->Stop();
7680 :
7681 : // Try to extract the canvas background color from the old
7682 : // presentation shell, so we can use it for the next document.
7683 0 : nsCOMPtr<nsIPresShell> shell;
7684 0 : mContentViewer->GetPresShell(getter_AddRefs(shell));
7685 :
7686 0 : if (shell) {
7687 0 : bgcolor = shell->GetCanvasBackground();
7688 : }
7689 :
7690 0 : mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull);
7691 0 : aNewViewer->SetPreviousViewer(mContentViewer);
7692 : }
7693 0 : if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
7694 : // We don't plan to save a viewer in mOSHE; tell it to drop
7695 : // any other state it's holding.
7696 0 : mOSHE->SyncPresentationState();
7697 : }
7698 :
7699 0 : mContentViewer = nsnull;
7700 :
7701 : // Now that we're about to switch documents, forget all of our children.
7702 : // Note that we cached them as needed up in CaptureState above.
7703 0 : DestroyChildren();
7704 :
7705 0 : mContentViewer = aNewViewer;
7706 :
7707 0 : nsCOMPtr<nsIWidget> widget;
7708 0 : NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
7709 :
7710 0 : nsIntRect bounds(x, y, cx, cy);
7711 :
7712 0 : mContentViewer->SetNavigationTiming(mTiming);
7713 :
7714 0 : if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
7715 0 : mContentViewer = nsnull;
7716 0 : NS_ERROR("ContentViewer Initialization failed");
7717 0 : return NS_ERROR_FAILURE;
7718 : }
7719 :
7720 : // If we have old state to copy, set the old state onto the new content
7721 : // viewer
7722 0 : if (newMUDV) {
7723 0 : NS_ENSURE_SUCCESS(newMUDV->SetDefaultCharacterSet(defaultCharset),
7724 : NS_ERROR_FAILURE);
7725 0 : NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset),
7726 : NS_ERROR_FAILURE);
7727 0 : NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset),
7728 : NS_ERROR_FAILURE);
7729 0 : NS_ENSURE_SUCCESS(newMUDV->
7730 : SetHintCharacterSetSource(hintCharsetSource),
7731 : NS_ERROR_FAILURE);
7732 0 : NS_ENSURE_SUCCESS(newMUDV->SetPrevDocCharacterSet(prevDocCharset),
7733 : NS_ERROR_FAILURE);
7734 0 : NS_ENSURE_SUCCESS(newMUDV->SetMinFontSize(minFontSize),
7735 : NS_ERROR_FAILURE);
7736 0 : NS_ENSURE_SUCCESS(newMUDV->SetTextZoom(textZoom),
7737 : NS_ERROR_FAILURE);
7738 0 : NS_ENSURE_SUCCESS(newMUDV->SetFullZoom(pageZoom),
7739 : NS_ERROR_FAILURE);
7740 0 : NS_ENSURE_SUCCESS(newMUDV->SetAuthorStyleDisabled(styleDisabled),
7741 : NS_ERROR_FAILURE);
7742 : }
7743 :
7744 : // Stuff the bgcolor from the old pres shell into the new
7745 : // pres shell. This improves page load continuity.
7746 0 : nsCOMPtr<nsIPresShell> shell;
7747 0 : mContentViewer->GetPresShell(getter_AddRefs(shell));
7748 :
7749 0 : if (shell) {
7750 0 : shell->SetCanvasBackground(bgcolor);
7751 : }
7752 :
7753 : // XXX: It looks like the LayoutState gets restored again in Embed()
7754 : // right after the call to SetupNewViewer(...)
7755 :
7756 : // We don't show the mContentViewer yet, since we want to draw the old page
7757 : // until we have enough of the new page to show. Just return with the new
7758 : // viewer still set to hidden.
7759 :
7760 0 : return NS_OK;
7761 : }
7762 :
7763 : nsresult
7764 0 : nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry)
7765 : {
7766 0 : nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
7767 0 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
7768 :
7769 0 : nsCOMPtr<nsIStructuredCloneContainer> scContainer;
7770 0 : if (shEntry) {
7771 0 : nsresult rv = shEntry->GetStateData(getter_AddRefs(scContainer));
7772 0 : NS_ENSURE_SUCCESS(rv, rv);
7773 :
7774 : // If shEntry is null, just set the document's state object to null.
7775 : }
7776 :
7777 : // It's OK for scContainer too be null here; that just means there's no
7778 : // state data associated with this history entry.
7779 0 : document->SetStateObject(scContainer);
7780 :
7781 0 : return NS_OK;
7782 : }
7783 :
7784 : nsresult
7785 0 : nsDocShell::CheckLoadingPermissions()
7786 : {
7787 : // This method checks whether the caller may load content into
7788 : // this docshell. Even though we've done our best to hide windows
7789 : // from code that doesn't have the right to access them, it's
7790 : // still possible for an evil site to open a window and access
7791 : // frames in the new window through window.frames[] (which is
7792 : // allAccess for historic reasons), so we still need to do this
7793 : // check on load.
7794 0 : nsresult rv = NS_OK, sameOrigin = NS_OK;
7795 :
7796 0 : if (!gValidateOrigin || !IsFrame()) {
7797 : // Origin validation was turned off, or we're not a frame.
7798 : // Permit all loads.
7799 :
7800 0 : return rv;
7801 : }
7802 :
7803 : // We're a frame. Check that the caller has write permission to
7804 : // the parent before allowing it to load anything into this
7805 : // docshell.
7806 :
7807 : nsCOMPtr<nsIScriptSecurityManager> securityManager =
7808 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
7809 0 : NS_ENSURE_SUCCESS(rv, rv);
7810 :
7811 0 : bool ubwEnabled = false;
7812 0 : rv = securityManager->IsCapabilityEnabled("UniversalXPConnect",
7813 0 : &ubwEnabled);
7814 0 : if (NS_FAILED(rv) || ubwEnabled) {
7815 0 : return rv;
7816 : }
7817 :
7818 0 : nsCOMPtr<nsIPrincipal> subjPrincipal;
7819 0 : rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal));
7820 0 : NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv);
7821 :
7822 : // Check if the caller is from the same origin as this docshell,
7823 : // or any of its ancestors.
7824 0 : nsCOMPtr<nsIDocShellTreeItem> item(this);
7825 0 : do {
7826 0 : nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item));
7827 0 : nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
7828 :
7829 : nsIPrincipal *p;
7830 0 : if (!sop || !(p = sop->GetPrincipal())) {
7831 0 : return NS_ERROR_UNEXPECTED;
7832 : }
7833 :
7834 : // Compare origins
7835 : bool equal;
7836 0 : sameOrigin = subjPrincipal->Equals(p, &equal);
7837 0 : if (NS_SUCCEEDED(sameOrigin)) {
7838 0 : if (equal) {
7839 : // Same origin, permit load
7840 :
7841 0 : return sameOrigin;
7842 : }
7843 :
7844 0 : sameOrigin = NS_ERROR_DOM_PROP_ACCESS_DENIED;
7845 : }
7846 :
7847 0 : nsCOMPtr<nsIDocShellTreeItem> tmp;
7848 0 : item->GetSameTypeParent(getter_AddRefs(tmp));
7849 0 : item.swap(tmp);
7850 0 : } while (item);
7851 :
7852 0 : return sameOrigin;
7853 : }
7854 :
7855 : //*****************************************************************************
7856 : // nsDocShell: Site Loading
7857 : //*****************************************************************************
7858 : namespace
7859 : {
7860 :
7861 : // Callback used by CopyFavicon to inform the favicon service that one URI
7862 : // (mNewURI) has the same favicon URI (OnFaviconDataAvailable's aFaviconURI) as
7863 : // another.
7864 : class nsCopyFaviconCallback : public nsIFaviconDataCallback
7865 0 : {
7866 : public:
7867 : NS_DECL_ISUPPORTS
7868 :
7869 0 : nsCopyFaviconCallback(nsIURI *aNewURI)
7870 0 : : mNewURI(aNewURI)
7871 : {
7872 0 : }
7873 :
7874 : NS_IMETHODIMP
7875 0 : OnFaviconDataAvailable(nsIURI *aFaviconURI, PRUint32 aDataLen,
7876 : const PRUint8 *aData, const nsACString &aMimeType)
7877 : {
7878 0 : NS_ASSERTION(aDataLen == 0,
7879 : "We weren't expecting the callback to deliver data.");
7880 : nsCOMPtr<mozIAsyncFavicons> favSvc =
7881 0 : do_GetService("@mozilla.org/browser/favicon-service;1");
7882 0 : NS_ENSURE_STATE(favSvc);
7883 :
7884 0 : return favSvc->SetAndFetchFaviconForPage(mNewURI, aFaviconURI,
7885 0 : false, nsnull);
7886 : }
7887 :
7888 : private:
7889 : nsCOMPtr<nsIURI> mNewURI;
7890 : };
7891 :
7892 0 : NS_IMPL_ISUPPORTS1(nsCopyFaviconCallback, nsIFaviconDataCallback)
7893 :
7894 : // Tell the favicon service that aNewURI has the same favicon as aOldURI.
7895 0 : void CopyFavicon(nsIURI *aOldURI, nsIURI *aNewURI)
7896 : {
7897 : nsCOMPtr<mozIAsyncFavicons> favSvc =
7898 0 : do_GetService("@mozilla.org/browser/favicon-service;1");
7899 0 : if (favSvc) {
7900 : nsCOMPtr<nsIFaviconDataCallback> callback =
7901 0 : new nsCopyFaviconCallback(aNewURI);
7902 0 : favSvc->GetFaviconURLForPage(aOldURI, callback);
7903 : }
7904 0 : }
7905 :
7906 : } // anonymous namespace
7907 :
7908 : class InternalLoadEvent : public nsRunnable
7909 0 : {
7910 : public:
7911 0 : InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
7912 : nsISupports * aOwner, PRUint32 aFlags,
7913 : const char* aTypeHint, nsIInputStream * aPostData,
7914 : nsIInputStream * aHeadersData, PRUint32 aLoadType,
7915 : nsISHEntry * aSHEntry, bool aFirstParty) :
7916 : mDocShell(aDocShell),
7917 : mURI(aURI),
7918 : mReferrer(aReferrer),
7919 : mOwner(aOwner),
7920 : mPostData(aPostData),
7921 : mHeadersData(aHeadersData),
7922 : mSHEntry(aSHEntry),
7923 : mFlags(aFlags),
7924 : mLoadType(aLoadType),
7925 0 : mFirstParty(aFirstParty)
7926 : {
7927 : // Make sure to keep null things null as needed
7928 0 : if (aTypeHint) {
7929 0 : mTypeHint = aTypeHint;
7930 : }
7931 0 : }
7932 :
7933 0 : NS_IMETHOD Run() {
7934 0 : return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
7935 : nsnull, mTypeHint.get(),
7936 : mPostData, mHeadersData, mLoadType,
7937 0 : mSHEntry, mFirstParty, nsnull, nsnull);
7938 : }
7939 :
7940 : private:
7941 :
7942 : // Use IDL strings so .get() returns null by default
7943 : nsXPIDLString mWindowTarget;
7944 : nsXPIDLCString mTypeHint;
7945 :
7946 : nsRefPtr<nsDocShell> mDocShell;
7947 : nsCOMPtr<nsIURI> mURI;
7948 : nsCOMPtr<nsIURI> mReferrer;
7949 : nsCOMPtr<nsISupports> mOwner;
7950 : nsCOMPtr<nsIInputStream> mPostData;
7951 : nsCOMPtr<nsIInputStream> mHeadersData;
7952 : nsCOMPtr<nsISHEntry> mSHEntry;
7953 : PRUint32 mFlags;
7954 : PRUint32 mLoadType;
7955 : bool mFirstParty;
7956 : };
7957 :
7958 : NS_IMETHODIMP
7959 0 : nsDocShell::InternalLoad(nsIURI * aURI,
7960 : nsIURI * aReferrer,
7961 : nsISupports * aOwner,
7962 : PRUint32 aFlags,
7963 : const PRUnichar *aWindowTarget,
7964 : const char* aTypeHint,
7965 : nsIInputStream * aPostData,
7966 : nsIInputStream * aHeadersData,
7967 : PRUint32 aLoadType,
7968 : nsISHEntry * aSHEntry,
7969 : bool aFirstParty,
7970 : nsIDocShell** aDocShell,
7971 : nsIRequest** aRequest)
7972 : {
7973 0 : nsresult rv = NS_OK;
7974 :
7975 : #ifdef PR_LOGGING
7976 0 : if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
7977 0 : nsCAutoString spec;
7978 0 : if (aURI)
7979 0 : aURI->GetSpec(spec);
7980 0 : PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get());
7981 : }
7982 : #endif
7983 :
7984 : // Initialize aDocShell/aRequest
7985 0 : if (aDocShell) {
7986 0 : *aDocShell = nsnull;
7987 : }
7988 0 : if (aRequest) {
7989 0 : *aRequest = nsnull;
7990 : }
7991 :
7992 0 : if (!aURI) {
7993 0 : return NS_ERROR_NULL_POINTER;
7994 : }
7995 :
7996 0 : NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
7997 :
7998 0 : NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
7999 :
8000 : // wyciwyg urls can only be loaded through history. Any normal load of
8001 : // wyciwyg through docshell is illegal. Disallow such loads.
8002 0 : if (aLoadType & LOAD_CMD_NORMAL) {
8003 0 : bool isWyciwyg = false;
8004 0 : rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
8005 0 : if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv))
8006 0 : return NS_ERROR_FAILURE;
8007 : }
8008 :
8009 0 : bool bIsJavascript = false;
8010 0 : if (NS_FAILED(aURI->SchemeIs("javascript", &bIsJavascript))) {
8011 0 : bIsJavascript = false;
8012 : }
8013 :
8014 : //
8015 : // First, notify any nsIContentPolicy listeners about the document load.
8016 : // Only abort the load if a content policy listener explicitly vetos it!
8017 : //
8018 0 : nsCOMPtr<nsIDOMElement> requestingElement;
8019 : // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed
8020 0 : nsCOMPtr<nsPIDOMWindow> privateWin(do_QueryInterface(mScriptGlobal));
8021 0 : if (privateWin)
8022 0 : requestingElement = privateWin->GetFrameElementInternal();
8023 :
8024 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
8025 : PRUint32 contentType;
8026 0 : if (IsFrame()) {
8027 0 : NS_ASSERTION(requestingElement, "A frame but no DOM element!?");
8028 0 : contentType = nsIContentPolicy::TYPE_SUBDOCUMENT;
8029 : } else {
8030 0 : contentType = nsIContentPolicy::TYPE_DOCUMENT;
8031 : }
8032 :
8033 0 : nsISupports* context = requestingElement;
8034 0 : if (!context) {
8035 0 : context = mScriptGlobal;
8036 : }
8037 :
8038 : // XXXbz would be nice to know the loading principal here... but we don't
8039 0 : nsCOMPtr<nsIPrincipal> loadingPrincipal;
8040 0 : if (aReferrer) {
8041 : nsCOMPtr<nsIScriptSecurityManager> secMan =
8042 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
8043 0 : NS_ENSURE_SUCCESS(rv, rv);
8044 :
8045 0 : rv = secMan->GetCodebasePrincipal(aReferrer,
8046 0 : getter_AddRefs(loadingPrincipal));
8047 : }
8048 :
8049 : rv = NS_CheckContentLoadPolicy(contentType,
8050 : aURI,
8051 : loadingPrincipal,
8052 : context,
8053 0 : EmptyCString(), //mime guess
8054 : nsnull, //extra
8055 0 : &shouldLoad);
8056 :
8057 0 : if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
8058 0 : if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
8059 0 : return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
8060 : }
8061 :
8062 0 : return NS_ERROR_CONTENT_BLOCKED;
8063 : }
8064 :
8065 0 : nsCOMPtr<nsISupports> owner(aOwner);
8066 : //
8067 : // Get an owner from the current document if necessary. Note that we only
8068 : // do this for URIs that inherit a security context and local file URIs;
8069 : // in particular we do NOT do this for about:blank. This way, random
8070 : // about:blank loads that have no owner (which basically means they were
8071 : // done by someone from chrome manually messing with our nsIWebNavigation
8072 : // or by C++ setting document.location) don't get a funky principal. If
8073 : // callers want something interesting to happen with the about:blank
8074 : // principal in this case, they should pass an owner in.
8075 : //
8076 : {
8077 : bool inherits;
8078 : // One more twist: Don't inherit the owner for external loads.
8079 0 : if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
8080 : (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) &&
8081 0 : NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
8082 : &inherits)) &&
8083 : inherits) {
8084 :
8085 0 : owner = GetInheritedPrincipal(true);
8086 : }
8087 : }
8088 :
8089 : // Don't allow loads that would inherit our security context
8090 : // if this document came from an unsafe channel.
8091 : {
8092 : bool willInherit;
8093 : // This condition needs to match the one in
8094 : // nsContentUtils::SetUpChannelOwner.
8095 : // Except we reverse the rv check to be safe in case
8096 : // nsContentUtils::URIInheritsSecurityContext fails here and
8097 : // succeeds there.
8098 0 : rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
8099 0 : if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
8100 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
8101 0 : do {
8102 : nsCOMPtr<nsIDocShell> itemDocShell =
8103 0 : do_QueryInterface(treeItem);
8104 : bool isUnsafe;
8105 0 : if (itemDocShell &&
8106 0 : NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
8107 : isUnsafe) {
8108 0 : return NS_ERROR_DOM_SECURITY_ERR;
8109 : }
8110 :
8111 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
8112 0 : treeItem->GetSameTypeParent(getter_AddRefs(parent));
8113 0 : parent.swap(treeItem);
8114 0 : } while (treeItem);
8115 : }
8116 : }
8117 :
8118 : //
8119 : // Resolve the window target before going any further...
8120 : // If the load has been targeted to another DocShell, then transfer the
8121 : // load to it...
8122 : //
8123 0 : if (aWindowTarget && *aWindowTarget) {
8124 : // We've already done our owner-inheriting. Mask out that bit, so we
8125 : // don't try inheriting an owner from the target window if we came up
8126 : // with a null owner above.
8127 0 : aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
8128 :
8129 : // Locate the target DocShell.
8130 : // This may involve creating a new toplevel window - if necessary.
8131 : //
8132 0 : nsCOMPtr<nsIDocShellTreeItem> targetItem;
8133 : FindItemWithName(aWindowTarget, nsnull, this,
8134 0 : getter_AddRefs(targetItem));
8135 :
8136 0 : nsCOMPtr<nsIDocShell> targetDocShell = do_QueryInterface(targetItem);
8137 :
8138 0 : bool isNewWindow = false;
8139 0 : if (!targetDocShell) {
8140 : nsCOMPtr<nsIDOMWindow> win =
8141 0 : do_GetInterface(GetAsSupports(this));
8142 0 : NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
8143 :
8144 0 : nsDependentString name(aWindowTarget);
8145 0 : nsCOMPtr<nsIDOMWindow> newWin;
8146 0 : rv = win->Open(EmptyString(), // URL to load
8147 : name, // window name
8148 0 : EmptyString(), // Features
8149 0 : getter_AddRefs(newWin));
8150 :
8151 : // In some cases the Open call doesn't actually result in a new
8152 : // window being opened. We can detect these cases by examining the
8153 : // document in |newWin|, if any.
8154 0 : nsCOMPtr<nsPIDOMWindow> piNewWin = do_QueryInterface(newWin);
8155 0 : if (piNewWin) {
8156 : nsCOMPtr<nsIDocument> newDoc =
8157 0 : do_QueryInterface(piNewWin->GetExtantDocument());
8158 0 : if (!newDoc || newDoc->IsInitialDocument()) {
8159 0 : isNewWindow = true;
8160 0 : aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
8161 : }
8162 : }
8163 :
8164 0 : nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
8165 0 : targetDocShell = do_QueryInterface(webNav);
8166 : }
8167 :
8168 : //
8169 : // Transfer the load to the target DocShell... Pass nsnull as the
8170 : // window target name from to prevent recursive retargeting!
8171 : //
8172 0 : if (NS_SUCCEEDED(rv) && targetDocShell) {
8173 0 : rv = targetDocShell->InternalLoad(aURI,
8174 : aReferrer,
8175 : owner,
8176 : aFlags,
8177 : nsnull, // No window target
8178 : aTypeHint,
8179 : aPostData,
8180 : aHeadersData,
8181 : aLoadType,
8182 : aSHEntry,
8183 : aFirstParty,
8184 : aDocShell,
8185 0 : aRequest);
8186 0 : if (rv == NS_ERROR_NO_CONTENT) {
8187 : // XXXbz except we never reach this code!
8188 0 : if (isNewWindow) {
8189 : //
8190 : // At this point, a new window has been created, but the
8191 : // URI did not have any data associated with it...
8192 : //
8193 : // So, the best we can do, is to tear down the new window
8194 : // that was just created!
8195 : //
8196 : nsCOMPtr<nsIDOMWindow> domWin =
8197 0 : do_GetInterface(targetDocShell);
8198 0 : if (domWin) {
8199 0 : domWin->Close();
8200 : }
8201 : }
8202 : //
8203 : // NS_ERROR_NO_CONTENT should not be returned to the
8204 : // caller... This is an internal error code indicating that
8205 : // the URI had no data associated with it - probably a
8206 : // helper-app style protocol (ie. mailto://)
8207 : //
8208 0 : rv = NS_OK;
8209 : }
8210 : else if (isNewWindow) {
8211 : // XXX: Once new windows are created hidden, the new
8212 : // window will need to be made visible... For now,
8213 : // do nothing.
8214 : }
8215 : }
8216 :
8217 : // Else we ran out of memory, or were a popup and got blocked,
8218 : // or something.
8219 :
8220 0 : return rv;
8221 : }
8222 :
8223 : //
8224 : // Load is being targetted at this docshell so return an error if the
8225 : // docshell is in the process of being destroyed.
8226 : //
8227 0 : if (mIsBeingDestroyed) {
8228 0 : return NS_ERROR_FAILURE;
8229 : }
8230 :
8231 0 : rv = CheckLoadingPermissions();
8232 0 : if (NS_FAILED(rv)) {
8233 0 : return rv;
8234 : }
8235 :
8236 : // If this docshell is owned by a frameloader, make sure to cancel
8237 : // possible frameloader initialization before loading a new page.
8238 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
8239 0 : GetParent(getter_AddRefs(parent));
8240 0 : if (parent) {
8241 0 : nsCOMPtr<nsIDocument> doc = do_GetInterface(parent);
8242 0 : if (doc) {
8243 0 : doc->TryCancelFrameLoaderInitialization(this);
8244 : }
8245 : }
8246 :
8247 0 : if (mFiredUnloadEvent) {
8248 0 : if (IsOKToLoadURI(aURI)) {
8249 0 : NS_PRECONDITION(!aWindowTarget || !*aWindowTarget,
8250 : "Shouldn't have a window target here!");
8251 :
8252 : // If this is a replace load, make whatever load triggered
8253 : // the unload event also a replace load, so we don't
8254 : // create extra history entries.
8255 0 : if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
8256 0 : mLoadType = LOAD_NORMAL_REPLACE;
8257 : }
8258 :
8259 : // Do this asynchronously
8260 : nsCOMPtr<nsIRunnable> ev =
8261 : new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
8262 : aTypeHint, aPostData, aHeadersData,
8263 0 : aLoadType, aSHEntry, aFirstParty);
8264 0 : return NS_DispatchToCurrentThread(ev);
8265 : }
8266 :
8267 : // Just ignore this load attempt
8268 0 : return NS_OK;
8269 : }
8270 :
8271 : // Before going any further vet loads initiated by external programs.
8272 0 : if (aLoadType == LOAD_NORMAL_EXTERNAL) {
8273 : // Disallow external chrome: loads targetted at content windows
8274 0 : bool isChrome = false;
8275 0 : if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
8276 0 : NS_WARNING("blocked external chrome: url -- use '-chrome' option");
8277 0 : return NS_ERROR_FAILURE;
8278 : }
8279 :
8280 : // clear the decks to prevent context bleed-through (bug 298255)
8281 0 : rv = CreateAboutBlankContentViewer(nsnull, nsnull);
8282 0 : if (NS_FAILED(rv))
8283 0 : return NS_ERROR_FAILURE;
8284 :
8285 : // reset loadType so we don't have to add lots of tests for
8286 : // LOAD_NORMAL_EXTERNAL after this point
8287 0 : aLoadType = LOAD_NORMAL;
8288 : }
8289 :
8290 : mAllowKeywordFixup =
8291 0 : (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
8292 0 : mURIResultedInDocument = false; // reset the clock...
8293 :
8294 0 : if (aLoadType == LOAD_NORMAL ||
8295 : aLoadType == LOAD_STOP_CONTENT ||
8296 : LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
8297 : aLoadType == LOAD_HISTORY ||
8298 : aLoadType == LOAD_LINK) {
8299 :
8300 : // Split mCurrentURI and aURI on the '#' character. Make sure we read
8301 : // the return values of SplitURIAtHash; if it fails, we don't want to
8302 : // allow a short-circuited navigation.
8303 0 : nsCAutoString curBeforeHash, curHash, newBeforeHash, newHash;
8304 : nsresult splitRv1, splitRv2;
8305 : splitRv1 = mCurrentURI ?
8306 : nsContentUtils::SplitURIAtHash(mCurrentURI,
8307 0 : curBeforeHash, curHash) :
8308 0 : NS_ERROR_FAILURE;
8309 0 : splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash);
8310 :
8311 0 : bool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
8312 0 : NS_SUCCEEDED(splitRv2) &&
8313 0 : curBeforeHash.Equals(newBeforeHash);
8314 :
8315 0 : bool historyNavBetweenSameDoc = false;
8316 0 : if (mOSHE && aSHEntry) {
8317 : // We're doing a history load.
8318 :
8319 0 : mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
8320 :
8321 : #ifdef DEBUG
8322 0 : if (historyNavBetweenSameDoc) {
8323 0 : nsCOMPtr<nsIInputStream> currentPostData;
8324 0 : mOSHE->GetPostData(getter_AddRefs(currentPostData));
8325 0 : NS_ASSERTION(currentPostData == aPostData,
8326 : "Different POST data for entries for the same page?");
8327 : }
8328 : #endif
8329 : }
8330 :
8331 : // A short-circuited load happens when we navigate between two SHEntries
8332 : // for the same document. We do a short-circuited load under two
8333 : // circumstances. Either
8334 : //
8335 : // a) we're navigating between two different SHEntries which share a
8336 : // document, or
8337 : //
8338 : // b) we're navigating to a new shentry whose URI differs from the
8339 : // current URI only in its hash, the new hash is non-empty, and
8340 : // we're not doing a POST.
8341 : //
8342 : // The restriction tha the SHEntries in (a) must be different ensures
8343 : // that history.go(0) and the like trigger full refreshes, rather than
8344 : // short-circuited loads.
8345 : bool doShortCircuitedLoad =
8346 0 : (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
8347 : (!aSHEntry && aPostData == nsnull &&
8348 0 : sameExceptHashes && !newHash.IsEmpty());
8349 :
8350 0 : if (doShortCircuitedLoad) {
8351 : // Save the current URI; we need it if we fire a hashchange later.
8352 0 : nsCOMPtr<nsIURI> oldURI = mCurrentURI;
8353 :
8354 : // Save the position of the scrollers.
8355 0 : nscoord cx = 0, cy = 0;
8356 0 : GetCurScrollPos(ScrollOrientation_X, &cx);
8357 0 : GetCurScrollPos(ScrollOrientation_Y, &cy);
8358 :
8359 : // ScrollToAnchor doesn't necessarily cause us to scroll the window;
8360 : // the function decides whether a scroll is appropriate based on the
8361 : // arguments it receives. But even if we don't end up scrolling,
8362 : // ScrollToAnchor performs other important tasks, such as informing
8363 : // the presShell that we have a new hash. See bug 680257.
8364 0 : rv = ScrollToAnchor(curHash, newHash, aLoadType);
8365 0 : NS_ENSURE_SUCCESS(rv, rv);
8366 :
8367 : // Reset mLoadType to its original value once we exit this block,
8368 : // because this short-circuited load might have started after a
8369 : // normal, network load, and we don't want to clobber its load type.
8370 : // See bug 737307.
8371 0 : AutoRestore<PRUint32> loadTypeResetter(mLoadType);
8372 :
8373 0 : mLoadType = aLoadType;
8374 0 : mURIResultedInDocument = true;
8375 :
8376 : /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
8377 : * SetCurrentURI() called from OnNewURI() will send proper
8378 : * onLocationChange() notifications to the browser to update
8379 : * back/forward buttons.
8380 : */
8381 0 : SetHistoryEntry(&mLSHE, aSHEntry);
8382 :
8383 : /* This is a anchor traversal with in the same page.
8384 : * call OnNewURI() so that, this traversal will be
8385 : * recorded in session and global history.
8386 : */
8387 0 : nsCOMPtr<nsISupports> owner;
8388 0 : if (mOSHE) {
8389 0 : mOSHE->GetOwner(getter_AddRefs(owner));
8390 : }
8391 : // Pass true for aCloneSHChildren, since we're not
8392 : // changing documents here, so all of our subframes are
8393 : // still relevant to the new session history entry.
8394 : //
8395 : // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
8396 : // flag on firing onLocationChange(...).
8397 : // Anyway, aCloneSHChildren param is simply reflecting
8398 : // doShortCircuitedLoad in this scope.
8399 0 : OnNewURI(aURI, nsnull, owner, mLoadType, true, true, true);
8400 :
8401 0 : nsCOMPtr<nsIInputStream> postData;
8402 0 : nsCOMPtr<nsISupports> cacheKey;
8403 :
8404 0 : if (mOSHE) {
8405 : /* save current position of scroller(s) (bug 59774) */
8406 0 : mOSHE->SetScrollPosition(cx, cy);
8407 : // Get the postdata and page ident from the current page, if
8408 : // the new load is being done via normal means. Note that
8409 : // "normal means" can be checked for just by checking for
8410 : // LOAD_CMD_NORMAL, given the loadType and allowScroll check
8411 : // above -- it filters out some LOAD_CMD_NORMAL cases that we
8412 : // wouldn't want here.
8413 0 : if (aLoadType & LOAD_CMD_NORMAL) {
8414 0 : mOSHE->GetPostData(getter_AddRefs(postData));
8415 0 : mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
8416 :
8417 : // Link our new SHEntry to the old SHEntry's back/forward
8418 : // cache data, since the two SHEntries correspond to the
8419 : // same document.
8420 0 : if (mLSHE)
8421 0 : mLSHE->AdoptBFCacheEntry(mOSHE);
8422 : }
8423 : }
8424 :
8425 : /* Assign mOSHE to mLSHE. This will either be a new entry created
8426 : * by OnNewURI() for normal loads or aSHEntry for history loads.
8427 : */
8428 0 : if (mLSHE) {
8429 0 : SetHistoryEntry(&mOSHE, mLSHE);
8430 : // Save the postData obtained from the previous page
8431 : // in to the session history entry created for the
8432 : // anchor page, so that any history load of the anchor
8433 : // page will restore the appropriate postData.
8434 0 : if (postData)
8435 0 : mOSHE->SetPostData(postData);
8436 :
8437 : // Make sure we won't just repost without hitting the
8438 : // cache first
8439 0 : if (cacheKey)
8440 0 : mOSHE->SetCacheKey(cacheKey);
8441 : }
8442 :
8443 : /* restore previous position of scroller(s), if we're moving
8444 : * back in history (bug 59774)
8445 : */
8446 0 : if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL))
8447 : {
8448 : nscoord bx, by;
8449 0 : mOSHE->GetScrollPosition(&bx, &by);
8450 0 : SetCurScrollPosEx(bx, by);
8451 : }
8452 :
8453 : /* Clear out mLSHE so that further anchor visits get
8454 : * recorded in SH and SH won't misbehave.
8455 : */
8456 0 : SetHistoryEntry(&mLSHE, nsnull);
8457 : /* Set the title for the SH entry for this target url. so that
8458 : * SH menus in go/back/forward buttons won't be empty for this.
8459 : */
8460 0 : if (mSessionHistory) {
8461 0 : PRInt32 index = -1;
8462 0 : mSessionHistory->GetIndex(&index);
8463 0 : nsCOMPtr<nsIHistoryEntry> hEntry;
8464 0 : mSessionHistory->GetEntryAtIndex(index, false,
8465 0 : getter_AddRefs(hEntry));
8466 0 : NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE);
8467 0 : nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(hEntry));
8468 0 : if (shEntry)
8469 0 : shEntry->SetTitle(mTitle);
8470 : }
8471 :
8472 : /* Set the title for the Global History entry for this anchor url.
8473 : */
8474 0 : if (mUseGlobalHistory) {
8475 0 : nsCOMPtr<IHistory> history = services::GetHistoryService();
8476 0 : if (history) {
8477 0 : history->SetURITitle(aURI, mTitle);
8478 : }
8479 0 : else if (mGlobalHistory) {
8480 0 : mGlobalHistory->SetPageTitle(aURI, mTitle);
8481 : }
8482 : }
8483 :
8484 : // Set the doc's URI according to the new history entry's URI.
8485 : nsCOMPtr<nsIDocument> doc =
8486 0 : do_GetInterface(GetAsSupports(this));
8487 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
8488 0 : doc->SetDocumentURI(aURI);
8489 :
8490 0 : SetDocCurrentStateObj(mOSHE);
8491 :
8492 : // Dispatch the popstate and hashchange events, as appropriate.
8493 0 : nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
8494 0 : if (window) {
8495 : // Fire a hashchange event URIs differ, and only in their hashes.
8496 0 : bool doHashchange = sameExceptHashes && !curHash.Equals(newHash);
8497 :
8498 0 : if (historyNavBetweenSameDoc || doHashchange) {
8499 0 : window->DispatchSyncPopState();
8500 : }
8501 :
8502 0 : if (doHashchange) {
8503 : // Make sure to use oldURI here, not mCurrentURI, because by
8504 : // now, mCurrentURI has changed!
8505 0 : window->DispatchAsyncHashchange(oldURI, aURI);
8506 : }
8507 : }
8508 :
8509 : // Inform the favicon service that the favicon for oldURI also
8510 : // applies to aURI.
8511 0 : CopyFavicon(oldURI, aURI);
8512 :
8513 0 : return NS_OK;
8514 : }
8515 : }
8516 :
8517 : // mContentViewer->PermitUnload can destroy |this| docShell, which
8518 : // causes the next call of CanSavePresentation to crash.
8519 : // Hold onto |this| until we return, to prevent a crash from happening.
8520 : // (bug#331040)
8521 0 : nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
8522 :
8523 0 : rv = MaybeInitTiming();
8524 0 : if (mTiming) {
8525 0 : mTiming->NotifyBeforeUnload();
8526 : }
8527 : // Check if the page doesn't want to be unloaded. The javascript:
8528 : // protocol handler deals with this for javascript: URLs.
8529 0 : if (!bIsJavascript && mContentViewer) {
8530 : bool okToUnload;
8531 0 : rv = mContentViewer->PermitUnload(false, &okToUnload);
8532 :
8533 0 : if (NS_SUCCEEDED(rv) && !okToUnload) {
8534 : // The user chose not to unload the page, interrupt the
8535 : // load.
8536 0 : return NS_OK;
8537 : }
8538 : }
8539 :
8540 0 : if (mTiming) {
8541 0 : mTiming->NotifyUnloadAccepted(mCurrentURI);
8542 : }
8543 :
8544 : // Check for saving the presentation here, before calling Stop().
8545 : // This is necessary so that we can catch any pending requests.
8546 : // Since the new request has not been created yet, we pass null for the
8547 : // new request parameter.
8548 : // Also pass nsnull for the document, since it doesn't affect the return
8549 : // value for our purposes here.
8550 0 : bool savePresentation = CanSavePresentation(aLoadType, nsnull, nsnull);
8551 :
8552 : // Don't stop current network activity for javascript: URL's since
8553 : // they might not result in any data, and thus nothing should be
8554 : // stopped in those cases. In the case where they do result in
8555 : // data, the javascript: URL channel takes care of stopping
8556 : // current network activity.
8557 0 : if (!bIsJavascript) {
8558 : // Stop any current network activity.
8559 : // Also stop content if this is a zombie doc. otherwise
8560 : // the onload will be delayed by other loads initiated in the
8561 : // background by the first document that
8562 : // didn't fully load before the next load was initiated.
8563 : // If not a zombie, don't stop content until data
8564 : // starts arriving from the new URI...
8565 :
8566 0 : nsCOMPtr<nsIContentViewer> zombieViewer;
8567 0 : if (mContentViewer) {
8568 0 : mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
8569 : }
8570 :
8571 0 : if (zombieViewer ||
8572 0 : LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
8573 0 : rv = Stop(nsIWebNavigation::STOP_ALL);
8574 : } else {
8575 0 : rv = Stop(nsIWebNavigation::STOP_NETWORK);
8576 : }
8577 :
8578 0 : if (NS_FAILED(rv))
8579 0 : return rv;
8580 : }
8581 :
8582 0 : mLoadType = aLoadType;
8583 :
8584 : // mLSHE should be assigned to aSHEntry, only after Stop() has
8585 : // been called. But when loading an error page, do not clear the
8586 : // mLSHE for the real page.
8587 0 : if (mLoadType != LOAD_ERROR_PAGE)
8588 0 : SetHistoryEntry(&mLSHE, aSHEntry);
8589 :
8590 0 : mSavingOldViewer = savePresentation;
8591 :
8592 : // If we have a saved content viewer in history, restore and show it now.
8593 0 : if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
8594 : // Make sure our history ID points to the same ID as
8595 : // SHEntry's docshell ID.
8596 0 : aSHEntry->GetDocshellID(&mHistoryID);
8597 :
8598 : // It's possible that the previous viewer of mContentViewer is the
8599 : // viewer that will end up in aSHEntry when it gets closed. If that's
8600 : // the case, we need to go ahead and force it into its shentry so we
8601 : // can restore it.
8602 0 : if (mContentViewer) {
8603 0 : nsCOMPtr<nsIContentViewer> prevViewer;
8604 0 : mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
8605 0 : if (prevViewer) {
8606 : #ifdef DEBUG
8607 0 : nsCOMPtr<nsIContentViewer> prevPrevViewer;
8608 0 : prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
8609 0 : NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
8610 : #endif
8611 0 : nsCOMPtr<nsISHEntry> viewerEntry;
8612 0 : prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
8613 0 : if (viewerEntry == aSHEntry) {
8614 : // Make sure this viewer ends up in the right place
8615 0 : mContentViewer->SetPreviousViewer(nsnull);
8616 0 : prevViewer->Destroy();
8617 : }
8618 : }
8619 : }
8620 0 : nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
8621 : bool restoring;
8622 0 : rv = RestorePresentation(aSHEntry, &restoring);
8623 0 : if (restoring)
8624 0 : return rv;
8625 :
8626 : // We failed to restore the presentation, so clean up.
8627 : // Both the old and new history entries could potentially be in
8628 : // an inconsistent state.
8629 0 : if (NS_FAILED(rv)) {
8630 0 : if (oldEntry)
8631 0 : oldEntry->SyncPresentationState();
8632 :
8633 0 : aSHEntry->SyncPresentationState();
8634 : }
8635 : }
8636 :
8637 0 : nsCOMPtr<nsIRequest> req;
8638 : rv = DoURILoad(aURI, aReferrer,
8639 : !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
8640 : owner, aTypeHint, aPostData, aHeadersData, aFirstParty,
8641 0 : aDocShell, getter_AddRefs(req),
8642 : (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
8643 : (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
8644 0 : (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0);
8645 0 : if (req && aRequest)
8646 0 : NS_ADDREF(*aRequest = req);
8647 :
8648 0 : if (NS_FAILED(rv)) {
8649 0 : nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
8650 0 : DisplayLoadError(rv, aURI, nsnull, chan);
8651 : }
8652 :
8653 0 : return rv;
8654 : }
8655 :
8656 : nsIPrincipal*
8657 0 : nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
8658 : {
8659 0 : nsCOMPtr<nsIDocument> document;
8660 0 : bool inheritedFromCurrent = false;
8661 :
8662 0 : if (aConsiderCurrentDocument && mContentViewer) {
8663 0 : document = mContentViewer->GetDocument();
8664 0 : inheritedFromCurrent = true;
8665 : }
8666 :
8667 0 : if (!document) {
8668 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
8669 0 : GetSameTypeParent(getter_AddRefs(parentItem));
8670 0 : if (parentItem) {
8671 0 : document = do_GetInterface(parentItem);
8672 : }
8673 : }
8674 :
8675 0 : if (!document) {
8676 0 : if (!aConsiderCurrentDocument) {
8677 0 : return nsnull;
8678 : }
8679 :
8680 : // Make sure we end up with _something_ as the principal no matter
8681 : // what.
8682 0 : EnsureContentViewer(); // If this fails, we'll just get a null
8683 : // docViewer and bail.
8684 :
8685 0 : if (!mContentViewer)
8686 0 : return nsnull;
8687 0 : document = mContentViewer->GetDocument();
8688 : }
8689 :
8690 : //-- Get the document's principal
8691 0 : if (document) {
8692 0 : nsIPrincipal *docPrincipal = document->NodePrincipal();
8693 :
8694 : // Don't allow loads in typeContent docShells to inherit the system
8695 : // principal from existing documents.
8696 0 : if (inheritedFromCurrent &&
8697 : mItemType == typeContent &&
8698 0 : nsContentUtils::IsSystemPrincipal(docPrincipal)) {
8699 0 : return nsnull;
8700 : }
8701 :
8702 0 : return docPrincipal;
8703 : }
8704 :
8705 0 : return nsnull;
8706 : }
8707 :
8708 : bool
8709 0 : nsDocShell::ShouldCheckAppCache(nsIURI *aURI)
8710 : {
8711 : nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
8712 0 : do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
8713 0 : if (!offlineService) {
8714 0 : return false;
8715 : }
8716 :
8717 : bool allowed;
8718 0 : nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
8719 : nsnull,
8720 0 : &allowed);
8721 0 : return NS_SUCCEEDED(rv) && allowed;
8722 : }
8723 :
8724 : nsresult
8725 0 : nsDocShell::DoURILoad(nsIURI * aURI,
8726 : nsIURI * aReferrerURI,
8727 : bool aSendReferrer,
8728 : nsISupports * aOwner,
8729 : const char * aTypeHint,
8730 : nsIInputStream * aPostData,
8731 : nsIInputStream * aHeadersData,
8732 : bool aFirstParty,
8733 : nsIDocShell ** aDocShell,
8734 : nsIRequest ** aRequest,
8735 : bool aIsNewWindowTarget,
8736 : bool aBypassClassifier,
8737 : bool aForceAllowCookies)
8738 : {
8739 : nsresult rv;
8740 0 : nsCOMPtr<nsIURILoader> uriLoader;
8741 :
8742 0 : uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
8743 0 : if (NS_FAILED(rv)) return rv;
8744 :
8745 0 : nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
8746 0 : if (aFirstParty) {
8747 : // tag first party URL loads
8748 0 : loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
8749 : }
8750 :
8751 0 : if (mLoadType == LOAD_ERROR_PAGE) {
8752 : // Error pages are LOAD_BACKGROUND
8753 0 : loadFlags |= nsIChannel::LOAD_BACKGROUND;
8754 : }
8755 :
8756 : // check for Content Security Policy to pass along with the
8757 : // new channel we are creating
8758 0 : nsCOMPtr<nsIChannelPolicy> channelPolicy;
8759 0 : if (IsFrame()) {
8760 : // check the parent docshell for a CSP
8761 0 : nsCOMPtr<nsIContentSecurityPolicy> csp;
8762 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
8763 0 : GetSameTypeParent(getter_AddRefs(parentItem));
8764 0 : nsCOMPtr<nsIDocument> doc = do_GetInterface(parentItem);
8765 0 : if (doc) {
8766 0 : rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
8767 0 : NS_ENSURE_SUCCESS(rv, rv);
8768 0 : if (csp) {
8769 0 : channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
8770 0 : channelPolicy->SetContentSecurityPolicy(csp);
8771 0 : channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
8772 : }
8773 : }
8774 : }
8775 :
8776 : // open a channel for the url
8777 0 : nsCOMPtr<nsIChannel> channel;
8778 :
8779 0 : rv = NS_NewChannel(getter_AddRefs(channel),
8780 : aURI,
8781 : nsnull,
8782 : nsnull,
8783 : static_cast<nsIInterfaceRequestor *>(this),
8784 : loadFlags,
8785 0 : channelPolicy);
8786 0 : if (NS_FAILED(rv)) {
8787 0 : if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
8788 : // This is a uri with a protocol scheme we don't know how
8789 : // to handle. Embedders might still be interested in
8790 : // handling the load, though, so we fire a notification
8791 : // before throwing the load away.
8792 0 : bool abort = false;
8793 0 : nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
8794 0 : if (NS_SUCCEEDED(rv2) && abort) {
8795 : // Hey, they're handling the load for us! How convenient!
8796 0 : return NS_OK;
8797 : }
8798 : }
8799 :
8800 0 : return rv;
8801 : }
8802 :
8803 : nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
8804 0 : do_QueryInterface(channel);
8805 0 : if (appCacheChannel) {
8806 : // Any document load should not inherit application cache.
8807 0 : appCacheChannel->SetInheritApplicationCache(false);
8808 :
8809 : // Loads with the correct permissions should check for a matching
8810 : // application cache.
8811 : // Permission will be checked in the parent process
8812 0 : if (GeckoProcessType_Default != XRE_GetProcessType())
8813 0 : appCacheChannel->SetChooseApplicationCache(true);
8814 : else
8815 0 : appCacheChannel->SetChooseApplicationCache(
8816 0 : ShouldCheckAppCache(aURI));
8817 : }
8818 :
8819 : // Make sure to give the caller a channel if we managed to create one
8820 : // This is important for correct error page/session history interaction
8821 0 : if (aRequest)
8822 0 : NS_ADDREF(*aRequest = channel);
8823 :
8824 0 : channel->SetOriginalURI(aURI);
8825 0 : if (aTypeHint && *aTypeHint) {
8826 0 : channel->SetContentType(nsDependentCString(aTypeHint));
8827 0 : mContentTypeHint = aTypeHint;
8828 : }
8829 : else {
8830 0 : mContentTypeHint.Truncate();
8831 : }
8832 :
8833 : //hack
8834 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
8835 0 : nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
8836 0 : if (httpChannelInternal) {
8837 0 : if (aForceAllowCookies) {
8838 0 : httpChannelInternal->SetForceAllowThirdPartyCookie(true);
8839 : }
8840 0 : if (aFirstParty) {
8841 0 : httpChannelInternal->SetDocumentURI(aURI);
8842 : } else {
8843 0 : httpChannelInternal->SetDocumentURI(aReferrerURI);
8844 : }
8845 : }
8846 :
8847 0 : nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
8848 0 : if (props)
8849 : {
8850 : // save true referrer for those who need it (e.g. xpinstall whitelisting)
8851 : // Currently only http and ftp channels support this.
8852 0 : props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
8853 0 : aReferrerURI);
8854 : }
8855 :
8856 : //
8857 : // If this is a HTTP channel, then set up the HTTP specific information
8858 : // (ie. POST data, referrer, ...)
8859 : //
8860 0 : if (httpChannel) {
8861 0 : nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(httpChannel));
8862 : /* Get the cache Key from SH */
8863 0 : nsCOMPtr<nsISupports> cacheKey;
8864 0 : if (mLSHE) {
8865 0 : mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
8866 : }
8867 0 : else if (mOSHE) // for reload cases
8868 0 : mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
8869 :
8870 : // figure out if we need to set the post data stream on the channel...
8871 : // right now, this is only done for http channels.....
8872 0 : if (aPostData) {
8873 : // XXX it's a bit of a hack to rewind the postdata stream here but
8874 : // it has to be done in case the post data is being reused multiple
8875 : // times.
8876 : nsCOMPtr<nsISeekableStream>
8877 0 : postDataSeekable(do_QueryInterface(aPostData));
8878 0 : if (postDataSeekable) {
8879 0 : rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
8880 0 : NS_ENSURE_SUCCESS(rv, rv);
8881 : }
8882 :
8883 0 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
8884 0 : NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
8885 :
8886 : // we really need to have a content type associated with this stream!!
8887 0 : uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1);
8888 : /* If there is a valid postdata *and* it is a History Load,
8889 : * set up the cache key on the channel, to retrieve the
8890 : * data *only* from the cache. If it is a normal reload, the
8891 : * cache is free to go to the server for updated postdata.
8892 : */
8893 0 : if (cacheChannel && cacheKey) {
8894 0 : if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
8895 0 : cacheChannel->SetCacheKey(cacheKey);
8896 : PRUint32 loadFlags;
8897 0 : if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags)))
8898 0 : channel->SetLoadFlags(loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
8899 : }
8900 0 : else if (mLoadType == LOAD_RELOAD_NORMAL)
8901 0 : cacheChannel->SetCacheKey(cacheKey);
8902 : }
8903 : }
8904 : else {
8905 : /* If there is no postdata, set the cache key on the channel, and
8906 : * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
8907 : * will be free to get it from net if it is not found in cache.
8908 : * New cache may use it creatively on CGI pages with GET
8909 : * method and even on those that say "no-cache"
8910 : */
8911 0 : if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL
8912 : || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
8913 0 : if (cacheChannel && cacheKey)
8914 0 : cacheChannel->SetCacheKey(cacheKey);
8915 : }
8916 : }
8917 0 : if (aHeadersData) {
8918 0 : rv = AddHeadersToChannel(aHeadersData, httpChannel);
8919 : }
8920 : // Set the referrer explicitly
8921 0 : if (aReferrerURI && aSendReferrer) {
8922 : // Referrer is currenly only set for link clicks here.
8923 0 : httpChannel->SetReferrer(aReferrerURI);
8924 : }
8925 : }
8926 :
8927 0 : nsCOMPtr<nsIPrincipal> ownerPrincipal(do_QueryInterface(aOwner));
8928 0 : nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true);
8929 :
8930 0 : nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
8931 0 : if (scriptChannel) {
8932 : // Allow execution against our context if the principals match
8933 0 : scriptChannel->
8934 0 : SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
8935 : }
8936 :
8937 0 : if (aIsNewWindowTarget) {
8938 0 : nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
8939 0 : if (props) {
8940 0 : props->SetPropertyAsBool(
8941 0 : NS_LITERAL_STRING("docshell.newWindowTarget"),
8942 0 : true);
8943 : }
8944 : }
8945 :
8946 0 : if (Preferences::GetBool("dom.enable_performance", false)) {
8947 0 : nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
8948 0 : if (timedChannel) {
8949 0 : timedChannel->SetTimingEnabled(true);
8950 : }
8951 : }
8952 :
8953 0 : rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
8954 :
8955 : //
8956 : // If the channel load failed, we failed and nsIWebProgress just ain't
8957 : // gonna happen.
8958 : //
8959 0 : if (NS_SUCCEEDED(rv)) {
8960 0 : if (aDocShell) {
8961 0 : *aDocShell = this;
8962 0 : NS_ADDREF(*aDocShell);
8963 : }
8964 : }
8965 :
8966 0 : return rv;
8967 : }
8968 :
8969 : static NS_METHOD
8970 0 : AppendSegmentToString(nsIInputStream *in,
8971 : void *closure,
8972 : const char *fromRawSegment,
8973 : PRUint32 toOffset,
8974 : PRUint32 count,
8975 : PRUint32 *writeCount)
8976 : {
8977 : // aFromSegment now contains aCount bytes of data.
8978 :
8979 0 : nsCAutoString *buf = static_cast<nsCAutoString *>(closure);
8980 0 : buf->Append(fromRawSegment, count);
8981 :
8982 : // Indicate that we have consumed all of aFromSegment
8983 0 : *writeCount = count;
8984 0 : return NS_OK;
8985 : }
8986 :
8987 : NS_IMETHODIMP
8988 0 : nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData,
8989 : nsIChannel *aGenericChannel)
8990 : {
8991 0 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
8992 0 : NS_ENSURE_STATE(httpChannel);
8993 :
8994 : PRUint32 numRead;
8995 0 : nsCAutoString headersString;
8996 : nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
8997 : &headersString,
8998 : PR_UINT32_MAX,
8999 0 : &numRead);
9000 0 : NS_ENSURE_SUCCESS(rv, rv);
9001 :
9002 : // used during the manipulation of the String from the InputStream
9003 0 : nsCAutoString headerName;
9004 0 : nsCAutoString headerValue;
9005 : PRInt32 crlf;
9006 : PRInt32 colon;
9007 :
9008 : //
9009 : // Iterate over the headersString: for each "\r\n" delimited chunk,
9010 : // add the value as a header to the nsIHttpChannel
9011 : //
9012 :
9013 : static const char kWhitespace[] = "\b\t\r\n ";
9014 0 : while (true) {
9015 0 : crlf = headersString.Find("\r\n");
9016 0 : if (crlf == kNotFound)
9017 0 : return NS_OK;
9018 :
9019 0 : const nsCSubstring &oneHeader = StringHead(headersString, crlf);
9020 :
9021 0 : colon = oneHeader.FindChar(':');
9022 0 : if (colon == kNotFound)
9023 0 : return NS_ERROR_UNEXPECTED;
9024 :
9025 0 : headerName = StringHead(oneHeader, colon);
9026 0 : headerValue = Substring(oneHeader, colon + 1);
9027 :
9028 0 : headerName.Trim(kWhitespace);
9029 0 : headerValue.Trim(kWhitespace);
9030 :
9031 0 : headersString.Cut(0, crlf + 2);
9032 :
9033 : //
9034 : // FINALLY: we can set the header!
9035 : //
9036 :
9037 0 : rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
9038 0 : NS_ENSURE_SUCCESS(rv, rv);
9039 : }
9040 :
9041 : NS_NOTREACHED("oops");
9042 : return NS_ERROR_UNEXPECTED;
9043 : }
9044 :
9045 0 : nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
9046 : nsIURILoader * aURILoader,
9047 : bool aBypassClassifier)
9048 : {
9049 : nsresult rv;
9050 : // Mark the channel as being a document URI and allow content sniffing...
9051 0 : nsLoadFlags loadFlags = 0;
9052 0 : (void) aChannel->GetLoadFlags(&loadFlags);
9053 : loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
9054 0 : nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
9055 :
9056 : // Load attributes depend on load type...
9057 0 : switch (mLoadType) {
9058 : case LOAD_HISTORY:
9059 : {
9060 : // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
9061 : // push/replaceState (bug 669671).
9062 0 : bool uriModified = false;
9063 0 : if (mLSHE) {
9064 0 : mLSHE->GetURIWasModified(&uriModified);
9065 : }
9066 :
9067 0 : if (!uriModified)
9068 0 : loadFlags |= nsIRequest::VALIDATE_NEVER;
9069 : }
9070 0 : break;
9071 :
9072 : case LOAD_RELOAD_CHARSET_CHANGE:
9073 0 : loadFlags |= nsIRequest::LOAD_FROM_CACHE;
9074 0 : break;
9075 :
9076 : case LOAD_RELOAD_NORMAL:
9077 : case LOAD_REFRESH:
9078 0 : loadFlags |= nsIRequest::VALIDATE_ALWAYS;
9079 0 : break;
9080 :
9081 : case LOAD_NORMAL_BYPASS_CACHE:
9082 : case LOAD_NORMAL_BYPASS_PROXY:
9083 : case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
9084 : case LOAD_RELOAD_BYPASS_CACHE:
9085 : case LOAD_RELOAD_BYPASS_PROXY:
9086 : case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
9087 : loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
9088 0 : nsIRequest::LOAD_FRESH_CONNECTION;
9089 0 : break;
9090 :
9091 : case LOAD_NORMAL:
9092 : case LOAD_LINK:
9093 : // Set cache checking flags
9094 0 : switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
9095 : case 0:
9096 0 : loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
9097 0 : break;
9098 : case 1:
9099 0 : loadFlags |= nsIRequest::VALIDATE_ALWAYS;
9100 0 : break;
9101 : case 2:
9102 0 : loadFlags |= nsIRequest::VALIDATE_NEVER;
9103 0 : break;
9104 : }
9105 0 : break;
9106 : }
9107 :
9108 0 : if (!aBypassClassifier) {
9109 0 : loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
9110 : }
9111 :
9112 0 : (void) aChannel->SetLoadFlags(loadFlags);
9113 :
9114 : rv = aURILoader->OpenURI(aChannel,
9115 : (mLoadType == LOAD_LINK),
9116 0 : this);
9117 0 : NS_ENSURE_SUCCESS(rv, rv);
9118 :
9119 0 : return NS_OK;
9120 : }
9121 :
9122 : nsresult
9123 0 : nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
9124 : PRUint32 aLoadType)
9125 : {
9126 0 : if (!mCurrentURI) {
9127 0 : return NS_OK;
9128 : }
9129 :
9130 0 : nsCOMPtr<nsIPresShell> shell;
9131 0 : nsresult rv = GetPresShell(getter_AddRefs(shell));
9132 0 : if (NS_FAILED(rv) || !shell) {
9133 : // If we failed to get the shell, or if there is no shell,
9134 : // nothing left to do here.
9135 0 : return rv;
9136 : }
9137 :
9138 : // If we have no new anchor, we do not want to scroll, unless there is a
9139 : // current anchor and we are doing a history load. So return if we have no
9140 : // new anchor, and there is no current anchor or the load is not a history
9141 : // load.
9142 0 : if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) &&
9143 0 : aNewHash.IsEmpty()) {
9144 0 : return NS_OK;
9145 : }
9146 :
9147 : // Take the '#' off aNewHash to get the ref name. (aNewHash might be empty,
9148 : // but that's fine.)
9149 0 : nsDependentCSubstring newHashName(aNewHash, 1);
9150 :
9151 : // Both the new and current URIs refer to the same page. We can now
9152 : // browse to the hash stored in the new URI.
9153 :
9154 0 : if (!newHashName.IsEmpty()) {
9155 : // anchor is there, but if it's a load from history,
9156 : // we don't have any anchor jumping to do
9157 : bool scroll = aLoadType != LOAD_HISTORY &&
9158 0 : aLoadType != LOAD_RELOAD_NORMAL;
9159 :
9160 0 : char *str = ToNewCString(newHashName);
9161 0 : if (!str) {
9162 0 : return NS_ERROR_OUT_OF_MEMORY;
9163 : }
9164 :
9165 : // nsUnescape modifies the string that is passed into it.
9166 0 : nsUnescape(str);
9167 :
9168 : // We assume that the bytes are in UTF-8, as it says in the
9169 : // spec:
9170 : // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
9171 :
9172 : // We try the UTF-8 string first, and then try the document's
9173 : // charset (see below). If the string is not UTF-8,
9174 : // conversion will fail and give us an empty Unicode string.
9175 : // In that case, we should just fall through to using the
9176 : // page's charset.
9177 0 : rv = NS_ERROR_FAILURE;
9178 0 : NS_ConvertUTF8toUTF16 uStr(str);
9179 0 : if (!uStr.IsEmpty()) {
9180 0 : rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll);
9181 : }
9182 0 : nsMemory::Free(str);
9183 :
9184 : // Above will fail if the anchor name is not UTF-8. Need to
9185 : // convert from document charset to unicode.
9186 0 : if (NS_FAILED(rv)) {
9187 :
9188 : // Get a document charset
9189 0 : NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
9190 0 : nsIDocument* doc = mContentViewer->GetDocument();
9191 0 : NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
9192 0 : const nsACString &aCharset = doc->GetDocumentCharacterSet();
9193 :
9194 : nsCOMPtr<nsITextToSubURI> textToSubURI =
9195 0 : do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
9196 0 : NS_ENSURE_SUCCESS(rv, rv);
9197 :
9198 : // Unescape and convert to unicode
9199 0 : nsXPIDLString uStr;
9200 :
9201 0 : rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
9202 0 : PromiseFlatCString(newHashName).get(),
9203 0 : getter_Copies(uStr));
9204 0 : NS_ENSURE_SUCCESS(rv, rv);
9205 :
9206 : // Ignore return value of GoToAnchor, since it will return an error
9207 : // if there is no such anchor in the document, which is actually a
9208 : // success condition for us (we want to update the session history
9209 : // with the new URI no matter whether we actually scrolled
9210 : // somewhere).
9211 0 : shell->GoToAnchor(uStr, scroll);
9212 : }
9213 : }
9214 : else {
9215 :
9216 : // Tell the shell it's at an anchor, without scrolling.
9217 0 : shell->GoToAnchor(EmptyString(), false);
9218 :
9219 : // An empty anchor was found, but if it's a load from history,
9220 : // we don't have to jump to the top of the page. Scrollbar
9221 : // position will be restored by the caller, based on positions
9222 : // stored in session history.
9223 0 : if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
9224 0 : return NS_OK;
9225 : // An empty anchor. Scroll to the top of the page. Ignore the
9226 : // return value; failure to scroll here (e.g. if there is no
9227 : // root scrollframe) is not grounds for canceling the load!
9228 0 : SetCurScrollPosEx(0, 0);
9229 : }
9230 :
9231 0 : return NS_OK;
9232 : }
9233 :
9234 : void
9235 0 : nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
9236 : {
9237 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
9238 0 : if (httpChannel) {
9239 0 : nsCOMPtr<nsIURI> referrer;
9240 0 : nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
9241 0 : if (NS_SUCCEEDED(rv)) {
9242 0 : SetReferrerURI(referrer);
9243 : }
9244 : }
9245 0 : }
9246 :
9247 : bool
9248 0 : nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
9249 : PRUint32 aLoadType, bool aFireOnLocationChange,
9250 : bool aAddToGlobalHistory, bool aCloneSHChildren)
9251 : {
9252 0 : NS_PRECONDITION(aURI, "uri is null");
9253 0 : NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
9254 :
9255 : #if defined(PR_LOGGING) && defined(DEBUG)
9256 0 : if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
9257 0 : nsCAutoString spec;
9258 0 : aURI->GetSpec(spec);
9259 :
9260 0 : nsCAutoString chanName;
9261 0 : if (aChannel)
9262 0 : aChannel->GetName(chanName);
9263 : else
9264 0 : chanName.AssignLiteral("<no channel>");
9265 :
9266 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
9267 : ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(),
9268 : chanName.get(), aLoadType));
9269 : }
9270 : #endif
9271 :
9272 0 : bool updateHistory = true;
9273 0 : bool equalUri = false;
9274 0 : bool shAvailable = true;
9275 :
9276 : // Get the post data from the channel
9277 0 : nsCOMPtr<nsIInputStream> inputStream;
9278 0 : if (aChannel) {
9279 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
9280 :
9281 : // Check if the HTTPChannel is hiding under a multiPartChannel
9282 0 : if (!httpChannel) {
9283 0 : GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
9284 : }
9285 :
9286 0 : if (httpChannel) {
9287 0 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
9288 0 : if (uploadChannel) {
9289 0 : uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
9290 : }
9291 :
9292 : // If the response status indicates an error, unlink this session
9293 : // history entry from any entries sharing its document.
9294 : PRUint32 responseStatus;
9295 0 : nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
9296 0 : if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
9297 0 : mLSHE->AbandonBFCacheEntry();
9298 : }
9299 : }
9300 : }
9301 : /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
9302 : * the current frame or in the root docshell
9303 : */
9304 0 : nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
9305 0 : if (!rootSH) {
9306 : // Get the handle to SH from the root docshell
9307 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
9308 0 : if (!rootSH)
9309 0 : shAvailable = false;
9310 : } // rootSH
9311 :
9312 :
9313 : // Determine if this type of load should update history.
9314 0 : if (aLoadType == LOAD_BYPASS_HISTORY ||
9315 : aLoadType == LOAD_ERROR_PAGE ||
9316 : aLoadType & LOAD_CMD_HISTORY ||
9317 : aLoadType & LOAD_CMD_RELOAD)
9318 0 : updateHistory = false;
9319 :
9320 : // Check if the url to be loaded is the same as the one already loaded.
9321 0 : if (mCurrentURI)
9322 0 : aURI->Equals(mCurrentURI, &equalUri);
9323 :
9324 : #ifdef DEBUG
9325 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
9326 : (" shAvailable=%i updateHistory=%i equalURI=%i\n",
9327 : shAvailable, updateHistory, equalUri));
9328 :
9329 0 : if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
9330 0 : NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?");
9331 : }
9332 : #endif
9333 :
9334 : /* If the url to be loaded is the same as the one already there,
9335 : * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
9336 : * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
9337 : * AddToSessionHistory() won't mess with the current SHEntry and
9338 : * if this page has any frame children, it also will be handled
9339 : * properly. see bug 83684
9340 : *
9341 : * NB: If mOSHE is null but we have a current URI, then it means
9342 : * that we must be at the transient about:blank content viewer
9343 : * (asserted above) and we should let the normal load continue,
9344 : * since there's nothing to replace.
9345 : *
9346 : * XXX Hopefully changing the loadType at this time will not hurt
9347 : * anywhere. The other way to take care of sequentially repeating
9348 : * frameset pages is to add new methods to nsIDocShellTreeItem.
9349 : * Hopefully I don't have to do that.
9350 : */
9351 0 : if (equalUri &&
9352 0 : mOSHE &&
9353 : (mLoadType == LOAD_NORMAL ||
9354 : mLoadType == LOAD_LINK ||
9355 : mLoadType == LOAD_STOP_CONTENT) &&
9356 0 : !inputStream)
9357 : {
9358 0 : mLoadType = LOAD_NORMAL_REPLACE;
9359 : }
9360 :
9361 : // If this is a refresh to the currently loaded url, we don't
9362 : // have to update session or global history.
9363 0 : if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
9364 0 : SetHistoryEntry(&mLSHE, mOSHE);
9365 : }
9366 :
9367 : /* If the user pressed shift-reload, cache will create a new cache key
9368 : * for the page. Save the new cacheKey in Session History.
9369 : * see bug 90098
9370 : */
9371 0 : if (aChannel &&
9372 : (aLoadType == LOAD_RELOAD_BYPASS_CACHE ||
9373 : aLoadType == LOAD_RELOAD_BYPASS_PROXY ||
9374 : aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
9375 0 : NS_ASSERTION(!updateHistory,
9376 : "We shouldn't be updating history for forced reloads!");
9377 :
9378 0 : nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
9379 0 : nsCOMPtr<nsISupports> cacheKey;
9380 : // Get the Cache Key and store it in SH.
9381 0 : if (cacheChannel)
9382 0 : cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
9383 : // If we already have a loading history entry, store the new cache key
9384 : // in it. Otherwise, since we're doing a reload and won't be updating
9385 : // our history entry, store the cache key in our current history entry.
9386 0 : if (mLSHE)
9387 0 : mLSHE->SetCacheKey(cacheKey);
9388 0 : else if (mOSHE)
9389 0 : mOSHE->SetCacheKey(cacheKey);
9390 :
9391 : // Since we're force-reloading, clear all the sub frame history.
9392 0 : ClearFrameHistory(mLSHE);
9393 0 : ClearFrameHistory(mOSHE);
9394 : }
9395 :
9396 0 : if (aLoadType == LOAD_RELOAD_NORMAL) {
9397 0 : nsCOMPtr<nsISHEntry> currentSH;
9398 0 : bool oshe = false;
9399 0 : GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
9400 0 : bool dynamicallyAddedChild = false;
9401 0 : if (currentSH) {
9402 0 : currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
9403 : }
9404 0 : if (dynamicallyAddedChild) {
9405 0 : ClearFrameHistory(currentSH);
9406 : }
9407 : }
9408 :
9409 0 : if (aLoadType == LOAD_REFRESH) {
9410 0 : ClearFrameHistory(mLSHE);
9411 0 : ClearFrameHistory(mOSHE);
9412 : }
9413 :
9414 0 : if (updateHistory && shAvailable) {
9415 : // Update session history if necessary...
9416 0 : if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
9417 : /* This is a fresh page getting loaded for the first time
9418 : *.Create a Entry for it and add it to SH, if this is the
9419 : * rootDocShell
9420 : */
9421 : (void) AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren,
9422 0 : getter_AddRefs(mLSHE));
9423 : }
9424 :
9425 0 : if (aAddToGlobalHistory) {
9426 : // If this is a POST request, we do not want to include this in global
9427 : // history.
9428 0 : if (!ChannelIsPost(aChannel)) {
9429 0 : nsCOMPtr<nsIURI> previousURI;
9430 0 : PRUint32 previousFlags = 0;
9431 0 : ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
9432 0 : &previousFlags);
9433 :
9434 0 : nsCOMPtr<nsIURI> referrer;
9435 : // Treat referrer as null if there is an error getting it.
9436 : (void)NS_GetReferrerFromChannel(aChannel,
9437 0 : getter_AddRefs(referrer));
9438 :
9439 0 : AddURIVisit(aURI, referrer, previousURI, previousFlags);
9440 : }
9441 : }
9442 : }
9443 :
9444 : // If this was a history load or a refresh,
9445 : // update the index in SH.
9446 0 : if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) {
9447 0 : nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
9448 0 : if (shInternal) {
9449 0 : rootSH->GetIndex(&mPreviousTransIndex);
9450 0 : shInternal->UpdateIndex();
9451 0 : rootSH->GetIndex(&mLoadedTransIndex);
9452 : #ifdef DEBUG_PAGE_CACHE
9453 : printf("Previous index: %d, Loaded index: %d\n\n",
9454 : mPreviousTransIndex, mLoadedTransIndex);
9455 : #endif
9456 : }
9457 : }
9458 :
9459 : // aCloneSHChildren exactly means "we are not loading a new document".
9460 : PRUint32 locationFlags = aCloneSHChildren?
9461 0 : PRUint32(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
9462 :
9463 : bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
9464 : aFireOnLocationChange,
9465 0 : locationFlags);
9466 : // Make sure to store the referrer from the channel, if any
9467 0 : SetupReferrerFromChannel(aChannel);
9468 0 : return onLocationChangeNeeded;
9469 : }
9470 :
9471 : bool
9472 0 : nsDocShell::OnLoadingSite(nsIChannel * aChannel, bool aFireOnLocationChange,
9473 : bool aAddToGlobalHistory)
9474 : {
9475 0 : nsCOMPtr<nsIURI> uri;
9476 : // If this a redirect, use the final url (uri)
9477 : // else use the original url
9478 : //
9479 : // Note that this should match what documents do (see nsDocument::Reset).
9480 0 : NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
9481 0 : NS_ENSURE_TRUE(uri, false);
9482 :
9483 : // Pass false for aCloneSHChildren, since we're loading a new page here.
9484 : return OnNewURI(uri, aChannel, nsnull, mLoadType, aFireOnLocationChange,
9485 0 : aAddToGlobalHistory, false);
9486 :
9487 : }
9488 :
9489 : void
9490 0 : nsDocShell::SetReferrerURI(nsIURI * aURI)
9491 : {
9492 0 : mReferrerURI = aURI; // This assigment addrefs
9493 0 : }
9494 :
9495 : //*****************************************************************************
9496 : // nsDocShell: Session History
9497 : //*****************************************************************************
9498 :
9499 : NS_IMETHODIMP
9500 0 : nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
9501 : const nsAString& aURL, bool aReplace, JSContext* aCx)
9502 : {
9503 : // Implements History.pushState and History.replaceState
9504 :
9505 : // Here's what we do, roughly in the order specified by HTML5:
9506 : // 1. Serialize aData using structured clone.
9507 : // 2. If the third argument is present,
9508 : // a. Resolve the url, relative to the first script's base URL
9509 : // b. If (a) fails, raise a SECURITY_ERR
9510 : // c. Compare the resulting absolute URL to the document's address. If
9511 : // any part of the URLs difer other than the <path>, <query>, and
9512 : // <fragment> components, raise a SECURITY_ERR and abort.
9513 : // 3. If !aReplace:
9514 : // Remove from the session history all entries after the current entry,
9515 : // as we would after a regular navigation, and save the current
9516 : // entry's scroll position (bug 590573).
9517 : // 4. As apropriate, either add a state object entry to the session history
9518 : // after the current entry with the following properties, or modify the
9519 : // current session history entry to set
9520 : // a. cloned data as the state object,
9521 : // b. if the third argument was present, the absolute URL found in
9522 : // step 2
9523 : // Also clear the new history entry's POST data (see bug 580069).
9524 : // 5. If aReplace is false (i.e. we're doing a pushState instead of a
9525 : // replaceState), notify bfcache that we've navigated to a new page.
9526 : // 6. If the third argument is present, set the document's current address
9527 : // to the absolute URL found in step 2.
9528 : //
9529 : // It's important that this function not run arbitrary scripts after step 1
9530 : // and before completing step 5. For example, if a script called
9531 : // history.back() before we completed step 5, bfcache might destroy an
9532 : // active content viewer. Since EvictOutOfRangeContentViewers at the end of
9533 : // step 5 might run script, we can't just put a script blocker around the
9534 : // critical section.
9535 : //
9536 : // Note that we completely ignore the aTitle parameter.
9537 :
9538 : nsresult rv;
9539 :
9540 0 : nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
9541 0 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
9542 :
9543 : // Step 1: Serialize aData using structured clone.
9544 0 : nsCOMPtr<nsIStructuredCloneContainer> scContainer;
9545 :
9546 : // scContainer->Init might cause arbitrary JS to run, and this code might
9547 : // navigate the page we're on, potentially to a different origin! (bug
9548 : // 634834) To protect against this, we abort if our principal changes due
9549 : // to the InitFromVariant() call.
9550 : {
9551 : nsCOMPtr<nsIDocument> origDocument =
9552 0 : do_GetInterface(GetAsSupports(this));
9553 0 : if (!origDocument)
9554 0 : return NS_ERROR_DOM_SECURITY_ERR;
9555 0 : nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
9556 :
9557 0 : scContainer = new nsStructuredCloneContainer();
9558 0 : JSContext *cx = aCx;
9559 0 : if (!cx) {
9560 0 : cx = nsContentUtils::GetContextFromDocument(document);
9561 : }
9562 0 : rv = scContainer->InitFromVariant(aData, cx);
9563 :
9564 : // If we're running in the document's context and the structured clone
9565 : // failed, clear the context's pending exception. See bug 637116.
9566 0 : if (NS_FAILED(rv) && !aCx) {
9567 0 : JS_ClearPendingException(aCx);
9568 : }
9569 0 : NS_ENSURE_SUCCESS(rv, rv);
9570 :
9571 : nsCOMPtr<nsIDocument> newDocument =
9572 0 : do_GetInterface(GetAsSupports(this));
9573 0 : if (!newDocument)
9574 0 : return NS_ERROR_DOM_SECURITY_ERR;
9575 0 : nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
9576 :
9577 0 : bool principalsEqual = false;
9578 0 : origPrincipal->Equals(newPrincipal, &principalsEqual);
9579 0 : NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
9580 : }
9581 :
9582 : // Check that the state object isn't too long.
9583 : // Default max length: 640k bytes.
9584 : PRInt32 maxStateObjSize =
9585 0 : Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
9586 0 : if (maxStateObjSize < 0) {
9587 0 : maxStateObjSize = 0;
9588 : }
9589 :
9590 : PRUint64 scSize;
9591 0 : rv = scContainer->GetSerializedNBytes(&scSize);
9592 0 : NS_ENSURE_SUCCESS(rv, rv);
9593 :
9594 0 : NS_ENSURE_TRUE(scSize <= (PRUint32)maxStateObjSize,
9595 : NS_ERROR_ILLEGAL_VALUE);
9596 :
9597 : // Step 2: Resolve aURL
9598 0 : bool equalURIs = true;
9599 0 : nsCOMPtr<nsIURI> oldURI = mCurrentURI;
9600 0 : nsCOMPtr<nsIURI> newURI;
9601 0 : if (aURL.Length() == 0) {
9602 0 : newURI = mCurrentURI;
9603 : }
9604 : else {
9605 : // 2a: Resolve aURL relative to mURI
9606 :
9607 0 : nsIURI* docBaseURI = document->GetDocBaseURI();
9608 0 : if (!docBaseURI)
9609 0 : return NS_ERROR_FAILURE;
9610 :
9611 0 : nsCAutoString spec;
9612 0 : docBaseURI->GetSpec(spec);
9613 :
9614 0 : nsCAutoString charset;
9615 0 : rv = docBaseURI->GetOriginCharset(charset);
9616 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
9617 :
9618 0 : rv = NS_NewURI(getter_AddRefs(newURI), aURL,
9619 0 : charset.get(), docBaseURI);
9620 :
9621 : // 2b: If 2a fails, raise a SECURITY_ERR
9622 0 : if (NS_FAILED(rv)) {
9623 0 : return NS_ERROR_DOM_SECURITY_ERR;
9624 : }
9625 :
9626 : // 2c: Same-origin check.
9627 0 : if (!nsContentUtils::URIIsLocalFile(newURI)) {
9628 : // In addition to checking that the security manager says that
9629 : // the new URI has the same origin as our current URI, we also
9630 : // check that the two URIs have the same userpass. (The
9631 : // security manager says that |http://foo.com| and
9632 : // |http://me@foo.com| have the same origin.) mCurrentURI
9633 : // won't contain the password part of the userpass, so this
9634 : // means that it's never valid to specify a password in a
9635 : // pushState or replaceState URI.
9636 :
9637 : nsCOMPtr<nsIScriptSecurityManager> secMan =
9638 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
9639 0 : NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
9640 :
9641 : // It's very important that we check that newURI is of the same
9642 : // origin as mCurrentURI, not docBaseURI, because a page can
9643 : // set docBaseURI arbitrarily to any domain.
9644 0 : nsCAutoString currentUserPass, newUserPass;
9645 0 : NS_ENSURE_SUCCESS(mCurrentURI->GetUserPass(currentUserPass),
9646 : NS_ERROR_FAILURE);
9647 0 : NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass),
9648 : NS_ERROR_FAILURE);
9649 0 : if (NS_FAILED(secMan->CheckSameOriginURI(mCurrentURI,
9650 : newURI, true)) ||
9651 0 : !currentUserPass.Equals(newUserPass)) {
9652 :
9653 0 : return NS_ERROR_DOM_SECURITY_ERR;
9654 : }
9655 : }
9656 : else {
9657 : // It's a file:// URI
9658 : nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
9659 0 : do_QueryInterface(document);
9660 :
9661 0 : if (!docScriptObj) {
9662 0 : return NS_ERROR_DOM_SECURITY_ERR;
9663 : }
9664 :
9665 0 : nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
9666 :
9667 0 : if (!principal ||
9668 0 : NS_FAILED(principal->CheckMayLoad(newURI, true))) {
9669 :
9670 0 : return NS_ERROR_DOM_SECURITY_ERR;
9671 : }
9672 : }
9673 :
9674 0 : mCurrentURI->Equals(newURI, &equalURIs);
9675 :
9676 : } // end of same-origin check
9677 :
9678 0 : nsCOMPtr<nsISHistory> sessionHistory = mSessionHistory;
9679 0 : if (!sessionHistory) {
9680 : // Get the handle to SH from the root docshell
9681 0 : GetRootSessionHistory(getter_AddRefs(sessionHistory));
9682 : }
9683 0 : NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
9684 :
9685 : nsCOMPtr<nsISHistoryInternal> shInternal =
9686 0 : do_QueryInterface(sessionHistory, &rv);
9687 0 : NS_ENSURE_SUCCESS(rv, rv);
9688 :
9689 : // Step 3: Create a new entry in the session history. This will erase
9690 : // all SHEntries after the new entry and make this entry the current
9691 : // one. This operation may modify mOSHE, which we need later, so we
9692 : // keep a reference here.
9693 0 : NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
9694 0 : nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
9695 :
9696 0 : mLoadType = LOAD_PUSHSTATE;
9697 :
9698 0 : nsCOMPtr<nsISHEntry> newSHEntry;
9699 0 : if (!aReplace) {
9700 : // Save the current scroll position (bug 590573).
9701 0 : nscoord cx = 0, cy = 0;
9702 0 : GetCurScrollPos(ScrollOrientation_X, &cx);
9703 0 : GetCurScrollPos(ScrollOrientation_Y, &cy);
9704 0 : mOSHE->SetScrollPosition(cx, cy);
9705 :
9706 : // Since we're not changing which page we have loaded, pass
9707 : // true for aCloneChildren.
9708 : rv = AddToSessionHistory(newURI, nsnull, nsnull, true,
9709 0 : getter_AddRefs(newSHEntry));
9710 0 : NS_ENSURE_SUCCESS(rv, rv);
9711 :
9712 0 : NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
9713 :
9714 : // Link the new SHEntry to the old SHEntry's BFCache entry, since the
9715 : // two entries correspond to the same document.
9716 0 : NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE),
9717 : NS_ERROR_FAILURE);
9718 :
9719 : // Set the new SHEntry's title (bug 655273).
9720 0 : nsString title;
9721 0 : mOSHE->GetTitle(getter_Copies(title));
9722 0 : newSHEntry->SetTitle(title);
9723 :
9724 : // AddToSessionHistory may not modify mOSHE. In case it doesn't,
9725 : // we'll just set mOSHE here.
9726 0 : mOSHE = newSHEntry;
9727 :
9728 : } else {
9729 0 : newSHEntry = mOSHE;
9730 0 : newSHEntry->SetURI(newURI);
9731 : }
9732 :
9733 : // Step 4: Modify new/original session history entry and clear its POST
9734 : // data, if there is any.
9735 0 : newSHEntry->SetStateData(scContainer);
9736 0 : newSHEntry->SetPostData(nsnull);
9737 :
9738 : // If this push/replaceState changed the document's current URI and the new
9739 : // URI differs from the old URI in more than the hash, or if the old
9740 : // SHEntry's URI was modified in this way by a push/replaceState call
9741 : // set URIWasModified to true for the current SHEntry (bug 669671).
9742 0 : bool sameExceptHashes = true, oldURIWasModified = false;
9743 0 : newURI->EqualsExceptRef(mCurrentURI, &sameExceptHashes);
9744 0 : oldOSHE->GetURIWasModified(&oldURIWasModified);
9745 0 : newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
9746 :
9747 : // Step 5: If aReplace is false, indicating that we're doing a pushState
9748 : // rather than a replaceState, notify bfcache that we've added a page to
9749 : // the history so it can evict content viewers if appropriate.
9750 0 : if (!aReplace) {
9751 0 : nsCOMPtr<nsISHistory> rootSH;
9752 0 : GetRootSessionHistory(getter_AddRefs(rootSH));
9753 0 : NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
9754 :
9755 : nsCOMPtr<nsISHistoryInternal> internalSH =
9756 0 : do_QueryInterface(rootSH);
9757 0 : NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
9758 :
9759 0 : PRInt32 curIndex = -1;
9760 0 : rv = rootSH->GetIndex(&curIndex);
9761 0 : if (NS_SUCCEEDED(rv) && curIndex > -1) {
9762 0 : internalSH->EvictOutOfRangeContentViewers(curIndex);
9763 : }
9764 : }
9765 :
9766 : // Step 6: If the document's URI changed, update document's URI and update
9767 : // global history.
9768 : //
9769 : // We need to call FireOnLocationChange so that the browser's address bar
9770 : // gets updated and the back button is enabled, but we only need to
9771 : // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
9772 : // since SetCurrentURI will call FireOnLocationChange for us.
9773 : //
9774 : // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
9775 : // nsnull for aRequest param to FireOnLocationChange(...). Such an update
9776 : // notification is allowed only when we know docshell is not loading a new
9777 : // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
9778 : // FireOnLocationChange(...) breaks security UI.
9779 0 : if (!equalURIs) {
9780 0 : SetCurrentURI(newURI, nsnull, true, LOCATION_CHANGE_SAME_DOCUMENT);
9781 0 : document->SetDocumentURI(newURI);
9782 :
9783 0 : AddURIVisit(newURI, oldURI, oldURI, 0);
9784 :
9785 : // AddURIVisit doesn't set the title for the new URI in global history,
9786 : // so do that here.
9787 0 : if (mUseGlobalHistory) {
9788 0 : nsCOMPtr<IHistory> history = services::GetHistoryService();
9789 0 : if (history) {
9790 0 : history->SetURITitle(newURI, mTitle);
9791 : }
9792 0 : else if (mGlobalHistory) {
9793 0 : mGlobalHistory->SetPageTitle(newURI, mTitle);
9794 : }
9795 : }
9796 :
9797 : // Inform the favicon service that our old favicon applies to this new
9798 : // URI.
9799 0 : CopyFavicon(oldURI, newURI);
9800 : }
9801 : else {
9802 0 : FireDummyOnLocationChange();
9803 : }
9804 0 : document->SetStateObject(scContainer);
9805 :
9806 0 : return NS_OK;
9807 : }
9808 :
9809 : bool
9810 0 : nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
9811 : {
9812 : // I believe none of the about: urls should go in the history. But then
9813 : // that could just be me... If the intent is only deny about:blank then we
9814 : // should just do a spec compare, rather than two gets of the scheme and
9815 : // then the path. -Gagan
9816 : nsresult rv;
9817 0 : nsCAutoString buf;
9818 :
9819 0 : rv = aURI->GetScheme(buf);
9820 0 : if (NS_FAILED(rv))
9821 0 : return false;
9822 :
9823 0 : if (buf.Equals("about")) {
9824 0 : rv = aURI->GetPath(buf);
9825 0 : if (NS_FAILED(rv))
9826 0 : return false;
9827 :
9828 0 : if (buf.Equals("blank")) {
9829 0 : return false;
9830 : }
9831 : }
9832 0 : return true;
9833 : }
9834 :
9835 : nsresult
9836 0 : nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
9837 : nsISupports* aOwner, bool aCloneChildren,
9838 : nsISHEntry ** aNewEntry)
9839 : {
9840 0 : NS_PRECONDITION(aURI, "uri is null");
9841 0 : NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set");
9842 :
9843 : #if defined(PR_LOGGING) && defined(DEBUG)
9844 0 : if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) {
9845 0 : nsCAutoString spec;
9846 0 : aURI->GetSpec(spec);
9847 :
9848 0 : nsCAutoString chanName;
9849 0 : if (aChannel)
9850 0 : aChannel->GetName(chanName);
9851 : else
9852 0 : chanName.AssignLiteral("<no channel>");
9853 :
9854 0 : PR_LOG(gDocShellLog, PR_LOG_DEBUG,
9855 : ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(),
9856 : chanName.get()));
9857 : }
9858 : #endif
9859 :
9860 0 : nsresult rv = NS_OK;
9861 0 : nsCOMPtr<nsISHEntry> entry;
9862 : bool shouldPersist;
9863 :
9864 0 : shouldPersist = ShouldAddToSessionHistory(aURI);
9865 :
9866 : // Get a handle to the root docshell
9867 0 : nsCOMPtr<nsIDocShellTreeItem> root;
9868 0 : GetSameTypeRootTreeItem(getter_AddRefs(root));
9869 : /*
9870 : * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
9871 : * the existing SH entry in the page and replace the url and
9872 : * other vitalities.
9873 : */
9874 0 : if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
9875 0 : root != static_cast<nsIDocShellTreeItem *>(this)) {
9876 : // This is a subframe
9877 0 : entry = mOSHE;
9878 0 : nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
9879 0 : if (shContainer) {
9880 0 : PRInt32 childCount = 0;
9881 0 : shContainer->GetChildCount(&childCount);
9882 : // Remove all children of this entry
9883 0 : for (PRInt32 i = childCount - 1; i >= 0; i--) {
9884 0 : nsCOMPtr<nsISHEntry> child;
9885 0 : shContainer->GetChildAt(i, getter_AddRefs(child));
9886 0 : shContainer->RemoveChild(child);
9887 : } // for
9888 : } // shContainer
9889 : }
9890 :
9891 : // Create a new entry if necessary.
9892 0 : if (!entry) {
9893 0 : entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
9894 :
9895 0 : if (!entry) {
9896 0 : return NS_ERROR_OUT_OF_MEMORY;
9897 : }
9898 : }
9899 :
9900 : // Get the post data & referrer
9901 0 : nsCOMPtr<nsIInputStream> inputStream;
9902 0 : nsCOMPtr<nsIURI> referrerURI;
9903 0 : nsCOMPtr<nsISupports> cacheKey;
9904 0 : nsCOMPtr<nsISupports> owner = aOwner;
9905 0 : bool expired = false;
9906 0 : bool discardLayoutState = false;
9907 0 : nsCOMPtr<nsICachingChannel> cacheChannel;
9908 0 : if (aChannel) {
9909 0 : cacheChannel = do_QueryInterface(aChannel);
9910 :
9911 : /* If there is a caching channel, get the Cache Key and store it
9912 : * in SH.
9913 : */
9914 0 : if (cacheChannel) {
9915 0 : cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
9916 : }
9917 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
9918 :
9919 : // Check if the httpChannel is hiding under a multipartChannel
9920 0 : if (!httpChannel) {
9921 0 : GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
9922 : }
9923 0 : if (httpChannel) {
9924 0 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
9925 0 : if (uploadChannel) {
9926 0 : uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
9927 : }
9928 0 : httpChannel->GetReferrer(getter_AddRefs(referrerURI));
9929 :
9930 0 : discardLayoutState = ShouldDiscardLayoutState(httpChannel);
9931 : }
9932 0 : aChannel->GetOwner(getter_AddRefs(owner));
9933 : }
9934 :
9935 : //Title is set in nsDocShell::SetTitle()
9936 0 : entry->Create(aURI, // uri
9937 0 : EmptyString(), // Title
9938 : inputStream, // Post data stream
9939 : nsnull, // LayoutHistory state
9940 : cacheKey, // CacheKey
9941 : mContentTypeHint, // Content-type
9942 : owner, // Channel or provided owner
9943 : mHistoryID,
9944 0 : mDynamicallyCreated);
9945 0 : entry->SetReferrerURI(referrerURI);
9946 : /* If cache got a 'no-store', ask SH not to store
9947 : * HistoryLayoutState. By default, SH will set this
9948 : * flag to true and save HistoryLayoutState.
9949 : */
9950 0 : if (discardLayoutState) {
9951 0 : entry->SetSaveLayoutStateFlag(false);
9952 : }
9953 0 : if (cacheChannel) {
9954 : // Check if the page has expired from cache
9955 0 : PRUint32 expTime = 0;
9956 0 : cacheChannel->GetCacheTokenExpirationTime(&expTime);
9957 0 : PRUint32 now = PRTimeToSeconds(PR_Now());
9958 0 : if (expTime <= now)
9959 0 : expired = true;
9960 : }
9961 0 : if (expired)
9962 0 : entry->SetExpirationStatus(true);
9963 :
9964 :
9965 0 : if (root == static_cast<nsIDocShellTreeItem *>(this) && mSessionHistory) {
9966 : // If we need to clone our children onto the new session
9967 : // history entry, do so now.
9968 0 : if (aCloneChildren && mOSHE) {
9969 : PRUint32 cloneID;
9970 0 : mOSHE->GetID(&cloneID);
9971 0 : nsCOMPtr<nsISHEntry> newEntry;
9972 0 : CloneAndReplace(mOSHE, this, cloneID, entry, true, getter_AddRefs(newEntry));
9973 0 : NS_ASSERTION(entry == newEntry, "The new session history should be in the new entry");
9974 : }
9975 :
9976 : // This is the root docshell
9977 0 : if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
9978 : // Replace current entry in session history.
9979 0 : PRInt32 index = 0;
9980 0 : mSessionHistory->GetIndex(&index);
9981 0 : nsCOMPtr<nsISHistoryInternal> shPrivate(do_QueryInterface(mSessionHistory));
9982 : // Replace the current entry with the new entry
9983 0 : if (shPrivate)
9984 0 : rv = shPrivate->ReplaceEntry(index, entry);
9985 : }
9986 : else {
9987 : // Add to session history
9988 : nsCOMPtr<nsISHistoryInternal>
9989 0 : shPrivate(do_QueryInterface(mSessionHistory));
9990 0 : NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
9991 0 : mSessionHistory->GetIndex(&mPreviousTransIndex);
9992 0 : rv = shPrivate->AddEntry(entry, shouldPersist);
9993 0 : mSessionHistory->GetIndex(&mLoadedTransIndex);
9994 : #ifdef DEBUG_PAGE_CACHE
9995 : printf("Previous index: %d, Loaded index: %d\n\n",
9996 : mPreviousTransIndex, mLoadedTransIndex);
9997 : #endif
9998 : }
9999 : }
10000 : else {
10001 : // This is a subframe.
10002 0 : if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
10003 : LOAD_FLAGS_REPLACE_HISTORY))
10004 0 : rv = DoAddChildSHEntry(entry, mChildOffset, aCloneChildren);
10005 : }
10006 :
10007 : // Return the new SH entry...
10008 0 : if (aNewEntry) {
10009 0 : *aNewEntry = nsnull;
10010 0 : if (NS_SUCCEEDED(rv)) {
10011 0 : *aNewEntry = entry;
10012 0 : NS_ADDREF(*aNewEntry);
10013 : }
10014 : }
10015 :
10016 0 : return rv;
10017 : }
10018 :
10019 :
10020 : NS_IMETHODIMP
10021 0 : nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
10022 : {
10023 0 : if (!IsNavigationAllowed()) {
10024 0 : return NS_OK;
10025 : }
10026 :
10027 0 : nsCOMPtr<nsIURI> uri;
10028 0 : nsCOMPtr<nsIInputStream> postData;
10029 0 : nsCOMPtr<nsIURI> referrerURI;
10030 0 : nsCAutoString contentType;
10031 0 : nsCOMPtr<nsISupports> owner;
10032 :
10033 0 : NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
10034 :
10035 0 : NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
10036 0 : NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
10037 : NS_ERROR_FAILURE);
10038 0 : NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
10039 : NS_ERROR_FAILURE);
10040 0 : NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
10041 0 : NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)),
10042 : NS_ERROR_FAILURE);
10043 :
10044 : // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
10045 : // that's the only thing holding a ref to aEntry that will cause aEntry to
10046 : // die while we're loading it. So hold a strong ref to aEntry here, just
10047 : // in case.
10048 0 : nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
10049 : bool isJS;
10050 0 : nsresult rv = uri->SchemeIs("javascript", &isJS);
10051 0 : if (NS_FAILED(rv) || isJS) {
10052 : // We're loading a URL that will execute script from inside asyncOpen.
10053 : // Replace the current document with about:blank now to prevent
10054 : // anything from the current document from leaking into any JavaScript
10055 : // code in the URL.
10056 0 : nsCOMPtr<nsIPrincipal> prin = do_QueryInterface(owner);
10057 : // Don't cache the presentation if we're going to just reload the
10058 : // current entry. Caching would lead to trying to save the different
10059 : // content viewers in the same nsISHEntry object.
10060 0 : rv = CreateAboutBlankContentViewer(prin, nsnull, aEntry != mOSHE);
10061 :
10062 0 : if (NS_FAILED(rv)) {
10063 : // The creation of the intermittent about:blank content
10064 : // viewer failed for some reason (potentially because the
10065 : // user prevented it). Interrupt the history load.
10066 0 : return NS_OK;
10067 : }
10068 :
10069 0 : if (!owner) {
10070 : // Ensure that we have an owner. Otherwise javascript: URIs will
10071 : // pick it up from the about:blank page we just loaded, and we
10072 : // don't really want even that in this case.
10073 0 : owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
10074 0 : NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY);
10075 : }
10076 : }
10077 :
10078 : /* If there is a valid postdata *and* the user pressed
10079 : * reload or shift-reload, take user's permission before we
10080 : * repost the data to the server.
10081 : */
10082 0 : if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
10083 : bool repost;
10084 0 : rv = ConfirmRepost(&repost);
10085 0 : if (NS_FAILED(rv)) return rv;
10086 :
10087 : // If the user pressed cancel in the dialog, return. We're done here.
10088 0 : if (!repost)
10089 0 : return NS_BINDING_ABORTED;
10090 : }
10091 :
10092 : rv = InternalLoad(uri,
10093 : referrerURI,
10094 : owner,
10095 : INTERNAL_LOAD_FLAGS_NONE, // Do not inherit owner from document (security-critical!)
10096 : nsnull, // No window target
10097 : contentType.get(), // Type hint
10098 : postData, // Post data stream
10099 : nsnull, // No headers stream
10100 : aLoadType, // Load type
10101 : aEntry, // SHEntry
10102 : true,
10103 : nsnull, // No nsIDocShell
10104 0 : nsnull); // No nsIRequest
10105 0 : return rv;
10106 : }
10107 :
10108 0 : NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(bool* aShould)
10109 : {
10110 0 : *aShould = false;
10111 0 : if (mOSHE) {
10112 : // Don't capture historystate and save it in history
10113 : // if the page asked not to do so.
10114 0 : mOSHE->GetSaveLayoutStateFlag(aShould);
10115 : }
10116 :
10117 0 : return NS_OK;
10118 : }
10119 :
10120 0 : NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState()
10121 : {
10122 0 : nsresult rv = NS_OK;
10123 :
10124 0 : if (mOSHE) {
10125 0 : nsCOMPtr<nsIPresShell> shell;
10126 0 : rv = GetPresShell(getter_AddRefs(shell));
10127 0 : if (NS_SUCCEEDED(rv) && shell) {
10128 0 : nsCOMPtr<nsILayoutHistoryState> layoutState;
10129 0 : rv = shell->CaptureHistoryState(getter_AddRefs(layoutState),
10130 0 : true);
10131 : }
10132 : }
10133 :
10134 0 : return rv;
10135 : }
10136 :
10137 : /* static */ nsresult
10138 0 : nsDocShell::WalkHistoryEntries(nsISHEntry *aRootEntry,
10139 : nsDocShell *aRootShell,
10140 : WalkHistoryEntriesFunc aCallback,
10141 : void *aData)
10142 : {
10143 0 : NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
10144 :
10145 0 : nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
10146 0 : if (!container)
10147 0 : return NS_ERROR_FAILURE;
10148 :
10149 : PRInt32 childCount;
10150 0 : container->GetChildCount(&childCount);
10151 0 : for (PRInt32 i = 0; i < childCount; i++) {
10152 0 : nsCOMPtr<nsISHEntry> childEntry;
10153 0 : container->GetChildAt(i, getter_AddRefs(childEntry));
10154 0 : if (!childEntry) {
10155 : // childEntry can be null for valid reasons, for example if the
10156 : // docshell at index i never loaded anything useful.
10157 : // Remember to clone also nulls in the child array (bug 464064).
10158 0 : aCallback(nsnull, nsnull, i, aData);
10159 0 : continue;
10160 : }
10161 :
10162 0 : nsDocShell *childShell = nsnull;
10163 0 : if (aRootShell) {
10164 : // Walk the children of aRootShell and see if one of them
10165 : // has srcChild as a SHEntry.
10166 :
10167 0 : PRInt32 childCount = aRootShell->mChildList.Count();
10168 0 : for (PRInt32 j = 0; j < childCount; ++j) {
10169 : nsDocShell *child =
10170 0 : static_cast<nsDocShell*>(aRootShell->ChildAt(j));
10171 :
10172 0 : if (child->HasHistoryEntry(childEntry)) {
10173 0 : childShell = child;
10174 0 : break;
10175 : }
10176 : }
10177 : }
10178 0 : nsresult rv = aCallback(childEntry, childShell, i, aData);
10179 0 : NS_ENSURE_SUCCESS(rv, rv);
10180 : }
10181 :
10182 0 : return NS_OK;
10183 : }
10184 :
10185 : // callback data for WalkHistoryEntries
10186 : struct NS_STACK_CLASS CloneAndReplaceData
10187 0 : {
10188 0 : CloneAndReplaceData(PRUint32 aCloneID, nsISHEntry *aReplaceEntry,
10189 : bool aCloneChildren, nsISHEntry *aDestTreeParent)
10190 : : cloneID(aCloneID),
10191 : cloneChildren(aCloneChildren),
10192 : replaceEntry(aReplaceEntry),
10193 0 : destTreeParent(aDestTreeParent) { }
10194 :
10195 : PRUint32 cloneID;
10196 : bool cloneChildren;
10197 : nsISHEntry *replaceEntry;
10198 : nsISHEntry *destTreeParent;
10199 : nsCOMPtr<nsISHEntry> resultEntry;
10200 : };
10201 :
10202 : /* static */ nsresult
10203 0 : nsDocShell::CloneAndReplaceChild(nsISHEntry *aEntry, nsDocShell *aShell,
10204 : PRInt32 aEntryIndex, void *aData)
10205 : {
10206 0 : nsCOMPtr<nsISHEntry> dest;
10207 :
10208 0 : CloneAndReplaceData *data = static_cast<CloneAndReplaceData*>(aData);
10209 0 : PRUint32 cloneID = data->cloneID;
10210 0 : nsISHEntry *replaceEntry = data->replaceEntry;
10211 :
10212 : nsCOMPtr<nsISHContainer> container =
10213 0 : do_QueryInterface(data->destTreeParent);
10214 0 : if (!aEntry) {
10215 0 : if (container) {
10216 0 : container->AddChild(nsnull, aEntryIndex);
10217 : }
10218 0 : return NS_OK;
10219 : }
10220 :
10221 : PRUint32 srcID;
10222 0 : aEntry->GetID(&srcID);
10223 :
10224 0 : nsresult rv = NS_OK;
10225 0 : if (srcID == cloneID) {
10226 : // Replace the entry
10227 0 : dest = replaceEntry;
10228 : } else {
10229 : // Clone the SHEntry...
10230 0 : rv = aEntry->Clone(getter_AddRefs(dest));
10231 0 : NS_ENSURE_SUCCESS(rv, rv);
10232 : }
10233 0 : dest->SetIsSubFrame(true);
10234 :
10235 0 : if (srcID != cloneID || data->cloneChildren) {
10236 : // Walk the children
10237 : CloneAndReplaceData childData(cloneID, replaceEntry,
10238 0 : data->cloneChildren, dest);
10239 : rv = WalkHistoryEntries(aEntry, aShell,
10240 0 : CloneAndReplaceChild, &childData);
10241 0 : NS_ENSURE_SUCCESS(rv, rv);
10242 : }
10243 :
10244 0 : if (srcID != cloneID && aShell) {
10245 0 : aShell->SwapHistoryEntries(aEntry, dest);
10246 : }
10247 :
10248 0 : if (container)
10249 0 : container->AddChild(dest, aEntryIndex);
10250 :
10251 0 : data->resultEntry = dest;
10252 0 : return rv;
10253 : }
10254 :
10255 : /* static */ nsresult
10256 0 : nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
10257 : nsDocShell *aSrcShell,
10258 : PRUint32 aCloneID,
10259 : nsISHEntry *aReplaceEntry,
10260 : bool aCloneChildren,
10261 : nsISHEntry **aResultEntry)
10262 : {
10263 0 : NS_ENSURE_ARG_POINTER(aResultEntry);
10264 0 : NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
10265 :
10266 0 : CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nsnull);
10267 0 : nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
10268 :
10269 0 : data.resultEntry.swap(*aResultEntry);
10270 0 : return rv;
10271 : }
10272 :
10273 : void
10274 0 : nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
10275 : {
10276 0 : if (aOldEntry == mOSHE)
10277 0 : mOSHE = aNewEntry;
10278 :
10279 0 : if (aOldEntry == mLSHE)
10280 0 : mLSHE = aNewEntry;
10281 0 : }
10282 :
10283 :
10284 : struct SwapEntriesData
10285 : {
10286 : nsDocShell *ignoreShell; // constant; the shell to ignore
10287 : nsISHEntry *destTreeRoot; // constant; the root of the dest tree
10288 : nsISHEntry *destTreeParent; // constant; the node under destTreeRoot
10289 : // whose children will correspond to aEntry
10290 : };
10291 :
10292 :
10293 : nsresult
10294 0 : nsDocShell::SetChildHistoryEntry(nsISHEntry *aEntry, nsDocShell *aShell,
10295 : PRInt32 aEntryIndex, void *aData)
10296 : {
10297 0 : SwapEntriesData *data = static_cast<SwapEntriesData*>(aData);
10298 0 : nsDocShell *ignoreShell = data->ignoreShell;
10299 :
10300 0 : if (!aShell || aShell == ignoreShell)
10301 0 : return NS_OK;
10302 :
10303 0 : nsISHEntry *destTreeRoot = data->destTreeRoot;
10304 :
10305 0 : nsCOMPtr<nsISHEntry> destEntry;
10306 : nsCOMPtr<nsISHContainer> container =
10307 0 : do_QueryInterface(data->destTreeParent);
10308 :
10309 0 : if (container) {
10310 : // aEntry is a clone of some child of destTreeParent, but since the
10311 : // trees aren't necessarily in sync, we'll have to locate it.
10312 : // Note that we could set aShell's entry to null if we don't find a
10313 : // corresponding entry under destTreeParent.
10314 :
10315 : PRUint32 targetID, id;
10316 0 : aEntry->GetID(&targetID);
10317 :
10318 : // First look at the given index, since this is the common case.
10319 0 : nsCOMPtr<nsISHEntry> entry;
10320 0 : container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
10321 0 : if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
10322 0 : destEntry.swap(entry);
10323 : } else {
10324 : PRInt32 childCount;
10325 0 : container->GetChildCount(&childCount);
10326 0 : for (PRInt32 i = 0; i < childCount; ++i) {
10327 0 : container->GetChildAt(i, getter_AddRefs(entry));
10328 0 : if (!entry)
10329 0 : continue;
10330 :
10331 0 : entry->GetID(&id);
10332 0 : if (id == targetID) {
10333 0 : destEntry.swap(entry);
10334 0 : break;
10335 : }
10336 : }
10337 : }
10338 : } else {
10339 0 : destEntry = destTreeRoot;
10340 : }
10341 :
10342 0 : aShell->SwapHistoryEntries(aEntry, destEntry);
10343 :
10344 : // Now handle the children of aEntry.
10345 0 : SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
10346 : return WalkHistoryEntries(aEntry, aShell,
10347 0 : SetChildHistoryEntry, &childData);
10348 : }
10349 :
10350 :
10351 : static nsISHEntry*
10352 0 : GetRootSHEntry(nsISHEntry *aEntry)
10353 : {
10354 0 : nsCOMPtr<nsISHEntry> rootEntry = aEntry;
10355 0 : nsISHEntry *result = nsnull;
10356 0 : while (rootEntry) {
10357 0 : result = rootEntry;
10358 0 : result->GetParent(getter_AddRefs(rootEntry));
10359 : }
10360 :
10361 0 : return result;
10362 : }
10363 :
10364 :
10365 : void
10366 0 : nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry> *aPtr, nsISHEntry *aEntry)
10367 : {
10368 : // We need to sync up the docshell and session history trees for
10369 : // subframe navigation. If the load was in a subframe, we forward up to
10370 : // the root docshell, which will then recursively sync up all docshells
10371 : // to their corresponding entries in the new session history tree.
10372 : // If we don't do this, then we can cache a content viewer on the wrong
10373 : // cloned entry, and subsequently restore it at the wrong time.
10374 :
10375 0 : nsISHEntry *newRootEntry = GetRootSHEntry(aEntry);
10376 0 : if (newRootEntry) {
10377 : // newRootEntry is now the new root entry.
10378 : // Find the old root entry as well.
10379 :
10380 : // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
10381 : // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
10382 0 : nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
10383 0 : if (oldRootEntry) {
10384 0 : nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
10385 0 : GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
10386 0 : nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
10387 0 : if (rootShell) { // if we're the root just set it, nothing to swap
10388 0 : SwapEntriesData data = { this, newRootEntry };
10389 : nsIDocShell *rootIDocShell =
10390 0 : static_cast<nsIDocShell*>(rootShell);
10391 : nsDocShell *rootDocShell = static_cast<nsDocShell*>
10392 0 : (rootIDocShell);
10393 :
10394 : #ifdef NS_DEBUG
10395 : nsresult rv =
10396 : #endif
10397 : SetChildHistoryEntry(oldRootEntry, rootDocShell,
10398 0 : 0, &data);
10399 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
10400 : }
10401 : }
10402 : }
10403 :
10404 0 : *aPtr = aEntry;
10405 0 : }
10406 :
10407 :
10408 : nsresult
10409 0 : nsDocShell::GetRootSessionHistory(nsISHistory ** aReturn)
10410 : {
10411 : nsresult rv;
10412 :
10413 0 : nsCOMPtr<nsIDocShellTreeItem> root;
10414 : //Get the root docshell
10415 0 : rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
10416 : // QI to nsIWebNavigation
10417 0 : nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
10418 0 : if (rootAsWebnav) {
10419 : // Get the handle to SH from the root docshell
10420 0 : rv = rootAsWebnav->GetSessionHistory(aReturn);
10421 : }
10422 0 : return rv;
10423 : }
10424 :
10425 : nsresult
10426 0 : nsDocShell::GetHttpChannel(nsIChannel * aChannel, nsIHttpChannel ** aReturn)
10427 : {
10428 0 : NS_ENSURE_ARG_POINTER(aReturn);
10429 0 : if (!aChannel)
10430 0 : return NS_ERROR_FAILURE;
10431 :
10432 0 : nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
10433 0 : if (multiPartChannel) {
10434 0 : nsCOMPtr<nsIChannel> baseChannel;
10435 0 : multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
10436 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
10437 0 : *aReturn = httpChannel;
10438 0 : NS_IF_ADDREF(*aReturn);
10439 : }
10440 0 : return NS_OK;
10441 : }
10442 :
10443 : bool
10444 0 : nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel)
10445 : {
10446 : // By default layout State will be saved.
10447 0 : if (!aChannel)
10448 0 : return false;
10449 :
10450 : // figure out if SH should be saving layout state
10451 0 : nsCOMPtr<nsISupports> securityInfo;
10452 0 : bool noStore = false, noCache = false;
10453 0 : aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
10454 0 : aChannel->IsNoStoreResponse(&noStore);
10455 0 : aChannel->IsNoCacheResponse(&noCache);
10456 :
10457 0 : return (noStore || (noCache && securityInfo));
10458 : }
10459 :
10460 : //*****************************************************************************
10461 : // nsDocShell: nsIEditorDocShell
10462 : //*****************************************************************************
10463 :
10464 0 : NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
10465 : {
10466 0 : NS_ENSURE_ARG_POINTER(aEditor);
10467 :
10468 0 : if (!mEditorData) {
10469 0 : *aEditor = nsnull;
10470 0 : return NS_OK;
10471 : }
10472 :
10473 0 : return mEditorData->GetEditor(aEditor);
10474 : }
10475 :
10476 0 : NS_IMETHODIMP nsDocShell::SetEditor(nsIEditor * aEditor)
10477 : {
10478 0 : nsresult rv = EnsureEditorData();
10479 0 : if (NS_FAILED(rv)) return rv;
10480 :
10481 0 : return mEditorData->SetEditor(aEditor);
10482 : }
10483 :
10484 :
10485 0 : NS_IMETHODIMP nsDocShell::GetEditable(bool *aEditable)
10486 : {
10487 0 : NS_ENSURE_ARG_POINTER(aEditable);
10488 0 : *aEditable = mEditorData && mEditorData->GetEditable();
10489 0 : return NS_OK;
10490 : }
10491 :
10492 :
10493 0 : NS_IMETHODIMP nsDocShell::GetHasEditingSession(bool *aHasEditingSession)
10494 : {
10495 0 : NS_ENSURE_ARG_POINTER(aHasEditingSession);
10496 :
10497 0 : if (mEditorData)
10498 : {
10499 0 : nsCOMPtr<nsIEditingSession> editingSession;
10500 0 : mEditorData->GetEditingSession(getter_AddRefs(editingSession));
10501 0 : *aHasEditingSession = (editingSession.get() != nsnull);
10502 : }
10503 : else
10504 : {
10505 0 : *aHasEditingSession = false;
10506 : }
10507 :
10508 0 : return NS_OK;
10509 : }
10510 :
10511 0 : NS_IMETHODIMP nsDocShell::MakeEditable(bool inWaitForUriLoad)
10512 : {
10513 0 : nsresult rv = EnsureEditorData();
10514 0 : if (NS_FAILED(rv)) return rv;
10515 :
10516 0 : return mEditorData->MakeEditable(inWaitForUriLoad);
10517 : }
10518 :
10519 : bool
10520 0 : nsDocShell::ChannelIsPost(nsIChannel* aChannel)
10521 : {
10522 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
10523 0 : if (!httpChannel) {
10524 0 : return false;
10525 : }
10526 :
10527 0 : nsCAutoString method;
10528 0 : httpChannel->GetRequestMethod(method);
10529 0 : return method.Equals("POST");
10530 : }
10531 :
10532 : void
10533 0 : nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
10534 : nsIURI** aURI,
10535 : PRUint32* aChannelRedirectFlags)
10536 : {
10537 0 : nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
10538 0 : if (!props) {
10539 : return;
10540 : }
10541 :
10542 0 : nsresult rv = props->GetPropertyAsInterface(
10543 0 : NS_LITERAL_STRING("docshell.previousURI"),
10544 : NS_GET_IID(nsIURI),
10545 : reinterpret_cast<void**>(aURI)
10546 0 : );
10547 :
10548 0 : if (NS_FAILED(rv)) {
10549 : // There is no last visit for this channel, so this must be the first
10550 : // link. Link the visit to the referrer of this request, if any.
10551 : // Treat referrer as null if there is an error getting it.
10552 0 : (void)NS_GetReferrerFromChannel(aChannel, aURI);
10553 : }
10554 : else {
10555 0 : rv = props->GetPropertyAsUint32(
10556 0 : NS_LITERAL_STRING("docshell.previousFlags"),
10557 : aChannelRedirectFlags
10558 0 : );
10559 :
10560 0 : NS_WARN_IF_FALSE(
10561 : NS_SUCCEEDED(rv),
10562 : "Could not fetch previous flags, URI will be treated like referrer"
10563 : );
10564 : }
10565 : }
10566 :
10567 : void
10568 0 : nsDocShell::SaveLastVisit(nsIChannel* aChannel,
10569 : nsIURI* aURI,
10570 : PRUint32 aChannelRedirectFlags)
10571 : {
10572 0 : nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
10573 0 : if (!props || !aURI) {
10574 : return;
10575 : }
10576 :
10577 0 : props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
10578 0 : aURI);
10579 0 : props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
10580 0 : aChannelRedirectFlags);
10581 : }
10582 :
10583 : void
10584 0 : nsDocShell::AddURIVisit(nsIURI* aURI,
10585 : nsIURI* aReferrerURI,
10586 : nsIURI* aPreviousURI,
10587 : PRUint32 aChannelRedirectFlags)
10588 : {
10589 0 : NS_ASSERTION(aURI, "Visited URI is null!");
10590 :
10591 : // Only content-type docshells save URI visits. Also don't do
10592 : // anything here if we're not supposed to use global history.
10593 0 : if (mItemType != typeContent || !mUseGlobalHistory) {
10594 0 : return;
10595 : }
10596 :
10597 0 : nsCOMPtr<IHistory> history = services::GetHistoryService();
10598 :
10599 0 : if (history) {
10600 0 : PRUint32 visitURIFlags = 0;
10601 :
10602 0 : if (!IsFrame()) {
10603 0 : visitURIFlags |= IHistory::TOP_LEVEL;
10604 : }
10605 :
10606 0 : if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
10607 0 : visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
10608 : }
10609 0 : else if (aChannelRedirectFlags &
10610 : nsIChannelEventSink::REDIRECT_PERMANENT) {
10611 0 : visitURIFlags |= IHistory::REDIRECT_PERMANENT;
10612 : }
10613 :
10614 0 : (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
10615 : }
10616 0 : else if (mGlobalHistory) {
10617 : // Falls back to sync global history interface.
10618 0 : (void)mGlobalHistory->AddURI(aURI,
10619 : !!aChannelRedirectFlags,
10620 0 : !IsFrame(),
10621 0 : aReferrerURI);
10622 : }
10623 : }
10624 :
10625 : //*****************************************************************************
10626 : // nsDocShell: Helper Routines
10627 : //*****************************************************************************
10628 :
10629 : NS_IMETHODIMP
10630 0 : nsDocShell::SetLoadType(PRUint32 aLoadType)
10631 : {
10632 0 : mLoadType = aLoadType;
10633 0 : return NS_OK;
10634 : }
10635 :
10636 : NS_IMETHODIMP
10637 0 : nsDocShell::GetLoadType(PRUint32 * aLoadType)
10638 : {
10639 0 : *aLoadType = mLoadType;
10640 0 : return NS_OK;
10641 : }
10642 :
10643 : nsresult
10644 0 : nsDocShell::ConfirmRepost(bool * aRepost)
10645 : {
10646 0 : nsCOMPtr<nsIPrompt> prompter;
10647 0 : CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
10648 0 : if (!prompter) {
10649 0 : return NS_ERROR_NOT_AVAILABLE;
10650 : }
10651 :
10652 : nsCOMPtr<nsIStringBundleService> stringBundleService =
10653 0 : mozilla::services::GetStringBundleService();
10654 0 : if (!stringBundleService)
10655 0 : return NS_ERROR_FAILURE;
10656 :
10657 0 : nsCOMPtr<nsIStringBundle> appBundle;
10658 0 : nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
10659 0 : getter_AddRefs(appBundle));
10660 0 : NS_ENSURE_SUCCESS(rv, rv);
10661 :
10662 0 : nsCOMPtr<nsIStringBundle> brandBundle;
10663 0 : rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle));
10664 0 : NS_ENSURE_SUCCESS(rv, rv);
10665 :
10666 0 : NS_ASSERTION(prompter && brandBundle && appBundle,
10667 : "Unable to set up repost prompter.");
10668 :
10669 0 : nsXPIDLString brandName;
10670 0 : rv = brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
10671 0 : getter_Copies(brandName));
10672 :
10673 0 : nsXPIDLString msgString, button0Title;
10674 0 : if (NS_FAILED(rv)) { // No brand, use the generic version.
10675 0 : rv = appBundle->GetStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
10676 0 : getter_Copies(msgString));
10677 : }
10678 : else {
10679 : // Brand available - if the app has an override file with formatting, the app name will
10680 : // be included. Without an override, the prompt will look like the generic version.
10681 0 : const PRUnichar *formatStrings[] = { brandName.get() };
10682 0 : rv = appBundle->FormatStringFromName(NS_LITERAL_STRING("confirmRepostPrompt").get(),
10683 : formatStrings, ArrayLength(formatStrings),
10684 0 : getter_Copies(msgString));
10685 : }
10686 0 : if (NS_FAILED(rv)) return rv;
10687 :
10688 0 : rv = appBundle->GetStringFromName(NS_LITERAL_STRING("resendButton.label").get(),
10689 0 : getter_Copies(button0Title));
10690 0 : if (NS_FAILED(rv)) return rv;
10691 :
10692 : PRInt32 buttonPressed;
10693 : // The actual value here is irrelevant, but we can't pass an invalid
10694 : // bool through XPConnect.
10695 0 : bool checkState = false;
10696 0 : rv = prompter->
10697 : ConfirmEx(nsnull, msgString.get(),
10698 : (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
10699 : (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
10700 0 : button0Title.get(), nsnull, nsnull, nsnull, &checkState, &buttonPressed);
10701 0 : if (NS_FAILED(rv)) return rv;
10702 :
10703 0 : *aRepost = (buttonPressed == 0);
10704 0 : return NS_OK;
10705 : }
10706 :
10707 : NS_IMETHODIMP
10708 0 : nsDocShell::GetPromptAndStringBundle(nsIPrompt ** aPrompt,
10709 : nsIStringBundle ** aStringBundle)
10710 : {
10711 0 : NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void **) aPrompt),
10712 : NS_ERROR_FAILURE);
10713 :
10714 : nsCOMPtr<nsIStringBundleService> stringBundleService =
10715 0 : mozilla::services::GetStringBundleService();
10716 0 : NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
10717 :
10718 0 : NS_ENSURE_SUCCESS(stringBundleService->
10719 : CreateBundle(kAppstringsBundleURL,
10720 : aStringBundle),
10721 : NS_ERROR_FAILURE);
10722 :
10723 0 : return NS_OK;
10724 : }
10725 :
10726 : NS_IMETHODIMP
10727 0 : nsDocShell::GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent,
10728 : PRInt32 * aOffset)
10729 : {
10730 0 : NS_ENSURE_ARG_POINTER(aChild || aParent);
10731 :
10732 0 : nsCOMPtr<nsIDOMNodeList> childNodes;
10733 0 : NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
10734 : NS_ERROR_FAILURE);
10735 0 : NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
10736 :
10737 0 : PRInt32 i = 0;
10738 :
10739 0 : for (; true; i++) {
10740 0 : nsCOMPtr<nsIDOMNode> childNode;
10741 0 : NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
10742 : NS_ERROR_FAILURE);
10743 0 : NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
10744 :
10745 0 : if (childNode.get() == aChild) {
10746 0 : *aOffset = i;
10747 0 : return NS_OK;
10748 : }
10749 : }
10750 :
10751 : return NS_ERROR_FAILURE;
10752 : }
10753 :
10754 : nsIScrollableFrame *
10755 0 : nsDocShell::GetRootScrollFrame()
10756 : {
10757 0 : nsCOMPtr<nsIPresShell> shell;
10758 0 : NS_ENSURE_SUCCESS(GetPresShell(getter_AddRefs(shell)), nsnull);
10759 0 : NS_ENSURE_TRUE(shell, nsnull);
10760 :
10761 0 : return shell->GetRootScrollFrameAsScrollableExternal();
10762 : }
10763 :
10764 : NS_IMETHODIMP
10765 0 : nsDocShell::EnsureScriptEnvironment()
10766 : {
10767 0 : if (mScriptGlobal)
10768 0 : return NS_OK;
10769 :
10770 0 : if (mIsBeingDestroyed) {
10771 0 : return NS_ERROR_NOT_AVAILABLE;
10772 : }
10773 :
10774 : NS_TIME_FUNCTION;
10775 :
10776 : #ifdef DEBUG
10777 0 : NS_ASSERTION(!mInEnsureScriptEnv,
10778 : "Infinite loop! Calling EnsureScriptEnvironment() from "
10779 : "within EnsureScriptEnvironment()!");
10780 :
10781 : // Yeah, this isn't re-entrant safe, but that's ok since if we
10782 : // re-enter this method, we'll infinitely loop...
10783 0 : AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
10784 0 : mInEnsureScriptEnv = true;
10785 : #endif
10786 :
10787 : nsCOMPtr<nsIDOMScriptObjectFactory> factory =
10788 0 : do_GetService(kDOMScriptObjectFactoryCID);
10789 0 : NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
10790 :
10791 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
10792 0 : NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
10793 :
10794 : PRUint32 chromeFlags;
10795 0 : browserChrome->GetChromeFlags(&chromeFlags);
10796 :
10797 : bool isModalContentWindow =
10798 : (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) &&
10799 0 : !(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
10800 :
10801 : // If our window is modal and we're not opened as chrome, make
10802 : // this window a modal content window.
10803 0 : factory->NewScriptGlobalObject(mItemType == typeChrome,
10804 : isModalContentWindow,
10805 0 : getter_AddRefs(mScriptGlobal));
10806 0 : NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
10807 :
10808 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
10809 0 : win->SetDocShell(static_cast<nsIDocShell *>(this));
10810 :
10811 : // Ensure the script object is set to run javascript - other languages
10812 : // setup on demand.
10813 : // XXXmarkh - should this be setup to run the default language for this doc?
10814 : nsresult rv;
10815 0 : rv = mScriptGlobal->EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT);
10816 0 : NS_ENSURE_SUCCESS(rv, rv);
10817 :
10818 0 : return NS_OK;
10819 : }
10820 :
10821 :
10822 : NS_IMETHODIMP
10823 0 : nsDocShell::EnsureEditorData()
10824 : {
10825 0 : bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
10826 0 : if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
10827 : // We shouldn't recreate the editor data if it already exists, or
10828 : // we're shutting down, or we already have a detached editor data
10829 : // stored in the session history. We should only have one editordata
10830 : // per docshell.
10831 0 : mEditorData = new nsDocShellEditorData(this);
10832 : }
10833 :
10834 0 : return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
10835 : }
10836 :
10837 : nsresult
10838 0 : nsDocShell::EnsureTransferableHookData()
10839 : {
10840 0 : if (!mTransferableHookData) {
10841 0 : mTransferableHookData = new nsTransferableHookData();
10842 0 : if (!mTransferableHookData) return NS_ERROR_OUT_OF_MEMORY;
10843 : }
10844 :
10845 0 : return NS_OK;
10846 : }
10847 :
10848 :
10849 0 : NS_IMETHODIMP nsDocShell::EnsureFind()
10850 : {
10851 : nsresult rv;
10852 0 : if (!mFind)
10853 : {
10854 0 : mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
10855 0 : if (NS_FAILED(rv)) return rv;
10856 : }
10857 :
10858 : // we promise that the nsIWebBrowserFind that we return has been set
10859 : // up to point to the focused, or content window, so we have to
10860 : // set that up each time.
10861 :
10862 0 : nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
10863 0 : NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
10864 :
10865 : // default to our window
10866 0 : nsCOMPtr<nsIDOMWindow> windowToSearch(do_QueryInterface(mScriptGlobal));
10867 :
10868 0 : nsCOMPtr<nsIDocShellTreeItem> root;
10869 0 : GetRootTreeItem(getter_AddRefs(root));
10870 :
10871 : // if the active window is the same window that this docshell is in,
10872 : // use the currently focused frame
10873 0 : nsCOMPtr<nsIDOMWindow> rootWindow = do_GetInterface(root);
10874 0 : nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
10875 0 : if (fm) {
10876 0 : nsCOMPtr<nsIDOMWindow> activeWindow;
10877 0 : fm->GetActiveWindow(getter_AddRefs(activeWindow));
10878 0 : if (activeWindow == rootWindow)
10879 0 : fm->GetFocusedWindow(getter_AddRefs(windowToSearch));
10880 : }
10881 :
10882 0 : nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
10883 0 : if (!findInFrames) return NS_ERROR_NO_INTERFACE;
10884 :
10885 0 : rv = findInFrames->SetRootSearchFrame(rootWindow);
10886 0 : if (NS_FAILED(rv)) return rv;
10887 0 : rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
10888 0 : if (NS_FAILED(rv)) return rv;
10889 :
10890 0 : return NS_OK;
10891 : }
10892 :
10893 : bool
10894 0 : nsDocShell::IsFrame()
10895 : {
10896 : nsCOMPtr<nsIDocShellTreeItem> parent =
10897 0 : do_QueryInterface(GetAsSupports(mParent));
10898 0 : if (parent) {
10899 0 : PRInt32 parentType = ~mItemType; // Not us
10900 0 : parent->GetItemType(&parentType);
10901 0 : if (parentType == mItemType) // This is a frame
10902 0 : return true;
10903 : }
10904 :
10905 0 : return false;
10906 : }
10907 :
10908 : /* boolean IsBeingDestroyed (); */
10909 : NS_IMETHODIMP
10910 0 : nsDocShell::IsBeingDestroyed(bool *aDoomed)
10911 : {
10912 0 : NS_ENSURE_ARG(aDoomed);
10913 0 : *aDoomed = mIsBeingDestroyed;
10914 0 : return NS_OK;
10915 : }
10916 :
10917 :
10918 : NS_IMETHODIMP
10919 0 : nsDocShell::GetIsExecutingOnLoadHandler(bool *aResult)
10920 : {
10921 0 : NS_ENSURE_ARG(aResult);
10922 0 : *aResult = mIsExecutingOnLoadHandler;
10923 0 : return NS_OK;
10924 : }
10925 :
10926 : NS_IMETHODIMP
10927 0 : nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState **aLayoutHistoryState)
10928 : {
10929 0 : if (mOSHE)
10930 0 : mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
10931 0 : return NS_OK;
10932 : }
10933 :
10934 : NS_IMETHODIMP
10935 0 : nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState)
10936 : {
10937 0 : if (mOSHE)
10938 0 : mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
10939 0 : return NS_OK;
10940 : }
10941 :
10942 : //*****************************************************************************
10943 : //*** nsRefreshTimer: Object Management
10944 : //*****************************************************************************
10945 :
10946 0 : nsRefreshTimer::nsRefreshTimer()
10947 0 : : mDelay(0), mRepeat(false), mMetaRefresh(false)
10948 : {
10949 0 : }
10950 :
10951 0 : nsRefreshTimer::~nsRefreshTimer()
10952 : {
10953 0 : }
10954 :
10955 : //*****************************************************************************
10956 : // nsRefreshTimer::nsISupports
10957 : //*****************************************************************************
10958 :
10959 0 : NS_IMPL_THREADSAFE_ADDREF(nsRefreshTimer)
10960 0 : NS_IMPL_THREADSAFE_RELEASE(nsRefreshTimer)
10961 :
10962 0 : NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
10963 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
10964 0 : NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
10965 0 : NS_INTERFACE_MAP_END_THREADSAFE
10966 :
10967 : ///*****************************************************************************
10968 : // nsRefreshTimer::nsITimerCallback
10969 : //******************************************************************************
10970 : NS_IMETHODIMP
10971 0 : nsRefreshTimer::Notify(nsITimer * aTimer)
10972 : {
10973 0 : NS_ASSERTION(mDocShell, "DocShell is somehow null");
10974 :
10975 0 : if (mDocShell && aTimer) {
10976 : // Get the delay count to determine load type
10977 0 : PRUint32 delay = 0;
10978 0 : aTimer->GetDelay(&delay);
10979 0 : mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer);
10980 : }
10981 0 : return NS_OK;
10982 : }
10983 :
10984 : //*****************************************************************************
10985 : // nsDocShell::InterfaceRequestorProxy
10986 : //*****************************************************************************
10987 0 : nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor* p)
10988 : {
10989 0 : if (p) {
10990 0 : mWeakPtr = do_GetWeakReference(p);
10991 : }
10992 0 : }
10993 :
10994 0 : nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
10995 : {
10996 0 : mWeakPtr = nsnull;
10997 0 : }
10998 :
10999 0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)
11000 :
11001 : NS_IMETHODIMP
11002 0 : nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID & aIID, void **aSink)
11003 : {
11004 0 : NS_ENSURE_ARG_POINTER(aSink);
11005 0 : nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
11006 0 : if (ifReq) {
11007 0 : return ifReq->GetInterface(aIID, aSink);
11008 : }
11009 0 : *aSink = nsnull;
11010 0 : return NS_NOINTERFACE;
11011 : }
11012 :
11013 : nsresult
11014 0 : nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer)
11015 : {
11016 0 : if (!aContentViewer)
11017 0 : return NS_ERROR_FAILURE;
11018 :
11019 0 : nsCOMPtr<nsIURI> baseURI;
11020 0 : nsresult rv = NS_ERROR_NOT_AVAILABLE;
11021 :
11022 0 : if (sURIFixup)
11023 : rv = sURIFixup->CreateExposableURI(mCurrentURI,
11024 0 : getter_AddRefs(baseURI));
11025 :
11026 : // Get the current document and set the base uri
11027 0 : if (baseURI) {
11028 0 : nsIDocument* document = aContentViewer->GetDocument();
11029 0 : if (document) {
11030 0 : rv = document->SetBaseURI(baseURI);
11031 : }
11032 : }
11033 0 : return rv;
11034 : }
11035 :
11036 : //*****************************************************************************
11037 : // nsDocShell::nsIAuthPromptProvider
11038 : //*****************************************************************************
11039 :
11040 : NS_IMETHODIMP
11041 0 : nsDocShell::GetAuthPrompt(PRUint32 aPromptReason, const nsIID& iid,
11042 : void** aResult)
11043 : {
11044 : // a priority prompt request will override a false mAllowAuth setting
11045 0 : bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
11046 :
11047 0 : if (!mAllowAuth && !priorityPrompt)
11048 0 : return NS_ERROR_NOT_AVAILABLE;
11049 :
11050 : // we're either allowing auth, or it's a proxy request
11051 : nsresult rv;
11052 : nsCOMPtr<nsIPromptFactory> wwatch =
11053 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
11054 0 : NS_ENSURE_SUCCESS(rv, rv);
11055 :
11056 0 : rv = EnsureScriptEnvironment();
11057 0 : NS_ENSURE_SUCCESS(rv, rv);
11058 :
11059 0 : nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(mScriptGlobal));
11060 :
11061 : // Get the an auth prompter for our window so that the parenting
11062 : // of the dialogs works as it should when using tabs.
11063 :
11064 0 : return wwatch->GetPrompt(window, iid,
11065 0 : reinterpret_cast<void**>(aResult));
11066 : }
11067 :
11068 : //*****************************************************************************
11069 : // nsDocShell::nsIObserver
11070 : //*****************************************************************************
11071 :
11072 : NS_IMETHODIMP
11073 0 : nsDocShell::Observe(nsISupports *aSubject, const char *aTopic,
11074 : const PRUnichar *aData)
11075 : {
11076 0 : nsresult rv = NS_OK;
11077 0 : if (mObserveErrorPages &&
11078 0 : !nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
11079 : !nsCRT::strcmp(aData,
11080 0 : NS_LITERAL_STRING("browser.xul.error_pages.enabled").get())) {
11081 :
11082 : bool tmpbool;
11083 0 : rv = Preferences::GetBool("browser.xul.error_pages.enabled", &tmpbool);
11084 0 : if (NS_SUCCEEDED(rv))
11085 0 : mUseErrorPages = tmpbool;
11086 :
11087 : } else {
11088 0 : rv = NS_ERROR_UNEXPECTED;
11089 : }
11090 0 : return rv;
11091 : }
11092 :
11093 : //*****************************************************************************
11094 : // nsDocShell::nsILoadContext
11095 : //*****************************************************************************
11096 : NS_IMETHODIMP
11097 0 : nsDocShell::GetAssociatedWindow(nsIDOMWindow** aWindow)
11098 : {
11099 0 : CallGetInterface(this, aWindow);
11100 0 : return NS_OK;
11101 : }
11102 :
11103 : NS_IMETHODIMP
11104 0 : nsDocShell::GetTopWindow(nsIDOMWindow** aWindow)
11105 : {
11106 0 : nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this));
11107 0 : if (win) {
11108 0 : win->GetTop(aWindow);
11109 : }
11110 0 : return NS_OK;
11111 : }
11112 :
11113 : NS_IMETHODIMP
11114 0 : nsDocShell::IsAppOfType(PRUint32 aAppType, bool *aIsOfType)
11115 : {
11116 0 : nsCOMPtr<nsIDocShell> shell = this;
11117 0 : while (shell) {
11118 : PRUint32 type;
11119 0 : shell->GetAppType(&type);
11120 0 : if (type == aAppType) {
11121 0 : *aIsOfType = true;
11122 0 : return NS_OK;
11123 : }
11124 0 : nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(shell);
11125 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
11126 0 : item->GetParent(getter_AddRefs(parent));
11127 0 : shell = do_QueryInterface(parent);
11128 : }
11129 :
11130 0 : *aIsOfType = false;
11131 0 : return NS_OK;
11132 : }
11133 :
11134 : NS_IMETHODIMP
11135 0 : nsDocShell::GetIsContent(bool *aIsContent)
11136 : {
11137 0 : *aIsContent = (mItemType == typeContent);
11138 0 : return NS_OK;
11139 : }
11140 :
11141 : bool
11142 0 : nsDocShell::IsOKToLoadURI(nsIURI* aURI)
11143 : {
11144 0 : NS_PRECONDITION(aURI, "Must have a URI!");
11145 :
11146 0 : if (!mFiredUnloadEvent) {
11147 0 : return true;
11148 : }
11149 :
11150 0 : if (!mLoadingURI) {
11151 0 : return false;
11152 : }
11153 :
11154 : nsCOMPtr<nsIScriptSecurityManager> secMan =
11155 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
11156 : return
11157 : secMan &&
11158 0 : NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
11159 : }
11160 :
11161 : //
11162 : // Routines for selection and clipboard
11163 : //
11164 : nsresult
11165 0 : nsDocShell::GetControllerForCommand(const char * inCommand,
11166 : nsIController** outController)
11167 : {
11168 0 : NS_ENSURE_ARG_POINTER(outController);
11169 0 : *outController = nsnull;
11170 :
11171 0 : nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mScriptGlobal));
11172 0 : if (window) {
11173 0 : nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
11174 0 : if (root) {
11175 0 : return root->GetControllerForCommand(inCommand, outController);
11176 : }
11177 : }
11178 :
11179 0 : return NS_ERROR_FAILURE;
11180 : }
11181 :
11182 : nsresult
11183 0 : nsDocShell::IsCommandEnabled(const char * inCommand, bool* outEnabled)
11184 : {
11185 0 : NS_ENSURE_ARG_POINTER(outEnabled);
11186 0 : *outEnabled = false;
11187 :
11188 0 : nsresult rv = NS_ERROR_FAILURE;
11189 :
11190 0 : nsCOMPtr<nsIController> controller;
11191 0 : rv = GetControllerForCommand (inCommand, getter_AddRefs(controller));
11192 0 : if (controller)
11193 0 : rv = controller->IsCommandEnabled(inCommand, outEnabled);
11194 :
11195 0 : return rv;
11196 : }
11197 :
11198 : nsresult
11199 0 : nsDocShell::DoCommand(const char * inCommand)
11200 : {
11201 0 : nsresult rv = NS_ERROR_FAILURE;
11202 :
11203 0 : nsCOMPtr<nsIController> controller;
11204 0 : rv = GetControllerForCommand(inCommand, getter_AddRefs(controller));
11205 0 : if (controller)
11206 0 : rv = controller->DoCommand(inCommand);
11207 :
11208 0 : return rv;
11209 : }
11210 :
11211 : nsresult
11212 0 : nsDocShell::EnsureCommandHandler()
11213 : {
11214 0 : if (!mCommandManager)
11215 : {
11216 : nsCOMPtr<nsPICommandUpdater> commandUpdater =
11217 0 : do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
11218 0 : if (!commandUpdater) return NS_ERROR_OUT_OF_MEMORY;
11219 :
11220 : nsCOMPtr<nsIDOMWindow> domWindow =
11221 0 : do_GetInterface(static_cast<nsIInterfaceRequestor *>(this));
11222 :
11223 0 : nsresult rv = commandUpdater->Init(domWindow);
11224 0 : if (NS_SUCCEEDED(rv))
11225 0 : mCommandManager = do_QueryInterface(commandUpdater);
11226 : }
11227 :
11228 0 : return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
11229 : }
11230 :
11231 : NS_IMETHODIMP
11232 0 : nsDocShell::CanCutSelection(bool* aResult)
11233 : {
11234 0 : return IsCommandEnabled("cmd_cut", aResult);
11235 : }
11236 :
11237 : NS_IMETHODIMP
11238 0 : nsDocShell::CanCopySelection(bool* aResult)
11239 : {
11240 0 : return IsCommandEnabled("cmd_copy", aResult);
11241 : }
11242 :
11243 : NS_IMETHODIMP
11244 0 : nsDocShell::CanCopyLinkLocation(bool* aResult)
11245 : {
11246 0 : return IsCommandEnabled("cmd_copyLink", aResult);
11247 : }
11248 :
11249 : NS_IMETHODIMP
11250 0 : nsDocShell::CanCopyImageLocation(bool* aResult)
11251 : {
11252 : return IsCommandEnabled("cmd_copyImageLocation",
11253 0 : aResult);
11254 : }
11255 :
11256 : NS_IMETHODIMP
11257 0 : nsDocShell::CanCopyImageContents(bool* aResult)
11258 : {
11259 : return IsCommandEnabled("cmd_copyImageContents",
11260 0 : aResult);
11261 : }
11262 :
11263 : NS_IMETHODIMP
11264 0 : nsDocShell::CanPaste(bool* aResult)
11265 : {
11266 0 : return IsCommandEnabled("cmd_paste", aResult);
11267 : }
11268 :
11269 : NS_IMETHODIMP
11270 0 : nsDocShell::CutSelection(void)
11271 : {
11272 0 : return DoCommand ( "cmd_cut" );
11273 : }
11274 :
11275 : NS_IMETHODIMP
11276 0 : nsDocShell::CopySelection(void)
11277 : {
11278 0 : return DoCommand ( "cmd_copy" );
11279 : }
11280 :
11281 : NS_IMETHODIMP
11282 0 : nsDocShell::CopyLinkLocation(void)
11283 : {
11284 0 : return DoCommand ( "cmd_copyLink" );
11285 : }
11286 :
11287 : NS_IMETHODIMP
11288 0 : nsDocShell::CopyImageLocation(void)
11289 : {
11290 0 : return DoCommand ( "cmd_copyImageLocation" );
11291 : }
11292 :
11293 : NS_IMETHODIMP
11294 0 : nsDocShell::CopyImageContents(void)
11295 : {
11296 0 : return DoCommand ( "cmd_copyImageContents" );
11297 : }
11298 :
11299 : NS_IMETHODIMP
11300 0 : nsDocShell::Paste(void)
11301 : {
11302 0 : return DoCommand ( "cmd_paste" );
11303 : }
11304 :
11305 : NS_IMETHODIMP
11306 0 : nsDocShell::SelectAll(void)
11307 : {
11308 0 : return DoCommand ( "cmd_selectAll" );
11309 : }
11310 :
11311 : //
11312 : // SelectNone
11313 : //
11314 : // Collapses the current selection, insertion point ends up at beginning
11315 : // of previous selection.
11316 : //
11317 : NS_IMETHODIMP
11318 0 : nsDocShell::SelectNone(void)
11319 : {
11320 0 : return DoCommand ( "cmd_selectNone" );
11321 : }
11322 :
11323 : //----------------------------------------------------------------------
11324 :
11325 : // link handling
11326 :
11327 0 : class OnLinkClickEvent : public nsRunnable {
11328 : public:
11329 : OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
11330 : nsIURI* aURI,
11331 : const PRUnichar* aTargetSpec,
11332 : nsIInputStream* aPostDataStream,
11333 : nsIInputStream* aHeadersDataStream,
11334 : bool aIsTrusted);
11335 :
11336 0 : NS_IMETHOD Run() {
11337 0 : nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mHandler->mScriptGlobal));
11338 0 : nsAutoPopupStatePusher popupStatePusher(window, mPopupState);
11339 :
11340 0 : nsCxPusher pusher;
11341 0 : if (mIsTrusted || pusher.Push(mContent)) {
11342 0 : mHandler->OnLinkClickSync(mContent, mURI,
11343 : mTargetSpec.get(), mPostDataStream,
11344 : mHeadersDataStream,
11345 0 : nsnull, nsnull);
11346 : }
11347 0 : return NS_OK;
11348 : }
11349 :
11350 : private:
11351 : nsRefPtr<nsDocShell> mHandler;
11352 : nsCOMPtr<nsIURI> mURI;
11353 : nsString mTargetSpec;
11354 : nsCOMPtr<nsIInputStream> mPostDataStream;
11355 : nsCOMPtr<nsIInputStream> mHeadersDataStream;
11356 : nsCOMPtr<nsIContent> mContent;
11357 : PopupControlState mPopupState;
11358 : bool mIsTrusted;
11359 : };
11360 :
11361 0 : OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
11362 : nsIContent *aContent,
11363 : nsIURI* aURI,
11364 : const PRUnichar* aTargetSpec,
11365 : nsIInputStream* aPostDataStream,
11366 : nsIInputStream* aHeadersDataStream,
11367 : bool aIsTrusted)
11368 : : mHandler(aHandler)
11369 : , mURI(aURI)
11370 : , mTargetSpec(aTargetSpec)
11371 : , mPostDataStream(aPostDataStream)
11372 : , mHeadersDataStream(aHeadersDataStream)
11373 : , mContent(aContent)
11374 0 : , mIsTrusted(aIsTrusted)
11375 : {
11376 0 : nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mHandler->mScriptGlobal));
11377 :
11378 0 : mPopupState = window->GetPopupControlState();
11379 0 : }
11380 :
11381 : //----------------------------------------
11382 :
11383 : NS_IMETHODIMP
11384 0 : nsDocShell::OnLinkClick(nsIContent* aContent,
11385 : nsIURI* aURI,
11386 : const PRUnichar* aTargetSpec,
11387 : nsIInputStream* aPostDataStream,
11388 : nsIInputStream* aHeadersDataStream,
11389 : bool aIsTrusted)
11390 : {
11391 0 : NS_ASSERTION(NS_IsMainThread(), "wrong thread");
11392 :
11393 0 : if (!IsOKToLoadURI(aURI)) {
11394 0 : return NS_OK;
11395 : }
11396 :
11397 0 : if (aContent->IsEditable()) {
11398 0 : return NS_OK;
11399 : }
11400 :
11401 0 : nsresult rv = NS_ERROR_FAILURE;
11402 0 : nsAutoString target;
11403 :
11404 0 : nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
11405 0 : if (browserChrome3) {
11406 0 : nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
11407 0 : nsAutoString oldTarget(aTargetSpec);
11408 0 : rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
11409 0 : linkNode, mIsAppTab, target);
11410 : }
11411 :
11412 0 : if (NS_FAILED(rv))
11413 0 : target = aTargetSpec;
11414 :
11415 : nsCOMPtr<nsIRunnable> ev =
11416 : new OnLinkClickEvent(this, aContent, aURI, target.get(),
11417 0 : aPostDataStream, aHeadersDataStream, aIsTrusted);
11418 0 : return NS_DispatchToCurrentThread(ev);
11419 : }
11420 :
11421 : NS_IMETHODIMP
11422 0 : nsDocShell::OnLinkClickSync(nsIContent *aContent,
11423 : nsIURI* aURI,
11424 : const PRUnichar* aTargetSpec,
11425 : nsIInputStream* aPostDataStream,
11426 : nsIInputStream* aHeadersDataStream,
11427 : nsIDocShell** aDocShell,
11428 : nsIRequest** aRequest)
11429 : {
11430 : // Initialize the DocShell / Request
11431 0 : if (aDocShell) {
11432 0 : *aDocShell = nsnull;
11433 : }
11434 0 : if (aRequest) {
11435 0 : *aRequest = nsnull;
11436 : }
11437 :
11438 0 : if (!IsOKToLoadURI(aURI)) {
11439 0 : return NS_OK;
11440 : }
11441 :
11442 0 : if (aContent->IsEditable()) {
11443 0 : return NS_OK;
11444 : }
11445 :
11446 : {
11447 : // defer to an external protocol handler if necessary...
11448 : nsCOMPtr<nsIExternalProtocolService> extProtService =
11449 0 : do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
11450 0 : if (extProtService) {
11451 0 : nsCAutoString scheme;
11452 0 : aURI->GetScheme(scheme);
11453 0 : if (!scheme.IsEmpty()) {
11454 : // if the URL scheme does not correspond to an exposed protocol, then we
11455 : // need to hand this link click over to the external protocol handler.
11456 : bool isExposed;
11457 0 : nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
11458 0 : if (NS_SUCCEEDED(rv) && !isExposed) {
11459 0 : return extProtService->LoadURI(aURI, this);
11460 : }
11461 : }
11462 : }
11463 : }
11464 :
11465 : // Get the owner document of the link that was clicked, this will be
11466 : // the document that the link is in, or the last document that the
11467 : // link was in. From that document, we'll get the URI to use as the
11468 : // referer, since the current URI in this docshell may be a
11469 : // new document that we're in the process of loading.
11470 0 : nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
11471 0 : NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
11472 :
11473 : // Now check that the refererDoc's inner window is the current inner
11474 : // window for mScriptGlobal. If it's not, then we don't want to
11475 : // follow this link.
11476 0 : nsPIDOMWindow* refererInner = refererDoc->GetInnerWindow();
11477 0 : NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
11478 0 : nsCOMPtr<nsPIDOMWindow> outerWindow = do_QueryInterface(mScriptGlobal);
11479 0 : if (!outerWindow || outerWindow->GetCurrentInnerWindow() != refererInner) {
11480 : // We're no longer the current inner window
11481 0 : return NS_OK;
11482 : }
11483 :
11484 0 : nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
11485 :
11486 : // referer could be null here in some odd cases, but that's ok,
11487 : // we'll just load the link w/o sending a referer in those cases.
11488 :
11489 0 : nsAutoString target(aTargetSpec);
11490 :
11491 : // If this is an anchor element, grab its type property to use as a hint
11492 0 : nsAutoString typeHint;
11493 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent));
11494 0 : if (anchor) {
11495 0 : anchor->GetType(typeHint);
11496 0 : NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
11497 0 : nsCAutoString type, dummy;
11498 0 : NS_ParseContentType(utf8Hint, type, dummy);
11499 0 : CopyUTF8toUTF16(type, typeHint);
11500 : }
11501 :
11502 : // Clone the URI now, in case a content policy or something messes
11503 : // with it under InternalLoad; we do _not_ want to change the URI
11504 : // our caller passed in.
11505 0 : nsCOMPtr<nsIURI> clonedURI;
11506 0 : aURI->Clone(getter_AddRefs(clonedURI));
11507 0 : if (!clonedURI) {
11508 0 : return NS_ERROR_OUT_OF_MEMORY;
11509 : }
11510 :
11511 : nsresult rv = InternalLoad(clonedURI, // New URI
11512 : referer, // Referer URI
11513 0 : aContent->NodePrincipal(), // Owner is our node's
11514 : // principal
11515 : INTERNAL_LOAD_FLAGS_NONE,
11516 : target.get(), // Window target
11517 0 : NS_LossyConvertUTF16toASCII(typeHint).get(),
11518 : aPostDataStream, // Post data stream
11519 : aHeadersDataStream, // Headers stream
11520 : LOAD_LINK, // Load type
11521 : nsnull, // No SHEntry
11522 : true, // first party site
11523 : aDocShell, // DocShell out-param
11524 0 : aRequest); // Request out-param
11525 0 : if (NS_SUCCEEDED(rv)) {
11526 0 : DispatchPings(aContent, referer);
11527 : }
11528 0 : return rv;
11529 : }
11530 :
11531 : NS_IMETHODIMP
11532 0 : nsDocShell::OnOverLink(nsIContent* aContent,
11533 : nsIURI* aURI,
11534 : const PRUnichar* aTargetSpec)
11535 : {
11536 0 : if (aContent->IsEditable()) {
11537 0 : return NS_OK;
11538 : }
11539 :
11540 0 : nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
11541 0 : nsresult rv = NS_ERROR_FAILURE;
11542 :
11543 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome;
11544 0 : if (!browserChrome2) {
11545 0 : browserChrome = do_GetInterface(mTreeOwner);
11546 0 : if (!browserChrome)
11547 0 : return rv;
11548 : }
11549 :
11550 : nsCOMPtr<nsITextToSubURI> textToSubURI =
11551 0 : do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
11552 0 : if (NS_FAILED(rv))
11553 0 : return rv;
11554 :
11555 : // use url origin charset to unescape the URL
11556 0 : nsCAutoString charset;
11557 0 : rv = aURI->GetOriginCharset(charset);
11558 0 : NS_ENSURE_SUCCESS(rv, rv);
11559 :
11560 0 : nsCAutoString spec;
11561 0 : rv = aURI->GetSpec(spec);
11562 0 : NS_ENSURE_SUCCESS(rv, rv);
11563 :
11564 0 : nsAutoString uStr;
11565 0 : rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr);
11566 0 : NS_ENSURE_SUCCESS(rv, rv);
11567 :
11568 0 : if (browserChrome2) {
11569 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
11570 0 : rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
11571 0 : uStr, element);
11572 : } else {
11573 0 : rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
11574 : }
11575 0 : return rv;
11576 : }
11577 :
11578 : NS_IMETHODIMP
11579 0 : nsDocShell::OnLeaveLink()
11580 : {
11581 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
11582 0 : nsresult rv = NS_ERROR_FAILURE;
11583 :
11584 0 : if (browserChrome) {
11585 0 : rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
11586 0 : EmptyString().get());
11587 : }
11588 0 : return rv;
11589 : }
11590 :
11591 : //----------------------------------------------------------------------
11592 : // Web Shell Services API
11593 :
11594 : //This functions is only called when a new charset is detected in loading a document.
11595 : //Its name should be changed to "CharsetReloadDocument"
11596 : NS_IMETHODIMP
11597 0 : nsDocShell::ReloadDocument(const char* aCharset,
11598 : PRInt32 aSource)
11599 : {
11600 :
11601 : // XXX hack. keep the aCharset and aSource wait to pick it up
11602 0 : nsCOMPtr<nsIContentViewer> cv;
11603 0 : NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
11604 0 : if (cv)
11605 : {
11606 0 : nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv);
11607 0 : if (muDV)
11608 : {
11609 : PRInt32 hint;
11610 0 : muDV->GetHintCharacterSetSource(&hint);
11611 0 : if (aSource > hint)
11612 : {
11613 0 : nsCString charset(aCharset);
11614 0 : muDV->SetHintCharacterSet(charset);
11615 0 : muDV->SetHintCharacterSetSource(aSource);
11616 0 : if(eCharsetReloadRequested != mCharsetReloadState)
11617 : {
11618 0 : mCharsetReloadState = eCharsetReloadRequested;
11619 0 : return Reload(LOAD_FLAGS_CHARSET_CHANGE);
11620 : }
11621 : }
11622 : }
11623 : }
11624 : //return failure if this request is not accepted due to mCharsetReloadState
11625 0 : return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
11626 : }
11627 :
11628 :
11629 : NS_IMETHODIMP
11630 0 : nsDocShell::StopDocumentLoad(void)
11631 : {
11632 0 : if(eCharsetReloadRequested != mCharsetReloadState)
11633 : {
11634 0 : Stop(nsIWebNavigation::STOP_ALL);
11635 0 : return NS_OK;
11636 : }
11637 : //return failer if this request is not accepted due to mCharsetReloadState
11638 0 : return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
11639 : }
11640 :
11641 : NS_IMETHODIMP
11642 0 : nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
11643 : {
11644 0 : *aPrintPreview = nsnull;
11645 : #if NS_PRINT_PREVIEW
11646 0 : nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
11647 0 : if (!print || !print->IsInitializedForPrintPreview()) {
11648 0 : Stop(nsIWebNavigation::STOP_ALL);
11649 : nsCOMPtr<nsIPrincipal> principal =
11650 0 : do_CreateInstance("@mozilla.org/nullprincipal;1");
11651 0 : NS_ENSURE_STATE(principal);
11652 0 : nsresult rv = CreateAboutBlankContentViewer(principal, nsnull);
11653 0 : NS_ENSURE_SUCCESS(rv, rv);
11654 0 : print = do_QueryInterface(mContentViewer);
11655 0 : NS_ENSURE_STATE(print);
11656 0 : print->InitializeForPrintPreview();
11657 : }
11658 0 : nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
11659 0 : result.forget(aPrintPreview);
11660 0 : return NS_OK;
11661 : #else
11662 : return NS_ERROR_NOT_IMPLEMENTED;
11663 : #endif
11664 : }
11665 :
11666 :
11667 : #ifdef DEBUG
11668 : unsigned long nsDocShell::gNumberOfDocShells = 0;
11669 : #endif
11670 :
11671 : NS_IMETHODIMP
11672 0 : nsDocShell::GetCanExecuteScripts(bool *aResult)
11673 : {
11674 0 : NS_ENSURE_ARG_POINTER(aResult);
11675 0 : *aResult = false; // disallow by default
11676 :
11677 0 : nsCOMPtr<nsIDocShell> docshell = this;
11678 : nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem =
11679 0 : do_QueryInterface(docshell);
11680 :
11681 0 : if (globalObjTreeItem)
11682 : {
11683 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
11684 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
11685 0 : bool firstPass = true;
11686 0 : bool lookForParents = false;
11687 :
11688 : // Walk up the docshell tree to see if any containing docshell disallows scripts
11689 0 : do
11690 : {
11691 0 : nsresult rv = docshell->GetAllowJavascript(aResult);
11692 0 : if (NS_FAILED(rv)) return rv;
11693 0 : if (!*aResult) {
11694 0 : nsDocShell* realDocshell = static_cast<nsDocShell*>(docshell.get());
11695 0 : if (realDocshell->mContentViewer) {
11696 0 : nsIDocument* doc = realDocshell->mContentViewer->GetDocument();
11697 0 : if (doc && doc->HasFlag(NODE_IS_EDITABLE) &&
11698 0 : realDocshell->mEditorData) {
11699 0 : nsCOMPtr<nsIEditingSession> editSession;
11700 0 : realDocshell->mEditorData->GetEditingSession(getter_AddRefs(editSession));
11701 0 : bool jsDisabled = false;
11702 0 : if (editSession &&
11703 0 : NS_SUCCEEDED(rv = editSession->GetJsAndPluginsDisabled(&jsDisabled))) {
11704 0 : if (firstPass) {
11705 0 : if (jsDisabled) {
11706 : // We have a docshell which has been explicitly set
11707 : // to design mode, so we disallow scripts.
11708 0 : return NS_OK;
11709 : }
11710 : // The docshell was not explicitly set to design mode,
11711 : // so it must be so because a parent was explicitly
11712 : // set to design mode. We don't need to look at higher
11713 : // docshells.
11714 0 : *aResult = true;
11715 : break;
11716 0 : } else if (lookForParents && jsDisabled) {
11717 : // If a parent was explicitly set to design mode,
11718 : // we should allow script execution on the child.
11719 0 : *aResult = true;
11720 : break;
11721 : }
11722 : // If the child docshell allows scripting, and the
11723 : // parent is inside design mode, we don't need to look
11724 : // further.
11725 0 : *aResult = true;
11726 0 : return NS_OK;
11727 : }
11728 0 : NS_WARNING("The editing session does not work?");
11729 0 : return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
11730 : }
11731 0 : if (firstPass) {
11732 : // Don't be too hard on docshells on the first pass.
11733 : // There may be a parent docshell which has been set
11734 : // to design mode, so look for it.
11735 0 : lookForParents = true;
11736 : } else {
11737 : // We have a docshell which disallows scripts
11738 : // and is not editable, so we shouldn't allow
11739 : // scripts at all.
11740 0 : return NS_OK;
11741 : }
11742 : }
11743 0 : } else if (lookForParents) {
11744 : // The parent docshell was not explicitly set to design
11745 : // mode, so js on the child docshell was disabled for
11746 : // another reason. Therefore, we need to disable js.
11747 0 : *aResult = false;
11748 0 : return NS_OK;
11749 : }
11750 0 : firstPass = false;
11751 :
11752 0 : treeItem->GetParent(getter_AddRefs(parentItem));
11753 0 : treeItem.swap(parentItem);
11754 0 : docshell = do_QueryInterface(treeItem);
11755 : #ifdef DEBUG
11756 0 : if (treeItem && !docshell) {
11757 0 : NS_ERROR("cannot get a docshell from a treeItem!");
11758 : }
11759 : #endif // DEBUG
11760 0 : } while (treeItem && docshell);
11761 : }
11762 :
11763 0 : return NS_OK;
11764 : }
11765 :
11766 : NS_IMETHODIMP
11767 0 : nsDocShell::GetIsBrowserFrame(bool *aOut)
11768 : {
11769 0 : NS_ENSURE_ARG_POINTER(aOut);
11770 0 : *aOut = mIsBrowserFrame;
11771 0 : return NS_OK;
11772 : }
11773 :
11774 : NS_IMETHODIMP
11775 0 : nsDocShell::SetIsBrowserFrame(bool aValue)
11776 : {
11777 0 : mIsBrowserFrame = aValue;
11778 0 : return NS_OK;
11779 : }
|