|
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 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "nsDocShell.h" |
|
8 |
|
9 #include <algorithm> |
|
10 |
|
11 #include "mozilla/ArrayUtils.h" |
|
12 #include "mozilla/Attributes.h" |
|
13 #include "mozilla/AutoRestore.h" |
|
14 #include "mozilla/Casting.h" |
|
15 #include "mozilla/dom/ContentChild.h" |
|
16 #include "mozilla/dom/Element.h" |
|
17 #include "mozilla/dom/TabChild.h" |
|
18 #include "mozilla/EventStateManager.h" |
|
19 #include "mozilla/Preferences.h" |
|
20 #include "mozilla/Services.h" |
|
21 #include "mozilla/StartupTimeline.h" |
|
22 #include "mozilla/Telemetry.h" |
|
23 #include "mozilla/unused.h" |
|
24 #include "mozilla/VisualEventTracer.h" |
|
25 |
|
26 #ifdef MOZ_LOGGING |
|
27 // so we can get logging even in release builds (but only for some things) |
|
28 #define FORCE_PR_LOG 1 |
|
29 #endif |
|
30 |
|
31 #include "nsIContent.h" |
|
32 #include "nsIDocument.h" |
|
33 #include "nsIDOMDocument.h" |
|
34 #include "nsIDOMElement.h" |
|
35 #include "nsIDOMStorage.h" |
|
36 #include "nsPIDOMStorage.h" |
|
37 #include "nsIContentViewer.h" |
|
38 #include "nsIDocumentLoaderFactory.h" |
|
39 #include "nsCURILoader.h" |
|
40 #include "nsDocShellCID.h" |
|
41 #include "nsDOMCID.h" |
|
42 #include "nsNetUtil.h" |
|
43 #include "nsRect.h" |
|
44 #include "prenv.h" |
|
45 #include "nsIMarkupDocumentViewer.h" |
|
46 #include "nsIDOMWindow.h" |
|
47 #include "nsIWebBrowserChrome.h" |
|
48 #include "nsPoint.h" |
|
49 #include "nsIObserverService.h" |
|
50 #include "nsIPrompt.h" |
|
51 #include "nsIAuthPrompt.h" |
|
52 #include "nsIAuthPrompt2.h" |
|
53 #include "nsIChannelEventSink.h" |
|
54 #include "nsIAsyncVerifyRedirectCallback.h" |
|
55 #include "nsIScriptSecurityManager.h" |
|
56 #include "nsIScriptObjectPrincipal.h" |
|
57 #include "nsIScrollableFrame.h" |
|
58 #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...) |
|
59 #include "nsISeekableStream.h" |
|
60 #include "nsAutoPtr.h" |
|
61 #include "nsIWritablePropertyBag2.h" |
|
62 #include "nsIAppShell.h" |
|
63 #include "nsWidgetsCID.h" |
|
64 #include "nsIInterfaceRequestorUtils.h" |
|
65 #include "nsView.h" |
|
66 #include "nsViewManager.h" |
|
67 #include "nsIScriptChannel.h" |
|
68 #include "nsITimedChannel.h" |
|
69 #include "nsIPrivacyTransitionObserver.h" |
|
70 #include "nsIReflowObserver.h" |
|
71 #include "nsIScrollObserver.h" |
|
72 #include "nsIDocShellTreeItem.h" |
|
73 #include "nsIChannel.h" |
|
74 #include "IHistory.h" |
|
75 #include "nsViewSourceHandler.h" |
|
76 |
|
77 // we want to explore making the document own the load group |
|
78 // so we can associate the document URI with the load group. |
|
79 // until this point, we have an evil hack: |
|
80 #include "nsIHttpChannelInternal.h" |
|
81 #include "nsPILoadGroupInternal.h" |
|
82 |
|
83 // Local Includes |
|
84 #include "nsDocShellLoadInfo.h" |
|
85 #include "nsCDefaultURIFixup.h" |
|
86 #include "nsDocShellEnumerator.h" |
|
87 #include "nsSHistory.h" |
|
88 #include "nsDocShellEditorData.h" |
|
89 |
|
90 // Helper Classes |
|
91 #include "nsError.h" |
|
92 #include "nsEscape.h" |
|
93 |
|
94 // Interfaces Needed |
|
95 #include "nsIUploadChannel.h" |
|
96 #include "nsIUploadChannel2.h" |
|
97 #include "nsIWebProgress.h" |
|
98 #include "nsILayoutHistoryState.h" |
|
99 #include "nsITimer.h" |
|
100 #include "nsISHistoryInternal.h" |
|
101 #include "nsIPrincipal.h" |
|
102 #include "nsISHEntry.h" |
|
103 #include "nsIWindowWatcher.h" |
|
104 #include "nsIPromptFactory.h" |
|
105 #include "nsITransportSecurityInfo.h" |
|
106 #include "nsINSSErrorsService.h" |
|
107 #include "nsIApplicationCacheChannel.h" |
|
108 #include "nsIApplicationCacheContainer.h" |
|
109 #include "nsStreamUtils.h" |
|
110 #include "nsIController.h" |
|
111 #include "nsPICommandUpdater.h" |
|
112 #include "nsIDOMHTMLAnchorElement.h" |
|
113 #include "nsIWebBrowserChrome3.h" |
|
114 #include "nsITabChild.h" |
|
115 #include "nsISiteSecurityService.h" |
|
116 #include "nsStructuredCloneContainer.h" |
|
117 #include "nsIStructuredCloneContainer.h" |
|
118 #ifdef MOZ_PLACES |
|
119 #include "nsIFaviconService.h" |
|
120 #include "mozIAsyncFavicons.h" |
|
121 #endif |
|
122 #include "nsINetworkSeer.h" |
|
123 |
|
124 // Editor-related |
|
125 #include "nsIEditingSession.h" |
|
126 |
|
127 #include "nsPIDOMWindow.h" |
|
128 #include "nsGlobalWindow.h" |
|
129 #include "nsPIWindowRoot.h" |
|
130 #include "nsICachingChannel.h" |
|
131 #include "nsIMultiPartChannel.h" |
|
132 #include "nsIWyciwygChannel.h" |
|
133 |
|
134 // For reporting errors with the console service. |
|
135 // These can go away if error reporting is propagated up past nsDocShell. |
|
136 #include "nsIScriptError.h" |
|
137 |
|
138 // used to dispatch urls to default protocol handlers |
|
139 #include "nsCExternalHandlerService.h" |
|
140 #include "nsIExternalProtocolService.h" |
|
141 |
|
142 #include "nsFocusManager.h" |
|
143 |
|
144 #include "nsITextToSubURI.h" |
|
145 |
|
146 #include "nsIJARChannel.h" |
|
147 |
|
148 #include "prlog.h" |
|
149 |
|
150 #include "nsISelectionDisplay.h" |
|
151 |
|
152 #include "nsIGlobalHistory2.h" |
|
153 |
|
154 #include "nsIFrame.h" |
|
155 #include "nsSubDocumentFrame.h" |
|
156 |
|
157 // for embedding |
|
158 #include "nsIWebBrowserChromeFocus.h" |
|
159 |
|
160 #if NS_PRINT_PREVIEW |
|
161 #include "nsIDocumentViewerPrint.h" |
|
162 #include "nsIWebBrowserPrint.h" |
|
163 #endif |
|
164 |
|
165 #include "nsContentUtils.h" |
|
166 #include "nsCxPusher.h" |
|
167 #include "nsIChannelPolicy.h" |
|
168 #include "nsIContentSecurityPolicy.h" |
|
169 #include "nsSandboxFlags.h" |
|
170 #include "mozIThirdPartyUtil.h" |
|
171 #include "nsXULAppAPI.h" |
|
172 #include "nsDOMNavigationTiming.h" |
|
173 #include "nsISecurityUITelemetry.h" |
|
174 #include "nsIAppsService.h" |
|
175 #include "nsDSURIContentListener.h" |
|
176 #include "nsDocShellLoadTypes.h" |
|
177 #include "nsDocShellTransferableHooks.h" |
|
178 #include "nsICommandManager.h" |
|
179 #include "nsIDOMNode.h" |
|
180 #include "nsIDocShellTreeOwner.h" |
|
181 #include "nsIHttpChannel.h" |
|
182 #include "nsISHContainer.h" |
|
183 #include "nsISHistory.h" |
|
184 #include "nsISecureBrowserUI.h" |
|
185 #include "nsIStringBundle.h" |
|
186 #include "nsISupportsArray.h" |
|
187 #include "nsIURIFixup.h" |
|
188 #include "nsIURILoader.h" |
|
189 #include "nsIWebBrowserFind.h" |
|
190 #include "nsIWidget.h" |
|
191 #include "mozilla/dom/EncodingUtils.h" |
|
192 |
|
193 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); |
|
194 |
|
195 #if defined(DEBUG_bryner) || defined(DEBUG_chb) |
|
196 //#define DEBUG_DOCSHELL_FOCUS |
|
197 #define DEBUG_PAGE_CACHE |
|
198 #endif |
|
199 |
|
200 #ifdef XP_WIN |
|
201 #include <process.h> |
|
202 #define getpid _getpid |
|
203 #else |
|
204 #include <unistd.h> // for getpid() |
|
205 #endif |
|
206 |
|
207 using namespace mozilla; |
|
208 using namespace mozilla::dom; |
|
209 |
|
210 // True means sUseErrorPages has been added to preferences var cache. |
|
211 static bool gAddedPreferencesVarCache = false; |
|
212 |
|
213 bool nsDocShell::sUseErrorPages = false; |
|
214 |
|
215 // Number of documents currently loading |
|
216 static int32_t gNumberOfDocumentsLoading = 0; |
|
217 |
|
218 // Global count of existing docshells. |
|
219 static int32_t gDocShellCount = 0; |
|
220 |
|
221 // Global count of docshells with the private attribute set |
|
222 static uint32_t gNumberOfPrivateDocShells = 0; |
|
223 |
|
224 // Global reference to the URI fixup service. |
|
225 nsIURIFixup *nsDocShell::sURIFixup = 0; |
|
226 |
|
227 // True means we validate window targets to prevent frameset |
|
228 // spoofing. Initialize this to a non-bolean value so we know to check |
|
229 // the pref on the creation of the first docshell. |
|
230 static uint32_t gValidateOrigin = 0xffffffff; |
|
231 |
|
232 // Hint for native dispatch of events on how long to delay after |
|
233 // all documents have loaded in milliseconds before favoring normal |
|
234 // native event dispatch priorites over performance |
|
235 // Can be overridden with docshell.event_starvation_delay_hint pref. |
|
236 #define NS_EVENT_STARVATION_DELAY_HINT 2000 |
|
237 |
|
238 #ifdef PR_LOGGING |
|
239 #ifdef DEBUG |
|
240 static PRLogModuleInfo* gDocShellLog; |
|
241 #endif |
|
242 static PRLogModuleInfo* gDocShellLeakLog; |
|
243 #endif |
|
244 |
|
245 const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties"; |
|
246 const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties"; |
|
247 |
|
248 static void |
|
249 FavorPerformanceHint(bool perfOverStarvation) |
|
250 { |
|
251 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID); |
|
252 if (appShell) { |
|
253 appShell->FavorPerformanceHint(perfOverStarvation, |
|
254 Preferences::GetUint("docshell.event_starvation_delay_hint", |
|
255 NS_EVENT_STARVATION_DELAY_HINT)); |
|
256 } |
|
257 } |
|
258 |
|
259 //***************************************************************************** |
|
260 // <a ping> support |
|
261 //***************************************************************************** |
|
262 |
|
263 #define PREF_PINGS_ENABLED "browser.send_pings" |
|
264 #define PREF_PINGS_MAX_PER_LINK "browser.send_pings.max_per_link" |
|
265 #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host" |
|
266 |
|
267 // Check prefs to see if pings are enabled and if so what restrictions might |
|
268 // be applied. |
|
269 // |
|
270 // @param maxPerLink |
|
271 // This parameter returns the number of pings that are allowed per link click |
|
272 // |
|
273 // @param requireSameHost |
|
274 // This parameter returns true if pings are restricted to the same host as |
|
275 // the document in which the click occurs. If the same host restriction is |
|
276 // imposed, then we still allow for pings to cross over to different |
|
277 // protocols and ports for flexibility and because it is not possible to send |
|
278 // a ping via FTP. |
|
279 // |
|
280 // @returns |
|
281 // true if pings are enabled and false otherwise. |
|
282 // |
|
283 static bool |
|
284 PingsEnabled(int32_t *maxPerLink, bool *requireSameHost) |
|
285 { |
|
286 bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false); |
|
287 |
|
288 *maxPerLink = 1; |
|
289 *requireSameHost = true; |
|
290 |
|
291 if (allow) { |
|
292 Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, maxPerLink); |
|
293 Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost); |
|
294 } |
|
295 |
|
296 return allow; |
|
297 } |
|
298 |
|
299 static bool |
|
300 CheckPingURI(nsIURI* uri, nsIContent* content) |
|
301 { |
|
302 if (!uri) |
|
303 return false; |
|
304 |
|
305 // Check with nsIScriptSecurityManager |
|
306 nsCOMPtr<nsIScriptSecurityManager> ssmgr = |
|
307 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
308 NS_ENSURE_TRUE(ssmgr, false); |
|
309 |
|
310 nsresult rv = |
|
311 ssmgr->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri, |
|
312 nsIScriptSecurityManager::STANDARD); |
|
313 if (NS_FAILED(rv)) { |
|
314 return false; |
|
315 } |
|
316 |
|
317 // Ignore non-HTTP(S) |
|
318 bool match; |
|
319 if ((NS_FAILED(uri->SchemeIs("http", &match)) || !match) && |
|
320 (NS_FAILED(uri->SchemeIs("https", &match)) || !match)) { |
|
321 return false; |
|
322 } |
|
323 |
|
324 // Check with contentpolicy |
|
325 int16_t shouldLoad = nsIContentPolicy::ACCEPT; |
|
326 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING, |
|
327 uri, |
|
328 content->NodePrincipal(), |
|
329 content, |
|
330 EmptyCString(), // mime hint |
|
331 nullptr, //extra |
|
332 &shouldLoad); |
|
333 return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad); |
|
334 } |
|
335 |
|
336 typedef void (* ForEachPingCallback)(void *closure, nsIContent *content, |
|
337 nsIURI *uri, nsIIOService *ios); |
|
338 |
|
339 static void |
|
340 ForEachPing(nsIContent *content, ForEachPingCallback callback, void *closure) |
|
341 { |
|
342 // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here |
|
343 // since we'd still need to parse the resulting string. Instead, we |
|
344 // just parse the raw attribute. It might be nice if the content node |
|
345 // implemented an interface that exposed an enumeration of nsIURIs. |
|
346 |
|
347 // Make sure we are dealing with either an <A> or <AREA> element in the HTML |
|
348 // or XHTML namespace. |
|
349 if (!content->IsHTML()) |
|
350 return; |
|
351 nsIAtom *nameAtom = content->Tag(); |
|
352 if (nameAtom != nsGkAtoms::a && nameAtom != nsGkAtoms::area) |
|
353 return; |
|
354 |
|
355 nsCOMPtr<nsIAtom> pingAtom = do_GetAtom("ping"); |
|
356 if (!pingAtom) |
|
357 return; |
|
358 |
|
359 nsAutoString value; |
|
360 content->GetAttr(kNameSpaceID_None, pingAtom, value); |
|
361 if (value.IsEmpty()) |
|
362 return; |
|
363 |
|
364 nsCOMPtr<nsIIOService> ios = do_GetIOService(); |
|
365 if (!ios) |
|
366 return; |
|
367 |
|
368 nsIDocument *doc = content->OwnerDoc(); |
|
369 |
|
370 // value contains relative URIs split on spaces (U+0020) |
|
371 const char16_t *start = value.BeginReading(); |
|
372 const char16_t *end = value.EndReading(); |
|
373 const char16_t *iter = start; |
|
374 for (;;) { |
|
375 if (iter < end && *iter != ' ') { |
|
376 ++iter; |
|
377 } else { // iter is pointing at either end or a space |
|
378 while (*start == ' ' && start < iter) |
|
379 ++start; |
|
380 if (iter != start) { |
|
381 nsCOMPtr<nsIURI> uri, baseURI = content->GetBaseURI(); |
|
382 ios->NewURI(NS_ConvertUTF16toUTF8(Substring(start, iter)), |
|
383 doc->GetDocumentCharacterSet().get(), |
|
384 baseURI, getter_AddRefs(uri)); |
|
385 if (CheckPingURI(uri, content)) { |
|
386 callback(closure, content, uri, ios); |
|
387 } |
|
388 } |
|
389 start = iter = iter + 1; |
|
390 if (iter >= end) |
|
391 break; |
|
392 } |
|
393 } |
|
394 } |
|
395 |
|
396 //---------------------------------------------------------------------- |
|
397 |
|
398 // We wait this many milliseconds before killing the ping channel... |
|
399 #define PING_TIMEOUT 10000 |
|
400 |
|
401 static void |
|
402 OnPingTimeout(nsITimer *timer, void *closure) |
|
403 { |
|
404 nsILoadGroup *loadGroup = static_cast<nsILoadGroup *>(closure); |
|
405 if (loadGroup) |
|
406 loadGroup->Cancel(NS_ERROR_ABORT); |
|
407 } |
|
408 |
|
409 // Check to see if two URIs have the same host or not |
|
410 static bool |
|
411 IsSameHost(nsIURI *uri1, nsIURI *uri2) |
|
412 { |
|
413 nsAutoCString host1, host2; |
|
414 uri1->GetAsciiHost(host1); |
|
415 uri2->GetAsciiHost(host2); |
|
416 return host1.Equals(host2); |
|
417 } |
|
418 |
|
419 class nsPingListener MOZ_FINAL : public nsIStreamListener |
|
420 , public nsIInterfaceRequestor |
|
421 , public nsIChannelEventSink |
|
422 { |
|
423 public: |
|
424 NS_DECL_ISUPPORTS |
|
425 NS_DECL_NSIREQUESTOBSERVER |
|
426 NS_DECL_NSISTREAMLISTENER |
|
427 NS_DECL_NSIINTERFACEREQUESTOR |
|
428 NS_DECL_NSICHANNELEVENTSINK |
|
429 |
|
430 nsPingListener(bool requireSameHost, nsIContent* content, nsILoadGroup* loadGroup) |
|
431 : mRequireSameHost(requireSameHost), |
|
432 mContent(content), |
|
433 mLoadGroup(loadGroup) |
|
434 {} |
|
435 |
|
436 ~nsPingListener(); |
|
437 |
|
438 nsresult StartTimeout(); |
|
439 |
|
440 private: |
|
441 bool mRequireSameHost; |
|
442 nsCOMPtr<nsIContent> mContent; |
|
443 nsCOMPtr<nsILoadGroup> mLoadGroup; |
|
444 nsCOMPtr<nsITimer> mTimer; |
|
445 }; |
|
446 |
|
447 NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver, |
|
448 nsIInterfaceRequestor, nsIChannelEventSink) |
|
449 |
|
450 nsPingListener::~nsPingListener() |
|
451 { |
|
452 if (mTimer) { |
|
453 mTimer->Cancel(); |
|
454 mTimer = nullptr; |
|
455 } |
|
456 } |
|
457 |
|
458 nsresult |
|
459 nsPingListener::StartTimeout() |
|
460 { |
|
461 nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID); |
|
462 |
|
463 if (timer) { |
|
464 nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, mLoadGroup, |
|
465 PING_TIMEOUT, |
|
466 nsITimer::TYPE_ONE_SHOT); |
|
467 if (NS_SUCCEEDED(rv)) { |
|
468 mTimer = timer; |
|
469 return NS_OK; |
|
470 } |
|
471 } |
|
472 |
|
473 return NS_ERROR_OUT_OF_MEMORY; |
|
474 } |
|
475 |
|
476 NS_IMETHODIMP |
|
477 nsPingListener::OnStartRequest(nsIRequest *request, nsISupports *context) |
|
478 { |
|
479 return NS_OK; |
|
480 } |
|
481 |
|
482 NS_IMETHODIMP |
|
483 nsPingListener::OnDataAvailable(nsIRequest *request, nsISupports *context, |
|
484 nsIInputStream *stream, uint64_t offset, |
|
485 uint32_t count) |
|
486 { |
|
487 uint32_t result; |
|
488 return stream->ReadSegments(NS_DiscardSegment, nullptr, count, &result); |
|
489 } |
|
490 |
|
491 NS_IMETHODIMP |
|
492 nsPingListener::OnStopRequest(nsIRequest *request, nsISupports *context, |
|
493 nsresult status) |
|
494 { |
|
495 mLoadGroup = nullptr; |
|
496 |
|
497 if (mTimer) { |
|
498 mTimer->Cancel(); |
|
499 mTimer = nullptr; |
|
500 } |
|
501 |
|
502 return NS_OK; |
|
503 } |
|
504 |
|
505 NS_IMETHODIMP |
|
506 nsPingListener::GetInterface(const nsIID &iid, void **result) |
|
507 { |
|
508 if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) { |
|
509 NS_ADDREF_THIS(); |
|
510 *result = (nsIChannelEventSink *) this; |
|
511 return NS_OK; |
|
512 } |
|
513 |
|
514 return NS_ERROR_NO_INTERFACE; |
|
515 } |
|
516 |
|
517 NS_IMETHODIMP |
|
518 nsPingListener::AsyncOnChannelRedirect(nsIChannel *oldChan, nsIChannel *newChan, |
|
519 uint32_t flags, |
|
520 nsIAsyncVerifyRedirectCallback *callback) |
|
521 { |
|
522 nsCOMPtr<nsIURI> newURI; |
|
523 newChan->GetURI(getter_AddRefs(newURI)); |
|
524 |
|
525 if (!CheckPingURI(newURI, mContent)) |
|
526 return NS_ERROR_ABORT; |
|
527 |
|
528 if (!mRequireSameHost) { |
|
529 callback->OnRedirectVerifyCallback(NS_OK); |
|
530 return NS_OK; |
|
531 } |
|
532 |
|
533 // XXXbz should this be using something more like the nsContentUtils |
|
534 // same-origin checker? |
|
535 nsCOMPtr<nsIURI> oldURI; |
|
536 oldChan->GetURI(getter_AddRefs(oldURI)); |
|
537 NS_ENSURE_STATE(oldURI && newURI); |
|
538 |
|
539 if (!IsSameHost(oldURI, newURI)) |
|
540 return NS_ERROR_ABORT; |
|
541 |
|
542 callback->OnRedirectVerifyCallback(NS_OK); |
|
543 return NS_OK; |
|
544 } |
|
545 |
|
546 struct SendPingInfo { |
|
547 int32_t numPings; |
|
548 int32_t maxPings; |
|
549 bool requireSameHost; |
|
550 nsIURI *target; |
|
551 nsIURI *referrer; |
|
552 }; |
|
553 |
|
554 static void |
|
555 SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios) |
|
556 { |
|
557 SendPingInfo *info = static_cast<SendPingInfo *>(closure); |
|
558 if (info->numPings >= info->maxPings) |
|
559 return; |
|
560 |
|
561 if (info->requireSameHost) { |
|
562 // Make sure the referrer and the given uri share the same origin. We |
|
563 // only require the same hostname. The scheme and port may differ. |
|
564 if (!IsSameHost(uri, info->referrer)) |
|
565 return; |
|
566 } |
|
567 |
|
568 nsIDocument *doc = content->OwnerDoc(); |
|
569 |
|
570 nsCOMPtr<nsIChannel> chan; |
|
571 ios->NewChannelFromURI(uri, getter_AddRefs(chan)); |
|
572 if (!chan) |
|
573 return; |
|
574 |
|
575 // Don't bother caching the result of this URI load. |
|
576 chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING); |
|
577 |
|
578 nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan); |
|
579 if (!httpChan) |
|
580 return; |
|
581 |
|
582 // This is needed in order for 3rd-party cookie blocking to work. |
|
583 nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan); |
|
584 if (httpInternal) |
|
585 httpInternal->SetDocumentURI(doc->GetDocumentURI()); |
|
586 |
|
587 |
|
588 httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST")); |
|
589 |
|
590 // Remove extraneous request headers (to reduce request size) |
|
591 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"), |
|
592 EmptyCString(), false); |
|
593 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"), |
|
594 EmptyCString(), false); |
|
595 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"), |
|
596 EmptyCString(), false); |
|
597 |
|
598 // Always send a Ping-To header. |
|
599 nsAutoCString pingTo; |
|
600 if (NS_SUCCEEDED(info->target->GetSpec(pingTo))) |
|
601 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false); |
|
602 |
|
603 nsCOMPtr<nsIScriptSecurityManager> sm = |
|
604 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
605 |
|
606 if (sm && info->referrer) { |
|
607 bool referrerIsSecure; |
|
608 uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT; |
|
609 nsresult rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure); |
|
610 |
|
611 // Default to sending less data if NS_URIChainHasFlags() fails. |
|
612 referrerIsSecure = NS_FAILED(rv) || referrerIsSecure; |
|
613 |
|
614 bool sameOrigin = |
|
615 NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, uri, false)); |
|
616 |
|
617 // If both the address of the document containing the hyperlink being |
|
618 // audited and "ping URL" have the same origin or the document containing |
|
619 // the hyperlink being audited was not retrieved over an encrypted |
|
620 // connection, send a Ping-From header. |
|
621 if (sameOrigin || !referrerIsSecure) { |
|
622 nsAutoCString pingFrom; |
|
623 if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom))) |
|
624 httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom, false); |
|
625 } |
|
626 |
|
627 // If the document containing the hyperlink being audited was not retrieved |
|
628 // over an encrypted connection and its address does not have the same |
|
629 // origin as "ping URL", send a referrer. |
|
630 if (!sameOrigin && !referrerIsSecure) |
|
631 httpChan->SetReferrer(info->referrer); |
|
632 } |
|
633 |
|
634 nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan); |
|
635 if (!uploadChan) |
|
636 return; |
|
637 |
|
638 NS_NAMED_LITERAL_CSTRING(uploadData, "PING"); |
|
639 |
|
640 nsCOMPtr<nsIInputStream> uploadStream; |
|
641 NS_NewPostDataStream(getter_AddRefs(uploadStream), false, uploadData); |
|
642 if (!uploadStream) |
|
643 return; |
|
644 |
|
645 uploadChan->ExplicitSetUploadStream(uploadStream, |
|
646 NS_LITERAL_CSTRING("text/ping"), uploadData.Length(), |
|
647 NS_LITERAL_CSTRING("POST"), false); |
|
648 |
|
649 // The channel needs to have a loadgroup associated with it, so that we can |
|
650 // cancel the channel and any redirected channels it may create. |
|
651 nsCOMPtr<nsILoadGroup> loadGroup = |
|
652 do_CreateInstance(NS_LOADGROUP_CONTRACTID); |
|
653 if (!loadGroup) |
|
654 return; |
|
655 chan->SetLoadGroup(loadGroup); |
|
656 |
|
657 // Construct a listener that merely discards any response. If successful at |
|
658 // opening the channel, then it is not necessary to hold a reference to the |
|
659 // channel. The networking subsystem will take care of that for us. |
|
660 nsPingListener *pingListener = |
|
661 new nsPingListener(info->requireSameHost, content, loadGroup); |
|
662 if (!pingListener) |
|
663 return; |
|
664 |
|
665 nsCOMPtr<nsIStreamListener> listener(pingListener); |
|
666 |
|
667 // Observe redirects as well: |
|
668 nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(listener); |
|
669 NS_ASSERTION(callbacks, "oops"); |
|
670 loadGroup->SetNotificationCallbacks(callbacks); |
|
671 |
|
672 chan->AsyncOpen(listener, nullptr); |
|
673 |
|
674 // Even if AsyncOpen failed, we still count this as a successful ping. It's |
|
675 // possible that AsyncOpen may have failed after triggering some background |
|
676 // process that may have written something to the network. |
|
677 info->numPings++; |
|
678 |
|
679 // Prevent ping requests from stalling and never being garbage collected... |
|
680 if (NS_FAILED(pingListener->StartTimeout())) { |
|
681 // If we failed to setup the timer, then we should just cancel the channel |
|
682 // because we won't be able to ensure that it goes away in a timely manner. |
|
683 chan->Cancel(NS_ERROR_ABORT); |
|
684 } |
|
685 } |
|
686 |
|
687 // Spec: http://whatwg.org/specs/web-apps/current-work/#ping |
|
688 static void |
|
689 DispatchPings(nsIContent *content, nsIURI *target, nsIURI *referrer) |
|
690 { |
|
691 SendPingInfo info; |
|
692 |
|
693 if (!PingsEnabled(&info.maxPings, &info.requireSameHost)) |
|
694 return; |
|
695 if (info.maxPings == 0) |
|
696 return; |
|
697 |
|
698 info.numPings = 0; |
|
699 info.target = target; |
|
700 info.referrer = referrer; |
|
701 |
|
702 ForEachPing(content, SendPing, &info); |
|
703 } |
|
704 |
|
705 static nsDOMPerformanceNavigationType |
|
706 ConvertLoadTypeToNavigationType(uint32_t aLoadType) |
|
707 { |
|
708 // Not initialized, assume it's normal load. |
|
709 if (aLoadType == 0) { |
|
710 aLoadType = LOAD_NORMAL; |
|
711 } |
|
712 |
|
713 nsDOMPerformanceNavigationType result = dom::PerformanceNavigation::TYPE_RESERVED; |
|
714 switch (aLoadType) { |
|
715 case LOAD_NORMAL: |
|
716 case LOAD_NORMAL_EXTERNAL: |
|
717 case LOAD_NORMAL_BYPASS_CACHE: |
|
718 case LOAD_NORMAL_BYPASS_PROXY: |
|
719 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE: |
|
720 case LOAD_NORMAL_REPLACE: |
|
721 case LOAD_NORMAL_ALLOW_MIXED_CONTENT: |
|
722 case LOAD_LINK: |
|
723 case LOAD_STOP_CONTENT: |
|
724 case LOAD_REPLACE_BYPASS_CACHE: |
|
725 result = dom::PerformanceNavigation::TYPE_NAVIGATE; |
|
726 break; |
|
727 case LOAD_HISTORY: |
|
728 result = dom::PerformanceNavigation::TYPE_BACK_FORWARD; |
|
729 break; |
|
730 case LOAD_RELOAD_NORMAL: |
|
731 case LOAD_RELOAD_CHARSET_CHANGE: |
|
732 case LOAD_RELOAD_BYPASS_CACHE: |
|
733 case LOAD_RELOAD_BYPASS_PROXY: |
|
734 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
|
735 case LOAD_RELOAD_ALLOW_MIXED_CONTENT: |
|
736 result = dom::PerformanceNavigation::TYPE_RELOAD; |
|
737 break; |
|
738 case LOAD_STOP_CONTENT_AND_REPLACE: |
|
739 case LOAD_REFRESH: |
|
740 case LOAD_BYPASS_HISTORY: |
|
741 case LOAD_ERROR_PAGE: |
|
742 case LOAD_PUSHSTATE: |
|
743 result = dom::PerformanceNavigation::TYPE_RESERVED; |
|
744 break; |
|
745 default: |
|
746 // NS_NOTREACHED("Unexpected load type value"); |
|
747 result = dom::PerformanceNavigation::TYPE_RESERVED; |
|
748 break; |
|
749 } |
|
750 |
|
751 return result; |
|
752 } |
|
753 |
|
754 static nsISHEntry* GetRootSHEntry(nsISHEntry *entry); |
|
755 |
|
756 static void |
|
757 IncreasePrivateDocShellCount() |
|
758 { |
|
759 gNumberOfPrivateDocShells++; |
|
760 if (gNumberOfPrivateDocShells > 1 || |
|
761 XRE_GetProcessType() != GeckoProcessType_Content) { |
|
762 return; |
|
763 } |
|
764 |
|
765 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); |
|
766 cc->SendPrivateDocShellsExist(true); |
|
767 } |
|
768 |
|
769 static void |
|
770 DecreasePrivateDocShellCount() |
|
771 { |
|
772 MOZ_ASSERT(gNumberOfPrivateDocShells > 0); |
|
773 gNumberOfPrivateDocShells--; |
|
774 if (!gNumberOfPrivateDocShells) |
|
775 { |
|
776 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
777 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); |
|
778 cc->SendPrivateDocShellsExist(false); |
|
779 return; |
|
780 } |
|
781 |
|
782 nsCOMPtr<nsIObserverService> obsvc = mozilla::services::GetObserverService(); |
|
783 if (obsvc) { |
|
784 obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr); |
|
785 } |
|
786 } |
|
787 } |
|
788 |
|
789 //***************************************************************************** |
|
790 //*** nsDocShell: Object Management |
|
791 //***************************************************************************** |
|
792 |
|
793 static uint64_t gDocshellIDCounter = 0; |
|
794 |
|
795 // Note: operator new zeros our memory |
|
796 nsDocShell::nsDocShell(): |
|
797 nsDocLoader(), |
|
798 mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto), |
|
799 mTreeOwner(nullptr), |
|
800 mChromeEventHandler(nullptr), |
|
801 mCharsetReloadState(eCharsetReloadInit), |
|
802 mChildOffset(0), |
|
803 mBusyFlags(BUSY_FLAGS_NONE), |
|
804 mAppType(nsIDocShell::APP_TYPE_UNKNOWN), |
|
805 mLoadType(0), |
|
806 mMarginWidth(-1), |
|
807 mMarginHeight(-1), |
|
808 mItemType(typeContent), |
|
809 mPreviousTransIndex(-1), |
|
810 mLoadedTransIndex(-1), |
|
811 mSandboxFlags(0), |
|
812 mFullscreenAllowed(CHECK_ATTRIBUTES), |
|
813 mCreated(false), |
|
814 mAllowSubframes(true), |
|
815 mAllowPlugins(true), |
|
816 mAllowJavascript(true), |
|
817 mAllowMetaRedirects(true), |
|
818 mAllowImages(true), |
|
819 mAllowMedia(true), |
|
820 mAllowDNSPrefetch(true), |
|
821 mAllowWindowControl(true), |
|
822 mAllowContentRetargeting(true), |
|
823 mCreatingDocument(false), |
|
824 mUseErrorPages(false), |
|
825 mObserveErrorPages(true), |
|
826 mAllowAuth(true), |
|
827 mAllowKeywordFixup(false), |
|
828 mIsOffScreenBrowser(false), |
|
829 mIsActive(true), |
|
830 mIsAppTab(false), |
|
831 mUseGlobalHistory(false), |
|
832 mInPrivateBrowsing(false), |
|
833 mUseRemoteTabs(false), |
|
834 mDeviceSizeIsPageSize(false), |
|
835 mCanExecuteScripts(false), |
|
836 mFiredUnloadEvent(false), |
|
837 mEODForCurrentDocument(false), |
|
838 mURIResultedInDocument(false), |
|
839 mIsBeingDestroyed(false), |
|
840 mIsExecutingOnLoadHandler(false), |
|
841 mIsPrintingOrPP(false), |
|
842 mSavingOldViewer(false), |
|
843 #ifdef DEBUG |
|
844 mInEnsureScriptEnv(false), |
|
845 #endif |
|
846 mAffectPrivateSessionLifetime(true), |
|
847 mInvisible(false), |
|
848 mDefaultLoadFlags(nsIRequest::LOAD_NORMAL), |
|
849 mFrameType(eFrameTypeRegular), |
|
850 mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID), |
|
851 mParentCharsetSource(0) |
|
852 { |
|
853 mHistoryID = ++gDocshellIDCounter; |
|
854 if (gDocShellCount++ == 0) { |
|
855 NS_ASSERTION(sURIFixup == nullptr, |
|
856 "Huh, sURIFixup not null in first nsDocShell ctor!"); |
|
857 |
|
858 CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup); |
|
859 } |
|
860 |
|
861 #ifdef PR_LOGGING |
|
862 #ifdef DEBUG |
|
863 if (! gDocShellLog) |
|
864 gDocShellLog = PR_NewLogModule("nsDocShell"); |
|
865 #endif |
|
866 if (nullptr == gDocShellLeakLog) |
|
867 gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak"); |
|
868 if (gDocShellLeakLog) |
|
869 PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this)); |
|
870 #endif |
|
871 |
|
872 #ifdef DEBUG |
|
873 // We're counting the number of |nsDocShells| to help find leaks |
|
874 ++gNumberOfDocShells; |
|
875 if (!PR_GetEnv("MOZ_QUIET")) { |
|
876 printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n", |
|
877 (void*) this, |
|
878 gNumberOfDocShells, |
|
879 getpid(), |
|
880 SafeCast<unsigned long long>(mHistoryID)); |
|
881 } |
|
882 #endif |
|
883 } |
|
884 |
|
885 nsDocShell::~nsDocShell() |
|
886 { |
|
887 Destroy(); |
|
888 |
|
889 nsCOMPtr<nsISHistoryInternal> |
|
890 shPrivate(do_QueryInterface(mSessionHistory)); |
|
891 if (shPrivate) { |
|
892 shPrivate->SetRootDocShell(nullptr); |
|
893 } |
|
894 |
|
895 if (--gDocShellCount == 0) { |
|
896 NS_IF_RELEASE(sURIFixup); |
|
897 } |
|
898 |
|
899 #ifdef PR_LOGGING |
|
900 if (gDocShellLeakLog) |
|
901 PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this)); |
|
902 #endif |
|
903 |
|
904 #ifdef DEBUG |
|
905 // We're counting the number of |nsDocShells| to help find leaks |
|
906 --gNumberOfDocShells; |
|
907 if (!PR_GetEnv("MOZ_QUIET")) { |
|
908 printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %llu]\n", |
|
909 (void*) this, |
|
910 gNumberOfDocShells, |
|
911 getpid(), |
|
912 SafeCast<unsigned long long>(mHistoryID)); |
|
913 } |
|
914 #endif |
|
915 } |
|
916 |
|
917 nsresult |
|
918 nsDocShell::Init() |
|
919 { |
|
920 nsresult rv = nsDocLoader::Init(); |
|
921 NS_ENSURE_SUCCESS(rv, rv); |
|
922 |
|
923 NS_ASSERTION(mLoadGroup, "Something went wrong!"); |
|
924 |
|
925 mContentListener = new nsDSURIContentListener(this); |
|
926 NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY); |
|
927 |
|
928 rv = mContentListener->Init(); |
|
929 NS_ENSURE_SUCCESS(rv, rv); |
|
930 |
|
931 // We want to hold a strong ref to the loadgroup, so it better hold a weak |
|
932 // ref to us... use an InterfaceRequestorProxy to do this. |
|
933 nsCOMPtr<nsIInterfaceRequestor> proxy = |
|
934 new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*> |
|
935 (this)); |
|
936 NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY); |
|
937 mLoadGroup->SetNotificationCallbacks(proxy); |
|
938 |
|
939 rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this); |
|
940 NS_ENSURE_SUCCESS(rv, rv); |
|
941 |
|
942 // Add as |this| a progress listener to itself. A little weird, but |
|
943 // simpler than reproducing all the listener-notification logic in |
|
944 // overrides of the various methods via which nsDocLoader can be |
|
945 // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok. |
|
946 return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT | |
|
947 nsIWebProgress::NOTIFY_STATE_NETWORK); |
|
948 |
|
949 } |
|
950 |
|
951 void |
|
952 nsDocShell::DestroyChildren() |
|
953 { |
|
954 nsCOMPtr<nsIDocShellTreeItem> shell; |
|
955 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
956 while (iter.HasMore()) { |
|
957 shell = do_QueryObject(iter.GetNext()); |
|
958 NS_ASSERTION(shell, "docshell has null child"); |
|
959 |
|
960 if (shell) { |
|
961 shell->SetTreeOwner(nullptr); |
|
962 } |
|
963 } |
|
964 |
|
965 nsDocLoader::DestroyChildren(); |
|
966 } |
|
967 |
|
968 //***************************************************************************** |
|
969 // nsDocShell::nsISupports |
|
970 //***************************************************************************** |
|
971 |
|
972 NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader) |
|
973 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader) |
|
974 |
|
975 NS_INTERFACE_MAP_BEGIN(nsDocShell) |
|
976 NS_INTERFACE_MAP_ENTRY(nsIDocShell) |
|
977 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem) |
|
978 NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) |
|
979 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) |
|
980 NS_INTERFACE_MAP_ENTRY(nsIScrollable) |
|
981 NS_INTERFACE_MAP_ENTRY(nsITextScroll) |
|
982 NS_INTERFACE_MAP_ENTRY(nsIDocCharset) |
|
983 NS_INTERFACE_MAP_ENTRY(nsIRefreshURI) |
|
984 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) |
|
985 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
|
986 NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer) |
|
987 NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor) |
|
988 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider) |
|
989 NS_INTERFACE_MAP_ENTRY(nsILoadContext) |
|
990 NS_INTERFACE_MAP_ENTRY(nsIWebShellServices) |
|
991 NS_INTERFACE_MAP_ENTRY(nsILinkHandler) |
|
992 NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands) |
|
993 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager) |
|
994 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader) |
|
995 |
|
996 ///***************************************************************************** |
|
997 // nsDocShell::nsIInterfaceRequestor |
|
998 //***************************************************************************** |
|
999 NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink) |
|
1000 { |
|
1001 NS_PRECONDITION(aSink, "null out param"); |
|
1002 |
|
1003 *aSink = nullptr; |
|
1004 |
|
1005 if (aIID.Equals(NS_GET_IID(nsICommandManager))) { |
|
1006 NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE); |
|
1007 *aSink = mCommandManager; |
|
1008 } |
|
1009 else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) { |
|
1010 *aSink = mContentListener; |
|
1011 } |
|
1012 else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) || |
|
1013 aIID.Equals(NS_GET_IID(nsPIDOMWindow)) || |
|
1014 aIID.Equals(NS_GET_IID(nsIDOMWindow)) || |
|
1015 aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) && |
|
1016 NS_SUCCEEDED(EnsureScriptEnvironment())) { |
|
1017 return mScriptGlobal->QueryInterface(aIID, aSink); |
|
1018 } |
|
1019 else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) && |
|
1020 NS_SUCCEEDED(EnsureContentViewer())) { |
|
1021 mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink); |
|
1022 return *aSink ? NS_OK : NS_NOINTERFACE; |
|
1023 } |
|
1024 else if (aIID.Equals(NS_GET_IID(nsIDocument)) && |
|
1025 NS_SUCCEEDED(EnsureContentViewer())) { |
|
1026 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument(); |
|
1027 doc.forget(aSink); |
|
1028 return *aSink ? NS_OK : NS_NOINTERFACE; |
|
1029 } |
|
1030 else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) { |
|
1031 *aSink = nullptr; |
|
1032 |
|
1033 // Return application cache associated with this docshell, if any |
|
1034 |
|
1035 nsCOMPtr<nsIContentViewer> contentViewer; |
|
1036 GetContentViewer(getter_AddRefs(contentViewer)); |
|
1037 if (!contentViewer) |
|
1038 return NS_ERROR_NO_INTERFACE; |
|
1039 |
|
1040 nsCOMPtr<nsIDOMDocument> domDoc; |
|
1041 contentViewer->GetDOMDocument(getter_AddRefs(domDoc)); |
|
1042 NS_ASSERTION(domDoc, "Should have a document."); |
|
1043 if (!domDoc) |
|
1044 return NS_ERROR_NO_INTERFACE; |
|
1045 |
|
1046 #if defined(PR_LOGGING) && defined(DEBUG) |
|
1047 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
1048 ("nsDocShell[%p]: returning app cache container %p", |
|
1049 this, domDoc.get())); |
|
1050 #endif |
|
1051 return domDoc->QueryInterface(aIID, aSink); |
|
1052 } |
|
1053 else if (aIID.Equals(NS_GET_IID(nsIPrompt)) && |
|
1054 NS_SUCCEEDED(EnsureScriptEnvironment())) { |
|
1055 nsresult rv; |
|
1056 nsCOMPtr<nsIWindowWatcher> wwatch = |
|
1057 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); |
|
1058 NS_ENSURE_SUCCESS(rv, rv); |
|
1059 |
|
1060 // Get the an auth prompter for our window so that the parenting |
|
1061 // of the dialogs works as it should when using tabs. |
|
1062 nsIPrompt *prompt; |
|
1063 rv = wwatch->GetNewPrompter(mScriptGlobal, &prompt); |
|
1064 NS_ENSURE_SUCCESS(rv, rv); |
|
1065 |
|
1066 *aSink = prompt; |
|
1067 return NS_OK; |
|
1068 } |
|
1069 else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || |
|
1070 aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { |
|
1071 return NS_SUCCEEDED( |
|
1072 GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ? |
|
1073 NS_OK : NS_NOINTERFACE; |
|
1074 } |
|
1075 else if (aIID.Equals(NS_GET_IID(nsISHistory))) { |
|
1076 nsCOMPtr<nsISHistory> shistory; |
|
1077 nsresult |
|
1078 rv = |
|
1079 GetSessionHistory(getter_AddRefs(shistory)); |
|
1080 if (NS_SUCCEEDED(rv) && shistory) { |
|
1081 *aSink = shistory; |
|
1082 NS_ADDREF((nsISupports *) * aSink); |
|
1083 return NS_OK; |
|
1084 } |
|
1085 return NS_NOINTERFACE; |
|
1086 } |
|
1087 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) { |
|
1088 nsresult rv = EnsureFind(); |
|
1089 if (NS_FAILED(rv)) return rv; |
|
1090 |
|
1091 *aSink = mFind; |
|
1092 NS_ADDREF((nsISupports*)*aSink); |
|
1093 return NS_OK; |
|
1094 } |
|
1095 else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) && NS_SUCCEEDED(EnsureEditorData())) { |
|
1096 nsCOMPtr<nsIEditingSession> editingSession; |
|
1097 mEditorData->GetEditingSession(getter_AddRefs(editingSession)); |
|
1098 if (editingSession) |
|
1099 { |
|
1100 *aSink = editingSession; |
|
1101 NS_ADDREF((nsISupports *)*aSink); |
|
1102 return NS_OK; |
|
1103 } |
|
1104 |
|
1105 return NS_NOINTERFACE; |
|
1106 } |
|
1107 else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) |
|
1108 && NS_SUCCEEDED(EnsureTransferableHookData())) { |
|
1109 *aSink = mTransferableHookData; |
|
1110 NS_ADDREF((nsISupports *)*aSink); |
|
1111 return NS_OK; |
|
1112 } |
|
1113 else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) { |
|
1114 nsIPresShell* shell = GetPresShell(); |
|
1115 if (shell) |
|
1116 return shell->QueryInterface(aIID,aSink); |
|
1117 } |
|
1118 else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) { |
|
1119 nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
|
1120 nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner)); |
|
1121 if (NS_SUCCEEDED(rv) && treeOwner) |
|
1122 return treeOwner->QueryInterface(aIID, aSink); |
|
1123 } |
|
1124 else if (aIID.Equals(NS_GET_IID(nsITabChild))) { |
|
1125 nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
|
1126 nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner)); |
|
1127 if (NS_SUCCEEDED(rv) && treeOwner) { |
|
1128 nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(treeOwner); |
|
1129 if (ir) |
|
1130 return ir->GetInterface(aIID, aSink); |
|
1131 } |
|
1132 } |
|
1133 else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) { |
|
1134 nsCOMPtr<nsITabChild> tabChild = |
|
1135 do_GetInterface(static_cast<nsIDocShell*>(this)); |
|
1136 nsCOMPtr<nsIContentFrameMessageManager> mm; |
|
1137 if (tabChild) { |
|
1138 tabChild-> |
|
1139 GetMessageManager(getter_AddRefs(mm)); |
|
1140 } else { |
|
1141 nsCOMPtr<nsPIDOMWindow> win = |
|
1142 do_GetInterface(static_cast<nsIDocShell*>(this)); |
|
1143 if (win) { |
|
1144 mm = do_QueryInterface(win->GetParentTarget()); |
|
1145 } |
|
1146 } |
|
1147 *aSink = mm.get(); |
|
1148 } |
|
1149 else { |
|
1150 return nsDocLoader::GetInterface(aIID, aSink); |
|
1151 } |
|
1152 |
|
1153 NS_IF_ADDREF(((nsISupports *) * aSink)); |
|
1154 return *aSink ? NS_OK : NS_NOINTERFACE; |
|
1155 } |
|
1156 |
|
1157 uint32_t |
|
1158 nsDocShell:: |
|
1159 ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType) |
|
1160 { |
|
1161 uint32_t loadType = LOAD_NORMAL; |
|
1162 |
|
1163 switch (aDocShellLoadType) { |
|
1164 case nsIDocShellLoadInfo::loadNormal: |
|
1165 loadType = LOAD_NORMAL; |
|
1166 break; |
|
1167 case nsIDocShellLoadInfo::loadNormalReplace: |
|
1168 loadType = LOAD_NORMAL_REPLACE; |
|
1169 break; |
|
1170 case nsIDocShellLoadInfo::loadNormalExternal: |
|
1171 loadType = LOAD_NORMAL_EXTERNAL; |
|
1172 break; |
|
1173 case nsIDocShellLoadInfo::loadHistory: |
|
1174 loadType = LOAD_HISTORY; |
|
1175 break; |
|
1176 case nsIDocShellLoadInfo::loadNormalBypassCache: |
|
1177 loadType = LOAD_NORMAL_BYPASS_CACHE; |
|
1178 break; |
|
1179 case nsIDocShellLoadInfo::loadNormalBypassProxy: |
|
1180 loadType = LOAD_NORMAL_BYPASS_PROXY; |
|
1181 break; |
|
1182 case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache: |
|
1183 loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE; |
|
1184 break; |
|
1185 case nsIDocShellLoadInfo::loadNormalAllowMixedContent: |
|
1186 loadType = LOAD_NORMAL_ALLOW_MIXED_CONTENT; |
|
1187 break; |
|
1188 case nsIDocShellLoadInfo::loadReloadNormal: |
|
1189 loadType = LOAD_RELOAD_NORMAL; |
|
1190 break; |
|
1191 case nsIDocShellLoadInfo::loadReloadCharsetChange: |
|
1192 loadType = LOAD_RELOAD_CHARSET_CHANGE; |
|
1193 break; |
|
1194 case nsIDocShellLoadInfo::loadReloadBypassCache: |
|
1195 loadType = LOAD_RELOAD_BYPASS_CACHE; |
|
1196 break; |
|
1197 case nsIDocShellLoadInfo::loadReloadBypassProxy: |
|
1198 loadType = LOAD_RELOAD_BYPASS_PROXY; |
|
1199 break; |
|
1200 case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache: |
|
1201 loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE; |
|
1202 break; |
|
1203 case nsIDocShellLoadInfo::loadLink: |
|
1204 loadType = LOAD_LINK; |
|
1205 break; |
|
1206 case nsIDocShellLoadInfo::loadRefresh: |
|
1207 loadType = LOAD_REFRESH; |
|
1208 break; |
|
1209 case nsIDocShellLoadInfo::loadBypassHistory: |
|
1210 loadType = LOAD_BYPASS_HISTORY; |
|
1211 break; |
|
1212 case nsIDocShellLoadInfo::loadStopContent: |
|
1213 loadType = LOAD_STOP_CONTENT; |
|
1214 break; |
|
1215 case nsIDocShellLoadInfo::loadStopContentAndReplace: |
|
1216 loadType = LOAD_STOP_CONTENT_AND_REPLACE; |
|
1217 break; |
|
1218 case nsIDocShellLoadInfo::loadPushState: |
|
1219 loadType = LOAD_PUSHSTATE; |
|
1220 break; |
|
1221 case nsIDocShellLoadInfo::loadReplaceBypassCache: |
|
1222 loadType = LOAD_REPLACE_BYPASS_CACHE; |
|
1223 break; |
|
1224 case nsIDocShellLoadInfo::loadReloadMixedContent: |
|
1225 loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT; |
|
1226 break; |
|
1227 default: |
|
1228 NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value"); |
|
1229 } |
|
1230 |
|
1231 return loadType; |
|
1232 } |
|
1233 |
|
1234 |
|
1235 nsDocShellInfoLoadType |
|
1236 nsDocShell::ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType) |
|
1237 { |
|
1238 nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal; |
|
1239 switch (aLoadType) { |
|
1240 case LOAD_NORMAL: |
|
1241 docShellLoadType = nsIDocShellLoadInfo::loadNormal; |
|
1242 break; |
|
1243 case LOAD_NORMAL_REPLACE: |
|
1244 docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace; |
|
1245 break; |
|
1246 case LOAD_NORMAL_EXTERNAL: |
|
1247 docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal; |
|
1248 break; |
|
1249 case LOAD_NORMAL_BYPASS_CACHE: |
|
1250 docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache; |
|
1251 break; |
|
1252 case LOAD_NORMAL_BYPASS_PROXY: |
|
1253 docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy; |
|
1254 break; |
|
1255 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE: |
|
1256 docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache; |
|
1257 break; |
|
1258 case LOAD_NORMAL_ALLOW_MIXED_CONTENT: |
|
1259 docShellLoadType = nsIDocShellLoadInfo::loadNormalAllowMixedContent; |
|
1260 break; |
|
1261 case LOAD_HISTORY: |
|
1262 docShellLoadType = nsIDocShellLoadInfo::loadHistory; |
|
1263 break; |
|
1264 case LOAD_RELOAD_NORMAL: |
|
1265 docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal; |
|
1266 break; |
|
1267 case LOAD_RELOAD_CHARSET_CHANGE: |
|
1268 docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange; |
|
1269 break; |
|
1270 case LOAD_RELOAD_BYPASS_CACHE: |
|
1271 docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache; |
|
1272 break; |
|
1273 case LOAD_RELOAD_BYPASS_PROXY: |
|
1274 docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy; |
|
1275 break; |
|
1276 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
|
1277 docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache; |
|
1278 break; |
|
1279 case LOAD_LINK: |
|
1280 docShellLoadType = nsIDocShellLoadInfo::loadLink; |
|
1281 break; |
|
1282 case LOAD_REFRESH: |
|
1283 docShellLoadType = nsIDocShellLoadInfo::loadRefresh; |
|
1284 break; |
|
1285 case LOAD_BYPASS_HISTORY: |
|
1286 case LOAD_ERROR_PAGE: |
|
1287 docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory; |
|
1288 break; |
|
1289 case LOAD_STOP_CONTENT: |
|
1290 docShellLoadType = nsIDocShellLoadInfo::loadStopContent; |
|
1291 break; |
|
1292 case LOAD_STOP_CONTENT_AND_REPLACE: |
|
1293 docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace; |
|
1294 break; |
|
1295 case LOAD_PUSHSTATE: |
|
1296 docShellLoadType = nsIDocShellLoadInfo::loadPushState; |
|
1297 break; |
|
1298 case LOAD_REPLACE_BYPASS_CACHE: |
|
1299 docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache; |
|
1300 break; |
|
1301 case LOAD_RELOAD_ALLOW_MIXED_CONTENT: |
|
1302 docShellLoadType = nsIDocShellLoadInfo::loadReloadMixedContent; |
|
1303 break; |
|
1304 default: |
|
1305 NS_NOTREACHED("Unexpected load type value"); |
|
1306 } |
|
1307 |
|
1308 return docShellLoadType; |
|
1309 } |
|
1310 |
|
1311 //***************************************************************************** |
|
1312 // nsDocShell::nsIDocShell |
|
1313 //***************************************************************************** |
|
1314 NS_IMETHODIMP |
|
1315 nsDocShell::LoadURI(nsIURI * aURI, |
|
1316 nsIDocShellLoadInfo * aLoadInfo, |
|
1317 uint32_t aLoadFlags, |
|
1318 bool aFirstParty) |
|
1319 { |
|
1320 NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0, |
|
1321 "Unexpected flags"); |
|
1322 NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set"); |
|
1323 |
|
1324 // Note: we allow loads to get through here even if mFiredUnloadEvent is |
|
1325 // true; that case will get handled in LoadInternal or LoadHistoryEntry. |
|
1326 if (IsPrintingOrPP()) { |
|
1327 return NS_OK; // JS may not handle returning of an error code |
|
1328 } |
|
1329 nsCOMPtr<nsIURI> referrer; |
|
1330 nsCOMPtr<nsIInputStream> postStream; |
|
1331 nsCOMPtr<nsIInputStream> headersStream; |
|
1332 nsCOMPtr<nsISupports> owner; |
|
1333 bool inheritOwner = false; |
|
1334 bool ownerIsExplicit = false; |
|
1335 bool sendReferrer = true; |
|
1336 bool isSrcdoc = false; |
|
1337 nsCOMPtr<nsISHEntry> shEntry; |
|
1338 nsXPIDLString target; |
|
1339 nsAutoString srcdoc; |
|
1340 nsCOMPtr<nsIDocShell> sourceDocShell; |
|
1341 nsCOMPtr<nsIURI> baseURI; |
|
1342 |
|
1343 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); |
|
1344 |
|
1345 NS_ENSURE_ARG(aURI); |
|
1346 |
|
1347 if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) && |
|
1348 mItemType == typeContent && !NS_IsAboutBlank(aURI)) { |
|
1349 StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI); |
|
1350 } |
|
1351 |
|
1352 // Extract the info from the DocShellLoadInfo struct... |
|
1353 if (aLoadInfo) { |
|
1354 aLoadInfo->GetReferrer(getter_AddRefs(referrer)); |
|
1355 |
|
1356 nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal; |
|
1357 aLoadInfo->GetLoadType(<); |
|
1358 // Get the appropriate loadType from nsIDocShellLoadInfo type |
|
1359 loadType = ConvertDocShellLoadInfoToLoadType(lt); |
|
1360 |
|
1361 aLoadInfo->GetOwner(getter_AddRefs(owner)); |
|
1362 aLoadInfo->GetInheritOwner(&inheritOwner); |
|
1363 aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit); |
|
1364 aLoadInfo->GetSHEntry(getter_AddRefs(shEntry)); |
|
1365 aLoadInfo->GetTarget(getter_Copies(target)); |
|
1366 aLoadInfo->GetPostDataStream(getter_AddRefs(postStream)); |
|
1367 aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream)); |
|
1368 aLoadInfo->GetSendReferrer(&sendReferrer); |
|
1369 aLoadInfo->GetIsSrcdocLoad(&isSrcdoc); |
|
1370 aLoadInfo->GetSrcdocData(srcdoc); |
|
1371 aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell)); |
|
1372 aLoadInfo->GetBaseURI(getter_AddRefs(baseURI)); |
|
1373 } |
|
1374 |
|
1375 #if defined(PR_LOGGING) && defined(DEBUG) |
|
1376 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) { |
|
1377 nsAutoCString uristr; |
|
1378 aURI->GetAsciiSpec(uristr); |
|
1379 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
1380 ("nsDocShell[%p]: loading %s with flags 0x%08x", |
|
1381 this, uristr.get(), aLoadFlags)); |
|
1382 } |
|
1383 #endif |
|
1384 |
|
1385 if (!shEntry && |
|
1386 !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) { |
|
1387 // First verify if this is a subframe. |
|
1388 nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
|
1389 GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
1390 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem)); |
|
1391 uint32_t parentLoadType; |
|
1392 |
|
1393 if (parentDS && parentDS != static_cast<nsIDocShell *>(this)) { |
|
1394 /* OK. It is a subframe. Checkout the |
|
1395 * parent's loadtype. If the parent was loaded thro' a history |
|
1396 * mechanism, then get the SH entry for the child from the parent. |
|
1397 * This is done to restore frameset navigation while going back/forward. |
|
1398 * If the parent was loaded through any other loadType, set the |
|
1399 * child's loadType too accordingly, so that session history does not |
|
1400 * get confused. |
|
1401 */ |
|
1402 |
|
1403 // Get the parent's load type |
|
1404 parentDS->GetLoadType(&parentLoadType); |
|
1405 |
|
1406 // Get the ShEntry for the child from the parent |
|
1407 nsCOMPtr<nsISHEntry> currentSH; |
|
1408 bool oshe = false; |
|
1409 parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe); |
|
1410 bool dynamicallyAddedChild = mDynamicallyCreated; |
|
1411 if (!dynamicallyAddedChild && !oshe && currentSH) { |
|
1412 currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild); |
|
1413 } |
|
1414 if (!dynamicallyAddedChild) { |
|
1415 // Only use the old SHEntry, if we're sure enough that |
|
1416 // it wasn't originally for some other frame. |
|
1417 parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry)); |
|
1418 } |
|
1419 |
|
1420 // Make some decisions on the child frame's loadType based on the |
|
1421 // parent's loadType. |
|
1422 if (mCurrentURI == nullptr) { |
|
1423 // This is a newly created frame. Check for exception cases first. |
|
1424 // By default the subframe will inherit the parent's loadType. |
|
1425 if (shEntry && (parentLoadType == LOAD_NORMAL || |
|
1426 parentLoadType == LOAD_LINK || |
|
1427 parentLoadType == LOAD_NORMAL_EXTERNAL)) { |
|
1428 // The parent was loaded normally. In this case, this *brand new* child really shouldn't |
|
1429 // have a SHEntry. If it does, it could be because the parent is replacing an |
|
1430 // existing frame with a new frame, in the onLoadHandler. We don't want this |
|
1431 // url to get into session history. Clear off shEntry, and set load type to |
|
1432 // LOAD_BYPASS_HISTORY. |
|
1433 bool inOnLoadHandler=false; |
|
1434 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
|
1435 if (inOnLoadHandler) { |
|
1436 loadType = LOAD_NORMAL_REPLACE; |
|
1437 shEntry = nullptr; |
|
1438 } |
|
1439 } else if (parentLoadType == LOAD_REFRESH) { |
|
1440 // Clear shEntry. For refresh loads, we have to load |
|
1441 // what comes thro' the pipe, not what's in history. |
|
1442 shEntry = nullptr; |
|
1443 } else if ((parentLoadType == LOAD_BYPASS_HISTORY) || |
|
1444 (shEntry && |
|
1445 ((parentLoadType & LOAD_CMD_HISTORY) || |
|
1446 (parentLoadType == LOAD_RELOAD_NORMAL) || |
|
1447 (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) { |
|
1448 // If the parent url, bypassed history or was loaded from |
|
1449 // history, pass on the parent's loadType to the new child |
|
1450 // frame too, so that the child frame will also |
|
1451 // avoid getting into history. |
|
1452 loadType = parentLoadType; |
|
1453 } else if (parentLoadType == LOAD_ERROR_PAGE) { |
|
1454 // If the parent document is an error page, we don't |
|
1455 // want to update global/session history. However, |
|
1456 // this child frame is not an error page. |
|
1457 loadType = LOAD_BYPASS_HISTORY; |
|
1458 } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) || |
|
1459 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) || |
|
1460 (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) { |
|
1461 // the new frame should inherit the parent's load type so that it also |
|
1462 // bypasses the cache and/or proxy |
|
1463 loadType = parentLoadType; |
|
1464 } |
|
1465 } else { |
|
1466 // This is a pre-existing subframe. If the load was not originally initiated |
|
1467 // by session history, (if (!shEntry) condition succeeded) and mCurrentURI is not null, |
|
1468 // it is possible that a parent's onLoadHandler or even self's onLoadHandler is loading |
|
1469 // a new page in this child. Check parent's and self's busy flag and if it is set, |
|
1470 // we don't want this onLoadHandler load to get in to session history. |
|
1471 uint32_t parentBusy = BUSY_FLAGS_NONE; |
|
1472 uint32_t selfBusy = BUSY_FLAGS_NONE; |
|
1473 parentDS->GetBusyFlags(&parentBusy); |
|
1474 GetBusyFlags(&selfBusy); |
|
1475 if (parentBusy & BUSY_FLAGS_BUSY || |
|
1476 selfBusy & BUSY_FLAGS_BUSY) { |
|
1477 loadType = LOAD_NORMAL_REPLACE; |
|
1478 shEntry = nullptr; |
|
1479 } |
|
1480 } |
|
1481 } //parentDS |
|
1482 else { |
|
1483 // This is the root docshell. If we got here while |
|
1484 // executing an onLoad Handler,this load will not go |
|
1485 // into session history. |
|
1486 bool inOnLoadHandler=false; |
|
1487 GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
|
1488 if (inOnLoadHandler) { |
|
1489 loadType = LOAD_NORMAL_REPLACE; |
|
1490 } |
|
1491 } |
|
1492 } // !shEntry |
|
1493 |
|
1494 if (shEntry) { |
|
1495 #ifdef DEBUG |
|
1496 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
1497 ("nsDocShell[%p]: loading from session history", this)); |
|
1498 #endif |
|
1499 |
|
1500 return LoadHistoryEntry(shEntry, loadType); |
|
1501 } |
|
1502 |
|
1503 // On history navigation via Back/Forward buttons, don't execute |
|
1504 // automatic JavaScript redirection such as |location.href = ...| or |
|
1505 // |window.open()| |
|
1506 // |
|
1507 // LOAD_NORMAL: window.open(...) etc. |
|
1508 // LOAD_STOP_CONTENT: location.href = ..., location.assign(...) |
|
1509 if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) && |
|
1510 ShouldBlockLoadingForBackButton()) { |
|
1511 return NS_OK; |
|
1512 } |
|
1513 |
|
1514 // Perform the load... |
|
1515 |
|
1516 // We need an owner (a referring principal). |
|
1517 // |
|
1518 // If ownerIsExplicit is not set there are 4 possibilities: |
|
1519 // (1) If the system principal or an expanded principal was passed |
|
1520 // in and we're a typeContent docshell, inherit the principal |
|
1521 // from the current document instead. |
|
1522 // (2) In all other cases when the principal passed in is not null, |
|
1523 // use that principal. |
|
1524 // (3) If the caller has allowed inheriting from the current document, |
|
1525 // or if we're being called from system code (eg chrome JS or pure |
|
1526 // C++) then inheritOwner should be true and InternalLoad will get |
|
1527 // an owner from the current document. If none of these things are |
|
1528 // true, then |
|
1529 // (4) we pass a null owner into the channel, and an owner will be |
|
1530 // created later from the channel's internal data. |
|
1531 // |
|
1532 // If ownerIsExplicit *is* set, there are 4 possibilities |
|
1533 // (1) If the system principal or an expanded principal was passed in |
|
1534 // and we're a typeContent docshell, return an error. |
|
1535 // (2) In all other cases when the principal passed in is not null, |
|
1536 // use that principal. |
|
1537 // (3) If the caller has allowed inheriting from the current document, |
|
1538 // then inheritOwner should be true and InternalLoad will get an owner |
|
1539 // from the current document. If none of these things are true, then |
|
1540 // (4) we pass a null owner into the channel, and an owner will be |
|
1541 // created later from the channel's internal data. |
|
1542 // |
|
1543 // NOTE: This all only works because the only thing the owner is used |
|
1544 // for in InternalLoad is data:, javascript:, and about:blank |
|
1545 // URIs. For other URIs this would all be dead wrong! |
|
1546 |
|
1547 if (owner && mItemType != typeChrome) { |
|
1548 nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner); |
|
1549 if (nsContentUtils::IsSystemOrExpandedPrincipal(ownerPrincipal)) { |
|
1550 if (ownerIsExplicit) { |
|
1551 return NS_ERROR_DOM_SECURITY_ERR; |
|
1552 } |
|
1553 owner = nullptr; |
|
1554 inheritOwner = true; |
|
1555 } |
|
1556 } |
|
1557 if (!owner && !inheritOwner && !ownerIsExplicit) { |
|
1558 // See if there's system or chrome JS code running |
|
1559 inheritOwner = nsContentUtils::IsSystemPrincipal( |
|
1560 nsContentUtils::GetSubjectPrincipal()); |
|
1561 } |
|
1562 |
|
1563 if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) { |
|
1564 inheritOwner = false; |
|
1565 owner = do_CreateInstance("@mozilla.org/nullprincipal;1"); |
|
1566 } |
|
1567 |
|
1568 uint32_t flags = 0; |
|
1569 |
|
1570 if (inheritOwner) |
|
1571 flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER; |
|
1572 |
|
1573 if (!sendReferrer) |
|
1574 flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER; |
|
1575 |
|
1576 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) |
|
1577 flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; |
|
1578 |
|
1579 if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) |
|
1580 flags |= INTERNAL_LOAD_FLAGS_FIXUP_SCHEME_TYPOS; |
|
1581 |
|
1582 if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) |
|
1583 flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; |
|
1584 |
|
1585 if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) |
|
1586 flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER; |
|
1587 |
|
1588 if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) |
|
1589 flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES; |
|
1590 |
|
1591 if (isSrcdoc) |
|
1592 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; |
|
1593 |
|
1594 return InternalLoad(aURI, |
|
1595 referrer, |
|
1596 owner, |
|
1597 flags, |
|
1598 target.get(), |
|
1599 nullptr, // No type hint |
|
1600 NullString(), // No forced download |
|
1601 postStream, |
|
1602 headersStream, |
|
1603 loadType, |
|
1604 nullptr, // No SHEntry |
|
1605 aFirstParty, |
|
1606 srcdoc, |
|
1607 sourceDocShell, |
|
1608 baseURI, |
|
1609 nullptr, // No nsIDocShell |
|
1610 nullptr); // No nsIRequest |
|
1611 } |
|
1612 |
|
1613 NS_IMETHODIMP |
|
1614 nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI, |
|
1615 const nsACString &aContentType, |
|
1616 const nsACString &aContentCharset, |
|
1617 nsIDocShellLoadInfo * aLoadInfo) |
|
1618 { |
|
1619 NS_ENSURE_ARG(aStream); |
|
1620 |
|
1621 mAllowKeywordFixup = false; |
|
1622 |
|
1623 // if the caller doesn't pass in a URI we need to create a dummy URI. necko |
|
1624 // currently requires a URI in various places during the load. Some consumers |
|
1625 // do as well. |
|
1626 nsCOMPtr<nsIURI> uri = aURI; |
|
1627 if (!uri) { |
|
1628 // HACK ALERT |
|
1629 nsresult rv = NS_OK; |
|
1630 uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv); |
|
1631 if (NS_FAILED(rv)) |
|
1632 return rv; |
|
1633 // Make sure that the URI spec "looks" like a protocol and path... |
|
1634 // For now, just use a bogus protocol called "internal" |
|
1635 rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream")); |
|
1636 if (NS_FAILED(rv)) |
|
1637 return rv; |
|
1638 } |
|
1639 |
|
1640 uint32_t loadType = LOAD_NORMAL; |
|
1641 if (aLoadInfo) { |
|
1642 nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal; |
|
1643 (void) aLoadInfo->GetLoadType(<); |
|
1644 // Get the appropriate LoadType from nsIDocShellLoadInfo type |
|
1645 loadType = ConvertDocShellLoadInfoToLoadType(lt); |
|
1646 } |
|
1647 |
|
1648 NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE); |
|
1649 |
|
1650 mLoadType = loadType; |
|
1651 |
|
1652 // build up a channel for this stream. |
|
1653 nsCOMPtr<nsIChannel> channel; |
|
1654 NS_ENSURE_SUCCESS(NS_NewInputStreamChannel |
|
1655 (getter_AddRefs(channel), uri, aStream, |
|
1656 aContentType, aContentCharset), |
|
1657 NS_ERROR_FAILURE); |
|
1658 |
|
1659 nsCOMPtr<nsIURILoader> |
|
1660 uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID)); |
|
1661 NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE); |
|
1662 |
|
1663 NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false), |
|
1664 NS_ERROR_FAILURE); |
|
1665 return NS_OK; |
|
1666 } |
|
1667 |
|
1668 NS_IMETHODIMP |
|
1669 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo ** aLoadInfo) |
|
1670 { |
|
1671 nsDocShellLoadInfo *loadInfo = new nsDocShellLoadInfo(); |
|
1672 NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY); |
|
1673 nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo); |
|
1674 |
|
1675 *aLoadInfo = localRef; |
|
1676 NS_ADDREF(*aLoadInfo); |
|
1677 return NS_OK; |
|
1678 } |
|
1679 |
|
1680 |
|
1681 /* |
|
1682 * Reset state to a new content model within the current document and the document |
|
1683 * viewer. Called by the document before initiating an out of band document.write(). |
|
1684 */ |
|
1685 NS_IMETHODIMP |
|
1686 nsDocShell::PrepareForNewContentModel() |
|
1687 { |
|
1688 mEODForCurrentDocument = false; |
|
1689 return NS_OK; |
|
1690 } |
|
1691 |
|
1692 |
|
1693 NS_IMETHODIMP |
|
1694 nsDocShell::FirePageHideNotification(bool aIsUnload) |
|
1695 { |
|
1696 if (mContentViewer && !mFiredUnloadEvent) { |
|
1697 // Keep an explicit reference since calling PageHide could release |
|
1698 // mContentViewer |
|
1699 nsCOMPtr<nsIContentViewer> kungFuDeathGrip(mContentViewer); |
|
1700 mFiredUnloadEvent = true; |
|
1701 |
|
1702 if (mTiming) { |
|
1703 mTiming->NotifyUnloadEventStart(); |
|
1704 } |
|
1705 |
|
1706 mContentViewer->PageHide(aIsUnload); |
|
1707 |
|
1708 if (mTiming) { |
|
1709 mTiming->NotifyUnloadEventEnd(); |
|
1710 } |
|
1711 |
|
1712 nsAutoTArray<nsCOMPtr<nsIDocShell>, 8> kids; |
|
1713 uint32_t n = mChildList.Length(); |
|
1714 kids.SetCapacity(n); |
|
1715 for (uint32_t i = 0; i < n; i++) { |
|
1716 kids.AppendElement(do_QueryInterface(ChildAt(i))); |
|
1717 } |
|
1718 |
|
1719 n = kids.Length(); |
|
1720 for (uint32_t i = 0; i < n; ++i) { |
|
1721 if (kids[i]) { |
|
1722 kids[i]->FirePageHideNotification(aIsUnload); |
|
1723 } |
|
1724 } |
|
1725 // Now make sure our editor, if any, is detached before we go |
|
1726 // any farther. |
|
1727 DetachEditorFromWindow(); |
|
1728 } |
|
1729 |
|
1730 return NS_OK; |
|
1731 } |
|
1732 |
|
1733 void |
|
1734 nsDocShell::MaybeInitTiming() |
|
1735 { |
|
1736 if (mTiming) { |
|
1737 return; |
|
1738 } |
|
1739 |
|
1740 mTiming = new nsDOMNavigationTiming(); |
|
1741 mTiming->NotifyNavigationStart(); |
|
1742 } |
|
1743 |
|
1744 |
|
1745 // |
|
1746 // Bug 13871: Prevent frameset spoofing |
|
1747 // |
|
1748 // This routine answers: 'Is origin's document from same domain as |
|
1749 // target's document?' |
|
1750 // |
|
1751 // file: uris are considered the same domain for the purpose of |
|
1752 // frame navigation regardless of script accessibility (bug 420425) |
|
1753 // |
|
1754 /* static */ |
|
1755 bool |
|
1756 nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem, |
|
1757 nsIDocShellTreeItem* aTargetTreeItem) |
|
1758 { |
|
1759 // We want to bypass this check for chrome callers, but only if there's |
|
1760 // JS on the stack. System callers still need to do it. |
|
1761 if (nsContentUtils::GetCurrentJSContext() && nsContentUtils::IsCallerChrome()) { |
|
1762 return true; |
|
1763 } |
|
1764 |
|
1765 // Get origin document principal |
|
1766 nsCOMPtr<nsIDocument> originDocument(do_GetInterface(aOriginTreeItem)); |
|
1767 NS_ENSURE_TRUE(originDocument, false); |
|
1768 |
|
1769 // Get target principal |
|
1770 nsCOMPtr<nsIDocument> targetDocument(do_GetInterface(aTargetTreeItem)); |
|
1771 NS_ENSURE_TRUE(targetDocument, false); |
|
1772 |
|
1773 bool equal; |
|
1774 nsresult rv = originDocument->NodePrincipal()->Equals(targetDocument->NodePrincipal(), |
|
1775 &equal); |
|
1776 if (NS_SUCCEEDED(rv) && equal) { |
|
1777 return true; |
|
1778 } |
|
1779 |
|
1780 // Not strictly equal, special case if both are file: uris |
|
1781 bool originIsFile = false; |
|
1782 bool targetIsFile = false; |
|
1783 nsCOMPtr<nsIURI> originURI; |
|
1784 nsCOMPtr<nsIURI> targetURI; |
|
1785 nsCOMPtr<nsIURI> innerOriginURI; |
|
1786 nsCOMPtr<nsIURI> innerTargetURI; |
|
1787 |
|
1788 rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI)); |
|
1789 if (NS_SUCCEEDED(rv) && originURI) |
|
1790 innerOriginURI = NS_GetInnermostURI(originURI); |
|
1791 |
|
1792 rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI)); |
|
1793 if (NS_SUCCEEDED(rv) && targetURI) |
|
1794 innerTargetURI = NS_GetInnermostURI(targetURI); |
|
1795 |
|
1796 return innerOriginURI && innerTargetURI && |
|
1797 NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) && |
|
1798 NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) && |
|
1799 originIsFile && targetIsFile; |
|
1800 } |
|
1801 |
|
1802 NS_IMETHODIMP |
|
1803 nsDocShell::GetEldestPresContext(nsPresContext** aPresContext) |
|
1804 { |
|
1805 NS_ENSURE_ARG_POINTER(aPresContext); |
|
1806 *aPresContext = nullptr; |
|
1807 |
|
1808 nsCOMPtr<nsIContentViewer> viewer = mContentViewer; |
|
1809 while (viewer) { |
|
1810 nsCOMPtr<nsIContentViewer> prevViewer; |
|
1811 viewer->GetPreviousViewer(getter_AddRefs(prevViewer)); |
|
1812 if (!prevViewer) { |
|
1813 return viewer->GetPresContext(aPresContext); |
|
1814 } |
|
1815 viewer = prevViewer; |
|
1816 } |
|
1817 |
|
1818 return NS_OK; |
|
1819 } |
|
1820 |
|
1821 NS_IMETHODIMP |
|
1822 nsDocShell::GetPresContext(nsPresContext ** aPresContext) |
|
1823 { |
|
1824 NS_ENSURE_ARG_POINTER(aPresContext); |
|
1825 *aPresContext = nullptr; |
|
1826 |
|
1827 if (!mContentViewer) |
|
1828 return NS_OK; |
|
1829 |
|
1830 return mContentViewer->GetPresContext(aPresContext); |
|
1831 } |
|
1832 |
|
1833 NS_IMETHODIMP_(nsIPresShell*) |
|
1834 nsDocShell::GetPresShell() |
|
1835 { |
|
1836 nsRefPtr<nsPresContext> presContext; |
|
1837 (void) GetPresContext(getter_AddRefs(presContext)); |
|
1838 return presContext ? presContext->GetPresShell() : nullptr; |
|
1839 } |
|
1840 |
|
1841 NS_IMETHODIMP |
|
1842 nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell) |
|
1843 { |
|
1844 nsresult rv = NS_OK; |
|
1845 |
|
1846 NS_ENSURE_ARG_POINTER(aPresShell); |
|
1847 *aPresShell = nullptr; |
|
1848 |
|
1849 nsRefPtr<nsPresContext> presContext; |
|
1850 (void) GetEldestPresContext(getter_AddRefs(presContext)); |
|
1851 |
|
1852 if (presContext) { |
|
1853 NS_IF_ADDREF(*aPresShell = presContext->GetPresShell()); |
|
1854 } |
|
1855 |
|
1856 return rv; |
|
1857 } |
|
1858 |
|
1859 NS_IMETHODIMP |
|
1860 nsDocShell::GetContentViewer(nsIContentViewer ** aContentViewer) |
|
1861 { |
|
1862 NS_ENSURE_ARG_POINTER(aContentViewer); |
|
1863 |
|
1864 *aContentViewer = mContentViewer; |
|
1865 NS_IF_ADDREF(*aContentViewer); |
|
1866 return NS_OK; |
|
1867 } |
|
1868 |
|
1869 NS_IMETHODIMP |
|
1870 nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler) |
|
1871 { |
|
1872 // Weak reference. Don't addref. |
|
1873 nsCOMPtr<EventTarget> handler = do_QueryInterface(aChromeEventHandler); |
|
1874 mChromeEventHandler = handler.get(); |
|
1875 |
|
1876 if (mScriptGlobal) { |
|
1877 mScriptGlobal->SetChromeEventHandler(mChromeEventHandler); |
|
1878 } |
|
1879 |
|
1880 return NS_OK; |
|
1881 } |
|
1882 |
|
1883 NS_IMETHODIMP |
|
1884 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler) |
|
1885 { |
|
1886 NS_ENSURE_ARG_POINTER(aChromeEventHandler); |
|
1887 nsCOMPtr<EventTarget> handler = mChromeEventHandler; |
|
1888 handler.forget(aChromeEventHandler); |
|
1889 return NS_OK; |
|
1890 } |
|
1891 |
|
1892 /* void setCurrentURI (in nsIURI uri); */ |
|
1893 NS_IMETHODIMP |
|
1894 nsDocShell::SetCurrentURI(nsIURI *aURI) |
|
1895 { |
|
1896 // Note that securityUI will set STATE_IS_INSECURE, even if |
|
1897 // the scheme of |aURI| is "https". |
|
1898 SetCurrentURI(aURI, nullptr, true, 0); |
|
1899 return NS_OK; |
|
1900 } |
|
1901 |
|
1902 bool |
|
1903 nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest, |
|
1904 bool aFireOnLocationChange, uint32_t aLocationFlags) |
|
1905 { |
|
1906 #ifdef PR_LOGGING |
|
1907 if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) { |
|
1908 nsAutoCString spec; |
|
1909 if (aURI) |
|
1910 aURI->GetSpec(spec); |
|
1911 PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get()); |
|
1912 } |
|
1913 #endif |
|
1914 |
|
1915 // We don't want to send a location change when we're displaying an error |
|
1916 // page, and we don't want to change our idea of "current URI" either |
|
1917 if (mLoadType == LOAD_ERROR_PAGE) { |
|
1918 return false; |
|
1919 } |
|
1920 |
|
1921 mCurrentURI = NS_TryToMakeImmutable(aURI); |
|
1922 |
|
1923 bool isRoot = false; // Is this the root docshell |
|
1924 bool isSubFrame = false; // Is this a subframe navigation? |
|
1925 |
|
1926 nsCOMPtr<nsIDocShellTreeItem> root; |
|
1927 |
|
1928 GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
1929 if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) |
|
1930 { |
|
1931 // This is the root docshell |
|
1932 isRoot = true; |
|
1933 } |
|
1934 if (mLSHE) { |
|
1935 mLSHE->GetIsSubFrame(&isSubFrame); |
|
1936 } |
|
1937 |
|
1938 if (!isSubFrame && !isRoot) { |
|
1939 /* |
|
1940 * We don't want to send OnLocationChange notifications when |
|
1941 * a subframe is being loaded for the first time, while |
|
1942 * visiting a frameset page |
|
1943 */ |
|
1944 return false; |
|
1945 } |
|
1946 |
|
1947 if (aFireOnLocationChange) { |
|
1948 FireOnLocationChange(this, aRequest, aURI, aLocationFlags); |
|
1949 } |
|
1950 return !aFireOnLocationChange; |
|
1951 } |
|
1952 |
|
1953 NS_IMETHODIMP |
|
1954 nsDocShell::GetCharset(nsACString& aCharset) |
|
1955 { |
|
1956 aCharset.Truncate(); |
|
1957 |
|
1958 nsIPresShell* presShell = GetPresShell(); |
|
1959 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); |
|
1960 nsIDocument *doc = presShell->GetDocument(); |
|
1961 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
|
1962 aCharset = doc->GetDocumentCharacterSet(); |
|
1963 return NS_OK; |
|
1964 } |
|
1965 |
|
1966 NS_IMETHODIMP |
|
1967 nsDocShell::GatherCharsetMenuTelemetry() |
|
1968 { |
|
1969 nsCOMPtr<nsIContentViewer> viewer; |
|
1970 GetContentViewer(getter_AddRefs(viewer)); |
|
1971 if (!viewer) { |
|
1972 return NS_OK; |
|
1973 } |
|
1974 |
|
1975 nsIDocument* doc = viewer->GetDocument(); |
|
1976 if (!doc || doc->WillIgnoreCharsetOverride()) { |
|
1977 return NS_OK; |
|
1978 } |
|
1979 |
|
1980 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true); |
|
1981 |
|
1982 bool isFileURL = false; |
|
1983 nsIURI* url = doc->GetOriginalURI(); |
|
1984 if (url) { |
|
1985 url->SchemeIs("file", &isFileURL); |
|
1986 } |
|
1987 |
|
1988 int32_t charsetSource = doc->GetDocumentCharacterSetSource(); |
|
1989 switch (charsetSource) { |
|
1990 case kCharsetFromTopLevelDomain: |
|
1991 // Unlabeled doc on a domain that we map to a fallback encoding |
|
1992 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 7); |
|
1993 break; |
|
1994 case kCharsetFromFallback: |
|
1995 case kCharsetFromDocTypeDefault: |
|
1996 case kCharsetFromCache: |
|
1997 case kCharsetFromParentFrame: |
|
1998 case kCharsetFromHintPrevDoc: |
|
1999 // Changing charset on an unlabeled doc. |
|
2000 if (isFileURL) { |
|
2001 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0); |
|
2002 } else { |
|
2003 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1); |
|
2004 } |
|
2005 break; |
|
2006 case kCharsetFromAutoDetection: |
|
2007 // Changing charset on unlabeled doc where chardet fired |
|
2008 if (isFileURL) { |
|
2009 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2); |
|
2010 } else { |
|
2011 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3); |
|
2012 } |
|
2013 break; |
|
2014 case kCharsetFromMetaPrescan: |
|
2015 case kCharsetFromMetaTag: |
|
2016 case kCharsetFromChannel: |
|
2017 // Changing charset on a doc that had a charset label. |
|
2018 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4); |
|
2019 break; |
|
2020 case kCharsetFromParentForced: |
|
2021 case kCharsetFromUserForced: |
|
2022 // Changing charset on a document that already had an override. |
|
2023 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5); |
|
2024 break; |
|
2025 case kCharsetFromIrreversibleAutoDetection: |
|
2026 case kCharsetFromOtherComponent: |
|
2027 case kCharsetFromByteOrderMark: |
|
2028 case kCharsetUninitialized: |
|
2029 default: |
|
2030 // Bug. This isn't supposed to happen. |
|
2031 Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6); |
|
2032 break; |
|
2033 } |
|
2034 return NS_OK; |
|
2035 } |
|
2036 |
|
2037 NS_IMETHODIMP |
|
2038 nsDocShell::SetCharset(const nsACString& aCharset) |
|
2039 { |
|
2040 // set the charset override |
|
2041 return SetForcedCharset(aCharset); |
|
2042 } |
|
2043 |
|
2044 NS_IMETHODIMP nsDocShell::SetForcedCharset(const nsACString& aCharset) |
|
2045 { |
|
2046 if (aCharset.IsEmpty()) { |
|
2047 mForcedCharset.Truncate(); |
|
2048 return NS_OK; |
|
2049 } |
|
2050 nsAutoCString encoding; |
|
2051 if (!EncodingUtils::FindEncodingForLabel(aCharset, encoding)) { |
|
2052 // Reject unknown labels |
|
2053 return NS_ERROR_INVALID_ARG; |
|
2054 } |
|
2055 if (!EncodingUtils::IsAsciiCompatible(encoding)) { |
|
2056 // Reject XSS hazards |
|
2057 return NS_ERROR_INVALID_ARG; |
|
2058 } |
|
2059 mForcedCharset = encoding; |
|
2060 return NS_OK; |
|
2061 } |
|
2062 |
|
2063 NS_IMETHODIMP nsDocShell::GetForcedCharset(nsACString& aResult) |
|
2064 { |
|
2065 aResult = mForcedCharset; |
|
2066 return NS_OK; |
|
2067 } |
|
2068 |
|
2069 void |
|
2070 nsDocShell::SetParentCharset(const nsACString& aCharset, |
|
2071 int32_t aCharsetSource, |
|
2072 nsIPrincipal* aPrincipal) |
|
2073 { |
|
2074 mParentCharset = aCharset; |
|
2075 mParentCharsetSource = aCharsetSource; |
|
2076 mParentCharsetPrincipal = aPrincipal; |
|
2077 } |
|
2078 |
|
2079 void |
|
2080 nsDocShell::GetParentCharset(nsACString& aCharset, |
|
2081 int32_t* aCharsetSource, |
|
2082 nsIPrincipal** aPrincipal) |
|
2083 { |
|
2084 aCharset = mParentCharset; |
|
2085 *aCharsetSource = mParentCharsetSource; |
|
2086 NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal); |
|
2087 } |
|
2088 |
|
2089 NS_IMETHODIMP |
|
2090 nsDocShell::GetChannelIsUnsafe(bool *aUnsafe) |
|
2091 { |
|
2092 *aUnsafe = false; |
|
2093 |
|
2094 nsIChannel* channel = GetCurrentDocChannel(); |
|
2095 if (!channel) { |
|
2096 return NS_OK; |
|
2097 } |
|
2098 |
|
2099 nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel); |
|
2100 if (!jarChannel) { |
|
2101 return NS_OK; |
|
2102 } |
|
2103 |
|
2104 return jarChannel->GetIsUnsafe(aUnsafe); |
|
2105 } |
|
2106 |
|
2107 NS_IMETHODIMP |
|
2108 nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded) |
|
2109 { |
|
2110 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
2111 *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded(); |
|
2112 return NS_OK; |
|
2113 } |
|
2114 |
|
2115 NS_IMETHODIMP |
|
2116 nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked) |
|
2117 { |
|
2118 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
2119 *aHasMixedActiveContentBlocked = doc && doc->GetHasMixedActiveContentBlocked(); |
|
2120 return NS_OK; |
|
2121 } |
|
2122 |
|
2123 NS_IMETHODIMP |
|
2124 nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded) |
|
2125 { |
|
2126 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
2127 *aHasMixedDisplayContentLoaded = doc && doc->GetHasMixedDisplayContentLoaded(); |
|
2128 return NS_OK; |
|
2129 } |
|
2130 |
|
2131 NS_IMETHODIMP |
|
2132 nsDocShell::GetHasMixedDisplayContentBlocked(bool* aHasMixedDisplayContentBlocked) |
|
2133 { |
|
2134 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
2135 *aHasMixedDisplayContentBlocked = doc && doc->GetHasMixedDisplayContentBlocked(); |
|
2136 return NS_OK; |
|
2137 } |
|
2138 |
|
2139 NS_IMETHODIMP |
|
2140 nsDocShell::GetAllowPlugins(bool * aAllowPlugins) |
|
2141 { |
|
2142 NS_ENSURE_ARG_POINTER(aAllowPlugins); |
|
2143 |
|
2144 *aAllowPlugins = mAllowPlugins; |
|
2145 if (!mAllowPlugins) { |
|
2146 return NS_OK; |
|
2147 } |
|
2148 |
|
2149 bool unsafe; |
|
2150 *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe; |
|
2151 return NS_OK; |
|
2152 } |
|
2153 |
|
2154 NS_IMETHODIMP |
|
2155 nsDocShell::SetAllowPlugins(bool aAllowPlugins) |
|
2156 { |
|
2157 mAllowPlugins = aAllowPlugins; |
|
2158 //XXX should enable or disable a plugin host |
|
2159 return NS_OK; |
|
2160 } |
|
2161 |
|
2162 NS_IMETHODIMP |
|
2163 nsDocShell::GetAllowJavascript(bool * aAllowJavascript) |
|
2164 { |
|
2165 NS_ENSURE_ARG_POINTER(aAllowJavascript); |
|
2166 |
|
2167 *aAllowJavascript = mAllowJavascript; |
|
2168 return NS_OK; |
|
2169 } |
|
2170 |
|
2171 NS_IMETHODIMP |
|
2172 nsDocShell::SetAllowJavascript(bool aAllowJavascript) |
|
2173 { |
|
2174 mAllowJavascript = aAllowJavascript; |
|
2175 RecomputeCanExecuteScripts(); |
|
2176 return NS_OK; |
|
2177 } |
|
2178 |
|
2179 NS_IMETHODIMP |
|
2180 nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) |
|
2181 { |
|
2182 NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing); |
|
2183 |
|
2184 *aUsePrivateBrowsing = mInPrivateBrowsing; |
|
2185 return NS_OK; |
|
2186 } |
|
2187 |
|
2188 NS_IMETHODIMP |
|
2189 nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) |
|
2190 { |
|
2191 nsContentUtils::ReportToConsoleNonLocalized( |
|
2192 NS_LITERAL_STRING("Only internal code is allowed to set the usePrivateBrowsing attribute"), |
|
2193 nsIScriptError::warningFlag, |
|
2194 NS_LITERAL_CSTRING("Internal API Used"), |
|
2195 mContentViewer ? mContentViewer->GetDocument() : nullptr); |
|
2196 |
|
2197 return SetPrivateBrowsing(aUsePrivateBrowsing); |
|
2198 } |
|
2199 |
|
2200 NS_IMETHODIMP |
|
2201 nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing) |
|
2202 { |
|
2203 bool changed = aUsePrivateBrowsing != mInPrivateBrowsing; |
|
2204 if (changed) { |
|
2205 mInPrivateBrowsing = aUsePrivateBrowsing; |
|
2206 if (mAffectPrivateSessionLifetime) { |
|
2207 if (aUsePrivateBrowsing) { |
|
2208 IncreasePrivateDocShellCount(); |
|
2209 } else { |
|
2210 DecreasePrivateDocShellCount(); |
|
2211 } |
|
2212 } |
|
2213 } |
|
2214 |
|
2215 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
2216 while (iter.HasMore()) { |
|
2217 nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext()); |
|
2218 if (shell) { |
|
2219 shell->SetPrivateBrowsing(aUsePrivateBrowsing); |
|
2220 } |
|
2221 } |
|
2222 |
|
2223 if (changed) { |
|
2224 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers); |
|
2225 while (iter.HasMore()) { |
|
2226 nsWeakPtr ref = iter.GetNext(); |
|
2227 nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref); |
|
2228 if (!obs) { |
|
2229 mPrivacyObservers.RemoveElement(ref); |
|
2230 } else { |
|
2231 obs->PrivateModeChanged(aUsePrivateBrowsing); |
|
2232 } |
|
2233 } |
|
2234 } |
|
2235 return NS_OK; |
|
2236 } |
|
2237 |
|
2238 NS_IMETHODIMP |
|
2239 nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs) |
|
2240 { |
|
2241 NS_ENSURE_ARG_POINTER(aUseRemoteTabs); |
|
2242 |
|
2243 *aUseRemoteTabs = mUseRemoteTabs; |
|
2244 return NS_OK; |
|
2245 } |
|
2246 |
|
2247 NS_IMETHODIMP |
|
2248 nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) |
|
2249 { |
|
2250 #ifdef MOZ_CRASHREPORTER |
|
2251 if (aUseRemoteTabs) { |
|
2252 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"), |
|
2253 NS_LITERAL_CSTRING("1")); |
|
2254 } |
|
2255 #endif |
|
2256 |
|
2257 mUseRemoteTabs = aUseRemoteTabs; |
|
2258 return NS_OK; |
|
2259 } |
|
2260 |
|
2261 NS_IMETHODIMP |
|
2262 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime) |
|
2263 { |
|
2264 bool change = aAffectLifetime != mAffectPrivateSessionLifetime; |
|
2265 if (change && mInPrivateBrowsing) { |
|
2266 if (aAffectLifetime) { |
|
2267 IncreasePrivateDocShellCount(); |
|
2268 } else { |
|
2269 DecreasePrivateDocShellCount(); |
|
2270 } |
|
2271 } |
|
2272 mAffectPrivateSessionLifetime = aAffectLifetime; |
|
2273 |
|
2274 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
2275 while (iter.HasMore()) { |
|
2276 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
|
2277 if (shell) { |
|
2278 shell->SetAffectPrivateSessionLifetime(aAffectLifetime); |
|
2279 } |
|
2280 } |
|
2281 return NS_OK; |
|
2282 } |
|
2283 |
|
2284 NS_IMETHODIMP |
|
2285 nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime) |
|
2286 { |
|
2287 *aAffectLifetime = mAffectPrivateSessionLifetime; |
|
2288 return NS_OK; |
|
2289 } |
|
2290 |
|
2291 NS_IMETHODIMP |
|
2292 nsDocShell::AddWeakPrivacyTransitionObserver(nsIPrivacyTransitionObserver* aObserver) |
|
2293 { |
|
2294 nsWeakPtr weakObs = do_GetWeakReference(aObserver); |
|
2295 if (!weakObs) { |
|
2296 return NS_ERROR_NOT_AVAILABLE; |
|
2297 } |
|
2298 return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; |
|
2299 } |
|
2300 |
|
2301 NS_IMETHODIMP |
|
2302 nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver) |
|
2303 { |
|
2304 nsWeakPtr weakObs = do_GetWeakReference(aObserver); |
|
2305 if (!weakObs) { |
|
2306 return NS_ERROR_FAILURE; |
|
2307 } |
|
2308 return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; |
|
2309 } |
|
2310 |
|
2311 NS_IMETHODIMP |
|
2312 nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver) |
|
2313 { |
|
2314 nsWeakPtr obs = do_GetWeakReference(aObserver); |
|
2315 return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE; |
|
2316 } |
|
2317 |
|
2318 NS_IMETHODIMP |
|
2319 nsDocShell::NotifyReflowObservers(bool aInterruptible, |
|
2320 DOMHighResTimeStamp aStart, |
|
2321 DOMHighResTimeStamp aEnd) |
|
2322 { |
|
2323 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers); |
|
2324 while (iter.HasMore()) { |
|
2325 nsWeakPtr ref = iter.GetNext(); |
|
2326 nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref); |
|
2327 if (!obs) { |
|
2328 mReflowObservers.RemoveElement(ref); |
|
2329 } else if (aInterruptible) { |
|
2330 obs->ReflowInterruptible(aStart, aEnd); |
|
2331 } else { |
|
2332 obs->Reflow(aStart, aEnd); |
|
2333 } |
|
2334 } |
|
2335 return NS_OK; |
|
2336 } |
|
2337 |
|
2338 NS_IMETHODIMP nsDocShell::GetAllowMetaRedirects(bool * aReturn) |
|
2339 { |
|
2340 NS_ENSURE_ARG_POINTER(aReturn); |
|
2341 |
|
2342 *aReturn = mAllowMetaRedirects; |
|
2343 if (!mAllowMetaRedirects) { |
|
2344 return NS_OK; |
|
2345 } |
|
2346 |
|
2347 bool unsafe; |
|
2348 *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe; |
|
2349 return NS_OK; |
|
2350 } |
|
2351 |
|
2352 NS_IMETHODIMP nsDocShell::SetAllowMetaRedirects(bool aValue) |
|
2353 { |
|
2354 mAllowMetaRedirects = aValue; |
|
2355 return NS_OK; |
|
2356 } |
|
2357 |
|
2358 NS_IMETHODIMP nsDocShell::GetAllowSubframes(bool * aAllowSubframes) |
|
2359 { |
|
2360 NS_ENSURE_ARG_POINTER(aAllowSubframes); |
|
2361 |
|
2362 *aAllowSubframes = mAllowSubframes; |
|
2363 return NS_OK; |
|
2364 } |
|
2365 |
|
2366 NS_IMETHODIMP nsDocShell::SetAllowSubframes(bool aAllowSubframes) |
|
2367 { |
|
2368 mAllowSubframes = aAllowSubframes; |
|
2369 return NS_OK; |
|
2370 } |
|
2371 |
|
2372 NS_IMETHODIMP nsDocShell::GetAllowImages(bool * aAllowImages) |
|
2373 { |
|
2374 NS_ENSURE_ARG_POINTER(aAllowImages); |
|
2375 |
|
2376 *aAllowImages = mAllowImages; |
|
2377 return NS_OK; |
|
2378 } |
|
2379 |
|
2380 NS_IMETHODIMP nsDocShell::SetAllowImages(bool aAllowImages) |
|
2381 { |
|
2382 mAllowImages = aAllowImages; |
|
2383 return NS_OK; |
|
2384 } |
|
2385 |
|
2386 NS_IMETHODIMP nsDocShell::GetAllowMedia(bool * aAllowMedia) |
|
2387 { |
|
2388 *aAllowMedia = mAllowMedia; |
|
2389 return NS_OK; |
|
2390 } |
|
2391 |
|
2392 NS_IMETHODIMP nsDocShell::SetAllowMedia(bool aAllowMedia) |
|
2393 { |
|
2394 mAllowMedia = aAllowMedia; |
|
2395 |
|
2396 // Mute or unmute audio contexts attached to the inner window. |
|
2397 if (mScriptGlobal) { |
|
2398 nsPIDOMWindow* innerWin = mScriptGlobal->GetCurrentInnerWindow(); |
|
2399 if (innerWin) { |
|
2400 if (aAllowMedia) { |
|
2401 innerWin->UnmuteAudioContexts(); |
|
2402 } else { |
|
2403 innerWin->MuteAudioContexts(); |
|
2404 } |
|
2405 } |
|
2406 } |
|
2407 |
|
2408 return NS_OK; |
|
2409 } |
|
2410 |
|
2411 NS_IMETHODIMP nsDocShell::GetAllowDNSPrefetch(bool * aAllowDNSPrefetch) |
|
2412 { |
|
2413 *aAllowDNSPrefetch = mAllowDNSPrefetch; |
|
2414 return NS_OK; |
|
2415 } |
|
2416 |
|
2417 NS_IMETHODIMP nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch) |
|
2418 { |
|
2419 mAllowDNSPrefetch = aAllowDNSPrefetch; |
|
2420 return NS_OK; |
|
2421 } |
|
2422 |
|
2423 NS_IMETHODIMP nsDocShell::GetAllowWindowControl(bool * aAllowWindowControl) |
|
2424 { |
|
2425 *aAllowWindowControl = mAllowWindowControl; |
|
2426 return NS_OK; |
|
2427 } |
|
2428 |
|
2429 NS_IMETHODIMP nsDocShell::SetAllowWindowControl(bool aAllowWindowControl) |
|
2430 { |
|
2431 mAllowWindowControl = aAllowWindowControl; |
|
2432 return NS_OK; |
|
2433 } |
|
2434 |
|
2435 NS_IMETHODIMP |
|
2436 nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting) |
|
2437 { |
|
2438 *aAllowContentRetargeting = mAllowContentRetargeting; |
|
2439 return NS_OK; |
|
2440 } |
|
2441 |
|
2442 NS_IMETHODIMP |
|
2443 nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting) |
|
2444 { |
|
2445 mAllowContentRetargeting = aAllowContentRetargeting; |
|
2446 return NS_OK; |
|
2447 } |
|
2448 |
|
2449 NS_IMETHODIMP |
|
2450 nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed) |
|
2451 { |
|
2452 NS_ENSURE_ARG_POINTER(aFullscreenAllowed); |
|
2453 |
|
2454 // Browsers and apps have their mFullscreenAllowed retrieved from their |
|
2455 // corresponding iframe in their parent upon creation. |
|
2456 if (mFullscreenAllowed != CHECK_ATTRIBUTES) { |
|
2457 *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS); |
|
2458 return NS_OK; |
|
2459 } |
|
2460 |
|
2461 // Assume false until we determine otherwise... |
|
2462 *aFullscreenAllowed = false; |
|
2463 |
|
2464 // For non-browsers/apps, check that the enclosing iframe element |
|
2465 // has the allowfullscreen attribute set to true. If any ancestor |
|
2466 // iframe does not have mozallowfullscreen=true, then fullscreen is |
|
2467 // prohibited. |
|
2468 nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(GetAsSupports(this)); |
|
2469 if (!win) { |
|
2470 return NS_OK; |
|
2471 } |
|
2472 nsCOMPtr<nsIContent> frameElement = do_QueryInterface(win->GetFrameElementInternal()); |
|
2473 if (frameElement && |
|
2474 frameElement->IsHTML(nsGkAtoms::iframe) && |
|
2475 !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) && |
|
2476 !frameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) { |
|
2477 return NS_OK; |
|
2478 } |
|
2479 |
|
2480 // If we have no parent then we're the root docshell; no ancestor of the |
|
2481 // original docshell doesn't have a allowfullscreen attribute, so |
|
2482 // report fullscreen as allowed. |
|
2483 nsCOMPtr<nsIDocShellTreeItem> dsti = do_GetInterface(GetAsSupports(this)); |
|
2484 NS_ENSURE_TRUE(dsti, NS_OK); |
|
2485 |
|
2486 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem; |
|
2487 dsti->GetParent(getter_AddRefs(parentTreeItem)); |
|
2488 if (!parentTreeItem) { |
|
2489 *aFullscreenAllowed = true; |
|
2490 return NS_OK; |
|
2491 } |
|
2492 // Otherwise, we have a parent, continue the checking for |
|
2493 // mozFullscreenAllowed in the parent docshell's ancestors. |
|
2494 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem); |
|
2495 NS_ENSURE_TRUE(parent, NS_OK); |
|
2496 |
|
2497 return parent->GetFullscreenAllowed(aFullscreenAllowed); |
|
2498 } |
|
2499 |
|
2500 NS_IMETHODIMP |
|
2501 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed) |
|
2502 { |
|
2503 if (!nsIDocShell::GetIsBrowserOrApp()) { |
|
2504 // Only allow setting of fullscreenAllowed on content/process boundaries. |
|
2505 // At non-boundaries the fullscreenAllowed attribute is calculated based on |
|
2506 // whether all enclosing frames have the "mozFullscreenAllowed" attribute |
|
2507 // set to "true". fullscreenAllowed is set at the process boundaries to |
|
2508 // propagate the value of the parent's "mozFullscreenAllowed" attribute |
|
2509 // across process boundaries. |
|
2510 return NS_ERROR_UNEXPECTED; |
|
2511 } |
|
2512 mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS); |
|
2513 return NS_OK; |
|
2514 } |
|
2515 |
|
2516 NS_IMETHODIMP |
|
2517 nsDocShell::GetMayEnableCharacterEncodingMenu(bool* aMayEnableCharacterEncodingMenu) |
|
2518 { |
|
2519 *aMayEnableCharacterEncodingMenu = false; |
|
2520 if (!mContentViewer) { |
|
2521 return NS_OK; |
|
2522 } |
|
2523 nsIDocument* doc = mContentViewer->GetDocument(); |
|
2524 if (!doc) { |
|
2525 return NS_OK; |
|
2526 } |
|
2527 if (doc->WillIgnoreCharsetOverride()) { |
|
2528 return NS_OK; |
|
2529 } |
|
2530 |
|
2531 *aMayEnableCharacterEncodingMenu = true; |
|
2532 return NS_OK; |
|
2533 } |
|
2534 |
|
2535 NS_IMETHODIMP |
|
2536 nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection, nsISimpleEnumerator **outEnum) |
|
2537 { |
|
2538 NS_ENSURE_ARG_POINTER(outEnum); |
|
2539 *outEnum = nullptr; |
|
2540 |
|
2541 nsRefPtr<nsDocShellEnumerator> docShellEnum; |
|
2542 if (aDirection == ENUMERATE_FORWARDS) |
|
2543 docShellEnum = new nsDocShellForwardsEnumerator; |
|
2544 else |
|
2545 docShellEnum = new nsDocShellBackwardsEnumerator; |
|
2546 |
|
2547 if (!docShellEnum) return NS_ERROR_OUT_OF_MEMORY; |
|
2548 |
|
2549 nsresult rv = docShellEnum->SetEnumDocShellType(aItemType); |
|
2550 if (NS_FAILED(rv)) return rv; |
|
2551 |
|
2552 rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem *)this); |
|
2553 if (NS_FAILED(rv)) return rv; |
|
2554 |
|
2555 rv = docShellEnum->First(); |
|
2556 if (NS_FAILED(rv)) return rv; |
|
2557 |
|
2558 rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)outEnum); |
|
2559 |
|
2560 return rv; |
|
2561 } |
|
2562 |
|
2563 NS_IMETHODIMP |
|
2564 nsDocShell::GetAppType(uint32_t * aAppType) |
|
2565 { |
|
2566 *aAppType = mAppType; |
|
2567 return NS_OK; |
|
2568 } |
|
2569 |
|
2570 NS_IMETHODIMP |
|
2571 nsDocShell::SetAppType(uint32_t aAppType) |
|
2572 { |
|
2573 mAppType = aAppType; |
|
2574 return NS_OK; |
|
2575 } |
|
2576 |
|
2577 |
|
2578 NS_IMETHODIMP |
|
2579 nsDocShell::GetAllowAuth(bool * aAllowAuth) |
|
2580 { |
|
2581 *aAllowAuth = mAllowAuth; |
|
2582 return NS_OK; |
|
2583 } |
|
2584 |
|
2585 NS_IMETHODIMP |
|
2586 nsDocShell::SetAllowAuth(bool aAllowAuth) |
|
2587 { |
|
2588 mAllowAuth = aAllowAuth; |
|
2589 return NS_OK; |
|
2590 } |
|
2591 |
|
2592 NS_IMETHODIMP |
|
2593 nsDocShell::GetZoom(float *zoom) |
|
2594 { |
|
2595 NS_ENSURE_ARG_POINTER(zoom); |
|
2596 *zoom = 1.0f; |
|
2597 return NS_OK; |
|
2598 } |
|
2599 |
|
2600 NS_IMETHODIMP |
|
2601 nsDocShell::SetZoom(float zoom) |
|
2602 { |
|
2603 return NS_ERROR_NOT_IMPLEMENTED; |
|
2604 } |
|
2605 |
|
2606 NS_IMETHODIMP |
|
2607 nsDocShell::GetMarginWidth(int32_t * aWidth) |
|
2608 { |
|
2609 NS_ENSURE_ARG_POINTER(aWidth); |
|
2610 |
|
2611 *aWidth = mMarginWidth; |
|
2612 return NS_OK; |
|
2613 } |
|
2614 |
|
2615 NS_IMETHODIMP |
|
2616 nsDocShell::SetMarginWidth(int32_t aWidth) |
|
2617 { |
|
2618 mMarginWidth = aWidth; |
|
2619 return NS_OK; |
|
2620 } |
|
2621 |
|
2622 NS_IMETHODIMP |
|
2623 nsDocShell::GetMarginHeight(int32_t * aHeight) |
|
2624 { |
|
2625 NS_ENSURE_ARG_POINTER(aHeight); |
|
2626 |
|
2627 *aHeight = mMarginHeight; |
|
2628 return NS_OK; |
|
2629 } |
|
2630 |
|
2631 NS_IMETHODIMP |
|
2632 nsDocShell::SetMarginHeight(int32_t aHeight) |
|
2633 { |
|
2634 mMarginHeight = aHeight; |
|
2635 return NS_OK; |
|
2636 } |
|
2637 |
|
2638 NS_IMETHODIMP |
|
2639 nsDocShell::GetBusyFlags(uint32_t * aBusyFlags) |
|
2640 { |
|
2641 NS_ENSURE_ARG_POINTER(aBusyFlags); |
|
2642 |
|
2643 *aBusyFlags = mBusyFlags; |
|
2644 return NS_OK; |
|
2645 } |
|
2646 |
|
2647 NS_IMETHODIMP |
|
2648 nsDocShell::TabToTreeOwner(bool aForward, bool* aTookFocus) |
|
2649 { |
|
2650 NS_ENSURE_ARG_POINTER(aTookFocus); |
|
2651 |
|
2652 nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner); |
|
2653 if (chromeFocus) { |
|
2654 if (aForward) |
|
2655 *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement()); |
|
2656 else |
|
2657 *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement()); |
|
2658 } else |
|
2659 *aTookFocus = false; |
|
2660 |
|
2661 return NS_OK; |
|
2662 } |
|
2663 |
|
2664 NS_IMETHODIMP |
|
2665 nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI) |
|
2666 { |
|
2667 NS_IF_ADDREF(*aSecurityUI = mSecurityUI); |
|
2668 return NS_OK; |
|
2669 } |
|
2670 |
|
2671 NS_IMETHODIMP |
|
2672 nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI) |
|
2673 { |
|
2674 mSecurityUI = aSecurityUI; |
|
2675 mSecurityUI->SetDocShell(this); |
|
2676 return NS_OK; |
|
2677 } |
|
2678 |
|
2679 NS_IMETHODIMP |
|
2680 nsDocShell::GetUseErrorPages(bool *aUseErrorPages) |
|
2681 { |
|
2682 *aUseErrorPages = UseErrorPages(); |
|
2683 return NS_OK; |
|
2684 } |
|
2685 |
|
2686 NS_IMETHODIMP |
|
2687 nsDocShell::SetUseErrorPages(bool aUseErrorPages) |
|
2688 { |
|
2689 // If mUseErrorPages is set explicitly, stop using sUseErrorPages. |
|
2690 if (mObserveErrorPages) { |
|
2691 mObserveErrorPages = false; |
|
2692 } |
|
2693 mUseErrorPages = aUseErrorPages; |
|
2694 return NS_OK; |
|
2695 } |
|
2696 |
|
2697 NS_IMETHODIMP |
|
2698 nsDocShell::GetPreviousTransIndex(int32_t *aPreviousTransIndex) |
|
2699 { |
|
2700 *aPreviousTransIndex = mPreviousTransIndex; |
|
2701 return NS_OK; |
|
2702 } |
|
2703 |
|
2704 NS_IMETHODIMP |
|
2705 nsDocShell::GetLoadedTransIndex(int32_t *aLoadedTransIndex) |
|
2706 { |
|
2707 *aLoadedTransIndex = mLoadedTransIndex; |
|
2708 return NS_OK; |
|
2709 } |
|
2710 |
|
2711 NS_IMETHODIMP |
|
2712 nsDocShell::HistoryPurged(int32_t aNumEntries) |
|
2713 { |
|
2714 // These indices are used for fastback cache eviction, to determine |
|
2715 // which session history entries are candidates for content viewer |
|
2716 // eviction. We need to adjust by the number of entries that we |
|
2717 // just purged from history, so that we look at the right session history |
|
2718 // entries during eviction. |
|
2719 mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries); |
|
2720 mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries); |
|
2721 |
|
2722 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
2723 while (iter.HasMore()) { |
|
2724 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
|
2725 if (shell) { |
|
2726 shell->HistoryPurged(aNumEntries); |
|
2727 } |
|
2728 } |
|
2729 |
|
2730 return NS_OK; |
|
2731 } |
|
2732 |
|
2733 nsresult |
|
2734 nsDocShell::HistoryTransactionRemoved(int32_t aIndex) |
|
2735 { |
|
2736 // These indices are used for fastback cache eviction, to determine |
|
2737 // which session history entries are candidates for content viewer |
|
2738 // eviction. We need to adjust by the number of entries that we |
|
2739 // just purged from history, so that we look at the right session history |
|
2740 // entries during eviction. |
|
2741 if (aIndex == mPreviousTransIndex) { |
|
2742 mPreviousTransIndex = -1; |
|
2743 } else if (aIndex < mPreviousTransIndex) { |
|
2744 --mPreviousTransIndex; |
|
2745 } |
|
2746 if (mLoadedTransIndex == aIndex) { |
|
2747 mLoadedTransIndex = 0; |
|
2748 } else if (aIndex < mLoadedTransIndex) { |
|
2749 --mLoadedTransIndex; |
|
2750 } |
|
2751 |
|
2752 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
2753 while (iter.HasMore()) { |
|
2754 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
|
2755 if (shell) { |
|
2756 static_cast<nsDocShell*>(shell.get())-> |
|
2757 HistoryTransactionRemoved(aIndex); |
|
2758 } |
|
2759 } |
|
2760 |
|
2761 return NS_OK; |
|
2762 } |
|
2763 |
|
2764 nsIDOMStorageManager* |
|
2765 nsDocShell::TopSessionStorageManager() |
|
2766 { |
|
2767 nsresult rv; |
|
2768 |
|
2769 nsCOMPtr<nsIDocShellTreeItem> topItem; |
|
2770 rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem)); |
|
2771 if (NS_FAILED(rv)) { |
|
2772 return nullptr; |
|
2773 } |
|
2774 |
|
2775 if (!topItem) { |
|
2776 return nullptr; |
|
2777 } |
|
2778 |
|
2779 nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get()); |
|
2780 if (topDocShell != this) { |
|
2781 return topDocShell->TopSessionStorageManager(); |
|
2782 } |
|
2783 |
|
2784 if (!mSessionStorageManager) { |
|
2785 mSessionStorageManager = |
|
2786 do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1"); |
|
2787 } |
|
2788 |
|
2789 return mSessionStorageManager; |
|
2790 } |
|
2791 |
|
2792 NS_IMETHODIMP |
|
2793 nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal, |
|
2794 const nsAString& aDocumentURI, |
|
2795 bool aCreate, |
|
2796 nsIDOMStorage** aStorage) |
|
2797 { |
|
2798 nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager(); |
|
2799 if (!manager) { |
|
2800 return NS_ERROR_UNEXPECTED; |
|
2801 } |
|
2802 |
|
2803 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = |
|
2804 do_GetService(THIRDPARTYUTIL_CONTRACTID); |
|
2805 if (!thirdPartyUtil) |
|
2806 return NS_ERROR_FAILURE; |
|
2807 |
|
2808 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
2809 nsCOMPtr<nsIURI> firstPartyIsolationURI; |
|
2810 nsresult rv = thirdPartyUtil->GetFirstPartyIsolationURI(nullptr, doc, |
|
2811 getter_AddRefs(firstPartyIsolationURI)); |
|
2812 NS_ENSURE_SUCCESS(rv, rv); |
|
2813 |
|
2814 if (aCreate) { |
|
2815 return manager->CreateStorageForFirstParty(firstPartyIsolationURI, |
|
2816 aPrincipal, aDocumentURI, |
|
2817 mInPrivateBrowsing, aStorage); |
|
2818 } |
|
2819 |
|
2820 return manager->GetStorageForFirstParty(firstPartyIsolationURI, aPrincipal, |
|
2821 mInPrivateBrowsing, aStorage); |
|
2822 } |
|
2823 |
|
2824 // Bacause it is not called from anywhere, nsDocShell::AddSessionStorage() |
|
2825 // does not need to be modified to isolate DOM Storage to the first party URI. |
|
2826 nsresult |
|
2827 nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal, |
|
2828 nsIDOMStorage* aStorage) |
|
2829 { |
|
2830 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(aStorage); |
|
2831 nsIPrincipal* storagePrincipal = pistorage->GetPrincipal(); |
|
2832 if (storagePrincipal != aPrincipal) { |
|
2833 NS_ERROR("Wanting to add a sessionStorage for different principal"); |
|
2834 return NS_ERROR_DOM_SECURITY_ERR; |
|
2835 } |
|
2836 |
|
2837 nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager(); |
|
2838 if (!manager) { |
|
2839 return NS_ERROR_UNEXPECTED; |
|
2840 } |
|
2841 |
|
2842 return manager->CloneStorage(aStorage); |
|
2843 } |
|
2844 |
|
2845 NS_IMETHODIMP |
|
2846 nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult) |
|
2847 { |
|
2848 NS_IF_ADDREF(*aResult = GetCurrentDocChannel()); |
|
2849 return NS_OK; |
|
2850 } |
|
2851 |
|
2852 nsIChannel* |
|
2853 nsDocShell::GetCurrentDocChannel() |
|
2854 { |
|
2855 if (mContentViewer) { |
|
2856 nsIDocument* doc = mContentViewer->GetDocument(); |
|
2857 if (doc) { |
|
2858 return doc->GetChannel(); |
|
2859 } |
|
2860 } |
|
2861 return nullptr; |
|
2862 } |
|
2863 |
|
2864 NS_IMETHODIMP |
|
2865 nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver) |
|
2866 { |
|
2867 nsWeakPtr weakObs = do_GetWeakReference(aObserver); |
|
2868 if (!weakObs) { |
|
2869 return NS_ERROR_FAILURE; |
|
2870 } |
|
2871 return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE; |
|
2872 } |
|
2873 |
|
2874 NS_IMETHODIMP |
|
2875 nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver) |
|
2876 { |
|
2877 nsWeakPtr obs = do_GetWeakReference(aObserver); |
|
2878 return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE; |
|
2879 } |
|
2880 |
|
2881 NS_IMETHODIMP |
|
2882 nsDocShell::NotifyScrollObservers() |
|
2883 { |
|
2884 nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers); |
|
2885 while (iter.HasMore()) { |
|
2886 nsWeakPtr ref = iter.GetNext(); |
|
2887 nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref); |
|
2888 if (obs) { |
|
2889 obs->ScrollPositionChanged(); |
|
2890 } else { |
|
2891 mScrollObservers.RemoveElement(ref); |
|
2892 } |
|
2893 } |
|
2894 return NS_OK; |
|
2895 } |
|
2896 |
|
2897 //***************************************************************************** |
|
2898 // nsDocShell::nsIDocShellTreeItem |
|
2899 //***************************************************************************** |
|
2900 |
|
2901 NS_IMETHODIMP |
|
2902 nsDocShell::GetName(nsAString& aName) |
|
2903 { |
|
2904 aName = mName; |
|
2905 return NS_OK; |
|
2906 } |
|
2907 |
|
2908 NS_IMETHODIMP |
|
2909 nsDocShell::SetName(const nsAString& aName) |
|
2910 { |
|
2911 mName = aName; |
|
2912 return NS_OK; |
|
2913 } |
|
2914 |
|
2915 NS_IMETHODIMP |
|
2916 nsDocShell::NameEquals(const char16_t *aName, bool *_retval) |
|
2917 { |
|
2918 NS_ENSURE_ARG_POINTER(aName); |
|
2919 NS_ENSURE_ARG_POINTER(_retval); |
|
2920 *_retval = mName.Equals(aName); |
|
2921 return NS_OK; |
|
2922 } |
|
2923 |
|
2924 /* virtual */ int32_t |
|
2925 nsDocShell::ItemType() |
|
2926 { |
|
2927 return mItemType; |
|
2928 } |
|
2929 |
|
2930 NS_IMETHODIMP |
|
2931 nsDocShell::GetItemType(int32_t * aItemType) |
|
2932 { |
|
2933 NS_ENSURE_ARG_POINTER(aItemType); |
|
2934 |
|
2935 *aItemType = ItemType(); |
|
2936 return NS_OK; |
|
2937 } |
|
2938 |
|
2939 NS_IMETHODIMP |
|
2940 nsDocShell::SetItemType(int32_t aItemType) |
|
2941 { |
|
2942 NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType)); |
|
2943 |
|
2944 // Only allow setting the type on root docshells. Those would be the ones |
|
2945 // that have the docloader service as mParent or have no mParent at all. |
|
2946 nsCOMPtr<nsIDocumentLoader> docLoaderService = |
|
2947 do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); |
|
2948 NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED); |
|
2949 |
|
2950 NS_ENSURE_STATE(!mParent || mParent == docLoaderService); |
|
2951 |
|
2952 mItemType = aItemType; |
|
2953 |
|
2954 // disable auth prompting for anything but content |
|
2955 mAllowAuth = mItemType == typeContent; |
|
2956 |
|
2957 nsRefPtr<nsPresContext> presContext = nullptr; |
|
2958 GetPresContext(getter_AddRefs(presContext)); |
|
2959 if (presContext) { |
|
2960 presContext->UpdateIsChrome(); |
|
2961 } |
|
2962 |
|
2963 return NS_OK; |
|
2964 } |
|
2965 |
|
2966 NS_IMETHODIMP |
|
2967 nsDocShell::GetParent(nsIDocShellTreeItem ** aParent) |
|
2968 { |
|
2969 if (!mParent) { |
|
2970 *aParent = nullptr; |
|
2971 } else { |
|
2972 CallQueryInterface(mParent, aParent); |
|
2973 } |
|
2974 // Note that in the case when the parent is not an nsIDocShellTreeItem we |
|
2975 // don't want to throw; we just want to return null. |
|
2976 return NS_OK; |
|
2977 } |
|
2978 |
|
2979 already_AddRefed<nsDocShell> |
|
2980 nsDocShell::GetParentDocshell() |
|
2981 { |
|
2982 nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent)); |
|
2983 return docshell.forget().downcast<nsDocShell>(); |
|
2984 } |
|
2985 |
|
2986 void |
|
2987 nsDocShell::RecomputeCanExecuteScripts() |
|
2988 { |
|
2989 bool old = mCanExecuteScripts; |
|
2990 nsRefPtr<nsDocShell> parent = GetParentDocshell(); |
|
2991 |
|
2992 // If we have no tree owner, that means that we've been detached from the |
|
2993 // docshell tree (this is distinct from having no parent dochshell, which |
|
2994 // is the case for root docshells). It would be nice to simply disallow |
|
2995 // script in detached docshells, but bug 986542 demonstrates that this |
|
2996 // behavior breaks at least one website. |
|
2997 // |
|
2998 // So instead, we use our previous value, unless mAllowJavascript has been |
|
2999 // explicitly set to false. |
|
3000 if (!mTreeOwner) { |
|
3001 mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript; |
|
3002 // If scripting has been explicitly disabled on our docshell, we're done. |
|
3003 } else if (!mAllowJavascript) { |
|
3004 mCanExecuteScripts = false; |
|
3005 // If we have a parent, inherit. |
|
3006 } else if (parent) { |
|
3007 mCanExecuteScripts = parent->mCanExecuteScripts; |
|
3008 // Otherwise, we're the root of the tree, and we haven't explicitly disabled |
|
3009 // script. Allow. |
|
3010 } else { |
|
3011 mCanExecuteScripts = true; |
|
3012 } |
|
3013 |
|
3014 // Inform our active DOM window. |
|
3015 // |
|
3016 // This will pass the outer, which will be in the scope of the active inner. |
|
3017 if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) { |
|
3018 xpc::Scriptability& scriptability = |
|
3019 xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject()); |
|
3020 scriptability.SetDocShellAllowsScript(mCanExecuteScripts); |
|
3021 } |
|
3022 |
|
3023 // If our value has changed, our children might be affected. Recompute their |
|
3024 // value as well. |
|
3025 if (old != mCanExecuteScripts) { |
|
3026 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
3027 while (iter.HasMore()) { |
|
3028 static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts(); |
|
3029 } |
|
3030 } |
|
3031 } |
|
3032 |
|
3033 nsresult |
|
3034 nsDocShell::SetDocLoaderParent(nsDocLoader * aParent) |
|
3035 { |
|
3036 bool wasFrame = IsFrame(); |
|
3037 |
|
3038 nsDocLoader::SetDocLoaderParent(aParent); |
|
3039 |
|
3040 nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup); |
|
3041 if (wasFrame != IsFrame() && priorityGroup) { |
|
3042 priorityGroup->AdjustPriority(wasFrame ? -1 : 1); |
|
3043 } |
|
3044 |
|
3045 // Curse ambiguous nsISupports inheritance! |
|
3046 nsISupports* parent = GetAsSupports(aParent); |
|
3047 |
|
3048 // If parent is another docshell, we inherit all their flags for |
|
3049 // allowing plugins, scripting etc. |
|
3050 bool value; |
|
3051 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent)); |
|
3052 if (parentAsDocShell) |
|
3053 { |
|
3054 if (NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) |
|
3055 { |
|
3056 SetAllowPlugins(value); |
|
3057 } |
|
3058 if (NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) |
|
3059 { |
|
3060 SetAllowJavascript(value); |
|
3061 } |
|
3062 if (NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) |
|
3063 { |
|
3064 SetAllowMetaRedirects(value); |
|
3065 } |
|
3066 if (NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) |
|
3067 { |
|
3068 SetAllowSubframes(value); |
|
3069 } |
|
3070 if (NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) |
|
3071 { |
|
3072 SetAllowImages(value); |
|
3073 } |
|
3074 SetAllowMedia(parentAsDocShell->GetAllowMedia()); |
|
3075 if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) |
|
3076 { |
|
3077 SetAllowWindowControl(value); |
|
3078 } |
|
3079 SetAllowContentRetargeting( |
|
3080 parentAsDocShell->GetAllowContentRetargeting()); |
|
3081 if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) |
|
3082 { |
|
3083 SetIsActive(value); |
|
3084 } |
|
3085 if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) { |
|
3086 value = false; |
|
3087 } |
|
3088 SetAllowDNSPrefetch(value); |
|
3089 value = parentAsDocShell->GetAffectPrivateSessionLifetime(); |
|
3090 SetAffectPrivateSessionLifetime(value); |
|
3091 uint32_t flags; |
|
3092 if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) |
|
3093 { |
|
3094 SetDefaultLoadFlags(flags); |
|
3095 } |
|
3096 |
|
3097 } |
|
3098 |
|
3099 nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent)); |
|
3100 if (parentAsLoadContext && |
|
3101 NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) |
|
3102 { |
|
3103 SetPrivateBrowsing(value); |
|
3104 } |
|
3105 |
|
3106 nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent)); |
|
3107 if (parentURIListener) |
|
3108 mContentListener->SetParentContentListener(parentURIListener); |
|
3109 |
|
3110 // Our parent has changed. Recompute scriptability. |
|
3111 RecomputeCanExecuteScripts(); |
|
3112 |
|
3113 return NS_OK; |
|
3114 } |
|
3115 |
|
3116 NS_IMETHODIMP |
|
3117 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent) |
|
3118 { |
|
3119 NS_ENSURE_ARG_POINTER(aParent); |
|
3120 *aParent = nullptr; |
|
3121 |
|
3122 if (nsIDocShell::GetIsBrowserOrApp()) { |
|
3123 return NS_OK; |
|
3124 } |
|
3125 |
|
3126 nsCOMPtr<nsIDocShellTreeItem> parent = |
|
3127 do_QueryInterface(GetAsSupports(mParent)); |
|
3128 if (!parent) |
|
3129 return NS_OK; |
|
3130 |
|
3131 if (parent->ItemType() == mItemType) { |
|
3132 parent.swap(*aParent); |
|
3133 } |
|
3134 return NS_OK; |
|
3135 } |
|
3136 |
|
3137 NS_IMETHODIMP |
|
3138 nsDocShell::GetSameTypeParentIgnoreBrowserAndAppBoundaries(nsIDocShell** aParent) |
|
3139 { |
|
3140 NS_ENSURE_ARG_POINTER(aParent); |
|
3141 *aParent = nullptr; |
|
3142 |
|
3143 nsCOMPtr<nsIDocShellTreeItem> parent = |
|
3144 do_QueryInterface(GetAsSupports(mParent)); |
|
3145 if (!parent) |
|
3146 return NS_OK; |
|
3147 |
|
3148 if (parent->ItemType() == mItemType) { |
|
3149 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent); |
|
3150 parentDS.forget(aParent); |
|
3151 } |
|
3152 return NS_OK; |
|
3153 } |
|
3154 |
|
3155 NS_IMETHODIMP |
|
3156 nsDocShell::GetRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem) |
|
3157 { |
|
3158 NS_ENSURE_ARG_POINTER(aRootTreeItem); |
|
3159 *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this); |
|
3160 |
|
3161 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
3162 NS_ENSURE_SUCCESS(GetParent(getter_AddRefs(parent)), NS_ERROR_FAILURE); |
|
3163 while (parent) { |
|
3164 *aRootTreeItem = parent; |
|
3165 NS_ENSURE_SUCCESS((*aRootTreeItem)->GetParent(getter_AddRefs(parent)), |
|
3166 NS_ERROR_FAILURE); |
|
3167 } |
|
3168 NS_ADDREF(*aRootTreeItem); |
|
3169 return NS_OK; |
|
3170 } |
|
3171 |
|
3172 NS_IMETHODIMP |
|
3173 nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem ** aRootTreeItem) |
|
3174 { |
|
3175 NS_ENSURE_ARG_POINTER(aRootTreeItem); |
|
3176 *aRootTreeItem = static_cast<nsIDocShellTreeItem *>(this); |
|
3177 |
|
3178 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
3179 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)), |
|
3180 NS_ERROR_FAILURE); |
|
3181 while (parent) { |
|
3182 *aRootTreeItem = parent; |
|
3183 NS_ENSURE_SUCCESS((*aRootTreeItem)-> |
|
3184 GetSameTypeParent(getter_AddRefs(parent)), |
|
3185 NS_ERROR_FAILURE); |
|
3186 } |
|
3187 NS_ADDREF(*aRootTreeItem); |
|
3188 return NS_OK; |
|
3189 } |
|
3190 |
|
3191 /* static */ |
|
3192 bool |
|
3193 nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem, |
|
3194 nsIDocShellTreeItem* aAccessingItem, |
|
3195 bool aConsiderOpener) |
|
3196 { |
|
3197 NS_PRECONDITION(aTargetItem, "Must have target item!"); |
|
3198 |
|
3199 if (!gValidateOrigin || !aAccessingItem) { |
|
3200 // Good to go |
|
3201 return true; |
|
3202 } |
|
3203 |
|
3204 // XXXbz should we care if aAccessingItem or the document therein is |
|
3205 // chrome? Should those get extra privileges? |
|
3206 |
|
3207 // For historical context, see: |
|
3208 // |
|
3209 // Bug 13871: Prevent frameset spoofing |
|
3210 // Bug 103638: Targets with same name in different windows open in wrong |
|
3211 // window with javascript |
|
3212 // Bug 408052: Adopt "ancestor" frame navigation policy |
|
3213 |
|
3214 // Now do a security check. |
|
3215 // |
|
3216 // Disallow navigation if the two frames are not part of the same app, or if |
|
3217 // they have different is-in-browser-element states. |
|
3218 // |
|
3219 // Allow navigation if |
|
3220 // 1) aAccessingItem can script aTargetItem or one of its ancestors in |
|
3221 // the frame hierarchy or |
|
3222 // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant |
|
3223 // 3) aTargetItem is a top-level frame and aAccessingItem can target |
|
3224 // its opener per rule (1) or (2). |
|
3225 |
|
3226 if (aTargetItem == aAccessingItem) { |
|
3227 // A frame is allowed to navigate itself. |
|
3228 return true; |
|
3229 } |
|
3230 |
|
3231 nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem); |
|
3232 nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem); |
|
3233 if (!!targetDS != !!accessingDS) { |
|
3234 // We must be able to convert both or neither to nsIDocShell. |
|
3235 return false; |
|
3236 } |
|
3237 |
|
3238 if (targetDS && accessingDS && |
|
3239 (targetDS->GetIsInBrowserElement() != |
|
3240 accessingDS->GetIsInBrowserElement() || |
|
3241 targetDS->GetAppId() != accessingDS->GetAppId())) { |
|
3242 return false; |
|
3243 } |
|
3244 |
|
3245 nsCOMPtr<nsIDocShellTreeItem> accessingRoot; |
|
3246 aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot)); |
|
3247 |
|
3248 if (aTargetItem == accessingRoot) { |
|
3249 // A frame can navigate its root. |
|
3250 return true; |
|
3251 } |
|
3252 |
|
3253 // Check if aAccessingItem can navigate one of aTargetItem's ancestors. |
|
3254 nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem; |
|
3255 do { |
|
3256 if (ValidateOrigin(aAccessingItem, target)) { |
|
3257 return true; |
|
3258 } |
|
3259 |
|
3260 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
3261 target->GetSameTypeParent(getter_AddRefs(parent)); |
|
3262 parent.swap(target); |
|
3263 } while (target); |
|
3264 |
|
3265 nsCOMPtr<nsIDocShellTreeItem> targetRoot; |
|
3266 aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot)); |
|
3267 |
|
3268 if (aTargetItem != targetRoot) { |
|
3269 // target is a subframe, not in accessor's frame hierarchy, and all its |
|
3270 // ancestors have origins different from that of the accessor. Don't |
|
3271 // allow access. |
|
3272 return false; |
|
3273 } |
|
3274 |
|
3275 if (!aConsiderOpener) { |
|
3276 // All done here |
|
3277 return false; |
|
3278 } |
|
3279 |
|
3280 nsCOMPtr<nsIDOMWindow> targetWindow = do_GetInterface(aTargetItem); |
|
3281 if (!targetWindow) { |
|
3282 NS_ERROR("This should not happen, really"); |
|
3283 return false; |
|
3284 } |
|
3285 |
|
3286 nsCOMPtr<nsIDOMWindow> targetOpener; |
|
3287 targetWindow->GetOpener(getter_AddRefs(targetOpener)); |
|
3288 nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener)); |
|
3289 nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav)); |
|
3290 |
|
3291 if (!openerItem) { |
|
3292 return false; |
|
3293 } |
|
3294 |
|
3295 return CanAccessItem(openerItem, aAccessingItem, false); |
|
3296 } |
|
3297 |
|
3298 static bool |
|
3299 ItemIsActive(nsIDocShellTreeItem *aItem) |
|
3300 { |
|
3301 nsCOMPtr<nsIDOMWindow> window(do_GetInterface(aItem)); |
|
3302 |
|
3303 if (window) { |
|
3304 bool isClosed; |
|
3305 |
|
3306 if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) { |
|
3307 return true; |
|
3308 } |
|
3309 } |
|
3310 |
|
3311 return false; |
|
3312 } |
|
3313 |
|
3314 NS_IMETHODIMP |
|
3315 nsDocShell::FindItemWithName(const char16_t * aName, |
|
3316 nsISupports * aRequestor, |
|
3317 nsIDocShellTreeItem * aOriginalRequestor, |
|
3318 nsIDocShellTreeItem ** _retval) |
|
3319 { |
|
3320 NS_ENSURE_ARG(aName); |
|
3321 NS_ENSURE_ARG_POINTER(_retval); |
|
3322 |
|
3323 // If we don't find one, we return NS_OK and a null result |
|
3324 *_retval = nullptr; |
|
3325 |
|
3326 if (!*aName) |
|
3327 return NS_OK; |
|
3328 |
|
3329 if (aRequestor) { |
|
3330 // If aRequestor is not null we don't need to check special names, so |
|
3331 // just hand straight off to the search by actual name function. |
|
3332 return DoFindItemWithName(aName, aRequestor, aOriginalRequestor, |
|
3333 _retval); |
|
3334 } else { |
|
3335 |
|
3336 // This is the entry point into the target-finding algorithm. Check |
|
3337 // for special names. This should only be done once, hence the check |
|
3338 // for a null aRequestor. |
|
3339 |
|
3340 nsCOMPtr<nsIDocShellTreeItem> foundItem; |
|
3341 nsDependentString name(aName); |
|
3342 if (name.LowerCaseEqualsLiteral("_self")) { |
|
3343 foundItem = this; |
|
3344 } |
|
3345 else if (name.LowerCaseEqualsLiteral("_blank")) |
|
3346 { |
|
3347 // Just return null. Caller must handle creating a new window with |
|
3348 // a blank name himself. |
|
3349 return NS_OK; |
|
3350 } |
|
3351 else if (name.LowerCaseEqualsLiteral("_parent")) |
|
3352 { |
|
3353 GetSameTypeParent(getter_AddRefs(foundItem)); |
|
3354 if(!foundItem) |
|
3355 foundItem = this; |
|
3356 } |
|
3357 else if (name.LowerCaseEqualsLiteral("_top")) |
|
3358 { |
|
3359 GetSameTypeRootTreeItem(getter_AddRefs(foundItem)); |
|
3360 NS_ASSERTION(foundItem, "Must have this; worst case it's us!"); |
|
3361 } |
|
3362 // _main is an IE target which should be case-insensitive but isn't |
|
3363 // see bug 217886 for details |
|
3364 else if (name.LowerCaseEqualsLiteral("_content") || |
|
3365 name.EqualsLiteral("_main")) |
|
3366 { |
|
3367 // Must pass our same type root as requestor to the |
|
3368 // treeowner to make sure things work right. |
|
3369 nsCOMPtr<nsIDocShellTreeItem> root; |
|
3370 GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
3371 if (mTreeOwner) { |
|
3372 NS_ASSERTION(root, "Must have this; worst case it's us!"); |
|
3373 mTreeOwner->FindItemWithName(aName, root, aOriginalRequestor, |
|
3374 getter_AddRefs(foundItem)); |
|
3375 } |
|
3376 #ifdef DEBUG |
|
3377 else { |
|
3378 NS_ERROR("Someone isn't setting up the tree owner. " |
|
3379 "You might like to try that. " |
|
3380 "Things will.....you know, work."); |
|
3381 // Note: _content should always exist. If we don't have one |
|
3382 // hanging off the treeowner, just create a named window.... |
|
3383 // so don't return here, in case we did that and can now find |
|
3384 // it. |
|
3385 // XXXbz should we be using |root| instead of creating |
|
3386 // a new window? |
|
3387 } |
|
3388 #endif |
|
3389 } else { |
|
3390 // Do the search for item by an actual name. |
|
3391 DoFindItemWithName(aName, aRequestor, aOriginalRequestor, |
|
3392 getter_AddRefs(foundItem)); |
|
3393 } |
|
3394 |
|
3395 if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) { |
|
3396 foundItem = nullptr; |
|
3397 } |
|
3398 |
|
3399 // DoFindItemWithName only returns active items and we don't check if |
|
3400 // the item is active for the special cases. |
|
3401 if (foundItem) { |
|
3402 foundItem.swap(*_retval); |
|
3403 } |
|
3404 return NS_OK; |
|
3405 } |
|
3406 } |
|
3407 |
|
3408 nsresult |
|
3409 nsDocShell::DoFindItemWithName(const char16_t* aName, |
|
3410 nsISupports* aRequestor, |
|
3411 nsIDocShellTreeItem* aOriginalRequestor, |
|
3412 nsIDocShellTreeItem** _retval) |
|
3413 { |
|
3414 // First we check our name. |
|
3415 if (mName.Equals(aName) && ItemIsActive(this) && |
|
3416 CanAccessItem(this, aOriginalRequestor)) { |
|
3417 NS_ADDREF(*_retval = this); |
|
3418 return NS_OK; |
|
3419 } |
|
3420 |
|
3421 // This QI may fail, but the places where we want to compare, comparing |
|
3422 // against nullptr serves the same purpose. |
|
3423 nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor)); |
|
3424 |
|
3425 // Second we check our children making sure not to ask a child if |
|
3426 // it is the aRequestor. |
|
3427 #ifdef DEBUG |
|
3428 nsresult rv = |
|
3429 #endif |
|
3430 FindChildWithName(aName, true, true, reqAsTreeItem, |
|
3431 aOriginalRequestor, _retval); |
|
3432 NS_ASSERTION(NS_SUCCEEDED(rv), |
|
3433 "FindChildWithName should not be failing here."); |
|
3434 if (*_retval) |
|
3435 return NS_OK; |
|
3436 |
|
3437 // Third if we have a parent and it isn't the requestor then we |
|
3438 // should ask it to do the search. If it is the requestor we |
|
3439 // should just stop here and let the parent do the rest. If we |
|
3440 // don't have a parent, then we should ask the |
|
3441 // docShellTreeOwner to do the search. |
|
3442 nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem = |
|
3443 do_QueryInterface(GetAsSupports(mParent)); |
|
3444 if (parentAsTreeItem) { |
|
3445 if (parentAsTreeItem == reqAsTreeItem) |
|
3446 return NS_OK; |
|
3447 |
|
3448 if (parentAsTreeItem->ItemType() == mItemType) { |
|
3449 return parentAsTreeItem-> |
|
3450 FindItemWithName(aName, |
|
3451 static_cast<nsIDocShellTreeItem*> |
|
3452 (this), |
|
3453 aOriginalRequestor, |
|
3454 _retval); |
|
3455 } |
|
3456 } |
|
3457 |
|
3458 // If the parent is null or not of the same type fall through and ask tree |
|
3459 // owner. |
|
3460 |
|
3461 // This may fail, but comparing against null serves the same purpose |
|
3462 nsCOMPtr<nsIDocShellTreeOwner> |
|
3463 reqAsTreeOwner(do_QueryInterface(aRequestor)); |
|
3464 |
|
3465 if (mTreeOwner && mTreeOwner != reqAsTreeOwner) { |
|
3466 return mTreeOwner-> |
|
3467 FindItemWithName(aName, this, aOriginalRequestor, _retval); |
|
3468 } |
|
3469 |
|
3470 return NS_OK; |
|
3471 } |
|
3472 |
|
3473 bool |
|
3474 nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell) |
|
3475 { |
|
3476 // If no target then not sandboxed. |
|
3477 if (!aTargetDocShell) { |
|
3478 return false; |
|
3479 } |
|
3480 |
|
3481 // We cannot be sandboxed from ourselves. |
|
3482 if (aTargetDocShell == this) { |
|
3483 return false; |
|
3484 } |
|
3485 |
|
3486 // Default the sandbox flags to our flags, so that if we can't retrieve the |
|
3487 // active document, we will still enforce our own. |
|
3488 uint32_t sandboxFlags = mSandboxFlags; |
|
3489 if (mContentViewer) { |
|
3490 nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument(); |
|
3491 if (doc) { |
|
3492 sandboxFlags = doc->GetSandboxFlags(); |
|
3493 } |
|
3494 } |
|
3495 |
|
3496 // If no flags, we are not sandboxed at all. |
|
3497 if (!sandboxFlags) { |
|
3498 return false; |
|
3499 } |
|
3500 |
|
3501 // If aTargetDocShell has an ancestor, it is not top level. |
|
3502 nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget; |
|
3503 aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget)); |
|
3504 if (ancestorOfTarget) { |
|
3505 do { |
|
3506 // We are not sandboxed if we are an ancestor of target. |
|
3507 if (ancestorOfTarget == this) { |
|
3508 return false; |
|
3509 } |
|
3510 nsCOMPtr<nsIDocShellTreeItem> tempTreeItem; |
|
3511 ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem)); |
|
3512 tempTreeItem.swap(ancestorOfTarget); |
|
3513 } while (ancestorOfTarget); |
|
3514 |
|
3515 // Otherwise, we are sandboxed from aTargetDocShell. |
|
3516 return true; |
|
3517 } |
|
3518 |
|
3519 // aTargetDocShell is top level, are we the "one permitted sandboxed |
|
3520 // navigator", i.e. did we open aTargetDocShell? |
|
3521 nsCOMPtr<nsIDocShell> permittedNavigator; |
|
3522 aTargetDocShell-> |
|
3523 GetOnePermittedSandboxedNavigator(getter_AddRefs(permittedNavigator)); |
|
3524 if (permittedNavigator == this) { |
|
3525 return false; |
|
3526 } |
|
3527 |
|
3528 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed |
|
3529 // from our top. |
|
3530 if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) { |
|
3531 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; |
|
3532 GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem)); |
|
3533 if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) { |
|
3534 return false; |
|
3535 } |
|
3536 } |
|
3537 |
|
3538 // Otherwise, we are sandboxed from aTargetDocShell. |
|
3539 return true; |
|
3540 } |
|
3541 |
|
3542 NS_IMETHODIMP |
|
3543 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner) |
|
3544 { |
|
3545 NS_ENSURE_ARG_POINTER(aTreeOwner); |
|
3546 |
|
3547 *aTreeOwner = mTreeOwner; |
|
3548 NS_IF_ADDREF(*aTreeOwner); |
|
3549 return NS_OK; |
|
3550 } |
|
3551 |
|
3552 #ifdef DEBUG_DOCSHELL_FOCUS |
|
3553 static void |
|
3554 PrintDocTree(nsIDocShellTreeItem * aParentNode, int aLevel) |
|
3555 { |
|
3556 for (int32_t i=0;i<aLevel;i++) printf(" "); |
|
3557 |
|
3558 int32_t childWebshellCount; |
|
3559 aParentNode->GetChildCount(&childWebshellCount); |
|
3560 nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode)); |
|
3561 int32_t type = aParentNode->ItemType(); |
|
3562 nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell(); |
|
3563 nsRefPtr<nsPresContext> presContext; |
|
3564 parentAsDocShell->GetPresContext(getter_AddRefs(presContext)); |
|
3565 nsIDocument *doc = presShell->GetDocument(); |
|
3566 |
|
3567 nsCOMPtr<nsIDOMWindow> domwin(doc->GetWindow()); |
|
3568 |
|
3569 nsCOMPtr<nsIWidget> widget; |
|
3570 nsViewManager* vm = presShell->GetViewManager(); |
|
3571 if (vm) { |
|
3572 vm->GetWidget(getter_AddRefs(widget)); |
|
3573 } |
|
3574 dom::Element* rootElement = doc->GetRootElement(); |
|
3575 |
|
3576 printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n", |
|
3577 (void*)parentAsDocShell.get(), |
|
3578 type==nsIDocShellTreeItem::typeChrome?"Chr":"Con", |
|
3579 (void*)doc, (void*)domwin.get(), |
|
3580 (void*)presContext->EventStateManager(), (void*)rootElement); |
|
3581 |
|
3582 if (childWebshellCount > 0) { |
|
3583 for (int32_t i=0;i<childWebshellCount;i++) { |
|
3584 nsCOMPtr<nsIDocShellTreeItem> child; |
|
3585 aParentNode->GetChildAt(i, getter_AddRefs(child)); |
|
3586 PrintDocTree(child, aLevel+1); |
|
3587 } |
|
3588 } |
|
3589 } |
|
3590 |
|
3591 static void |
|
3592 PrintDocTree(nsIDocShellTreeItem * aParentNode) |
|
3593 { |
|
3594 NS_ASSERTION(aParentNode, "Pointer is null!"); |
|
3595 |
|
3596 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
3597 aParentNode->GetParent(getter_AddRefs(parentItem)); |
|
3598 while (parentItem) { |
|
3599 nsCOMPtr<nsIDocShellTreeItem>tmp; |
|
3600 parentItem->GetParent(getter_AddRefs(tmp)); |
|
3601 if (!tmp) { |
|
3602 break; |
|
3603 } |
|
3604 parentItem = tmp; |
|
3605 } |
|
3606 |
|
3607 if (!parentItem) { |
|
3608 parentItem = aParentNode; |
|
3609 } |
|
3610 |
|
3611 PrintDocTree(parentItem, 0); |
|
3612 } |
|
3613 #endif |
|
3614 |
|
3615 NS_IMETHODIMP |
|
3616 nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner) |
|
3617 { |
|
3618 #ifdef DEBUG_DOCSHELL_FOCUS |
|
3619 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner)); |
|
3620 if (item) { |
|
3621 PrintDocTree(item); |
|
3622 } |
|
3623 #endif |
|
3624 |
|
3625 // Don't automatically set the progress based on the tree owner for frames |
|
3626 if (!IsFrame()) { |
|
3627 nsCOMPtr<nsIWebProgress> webProgress = |
|
3628 do_QueryInterface(GetAsSupports(this)); |
|
3629 |
|
3630 if (webProgress) { |
|
3631 nsCOMPtr<nsIWebProgressListener> |
|
3632 oldListener(do_QueryInterface(mTreeOwner)); |
|
3633 nsCOMPtr<nsIWebProgressListener> |
|
3634 newListener(do_QueryInterface(aTreeOwner)); |
|
3635 |
|
3636 if (oldListener) { |
|
3637 webProgress->RemoveProgressListener(oldListener); |
|
3638 } |
|
3639 |
|
3640 if (newListener) { |
|
3641 webProgress->AddProgressListener(newListener, |
|
3642 nsIWebProgress::NOTIFY_ALL); |
|
3643 } |
|
3644 } |
|
3645 } |
|
3646 |
|
3647 mTreeOwner = aTreeOwner; // Weak reference per API |
|
3648 |
|
3649 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
3650 while (iter.HasMore()) { |
|
3651 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext()); |
|
3652 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); |
|
3653 |
|
3654 if (child->ItemType() == mItemType) |
|
3655 child->SetTreeOwner(aTreeOwner); |
|
3656 } |
|
3657 |
|
3658 // Our tree owner has changed. Recompute scriptability. |
|
3659 // |
|
3660 // Note that this is near-redundant with the recomputation in |
|
3661 // SetDocLoaderParent(), but not so for the root DocShell, where the call to |
|
3662 // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(), |
|
3663 // and we never set another parent. Given that this is neither expensive nor |
|
3664 // performance-critical, let's be safe and unconditionally recompute this |
|
3665 // state whenever dependent state changes. |
|
3666 RecomputeCanExecuteScripts(); |
|
3667 |
|
3668 return NS_OK; |
|
3669 } |
|
3670 |
|
3671 NS_IMETHODIMP |
|
3672 nsDocShell::SetChildOffset(uint32_t aChildOffset) |
|
3673 { |
|
3674 mChildOffset = aChildOffset; |
|
3675 return NS_OK; |
|
3676 } |
|
3677 |
|
3678 NS_IMETHODIMP |
|
3679 nsDocShell::GetHistoryID(uint64_t* aID) |
|
3680 { |
|
3681 *aID = mHistoryID; |
|
3682 return NS_OK; |
|
3683 } |
|
3684 |
|
3685 NS_IMETHODIMP |
|
3686 nsDocShell::GetIsInUnload(bool* aIsInUnload) |
|
3687 { |
|
3688 *aIsInUnload = mFiredUnloadEvent; |
|
3689 return NS_OK; |
|
3690 } |
|
3691 |
|
3692 NS_IMETHODIMP |
|
3693 nsDocShell::GetChildCount(int32_t * aChildCount) |
|
3694 { |
|
3695 NS_ENSURE_ARG_POINTER(aChildCount); |
|
3696 *aChildCount = mChildList.Length(); |
|
3697 return NS_OK; |
|
3698 } |
|
3699 |
|
3700 |
|
3701 |
|
3702 NS_IMETHODIMP |
|
3703 nsDocShell::AddChild(nsIDocShellTreeItem * aChild) |
|
3704 { |
|
3705 NS_ENSURE_ARG_POINTER(aChild); |
|
3706 |
|
3707 nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild); |
|
3708 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED); |
|
3709 |
|
3710 // Make sure we're not creating a loop in the docshell tree |
|
3711 nsDocLoader* ancestor = this; |
|
3712 do { |
|
3713 if (childAsDocLoader == ancestor) { |
|
3714 return NS_ERROR_ILLEGAL_VALUE; |
|
3715 } |
|
3716 ancestor = ancestor->GetParent(); |
|
3717 } while (ancestor); |
|
3718 |
|
3719 // Make sure to remove the child from its current parent. |
|
3720 nsDocLoader* childsParent = childAsDocLoader->GetParent(); |
|
3721 if (childsParent) { |
|
3722 childsParent->RemoveChildLoader(childAsDocLoader); |
|
3723 } |
|
3724 |
|
3725 // Make sure to clear the treeowner in case this child is a different type |
|
3726 // from us. |
|
3727 aChild->SetTreeOwner(nullptr); |
|
3728 |
|
3729 nsresult res = AddChildLoader(childAsDocLoader); |
|
3730 NS_ENSURE_SUCCESS(res, res); |
|
3731 NS_ASSERTION(!mChildList.IsEmpty(), |
|
3732 "child list must not be empty after a successful add"); |
|
3733 |
|
3734 nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild); |
|
3735 bool dynamic = false; |
|
3736 childDocShell->GetCreatedDynamically(&dynamic); |
|
3737 if (!dynamic) { |
|
3738 nsCOMPtr<nsISHEntry> currentSH; |
|
3739 bool oshe = false; |
|
3740 GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe); |
|
3741 if (currentSH) { |
|
3742 currentSH->HasDynamicallyAddedChild(&dynamic); |
|
3743 } |
|
3744 } |
|
3745 childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1); |
|
3746 |
|
3747 /* Set the child's global history if the parent has one */ |
|
3748 if (mUseGlobalHistory) { |
|
3749 childDocShell->SetUseGlobalHistory(true); |
|
3750 } |
|
3751 |
|
3752 if (aChild->ItemType() != mItemType) { |
|
3753 return NS_OK; |
|
3754 } |
|
3755 |
|
3756 aChild->SetTreeOwner(mTreeOwner); |
|
3757 |
|
3758 nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild)); |
|
3759 if (!childAsDocShell) |
|
3760 return NS_OK; |
|
3761 |
|
3762 // charset, style-disabling, and zoom will be inherited in SetupNewViewer() |
|
3763 |
|
3764 // Now take this document's charset and set the child's parentCharset field |
|
3765 // to it. We'll later use that field, in the loading process, for the |
|
3766 // charset choosing algorithm. |
|
3767 // If we fail, at any point, we just return NS_OK. |
|
3768 // This code has some performance impact. But this will be reduced when |
|
3769 // the current charset will finally be stored as an Atom, avoiding the |
|
3770 // alias resolution extra look-up. |
|
3771 |
|
3772 // we are NOT going to propagate the charset is this Chrome's docshell |
|
3773 if (mItemType == nsIDocShellTreeItem::typeChrome) |
|
3774 return NS_OK; |
|
3775 |
|
3776 // get the parent's current charset |
|
3777 if (!mContentViewer) |
|
3778 return NS_OK; |
|
3779 nsIDocument* doc = mContentViewer->GetDocument(); |
|
3780 if (!doc) |
|
3781 return NS_OK; |
|
3782 |
|
3783 bool isWyciwyg = false; |
|
3784 |
|
3785 if (mCurrentURI) { |
|
3786 // Check if the url is wyciwyg |
|
3787 mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg); |
|
3788 } |
|
3789 |
|
3790 if (!isWyciwyg) { |
|
3791 // If this docshell is loaded from a wyciwyg: URI, don't |
|
3792 // advertise our charset since it does not in any way reflect |
|
3793 // the actual source charset, which is what we're trying to |
|
3794 // expose here. |
|
3795 |
|
3796 const nsACString &parentCS = doc->GetDocumentCharacterSet(); |
|
3797 int32_t charsetSource = doc->GetDocumentCharacterSetSource(); |
|
3798 // set the child's parentCharset |
|
3799 childAsDocShell->SetParentCharset(parentCS, |
|
3800 charsetSource, |
|
3801 doc->NodePrincipal()); |
|
3802 } |
|
3803 |
|
3804 // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n", NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType); |
|
3805 |
|
3806 return NS_OK; |
|
3807 } |
|
3808 |
|
3809 NS_IMETHODIMP |
|
3810 nsDocShell::RemoveChild(nsIDocShellTreeItem * aChild) |
|
3811 { |
|
3812 NS_ENSURE_ARG_POINTER(aChild); |
|
3813 |
|
3814 nsRefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild); |
|
3815 NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED); |
|
3816 |
|
3817 nsresult rv = RemoveChildLoader(childAsDocLoader); |
|
3818 NS_ENSURE_SUCCESS(rv, rv); |
|
3819 |
|
3820 aChild->SetTreeOwner(nullptr); |
|
3821 |
|
3822 return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader); |
|
3823 } |
|
3824 |
|
3825 NS_IMETHODIMP |
|
3826 nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem ** aChild) |
|
3827 { |
|
3828 NS_ENSURE_ARG_POINTER(aChild); |
|
3829 |
|
3830 #ifdef DEBUG |
|
3831 if (aIndex < 0) { |
|
3832 NS_WARNING("Negative index passed to GetChildAt"); |
|
3833 } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) { |
|
3834 NS_WARNING("Too large an index passed to GetChildAt"); |
|
3835 } |
|
3836 #endif |
|
3837 |
|
3838 nsIDocumentLoader* child = ChildAt(aIndex); |
|
3839 NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED); |
|
3840 |
|
3841 return CallQueryInterface(child, aChild); |
|
3842 } |
|
3843 |
|
3844 NS_IMETHODIMP |
|
3845 nsDocShell::FindChildWithName(const char16_t * aName, |
|
3846 bool aRecurse, bool aSameType, |
|
3847 nsIDocShellTreeItem * aRequestor, |
|
3848 nsIDocShellTreeItem * aOriginalRequestor, |
|
3849 nsIDocShellTreeItem ** _retval) |
|
3850 { |
|
3851 NS_ENSURE_ARG(aName); |
|
3852 NS_ENSURE_ARG_POINTER(_retval); |
|
3853 |
|
3854 *_retval = nullptr; // if we don't find one, we return NS_OK and a null result |
|
3855 |
|
3856 if (!*aName) |
|
3857 return NS_OK; |
|
3858 |
|
3859 nsXPIDLString childName; |
|
3860 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
3861 while (iter.HasMore()) { |
|
3862 nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext()); |
|
3863 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); |
|
3864 int32_t childType = child->ItemType(); |
|
3865 |
|
3866 if (aSameType && (childType != mItemType)) |
|
3867 continue; |
|
3868 |
|
3869 bool childNameEquals = false; |
|
3870 child->NameEquals(aName, &childNameEquals); |
|
3871 if (childNameEquals && ItemIsActive(child) && |
|
3872 CanAccessItem(child, aOriginalRequestor)) { |
|
3873 child.swap(*_retval); |
|
3874 break; |
|
3875 } |
|
3876 |
|
3877 if (childType != mItemType) //Only ask it to check children if it is same type |
|
3878 continue; |
|
3879 |
|
3880 if (aRecurse && (aRequestor != child)) // Only ask the child if it isn't the requestor |
|
3881 { |
|
3882 // See if child contains the shell with the given name |
|
3883 #ifdef DEBUG |
|
3884 nsresult rv = |
|
3885 #endif |
|
3886 child->FindChildWithName(aName, true, |
|
3887 aSameType, |
|
3888 static_cast<nsIDocShellTreeItem*> |
|
3889 (this), |
|
3890 aOriginalRequestor, |
|
3891 _retval); |
|
3892 NS_ASSERTION(NS_SUCCEEDED(rv), |
|
3893 "FindChildWithName should not fail here"); |
|
3894 if (*_retval) // found it |
|
3895 return NS_OK; |
|
3896 } |
|
3897 } |
|
3898 return NS_OK; |
|
3899 } |
|
3900 |
|
3901 NS_IMETHODIMP |
|
3902 nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry ** aResult) |
|
3903 { |
|
3904 nsresult rv = NS_OK; |
|
3905 |
|
3906 NS_ENSURE_ARG_POINTER(aResult); |
|
3907 *aResult = nullptr; |
|
3908 |
|
3909 |
|
3910 // A nsISHEntry for a child is *only* available when the parent is in |
|
3911 // the progress of loading a document too... |
|
3912 |
|
3913 if (mLSHE) { |
|
3914 /* Before looking for the subframe's url, check |
|
3915 * the expiration status of the parent. If the parent |
|
3916 * has expired from cache, then subframes will not be |
|
3917 * loaded from history in certain situations. |
|
3918 */ |
|
3919 bool parentExpired=false; |
|
3920 mLSHE->GetExpirationStatus(&parentExpired); |
|
3921 |
|
3922 /* Get the parent's Load Type so that it can be set on the child too. |
|
3923 * By default give a loadHistory value |
|
3924 */ |
|
3925 uint32_t loadType = nsIDocShellLoadInfo::loadHistory; |
|
3926 mLSHE->GetLoadType(&loadType); |
|
3927 // If the user did a shift-reload on this frameset page, |
|
3928 // we don't want to load the subframes from history. |
|
3929 if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache || |
|
3930 loadType == nsIDocShellLoadInfo::loadReloadBypassProxy || |
|
3931 loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache || |
|
3932 loadType == nsIDocShellLoadInfo::loadRefresh) |
|
3933 return rv; |
|
3934 |
|
3935 /* If the user pressed reload and the parent frame has expired |
|
3936 * from cache, we do not want to load the child frame from history. |
|
3937 */ |
|
3938 if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) { |
|
3939 // The parent has expired. Return null. |
|
3940 *aResult = nullptr; |
|
3941 return rv; |
|
3942 } |
|
3943 |
|
3944 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE)); |
|
3945 if (container) { |
|
3946 // Get the child subframe from session history. |
|
3947 rv = container->GetChildAt(aChildOffset, aResult); |
|
3948 if (*aResult) |
|
3949 (*aResult)->SetLoadType(loadType); |
|
3950 } |
|
3951 } |
|
3952 return rv; |
|
3953 } |
|
3954 |
|
3955 NS_IMETHODIMP |
|
3956 nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry, |
|
3957 int32_t aChildOffset, uint32_t loadType, |
|
3958 bool aCloneChildren) |
|
3959 { |
|
3960 nsresult rv; |
|
3961 |
|
3962 if (mLSHE && loadType != LOAD_PUSHSTATE) { |
|
3963 /* You get here if you are currently building a |
|
3964 * hierarchy ie.,you just visited a frameset page |
|
3965 */ |
|
3966 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv)); |
|
3967 if (container) { |
|
3968 rv = container->AddChild(aNewEntry, aChildOffset); |
|
3969 } |
|
3970 } |
|
3971 else if (!aCloneRef) { |
|
3972 /* This is an initial load in some subframe. Just append it if we can */ |
|
3973 nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv)); |
|
3974 if (container) { |
|
3975 rv = container->AddChild(aNewEntry, aChildOffset); |
|
3976 } |
|
3977 } |
|
3978 else if (mSessionHistory) { |
|
3979 /* You are currently in the rootDocShell. |
|
3980 * You will get here when a subframe has a new url |
|
3981 * to load and you have walked up the tree all the |
|
3982 * way to the top to clone the current SHEntry hierarchy |
|
3983 * and replace the subframe where a new url was loaded with |
|
3984 * a new entry. |
|
3985 */ |
|
3986 int32_t index = -1; |
|
3987 nsCOMPtr<nsISHEntry> currentHE; |
|
3988 mSessionHistory->GetIndex(&index); |
|
3989 if (index < 0) |
|
3990 return NS_ERROR_FAILURE; |
|
3991 |
|
3992 rv = mSessionHistory->GetEntryAtIndex(index, false, |
|
3993 getter_AddRefs(currentHE)); |
|
3994 NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE); |
|
3995 |
|
3996 nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE)); |
|
3997 if (currentEntry) { |
|
3998 uint32_t cloneID = 0; |
|
3999 nsCOMPtr<nsISHEntry> nextEntry; |
|
4000 aCloneRef->GetID(&cloneID); |
|
4001 rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry, |
|
4002 aCloneChildren, getter_AddRefs(nextEntry)); |
|
4003 |
|
4004 if (NS_SUCCEEDED(rv)) { |
|
4005 nsCOMPtr<nsISHistoryInternal> |
|
4006 shPrivate(do_QueryInterface(mSessionHistory)); |
|
4007 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE); |
|
4008 rv = shPrivate->AddEntry(nextEntry, true); |
|
4009 } |
|
4010 } |
|
4011 } |
|
4012 else { |
|
4013 /* Just pass this along */ |
|
4014 nsCOMPtr<nsIDocShell> parent = |
|
4015 do_QueryInterface(GetAsSupports(mParent), &rv); |
|
4016 if (parent) { |
|
4017 rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset, |
|
4018 loadType, aCloneChildren); |
|
4019 } |
|
4020 } |
|
4021 return rv; |
|
4022 } |
|
4023 |
|
4024 nsresult |
|
4025 nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, int32_t aChildOffset, |
|
4026 bool aCloneChildren) |
|
4027 { |
|
4028 /* You will get here when you are in a subframe and |
|
4029 * a new url has been loaded on you. |
|
4030 * The mOSHE in this subframe will be the previous url's |
|
4031 * mOSHE. This mOSHE will be used as the identification |
|
4032 * for this subframe in the CloneAndReplace function. |
|
4033 */ |
|
4034 |
|
4035 // In this case, we will end up calling AddEntry, which increases the |
|
4036 // current index by 1 |
|
4037 nsCOMPtr<nsISHistory> rootSH; |
|
4038 GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4039 if (rootSH) { |
|
4040 rootSH->GetIndex(&mPreviousTransIndex); |
|
4041 } |
|
4042 |
|
4043 nsresult rv; |
|
4044 nsCOMPtr<nsIDocShell> parent = |
|
4045 do_QueryInterface(GetAsSupports(mParent), &rv); |
|
4046 if (parent) { |
|
4047 rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType, |
|
4048 aCloneChildren); |
|
4049 } |
|
4050 |
|
4051 |
|
4052 if (rootSH) { |
|
4053 rootSH->GetIndex(&mLoadedTransIndex); |
|
4054 #ifdef DEBUG_PAGE_CACHE |
|
4055 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex, |
|
4056 mLoadedTransIndex); |
|
4057 #endif |
|
4058 } |
|
4059 |
|
4060 return rv; |
|
4061 } |
|
4062 |
|
4063 NS_IMETHODIMP |
|
4064 nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory) |
|
4065 { |
|
4066 nsresult rv; |
|
4067 |
|
4068 mUseGlobalHistory = aUseGlobalHistory; |
|
4069 |
|
4070 if (!aUseGlobalHistory) { |
|
4071 mGlobalHistory = nullptr; |
|
4072 return NS_OK; |
|
4073 } |
|
4074 |
|
4075 // No need to initialize mGlobalHistory if IHistory is available. |
|
4076 nsCOMPtr<IHistory> history = services::GetHistoryService(); |
|
4077 if (history) { |
|
4078 return NS_OK; |
|
4079 } |
|
4080 |
|
4081 if (mGlobalHistory) { |
|
4082 return NS_OK; |
|
4083 } |
|
4084 |
|
4085 mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv); |
|
4086 return rv; |
|
4087 } |
|
4088 |
|
4089 NS_IMETHODIMP |
|
4090 nsDocShell::GetUseGlobalHistory(bool *aUseGlobalHistory) |
|
4091 { |
|
4092 *aUseGlobalHistory = mUseGlobalHistory; |
|
4093 return NS_OK; |
|
4094 } |
|
4095 |
|
4096 NS_IMETHODIMP |
|
4097 nsDocShell::RemoveFromSessionHistory() |
|
4098 { |
|
4099 nsCOMPtr<nsISHistoryInternal> internalHistory; |
|
4100 nsCOMPtr<nsISHistory> sessionHistory; |
|
4101 nsCOMPtr<nsIDocShellTreeItem> root; |
|
4102 GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
4103 if (root) { |
|
4104 nsCOMPtr<nsIWebNavigation> rootAsWebnav = |
|
4105 do_QueryInterface(root); |
|
4106 if (rootAsWebnav) { |
|
4107 rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory)); |
|
4108 internalHistory = do_QueryInterface(sessionHistory); |
|
4109 } |
|
4110 } |
|
4111 if (!internalHistory) { |
|
4112 return NS_OK; |
|
4113 } |
|
4114 |
|
4115 int32_t index = 0; |
|
4116 sessionHistory->GetIndex(&index); |
|
4117 nsAutoTArray<uint64_t, 16> ids; |
|
4118 ids.AppendElement(mHistoryID); |
|
4119 internalHistory->RemoveEntries(ids, index); |
|
4120 return NS_OK; |
|
4121 } |
|
4122 |
|
4123 NS_IMETHODIMP |
|
4124 nsDocShell::SetCreatedDynamically(bool aDynamic) |
|
4125 { |
|
4126 mDynamicallyCreated = aDynamic; |
|
4127 return NS_OK; |
|
4128 } |
|
4129 |
|
4130 NS_IMETHODIMP |
|
4131 nsDocShell::GetCreatedDynamically(bool* aDynamic) |
|
4132 { |
|
4133 *aDynamic = mDynamicallyCreated; |
|
4134 return NS_OK; |
|
4135 } |
|
4136 |
|
4137 NS_IMETHODIMP |
|
4138 nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE) |
|
4139 { |
|
4140 *aOSHE = false; |
|
4141 *aEntry = nullptr; |
|
4142 if (mLSHE) { |
|
4143 NS_ADDREF(*aEntry = mLSHE); |
|
4144 } else if (mOSHE) { |
|
4145 NS_ADDREF(*aEntry = mOSHE); |
|
4146 *aOSHE = true; |
|
4147 } |
|
4148 return NS_OK; |
|
4149 } |
|
4150 |
|
4151 nsIScriptGlobalObject* |
|
4152 nsDocShell::GetScriptGlobalObject() |
|
4153 { |
|
4154 NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr); |
|
4155 return mScriptGlobal; |
|
4156 } |
|
4157 |
|
4158 NS_IMETHODIMP |
|
4159 nsDocShell::SetDeviceSizeIsPageSize(bool aValue) |
|
4160 { |
|
4161 if (mDeviceSizeIsPageSize != aValue) { |
|
4162 mDeviceSizeIsPageSize = aValue; |
|
4163 nsRefPtr<nsPresContext> presContext; |
|
4164 GetPresContext(getter_AddRefs(presContext)); |
|
4165 if (presContext) { |
|
4166 presContext->MediaFeatureValuesChanged(presContext->eAlwaysRebuildStyle); |
|
4167 } |
|
4168 } |
|
4169 return NS_OK; |
|
4170 } |
|
4171 |
|
4172 NS_IMETHODIMP |
|
4173 nsDocShell::GetDeviceSizeIsPageSize(bool* aValue) |
|
4174 { |
|
4175 *aValue = mDeviceSizeIsPageSize; |
|
4176 return NS_OK; |
|
4177 } |
|
4178 |
|
4179 void |
|
4180 nsDocShell::ClearFrameHistory(nsISHEntry* aEntry) |
|
4181 { |
|
4182 nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry); |
|
4183 nsCOMPtr<nsISHistory> rootSH; |
|
4184 GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4185 nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH); |
|
4186 if (!history || !shcontainer) { |
|
4187 return; |
|
4188 } |
|
4189 |
|
4190 int32_t count = 0; |
|
4191 shcontainer->GetChildCount(&count); |
|
4192 nsAutoTArray<uint64_t, 16> ids; |
|
4193 for (int32_t i = 0; i < count; ++i) { |
|
4194 nsCOMPtr<nsISHEntry> child; |
|
4195 shcontainer->GetChildAt(i, getter_AddRefs(child)); |
|
4196 if (child) { |
|
4197 uint64_t id = 0; |
|
4198 child->GetDocshellID(&id); |
|
4199 ids.AppendElement(id); |
|
4200 } |
|
4201 } |
|
4202 int32_t index = 0; |
|
4203 rootSH->GetIndex(&index); |
|
4204 history->RemoveEntries(ids, index); |
|
4205 } |
|
4206 |
|
4207 //------------------------------------- |
|
4208 //-- Helper Method for Print discovery |
|
4209 //------------------------------------- |
|
4210 bool |
|
4211 nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog) |
|
4212 { |
|
4213 if (mIsPrintingOrPP && aDisplayErrorDialog) { |
|
4214 DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr); |
|
4215 } |
|
4216 |
|
4217 return mIsPrintingOrPP; |
|
4218 } |
|
4219 |
|
4220 bool |
|
4221 nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog) |
|
4222 { |
|
4223 bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent; |
|
4224 if (!isAllowed) { |
|
4225 return false; |
|
4226 } |
|
4227 if (!mContentViewer) { |
|
4228 return true; |
|
4229 } |
|
4230 bool firingBeforeUnload; |
|
4231 mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload); |
|
4232 return !firingBeforeUnload; |
|
4233 } |
|
4234 |
|
4235 //***************************************************************************** |
|
4236 // nsDocShell::nsIWebNavigation |
|
4237 //***************************************************************************** |
|
4238 |
|
4239 NS_IMETHODIMP |
|
4240 nsDocShell::GetCanGoBack(bool * aCanGoBack) |
|
4241 { |
|
4242 if (!IsNavigationAllowed(false)) { |
|
4243 *aCanGoBack = false; |
|
4244 return NS_OK; // JS may not handle returning of an error code |
|
4245 } |
|
4246 nsresult rv; |
|
4247 nsCOMPtr<nsISHistory> rootSH; |
|
4248 rv = GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4249 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH)); |
|
4250 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); |
|
4251 rv = webnav->GetCanGoBack(aCanGoBack); |
|
4252 return rv; |
|
4253 |
|
4254 } |
|
4255 |
|
4256 NS_IMETHODIMP |
|
4257 nsDocShell::GetCanGoForward(bool * aCanGoForward) |
|
4258 { |
|
4259 if (!IsNavigationAllowed(false)) { |
|
4260 *aCanGoForward = false; |
|
4261 return NS_OK; // JS may not handle returning of an error code |
|
4262 } |
|
4263 nsresult rv; |
|
4264 nsCOMPtr<nsISHistory> rootSH; |
|
4265 rv = GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4266 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH)); |
|
4267 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); |
|
4268 rv = webnav->GetCanGoForward(aCanGoForward); |
|
4269 return rv; |
|
4270 |
|
4271 } |
|
4272 |
|
4273 NS_IMETHODIMP |
|
4274 nsDocShell::GoBack() |
|
4275 { |
|
4276 if (!IsNavigationAllowed()) { |
|
4277 return NS_OK; // JS may not handle returning of an error code |
|
4278 } |
|
4279 nsresult rv; |
|
4280 nsCOMPtr<nsISHistory> rootSH; |
|
4281 rv = GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4282 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH)); |
|
4283 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); |
|
4284 rv = webnav->GoBack(); |
|
4285 return rv; |
|
4286 |
|
4287 } |
|
4288 |
|
4289 NS_IMETHODIMP |
|
4290 nsDocShell::GoForward() |
|
4291 { |
|
4292 if (!IsNavigationAllowed()) { |
|
4293 return NS_OK; // JS may not handle returning of an error code |
|
4294 } |
|
4295 nsresult rv; |
|
4296 nsCOMPtr<nsISHistory> rootSH; |
|
4297 rv = GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4298 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH)); |
|
4299 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); |
|
4300 rv = webnav->GoForward(); |
|
4301 return rv; |
|
4302 |
|
4303 } |
|
4304 |
|
4305 NS_IMETHODIMP nsDocShell::GotoIndex(int32_t aIndex) |
|
4306 { |
|
4307 if (!IsNavigationAllowed()) { |
|
4308 return NS_OK; // JS may not handle returning of an error code |
|
4309 } |
|
4310 nsresult rv; |
|
4311 nsCOMPtr<nsISHistory> rootSH; |
|
4312 rv = GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4313 nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH)); |
|
4314 NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); |
|
4315 rv = webnav->GotoIndex(aIndex); |
|
4316 return rv; |
|
4317 |
|
4318 } |
|
4319 |
|
4320 NS_IMETHODIMP |
|
4321 nsDocShell::LoadURI(const char16_t * aURI, |
|
4322 uint32_t aLoadFlags, |
|
4323 nsIURI * aReferringURI, |
|
4324 nsIInputStream * aPostStream, |
|
4325 nsIInputStream * aHeaderStream) |
|
4326 { |
|
4327 return LoadURIWithBase(aURI, aLoadFlags, aReferringURI, aPostStream, |
|
4328 aHeaderStream, nullptr); |
|
4329 } |
|
4330 |
|
4331 NS_IMETHODIMP |
|
4332 nsDocShell::LoadURIWithBase(const char16_t * aURI, |
|
4333 uint32_t aLoadFlags, |
|
4334 nsIURI * aReferringURI, |
|
4335 nsIInputStream * aPostStream, |
|
4336 nsIInputStream * aHeaderStream, |
|
4337 nsIURI * aBaseURI) |
|
4338 { |
|
4339 NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags"); |
|
4340 |
|
4341 if (!IsNavigationAllowed()) { |
|
4342 return NS_OK; // JS may not handle returning of an error code |
|
4343 } |
|
4344 nsCOMPtr<nsIURI> uri; |
|
4345 nsCOMPtr<nsIInputStream> postStream(aPostStream); |
|
4346 nsresult rv = NS_OK; |
|
4347 |
|
4348 // Create a URI from our string; if that succeeds, we want to |
|
4349 // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP |
|
4350 // flag. |
|
4351 |
|
4352 NS_ConvertUTF16toUTF8 uriString(aURI); |
|
4353 // Cleanup the empty spaces that might be on each end. |
|
4354 uriString.Trim(" "); |
|
4355 // Eliminate embedded newlines, which single-line text fields now allow: |
|
4356 uriString.StripChars("\r\n"); |
|
4357 NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE); |
|
4358 |
|
4359 rv = NS_NewURI(getter_AddRefs(uri), uriString); |
|
4360 if (uri) { |
|
4361 aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; |
|
4362 } |
|
4363 |
|
4364 if (sURIFixup) { |
|
4365 // Call the fixup object. This will clobber the rv from NS_NewURI |
|
4366 // above, but that's fine with us. Note that we need to do this even |
|
4367 // if NS_NewURI returned a URI, because fixup handles nested URIs, etc |
|
4368 // (things like view-source:mozilla.org for example). |
|
4369 uint32_t fixupFlags = 0; |
|
4370 if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { |
|
4371 fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; |
|
4372 } |
|
4373 if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) { |
|
4374 fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS; |
|
4375 } |
|
4376 nsCOMPtr<nsIInputStream> fixupStream; |
|
4377 rv = sURIFixup->CreateFixupURI(uriString, fixupFlags, |
|
4378 getter_AddRefs(fixupStream), |
|
4379 getter_AddRefs(uri)); |
|
4380 if (fixupStream) { |
|
4381 // CreateFixupURI only returns a post data stream if it succeeded |
|
4382 // and changed the URI, in which case we should override the |
|
4383 // passed-in post data. |
|
4384 postStream = fixupStream; |
|
4385 } |
|
4386 } |
|
4387 // else no fixup service so just use the URI we created and see |
|
4388 // what happens |
|
4389 |
|
4390 if (NS_ERROR_MALFORMED_URI == rv) { |
|
4391 DisplayLoadError(rv, uri, aURI, nullptr); |
|
4392 } |
|
4393 |
|
4394 if (NS_FAILED(rv) || !uri) |
|
4395 return NS_ERROR_FAILURE; |
|
4396 |
|
4397 PopupControlState popupState; |
|
4398 if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) { |
|
4399 popupState = openAllowed; |
|
4400 aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS; |
|
4401 } else { |
|
4402 popupState = openOverridden; |
|
4403 } |
|
4404 nsAutoPopupStatePusher statePusher(popupState); |
|
4405 |
|
4406 // Don't pass certain flags that aren't needed and end up confusing |
|
4407 // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are |
|
4408 // passed to LoadURI though, since it uses them. |
|
4409 uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS); |
|
4410 aLoadFlags &= ~EXTRA_LOAD_FLAGS; |
|
4411 |
|
4412 nsCOMPtr<nsIDocShellLoadInfo> loadInfo; |
|
4413 rv = CreateLoadInfo(getter_AddRefs(loadInfo)); |
|
4414 if (NS_FAILED(rv)) return rv; |
|
4415 |
|
4416 /* |
|
4417 * If the user "Disables Protection on This Page", we have to make sure to |
|
4418 * remember the users decision when opening links in child tabs [Bug 906190] |
|
4419 */ |
|
4420 uint32_t loadType; |
|
4421 if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) { |
|
4422 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags); |
|
4423 } else { |
|
4424 loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags); |
|
4425 } |
|
4426 |
|
4427 loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType)); |
|
4428 loadInfo->SetPostDataStream(postStream); |
|
4429 loadInfo->SetReferrer(aReferringURI); |
|
4430 loadInfo->SetHeadersStream(aHeaderStream); |
|
4431 loadInfo->SetBaseURI(aBaseURI); |
|
4432 |
|
4433 rv = LoadURI(uri, loadInfo, extraFlags, true); |
|
4434 |
|
4435 // Save URI string in case it's needed later when |
|
4436 // sending to search engine service in EndPageLoad() |
|
4437 mOriginalUriString = uriString; |
|
4438 |
|
4439 return rv; |
|
4440 } |
|
4441 |
|
4442 NS_IMETHODIMP |
|
4443 nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, |
|
4444 const char16_t *aURL, |
|
4445 nsIChannel* aFailedChannel) |
|
4446 { |
|
4447 // Get prompt and string bundle servcies |
|
4448 nsCOMPtr<nsIPrompt> prompter; |
|
4449 nsCOMPtr<nsIStringBundle> stringBundle; |
|
4450 GetPromptAndStringBundle(getter_AddRefs(prompter), |
|
4451 getter_AddRefs(stringBundle)); |
|
4452 |
|
4453 NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE); |
|
4454 NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE); |
|
4455 |
|
4456 nsAutoString error; |
|
4457 const uint32_t kMaxFormatStrArgs = 3; |
|
4458 nsAutoString formatStrs[kMaxFormatStrArgs]; |
|
4459 uint32_t formatStrCount = 0; |
|
4460 bool addHostPort = false; |
|
4461 nsresult rv = NS_OK; |
|
4462 nsAutoString messageStr; |
|
4463 nsAutoCString cssClass; |
|
4464 nsAutoCString errorPage; |
|
4465 |
|
4466 errorPage.AssignLiteral("neterror"); |
|
4467 |
|
4468 // Turn the error code into a human readable error message. |
|
4469 if (NS_ERROR_UNKNOWN_PROTOCOL == aError) { |
|
4470 NS_ENSURE_ARG_POINTER(aURI); |
|
4471 |
|
4472 // Extract the schemes into a comma delimited list. |
|
4473 nsAutoCString scheme; |
|
4474 aURI->GetScheme(scheme); |
|
4475 CopyASCIItoUTF16(scheme, formatStrs[0]); |
|
4476 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI); |
|
4477 while (nestedURI) { |
|
4478 nsCOMPtr<nsIURI> tempURI; |
|
4479 nsresult rv2; |
|
4480 rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI)); |
|
4481 if (NS_SUCCEEDED(rv2) && tempURI) { |
|
4482 tempURI->GetScheme(scheme); |
|
4483 formatStrs[0].Append(NS_LITERAL_STRING(", ")); |
|
4484 AppendASCIItoUTF16(scheme, formatStrs[0]); |
|
4485 } |
|
4486 nestedURI = do_QueryInterface(tempURI); |
|
4487 } |
|
4488 formatStrCount = 1; |
|
4489 error.AssignLiteral("unknownProtocolFound"); |
|
4490 } |
|
4491 else if (NS_ERROR_FILE_NOT_FOUND == aError) { |
|
4492 NS_ENSURE_ARG_POINTER(aURI); |
|
4493 error.AssignLiteral("fileNotFound"); |
|
4494 } |
|
4495 else if (NS_ERROR_UNKNOWN_HOST == aError) { |
|
4496 NS_ENSURE_ARG_POINTER(aURI); |
|
4497 // Get the host |
|
4498 nsAutoCString host; |
|
4499 nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI); |
|
4500 innermostURI->GetHost(host); |
|
4501 CopyUTF8toUTF16(host, formatStrs[0]); |
|
4502 formatStrCount = 1; |
|
4503 error.AssignLiteral("dnsNotFound"); |
|
4504 } |
|
4505 else if(NS_ERROR_CONNECTION_REFUSED == aError) { |
|
4506 NS_ENSURE_ARG_POINTER(aURI); |
|
4507 addHostPort = true; |
|
4508 error.AssignLiteral("connectionFailure"); |
|
4509 } |
|
4510 else if(NS_ERROR_NET_INTERRUPT == aError) { |
|
4511 NS_ENSURE_ARG_POINTER(aURI); |
|
4512 addHostPort = true; |
|
4513 error.AssignLiteral("netInterrupt"); |
|
4514 } |
|
4515 else if (NS_ERROR_NET_TIMEOUT == aError) { |
|
4516 NS_ENSURE_ARG_POINTER(aURI); |
|
4517 // Get the host |
|
4518 nsAutoCString host; |
|
4519 aURI->GetHost(host); |
|
4520 CopyUTF8toUTF16(host, formatStrs[0]); |
|
4521 formatStrCount = 1; |
|
4522 error.AssignLiteral("netTimeout"); |
|
4523 } |
|
4524 else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError) { |
|
4525 // CSP error |
|
4526 cssClass.AssignLiteral("neterror"); |
|
4527 error.AssignLiteral("cspFrameAncestorBlocked"); |
|
4528 } |
|
4529 else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) { |
|
4530 nsCOMPtr<nsINSSErrorsService> nsserr = |
|
4531 do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID); |
|
4532 |
|
4533 uint32_t errorClass; |
|
4534 if (!nsserr || |
|
4535 NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) { |
|
4536 errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL; |
|
4537 } |
|
4538 |
|
4539 nsCOMPtr<nsISupports> securityInfo; |
|
4540 nsCOMPtr<nsITransportSecurityInfo> tsi; |
|
4541 if (aFailedChannel) |
|
4542 aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo)); |
|
4543 tsi = do_QueryInterface(securityInfo); |
|
4544 if (tsi) { |
|
4545 // Usually we should have aFailedChannel and get a detailed message |
|
4546 tsi->GetErrorMessage(getter_Copies(messageStr)); |
|
4547 } |
|
4548 else { |
|
4549 // No channel, let's obtain the generic error message |
|
4550 if (nsserr) { |
|
4551 nsserr->GetErrorMessage(aError, messageStr); |
|
4552 } |
|
4553 } |
|
4554 if (!messageStr.IsEmpty()) { |
|
4555 if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) { |
|
4556 error.AssignLiteral("nssBadCert"); |
|
4557 |
|
4558 // if this is a Strict-Transport-Security host and the cert |
|
4559 // is bad, don't allow overrides (STS Spec section 7.3). |
|
4560 nsCOMPtr<nsISiteSecurityService> sss = |
|
4561 do_GetService(NS_SSSERVICE_CONTRACTID, &rv); |
|
4562 NS_ENSURE_SUCCESS(rv, rv); |
|
4563 uint32_t flags = |
|
4564 mInPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0; |
|
4565 |
|
4566 bool isStsHost = false; |
|
4567 rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, |
|
4568 aURI, flags, &isStsHost); |
|
4569 NS_ENSURE_SUCCESS(rv, rv); |
|
4570 |
|
4571 uint32_t bucketId; |
|
4572 if (isStsHost) { |
|
4573 cssClass.AssignLiteral("badStsCert"); |
|
4574 //measuring STS separately allows us to measure click through |
|
4575 //rates easily |
|
4576 bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS; |
|
4577 } else { |
|
4578 bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP; |
|
4579 } |
|
4580 |
|
4581 |
|
4582 if (Preferences::GetBool( |
|
4583 "browser.xul.error_pages.expert_bad_cert", false)) { |
|
4584 cssClass.AssignLiteral("expertBadCert"); |
|
4585 } |
|
4586 |
|
4587 // See if an alternate cert error page is registered |
|
4588 nsAdoptingCString alternateErrorPage = |
|
4589 Preferences::GetCString( |
|
4590 "security.alternate_certificate_error_page"); |
|
4591 if (alternateErrorPage) |
|
4592 errorPage.Assign(alternateErrorPage); |
|
4593 |
|
4594 if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) |
|
4595 mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId); |
|
4596 |
|
4597 } else { |
|
4598 error.AssignLiteral("nssFailure2"); |
|
4599 } |
|
4600 } |
|
4601 } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError) { |
|
4602 nsAutoCString host; |
|
4603 aURI->GetHost(host); |
|
4604 CopyUTF8toUTF16(host, formatStrs[0]); |
|
4605 formatStrCount = 1; |
|
4606 |
|
4607 // Malware and phishing detectors may want to use an alternate error |
|
4608 // page, but if the pref's not set, we'll fall back on the standard page |
|
4609 nsAdoptingCString alternateErrorPage = |
|
4610 Preferences::GetCString("urlclassifier.alternate_error_page"); |
|
4611 if (alternateErrorPage) |
|
4612 errorPage.Assign(alternateErrorPage); |
|
4613 |
|
4614 uint32_t bucketId; |
|
4615 if (NS_ERROR_PHISHING_URI == aError) { |
|
4616 error.AssignLiteral("phishingBlocked"); |
|
4617 bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME : |
|
4618 nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP ; |
|
4619 } else { |
|
4620 error.AssignLiteral("malwareBlocked"); |
|
4621 bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME : |
|
4622 nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP ; |
|
4623 } |
|
4624 |
|
4625 if (errorPage.EqualsIgnoreCase("blocked")) |
|
4626 mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, |
|
4627 bucketId); |
|
4628 |
|
4629 cssClass.AssignLiteral("blacklist"); |
|
4630 } else if (NS_ERROR_CONTENT_CRASHED == aError) { |
|
4631 errorPage.AssignLiteral("tabcrashed"); |
|
4632 error.AssignLiteral("tabcrashed"); |
|
4633 |
|
4634 nsCOMPtr<EventTarget> handler = mChromeEventHandler; |
|
4635 if (handler) { |
|
4636 nsCOMPtr<Element> element = do_QueryInterface(handler); |
|
4637 element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr); |
|
4638 } |
|
4639 |
|
4640 // DisplayLoadError requires a non-empty messageStr to proceed and call LoadErrorPage. |
|
4641 // If the page doesn't have a title, we will use a blank space which will be trimmed |
|
4642 // and thus treated as empty by the front-end. |
|
4643 if (messageStr.IsEmpty()) { |
|
4644 messageStr.Assign(NS_LITERAL_STRING(" ")); |
|
4645 } |
|
4646 } |
|
4647 else { |
|
4648 // Errors requiring simple formatting |
|
4649 switch (aError) { |
|
4650 case NS_ERROR_MALFORMED_URI: |
|
4651 // URI is malformed |
|
4652 error.AssignLiteral("malformedURI"); |
|
4653 break; |
|
4654 case NS_ERROR_REDIRECT_LOOP: |
|
4655 // Doc failed to load because the server generated too many redirects |
|
4656 error.AssignLiteral("redirectLoop"); |
|
4657 break; |
|
4658 case NS_ERROR_UNKNOWN_SOCKET_TYPE: |
|
4659 // Doc failed to load because PSM is not installed |
|
4660 error.AssignLiteral("unknownSocketType"); |
|
4661 break; |
|
4662 case NS_ERROR_NET_RESET: |
|
4663 // Doc failed to load because the server kept reseting the connection |
|
4664 // before we could read any data from it |
|
4665 error.AssignLiteral("netReset"); |
|
4666 break; |
|
4667 case NS_ERROR_DOCUMENT_NOT_CACHED: |
|
4668 // Doc failed to load because the cache does not contain a copy of |
|
4669 // the document. |
|
4670 error.AssignLiteral("notCached"); |
|
4671 break; |
|
4672 case NS_ERROR_OFFLINE: |
|
4673 // Doc failed to load because we are offline. |
|
4674 error.AssignLiteral("netOffline"); |
|
4675 break; |
|
4676 case NS_ERROR_DOCUMENT_IS_PRINTMODE: |
|
4677 // Doc navigation attempted while Printing or Print Preview |
|
4678 error.AssignLiteral("isprinting"); |
|
4679 break; |
|
4680 case NS_ERROR_PORT_ACCESS_NOT_ALLOWED: |
|
4681 // Port blocked for security reasons |
|
4682 addHostPort = true; |
|
4683 error.AssignLiteral("deniedPortAccess"); |
|
4684 break; |
|
4685 case NS_ERROR_UNKNOWN_PROXY_HOST: |
|
4686 // Proxy hostname could not be resolved. |
|
4687 error.AssignLiteral("proxyResolveFailure"); |
|
4688 break; |
|
4689 case NS_ERROR_PROXY_CONNECTION_REFUSED: |
|
4690 // Proxy connection was refused. |
|
4691 error.AssignLiteral("proxyConnectFailure"); |
|
4692 break; |
|
4693 case NS_ERROR_INVALID_CONTENT_ENCODING: |
|
4694 // Bad Content Encoding. |
|
4695 error.AssignLiteral("contentEncodingError"); |
|
4696 break; |
|
4697 case NS_ERROR_REMOTE_XUL: |
|
4698 { |
|
4699 error.AssignLiteral("remoteXUL"); |
|
4700 break; |
|
4701 } |
|
4702 case NS_ERROR_UNSAFE_CONTENT_TYPE: |
|
4703 // Channel refused to load from an unrecognized content type. |
|
4704 error.AssignLiteral("unsafeContentType"); |
|
4705 break; |
|
4706 case NS_ERROR_CORRUPTED_CONTENT: |
|
4707 // Broken Content Detected. e.g. Content-MD5 check failure. |
|
4708 error.AssignLiteral("corruptedContentError"); |
|
4709 break; |
|
4710 default: |
|
4711 break; |
|
4712 } |
|
4713 } |
|
4714 |
|
4715 // Test if the error should be displayed |
|
4716 if (error.IsEmpty()) { |
|
4717 return NS_OK; |
|
4718 } |
|
4719 |
|
4720 // Test if the error needs to be formatted |
|
4721 if (!messageStr.IsEmpty()) { |
|
4722 // already obtained message |
|
4723 } |
|
4724 else { |
|
4725 if (addHostPort) { |
|
4726 // Build up the host:port string. |
|
4727 nsAutoCString hostport; |
|
4728 if (aURI) { |
|
4729 aURI->GetHostPort(hostport); |
|
4730 } else { |
|
4731 hostport.AssignLiteral("?"); |
|
4732 } |
|
4733 CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]); |
|
4734 } |
|
4735 |
|
4736 nsAutoCString spec; |
|
4737 rv = NS_ERROR_NOT_AVAILABLE; |
|
4738 if (aURI) { |
|
4739 // displaying "file://" is aesthetically unpleasing and could even be |
|
4740 // confusing to the user |
|
4741 bool isFileURI = false; |
|
4742 rv = aURI->SchemeIs("file", &isFileURI); |
|
4743 if (NS_SUCCEEDED(rv) && isFileURI) |
|
4744 aURI->GetPath(spec); |
|
4745 else |
|
4746 aURI->GetSpec(spec); |
|
4747 |
|
4748 nsAutoCString charset; |
|
4749 // unescape and convert from origin charset |
|
4750 aURI->GetOriginCharset(charset); |
|
4751 nsCOMPtr<nsITextToSubURI> textToSubURI( |
|
4752 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv)); |
|
4753 if (NS_SUCCEEDED(rv)) { |
|
4754 rv = textToSubURI->UnEscapeURIForUI(charset, spec, formatStrs[formatStrCount]); |
|
4755 } |
|
4756 } else { |
|
4757 spec.AssignLiteral("?"); |
|
4758 } |
|
4759 if (NS_FAILED(rv)) |
|
4760 CopyUTF8toUTF16(spec, formatStrs[formatStrCount]); |
|
4761 rv = NS_OK; |
|
4762 ++formatStrCount; |
|
4763 |
|
4764 const char16_t *strs[kMaxFormatStrArgs]; |
|
4765 for (uint32_t i = 0; i < formatStrCount; i++) { |
|
4766 strs[i] = formatStrs[i].get(); |
|
4767 } |
|
4768 nsXPIDLString str; |
|
4769 rv = stringBundle->FormatStringFromName( |
|
4770 error.get(), |
|
4771 strs, formatStrCount, getter_Copies(str)); |
|
4772 NS_ENSURE_SUCCESS(rv, rv); |
|
4773 messageStr.Assign(str.get()); |
|
4774 } |
|
4775 |
|
4776 // Display the error as a page or an alert prompt |
|
4777 NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE); |
|
4778 |
|
4779 if (UseErrorPages()) { |
|
4780 // Display an error page |
|
4781 LoadErrorPage(aURI, aURL, errorPage.get(), error.get(), |
|
4782 messageStr.get(), cssClass.get(), aFailedChannel); |
|
4783 } |
|
4784 else |
|
4785 { |
|
4786 // The prompter reqires that our private window has a document (or it |
|
4787 // asserts). Satisfy that assertion now since GetDoc will force |
|
4788 // creation of one if it hasn't already been created. |
|
4789 if (mScriptGlobal) { |
|
4790 unused << mScriptGlobal->GetDoc(); |
|
4791 } |
|
4792 |
|
4793 // Display a message box |
|
4794 prompter->Alert(nullptr, messageStr.get()); |
|
4795 } |
|
4796 |
|
4797 return NS_OK; |
|
4798 } |
|
4799 |
|
4800 |
|
4801 NS_IMETHODIMP |
|
4802 nsDocShell::LoadErrorPage(nsIURI *aURI, const char16_t *aURL, |
|
4803 const char *aErrorPage, |
|
4804 const char16_t *aErrorType, |
|
4805 const char16_t *aDescription, |
|
4806 const char *aCSSClass, |
|
4807 nsIChannel* aFailedChannel) |
|
4808 { |
|
4809 #if defined(PR_LOGGING) && defined(DEBUG) |
|
4810 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) { |
|
4811 nsAutoCString spec; |
|
4812 aURI->GetSpec(spec); |
|
4813 |
|
4814 nsAutoCString chanName; |
|
4815 if (aFailedChannel) |
|
4816 aFailedChannel->GetName(chanName); |
|
4817 else |
|
4818 chanName.AssignLiteral("<no channel>"); |
|
4819 |
|
4820 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
4821 ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this, |
|
4822 spec.get(), NS_ConvertUTF16toUTF8(aURL).get(), chanName.get())); |
|
4823 } |
|
4824 #endif |
|
4825 mFailedChannel = aFailedChannel; |
|
4826 mFailedURI = aURI; |
|
4827 mFailedLoadType = mLoadType; |
|
4828 |
|
4829 if (mLSHE) { |
|
4830 // Abandon mLSHE's BFCache entry and create a new one. This way, if |
|
4831 // we go back or forward to another SHEntry with the same doc |
|
4832 // identifier, the error page won't persist. |
|
4833 mLSHE->AbandonBFCacheEntry(); |
|
4834 } |
|
4835 |
|
4836 nsAutoCString url; |
|
4837 nsAutoCString charset; |
|
4838 if (aURI) |
|
4839 { |
|
4840 nsresult rv = aURI->GetSpec(url); |
|
4841 NS_ENSURE_SUCCESS(rv, rv); |
|
4842 rv = aURI->GetOriginCharset(charset); |
|
4843 NS_ENSURE_SUCCESS(rv, rv); |
|
4844 } |
|
4845 else if (aURL) |
|
4846 { |
|
4847 CopyUTF16toUTF8(aURL, url); |
|
4848 } |
|
4849 else |
|
4850 { |
|
4851 return NS_ERROR_INVALID_POINTER; |
|
4852 } |
|
4853 |
|
4854 // Create a URL to pass all the error information through to the page. |
|
4855 |
|
4856 #undef SAFE_ESCAPE |
|
4857 #define SAFE_ESCAPE(cstring, escArg1, escArg2) \ |
|
4858 { \ |
|
4859 char* s = nsEscape(escArg1, escArg2); \ |
|
4860 if (!s) \ |
|
4861 return NS_ERROR_OUT_OF_MEMORY; \ |
|
4862 cstring.Adopt(s); \ |
|
4863 } |
|
4864 nsCString escapedUrl, escapedCharset, escapedError, escapedDescription, |
|
4865 escapedCSSClass; |
|
4866 SAFE_ESCAPE(escapedUrl, url.get(), url_Path); |
|
4867 SAFE_ESCAPE(escapedCharset, charset.get(), url_Path); |
|
4868 SAFE_ESCAPE(escapedError, |
|
4869 NS_ConvertUTF16toUTF8(aErrorType).get(), url_Path); |
|
4870 SAFE_ESCAPE(escapedDescription, |
|
4871 NS_ConvertUTF16toUTF8(aDescription).get(), url_Path); |
|
4872 if (aCSSClass) { |
|
4873 SAFE_ESCAPE(escapedCSSClass, aCSSClass, url_Path); |
|
4874 } |
|
4875 nsCString errorPageUrl("about:"); |
|
4876 errorPageUrl.AppendASCII(aErrorPage); |
|
4877 errorPageUrl.AppendLiteral("?e="); |
|
4878 |
|
4879 errorPageUrl.AppendASCII(escapedError.get()); |
|
4880 errorPageUrl.AppendLiteral("&u="); |
|
4881 errorPageUrl.AppendASCII(escapedUrl.get()); |
|
4882 if (!escapedCSSClass.IsEmpty()) { |
|
4883 errorPageUrl.AppendLiteral("&s="); |
|
4884 errorPageUrl.AppendASCII(escapedCSSClass.get()); |
|
4885 } |
|
4886 errorPageUrl.AppendLiteral("&c="); |
|
4887 errorPageUrl.AppendASCII(escapedCharset.get()); |
|
4888 |
|
4889 nsAutoCString frameType(FrameTypeToString(mFrameType)); |
|
4890 errorPageUrl.AppendLiteral("&f="); |
|
4891 errorPageUrl.AppendASCII(frameType.get()); |
|
4892 |
|
4893 // Append the manifest URL if the error comes from an app. |
|
4894 nsString manifestURL; |
|
4895 nsresult rv = GetAppManifestURL(manifestURL); |
|
4896 if (manifestURL.Length() > 0) { |
|
4897 nsCString manifestParam; |
|
4898 SAFE_ESCAPE(manifestParam, |
|
4899 NS_ConvertUTF16toUTF8(manifestURL).get(), |
|
4900 url_Path); |
|
4901 errorPageUrl.AppendLiteral("&m="); |
|
4902 errorPageUrl.AppendASCII(manifestParam.get()); |
|
4903 } |
|
4904 |
|
4905 // netError.xhtml's getDescription only handles the "d" parameter at the |
|
4906 // end of the URL, so append it last. |
|
4907 errorPageUrl.AppendLiteral("&d="); |
|
4908 errorPageUrl.AppendASCII(escapedDescription.get()); |
|
4909 |
|
4910 nsCOMPtr<nsIURI> errorPageURI; |
|
4911 rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl); |
|
4912 NS_ENSURE_SUCCESS(rv, rv); |
|
4913 |
|
4914 return InternalLoad(errorPageURI, nullptr, nullptr, |
|
4915 INTERNAL_LOAD_FLAGS_INHERIT_OWNER, nullptr, nullptr, |
|
4916 NullString(), nullptr, nullptr, LOAD_ERROR_PAGE, |
|
4917 nullptr, true, NullString(), this, nullptr, nullptr, |
|
4918 nullptr); |
|
4919 } |
|
4920 |
|
4921 |
|
4922 NS_IMETHODIMP |
|
4923 nsDocShell::Reload(uint32_t aReloadFlags) |
|
4924 { |
|
4925 if (!IsNavigationAllowed()) { |
|
4926 return NS_OK; // JS may not handle returning of an error code |
|
4927 } |
|
4928 nsresult rv; |
|
4929 NS_ASSERTION(((aReloadFlags & 0xf) == 0), |
|
4930 "Reload command not updated to use load flags!"); |
|
4931 NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0, |
|
4932 "Don't pass these flags to Reload"); |
|
4933 |
|
4934 uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags); |
|
4935 NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG); |
|
4936 |
|
4937 // Send notifications to the HistoryListener if any, about the impending reload |
|
4938 nsCOMPtr<nsISHistory> rootSH; |
|
4939 rv = GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
4940 nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH)); |
|
4941 bool canReload = true; |
|
4942 if (rootSH) { |
|
4943 shistInt->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload); |
|
4944 } |
|
4945 |
|
4946 if (!canReload) |
|
4947 return NS_OK; |
|
4948 |
|
4949 /* If you change this part of code, make sure bug 45297 does not re-occur */ |
|
4950 if (mOSHE) { |
|
4951 rv = LoadHistoryEntry(mOSHE, loadType); |
|
4952 } |
|
4953 else if (mLSHE) { // In case a reload happened before the current load is done |
|
4954 rv = LoadHistoryEntry(mLSHE, loadType); |
|
4955 } |
|
4956 else { |
|
4957 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
4958 |
|
4959 // Do not inherit owner from document |
|
4960 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE; |
|
4961 nsAutoString srcdoc; |
|
4962 nsIPrincipal* principal = nullptr; |
|
4963 nsAutoString contentTypeHint; |
|
4964 nsCOMPtr<nsIURI> baseURI; |
|
4965 if (doc) { |
|
4966 principal = doc->NodePrincipal(); |
|
4967 doc->GetContentType(contentTypeHint); |
|
4968 |
|
4969 if (doc->IsSrcdocDocument()) { |
|
4970 doc->GetSrcdocData(srcdoc); |
|
4971 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; |
|
4972 baseURI = doc->GetBaseURI(); |
|
4973 } |
|
4974 } |
|
4975 rv = InternalLoad(mCurrentURI, |
|
4976 mReferrerURI, |
|
4977 principal, |
|
4978 flags, |
|
4979 nullptr, // No window target |
|
4980 NS_LossyConvertUTF16toASCII(contentTypeHint).get(), |
|
4981 NullString(), // No forced download |
|
4982 nullptr, // No post data |
|
4983 nullptr, // No headers data |
|
4984 loadType, // Load type |
|
4985 nullptr, // No SHEntry |
|
4986 true, |
|
4987 srcdoc, // srcdoc argument for iframe |
|
4988 this, // For reloads we are the source |
|
4989 baseURI, |
|
4990 nullptr, // No nsIDocShell |
|
4991 nullptr); // No nsIRequest |
|
4992 } |
|
4993 |
|
4994 return rv; |
|
4995 } |
|
4996 |
|
4997 NS_IMETHODIMP |
|
4998 nsDocShell::Stop(uint32_t aStopFlags) |
|
4999 { |
|
5000 // Revoke any pending event related to content viewer restoration |
|
5001 mRestorePresentationEvent.Revoke(); |
|
5002 |
|
5003 if (mLoadType == LOAD_ERROR_PAGE) { |
|
5004 if (mLSHE) { |
|
5005 // Since error page loads never unset mLSHE, do so now |
|
5006 SetHistoryEntry(&mOSHE, mLSHE); |
|
5007 SetHistoryEntry(&mLSHE, nullptr); |
|
5008 } |
|
5009 |
|
5010 mFailedChannel = nullptr; |
|
5011 mFailedURI = nullptr; |
|
5012 } |
|
5013 |
|
5014 if (nsIWebNavigation::STOP_CONTENT & aStopFlags) { |
|
5015 // Stop the document loading |
|
5016 if (mContentViewer) { |
|
5017 nsCOMPtr<nsIContentViewer> cv = mContentViewer; |
|
5018 cv->Stop(); |
|
5019 } |
|
5020 } |
|
5021 |
|
5022 if (nsIWebNavigation::STOP_NETWORK & aStopFlags) { |
|
5023 // Suspend any timers that were set for this loader. We'll clear |
|
5024 // them out for good in CreateContentViewer. |
|
5025 if (mRefreshURIList) { |
|
5026 SuspendRefreshURIs(); |
|
5027 mSavedRefreshURIList.swap(mRefreshURIList); |
|
5028 mRefreshURIList = nullptr; |
|
5029 } |
|
5030 |
|
5031 // XXXbz We could also pass |this| to nsIURILoader::Stop. That will |
|
5032 // just call Stop() on us as an nsIDocumentLoader... We need fewer |
|
5033 // redundant apis! |
|
5034 Stop(); |
|
5035 } |
|
5036 |
|
5037 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
5038 while (iter.HasMore()) { |
|
5039 nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext())); |
|
5040 if (shellAsNav) |
|
5041 shellAsNav->Stop(aStopFlags); |
|
5042 } |
|
5043 |
|
5044 return NS_OK; |
|
5045 } |
|
5046 |
|
5047 NS_IMETHODIMP |
|
5048 nsDocShell::GetDocument(nsIDOMDocument ** aDocument) |
|
5049 { |
|
5050 NS_ENSURE_ARG_POINTER(aDocument); |
|
5051 NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE); |
|
5052 |
|
5053 return mContentViewer->GetDOMDocument(aDocument); |
|
5054 } |
|
5055 |
|
5056 NS_IMETHODIMP |
|
5057 nsDocShell::GetCurrentURI(nsIURI ** aURI) |
|
5058 { |
|
5059 NS_ENSURE_ARG_POINTER(aURI); |
|
5060 |
|
5061 if (mCurrentURI) { |
|
5062 return NS_EnsureSafeToReturn(mCurrentURI, aURI); |
|
5063 } |
|
5064 |
|
5065 *aURI = nullptr; |
|
5066 return NS_OK; |
|
5067 } |
|
5068 |
|
5069 NS_IMETHODIMP |
|
5070 nsDocShell::GetReferringURI(nsIURI ** aURI) |
|
5071 { |
|
5072 NS_ENSURE_ARG_POINTER(aURI); |
|
5073 |
|
5074 *aURI = mReferrerURI; |
|
5075 NS_IF_ADDREF(*aURI); |
|
5076 |
|
5077 return NS_OK; |
|
5078 } |
|
5079 |
|
5080 NS_IMETHODIMP |
|
5081 nsDocShell::SetSessionHistory(nsISHistory * aSessionHistory) |
|
5082 { |
|
5083 |
|
5084 NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE); |
|
5085 // make sure that we are the root docshell and |
|
5086 // set a handle to root docshell in SH. |
|
5087 |
|
5088 nsCOMPtr<nsIDocShellTreeItem> root; |
|
5089 /* Get the root docshell. If *this* is the root docshell |
|
5090 * then save a handle to *this* in SH. SH needs it to do |
|
5091 * traversions thro' its entries |
|
5092 */ |
|
5093 GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
5094 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); |
|
5095 if (root.get() == static_cast<nsIDocShellTreeItem *>(this)) { |
|
5096 mSessionHistory = aSessionHistory; |
|
5097 nsCOMPtr<nsISHistoryInternal> |
|
5098 shPrivate(do_QueryInterface(mSessionHistory)); |
|
5099 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE); |
|
5100 shPrivate->SetRootDocShell(this); |
|
5101 return NS_OK; |
|
5102 } |
|
5103 return NS_ERROR_FAILURE; |
|
5104 |
|
5105 } |
|
5106 |
|
5107 |
|
5108 NS_IMETHODIMP |
|
5109 nsDocShell::GetSessionHistory(nsISHistory ** aSessionHistory) |
|
5110 { |
|
5111 NS_ENSURE_ARG_POINTER(aSessionHistory); |
|
5112 *aSessionHistory = mSessionHistory; |
|
5113 NS_IF_ADDREF(*aSessionHistory); |
|
5114 return NS_OK; |
|
5115 } |
|
5116 |
|
5117 //***************************************************************************** |
|
5118 // nsDocShell::nsIWebPageDescriptor |
|
5119 //***************************************************************************** |
|
5120 NS_IMETHODIMP |
|
5121 nsDocShell::LoadPage(nsISupports *aPageDescriptor, uint32_t aDisplayType) |
|
5122 { |
|
5123 nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor)); |
|
5124 |
|
5125 // Currently, the opaque 'page descriptor' is an nsISHEntry... |
|
5126 if (!shEntryIn) { |
|
5127 return NS_ERROR_INVALID_POINTER; |
|
5128 } |
|
5129 |
|
5130 // Now clone shEntryIn, since we might end up modifying it later on, and we |
|
5131 // want a page descriptor to be reusable. |
|
5132 nsCOMPtr<nsISHEntry> shEntry; |
|
5133 nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry)); |
|
5134 NS_ENSURE_SUCCESS(rv, rv); |
|
5135 |
|
5136 // Give our cloned shEntry a new bfcache entry so this load is independent |
|
5137 // of all other loads. (This is important, in particular, for bugs 582795 |
|
5138 // and 585298.) |
|
5139 rv = shEntry->AbandonBFCacheEntry(); |
|
5140 NS_ENSURE_SUCCESS(rv, rv); |
|
5141 |
|
5142 // |
|
5143 // load the page as view-source |
|
5144 // |
|
5145 if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) { |
|
5146 nsCOMPtr<nsIURI> oldUri, newUri; |
|
5147 nsCString spec, newSpec; |
|
5148 |
|
5149 // Create a new view-source URI and replace the original. |
|
5150 rv = shEntry->GetURI(getter_AddRefs(oldUri)); |
|
5151 if (NS_FAILED(rv)) |
|
5152 return rv; |
|
5153 |
|
5154 oldUri->GetSpec(spec); |
|
5155 newSpec.AppendLiteral("view-source:"); |
|
5156 newSpec.Append(spec); |
|
5157 |
|
5158 rv = NS_NewURI(getter_AddRefs(newUri), newSpec); |
|
5159 if (NS_FAILED(rv)) { |
|
5160 return rv; |
|
5161 } |
|
5162 shEntry->SetURI(newUri); |
|
5163 } |
|
5164 |
|
5165 rv = LoadHistoryEntry(shEntry, LOAD_HISTORY); |
|
5166 return rv; |
|
5167 } |
|
5168 |
|
5169 NS_IMETHODIMP |
|
5170 nsDocShell::GetCurrentDescriptor(nsISupports **aPageDescriptor) |
|
5171 { |
|
5172 NS_PRECONDITION(aPageDescriptor, "Null out param?"); |
|
5173 |
|
5174 *aPageDescriptor = nullptr; |
|
5175 |
|
5176 nsISHEntry* src = mOSHE ? mOSHE : mLSHE; |
|
5177 if (src) { |
|
5178 nsCOMPtr<nsISHEntry> dest; |
|
5179 |
|
5180 nsresult rv = src->Clone(getter_AddRefs(dest)); |
|
5181 if (NS_FAILED(rv)) { |
|
5182 return rv; |
|
5183 } |
|
5184 |
|
5185 // null out inappropriate cloned attributes... |
|
5186 dest->SetParent(nullptr); |
|
5187 dest->SetIsSubFrame(false); |
|
5188 |
|
5189 return CallQueryInterface(dest, aPageDescriptor); |
|
5190 } |
|
5191 |
|
5192 return NS_ERROR_NOT_AVAILABLE; |
|
5193 } |
|
5194 |
|
5195 |
|
5196 //***************************************************************************** |
|
5197 // nsDocShell::nsIBaseWindow |
|
5198 //***************************************************************************** |
|
5199 |
|
5200 NS_IMETHODIMP |
|
5201 nsDocShell::InitWindow(nativeWindow parentNativeWindow, |
|
5202 nsIWidget * parentWidget, int32_t x, int32_t y, |
|
5203 int32_t cx, int32_t cy) |
|
5204 { |
|
5205 SetParentWidget(parentWidget); |
|
5206 SetPositionAndSize(x, y, cx, cy, false); |
|
5207 |
|
5208 return NS_OK; |
|
5209 } |
|
5210 |
|
5211 NS_IMETHODIMP |
|
5212 nsDocShell::Create() |
|
5213 { |
|
5214 if (mCreated) { |
|
5215 // We've already been created |
|
5216 return NS_OK; |
|
5217 } |
|
5218 |
|
5219 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome, |
|
5220 "Unexpected item type in docshell"); |
|
5221 |
|
5222 NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); |
|
5223 mCreated = true; |
|
5224 |
|
5225 mAllowSubframes = |
|
5226 Preferences::GetBool("browser.frames.enabled", mAllowSubframes); |
|
5227 |
|
5228 if (gValidateOrigin == 0xffffffff) { |
|
5229 // Check pref to see if we should prevent frameset spoofing |
|
5230 gValidateOrigin = |
|
5231 Preferences::GetBool("browser.frame.validate_origin", true); |
|
5232 } |
|
5233 |
|
5234 // Should we use XUL error pages instead of alerts if possible? |
|
5235 mUseErrorPages = |
|
5236 Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages); |
|
5237 |
|
5238 if(!gAddedPreferencesVarCache) { |
|
5239 Preferences::AddBoolVarCache(&sUseErrorPages, |
|
5240 "browser.xul.error_pages.enabled", |
|
5241 mUseErrorPages); |
|
5242 gAddedPreferencesVarCache = true; |
|
5243 } |
|
5244 |
|
5245 mDeviceSizeIsPageSize = |
|
5246 Preferences::GetBool("docshell.device_size_is_page_size", |
|
5247 mDeviceSizeIsPageSize); |
|
5248 |
|
5249 nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); |
|
5250 if (serv) { |
|
5251 const char* msg = mItemType == typeContent ? |
|
5252 NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE; |
|
5253 serv->NotifyObservers(GetAsSupports(this), msg, nullptr); |
|
5254 } |
|
5255 |
|
5256 return NS_OK; |
|
5257 } |
|
5258 |
|
5259 NS_IMETHODIMP |
|
5260 nsDocShell::Destroy() |
|
5261 { |
|
5262 NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome, |
|
5263 "Unexpected item type in docshell"); |
|
5264 |
|
5265 if (!mIsBeingDestroyed) { |
|
5266 nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); |
|
5267 if (serv) { |
|
5268 const char* msg = mItemType == typeContent ? |
|
5269 NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY; |
|
5270 serv->NotifyObservers(GetAsSupports(this), msg, nullptr); |
|
5271 } |
|
5272 } |
|
5273 |
|
5274 mIsBeingDestroyed = true; |
|
5275 |
|
5276 // Remove our pref observers |
|
5277 if (mObserveErrorPages) { |
|
5278 mObserveErrorPages = false; |
|
5279 } |
|
5280 |
|
5281 // Make sure to blow away our mLoadingURI just in case. No loads |
|
5282 // from inside this pagehide. |
|
5283 mLoadingURI = nullptr; |
|
5284 |
|
5285 // Fire unload event before we blow anything away. |
|
5286 (void) FirePageHideNotification(true); |
|
5287 |
|
5288 // Clear pointers to any detached nsEditorData that's lying |
|
5289 // around in shistory entries. Breaks cycle. See bug 430921. |
|
5290 if (mOSHE) |
|
5291 mOSHE->SetEditorData(nullptr); |
|
5292 if (mLSHE) |
|
5293 mLSHE->SetEditorData(nullptr); |
|
5294 |
|
5295 // Note: mContentListener can be null if Init() failed and we're being |
|
5296 // called from the destructor. |
|
5297 if (mContentListener) { |
|
5298 mContentListener->DropDocShellreference(); |
|
5299 mContentListener->SetParentContentListener(nullptr); |
|
5300 // Note that we do NOT set mContentListener to null here; that |
|
5301 // way if someone tries to do a load in us after this point |
|
5302 // the nsDSURIContentListener will block it. All of which |
|
5303 // means that we should do this before calling Stop(), of |
|
5304 // course. |
|
5305 } |
|
5306 |
|
5307 // Stop any URLs that are currently being loaded... |
|
5308 Stop(nsIWebNavigation::STOP_ALL); |
|
5309 |
|
5310 mEditorData = nullptr; |
|
5311 |
|
5312 mTransferableHookData = nullptr; |
|
5313 |
|
5314 // Save the state of the current document, before destroying the window. |
|
5315 // This is needed to capture the state of a frameset when the new document |
|
5316 // causes the frameset to be destroyed... |
|
5317 PersistLayoutHistoryState(); |
|
5318 |
|
5319 // Remove this docshell from its parent's child list |
|
5320 nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem = |
|
5321 do_QueryInterface(GetAsSupports(mParent)); |
|
5322 if (docShellParentAsItem) |
|
5323 docShellParentAsItem->RemoveChild(this); |
|
5324 |
|
5325 if (mContentViewer) { |
|
5326 mContentViewer->Close(nullptr); |
|
5327 mContentViewer->Destroy(); |
|
5328 mContentViewer = nullptr; |
|
5329 } |
|
5330 |
|
5331 nsDocLoader::Destroy(); |
|
5332 |
|
5333 mParentWidget = nullptr; |
|
5334 mCurrentURI = nullptr; |
|
5335 |
|
5336 if (mScriptGlobal) { |
|
5337 mScriptGlobal->DetachFromDocShell(); |
|
5338 mScriptGlobal = nullptr; |
|
5339 } |
|
5340 |
|
5341 if (mSessionHistory) { |
|
5342 // We want to destroy these content viewers now rather than |
|
5343 // letting their destruction wait for the session history |
|
5344 // entries to get garbage collected. (Bug 488394) |
|
5345 nsCOMPtr<nsISHistoryInternal> shPrivate = |
|
5346 do_QueryInterface(mSessionHistory); |
|
5347 if (shPrivate) { |
|
5348 shPrivate->EvictAllContentViewers(); |
|
5349 } |
|
5350 mSessionHistory = nullptr; |
|
5351 } |
|
5352 |
|
5353 SetTreeOwner(nullptr); |
|
5354 |
|
5355 mOnePermittedSandboxedNavigator = nullptr; |
|
5356 |
|
5357 // required to break ref cycle |
|
5358 mSecurityUI = nullptr; |
|
5359 |
|
5360 // Cancel any timers that were set for this docshell; this is needed |
|
5361 // to break the cycle between us and the timers. |
|
5362 CancelRefreshURITimers(); |
|
5363 |
|
5364 if (mInPrivateBrowsing) { |
|
5365 mInPrivateBrowsing = false; |
|
5366 if (mAffectPrivateSessionLifetime) { |
|
5367 DecreasePrivateDocShellCount(); |
|
5368 } |
|
5369 } |
|
5370 |
|
5371 return NS_OK; |
|
5372 } |
|
5373 |
|
5374 NS_IMETHODIMP |
|
5375 nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) |
|
5376 { |
|
5377 if (mParentWidget) { |
|
5378 *aScale = mParentWidget->GetDefaultScale().scale; |
|
5379 return NS_OK; |
|
5380 } |
|
5381 |
|
5382 nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner)); |
|
5383 if (ownerWindow) { |
|
5384 return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale); |
|
5385 } |
|
5386 |
|
5387 *aScale = 1.0; |
|
5388 return NS_OK; |
|
5389 } |
|
5390 |
|
5391 NS_IMETHODIMP |
|
5392 nsDocShell::SetPosition(int32_t x, int32_t y) |
|
5393 { |
|
5394 mBounds.x = x; |
|
5395 mBounds.y = y; |
|
5396 |
|
5397 if (mContentViewer) |
|
5398 NS_ENSURE_SUCCESS(mContentViewer->Move(x, y), NS_ERROR_FAILURE); |
|
5399 |
|
5400 return NS_OK; |
|
5401 } |
|
5402 |
|
5403 NS_IMETHODIMP |
|
5404 nsDocShell::GetPosition(int32_t * aX, int32_t * aY) |
|
5405 { |
|
5406 int32_t dummyHolder; |
|
5407 return GetPositionAndSize(aX, aY, &dummyHolder, &dummyHolder); |
|
5408 } |
|
5409 |
|
5410 NS_IMETHODIMP |
|
5411 nsDocShell::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) |
|
5412 { |
|
5413 int32_t x = 0, y = 0; |
|
5414 GetPosition(&x, &y); |
|
5415 return SetPositionAndSize(x, y, aCX, aCY, aRepaint); |
|
5416 } |
|
5417 |
|
5418 NS_IMETHODIMP |
|
5419 nsDocShell::GetSize(int32_t * aCX, int32_t * aCY) |
|
5420 { |
|
5421 int32_t dummyHolder; |
|
5422 return GetPositionAndSize(&dummyHolder, &dummyHolder, aCX, aCY); |
|
5423 } |
|
5424 |
|
5425 NS_IMETHODIMP |
|
5426 nsDocShell::SetPositionAndSize(int32_t x, int32_t y, int32_t cx, |
|
5427 int32_t cy, bool fRepaint) |
|
5428 { |
|
5429 mBounds.x = x; |
|
5430 mBounds.y = y; |
|
5431 mBounds.width = cx; |
|
5432 mBounds.height = cy; |
|
5433 |
|
5434 // Hold strong ref, since SetBounds can make us null out mContentViewer |
|
5435 nsCOMPtr<nsIContentViewer> viewer = mContentViewer; |
|
5436 if (viewer) { |
|
5437 //XXX Border figured in here or is that handled elsewhere? |
|
5438 NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE); |
|
5439 } |
|
5440 |
|
5441 return NS_OK; |
|
5442 } |
|
5443 |
|
5444 NS_IMETHODIMP |
|
5445 nsDocShell::GetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx, |
|
5446 int32_t * cy) |
|
5447 { |
|
5448 if (mParentWidget) { |
|
5449 // ensure size is up-to-date if window has changed resolution |
|
5450 nsIntRect r; |
|
5451 mParentWidget->GetClientBounds(r); |
|
5452 SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, false); |
|
5453 } |
|
5454 |
|
5455 // We should really consider just getting this information from |
|
5456 // our window instead of duplicating the storage and code... |
|
5457 if (cx || cy) { |
|
5458 // Caller wants to know our size; make sure to give them up to |
|
5459 // date information. |
|
5460 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent))); |
|
5461 if (doc) { |
|
5462 doc->FlushPendingNotifications(Flush_Layout); |
|
5463 } |
|
5464 } |
|
5465 |
|
5466 DoGetPositionAndSize(x, y, cx, cy); |
|
5467 return NS_OK; |
|
5468 } |
|
5469 |
|
5470 void |
|
5471 nsDocShell::DoGetPositionAndSize(int32_t * x, int32_t * y, int32_t * cx, |
|
5472 int32_t * cy) |
|
5473 { |
|
5474 if (x) |
|
5475 *x = mBounds.x; |
|
5476 if (y) |
|
5477 *y = mBounds.y; |
|
5478 if (cx) |
|
5479 *cx = mBounds.width; |
|
5480 if (cy) |
|
5481 *cy = mBounds.height; |
|
5482 } |
|
5483 |
|
5484 NS_IMETHODIMP |
|
5485 nsDocShell::Repaint(bool aForce) |
|
5486 { |
|
5487 nsCOMPtr<nsIPresShell> presShell =GetPresShell(); |
|
5488 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); |
|
5489 |
|
5490 nsViewManager* viewManager = presShell->GetViewManager(); |
|
5491 NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE); |
|
5492 |
|
5493 viewManager->InvalidateAllViews(); |
|
5494 return NS_OK; |
|
5495 } |
|
5496 |
|
5497 NS_IMETHODIMP |
|
5498 nsDocShell::GetParentWidget(nsIWidget ** parentWidget) |
|
5499 { |
|
5500 NS_ENSURE_ARG_POINTER(parentWidget); |
|
5501 |
|
5502 *parentWidget = mParentWidget; |
|
5503 NS_IF_ADDREF(*parentWidget); |
|
5504 |
|
5505 return NS_OK; |
|
5506 } |
|
5507 |
|
5508 NS_IMETHODIMP |
|
5509 nsDocShell::SetParentWidget(nsIWidget * aParentWidget) |
|
5510 { |
|
5511 mParentWidget = aParentWidget; |
|
5512 |
|
5513 return NS_OK; |
|
5514 } |
|
5515 |
|
5516 NS_IMETHODIMP |
|
5517 nsDocShell::GetParentNativeWindow(nativeWindow * parentNativeWindow) |
|
5518 { |
|
5519 NS_ENSURE_ARG_POINTER(parentNativeWindow); |
|
5520 |
|
5521 if (mParentWidget) |
|
5522 *parentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET); |
|
5523 else |
|
5524 *parentNativeWindow = nullptr; |
|
5525 |
|
5526 return NS_OK; |
|
5527 } |
|
5528 |
|
5529 NS_IMETHODIMP |
|
5530 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow) |
|
5531 { |
|
5532 return NS_ERROR_NOT_IMPLEMENTED; |
|
5533 } |
|
5534 |
|
5535 NS_IMETHODIMP |
|
5536 nsDocShell::GetNativeHandle(nsAString& aNativeHandle) |
|
5537 { |
|
5538 // the nativeHandle should be accessed from nsIXULWindow |
|
5539 return NS_ERROR_NOT_IMPLEMENTED; |
|
5540 } |
|
5541 |
|
5542 NS_IMETHODIMP |
|
5543 nsDocShell::GetVisibility(bool * aVisibility) |
|
5544 { |
|
5545 NS_ENSURE_ARG_POINTER(aVisibility); |
|
5546 |
|
5547 *aVisibility = false; |
|
5548 |
|
5549 if (!mContentViewer) |
|
5550 return NS_OK; |
|
5551 |
|
5552 nsCOMPtr<nsIPresShell> presShell = GetPresShell(); |
|
5553 if (!presShell) |
|
5554 return NS_OK; |
|
5555 |
|
5556 // get the view manager |
|
5557 nsViewManager* vm = presShell->GetViewManager(); |
|
5558 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE); |
|
5559 |
|
5560 // get the root view |
|
5561 nsView *view = vm->GetRootView(); // views are not ref counted |
|
5562 NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); |
|
5563 |
|
5564 // if our root view is hidden, we are not visible |
|
5565 if (view->GetVisibility() == nsViewVisibility_kHide) |
|
5566 return NS_OK; |
|
5567 |
|
5568 // otherwise, we must walk up the document and view trees checking |
|
5569 // for a hidden view, unless we're an off screen browser, which |
|
5570 // would make this test meaningless. |
|
5571 |
|
5572 nsCOMPtr<nsIDocShellTreeItem> treeItem = this; |
|
5573 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
5574 treeItem->GetParent(getter_AddRefs(parentItem)); |
|
5575 while (parentItem) { |
|
5576 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItem)); |
|
5577 presShell = docShell->GetPresShell(); |
|
5578 |
|
5579 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentItem); |
|
5580 nsCOMPtr<nsIPresShell> pPresShell = parentDS->GetPresShell(); |
|
5581 |
|
5582 // Null-check for crash in bug 267804 |
|
5583 if (!pPresShell) { |
|
5584 NS_NOTREACHED("parent docshell has null pres shell"); |
|
5585 return NS_OK; |
|
5586 } |
|
5587 |
|
5588 nsIContent *shellContent = |
|
5589 pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument()); |
|
5590 NS_ASSERTION(shellContent, "subshell not in the map"); |
|
5591 |
|
5592 nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nullptr; |
|
5593 bool isDocShellOffScreen = false; |
|
5594 docShell->GetIsOffScreenBrowser(&isDocShellOffScreen); |
|
5595 if (frame && |
|
5596 !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) && |
|
5597 !isDocShellOffScreen) { |
|
5598 return NS_OK; |
|
5599 } |
|
5600 |
|
5601 treeItem = parentItem; |
|
5602 treeItem->GetParent(getter_AddRefs(parentItem)); |
|
5603 } |
|
5604 |
|
5605 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner)); |
|
5606 if (!treeOwnerAsWin) { |
|
5607 *aVisibility = true; |
|
5608 return NS_OK; |
|
5609 } |
|
5610 |
|
5611 // Check with the tree owner as well to give embedders a chance to |
|
5612 // expose visibility as well. |
|
5613 return treeOwnerAsWin->GetVisibility(aVisibility); |
|
5614 } |
|
5615 |
|
5616 NS_IMETHODIMP |
|
5617 nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen) |
|
5618 { |
|
5619 mIsOffScreenBrowser = aIsOffScreen; |
|
5620 return NS_OK; |
|
5621 } |
|
5622 |
|
5623 NS_IMETHODIMP |
|
5624 nsDocShell::GetIsOffScreenBrowser(bool *aIsOffScreen) |
|
5625 { |
|
5626 *aIsOffScreen = mIsOffScreenBrowser; |
|
5627 return NS_OK; |
|
5628 } |
|
5629 |
|
5630 NS_IMETHODIMP |
|
5631 nsDocShell::SetIsActive(bool aIsActive) |
|
5632 { |
|
5633 // We disallow setting active on chrome docshells. |
|
5634 if (mItemType == nsIDocShellTreeItem::typeChrome) |
|
5635 return NS_ERROR_INVALID_ARG; |
|
5636 |
|
5637 // Keep track ourselves. |
|
5638 mIsActive = aIsActive; |
|
5639 |
|
5640 // Tell the PresShell about it. |
|
5641 nsCOMPtr<nsIPresShell> pshell = GetPresShell(); |
|
5642 if (pshell) |
|
5643 pshell->SetIsActive(aIsActive); |
|
5644 |
|
5645 // Tell the window about it |
|
5646 if (mScriptGlobal) { |
|
5647 mScriptGlobal->SetIsBackground(!aIsActive); |
|
5648 if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) { |
|
5649 doc->PostVisibilityUpdateEvent(); |
|
5650 } |
|
5651 } |
|
5652 |
|
5653 // Recursively tell all of our children, but don't tell <iframe mozbrowser> |
|
5654 // children; they handle their state separately. |
|
5655 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
5656 while (iter.HasMore()) { |
|
5657 nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext()); |
|
5658 if (!docshell) { |
|
5659 continue; |
|
5660 } |
|
5661 |
|
5662 if (!docshell->GetIsBrowserOrApp()) { |
|
5663 docshell->SetIsActive(aIsActive); |
|
5664 } |
|
5665 } |
|
5666 |
|
5667 return NS_OK; |
|
5668 } |
|
5669 |
|
5670 NS_IMETHODIMP |
|
5671 nsDocShell::GetIsActive(bool *aIsActive) |
|
5672 { |
|
5673 *aIsActive = mIsActive; |
|
5674 return NS_OK; |
|
5675 } |
|
5676 |
|
5677 NS_IMETHODIMP |
|
5678 nsDocShell::SetIsAppTab(bool aIsAppTab) |
|
5679 { |
|
5680 mIsAppTab = aIsAppTab; |
|
5681 return NS_OK; |
|
5682 } |
|
5683 |
|
5684 NS_IMETHODIMP |
|
5685 nsDocShell::GetIsAppTab(bool *aIsAppTab) |
|
5686 { |
|
5687 *aIsAppTab = mIsAppTab; |
|
5688 return NS_OK; |
|
5689 } |
|
5690 |
|
5691 NS_IMETHODIMP |
|
5692 nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags) |
|
5693 { |
|
5694 mSandboxFlags = aSandboxFlags; |
|
5695 return NS_OK; |
|
5696 } |
|
5697 |
|
5698 NS_IMETHODIMP |
|
5699 nsDocShell::GetSandboxFlags(uint32_t *aSandboxFlags) |
|
5700 { |
|
5701 *aSandboxFlags = mSandboxFlags; |
|
5702 return NS_OK; |
|
5703 } |
|
5704 |
|
5705 NS_IMETHODIMP |
|
5706 nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator) |
|
5707 { |
|
5708 if (mOnePermittedSandboxedNavigator) { |
|
5709 NS_ERROR("One Permitted Sandboxed Navigator should only be set once."); |
|
5710 return NS_OK; |
|
5711 } |
|
5712 |
|
5713 mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator); |
|
5714 NS_ASSERTION(mOnePermittedSandboxedNavigator, |
|
5715 "One Permitted Sandboxed Navigator must support weak references."); |
|
5716 |
|
5717 return NS_OK; |
|
5718 } |
|
5719 |
|
5720 NS_IMETHODIMP |
|
5721 nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator) |
|
5722 { |
|
5723 NS_ENSURE_ARG_POINTER(aSandboxedNavigator); |
|
5724 nsCOMPtr<nsIDocShell> permittedNavigator = |
|
5725 do_QueryReferent(mOnePermittedSandboxedNavigator); |
|
5726 NS_IF_ADDREF(*aSandboxedNavigator = permittedNavigator); |
|
5727 return NS_OK; |
|
5728 } |
|
5729 |
|
5730 NS_IMETHODIMP |
|
5731 nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags) |
|
5732 { |
|
5733 mDefaultLoadFlags = aDefaultLoadFlags; |
|
5734 |
|
5735 // Tell the load group to set these flags all requests in the group |
|
5736 if (mLoadGroup) { |
|
5737 mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags); |
|
5738 } else { |
|
5739 NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to"); |
|
5740 } |
|
5741 |
|
5742 // Recursively tell all of our children. We *do not* skip |
|
5743 // <iframe mozbrowser> children - if someone sticks custom flags in this |
|
5744 // docShell then they too get the same flags. |
|
5745 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
5746 while (iter.HasMore()) { |
|
5747 nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext()); |
|
5748 if (!docshell) { |
|
5749 continue; |
|
5750 } |
|
5751 docshell->SetDefaultLoadFlags(aDefaultLoadFlags); |
|
5752 } |
|
5753 return NS_OK; |
|
5754 } |
|
5755 |
|
5756 NS_IMETHODIMP |
|
5757 nsDocShell::GetDefaultLoadFlags(uint32_t *aDefaultLoadFlags) |
|
5758 { |
|
5759 *aDefaultLoadFlags = mDefaultLoadFlags; |
|
5760 return NS_OK; |
|
5761 } |
|
5762 |
|
5763 |
|
5764 NS_IMETHODIMP |
|
5765 nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel) |
|
5766 { |
|
5767 #ifdef DEBUG |
|
5768 // if the channel is non-null |
|
5769 if (aMixedContentChannel) { |
|
5770 // Get the root docshell. |
|
5771 nsCOMPtr<nsIDocShellTreeItem> root; |
|
5772 GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
5773 NS_WARN_IF_FALSE( |
|
5774 root.get() == static_cast<nsIDocShellTreeItem *>(this), |
|
5775 "Setting mMixedContentChannel on a docshell that is not the root docshell" |
|
5776 ); |
|
5777 } |
|
5778 #endif |
|
5779 mMixedContentChannel = aMixedContentChannel; |
|
5780 return NS_OK; |
|
5781 } |
|
5782 |
|
5783 NS_IMETHODIMP |
|
5784 nsDocShell::GetMixedContentChannel(nsIChannel **aMixedContentChannel) |
|
5785 { |
|
5786 NS_ENSURE_ARG_POINTER(aMixedContentChannel); |
|
5787 NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel); |
|
5788 return NS_OK; |
|
5789 } |
|
5790 |
|
5791 NS_IMETHODIMP |
|
5792 nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection, bool* aAllowMixedContent, bool* aIsRootDocShell) |
|
5793 { |
|
5794 *aRootHasSecureConnection = true; |
|
5795 *aAllowMixedContent = false; |
|
5796 *aIsRootDocShell = false; |
|
5797 |
|
5798 nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot; |
|
5799 GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); |
|
5800 NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!"); |
|
5801 *aIsRootDocShell = sameTypeRoot.get() == static_cast<nsIDocShellTreeItem *>(this); |
|
5802 |
|
5803 // now get the document from sameTypeRoot |
|
5804 nsCOMPtr<nsIDocument> rootDoc = do_GetInterface(sameTypeRoot); |
|
5805 if (rootDoc) { |
|
5806 nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal(); |
|
5807 |
|
5808 // For things with system principal (e.g. scratchpad) there is no uri |
|
5809 // aRootHasSecureConnection should be false. |
|
5810 nsCOMPtr<nsIURI> rootUri; |
|
5811 if (nsContentUtils::IsSystemPrincipal(rootPrincipal) || |
|
5812 NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri || |
|
5813 NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) { |
|
5814 *aRootHasSecureConnection = false; |
|
5815 } |
|
5816 |
|
5817 // Check the root doc's channel against the root docShell's mMixedContentChannel to see |
|
5818 // if they are the same. If they are the same, the user has overriden |
|
5819 // the block. |
|
5820 nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot); |
|
5821 nsCOMPtr<nsIChannel> mixedChannel; |
|
5822 rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel)); |
|
5823 *aAllowMixedContent = mixedChannel && (mixedChannel == rootDoc->GetChannel()); |
|
5824 } |
|
5825 |
|
5826 return NS_OK; |
|
5827 } |
|
5828 |
|
5829 NS_IMETHODIMP |
|
5830 nsDocShell::SetVisibility(bool aVisibility) |
|
5831 { |
|
5832 // Show()/Hide() may change mContentViewer. |
|
5833 nsCOMPtr<nsIContentViewer> cv = mContentViewer; |
|
5834 if (!cv) |
|
5835 return NS_OK; |
|
5836 if (aVisibility) { |
|
5837 cv->Show(); |
|
5838 } |
|
5839 else { |
|
5840 cv->Hide(); |
|
5841 } |
|
5842 |
|
5843 return NS_OK; |
|
5844 } |
|
5845 |
|
5846 NS_IMETHODIMP |
|
5847 nsDocShell::GetEnabled(bool *aEnabled) |
|
5848 { |
|
5849 NS_ENSURE_ARG_POINTER(aEnabled); |
|
5850 *aEnabled = true; |
|
5851 return NS_ERROR_NOT_IMPLEMENTED; |
|
5852 } |
|
5853 |
|
5854 NS_IMETHODIMP |
|
5855 nsDocShell::SetEnabled(bool aEnabled) |
|
5856 { |
|
5857 return NS_ERROR_NOT_IMPLEMENTED; |
|
5858 } |
|
5859 |
|
5860 NS_IMETHODIMP |
|
5861 nsDocShell::SetFocus() |
|
5862 { |
|
5863 return NS_OK; |
|
5864 } |
|
5865 |
|
5866 NS_IMETHODIMP |
|
5867 nsDocShell::GetMainWidget(nsIWidget ** aMainWidget) |
|
5868 { |
|
5869 // We don't create our own widget, so simply return the parent one. |
|
5870 return GetParentWidget(aMainWidget); |
|
5871 } |
|
5872 |
|
5873 NS_IMETHODIMP |
|
5874 nsDocShell::GetTitle(char16_t ** aTitle) |
|
5875 { |
|
5876 NS_ENSURE_ARG_POINTER(aTitle); |
|
5877 |
|
5878 *aTitle = ToNewUnicode(mTitle); |
|
5879 return NS_OK; |
|
5880 } |
|
5881 |
|
5882 NS_IMETHODIMP |
|
5883 nsDocShell::SetTitle(const char16_t * aTitle) |
|
5884 { |
|
5885 // Store local title |
|
5886 mTitle = aTitle; |
|
5887 |
|
5888 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
5889 GetSameTypeParent(getter_AddRefs(parent)); |
|
5890 |
|
5891 // When title is set on the top object it should then be passed to the |
|
5892 // tree owner. |
|
5893 if (!parent) { |
|
5894 nsCOMPtr<nsIBaseWindow> |
|
5895 treeOwnerAsWin(do_QueryInterface(mTreeOwner)); |
|
5896 if (treeOwnerAsWin) |
|
5897 treeOwnerAsWin->SetTitle(aTitle); |
|
5898 } |
|
5899 |
|
5900 if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE && mUseGlobalHistory && |
|
5901 !mInPrivateBrowsing) { |
|
5902 nsCOMPtr<IHistory> history = services::GetHistoryService(); |
|
5903 if (history) { |
|
5904 history->SetURITitle(mCurrentURI, mTitle); |
|
5905 } |
|
5906 else if (mGlobalHistory) { |
|
5907 mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle)); |
|
5908 } |
|
5909 } |
|
5910 |
|
5911 // Update SessionHistory with the document's title. |
|
5912 if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY && |
|
5913 mLoadType != LOAD_ERROR_PAGE) { |
|
5914 |
|
5915 mOSHE->SetTitle(mTitle); |
|
5916 } |
|
5917 |
|
5918 return NS_OK; |
|
5919 } |
|
5920 |
|
5921 nsresult |
|
5922 nsDocShell::GetCurScrollPos(int32_t scrollOrientation, int32_t * curPos) |
|
5923 { |
|
5924 NS_ENSURE_ARG_POINTER(curPos); |
|
5925 |
|
5926 nsIScrollableFrame* sf = GetRootScrollFrame(); |
|
5927 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
|
5928 |
|
5929 nsPoint pt = sf->GetScrollPosition(); |
|
5930 |
|
5931 switch (scrollOrientation) { |
|
5932 case ScrollOrientation_X: |
|
5933 *curPos = pt.x; |
|
5934 return NS_OK; |
|
5935 |
|
5936 case ScrollOrientation_Y: |
|
5937 *curPos = pt.y; |
|
5938 return NS_OK; |
|
5939 |
|
5940 default: |
|
5941 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG); |
|
5942 } |
|
5943 } |
|
5944 |
|
5945 nsresult |
|
5946 nsDocShell::SetCurScrollPosEx(int32_t curHorizontalPos, int32_t curVerticalPos) |
|
5947 { |
|
5948 nsIScrollableFrame* sf = GetRootScrollFrame(); |
|
5949 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
|
5950 |
|
5951 sf->ScrollTo(nsPoint(curHorizontalPos, curVerticalPos), |
|
5952 nsIScrollableFrame::INSTANT); |
|
5953 return NS_OK; |
|
5954 } |
|
5955 |
|
5956 //***************************************************************************** |
|
5957 // nsDocShell::nsIScrollable |
|
5958 //***************************************************************************** |
|
5959 |
|
5960 NS_IMETHODIMP |
|
5961 nsDocShell::GetDefaultScrollbarPreferences(int32_t scrollOrientation, |
|
5962 int32_t * scrollbarPref) |
|
5963 { |
|
5964 NS_ENSURE_ARG_POINTER(scrollbarPref); |
|
5965 switch (scrollOrientation) { |
|
5966 case ScrollOrientation_X: |
|
5967 *scrollbarPref = mDefaultScrollbarPref.x; |
|
5968 return NS_OK; |
|
5969 |
|
5970 case ScrollOrientation_Y: |
|
5971 *scrollbarPref = mDefaultScrollbarPref.y; |
|
5972 return NS_OK; |
|
5973 |
|
5974 default: |
|
5975 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG); |
|
5976 } |
|
5977 return NS_ERROR_FAILURE; |
|
5978 } |
|
5979 |
|
5980 NS_IMETHODIMP |
|
5981 nsDocShell::SetDefaultScrollbarPreferences(int32_t scrollOrientation, |
|
5982 int32_t scrollbarPref) |
|
5983 { |
|
5984 switch (scrollOrientation) { |
|
5985 case ScrollOrientation_X: |
|
5986 mDefaultScrollbarPref.x = scrollbarPref; |
|
5987 return NS_OK; |
|
5988 |
|
5989 case ScrollOrientation_Y: |
|
5990 mDefaultScrollbarPref.y = scrollbarPref; |
|
5991 return NS_OK; |
|
5992 |
|
5993 default: |
|
5994 NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG); |
|
5995 } |
|
5996 return NS_ERROR_FAILURE; |
|
5997 } |
|
5998 |
|
5999 NS_IMETHODIMP |
|
6000 nsDocShell::GetScrollbarVisibility(bool * verticalVisible, |
|
6001 bool * horizontalVisible) |
|
6002 { |
|
6003 nsIScrollableFrame* sf = GetRootScrollFrame(); |
|
6004 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
|
6005 |
|
6006 uint32_t scrollbarVisibility = sf->GetScrollbarVisibility(); |
|
6007 if (verticalVisible) |
|
6008 *verticalVisible = (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0; |
|
6009 if (horizontalVisible) |
|
6010 *horizontalVisible = (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0; |
|
6011 |
|
6012 return NS_OK; |
|
6013 } |
|
6014 |
|
6015 //***************************************************************************** |
|
6016 // nsDocShell::nsITextScroll |
|
6017 //***************************************************************************** |
|
6018 |
|
6019 NS_IMETHODIMP |
|
6020 nsDocShell::ScrollByLines(int32_t numLines) |
|
6021 { |
|
6022 nsIScrollableFrame* sf = GetRootScrollFrame(); |
|
6023 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
|
6024 |
|
6025 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES, |
|
6026 nsIScrollableFrame::SMOOTH); |
|
6027 return NS_OK; |
|
6028 } |
|
6029 |
|
6030 NS_IMETHODIMP |
|
6031 nsDocShell::ScrollByPages(int32_t numPages) |
|
6032 { |
|
6033 nsIScrollableFrame* sf = GetRootScrollFrame(); |
|
6034 NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); |
|
6035 |
|
6036 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES, |
|
6037 nsIScrollableFrame::SMOOTH); |
|
6038 return NS_OK; |
|
6039 } |
|
6040 |
|
6041 //***************************************************************************** |
|
6042 // nsDocShell::nsIRefreshURI |
|
6043 //***************************************************************************** |
|
6044 |
|
6045 NS_IMETHODIMP |
|
6046 nsDocShell::RefreshURI(nsIURI * aURI, int32_t aDelay, bool aRepeat, |
|
6047 bool aMetaRefresh) |
|
6048 { |
|
6049 NS_ENSURE_ARG(aURI); |
|
6050 |
|
6051 /* Check if Meta refresh/redirects are permitted. Some |
|
6052 * embedded applications may not want to do this. |
|
6053 * Must do this before sending out NOTIFY_REFRESH events |
|
6054 * because listeners may have side effects (e.g. displaying a |
|
6055 * button to manually trigger the refresh later). |
|
6056 */ |
|
6057 bool allowRedirects = true; |
|
6058 GetAllowMetaRedirects(&allowRedirects); |
|
6059 if (!allowRedirects) |
|
6060 return NS_OK; |
|
6061 |
|
6062 // If any web progress listeners are listening for NOTIFY_REFRESH events, |
|
6063 // give them a chance to block this refresh. |
|
6064 bool sameURI; |
|
6065 nsresult rv = aURI->Equals(mCurrentURI, &sameURI); |
|
6066 if (NS_FAILED(rv)) |
|
6067 sameURI = false; |
|
6068 if (!RefreshAttempted(this, aURI, aDelay, sameURI)) |
|
6069 return NS_OK; |
|
6070 |
|
6071 nsRefreshTimer *refreshTimer = new nsRefreshTimer(); |
|
6072 NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY); |
|
6073 uint32_t busyFlags = 0; |
|
6074 GetBusyFlags(&busyFlags); |
|
6075 |
|
6076 nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1 |
|
6077 |
|
6078 refreshTimer->mDocShell = this; |
|
6079 refreshTimer->mURI = aURI; |
|
6080 refreshTimer->mDelay = aDelay; |
|
6081 refreshTimer->mRepeat = aRepeat; |
|
6082 refreshTimer->mMetaRefresh = aMetaRefresh; |
|
6083 |
|
6084 if (!mRefreshURIList) { |
|
6085 NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)), |
|
6086 NS_ERROR_FAILURE); |
|
6087 } |
|
6088 |
|
6089 if (busyFlags & BUSY_FLAGS_BUSY) { |
|
6090 // We are busy loading another page. Don't create the |
|
6091 // timer right now. Instead queue up the request and trigger the |
|
6092 // timer in EndPageLoad(). |
|
6093 mRefreshURIList->AppendElement(refreshTimer); |
|
6094 } |
|
6095 else { |
|
6096 // There is no page loading going on right now. Create the |
|
6097 // timer and fire it right away. |
|
6098 nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1"); |
|
6099 NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE); |
|
6100 |
|
6101 mRefreshURIList->AppendElement(timer); // owning timer ref |
|
6102 timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT); |
|
6103 } |
|
6104 return NS_OK; |
|
6105 } |
|
6106 |
|
6107 nsresult |
|
6108 nsDocShell::ForceRefreshURIFromTimer(nsIURI * aURI, |
|
6109 int32_t aDelay, |
|
6110 bool aMetaRefresh, |
|
6111 nsITimer* aTimer) |
|
6112 { |
|
6113 NS_PRECONDITION(aTimer, "Must have a timer here"); |
|
6114 |
|
6115 // Remove aTimer from mRefreshURIList if needed |
|
6116 if (mRefreshURIList) { |
|
6117 uint32_t n = 0; |
|
6118 mRefreshURIList->Count(&n); |
|
6119 |
|
6120 for (uint32_t i = 0; i < n; ++i) { |
|
6121 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i); |
|
6122 if (timer == aTimer) { |
|
6123 mRefreshURIList->RemoveElementAt(i); |
|
6124 break; |
|
6125 } |
|
6126 } |
|
6127 } |
|
6128 |
|
6129 return ForceRefreshURI(aURI, aDelay, aMetaRefresh); |
|
6130 } |
|
6131 |
|
6132 NS_IMETHODIMP |
|
6133 nsDocShell::ForceRefreshURI(nsIURI * aURI, |
|
6134 int32_t aDelay, |
|
6135 bool aMetaRefresh) |
|
6136 { |
|
6137 NS_ENSURE_ARG(aURI); |
|
6138 |
|
6139 nsCOMPtr<nsIDocShellLoadInfo> loadInfo; |
|
6140 CreateLoadInfo(getter_AddRefs(loadInfo)); |
|
6141 NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY); |
|
6142 |
|
6143 /* We do need to pass in a referrer, but we don't want it to |
|
6144 * be sent to the server. |
|
6145 */ |
|
6146 loadInfo->SetSendReferrer(false); |
|
6147 |
|
6148 /* for most refreshes the current URI is an appropriate |
|
6149 * internal referrer |
|
6150 */ |
|
6151 loadInfo->SetReferrer(mCurrentURI); |
|
6152 |
|
6153 /* Don't ever "guess" on which owner to use to avoid picking |
|
6154 * the current owner. |
|
6155 */ |
|
6156 loadInfo->SetOwnerIsExplicit(true); |
|
6157 |
|
6158 /* Check if this META refresh causes a redirection |
|
6159 * to another site. |
|
6160 */ |
|
6161 bool equalUri = false; |
|
6162 nsresult rv = aURI->Equals(mCurrentURI, &equalUri); |
|
6163 if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh && |
|
6164 aDelay <= REFRESH_REDIRECT_TIMER) { |
|
6165 |
|
6166 /* It is a META refresh based redirection within the threshold time |
|
6167 * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER). |
|
6168 * Pass a REPLACE flag to LoadURI(). |
|
6169 */ |
|
6170 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace); |
|
6171 |
|
6172 /* for redirects we mimic HTTP, which passes the |
|
6173 * original referrer |
|
6174 */ |
|
6175 nsCOMPtr<nsIURI> internalReferrer; |
|
6176 GetReferringURI(getter_AddRefs(internalReferrer)); |
|
6177 if (internalReferrer) { |
|
6178 loadInfo->SetReferrer(internalReferrer); |
|
6179 } |
|
6180 } |
|
6181 else { |
|
6182 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh); |
|
6183 } |
|
6184 |
|
6185 /* |
|
6186 * LoadURI(...) will cancel all refresh timers... This causes the |
|
6187 * Timer and its refreshData instance to be released... |
|
6188 */ |
|
6189 LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true); |
|
6190 |
|
6191 return NS_OK; |
|
6192 } |
|
6193 |
|
6194 nsresult |
|
6195 nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI, |
|
6196 nsIPrincipal* aPrincipal, |
|
6197 const nsACString & aHeader) |
|
6198 { |
|
6199 // Refresh headers are parsed with the following format in mind |
|
6200 // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri"> |
|
6201 // By the time we are here, the following is true: |
|
6202 // header = "REFRESH" |
|
6203 // content = "5; URL=http://uri" // note the URL attribute is |
|
6204 // optional, if it is absent, the currently loaded url is used. |
|
6205 // Also note that the seconds and URL separator can be either |
|
6206 // a ';' or a ','. The ',' separator should be illegal but CNN |
|
6207 // is using it. |
|
6208 // |
|
6209 // We need to handle the following strings, where |
|
6210 // - X is a set of digits |
|
6211 // - URI is either a relative or absolute URI |
|
6212 // |
|
6213 // Note that URI should start with "url=" but we allow omission |
|
6214 // |
|
6215 // "" || ";" || "," |
|
6216 // empty string. use the currently loaded URI |
|
6217 // and refresh immediately. |
|
6218 // "X" || "X;" || "X," |
|
6219 // Refresh the currently loaded URI in X seconds. |
|
6220 // "X; URI" || "X, URI" |
|
6221 // Refresh using URI as the destination in X seconds. |
|
6222 // "URI" || "; URI" || ", URI" |
|
6223 // Refresh immediately using URI as the destination. |
|
6224 // |
|
6225 // Currently, anything immediately following the URI, if |
|
6226 // separated by any char in the set "'\"\t\r\n " will be |
|
6227 // ignored. So "10; url=go.html ; foo=bar" will work, |
|
6228 // and so will "10; url='go.html'; foo=bar". However, |
|
6229 // "10; url=go.html; foo=bar" will result in the uri |
|
6230 // "go.html;" since ';' and ',' are valid uri characters. |
|
6231 // |
|
6232 // Note that we need to remove any tokens wrapping the URI. |
|
6233 // These tokens currently include spaces, double and single |
|
6234 // quotes. |
|
6235 |
|
6236 // when done, seconds is 0 or the given number of seconds |
|
6237 // uriAttrib is empty or the URI specified |
|
6238 MOZ_ASSERT(aPrincipal); |
|
6239 |
|
6240 nsAutoCString uriAttrib; |
|
6241 int32_t seconds = 0; |
|
6242 bool specifiesSeconds = false; |
|
6243 |
|
6244 nsACString::const_iterator iter, tokenStart, doneIterating; |
|
6245 |
|
6246 aHeader.BeginReading(iter); |
|
6247 aHeader.EndReading(doneIterating); |
|
6248 |
|
6249 // skip leading whitespace |
|
6250 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) |
|
6251 ++iter; |
|
6252 |
|
6253 tokenStart = iter; |
|
6254 |
|
6255 // skip leading + and - |
|
6256 if (iter != doneIterating && (*iter == '-' || *iter == '+')) |
|
6257 ++iter; |
|
6258 |
|
6259 // parse number |
|
6260 while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) { |
|
6261 seconds = seconds * 10 + (*iter - '0'); |
|
6262 specifiesSeconds = true; |
|
6263 ++iter; |
|
6264 } |
|
6265 |
|
6266 if (iter != doneIterating) { |
|
6267 // if we started with a '-', number is negative |
|
6268 if (*tokenStart == '-') |
|
6269 seconds = -seconds; |
|
6270 |
|
6271 // skip to next ';' or ',' |
|
6272 nsACString::const_iterator iterAfterDigit = iter; |
|
6273 while (iter != doneIterating && !(*iter == ';' || *iter == ',')) |
|
6274 { |
|
6275 if (specifiesSeconds) |
|
6276 { |
|
6277 // Non-whitespace characters here mean that the string is |
|
6278 // malformed but tolerate sites that specify a decimal point, |
|
6279 // even though meta refresh only works on whole seconds. |
|
6280 if (iter == iterAfterDigit && |
|
6281 !nsCRT::IsAsciiSpace(*iter) && *iter != '.') |
|
6282 { |
|
6283 // The characters between the seconds and the next |
|
6284 // section are just garbage! |
|
6285 // e.g. content="2a0z+,URL=http://www.mozilla.org/" |
|
6286 // Just ignore this redirect. |
|
6287 return NS_ERROR_FAILURE; |
|
6288 } |
|
6289 else if (nsCRT::IsAsciiSpace(*iter)) |
|
6290 { |
|
6291 // We've had at least one whitespace so tolerate the mistake |
|
6292 // and drop through. |
|
6293 // e.g. content="10 foo" |
|
6294 ++iter; |
|
6295 break; |
|
6296 } |
|
6297 } |
|
6298 ++iter; |
|
6299 } |
|
6300 |
|
6301 // skip any remaining whitespace |
|
6302 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) |
|
6303 ++iter; |
|
6304 |
|
6305 // skip ';' or ',' |
|
6306 if (iter != doneIterating && (*iter == ';' || *iter == ',')) { |
|
6307 ++iter; |
|
6308 } |
|
6309 |
|
6310 // skip whitespace |
|
6311 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) |
|
6312 ++iter; |
|
6313 } |
|
6314 |
|
6315 // possible start of URI |
|
6316 tokenStart = iter; |
|
6317 |
|
6318 // skip "url = " to real start of URI |
|
6319 if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) { |
|
6320 ++iter; |
|
6321 if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) { |
|
6322 ++iter; |
|
6323 if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) { |
|
6324 ++iter; |
|
6325 |
|
6326 // skip whitespace |
|
6327 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) |
|
6328 ++iter; |
|
6329 |
|
6330 if (iter != doneIterating && *iter == '=') { |
|
6331 ++iter; |
|
6332 |
|
6333 // skip whitespace |
|
6334 while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) |
|
6335 ++iter; |
|
6336 |
|
6337 // found real start of URI |
|
6338 tokenStart = iter; |
|
6339 } |
|
6340 } |
|
6341 } |
|
6342 } |
|
6343 |
|
6344 // skip a leading '"' or '\''. |
|
6345 |
|
6346 bool isQuotedURI = false; |
|
6347 if (tokenStart != doneIterating && (*tokenStart == '"' || *tokenStart == '\'')) |
|
6348 { |
|
6349 isQuotedURI = true; |
|
6350 ++tokenStart; |
|
6351 } |
|
6352 |
|
6353 // set iter to start of URI |
|
6354 iter = tokenStart; |
|
6355 |
|
6356 // tokenStart here points to the beginning of URI |
|
6357 |
|
6358 // grab the rest of the URI |
|
6359 while (iter != doneIterating) |
|
6360 { |
|
6361 if (isQuotedURI && (*iter == '"' || *iter == '\'')) |
|
6362 break; |
|
6363 ++iter; |
|
6364 } |
|
6365 |
|
6366 // move iter one back if the last character is a '"' or '\'' |
|
6367 if (iter != tokenStart && isQuotedURI) { |
|
6368 --iter; |
|
6369 if (!(*iter == '"' || *iter == '\'')) |
|
6370 ++iter; |
|
6371 } |
|
6372 |
|
6373 // URI is whatever's contained from tokenStart to iter. |
|
6374 // note: if tokenStart == doneIterating, so is iter. |
|
6375 |
|
6376 nsresult rv = NS_OK; |
|
6377 |
|
6378 nsCOMPtr<nsIURI> uri; |
|
6379 bool specifiesURI = false; |
|
6380 if (tokenStart == iter) { |
|
6381 uri = aBaseURI; |
|
6382 } |
|
6383 else { |
|
6384 uriAttrib = Substring(tokenStart, iter); |
|
6385 // NS_NewURI takes care of any whitespace surrounding the URL |
|
6386 rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI); |
|
6387 specifiesURI = true; |
|
6388 } |
|
6389 |
|
6390 // No URI or seconds were specified |
|
6391 if (!specifiesSeconds && !specifiesURI) |
|
6392 { |
|
6393 // Do nothing because the alternative is to spin around in a refresh |
|
6394 // loop forever! |
|
6395 return NS_ERROR_FAILURE; |
|
6396 } |
|
6397 |
|
6398 if (NS_SUCCEEDED(rv)) { |
|
6399 nsCOMPtr<nsIScriptSecurityManager> |
|
6400 securityManager(do_GetService |
|
6401 (NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); |
|
6402 if (NS_SUCCEEDED(rv)) { |
|
6403 rv = securityManager-> |
|
6404 CheckLoadURIWithPrincipal(aPrincipal, uri, |
|
6405 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT); |
|
6406 |
|
6407 if (NS_SUCCEEDED(rv)) { |
|
6408 bool isjs = true; |
|
6409 rv = NS_URIChainHasFlags(uri, |
|
6410 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs); |
|
6411 NS_ENSURE_SUCCESS(rv, rv); |
|
6412 |
|
6413 if (isjs) { |
|
6414 return NS_ERROR_FAILURE; |
|
6415 } |
|
6416 } |
|
6417 |
|
6418 if (NS_SUCCEEDED(rv)) { |
|
6419 // Since we can't travel back in time yet, just pretend |
|
6420 // negative numbers do nothing at all. |
|
6421 if (seconds < 0) |
|
6422 return NS_ERROR_FAILURE; |
|
6423 |
|
6424 rv = RefreshURI(uri, seconds * 1000, false, true); |
|
6425 } |
|
6426 } |
|
6427 } |
|
6428 return rv; |
|
6429 } |
|
6430 |
|
6431 NS_IMETHODIMP nsDocShell::SetupRefreshURI(nsIChannel * aChannel) |
|
6432 { |
|
6433 nsresult rv; |
|
6434 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv)); |
|
6435 if (NS_SUCCEEDED(rv)) { |
|
6436 nsAutoCString refreshHeader; |
|
6437 rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"), |
|
6438 refreshHeader); |
|
6439 |
|
6440 if (!refreshHeader.IsEmpty()) { |
|
6441 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
6442 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); |
|
6443 NS_ENSURE_SUCCESS(rv, rv); |
|
6444 |
|
6445 nsCOMPtr<nsIPrincipal> principal; |
|
6446 rv = secMan->GetChannelPrincipal(aChannel, getter_AddRefs(principal)); |
|
6447 NS_ENSURE_SUCCESS(rv, rv); |
|
6448 |
|
6449 SetupReferrerFromChannel(aChannel); |
|
6450 rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader); |
|
6451 if (NS_SUCCEEDED(rv)) { |
|
6452 return NS_REFRESHURI_HEADER_FOUND; |
|
6453 } |
|
6454 } |
|
6455 } |
|
6456 return rv; |
|
6457 } |
|
6458 |
|
6459 static void |
|
6460 DoCancelRefreshURITimers(nsISupportsArray* aTimerList) |
|
6461 { |
|
6462 if (!aTimerList) |
|
6463 return; |
|
6464 |
|
6465 uint32_t n=0; |
|
6466 aTimerList->Count(&n); |
|
6467 |
|
6468 while (n) { |
|
6469 nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n)); |
|
6470 |
|
6471 aTimerList->RemoveElementAt(n); // bye bye owning timer ref |
|
6472 |
|
6473 if (timer) |
|
6474 timer->Cancel(); |
|
6475 } |
|
6476 } |
|
6477 |
|
6478 NS_IMETHODIMP |
|
6479 nsDocShell::CancelRefreshURITimers() |
|
6480 { |
|
6481 DoCancelRefreshURITimers(mRefreshURIList); |
|
6482 DoCancelRefreshURITimers(mSavedRefreshURIList); |
|
6483 mRefreshURIList = nullptr; |
|
6484 mSavedRefreshURIList = nullptr; |
|
6485 |
|
6486 return NS_OK; |
|
6487 } |
|
6488 |
|
6489 NS_IMETHODIMP |
|
6490 nsDocShell::GetRefreshPending(bool* _retval) |
|
6491 { |
|
6492 if (!mRefreshURIList) { |
|
6493 *_retval = false; |
|
6494 return NS_OK; |
|
6495 } |
|
6496 |
|
6497 uint32_t count; |
|
6498 nsresult rv = mRefreshURIList->Count(&count); |
|
6499 if (NS_SUCCEEDED(rv)) |
|
6500 *_retval = (count != 0); |
|
6501 return rv; |
|
6502 } |
|
6503 |
|
6504 NS_IMETHODIMP |
|
6505 nsDocShell::SuspendRefreshURIs() |
|
6506 { |
|
6507 if (mRefreshURIList) { |
|
6508 uint32_t n = 0; |
|
6509 mRefreshURIList->Count(&n); |
|
6510 |
|
6511 for (uint32_t i = 0; i < n; ++i) { |
|
6512 nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i); |
|
6513 if (!timer) |
|
6514 continue; // this must be a nsRefreshURI already |
|
6515 |
|
6516 // Replace this timer object with a nsRefreshTimer object. |
|
6517 nsCOMPtr<nsITimerCallback> callback; |
|
6518 timer->GetCallback(getter_AddRefs(callback)); |
|
6519 |
|
6520 timer->Cancel(); |
|
6521 |
|
6522 nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback); |
|
6523 NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects"); |
|
6524 |
|
6525 mRefreshURIList->ReplaceElementAt(rt, i); |
|
6526 } |
|
6527 } |
|
6528 |
|
6529 // Suspend refresh URIs for our child shells as well. |
|
6530 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
6531 while (iter.HasMore()) { |
|
6532 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
|
6533 if (shell) |
|
6534 shell->SuspendRefreshURIs(); |
|
6535 } |
|
6536 |
|
6537 return NS_OK; |
|
6538 } |
|
6539 |
|
6540 NS_IMETHODIMP |
|
6541 nsDocShell::ResumeRefreshURIs() |
|
6542 { |
|
6543 RefreshURIFromQueue(); |
|
6544 |
|
6545 // Resume refresh URIs for our child shells as well. |
|
6546 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
6547 while (iter.HasMore()) { |
|
6548 nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext()); |
|
6549 if (shell) |
|
6550 shell->ResumeRefreshURIs(); |
|
6551 } |
|
6552 |
|
6553 return NS_OK; |
|
6554 } |
|
6555 |
|
6556 nsresult |
|
6557 nsDocShell::RefreshURIFromQueue() |
|
6558 { |
|
6559 if (!mRefreshURIList) |
|
6560 return NS_OK; |
|
6561 uint32_t n = 0; |
|
6562 mRefreshURIList->Count(&n); |
|
6563 |
|
6564 while (n) { |
|
6565 nsCOMPtr<nsISupports> element; |
|
6566 mRefreshURIList->GetElementAt(--n, getter_AddRefs(element)); |
|
6567 nsCOMPtr<nsITimerCallback> refreshInfo(do_QueryInterface(element)); |
|
6568 |
|
6569 if (refreshInfo) { |
|
6570 // This is the nsRefreshTimer object, waiting to be |
|
6571 // setup in a timer object and fired. |
|
6572 // Create the timer and trigger it. |
|
6573 uint32_t delay = static_cast<nsRefreshTimer*>(static_cast<nsITimerCallback*>(refreshInfo))->GetDelay(); |
|
6574 nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1"); |
|
6575 if (timer) { |
|
6576 // Replace the nsRefreshTimer element in the queue with |
|
6577 // its corresponding timer object, so that in case another |
|
6578 // load comes through before the timer can go off, the timer will |
|
6579 // get cancelled in CancelRefreshURITimer() |
|
6580 mRefreshURIList->ReplaceElementAt(timer, n); |
|
6581 timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT); |
|
6582 } |
|
6583 } |
|
6584 } // while |
|
6585 |
|
6586 return NS_OK; |
|
6587 } |
|
6588 |
|
6589 //***************************************************************************** |
|
6590 // nsDocShell::nsIContentViewerContainer |
|
6591 //***************************************************************************** |
|
6592 |
|
6593 NS_IMETHODIMP |
|
6594 nsDocShell::Embed(nsIContentViewer * aContentViewer, |
|
6595 const char *aCommand, nsISupports * aExtraInfo) |
|
6596 { |
|
6597 // Save the LayoutHistoryState of the previous document, before |
|
6598 // setting up new document |
|
6599 PersistLayoutHistoryState(); |
|
6600 |
|
6601 nsresult rv = SetupNewViewer(aContentViewer); |
|
6602 |
|
6603 // If we are loading a wyciwyg url from history, change the base URI for |
|
6604 // the document to the original http url that created the document.write(). |
|
6605 // This makes sure that all relative urls in a document.written page loaded |
|
6606 // via history work properly. |
|
6607 if (mCurrentURI && |
|
6608 (mLoadType & LOAD_CMD_HISTORY || |
|
6609 mLoadType == LOAD_RELOAD_NORMAL || |
|
6610 mLoadType == LOAD_RELOAD_CHARSET_CHANGE)){ |
|
6611 bool isWyciwyg = false; |
|
6612 // Check if the url is wyciwyg |
|
6613 rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg); |
|
6614 if (isWyciwyg && NS_SUCCEEDED(rv)) |
|
6615 SetBaseUrlForWyciwyg(aContentViewer); |
|
6616 } |
|
6617 // XXX What if SetupNewViewer fails? |
|
6618 if (mLSHE) { |
|
6619 // Restore the editing state, if it's stored in session history. |
|
6620 if (mLSHE->HasDetachedEditor()) { |
|
6621 ReattachEditorToWindow(mLSHE); |
|
6622 } |
|
6623 // Set history.state |
|
6624 SetDocCurrentStateObj(mLSHE); |
|
6625 |
|
6626 SetHistoryEntry(&mOSHE, mLSHE); |
|
6627 } |
|
6628 |
|
6629 bool updateHistory = true; |
|
6630 |
|
6631 // Determine if this type of load should update history |
|
6632 switch (mLoadType) { |
|
6633 case LOAD_NORMAL_REPLACE: |
|
6634 case LOAD_STOP_CONTENT_AND_REPLACE: |
|
6635 case LOAD_RELOAD_BYPASS_CACHE: |
|
6636 case LOAD_RELOAD_BYPASS_PROXY: |
|
6637 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
|
6638 case LOAD_REPLACE_BYPASS_CACHE: |
|
6639 updateHistory = false; |
|
6640 break; |
|
6641 default: |
|
6642 break; |
|
6643 } |
|
6644 |
|
6645 if (!updateHistory) |
|
6646 SetLayoutHistoryState(nullptr); |
|
6647 |
|
6648 return NS_OK; |
|
6649 } |
|
6650 |
|
6651 /* void setIsPrinting (in boolean aIsPrinting); */ |
|
6652 NS_IMETHODIMP |
|
6653 nsDocShell::SetIsPrinting(bool aIsPrinting) |
|
6654 { |
|
6655 mIsPrintingOrPP = aIsPrinting; |
|
6656 return NS_OK; |
|
6657 } |
|
6658 |
|
6659 //***************************************************************************** |
|
6660 // nsDocShell::nsIWebProgressListener |
|
6661 //***************************************************************************** |
|
6662 |
|
6663 NS_IMETHODIMP |
|
6664 nsDocShell::OnProgressChange(nsIWebProgress * aProgress, |
|
6665 nsIRequest * aRequest, |
|
6666 int32_t aCurSelfProgress, |
|
6667 int32_t aMaxSelfProgress, |
|
6668 int32_t aCurTotalProgress, |
|
6669 int32_t aMaxTotalProgress) |
|
6670 { |
|
6671 return NS_OK; |
|
6672 } |
|
6673 |
|
6674 NS_IMETHODIMP |
|
6675 nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest, |
|
6676 uint32_t aStateFlags, nsresult aStatus) |
|
6677 { |
|
6678 if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) { |
|
6679 // Save timing statistics. |
|
6680 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
|
6681 nsCOMPtr<nsIURI> uri; |
|
6682 channel->GetURI(getter_AddRefs(uri)); |
|
6683 nsAutoCString aURI; |
|
6684 uri->GetAsciiSpec(aURI); |
|
6685 |
|
6686 nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest)); |
|
6687 nsCOMPtr<nsIWebProgress> webProgress = |
|
6688 do_QueryInterface(GetAsSupports(this)); |
|
6689 |
|
6690 // We don't update navigation timing for wyciwyg channels |
|
6691 if (this == aProgress && !wcwgChannel){ |
|
6692 MaybeInitTiming(); |
|
6693 mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType)); |
|
6694 } |
|
6695 |
|
6696 // Was the wyciwyg document loaded on this docshell? |
|
6697 if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) { |
|
6698 bool equalUri = true; |
|
6699 // Store the wyciwyg url in session history, only if it is |
|
6700 // being loaded fresh for the first time. We don't want |
|
6701 // multiple entries for successive loads |
|
6702 if (mCurrentURI && |
|
6703 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) && |
|
6704 !equalUri) { |
|
6705 |
|
6706 nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
|
6707 GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
6708 nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem)); |
|
6709 bool inOnLoadHandler = false; |
|
6710 if (parentDS) { |
|
6711 parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); |
|
6712 } |
|
6713 if (inOnLoadHandler) { |
|
6714 // We're handling parent's load event listener, which causes |
|
6715 // document.write in a subdocument. |
|
6716 // Need to clear the session history for all child |
|
6717 // docshells so that we can handle them like they would |
|
6718 // all be added dynamically. |
|
6719 nsCOMPtr<nsIDocShell> parent = |
|
6720 do_QueryInterface(parentAsItem); |
|
6721 if (parent) { |
|
6722 bool oshe = false; |
|
6723 nsCOMPtr<nsISHEntry> entry; |
|
6724 parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe); |
|
6725 static_cast<nsDocShell*>(parent.get())-> |
|
6726 ClearFrameHistory(entry); |
|
6727 } |
|
6728 } |
|
6729 |
|
6730 // This is a document.write(). Get the made-up url |
|
6731 // from the channel and store it in session history. |
|
6732 // Pass false for aCloneChildren, since we're creating |
|
6733 // a new DOM here. |
|
6734 AddToSessionHistory(uri, wcwgChannel, nullptr, false, |
|
6735 getter_AddRefs(mLSHE)); |
|
6736 SetCurrentURI(uri, aRequest, true, 0); |
|
6737 // Save history state of the previous page |
|
6738 PersistLayoutHistoryState(); |
|
6739 // We'll never get an Embed() for this load, so just go ahead |
|
6740 // and SetHistoryEntry now. |
|
6741 SetHistoryEntry(&mOSHE, mLSHE); |
|
6742 } |
|
6743 |
|
6744 } |
|
6745 // Page has begun to load |
|
6746 mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD; |
|
6747 |
|
6748 if ((aStateFlags & STATE_RESTORING) == 0) { |
|
6749 // Show the progress cursor if the pref is set |
|
6750 if (Preferences::GetBool("ui.use_activity_cursor", false)) { |
|
6751 nsCOMPtr<nsIWidget> mainWidget; |
|
6752 GetMainWidget(getter_AddRefs(mainWidget)); |
|
6753 if (mainWidget) { |
|
6754 mainWidget->SetCursor(eCursor_spinning); |
|
6755 } |
|
6756 } |
|
6757 } |
|
6758 } |
|
6759 else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) { |
|
6760 // Page is loading |
|
6761 mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING; |
|
6762 } |
|
6763 else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) { |
|
6764 // Page has finished loading |
|
6765 mBusyFlags = BUSY_FLAGS_NONE; |
|
6766 |
|
6767 // Hide the progress cursor if the pref is set |
|
6768 if (Preferences::GetBool("ui.use_activity_cursor", false)) { |
|
6769 nsCOMPtr<nsIWidget> mainWidget; |
|
6770 GetMainWidget(getter_AddRefs(mainWidget)); |
|
6771 if (mainWidget) { |
|
6772 mainWidget->SetCursor(eCursor_standard); |
|
6773 } |
|
6774 } |
|
6775 } |
|
6776 if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) { |
|
6777 nsCOMPtr<nsIWebProgress> webProgress = |
|
6778 do_QueryInterface(GetAsSupports(this)); |
|
6779 // Is the document stop notification for this document? |
|
6780 if (aProgress == webProgress.get()) { |
|
6781 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
|
6782 EndPageLoad(aProgress, channel, aStatus); |
|
6783 } |
|
6784 } |
|
6785 // note that redirect state changes will go through here as well, but it |
|
6786 // is better to handle those in OnRedirectStateChange where more |
|
6787 // information is available. |
|
6788 return NS_OK; |
|
6789 } |
|
6790 |
|
6791 NS_IMETHODIMP |
|
6792 nsDocShell::OnLocationChange(nsIWebProgress * aProgress, nsIRequest * aRequest, |
|
6793 nsIURI * aURI, uint32_t aFlags) |
|
6794 { |
|
6795 NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
|
6796 return NS_OK; |
|
6797 } |
|
6798 |
|
6799 void |
|
6800 nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, |
|
6801 nsIChannel* aNewChannel, |
|
6802 uint32_t aRedirectFlags, |
|
6803 uint32_t aStateFlags) |
|
6804 { |
|
6805 NS_ASSERTION(aStateFlags & STATE_REDIRECTING, |
|
6806 "Calling OnRedirectStateChange when there is no redirect"); |
|
6807 if (!(aStateFlags & STATE_IS_DOCUMENT)) |
|
6808 return; // not a toplevel document |
|
6809 |
|
6810 nsCOMPtr<nsIURI> oldURI, newURI; |
|
6811 aOldChannel->GetURI(getter_AddRefs(oldURI)); |
|
6812 aNewChannel->GetURI(getter_AddRefs(newURI)); |
|
6813 if (!oldURI || !newURI) { |
|
6814 return; |
|
6815 } |
|
6816 |
|
6817 // Check if we have a redirect registered for this url. |
|
6818 uint32_t appId; |
|
6819 nsresult rv = GetAppId(&appId); |
|
6820 if (NS_FAILED(rv)) { |
|
6821 return; |
|
6822 } |
|
6823 |
|
6824 if (appId != nsIScriptSecurityManager::NO_APP_ID && |
|
6825 appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
6826 nsCOMPtr<nsIAppsService> appsService = |
|
6827 do_GetService(APPS_SERVICE_CONTRACTID); |
|
6828 NS_ASSERTION(appsService, "No AppsService available"); |
|
6829 nsCOMPtr<nsIURI> redirect; |
|
6830 rv = appsService->GetRedirect(appId, newURI, getter_AddRefs(redirect)); |
|
6831 if (NS_SUCCEEDED(rv) && redirect) { |
|
6832 aNewChannel->Cancel(NS_BINDING_ABORTED); |
|
6833 rv = LoadURI(redirect, nullptr, 0, false); |
|
6834 if (NS_SUCCEEDED(rv)) { |
|
6835 return; |
|
6836 } |
|
6837 } |
|
6838 } |
|
6839 |
|
6840 // Below a URI visit is saved (see AddURIVisit method doc). |
|
6841 // The visit chain looks something like: |
|
6842 // ... |
|
6843 // Site N - 1 |
|
6844 // => Site N |
|
6845 // (redirect to =>) Site N + 1 (we are here!) |
|
6846 |
|
6847 // Get N - 1 and transition type |
|
6848 nsCOMPtr<nsIURI> previousURI; |
|
6849 uint32_t previousFlags = 0; |
|
6850 ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags); |
|
6851 |
|
6852 if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL || |
|
6853 ChannelIsPost(aOldChannel)) { |
|
6854 // 1. Internal redirects are ignored because they are specific to the |
|
6855 // channel implementation. |
|
6856 // 2. POSTs are not saved by global history. |
|
6857 // |
|
6858 // Regardless, we need to propagate the previous visit to the new |
|
6859 // channel. |
|
6860 SaveLastVisit(aNewChannel, previousURI, previousFlags); |
|
6861 } |
|
6862 else { |
|
6863 nsCOMPtr<nsIURI> referrer; |
|
6864 // Treat referrer as null if there is an error getting it. |
|
6865 (void)NS_GetReferrerFromChannel(aOldChannel, |
|
6866 getter_AddRefs(referrer)); |
|
6867 |
|
6868 // Get the HTTP response code, if available. |
|
6869 uint32_t responseStatus = 0; |
|
6870 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel); |
|
6871 if (httpChannel) { |
|
6872 (void)httpChannel->GetResponseStatus(&responseStatus); |
|
6873 } |
|
6874 |
|
6875 // Add visit N -1 => N |
|
6876 AddURIVisit(oldURI, referrer, previousURI, previousFlags, |
|
6877 responseStatus); |
|
6878 |
|
6879 // Since N + 1 could be the final destination, we will not save N => N + 1 |
|
6880 // here. OnNewURI will do that, so we will cache it. |
|
6881 SaveLastVisit(aNewChannel, oldURI, aRedirectFlags); |
|
6882 } |
|
6883 |
|
6884 // check if the new load should go through the application cache. |
|
6885 nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
|
6886 do_QueryInterface(aNewChannel); |
|
6887 if (appCacheChannel) { |
|
6888 if (GeckoProcessType_Default != XRE_GetProcessType()) { |
|
6889 // Permission will be checked in the parent process. |
|
6890 appCacheChannel->SetChooseApplicationCache(true); |
|
6891 } else { |
|
6892 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
6893 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
6894 |
|
6895 if (secMan) { |
|
6896 nsCOMPtr<nsIPrincipal> principal; |
|
6897 secMan->GetDocShellCodebasePrincipal(newURI, this, getter_AddRefs(principal)); |
|
6898 appCacheChannel->SetChooseApplicationCache(NS_ShouldCheckAppCache(principal, |
|
6899 mInPrivateBrowsing)); |
|
6900 } |
|
6901 } |
|
6902 } |
|
6903 |
|
6904 if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && |
|
6905 mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) { |
|
6906 mLoadType = LOAD_NORMAL_REPLACE; |
|
6907 SetHistoryEntry(&mLSHE, nullptr); |
|
6908 } |
|
6909 } |
|
6910 |
|
6911 NS_IMETHODIMP |
|
6912 nsDocShell::OnStatusChange(nsIWebProgress * aWebProgress, |
|
6913 nsIRequest * aRequest, |
|
6914 nsresult aStatus, const char16_t * aMessage) |
|
6915 { |
|
6916 NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
|
6917 return NS_OK; |
|
6918 } |
|
6919 |
|
6920 NS_IMETHODIMP |
|
6921 nsDocShell::OnSecurityChange(nsIWebProgress * aWebProgress, |
|
6922 nsIRequest * aRequest, uint32_t state) |
|
6923 { |
|
6924 NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
|
6925 return NS_OK; |
|
6926 } |
|
6927 |
|
6928 |
|
6929 nsresult |
|
6930 nsDocShell::EndPageLoad(nsIWebProgress * aProgress, |
|
6931 nsIChannel * aChannel, nsresult aStatus) |
|
6932 { |
|
6933 if(!aChannel) |
|
6934 return NS_ERROR_NULL_POINTER; |
|
6935 |
|
6936 MOZ_EVENT_TRACER_DONE(this, "docshell::pageload"); |
|
6937 |
|
6938 nsCOMPtr<nsIURI> url; |
|
6939 nsresult rv = aChannel->GetURI(getter_AddRefs(url)); |
|
6940 if (NS_FAILED(rv)) return rv; |
|
6941 |
|
6942 nsCOMPtr<nsITimedChannel> timingChannel = |
|
6943 do_QueryInterface(aChannel); |
|
6944 if (timingChannel) { |
|
6945 TimeStamp channelCreationTime; |
|
6946 rv = timingChannel->GetChannelCreation(&channelCreationTime); |
|
6947 if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) { |
|
6948 Telemetry::AccumulateTimeDelta( |
|
6949 Telemetry::TOTAL_CONTENT_PAGE_LOAD_TIME, |
|
6950 channelCreationTime); |
|
6951 nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup = |
|
6952 do_QueryInterface(mLoadGroup); |
|
6953 if (internalLoadGroup) |
|
6954 internalLoadGroup->OnEndPageLoad(aChannel); |
|
6955 } |
|
6956 } |
|
6957 |
|
6958 // Timing is picked up by the window, we don't need it anymore |
|
6959 mTiming = nullptr; |
|
6960 |
|
6961 // clean up reload state for meta charset |
|
6962 if (eCharsetReloadRequested == mCharsetReloadState) |
|
6963 mCharsetReloadState = eCharsetReloadStopOrigional; |
|
6964 else |
|
6965 mCharsetReloadState = eCharsetReloadInit; |
|
6966 |
|
6967 // Save a pointer to the currently-loading history entry. |
|
6968 // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history |
|
6969 // entry further down in this method. |
|
6970 nsCOMPtr<nsISHEntry> loadingSHE = mLSHE; |
|
6971 |
|
6972 // |
|
6973 // one of many safeguards that prevent death and destruction if |
|
6974 // someone is so very very rude as to bring this window down |
|
6975 // during this load handler. |
|
6976 // |
|
6977 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this); |
|
6978 |
|
6979 // Notify the ContentViewer that the Document has finished loading. This |
|
6980 // will cause any OnLoad(...) and PopState(...) handlers to fire. |
|
6981 if (!mEODForCurrentDocument && mContentViewer) { |
|
6982 mIsExecutingOnLoadHandler = true; |
|
6983 mContentViewer->LoadComplete(aStatus); |
|
6984 mIsExecutingOnLoadHandler = false; |
|
6985 |
|
6986 mEODForCurrentDocument = true; |
|
6987 |
|
6988 // If all documents have completed their loading |
|
6989 // favor native event dispatch priorities |
|
6990 // over performance |
|
6991 if (--gNumberOfDocumentsLoading == 0) { |
|
6992 // Hint to use normal native event dispatch priorities |
|
6993 FavorPerformanceHint(false); |
|
6994 } |
|
6995 } |
|
6996 /* Check if the httpChannel has any cache-control related response headers, |
|
6997 * like no-store, no-cache. If so, update SHEntry so that |
|
6998 * when a user goes back/forward to this page, we appropriately do |
|
6999 * form value restoration or load from server. |
|
7000 */ |
|
7001 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
|
7002 if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel. |
|
7003 GetHttpChannel(aChannel, getter_AddRefs(httpChannel)); |
|
7004 |
|
7005 if (httpChannel) { |
|
7006 // figure out if SH should be saving layout state. |
|
7007 bool discardLayoutState = ShouldDiscardLayoutState(httpChannel); |
|
7008 if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) && |
|
7009 (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) |
|
7010 mLSHE->SetSaveLayoutStateFlag(false); |
|
7011 } |
|
7012 |
|
7013 // Clear mLSHE after calling the onLoadHandlers. This way, if the |
|
7014 // onLoadHandler tries to load something different in |
|
7015 // itself or one of its children, we can deal with it appropriately. |
|
7016 if (mLSHE) { |
|
7017 mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory); |
|
7018 |
|
7019 // Clear the mLSHE reference to indicate document loading is done one |
|
7020 // way or another. |
|
7021 SetHistoryEntry(&mLSHE, nullptr); |
|
7022 } |
|
7023 // if there's a refresh header in the channel, this method |
|
7024 // will set it up for us. |
|
7025 RefreshURIFromQueue(); |
|
7026 |
|
7027 // Test whether this is the top frame or a subframe |
|
7028 bool isTopFrame = true; |
|
7029 nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem; |
|
7030 rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem)); |
|
7031 if (NS_SUCCEEDED(rv) && targetParentTreeItem) { |
|
7032 isTopFrame = false; |
|
7033 } |
|
7034 |
|
7035 // |
|
7036 // If the page load failed, then deal with the error condition... |
|
7037 // Errors are handled as follows: |
|
7038 // 1. Check to see if it's a file not found error or bad content |
|
7039 // encoding error. |
|
7040 // 2. Send the URI to a keyword server (if enabled) |
|
7041 // 3. If the error was DNS failure, then add www and .com to the URI |
|
7042 // (if appropriate). |
|
7043 // 4. Throw an error dialog box... |
|
7044 // |
|
7045 if (url && NS_FAILED(aStatus)) { |
|
7046 if (aStatus == NS_ERROR_FILE_NOT_FOUND || |
|
7047 aStatus == NS_ERROR_CORRUPTED_CONTENT || |
|
7048 aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) { |
|
7049 DisplayLoadError(aStatus, url, nullptr, aChannel); |
|
7050 return NS_OK; |
|
7051 } |
|
7052 |
|
7053 if (sURIFixup) { |
|
7054 // |
|
7055 // Try and make an alternative URI from the old one |
|
7056 // |
|
7057 nsCOMPtr<nsIURI> newURI; |
|
7058 nsCOMPtr<nsIInputStream> newPostData; |
|
7059 |
|
7060 nsAutoCString oldSpec; |
|
7061 url->GetSpec(oldSpec); |
|
7062 |
|
7063 // |
|
7064 // First try keyword fixup |
|
7065 // |
|
7066 if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) { |
|
7067 bool keywordsEnabled = |
|
7068 Preferences::GetBool("keyword.enabled", false); |
|
7069 |
|
7070 nsAutoCString host; |
|
7071 url->GetHost(host); |
|
7072 |
|
7073 nsAutoCString scheme; |
|
7074 url->GetScheme(scheme); |
|
7075 |
|
7076 int32_t dotLoc = host.FindChar('.'); |
|
7077 |
|
7078 // we should only perform a keyword search under the following |
|
7079 // conditions: |
|
7080 // (0) Pref keyword.enabled is true |
|
7081 // (1) the url scheme is http (or https) |
|
7082 // (2) the url does not have a protocol scheme |
|
7083 // If we don't enforce such a policy, then we end up doing |
|
7084 // keyword searchs on urls we don't intend like imap, file, |
|
7085 // mailbox, etc. This could lead to a security problem where we |
|
7086 // send data to the keyword server that we shouldn't be. |
|
7087 // Someone needs to clean up keywords in general so we can |
|
7088 // determine on a per url basis if we want keywords |
|
7089 // enabled...this is just a bandaid... |
|
7090 if (keywordsEnabled && !scheme.IsEmpty() && |
|
7091 (scheme.Find("http") != 0)) { |
|
7092 keywordsEnabled = false; |
|
7093 } |
|
7094 |
|
7095 if (keywordsEnabled && (kNotFound == dotLoc)) { |
|
7096 // only send non-qualified hosts to the keyword server |
|
7097 if (!mOriginalUriString.IsEmpty()) { |
|
7098 sURIFixup->KeywordToURI(mOriginalUriString, |
|
7099 getter_AddRefs(newPostData), |
|
7100 getter_AddRefs(newURI)); |
|
7101 } |
|
7102 else { |
|
7103 // |
|
7104 // If this string was passed through nsStandardURL by |
|
7105 // chance, then it may have been converted from UTF-8 to |
|
7106 // ACE, which would result in a completely bogus keyword |
|
7107 // query. Here we try to recover the original Unicode |
|
7108 // value, but this is not 100% correct since the value may |
|
7109 // have been normalized per the IDN normalization rules. |
|
7110 // |
|
7111 // Since we don't have access to the exact original string |
|
7112 // that was entered by the user, this will just have to do. |
|
7113 bool isACE; |
|
7114 nsAutoCString utf8Host; |
|
7115 nsCOMPtr<nsIIDNService> idnSrv = |
|
7116 do_GetService(NS_IDNSERVICE_CONTRACTID); |
|
7117 if (idnSrv && |
|
7118 NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE && |
|
7119 NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) { |
|
7120 sURIFixup->KeywordToURI(utf8Host, |
|
7121 getter_AddRefs(newPostData), |
|
7122 getter_AddRefs(newURI)); |
|
7123 } else { |
|
7124 sURIFixup->KeywordToURI(host, |
|
7125 getter_AddRefs(newPostData), |
|
7126 getter_AddRefs(newURI)); |
|
7127 } |
|
7128 } |
|
7129 } // end keywordsEnabled |
|
7130 } |
|
7131 |
|
7132 // |
|
7133 // Now try change the address, e.g. turn http://foo into |
|
7134 // http://www.foo.com |
|
7135 // |
|
7136 if (aStatus == NS_ERROR_UNKNOWN_HOST || |
|
7137 aStatus == NS_ERROR_NET_RESET) { |
|
7138 bool doCreateAlternate = true; |
|
7139 |
|
7140 // Skip fixup for anything except a normal document load |
|
7141 // operation on the topframe. |
|
7142 |
|
7143 if (mLoadType != LOAD_NORMAL || !isTopFrame) { |
|
7144 doCreateAlternate = false; |
|
7145 } |
|
7146 else { |
|
7147 // Test if keyword lookup produced a new URI or not |
|
7148 if (newURI) { |
|
7149 bool sameURI = false; |
|
7150 url->Equals(newURI, &sameURI); |
|
7151 if (!sameURI) { |
|
7152 // Keyword lookup made a new URI so no need to try |
|
7153 // an alternate one. |
|
7154 doCreateAlternate = false; |
|
7155 } |
|
7156 } |
|
7157 } |
|
7158 if (doCreateAlternate) { |
|
7159 newURI = nullptr; |
|
7160 newPostData = nullptr; |
|
7161 sURIFixup->CreateFixupURI(oldSpec, |
|
7162 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI, |
|
7163 getter_AddRefs(newPostData), |
|
7164 getter_AddRefs(newURI)); |
|
7165 } |
|
7166 } |
|
7167 |
|
7168 // Did we make a new URI that is different to the old one? If so |
|
7169 // load it. |
|
7170 // |
|
7171 if (newURI) { |
|
7172 // Make sure the new URI is different from the old one, |
|
7173 // otherwise there's little point trying to load it again. |
|
7174 bool sameURI = false; |
|
7175 url->Equals(newURI, &sameURI); |
|
7176 if (!sameURI) { |
|
7177 nsAutoCString newSpec; |
|
7178 newURI->GetSpec(newSpec); |
|
7179 NS_ConvertUTF8toUTF16 newSpecW(newSpec); |
|
7180 |
|
7181 return LoadURI(newSpecW.get(), // URI string |
|
7182 LOAD_FLAGS_NONE, // Load flags |
|
7183 nullptr, // Referring URI |
|
7184 newPostData, // Post data stream |
|
7185 nullptr); // Headers stream |
|
7186 } |
|
7187 } |
|
7188 } |
|
7189 |
|
7190 // Well, fixup didn't work :-( |
|
7191 // It is time to throw an error dialog box, and be done with it... |
|
7192 |
|
7193 // Errors to be shown only on top-level frames |
|
7194 if ((aStatus == NS_ERROR_UNKNOWN_HOST || |
|
7195 aStatus == NS_ERROR_CONNECTION_REFUSED || |
|
7196 aStatus == NS_ERROR_UNKNOWN_PROXY_HOST || |
|
7197 aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) && |
|
7198 (isTopFrame || UseErrorPages())) { |
|
7199 DisplayLoadError(aStatus, url, nullptr, aChannel); |
|
7200 } |
|
7201 // Errors to be shown for any frame |
|
7202 else if (aStatus == NS_ERROR_NET_TIMEOUT || |
|
7203 aStatus == NS_ERROR_REDIRECT_LOOP || |
|
7204 aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE || |
|
7205 aStatus == NS_ERROR_NET_INTERRUPT || |
|
7206 aStatus == NS_ERROR_NET_RESET || |
|
7207 aStatus == NS_ERROR_OFFLINE || |
|
7208 aStatus == NS_ERROR_MALWARE_URI || |
|
7209 aStatus == NS_ERROR_PHISHING_URI || |
|
7210 aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE || |
|
7211 aStatus == NS_ERROR_REMOTE_XUL || |
|
7212 aStatus == NS_ERROR_OFFLINE || |
|
7213 NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { |
|
7214 DisplayLoadError(aStatus, url, nullptr, aChannel); |
|
7215 } |
|
7216 else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) { |
|
7217 // Non-caching channels will simply return NS_ERROR_OFFLINE. |
|
7218 // Caching channels would have to look at their flags to work |
|
7219 // out which error to return. Or we can fix up the error here. |
|
7220 if (!(mLoadType & LOAD_CMD_HISTORY)) |
|
7221 aStatus = NS_ERROR_OFFLINE; |
|
7222 DisplayLoadError(aStatus, url, nullptr, aChannel); |
|
7223 } |
|
7224 } // if we have a host |
|
7225 else if (url && NS_SUCCEEDED(aStatus)) { |
|
7226 mozilla::net::SeerLearnRedirect(url, aChannel, this); |
|
7227 } |
|
7228 |
|
7229 return NS_OK; |
|
7230 } |
|
7231 |
|
7232 |
|
7233 //***************************************************************************** |
|
7234 // nsDocShell: Content Viewer Management |
|
7235 //***************************************************************************** |
|
7236 |
|
7237 NS_IMETHODIMP |
|
7238 nsDocShell::EnsureContentViewer() |
|
7239 { |
|
7240 if (mContentViewer) |
|
7241 return NS_OK; |
|
7242 if (mIsBeingDestroyed) |
|
7243 return NS_ERROR_FAILURE; |
|
7244 |
|
7245 nsCOMPtr<nsIURI> baseURI; |
|
7246 nsIPrincipal* principal = GetInheritedPrincipal(false); |
|
7247 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
7248 GetSameTypeParent(getter_AddRefs(parentItem)); |
|
7249 if (parentItem) { |
|
7250 nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this)); |
|
7251 if (domWin) { |
|
7252 nsCOMPtr<nsIContent> parentContent = |
|
7253 do_QueryInterface(domWin->GetFrameElementInternal()); |
|
7254 if (parentContent) { |
|
7255 baseURI = parentContent->GetBaseURI(); |
|
7256 } |
|
7257 } |
|
7258 } |
|
7259 |
|
7260 nsresult rv = CreateAboutBlankContentViewer(principal, baseURI); |
|
7261 |
|
7262 if (NS_SUCCEEDED(rv)) { |
|
7263 nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this))); |
|
7264 NS_ASSERTION(doc, |
|
7265 "Should have doc if CreateAboutBlankContentViewer " |
|
7266 "succeeded!"); |
|
7267 |
|
7268 doc->SetIsInitialDocument(true); |
|
7269 } |
|
7270 |
|
7271 return rv; |
|
7272 } |
|
7273 |
|
7274 nsresult |
|
7275 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, |
|
7276 nsIURI* aBaseURI, |
|
7277 bool aTryToSaveOldPresentation) |
|
7278 { |
|
7279 nsCOMPtr<nsIDocument> blankDoc; |
|
7280 nsCOMPtr<nsIContentViewer> viewer; |
|
7281 nsresult rv = NS_ERROR_FAILURE; |
|
7282 |
|
7283 /* mCreatingDocument should never be true at this point. However, it's |
|
7284 a theoretical possibility. We want to know about it and make it stop, |
|
7285 and this sounds like a job for an assertion. */ |
|
7286 NS_ASSERTION(!mCreatingDocument, "infinite(?) loop creating document averted"); |
|
7287 if (mCreatingDocument) |
|
7288 return NS_ERROR_FAILURE; |
|
7289 |
|
7290 mCreatingDocument = true; |
|
7291 |
|
7292 // mContentViewer->PermitUnload may release |this| docshell. |
|
7293 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this); |
|
7294 |
|
7295 // Make sure timing is created. But first record whether we had it |
|
7296 // already, so we don't clobber the timing for an in-progress load. |
|
7297 bool hadTiming = mTiming; |
|
7298 MaybeInitTiming(); |
|
7299 if (mContentViewer) { |
|
7300 // We've got a content viewer already. Make sure the user |
|
7301 // permits us to discard the current document and replace it |
|
7302 // with about:blank. And also ensure we fire the unload events |
|
7303 // in the current document. |
|
7304 |
|
7305 // Unload gets fired first for |
|
7306 // document loaded from the session history. |
|
7307 mTiming->NotifyBeforeUnload(); |
|
7308 |
|
7309 bool okToUnload; |
|
7310 rv = mContentViewer->PermitUnload(false, &okToUnload); |
|
7311 |
|
7312 if (NS_SUCCEEDED(rv) && !okToUnload) { |
|
7313 // The user chose not to unload the page, interrupt the load. |
|
7314 return NS_ERROR_FAILURE; |
|
7315 } |
|
7316 |
|
7317 mSavingOldViewer = aTryToSaveOldPresentation && |
|
7318 CanSavePresentation(LOAD_NORMAL, nullptr, nullptr); |
|
7319 |
|
7320 if (mTiming) { |
|
7321 mTiming->NotifyUnloadAccepted(mCurrentURI); |
|
7322 } |
|
7323 |
|
7324 // Make sure to blow away our mLoadingURI just in case. No loads |
|
7325 // from inside this pagehide. |
|
7326 mLoadingURI = nullptr; |
|
7327 |
|
7328 // Stop any in-progress loading, so that we don't accidentally trigger any |
|
7329 // PageShow notifications from Embed() interrupting our loading below. |
|
7330 Stop(); |
|
7331 |
|
7332 // Notify the current document that it is about to be unloaded!! |
|
7333 // |
|
7334 // It is important to fire the unload() notification *before* any state |
|
7335 // is changed within the DocShell - otherwise, javascript will get the |
|
7336 // wrong information :-( |
|
7337 // |
|
7338 (void) FirePageHideNotification(!mSavingOldViewer); |
|
7339 } |
|
7340 |
|
7341 // Now make sure we don't think we're in the middle of firing unload after |
|
7342 // this point. This will make us fire unload when the about:blank document |
|
7343 // unloads... but that's ok, more or less. Would be nice if it fired load |
|
7344 // too, of course. |
|
7345 mFiredUnloadEvent = false; |
|
7346 |
|
7347 nsCOMPtr<nsIDocumentLoaderFactory> docFactory = |
|
7348 nsContentUtils::FindInternalContentViewer("text/html"); |
|
7349 |
|
7350 if (docFactory) { |
|
7351 nsCOMPtr<nsIPrincipal> principal; |
|
7352 if (mSandboxFlags & SANDBOXED_ORIGIN) { |
|
7353 principal = do_CreateInstance("@mozilla.org/nullprincipal;1"); |
|
7354 } else { |
|
7355 principal = aPrincipal; |
|
7356 } |
|
7357 // generate (about:blank) document to load |
|
7358 docFactory->CreateBlankDocument(mLoadGroup, principal, |
|
7359 getter_AddRefs(blankDoc)); |
|
7360 if (blankDoc) { |
|
7361 // Hack: set the base URI manually, since this document never |
|
7362 // got Reset() with a channel. |
|
7363 blankDoc->SetBaseURI(aBaseURI); |
|
7364 |
|
7365 blankDoc->SetContainer(this); |
|
7366 |
|
7367 // Copy our sandbox flags to the document. These are immutable |
|
7368 // after being set here. |
|
7369 blankDoc->SetSandboxFlags(mSandboxFlags); |
|
7370 |
|
7371 // create a content viewer for us and the new document |
|
7372 docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this), |
|
7373 blankDoc, "view", getter_AddRefs(viewer)); |
|
7374 |
|
7375 // hook 'em up |
|
7376 if (viewer) { |
|
7377 viewer->SetContainer(this); |
|
7378 Embed(viewer, "", 0); |
|
7379 |
|
7380 SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0); |
|
7381 rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK; |
|
7382 } |
|
7383 } |
|
7384 } |
|
7385 mCreatingDocument = false; |
|
7386 |
|
7387 // The transient about:blank viewer doesn't have a session history entry. |
|
7388 SetHistoryEntry(&mOSHE, nullptr); |
|
7389 |
|
7390 // Clear out our mTiming like we would in EndPageLoad, if we didn't |
|
7391 // have one before entering this function. |
|
7392 if (!hadTiming) { |
|
7393 mTiming = nullptr; |
|
7394 } |
|
7395 |
|
7396 return rv; |
|
7397 } |
|
7398 |
|
7399 NS_IMETHODIMP |
|
7400 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal) |
|
7401 { |
|
7402 return CreateAboutBlankContentViewer(aPrincipal, nullptr); |
|
7403 } |
|
7404 |
|
7405 bool |
|
7406 nsDocShell::CanSavePresentation(uint32_t aLoadType, |
|
7407 nsIRequest *aNewRequest, |
|
7408 nsIDocument *aNewDocument) |
|
7409 { |
|
7410 if (!mOSHE) |
|
7411 return false; // no entry to save into |
|
7412 |
|
7413 nsCOMPtr<nsIContentViewer> viewer; |
|
7414 mOSHE->GetContentViewer(getter_AddRefs(viewer)); |
|
7415 if (viewer) { |
|
7416 NS_WARNING("mOSHE already has a content viewer!"); |
|
7417 return false; |
|
7418 } |
|
7419 |
|
7420 // Only save presentation for "normal" loads and link loads. Anything else |
|
7421 // probably wants to refetch the page, so caching the old presentation |
|
7422 // would be incorrect. |
|
7423 if (aLoadType != LOAD_NORMAL && |
|
7424 aLoadType != LOAD_HISTORY && |
|
7425 aLoadType != LOAD_LINK && |
|
7426 aLoadType != LOAD_STOP_CONTENT && |
|
7427 aLoadType != LOAD_STOP_CONTENT_AND_REPLACE && |
|
7428 aLoadType != LOAD_ERROR_PAGE) |
|
7429 return false; |
|
7430 |
|
7431 // If the session history entry has the saveLayoutState flag set to false, |
|
7432 // then we should not cache the presentation. |
|
7433 bool canSaveState; |
|
7434 mOSHE->GetSaveLayoutStateFlag(&canSaveState); |
|
7435 if (!canSaveState) |
|
7436 return false; |
|
7437 |
|
7438 // If the document is not done loading, don't cache it. |
|
7439 if (!mScriptGlobal || mScriptGlobal->IsLoading()) |
|
7440 return false; |
|
7441 |
|
7442 if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument)) |
|
7443 return false; |
|
7444 |
|
7445 // Avoid doing the work of saving the presentation state in the case where |
|
7446 // the content viewer cache is disabled. |
|
7447 if (nsSHistory::GetMaxTotalViewers() == 0) |
|
7448 return false; |
|
7449 |
|
7450 // Don't cache the content viewer if we're in a subframe and the subframe |
|
7451 // pref is disabled. |
|
7452 bool cacheFrames = |
|
7453 Preferences::GetBool("browser.sessionhistory.cache_subframes", |
|
7454 false); |
|
7455 if (!cacheFrames) { |
|
7456 nsCOMPtr<nsIDocShellTreeItem> root; |
|
7457 GetSameTypeParent(getter_AddRefs(root)); |
|
7458 if (root && root != this) { |
|
7459 return false; // this is a subframe load |
|
7460 } |
|
7461 } |
|
7462 |
|
7463 // If the document does not want its presentation cached, then don't. |
|
7464 nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc(); |
|
7465 return doc && doc->CanSavePresentation(aNewRequest); |
|
7466 } |
|
7467 |
|
7468 void |
|
7469 nsDocShell::ReattachEditorToWindow(nsISHEntry *aSHEntry) |
|
7470 { |
|
7471 NS_ASSERTION(!mEditorData, |
|
7472 "Why reattach an editor when we already have one?"); |
|
7473 NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(), |
|
7474 "Reattaching when there's not a detached editor."); |
|
7475 |
|
7476 if (mEditorData || !aSHEntry) |
|
7477 return; |
|
7478 |
|
7479 mEditorData = aSHEntry->ForgetEditorData(); |
|
7480 if (mEditorData) { |
|
7481 #ifdef DEBUG |
|
7482 nsresult rv = |
|
7483 #endif |
|
7484 mEditorData->ReattachToWindow(this); |
|
7485 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session"); |
|
7486 } |
|
7487 } |
|
7488 |
|
7489 void |
|
7490 nsDocShell::DetachEditorFromWindow() |
|
7491 { |
|
7492 if (!mEditorData || mEditorData->WaitingForLoad()) { |
|
7493 // If there's nothing to detach, or if the editor data is actually set |
|
7494 // up for the _new_ page that's coming in, don't detach. |
|
7495 return; |
|
7496 } |
|
7497 |
|
7498 NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(), |
|
7499 "Detaching editor when it's already detached."); |
|
7500 |
|
7501 nsresult res = mEditorData->DetachFromWindow(); |
|
7502 NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor"); |
|
7503 |
|
7504 if (NS_SUCCEEDED(res)) { |
|
7505 // Make mOSHE hold the owning ref to the editor data. |
|
7506 if (mOSHE) |
|
7507 mOSHE->SetEditorData(mEditorData.forget()); |
|
7508 else |
|
7509 mEditorData = nullptr; |
|
7510 } |
|
7511 |
|
7512 #ifdef DEBUG |
|
7513 { |
|
7514 bool isEditable; |
|
7515 GetEditable(&isEditable); |
|
7516 NS_ASSERTION(!isEditable, |
|
7517 "Window is still editable after detaching editor."); |
|
7518 } |
|
7519 #endif // DEBUG |
|
7520 } |
|
7521 |
|
7522 nsresult |
|
7523 nsDocShell::CaptureState() |
|
7524 { |
|
7525 if (!mOSHE || mOSHE == mLSHE) { |
|
7526 // No entry to save into, or we're replacing the existing entry. |
|
7527 return NS_ERROR_FAILURE; |
|
7528 } |
|
7529 |
|
7530 if (!mScriptGlobal) |
|
7531 return NS_ERROR_FAILURE; |
|
7532 |
|
7533 nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState(); |
|
7534 NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE); |
|
7535 |
|
7536 #ifdef DEBUG_PAGE_CACHE |
|
7537 nsCOMPtr<nsIURI> uri; |
|
7538 mOSHE->GetURI(getter_AddRefs(uri)); |
|
7539 nsAutoCString spec; |
|
7540 if (uri) |
|
7541 uri->GetSpec(spec); |
|
7542 printf("Saving presentation into session history\n"); |
|
7543 printf(" SH URI: %s\n", spec.get()); |
|
7544 #endif |
|
7545 |
|
7546 nsresult rv = mOSHE->SetWindowState(windowState); |
|
7547 NS_ENSURE_SUCCESS(rv, rv); |
|
7548 |
|
7549 // Suspend refresh URIs and save off the timer queue |
|
7550 rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList); |
|
7551 NS_ENSURE_SUCCESS(rv, rv); |
|
7552 |
|
7553 // Capture the current content viewer bounds. |
|
7554 if (mContentViewer) { |
|
7555 nsIntRect bounds; |
|
7556 mContentViewer->GetBounds(bounds); |
|
7557 rv = mOSHE->SetViewerBounds(bounds); |
|
7558 NS_ENSURE_SUCCESS(rv, rv); |
|
7559 } |
|
7560 |
|
7561 // Capture the docshell hierarchy. |
|
7562 mOSHE->ClearChildShells(); |
|
7563 |
|
7564 uint32_t childCount = mChildList.Length(); |
|
7565 for (uint32_t i = 0; i < childCount; ++i) { |
|
7566 nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i)); |
|
7567 NS_ASSERTION(childShell, "null child shell"); |
|
7568 |
|
7569 mOSHE->AddChildShell(childShell); |
|
7570 } |
|
7571 |
|
7572 return NS_OK; |
|
7573 } |
|
7574 |
|
7575 NS_IMETHODIMP |
|
7576 nsDocShell::RestorePresentationEvent::Run() |
|
7577 { |
|
7578 if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory())) |
|
7579 NS_WARNING("RestoreFromHistory failed"); |
|
7580 return NS_OK; |
|
7581 } |
|
7582 |
|
7583 NS_IMETHODIMP |
|
7584 nsDocShell::BeginRestore(nsIContentViewer *aContentViewer, bool aTop) |
|
7585 { |
|
7586 nsresult rv; |
|
7587 if (!aContentViewer) { |
|
7588 rv = EnsureContentViewer(); |
|
7589 NS_ENSURE_SUCCESS(rv, rv); |
|
7590 |
|
7591 aContentViewer = mContentViewer; |
|
7592 } |
|
7593 |
|
7594 // Dispatch events for restoring the presentation. We try to simulate |
|
7595 // the progress notifications loading the document would cause, so we add |
|
7596 // the document's channel to the loadgroup to initiate stateChange |
|
7597 // notifications. |
|
7598 |
|
7599 nsCOMPtr<nsIDOMDocument> domDoc; |
|
7600 aContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); |
|
7601 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
|
7602 if (doc) { |
|
7603 nsIChannel *channel = doc->GetChannel(); |
|
7604 if (channel) { |
|
7605 mEODForCurrentDocument = false; |
|
7606 mIsRestoringDocument = true; |
|
7607 mLoadGroup->AddRequest(channel, nullptr); |
|
7608 mIsRestoringDocument = false; |
|
7609 } |
|
7610 } |
|
7611 |
|
7612 if (!aTop) { |
|
7613 // This point corresponds to us having gotten OnStartRequest or |
|
7614 // STATE_START, so do the same thing that CreateContentViewer does at |
|
7615 // this point to ensure that unload/pagehide events for this document |
|
7616 // will fire when it's unloaded again. |
|
7617 mFiredUnloadEvent = false; |
|
7618 |
|
7619 // For non-top frames, there is no notion of making sure that the |
|
7620 // previous document is in the domwindow when STATE_START notifications |
|
7621 // happen. We can just call BeginRestore for all of the child shells |
|
7622 // now. |
|
7623 rv = BeginRestoreChildren(); |
|
7624 NS_ENSURE_SUCCESS(rv, rv); |
|
7625 } |
|
7626 |
|
7627 return NS_OK; |
|
7628 } |
|
7629 |
|
7630 nsresult |
|
7631 nsDocShell::BeginRestoreChildren() |
|
7632 { |
|
7633 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
7634 while (iter.HasMore()) { |
|
7635 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext()); |
|
7636 if (child) { |
|
7637 nsresult rv = child->BeginRestore(nullptr, false); |
|
7638 NS_ENSURE_SUCCESS(rv, rv); |
|
7639 } |
|
7640 } |
|
7641 return NS_OK; |
|
7642 } |
|
7643 |
|
7644 NS_IMETHODIMP |
|
7645 nsDocShell::FinishRestore() |
|
7646 { |
|
7647 // First we call finishRestore() on our children. In the simulated load, |
|
7648 // all of the child frames finish loading before the main document. |
|
7649 |
|
7650 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
7651 while (iter.HasMore()) { |
|
7652 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext()); |
|
7653 if (child) { |
|
7654 child->FinishRestore(); |
|
7655 } |
|
7656 } |
|
7657 |
|
7658 if (mOSHE && mOSHE->HasDetachedEditor()) { |
|
7659 ReattachEditorToWindow(mOSHE); |
|
7660 } |
|
7661 |
|
7662 nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this)); |
|
7663 if (doc) { |
|
7664 // Finally, we remove the request from the loadgroup. This will |
|
7665 // cause onStateChange(STATE_STOP) to fire, which will fire the |
|
7666 // pageshow event to the chrome. |
|
7667 |
|
7668 nsIChannel *channel = doc->GetChannel(); |
|
7669 if (channel) { |
|
7670 mIsRestoringDocument = true; |
|
7671 mLoadGroup->RemoveRequest(channel, nullptr, NS_OK); |
|
7672 mIsRestoringDocument = false; |
|
7673 } |
|
7674 } |
|
7675 |
|
7676 return NS_OK; |
|
7677 } |
|
7678 |
|
7679 NS_IMETHODIMP |
|
7680 nsDocShell::GetRestoringDocument(bool *aRestoring) |
|
7681 { |
|
7682 *aRestoring = mIsRestoringDocument; |
|
7683 return NS_OK; |
|
7684 } |
|
7685 |
|
7686 nsresult |
|
7687 nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, bool *aRestoring) |
|
7688 { |
|
7689 NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY, |
|
7690 "RestorePresentation should only be called for history loads"); |
|
7691 |
|
7692 nsCOMPtr<nsIContentViewer> viewer; |
|
7693 aSHEntry->GetContentViewer(getter_AddRefs(viewer)); |
|
7694 |
|
7695 #ifdef DEBUG_PAGE_CACHE |
|
7696 nsCOMPtr<nsIURI> uri; |
|
7697 aSHEntry->GetURI(getter_AddRefs(uri)); |
|
7698 |
|
7699 nsAutoCString spec; |
|
7700 if (uri) |
|
7701 uri->GetSpec(spec); |
|
7702 #endif |
|
7703 |
|
7704 *aRestoring = false; |
|
7705 |
|
7706 if (!viewer) { |
|
7707 #ifdef DEBUG_PAGE_CACHE |
|
7708 printf("no saved presentation for uri: %s\n", spec.get()); |
|
7709 #endif |
|
7710 return NS_OK; |
|
7711 } |
|
7712 |
|
7713 // We need to make sure the content viewer's container is this docshell. |
|
7714 // In subframe navigation, it's possible for the docshell that the |
|
7715 // content viewer was originally loaded into to be replaced with a |
|
7716 // different one. We don't currently support restoring the presentation |
|
7717 // in that case. |
|
7718 |
|
7719 nsCOMPtr<nsIDocShell> container; |
|
7720 viewer->GetContainer(getter_AddRefs(container)); |
|
7721 if (!::SameCOMIdentity(container, GetAsSupports(this))) { |
|
7722 #ifdef DEBUG_PAGE_CACHE |
|
7723 printf("No valid container, clearing presentation\n"); |
|
7724 #endif |
|
7725 aSHEntry->SetContentViewer(nullptr); |
|
7726 return NS_ERROR_FAILURE; |
|
7727 } |
|
7728 |
|
7729 NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation"); |
|
7730 |
|
7731 #ifdef DEBUG_PAGE_CACHE |
|
7732 printf("restoring presentation from session history: %s\n", spec.get()); |
|
7733 #endif |
|
7734 |
|
7735 SetHistoryEntry(&mLSHE, aSHEntry); |
|
7736 |
|
7737 // Add the request to our load group. We do this before swapping out |
|
7738 // the content viewers so that consumers of STATE_START can access |
|
7739 // the old document. We only deal with the toplevel load at this time -- |
|
7740 // to be consistent with normal document loading, subframes cannot start |
|
7741 // loading until after data arrives, which is after STATE_START completes. |
|
7742 |
|
7743 BeginRestore(viewer, true); |
|
7744 |
|
7745 // Post an event that will remove the request after we've returned |
|
7746 // to the event loop. This mimics the way it is called by nsIChannel |
|
7747 // implementations. |
|
7748 |
|
7749 // Revoke any pending restore (just in case) |
|
7750 NS_ASSERTION(!mRestorePresentationEvent.IsPending(), |
|
7751 "should only have one RestorePresentationEvent"); |
|
7752 mRestorePresentationEvent.Revoke(); |
|
7753 |
|
7754 nsRefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this); |
|
7755 nsresult rv = NS_DispatchToCurrentThread(evt); |
|
7756 if (NS_SUCCEEDED(rv)) { |
|
7757 mRestorePresentationEvent = evt.get(); |
|
7758 // The rest of the restore processing will happen on our event |
|
7759 // callback. |
|
7760 *aRestoring = true; |
|
7761 } |
|
7762 |
|
7763 return rv; |
|
7764 } |
|
7765 |
|
7766 nsresult |
|
7767 nsDocShell::RestoreFromHistory() |
|
7768 { |
|
7769 mRestorePresentationEvent.Forget(); |
|
7770 |
|
7771 // This section of code follows the same ordering as CreateContentViewer. |
|
7772 if (!mLSHE) |
|
7773 return NS_ERROR_FAILURE; |
|
7774 |
|
7775 nsCOMPtr<nsIContentViewer> viewer; |
|
7776 mLSHE->GetContentViewer(getter_AddRefs(viewer)); |
|
7777 if (!viewer) |
|
7778 return NS_ERROR_FAILURE; |
|
7779 |
|
7780 if (mSavingOldViewer) { |
|
7781 // We determined that it was safe to cache the document presentation |
|
7782 // at the time we initiated the new load. We need to check whether |
|
7783 // it's still safe to do so, since there may have been DOM mutations |
|
7784 // or new requests initiated. |
|
7785 nsCOMPtr<nsIDOMDocument> domDoc; |
|
7786 viewer->GetDOMDocument(getter_AddRefs(domDoc)); |
|
7787 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
|
7788 nsIRequest *request = nullptr; |
|
7789 if (doc) |
|
7790 request = doc->GetChannel(); |
|
7791 mSavingOldViewer = CanSavePresentation(mLoadType, request, doc); |
|
7792 } |
|
7793 |
|
7794 nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV( |
|
7795 do_QueryInterface(mContentViewer)); |
|
7796 nsCOMPtr<nsIMarkupDocumentViewer> newMUDV( |
|
7797 do_QueryInterface(viewer)); |
|
7798 int32_t minFontSize = 0; |
|
7799 float textZoom = 1.0f; |
|
7800 float pageZoom = 1.0f; |
|
7801 bool styleDisabled = false; |
|
7802 if (oldMUDV && newMUDV) { |
|
7803 oldMUDV->GetMinFontSize(&minFontSize); |
|
7804 oldMUDV->GetTextZoom(&textZoom); |
|
7805 oldMUDV->GetFullZoom(&pageZoom); |
|
7806 oldMUDV->GetAuthorStyleDisabled(&styleDisabled); |
|
7807 } |
|
7808 |
|
7809 // Protect against mLSHE going away via a load triggered from |
|
7810 // pagehide or unload. |
|
7811 nsCOMPtr<nsISHEntry> origLSHE = mLSHE; |
|
7812 |
|
7813 // Make sure to blow away our mLoadingURI just in case. No loads |
|
7814 // from inside this pagehide. |
|
7815 mLoadingURI = nullptr; |
|
7816 |
|
7817 // Notify the old content viewer that it's being hidden. |
|
7818 FirePageHideNotification(!mSavingOldViewer); |
|
7819 |
|
7820 // If mLSHE was changed as a result of the pagehide event, then |
|
7821 // something else was loaded. Don't finish restoring. |
|
7822 if (mLSHE != origLSHE) |
|
7823 return NS_OK; |
|
7824 |
|
7825 // Set mFiredUnloadEvent = false so that the unload handler for the |
|
7826 // *new* document will fire. |
|
7827 mFiredUnloadEvent = false; |
|
7828 |
|
7829 mURIResultedInDocument = true; |
|
7830 nsCOMPtr<nsISHistory> rootSH; |
|
7831 GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
7832 if (rootSH) { |
|
7833 nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH); |
|
7834 rootSH->GetIndex(&mPreviousTransIndex); |
|
7835 hist->UpdateIndex(); |
|
7836 rootSH->GetIndex(&mLoadedTransIndex); |
|
7837 #ifdef DEBUG_PAGE_CACHE |
|
7838 printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex, |
|
7839 mLoadedTransIndex); |
|
7840 #endif |
|
7841 } |
|
7842 |
|
7843 // Rather than call Embed(), we will retrieve the viewer from the session |
|
7844 // history entry and swap it in. |
|
7845 // XXX can we refactor this so that we can just call Embed()? |
|
7846 PersistLayoutHistoryState(); |
|
7847 nsresult rv; |
|
7848 if (mContentViewer) { |
|
7849 if (mSavingOldViewer && NS_FAILED(CaptureState())) { |
|
7850 if (mOSHE) { |
|
7851 mOSHE->SyncPresentationState(); |
|
7852 } |
|
7853 mSavingOldViewer = false; |
|
7854 } |
|
7855 } |
|
7856 |
|
7857 mSavedRefreshURIList = nullptr; |
|
7858 |
|
7859 // In cases where we use a transient about:blank viewer between loads, |
|
7860 // we never show the transient viewer, so _its_ previous viewer is never |
|
7861 // unhooked from the view hierarchy. Destroy any such previous viewer now, |
|
7862 // before we grab the root view sibling, so that we don't grab a view |
|
7863 // that's about to go away. |
|
7864 |
|
7865 if (mContentViewer) { |
|
7866 nsCOMPtr<nsIContentViewer> previousViewer; |
|
7867 mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer)); |
|
7868 if (previousViewer) { |
|
7869 mContentViewer->SetPreviousViewer(nullptr); |
|
7870 previousViewer->Destroy(); |
|
7871 } |
|
7872 } |
|
7873 |
|
7874 // Save off the root view's parent and sibling so that we can insert the |
|
7875 // new content viewer's root view at the same position. Also save the |
|
7876 // bounds of the root view's widget. |
|
7877 |
|
7878 nsView *rootViewSibling = nullptr, *rootViewParent = nullptr; |
|
7879 nsIntRect newBounds(0, 0, 0, 0); |
|
7880 |
|
7881 nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell(); |
|
7882 if (oldPresShell) { |
|
7883 nsViewManager *vm = oldPresShell->GetViewManager(); |
|
7884 if (vm) { |
|
7885 nsView *oldRootView = vm->GetRootView(); |
|
7886 |
|
7887 if (oldRootView) { |
|
7888 rootViewSibling = oldRootView->GetNextSibling(); |
|
7889 rootViewParent = oldRootView->GetParent(); |
|
7890 |
|
7891 mContentViewer->GetBounds(newBounds); |
|
7892 } |
|
7893 } |
|
7894 } |
|
7895 |
|
7896 nsCOMPtr<nsIContent> container; |
|
7897 nsCOMPtr<nsIDocument> sibling; |
|
7898 if (rootViewParent && rootViewParent->GetParent()) { |
|
7899 nsIFrame* frame = rootViewParent->GetParent()->GetFrame(); |
|
7900 container = frame ? frame->GetContent() : nullptr; |
|
7901 } |
|
7902 if (rootViewSibling) { |
|
7903 nsIFrame *frame = rootViewSibling->GetFrame(); |
|
7904 sibling = frame ? frame->PresContext()->PresShell()->GetDocument() : nullptr; |
|
7905 } |
|
7906 |
|
7907 // Transfer ownership to mContentViewer. By ensuring that either the |
|
7908 // docshell or the session history, but not both, have references to the |
|
7909 // content viewer, we prevent the viewer from being torn down after |
|
7910 // Destroy() is called. |
|
7911 |
|
7912 if (mContentViewer) { |
|
7913 mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr); |
|
7914 viewer->SetPreviousViewer(mContentViewer); |
|
7915 } |
|
7916 if (mOSHE && (!mContentViewer || !mSavingOldViewer)) { |
|
7917 // We don't plan to save a viewer in mOSHE; tell it to drop |
|
7918 // any other state it's holding. |
|
7919 mOSHE->SyncPresentationState(); |
|
7920 } |
|
7921 |
|
7922 // Order the mContentViewer setup just like Embed does. |
|
7923 mContentViewer = nullptr; |
|
7924 |
|
7925 // Now that we're about to switch documents, forget all of our children. |
|
7926 // Note that we cached them as needed up in CaptureState above. |
|
7927 DestroyChildren(); |
|
7928 |
|
7929 mContentViewer.swap(viewer); |
|
7930 |
|
7931 // Grab all of the related presentation from the SHEntry now. |
|
7932 // Clearing the viewer from the SHEntry will clear all of this state. |
|
7933 nsCOMPtr<nsISupports> windowState; |
|
7934 mLSHE->GetWindowState(getter_AddRefs(windowState)); |
|
7935 mLSHE->SetWindowState(nullptr); |
|
7936 |
|
7937 bool sticky; |
|
7938 mLSHE->GetSticky(&sticky); |
|
7939 |
|
7940 nsCOMPtr<nsIDOMDocument> domDoc; |
|
7941 mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); |
|
7942 |
|
7943 nsCOMArray<nsIDocShellTreeItem> childShells; |
|
7944 int32_t i = 0; |
|
7945 nsCOMPtr<nsIDocShellTreeItem> child; |
|
7946 while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) && |
|
7947 child) { |
|
7948 childShells.AppendObject(child); |
|
7949 } |
|
7950 |
|
7951 // get the previous content viewer size |
|
7952 nsIntRect oldBounds(0, 0, 0, 0); |
|
7953 mLSHE->GetViewerBounds(oldBounds); |
|
7954 |
|
7955 // Restore the refresh URI list. The refresh timers will be restarted |
|
7956 // when EndPageLoad() is called. |
|
7957 nsCOMPtr<nsISupportsArray> refreshURIList; |
|
7958 mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList)); |
|
7959 |
|
7960 // Reattach to the window object. |
|
7961 mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive |
|
7962 rv = mContentViewer->Open(windowState, mLSHE); |
|
7963 mIsRestoringDocument = false; |
|
7964 |
|
7965 // Hack to keep nsDocShellEditorData alive across the |
|
7966 // SetContentViewer(nullptr) call below. |
|
7967 nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData()); |
|
7968 |
|
7969 // Now remove it from the cached presentation. |
|
7970 mLSHE->SetContentViewer(nullptr); |
|
7971 mEODForCurrentDocument = false; |
|
7972 |
|
7973 mLSHE->SetEditorData(data.forget()); |
|
7974 |
|
7975 #ifdef DEBUG |
|
7976 { |
|
7977 nsCOMPtr<nsISupportsArray> refreshURIs; |
|
7978 mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs)); |
|
7979 nsCOMPtr<nsIDocShellTreeItem> childShell; |
|
7980 mLSHE->ChildShellAt(0, getter_AddRefs(childShell)); |
|
7981 NS_ASSERTION(!refreshURIs && !childShell, |
|
7982 "SHEntry should have cleared presentation state"); |
|
7983 } |
|
7984 #endif |
|
7985 |
|
7986 // Restore the sticky state of the viewer. The viewer has set this state |
|
7987 // on the history entry in Destroy() just before marking itself non-sticky, |
|
7988 // to avoid teardown of the presentation. |
|
7989 mContentViewer->SetSticky(sticky); |
|
7990 |
|
7991 NS_ENSURE_SUCCESS(rv, rv); |
|
7992 |
|
7993 // mLSHE is now our currently-loaded document. |
|
7994 SetHistoryEntry(&mOSHE, mLSHE); |
|
7995 |
|
7996 // XXX special wyciwyg handling in Embed()? |
|
7997 |
|
7998 // We aren't going to restore any items from the LayoutHistoryState, |
|
7999 // but we don't want them to stay around in case the page is reloaded. |
|
8000 SetLayoutHistoryState(nullptr); |
|
8001 |
|
8002 // This is the end of our Embed() replacement |
|
8003 |
|
8004 mSavingOldViewer = false; |
|
8005 mEODForCurrentDocument = false; |
|
8006 |
|
8007 // Tell the event loop to favor plevents over user events, see comments |
|
8008 // in CreateContentViewer. |
|
8009 if (++gNumberOfDocumentsLoading == 1) |
|
8010 FavorPerformanceHint(true); |
|
8011 |
|
8012 |
|
8013 if (oldMUDV && newMUDV) { |
|
8014 newMUDV->SetMinFontSize(minFontSize); |
|
8015 newMUDV->SetTextZoom(textZoom); |
|
8016 newMUDV->SetFullZoom(pageZoom); |
|
8017 newMUDV->SetAuthorStyleDisabled(styleDisabled); |
|
8018 } |
|
8019 |
|
8020 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc); |
|
8021 uint32_t parentSuspendCount = 0; |
|
8022 if (document) { |
|
8023 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
8024 GetParent(getter_AddRefs(parent)); |
|
8025 nsCOMPtr<nsIDocument> d = do_GetInterface(parent); |
|
8026 if (d) { |
|
8027 if (d->EventHandlingSuppressed()) { |
|
8028 document->SuppressEventHandling(nsIDocument::eEvents, |
|
8029 d->EventHandlingSuppressed()); |
|
8030 } |
|
8031 |
|
8032 // Ick, it'd be nicer to not rewalk all of the subdocs here. |
|
8033 if (d->AnimationsPaused()) { |
|
8034 document->SuppressEventHandling(nsIDocument::eAnimationsOnly, |
|
8035 d->AnimationsPaused()); |
|
8036 } |
|
8037 |
|
8038 nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow(); |
|
8039 if (parentWindow) { |
|
8040 parentSuspendCount = parentWindow->TimeoutSuspendCount(); |
|
8041 } |
|
8042 } |
|
8043 |
|
8044 // Use the uri from the mLSHE we had when we entered this function |
|
8045 // (which need not match the document's URI if anchors are involved), |
|
8046 // since that's the history entry we're loading. Note that if we use |
|
8047 // origLSHE we don't have to worry about whether the entry in question |
|
8048 // is still mLSHE or whether it's now mOSHE. |
|
8049 nsCOMPtr<nsIURI> uri; |
|
8050 origLSHE->GetURI(getter_AddRefs(uri)); |
|
8051 SetCurrentURI(uri, document->GetChannel(), true, 0); |
|
8052 } |
|
8053 |
|
8054 // This is the end of our CreateContentViewer() replacement. |
|
8055 // Now we simulate a load. First, we restore the state of the javascript |
|
8056 // window object. |
|
8057 nsCOMPtr<nsPIDOMWindow> privWin = |
|
8058 do_GetInterface(static_cast<nsIInterfaceRequestor*>(this)); |
|
8059 NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface"); |
|
8060 |
|
8061 rv = privWin->RestoreWindowState(windowState); |
|
8062 NS_ENSURE_SUCCESS(rv, rv); |
|
8063 |
|
8064 // Now, dispatch a title change event which would happen as the |
|
8065 // <head> is parsed. |
|
8066 document->NotifyPossibleTitleChange(false); |
|
8067 |
|
8068 // Now we simulate appending child docshells for subframes. |
|
8069 for (i = 0; i < childShells.Count(); ++i) { |
|
8070 nsIDocShellTreeItem *childItem = childShells.ObjectAt(i); |
|
8071 nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem); |
|
8072 |
|
8073 // Make sure to not clobber the state of the child. Since AddChild |
|
8074 // always clobbers it, save it off first. |
|
8075 bool allowPlugins; |
|
8076 childShell->GetAllowPlugins(&allowPlugins); |
|
8077 |
|
8078 bool allowJavascript; |
|
8079 childShell->GetAllowJavascript(&allowJavascript); |
|
8080 |
|
8081 bool allowRedirects; |
|
8082 childShell->GetAllowMetaRedirects(&allowRedirects); |
|
8083 |
|
8084 bool allowSubframes; |
|
8085 childShell->GetAllowSubframes(&allowSubframes); |
|
8086 |
|
8087 bool allowImages; |
|
8088 childShell->GetAllowImages(&allowImages); |
|
8089 |
|
8090 bool allowMedia = childShell->GetAllowMedia(); |
|
8091 |
|
8092 bool allowDNSPrefetch; |
|
8093 childShell->GetAllowDNSPrefetch(&allowDNSPrefetch); |
|
8094 |
|
8095 bool allowContentRetargeting = childShell->GetAllowContentRetargeting(); |
|
8096 |
|
8097 uint32_t defaultLoadFlags; |
|
8098 childShell->GetDefaultLoadFlags(&defaultLoadFlags); |
|
8099 |
|
8100 // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning |
|
8101 // that the child inherits our state. Among other things, this means |
|
8102 // that the child inherits our mIsActive and mInPrivateBrowsing, which |
|
8103 // is what we want. |
|
8104 AddChild(childItem); |
|
8105 |
|
8106 childShell->SetAllowPlugins(allowPlugins); |
|
8107 childShell->SetAllowJavascript(allowJavascript); |
|
8108 childShell->SetAllowMetaRedirects(allowRedirects); |
|
8109 childShell->SetAllowSubframes(allowSubframes); |
|
8110 childShell->SetAllowImages(allowImages); |
|
8111 childShell->SetAllowMedia(allowMedia); |
|
8112 childShell->SetAllowDNSPrefetch(allowDNSPrefetch); |
|
8113 childShell->SetAllowContentRetargeting(allowContentRetargeting); |
|
8114 childShell->SetDefaultLoadFlags(defaultLoadFlags); |
|
8115 |
|
8116 rv = childShell->BeginRestore(nullptr, false); |
|
8117 NS_ENSURE_SUCCESS(rv, rv); |
|
8118 } |
|
8119 |
|
8120 nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
|
8121 |
|
8122 // We may be displayed on a different monitor (or in a different |
|
8123 // HiDPI mode) than when we got into the history list. So we need |
|
8124 // to check if this has happened. See bug 838239. |
|
8125 |
|
8126 // Because the prescontext normally handles resolution changes via |
|
8127 // a runnable (see nsPresContext::UIResolutionChanged), its device |
|
8128 // context won't be -immediately- updated as a result of calling |
|
8129 // shell->BackingScaleFactorChanged(). |
|
8130 |
|
8131 // But we depend on that device context when adjusting the view size |
|
8132 // via mContentViewer->SetBounds(newBounds) below. So we need to |
|
8133 // explicitly tell it to check for changed resolution here. |
|
8134 if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) { |
|
8135 shell->BackingScaleFactorChanged(); |
|
8136 } |
|
8137 |
|
8138 nsViewManager *newVM = shell ? shell->GetViewManager() : nullptr; |
|
8139 nsView *newRootView = newVM ? newVM->GetRootView() : nullptr; |
|
8140 |
|
8141 // Insert the new root view at the correct location in the view tree. |
|
8142 if (container) { |
|
8143 nsSubDocumentFrame* subDocFrame = do_QueryFrame(container->GetPrimaryFrame()); |
|
8144 rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr; |
|
8145 } |
|
8146 if (sibling && |
|
8147 sibling->GetShell() && |
|
8148 sibling->GetShell()->GetViewManager()) { |
|
8149 rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView(); |
|
8150 } else { |
|
8151 rootViewSibling = nullptr; |
|
8152 } |
|
8153 if (rootViewParent && newRootView && newRootView->GetParent() != rootViewParent) { |
|
8154 nsViewManager *parentVM = rootViewParent->GetViewManager(); |
|
8155 if (parentVM) { |
|
8156 // InsertChild(parent, child, sib, true) inserts the child after |
|
8157 // sib in content order, which is before sib in view order. BUT |
|
8158 // when sib is null it inserts at the end of the the document |
|
8159 // order, i.e., first in view order. But when oldRootSibling is |
|
8160 // null, the old root as at the end of the view list --- last in |
|
8161 // content order --- and we want to call InsertChild(parent, child, |
|
8162 // nullptr, false) in that case. |
|
8163 parentVM->InsertChild(rootViewParent, newRootView, |
|
8164 rootViewSibling, |
|
8165 rootViewSibling ? true : false); |
|
8166 |
|
8167 NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling, |
|
8168 "error in InsertChild"); |
|
8169 } |
|
8170 } |
|
8171 |
|
8172 // If parent is suspended, increase suspension count. |
|
8173 // This can't be done as early as event suppression since this |
|
8174 // depends on docshell tree. |
|
8175 if (parentSuspendCount) { |
|
8176 privWin->SuspendTimeouts(parentSuspendCount, false); |
|
8177 } |
|
8178 |
|
8179 // Now that all of the child docshells have been put into place, we can |
|
8180 // restart the timers for the window and all of the child frames. |
|
8181 privWin->ResumeTimeouts(); |
|
8182 |
|
8183 // Restore the refresh URI list. The refresh timers will be restarted |
|
8184 // when EndPageLoad() is called. |
|
8185 mRefreshURIList = refreshURIList; |
|
8186 |
|
8187 // Meta-refresh timers have been restarted for this shell, but not |
|
8188 // for our children. Walk the child shells and restart their timers. |
|
8189 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList); |
|
8190 while (iter.HasMore()) { |
|
8191 nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext()); |
|
8192 if (child) |
|
8193 child->ResumeRefreshURIs(); |
|
8194 } |
|
8195 |
|
8196 // Make sure this presentation is the same size as the previous |
|
8197 // presentation. If this is not the same size we showed it at last time, |
|
8198 // then we need to resize the widget. |
|
8199 |
|
8200 // XXXbryner This interacts poorly with Firefox's infobar. If the old |
|
8201 // presentation had the infobar visible, then we will resize the new |
|
8202 // presentation to that smaller size. However, firing the locationchanged |
|
8203 // event will hide the infobar, which will immediately resize the window |
|
8204 // back to the larger size. A future optimization might be to restore |
|
8205 // the presentation at the "wrong" size, then fire the locationchanged |
|
8206 // event and check whether the docshell's new size is the same as the |
|
8207 // cached viewer size (skipping the resize if they are equal). |
|
8208 |
|
8209 if (newRootView) { |
|
8210 if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) { |
|
8211 #ifdef DEBUG_PAGE_CACHE |
|
8212 printf("resize widget(%d, %d, %d, %d)\n", newBounds.x, |
|
8213 newBounds.y, newBounds.width, newBounds.height); |
|
8214 #endif |
|
8215 mContentViewer->SetBounds(newBounds); |
|
8216 } else { |
|
8217 nsIScrollableFrame *rootScrollFrame = |
|
8218 shell->GetRootScrollFrameAsScrollableExternal(); |
|
8219 if (rootScrollFrame) { |
|
8220 rootScrollFrame->PostScrolledAreaEventForCurrentArea(); |
|
8221 } |
|
8222 } |
|
8223 } |
|
8224 |
|
8225 // The FinishRestore call below can kill these, null them out so we don't |
|
8226 // have invalid pointer lying around. |
|
8227 newRootView = rootViewSibling = rootViewParent = nullptr; |
|
8228 newVM = nullptr; |
|
8229 |
|
8230 // Simulate the completion of the load. |
|
8231 nsDocShell::FinishRestore(); |
|
8232 |
|
8233 // Restart plugins, and paint the content. |
|
8234 if (shell) { |
|
8235 shell->Thaw(); |
|
8236 } |
|
8237 |
|
8238 return privWin->FireDelayedDOMEvents(); |
|
8239 } |
|
8240 |
|
8241 NS_IMETHODIMP |
|
8242 nsDocShell::CreateContentViewer(const char *aContentType, |
|
8243 nsIRequest * request, |
|
8244 nsIStreamListener ** aContentHandler) |
|
8245 { |
|
8246 *aContentHandler = nullptr; |
|
8247 |
|
8248 // Can we check the content type of the current content viewer |
|
8249 // and reuse it without destroying it and re-creating it? |
|
8250 |
|
8251 NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?"); |
|
8252 |
|
8253 // Instantiate the content viewer object |
|
8254 nsCOMPtr<nsIContentViewer> viewer; |
|
8255 nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup, |
|
8256 aContentHandler, getter_AddRefs(viewer)); |
|
8257 |
|
8258 if (NS_FAILED(rv)) |
|
8259 return rv; |
|
8260 |
|
8261 // Notify the current document that it is about to be unloaded!! |
|
8262 // |
|
8263 // It is important to fire the unload() notification *before* any state |
|
8264 // is changed within the DocShell - otherwise, javascript will get the |
|
8265 // wrong information :-( |
|
8266 // |
|
8267 |
|
8268 if (mSavingOldViewer) { |
|
8269 // We determined that it was safe to cache the document presentation |
|
8270 // at the time we initiated the new load. We need to check whether |
|
8271 // it's still safe to do so, since there may have been DOM mutations |
|
8272 // or new requests initiated. |
|
8273 nsCOMPtr<nsIDOMDocument> domDoc; |
|
8274 viewer->GetDOMDocument(getter_AddRefs(domDoc)); |
|
8275 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
|
8276 mSavingOldViewer = CanSavePresentation(mLoadType, request, doc); |
|
8277 } |
|
8278 |
|
8279 NS_ASSERTION(!mLoadingURI, "Re-entering unload?"); |
|
8280 |
|
8281 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request); |
|
8282 if (aOpenedChannel) { |
|
8283 aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI)); |
|
8284 } |
|
8285 FirePageHideNotification(!mSavingOldViewer); |
|
8286 mLoadingURI = nullptr; |
|
8287 |
|
8288 // Set mFiredUnloadEvent = false so that the unload handler for the |
|
8289 // *new* document will fire. |
|
8290 mFiredUnloadEvent = false; |
|
8291 |
|
8292 // we've created a new document so go ahead and call |
|
8293 // OnLoadingSite(), but don't fire OnLocationChange() |
|
8294 // notifications before we've called Embed(). See bug 284993. |
|
8295 mURIResultedInDocument = true; |
|
8296 |
|
8297 if (mLoadType == LOAD_ERROR_PAGE) { |
|
8298 // We need to set the SH entry and our current URI here and not |
|
8299 // at the moment we load the page. We want the same behavior |
|
8300 // of Stop() as for a normal page load. See bug 514232 for details. |
|
8301 |
|
8302 // Revert mLoadType to load type to state the page load failed, |
|
8303 // following function calls need it. |
|
8304 mLoadType = mFailedLoadType; |
|
8305 |
|
8306 nsCOMPtr<nsIChannel> failedChannel = mFailedChannel; |
|
8307 |
|
8308 // Make sure we have a URI to set currentURI. |
|
8309 nsCOMPtr<nsIURI> failedURI; |
|
8310 if (failedChannel) { |
|
8311 NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI)); |
|
8312 } |
|
8313 |
|
8314 if (!failedURI) { |
|
8315 failedURI = mFailedURI; |
|
8316 } |
|
8317 if (!failedURI) { |
|
8318 // We need a URI object to store a session history entry, so make up a URI |
|
8319 NS_NewURI(getter_AddRefs(failedURI), "about:blank"); |
|
8320 } |
|
8321 |
|
8322 // When we don't have failedURI, something wrong will happen. See |
|
8323 // bug 291876. |
|
8324 MOZ_ASSERT(failedURI, "We don't have a URI for history APIs."); |
|
8325 |
|
8326 mFailedChannel = nullptr; |
|
8327 mFailedURI = nullptr; |
|
8328 |
|
8329 // Create an shistory entry for the old load. |
|
8330 if (failedURI) { |
|
8331 bool errorOnLocationChangeNeeded = |
|
8332 OnNewURI(failedURI, failedChannel, nullptr, mLoadType, false, |
|
8333 false, false); |
|
8334 |
|
8335 if (errorOnLocationChangeNeeded) { |
|
8336 FireOnLocationChange(this, failedChannel, failedURI, |
|
8337 LOCATION_CHANGE_ERROR_PAGE); |
|
8338 } |
|
8339 } |
|
8340 |
|
8341 // Be sure to have a correct mLSHE, it may have been cleared by |
|
8342 // EndPageLoad. See bug 302115. |
|
8343 if (mSessionHistory && !mLSHE) { |
|
8344 int32_t idx; |
|
8345 mSessionHistory->GetRequestedIndex(&idx); |
|
8346 if (idx == -1) |
|
8347 mSessionHistory->GetIndex(&idx); |
|
8348 mSessionHistory->GetEntryAtIndex(idx, false, |
|
8349 getter_AddRefs(mLSHE)); |
|
8350 } |
|
8351 |
|
8352 mLoadType = LOAD_ERROR_PAGE; |
|
8353 } |
|
8354 |
|
8355 bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false); |
|
8356 |
|
8357 // let's try resetting the load group if we need to... |
|
8358 nsCOMPtr<nsILoadGroup> currentLoadGroup; |
|
8359 NS_ENSURE_SUCCESS(aOpenedChannel-> |
|
8360 GetLoadGroup(getter_AddRefs(currentLoadGroup)), |
|
8361 NS_ERROR_FAILURE); |
|
8362 |
|
8363 if (currentLoadGroup != mLoadGroup) { |
|
8364 nsLoadFlags loadFlags = 0; |
|
8365 |
|
8366 //Cancel any URIs that are currently loading... |
|
8367 /// XXX: Need to do this eventually Stop(); |
|
8368 // |
|
8369 // Retarget the document to this loadgroup... |
|
8370 // |
|
8371 /* First attach the channel to the right loadgroup |
|
8372 * and then remove from the old loadgroup. This |
|
8373 * puts the notifications in the right order and |
|
8374 * we don't null-out mLSHE in OnStateChange() for |
|
8375 * all redirected urls |
|
8376 */ |
|
8377 aOpenedChannel->SetLoadGroup(mLoadGroup); |
|
8378 |
|
8379 // Mark the channel as being a document URI... |
|
8380 aOpenedChannel->GetLoadFlags(&loadFlags); |
|
8381 loadFlags |= nsIChannel::LOAD_DOCUMENT_URI; |
|
8382 |
|
8383 aOpenedChannel->SetLoadFlags(loadFlags); |
|
8384 |
|
8385 mLoadGroup->AddRequest(request, nullptr); |
|
8386 if (currentLoadGroup) |
|
8387 currentLoadGroup->RemoveRequest(request, nullptr, |
|
8388 NS_BINDING_RETARGETED); |
|
8389 |
|
8390 // Update the notification callbacks, so that progress and |
|
8391 // status information are sent to the right docshell... |
|
8392 aOpenedChannel->SetNotificationCallbacks(this); |
|
8393 } |
|
8394 |
|
8395 NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nullptr), |
|
8396 NS_ERROR_FAILURE); |
|
8397 |
|
8398 mSavedRefreshURIList = nullptr; |
|
8399 mSavingOldViewer = false; |
|
8400 mEODForCurrentDocument = false; |
|
8401 |
|
8402 // if this document is part of a multipart document, |
|
8403 // the ID can be used to distinguish it from the other parts. |
|
8404 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(request)); |
|
8405 if (multiPartChannel) { |
|
8406 nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
|
8407 if (NS_SUCCEEDED(rv) && shell) { |
|
8408 nsIDocument *doc = shell->GetDocument(); |
|
8409 if (doc) { |
|
8410 uint32_t partID; |
|
8411 multiPartChannel->GetPartID(&partID); |
|
8412 doc->SetPartID(partID); |
|
8413 } |
|
8414 } |
|
8415 } |
|
8416 |
|
8417 // Give hint to native plevent dispatch mechanism. If a document |
|
8418 // is loading the native plevent dispatch mechanism should favor |
|
8419 // performance over normal native event dispatch priorities. |
|
8420 if (++gNumberOfDocumentsLoading == 1) { |
|
8421 // Hint to favor performance for the plevent notification mechanism. |
|
8422 // We want the pages to load as fast as possible even if its means |
|
8423 // native messages might be starved. |
|
8424 FavorPerformanceHint(true); |
|
8425 } |
|
8426 |
|
8427 if (onLocationChangeNeeded) { |
|
8428 FireOnLocationChange(this, request, mCurrentURI, 0); |
|
8429 } |
|
8430 |
|
8431 return NS_OK; |
|
8432 } |
|
8433 |
|
8434 nsresult |
|
8435 nsDocShell::NewContentViewerObj(const char *aContentType, |
|
8436 nsIRequest * request, nsILoadGroup * aLoadGroup, |
|
8437 nsIStreamListener ** aContentHandler, |
|
8438 nsIContentViewer ** aViewer) |
|
8439 { |
|
8440 nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request); |
|
8441 |
|
8442 nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory = |
|
8443 nsContentUtils::FindInternalContentViewer(aContentType); |
|
8444 if (!docLoaderFactory) { |
|
8445 return NS_ERROR_FAILURE; |
|
8446 } |
|
8447 |
|
8448 // Now create an instance of the content viewer |
|
8449 // nsLayoutDLF makes the determination if it should be a "view-source" instead of "view" |
|
8450 nsresult rv = docLoaderFactory->CreateInstance("view", |
|
8451 aOpenedChannel, |
|
8452 aLoadGroup, aContentType, |
|
8453 this, |
|
8454 nullptr, |
|
8455 aContentHandler, |
|
8456 aViewer); |
|
8457 NS_ENSURE_SUCCESS(rv, rv); |
|
8458 |
|
8459 (*aViewer)->SetContainer(this); |
|
8460 return NS_OK; |
|
8461 } |
|
8462 |
|
8463 NS_IMETHODIMP |
|
8464 nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) |
|
8465 { |
|
8466 // |
|
8467 // Copy content viewer state from previous or parent content viewer. |
|
8468 // |
|
8469 // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad! |
|
8470 // |
|
8471 // Do NOT to maintain a reference to the old content viewer outside |
|
8472 // of this "copying" block, or it will not be destroyed until the end of |
|
8473 // this routine and all <SCRIPT>s and event handlers fail! (bug 20315) |
|
8474 // |
|
8475 // In this block of code, if we get an error result, we return it |
|
8476 // but if we get a null pointer, that's perfectly legal for parent |
|
8477 // and parentContentViewer. |
|
8478 // |
|
8479 |
|
8480 int32_t x = 0; |
|
8481 int32_t y = 0; |
|
8482 int32_t cx = 0; |
|
8483 int32_t cy = 0; |
|
8484 |
|
8485 // This will get the size from the current content viewer or from the |
|
8486 // Init settings |
|
8487 DoGetPositionAndSize(&x, &y, &cx, &cy); |
|
8488 |
|
8489 nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
|
8490 NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)), |
|
8491 NS_ERROR_FAILURE); |
|
8492 nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem)); |
|
8493 |
|
8494 nsAutoCString forceCharset; |
|
8495 nsAutoCString hintCharset; |
|
8496 int32_t hintCharsetSource; |
|
8497 int32_t minFontSize; |
|
8498 float textZoom; |
|
8499 float pageZoom; |
|
8500 bool styleDisabled; |
|
8501 // |newMUDV| also serves as a flag to set the data from the above vars |
|
8502 nsCOMPtr<nsIMarkupDocumentViewer> newMUDV; |
|
8503 |
|
8504 if (mContentViewer || parent) { |
|
8505 nsCOMPtr<nsIMarkupDocumentViewer> oldMUDV; |
|
8506 if (mContentViewer) { |
|
8507 // Get any interesting state from old content viewer |
|
8508 // XXX: it would be far better to just reuse the document viewer , |
|
8509 // since we know we're just displaying the same document as before |
|
8510 oldMUDV = do_QueryInterface(mContentViewer); |
|
8511 |
|
8512 // Tell the old content viewer to hibernate in session history when |
|
8513 // it is destroyed. |
|
8514 |
|
8515 if (mSavingOldViewer && NS_FAILED(CaptureState())) { |
|
8516 if (mOSHE) { |
|
8517 mOSHE->SyncPresentationState(); |
|
8518 } |
|
8519 mSavingOldViewer = false; |
|
8520 } |
|
8521 } |
|
8522 else { |
|
8523 // No old content viewer, so get state from parent's content viewer |
|
8524 nsCOMPtr<nsIContentViewer> parentContentViewer; |
|
8525 parent->GetContentViewer(getter_AddRefs(parentContentViewer)); |
|
8526 oldMUDV = do_QueryInterface(parentContentViewer); |
|
8527 } |
|
8528 |
|
8529 if (oldMUDV) { |
|
8530 nsresult rv; |
|
8531 |
|
8532 newMUDV = do_QueryInterface(aNewViewer,&rv); |
|
8533 if (newMUDV) { |
|
8534 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8535 GetForceCharacterSet(forceCharset), |
|
8536 NS_ERROR_FAILURE); |
|
8537 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8538 GetHintCharacterSet(hintCharset), |
|
8539 NS_ERROR_FAILURE); |
|
8540 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8541 GetHintCharacterSetSource(&hintCharsetSource), |
|
8542 NS_ERROR_FAILURE); |
|
8543 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8544 GetMinFontSize(&minFontSize), |
|
8545 NS_ERROR_FAILURE); |
|
8546 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8547 GetTextZoom(&textZoom), |
|
8548 NS_ERROR_FAILURE); |
|
8549 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8550 GetFullZoom(&pageZoom), |
|
8551 NS_ERROR_FAILURE); |
|
8552 NS_ENSURE_SUCCESS(oldMUDV-> |
|
8553 GetAuthorStyleDisabled(&styleDisabled), |
|
8554 NS_ERROR_FAILURE); |
|
8555 } |
|
8556 } |
|
8557 } |
|
8558 |
|
8559 nscolor bgcolor = NS_RGBA(0, 0, 0, 0); |
|
8560 // Ensure that the content viewer is destroyed *after* the GC - bug 71515 |
|
8561 nsCOMPtr<nsIContentViewer> kungfuDeathGrip = mContentViewer; |
|
8562 if (mContentViewer) { |
|
8563 // Stop any activity that may be happening in the old document before |
|
8564 // releasing it... |
|
8565 mContentViewer->Stop(); |
|
8566 |
|
8567 // Try to extract the canvas background color from the old |
|
8568 // presentation shell, so we can use it for the next document. |
|
8569 nsCOMPtr<nsIPresShell> shell; |
|
8570 mContentViewer->GetPresShell(getter_AddRefs(shell)); |
|
8571 |
|
8572 if (shell) { |
|
8573 bgcolor = shell->GetCanvasBackground(); |
|
8574 } |
|
8575 |
|
8576 mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr); |
|
8577 aNewViewer->SetPreviousViewer(mContentViewer); |
|
8578 } |
|
8579 if (mOSHE && (!mContentViewer || !mSavingOldViewer)) { |
|
8580 // We don't plan to save a viewer in mOSHE; tell it to drop |
|
8581 // any other state it's holding. |
|
8582 mOSHE->SyncPresentationState(); |
|
8583 } |
|
8584 |
|
8585 mContentViewer = nullptr; |
|
8586 |
|
8587 // Now that we're about to switch documents, forget all of our children. |
|
8588 // Note that we cached them as needed up in CaptureState above. |
|
8589 DestroyChildren(); |
|
8590 |
|
8591 mContentViewer = aNewViewer; |
|
8592 |
|
8593 nsCOMPtr<nsIWidget> widget; |
|
8594 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE); |
|
8595 |
|
8596 nsIntRect bounds(x, y, cx, cy); |
|
8597 |
|
8598 mContentViewer->SetNavigationTiming(mTiming); |
|
8599 |
|
8600 if (NS_FAILED(mContentViewer->Init(widget, bounds))) { |
|
8601 mContentViewer = nullptr; |
|
8602 NS_ERROR("ContentViewer Initialization failed"); |
|
8603 return NS_ERROR_FAILURE; |
|
8604 } |
|
8605 |
|
8606 // If we have old state to copy, set the old state onto the new content |
|
8607 // viewer |
|
8608 if (newMUDV) { |
|
8609 NS_ENSURE_SUCCESS(newMUDV->SetForceCharacterSet(forceCharset), |
|
8610 NS_ERROR_FAILURE); |
|
8611 NS_ENSURE_SUCCESS(newMUDV->SetHintCharacterSet(hintCharset), |
|
8612 NS_ERROR_FAILURE); |
|
8613 NS_ENSURE_SUCCESS(newMUDV-> |
|
8614 SetHintCharacterSetSource(hintCharsetSource), |
|
8615 NS_ERROR_FAILURE); |
|
8616 NS_ENSURE_SUCCESS(newMUDV->SetMinFontSize(minFontSize), |
|
8617 NS_ERROR_FAILURE); |
|
8618 NS_ENSURE_SUCCESS(newMUDV->SetTextZoom(textZoom), |
|
8619 NS_ERROR_FAILURE); |
|
8620 NS_ENSURE_SUCCESS(newMUDV->SetFullZoom(pageZoom), |
|
8621 NS_ERROR_FAILURE); |
|
8622 NS_ENSURE_SUCCESS(newMUDV->SetAuthorStyleDisabled(styleDisabled), |
|
8623 NS_ERROR_FAILURE); |
|
8624 } |
|
8625 |
|
8626 // Stuff the bgcolor from the old pres shell into the new |
|
8627 // pres shell. This improves page load continuity. |
|
8628 nsCOMPtr<nsIPresShell> shell; |
|
8629 mContentViewer->GetPresShell(getter_AddRefs(shell)); |
|
8630 |
|
8631 if (shell) { |
|
8632 shell->SetCanvasBackground(bgcolor); |
|
8633 } |
|
8634 |
|
8635 // XXX: It looks like the LayoutState gets restored again in Embed() |
|
8636 // right after the call to SetupNewViewer(...) |
|
8637 |
|
8638 // We don't show the mContentViewer yet, since we want to draw the old page |
|
8639 // until we have enough of the new page to show. Just return with the new |
|
8640 // viewer still set to hidden. |
|
8641 |
|
8642 return NS_OK; |
|
8643 } |
|
8644 |
|
8645 nsresult |
|
8646 nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry) |
|
8647 { |
|
8648 nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this)); |
|
8649 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); |
|
8650 |
|
8651 nsCOMPtr<nsIStructuredCloneContainer> scContainer; |
|
8652 if (shEntry) { |
|
8653 nsresult rv = shEntry->GetStateData(getter_AddRefs(scContainer)); |
|
8654 NS_ENSURE_SUCCESS(rv, rv); |
|
8655 |
|
8656 // If shEntry is null, just set the document's state object to null. |
|
8657 } |
|
8658 |
|
8659 // It's OK for scContainer too be null here; that just means there's no |
|
8660 // state data associated with this history entry. |
|
8661 document->SetStateObject(scContainer); |
|
8662 |
|
8663 return NS_OK; |
|
8664 } |
|
8665 |
|
8666 nsresult |
|
8667 nsDocShell::CheckLoadingPermissions() |
|
8668 { |
|
8669 // This method checks whether the caller may load content into |
|
8670 // this docshell. Even though we've done our best to hide windows |
|
8671 // from code that doesn't have the right to access them, it's |
|
8672 // still possible for an evil site to open a window and access |
|
8673 // frames in the new window through window.frames[] (which is |
|
8674 // allAccess for historic reasons), so we still need to do this |
|
8675 // check on load. |
|
8676 nsresult rv = NS_OK, sameOrigin = NS_OK; |
|
8677 |
|
8678 if (!gValidateOrigin || !IsFrame()) { |
|
8679 // Origin validation was turned off, or we're not a frame. |
|
8680 // Permit all loads. |
|
8681 |
|
8682 return rv; |
|
8683 } |
|
8684 |
|
8685 nsCOMPtr<nsIScriptSecurityManager> securityManager = |
|
8686 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); |
|
8687 NS_ENSURE_SUCCESS(rv, rv); |
|
8688 |
|
8689 // We're a frame. Check that the caller has write permission to |
|
8690 // the parent before allowing it to load anything into this |
|
8691 // docshell. |
|
8692 nsCOMPtr<nsIPrincipal> subjPrincipal; |
|
8693 rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal)); |
|
8694 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv); |
|
8695 |
|
8696 // Check if the caller is from the same origin as this docshell, |
|
8697 // or any of its ancestors. |
|
8698 nsCOMPtr<nsIDocShellTreeItem> item(this); |
|
8699 do { |
|
8700 nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item)); |
|
8701 nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo)); |
|
8702 |
|
8703 nsIPrincipal *p; |
|
8704 if (!sop || !(p = sop->GetPrincipal())) { |
|
8705 return NS_ERROR_UNEXPECTED; |
|
8706 } |
|
8707 |
|
8708 // Compare origins |
|
8709 bool subsumes; |
|
8710 sameOrigin = subjPrincipal->Subsumes(p, &subsumes); |
|
8711 if (NS_SUCCEEDED(sameOrigin)) { |
|
8712 if (subsumes) { |
|
8713 // Same origin, permit load |
|
8714 |
|
8715 return sameOrigin; |
|
8716 } |
|
8717 |
|
8718 sameOrigin = NS_ERROR_DOM_PROP_ACCESS_DENIED; |
|
8719 } |
|
8720 |
|
8721 nsCOMPtr<nsIDocShellTreeItem> tmp; |
|
8722 item->GetSameTypeParent(getter_AddRefs(tmp)); |
|
8723 item.swap(tmp); |
|
8724 } while (item); |
|
8725 |
|
8726 return sameOrigin; |
|
8727 } |
|
8728 |
|
8729 //***************************************************************************** |
|
8730 // nsDocShell: Site Loading |
|
8731 //***************************************************************************** |
|
8732 namespace |
|
8733 { |
|
8734 |
|
8735 #ifdef MOZ_PLACES |
|
8736 // Callback used by CopyFavicon to inform the favicon service that one URI |
|
8737 // (mNewURI) has the same favicon URI (OnComplete's aFaviconURI) as another. |
|
8738 class nsCopyFaviconCallback MOZ_FINAL : public nsIFaviconDataCallback |
|
8739 { |
|
8740 public: |
|
8741 NS_DECL_ISUPPORTS |
|
8742 |
|
8743 nsCopyFaviconCallback(nsIURI *aNewURI, bool aInPrivateBrowsing) |
|
8744 : mNewURI(aNewURI) |
|
8745 , mInPrivateBrowsing(aInPrivateBrowsing) |
|
8746 { |
|
8747 } |
|
8748 |
|
8749 NS_IMETHODIMP |
|
8750 OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen, |
|
8751 const uint8_t *aData, const nsACString &aMimeType) |
|
8752 { |
|
8753 // Continue only if there is an associated favicon. |
|
8754 if (!aFaviconURI) { |
|
8755 return NS_OK; |
|
8756 } |
|
8757 |
|
8758 NS_ASSERTION(aDataLen == 0, |
|
8759 "We weren't expecting the callback to deliver data."); |
|
8760 nsCOMPtr<mozIAsyncFavicons> favSvc = |
|
8761 do_GetService("@mozilla.org/browser/favicon-service;1"); |
|
8762 NS_ENSURE_STATE(favSvc); |
|
8763 |
|
8764 return favSvc->SetAndFetchFaviconForPage(mNewURI, aFaviconURI, |
|
8765 false, |
|
8766 mInPrivateBrowsing ? |
|
8767 nsIFaviconService::FAVICON_LOAD_PRIVATE : |
|
8768 nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, |
|
8769 nullptr); |
|
8770 } |
|
8771 |
|
8772 private: |
|
8773 nsCOMPtr<nsIURI> mNewURI; |
|
8774 bool mInPrivateBrowsing; |
|
8775 }; |
|
8776 |
|
8777 NS_IMPL_ISUPPORTS(nsCopyFaviconCallback, nsIFaviconDataCallback) |
|
8778 #endif |
|
8779 |
|
8780 // Tell the favicon service that aNewURI has the same favicon as aOldURI. |
|
8781 void CopyFavicon(nsIURI *aOldURI, nsIURI *aNewURI, bool inPrivateBrowsing) |
|
8782 { |
|
8783 #ifdef MOZ_PLACES |
|
8784 nsCOMPtr<mozIAsyncFavicons> favSvc = |
|
8785 do_GetService("@mozilla.org/browser/favicon-service;1"); |
|
8786 if (favSvc) { |
|
8787 nsCOMPtr<nsIFaviconDataCallback> callback = |
|
8788 new nsCopyFaviconCallback(aNewURI, inPrivateBrowsing); |
|
8789 favSvc->GetFaviconURLForPage(aOldURI, callback); |
|
8790 } |
|
8791 #endif |
|
8792 } |
|
8793 |
|
8794 } // anonymous namespace |
|
8795 |
|
8796 class InternalLoadEvent : public nsRunnable |
|
8797 { |
|
8798 public: |
|
8799 InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer, |
|
8800 nsISupports * aOwner, uint32_t aFlags, |
|
8801 const char* aTypeHint, nsIInputStream * aPostData, |
|
8802 nsIInputStream * aHeadersData, uint32_t aLoadType, |
|
8803 nsISHEntry * aSHEntry, bool aFirstParty, |
|
8804 const nsAString &aSrcdoc, nsIDocShell* aSourceDocShell, |
|
8805 nsIURI * aBaseURI) : |
|
8806 mSrcdoc(aSrcdoc), |
|
8807 mDocShell(aDocShell), |
|
8808 mURI(aURI), |
|
8809 mReferrer(aReferrer), |
|
8810 mOwner(aOwner), |
|
8811 mPostData(aPostData), |
|
8812 mHeadersData(aHeadersData), |
|
8813 mSHEntry(aSHEntry), |
|
8814 mFlags(aFlags), |
|
8815 mLoadType(aLoadType), |
|
8816 mFirstParty(aFirstParty), |
|
8817 mSourceDocShell(aSourceDocShell), |
|
8818 mBaseURI(aBaseURI) |
|
8819 { |
|
8820 // Make sure to keep null things null as needed |
|
8821 if (aTypeHint) { |
|
8822 mTypeHint = aTypeHint; |
|
8823 } |
|
8824 } |
|
8825 |
|
8826 NS_IMETHOD Run() { |
|
8827 return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags, |
|
8828 nullptr, mTypeHint.get(), |
|
8829 NullString(), mPostData, mHeadersData, |
|
8830 mLoadType, mSHEntry, mFirstParty, |
|
8831 mSrcdoc, mSourceDocShell, mBaseURI, |
|
8832 nullptr, nullptr); |
|
8833 } |
|
8834 |
|
8835 private: |
|
8836 |
|
8837 // Use IDL strings so .get() returns null by default |
|
8838 nsXPIDLString mWindowTarget; |
|
8839 nsXPIDLCString mTypeHint; |
|
8840 nsString mSrcdoc; |
|
8841 |
|
8842 nsRefPtr<nsDocShell> mDocShell; |
|
8843 nsCOMPtr<nsIURI> mURI; |
|
8844 nsCOMPtr<nsIURI> mReferrer; |
|
8845 nsCOMPtr<nsISupports> mOwner; |
|
8846 nsCOMPtr<nsIInputStream> mPostData; |
|
8847 nsCOMPtr<nsIInputStream> mHeadersData; |
|
8848 nsCOMPtr<nsISHEntry> mSHEntry; |
|
8849 uint32_t mFlags; |
|
8850 uint32_t mLoadType; |
|
8851 bool mFirstParty; |
|
8852 nsCOMPtr<nsIDocShell> mSourceDocShell; |
|
8853 nsCOMPtr<nsIURI> mBaseURI; |
|
8854 }; |
|
8855 |
|
8856 /** |
|
8857 * Returns true if we started an asynchronous load (i.e., from the network), but |
|
8858 * the document we're loading there hasn't yet become this docshell's active |
|
8859 * document. |
|
8860 * |
|
8861 * When JustStartedNetworkLoad is true, you should be careful about modifying |
|
8862 * mLoadType and mLSHE. These are both set when the asynchronous load first |
|
8863 * starts, and the load expects that, when it eventually runs InternalLoad, |
|
8864 * mLoadType and mLSHE will have their original values. |
|
8865 */ |
|
8866 bool |
|
8867 nsDocShell::JustStartedNetworkLoad() |
|
8868 { |
|
8869 return mDocumentRequest && |
|
8870 mDocumentRequest != GetCurrentDocChannel(); |
|
8871 } |
|
8872 |
|
8873 NS_IMETHODIMP |
|
8874 nsDocShell::InternalLoad(nsIURI * aURI, |
|
8875 nsIURI * aReferrer, |
|
8876 nsISupports * aOwner, |
|
8877 uint32_t aFlags, |
|
8878 const char16_t *aWindowTarget, |
|
8879 const char* aTypeHint, |
|
8880 const nsAString& aFileName, |
|
8881 nsIInputStream * aPostData, |
|
8882 nsIInputStream * aHeadersData, |
|
8883 uint32_t aLoadType, |
|
8884 nsISHEntry * aSHEntry, |
|
8885 bool aFirstParty, |
|
8886 const nsAString &aSrcdoc, |
|
8887 nsIDocShell* aSourceDocShell, |
|
8888 nsIURI* aBaseURI, |
|
8889 nsIDocShell** aDocShell, |
|
8890 nsIRequest** aRequest) |
|
8891 { |
|
8892 nsresult rv = NS_OK; |
|
8893 mOriginalUriString.Truncate(); |
|
8894 |
|
8895 #ifdef PR_LOGGING |
|
8896 if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) { |
|
8897 nsAutoCString spec; |
|
8898 if (aURI) |
|
8899 aURI->GetSpec(spec); |
|
8900 PR_LogPrint("DOCSHELL %p InternalLoad %s\n", this, spec.get()); |
|
8901 } |
|
8902 #endif |
|
8903 // Initialize aDocShell/aRequest |
|
8904 if (aDocShell) { |
|
8905 *aDocShell = nullptr; |
|
8906 } |
|
8907 if (aRequest) { |
|
8908 *aRequest = nullptr; |
|
8909 } |
|
8910 |
|
8911 if (!aURI) { |
|
8912 return NS_ERROR_NULL_POINTER; |
|
8913 } |
|
8914 |
|
8915 NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG); |
|
8916 |
|
8917 NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE); |
|
8918 |
|
8919 // wyciwyg urls can only be loaded through history. Any normal load of |
|
8920 // wyciwyg through docshell is illegal. Disallow such loads. |
|
8921 if (aLoadType & LOAD_CMD_NORMAL) { |
|
8922 bool isWyciwyg = false; |
|
8923 rv = aURI->SchemeIs("wyciwyg", &isWyciwyg); |
|
8924 if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) |
|
8925 return NS_ERROR_FAILURE; |
|
8926 } |
|
8927 |
|
8928 bool bIsJavascript = false; |
|
8929 if (NS_FAILED(aURI->SchemeIs("javascript", &bIsJavascript))) { |
|
8930 bIsJavascript = false; |
|
8931 } |
|
8932 |
|
8933 // |
|
8934 // First, notify any nsIContentPolicy listeners about the document load. |
|
8935 // Only abort the load if a content policy listener explicitly vetos it! |
|
8936 // |
|
8937 nsCOMPtr<Element> requestingElement; |
|
8938 // Use nsPIDOMWindow since we _want_ to cross the chrome boundary if needed |
|
8939 if (mScriptGlobal) |
|
8940 requestingElement = mScriptGlobal->GetFrameElementInternal(); |
|
8941 |
|
8942 nsRefPtr<nsGlobalWindow> MMADeathGrip = mScriptGlobal; |
|
8943 |
|
8944 int16_t shouldLoad = nsIContentPolicy::ACCEPT; |
|
8945 uint32_t contentType; |
|
8946 bool isNewDocShell = false; |
|
8947 bool isTargetTopLevelDocShell = false; |
|
8948 nsCOMPtr<nsIDocShell> targetDocShell; |
|
8949 if (aWindowTarget && *aWindowTarget) { |
|
8950 // Locate the target DocShell. |
|
8951 nsCOMPtr<nsIDocShellTreeItem> targetItem; |
|
8952 rv = FindItemWithName(aWindowTarget, nullptr, this, |
|
8953 getter_AddRefs(targetItem)); |
|
8954 NS_ENSURE_SUCCESS(rv, rv); |
|
8955 |
|
8956 targetDocShell = do_QueryInterface(targetItem); |
|
8957 // If the targetDocShell doesn't exist, then this is a new docShell |
|
8958 // and we should consider this a TYPE_DOCUMENT load |
|
8959 isNewDocShell = !targetDocShell; |
|
8960 |
|
8961 // If the targetDocShell and the rootDocShell are the same, then the |
|
8962 // targetDocShell is the top level document and hence we should |
|
8963 // consider this TYPE_DOCUMENT |
|
8964 if (targetDocShell) { |
|
8965 nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot; |
|
8966 targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); |
|
8967 NS_ASSERTION(sameTypeRoot, "No document shell root tree item from targetDocShell!"); |
|
8968 nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot); |
|
8969 NS_ASSERTION(rootShell, "No root docshell from document shell root tree item."); |
|
8970 |
|
8971 if (targetDocShell == rootShell) { |
|
8972 isTargetTopLevelDocShell = true; |
|
8973 } |
|
8974 } |
|
8975 } |
|
8976 if (IsFrame() && !isNewDocShell && !isTargetTopLevelDocShell) { |
|
8977 NS_ASSERTION(requestingElement, "A frame but no DOM element!?"); |
|
8978 contentType = nsIContentPolicy::TYPE_SUBDOCUMENT; |
|
8979 } else { |
|
8980 contentType = nsIContentPolicy::TYPE_DOCUMENT; |
|
8981 } |
|
8982 |
|
8983 nsISupports* context = requestingElement; |
|
8984 if (!context) { |
|
8985 context = ToSupports(mScriptGlobal); |
|
8986 } |
|
8987 |
|
8988 // XXXbz would be nice to know the loading principal here... but we don't |
|
8989 nsCOMPtr<nsIPrincipal> loadingPrincipal = do_QueryInterface(aOwner); |
|
8990 if (!loadingPrincipal && aReferrer) { |
|
8991 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
8992 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); |
|
8993 NS_ENSURE_SUCCESS(rv, rv); |
|
8994 |
|
8995 rv = secMan->GetSimpleCodebasePrincipal(aReferrer, |
|
8996 getter_AddRefs(loadingPrincipal)); |
|
8997 } |
|
8998 |
|
8999 rv = NS_CheckContentLoadPolicy(contentType, |
|
9000 aURI, |
|
9001 loadingPrincipal, |
|
9002 context, |
|
9003 EmptyCString(), //mime guess |
|
9004 nullptr, //extra |
|
9005 &shouldLoad); |
|
9006 |
|
9007 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) { |
|
9008 if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) { |
|
9009 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT; |
|
9010 } |
|
9011 |
|
9012 return NS_ERROR_CONTENT_BLOCKED; |
|
9013 } |
|
9014 |
|
9015 nsCOMPtr<nsISupports> owner(aOwner); |
|
9016 // |
|
9017 // Get an owner from the current document if necessary. Note that we only |
|
9018 // do this for URIs that inherit a security context and local file URIs; |
|
9019 // in particular we do NOT do this for about:blank. This way, random |
|
9020 // about:blank loads that have no owner (which basically means they were |
|
9021 // done by someone from chrome manually messing with our nsIWebNavigation |
|
9022 // or by C++ setting document.location) don't get a funky principal. If |
|
9023 // callers want something interesting to happen with the about:blank |
|
9024 // principal in this case, they should pass an owner in. |
|
9025 // |
|
9026 { |
|
9027 bool inherits; |
|
9028 // One more twist: Don't inherit the owner for external loads. |
|
9029 if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner && |
|
9030 (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) && |
|
9031 NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI, |
|
9032 &inherits)) && |
|
9033 inherits) { |
|
9034 |
|
9035 owner = GetInheritedPrincipal(true); |
|
9036 } |
|
9037 } |
|
9038 |
|
9039 // Don't allow loads that would inherit our security context |
|
9040 // if this document came from an unsafe channel. |
|
9041 { |
|
9042 bool willInherit; |
|
9043 // This condition needs to match the one in |
|
9044 // nsContentUtils::SetUpChannelOwner. |
|
9045 // Except we reverse the rv check to be safe in case |
|
9046 // nsContentUtils::URIInheritsSecurityContext fails here and |
|
9047 // succeeds there. |
|
9048 rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit); |
|
9049 if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) { |
|
9050 nsCOMPtr<nsIDocShellTreeItem> treeItem = this; |
|
9051 do { |
|
9052 nsCOMPtr<nsIDocShell> itemDocShell = |
|
9053 do_QueryInterface(treeItem); |
|
9054 bool isUnsafe; |
|
9055 if (itemDocShell && |
|
9056 NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) && |
|
9057 isUnsafe) { |
|
9058 return NS_ERROR_DOM_SECURITY_ERR; |
|
9059 } |
|
9060 |
|
9061 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
9062 treeItem->GetSameTypeParent(getter_AddRefs(parent)); |
|
9063 parent.swap(treeItem); |
|
9064 } while (treeItem); |
|
9065 } |
|
9066 } |
|
9067 |
|
9068 // |
|
9069 // Resolve the window target before going any further... |
|
9070 // If the load has been targeted to another DocShell, then transfer the |
|
9071 // load to it... |
|
9072 // |
|
9073 if (aWindowTarget && *aWindowTarget) { |
|
9074 // We've already done our owner-inheriting. Mask out that bit, so we |
|
9075 // don't try inheriting an owner from the target window if we came up |
|
9076 // with a null owner above. |
|
9077 aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER; |
|
9078 |
|
9079 bool isNewWindow = false; |
|
9080 if (!targetDocShell) { |
|
9081 // If the docshell's document is sandboxed, only open a new window |
|
9082 // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set. |
|
9083 // (i.e. if allow-popups is specified) |
|
9084 NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE); |
|
9085 nsIDocument* doc = mContentViewer->GetDocument(); |
|
9086 uint32_t sandboxFlags = 0; |
|
9087 |
|
9088 if (doc) { |
|
9089 sandboxFlags = doc->GetSandboxFlags(); |
|
9090 if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) { |
|
9091 return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
|
9092 } |
|
9093 } |
|
9094 |
|
9095 nsCOMPtr<nsPIDOMWindow> win = |
|
9096 do_GetInterface(GetAsSupports(this)); |
|
9097 NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE); |
|
9098 |
|
9099 nsDependentString name(aWindowTarget); |
|
9100 nsCOMPtr<nsIDOMWindow> newWin; |
|
9101 nsAutoCString spec; |
|
9102 if (aURI) |
|
9103 aURI->GetSpec(spec); |
|
9104 rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec), |
|
9105 name, // window name |
|
9106 EmptyString(), // Features |
|
9107 getter_AddRefs(newWin)); |
|
9108 |
|
9109 // In some cases the Open call doesn't actually result in a new |
|
9110 // window being opened. We can detect these cases by examining the |
|
9111 // document in |newWin|, if any. |
|
9112 nsCOMPtr<nsPIDOMWindow> piNewWin = do_QueryInterface(newWin); |
|
9113 if (piNewWin) { |
|
9114 nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc(); |
|
9115 if (!newDoc || newDoc->IsInitialDocument()) { |
|
9116 isNewWindow = true; |
|
9117 aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD; |
|
9118 } |
|
9119 } |
|
9120 |
|
9121 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin); |
|
9122 targetDocShell = do_QueryInterface(webNav); |
|
9123 } |
|
9124 |
|
9125 // |
|
9126 // Transfer the load to the target DocShell... Pass nullptr as the |
|
9127 // window target name from to prevent recursive retargeting! |
|
9128 // |
|
9129 if (NS_SUCCEEDED(rv) && targetDocShell) { |
|
9130 rv = targetDocShell->InternalLoad(aURI, |
|
9131 aReferrer, |
|
9132 owner, |
|
9133 aFlags, |
|
9134 nullptr, // No window target |
|
9135 aTypeHint, |
|
9136 NullString(), // No forced download |
|
9137 aPostData, |
|
9138 aHeadersData, |
|
9139 aLoadType, |
|
9140 aSHEntry, |
|
9141 aFirstParty, |
|
9142 aSrcdoc, |
|
9143 aSourceDocShell, |
|
9144 aBaseURI, |
|
9145 aDocShell, |
|
9146 aRequest); |
|
9147 if (rv == NS_ERROR_NO_CONTENT) { |
|
9148 // XXXbz except we never reach this code! |
|
9149 if (isNewWindow) { |
|
9150 // |
|
9151 // At this point, a new window has been created, but the |
|
9152 // URI did not have any data associated with it... |
|
9153 // |
|
9154 // So, the best we can do, is to tear down the new window |
|
9155 // that was just created! |
|
9156 // |
|
9157 nsCOMPtr<nsIDOMWindow> domWin = |
|
9158 do_GetInterface(targetDocShell); |
|
9159 if (domWin) { |
|
9160 domWin->Close(); |
|
9161 } |
|
9162 } |
|
9163 // |
|
9164 // NS_ERROR_NO_CONTENT should not be returned to the |
|
9165 // caller... This is an internal error code indicating that |
|
9166 // the URI had no data associated with it - probably a |
|
9167 // helper-app style protocol (ie. mailto://) |
|
9168 // |
|
9169 rv = NS_OK; |
|
9170 } |
|
9171 else if (isNewWindow) { |
|
9172 // XXX: Once new windows are created hidden, the new |
|
9173 // window will need to be made visible... For now, |
|
9174 // do nothing. |
|
9175 } |
|
9176 } |
|
9177 |
|
9178 // Else we ran out of memory, or were a popup and got blocked, |
|
9179 // or something. |
|
9180 |
|
9181 return rv; |
|
9182 } |
|
9183 |
|
9184 // |
|
9185 // Load is being targetted at this docshell so return an error if the |
|
9186 // docshell is in the process of being destroyed. |
|
9187 // |
|
9188 if (mIsBeingDestroyed) { |
|
9189 return NS_ERROR_FAILURE; |
|
9190 } |
|
9191 |
|
9192 NS_ENSURE_STATE(!HasUnloadedParent()); |
|
9193 |
|
9194 rv = CheckLoadingPermissions(); |
|
9195 if (NS_FAILED(rv)) { |
|
9196 return rv; |
|
9197 } |
|
9198 |
|
9199 if (mFiredUnloadEvent) { |
|
9200 if (IsOKToLoadURI(aURI)) { |
|
9201 NS_PRECONDITION(!aWindowTarget || !*aWindowTarget, |
|
9202 "Shouldn't have a window target here!"); |
|
9203 |
|
9204 // If this is a replace load, make whatever load triggered |
|
9205 // the unload event also a replace load, so we don't |
|
9206 // create extra history entries. |
|
9207 if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) { |
|
9208 mLoadType = LOAD_NORMAL_REPLACE; |
|
9209 } |
|
9210 |
|
9211 // Do this asynchronously |
|
9212 nsCOMPtr<nsIRunnable> ev = |
|
9213 new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags, |
|
9214 aTypeHint, aPostData, aHeadersData, |
|
9215 aLoadType, aSHEntry, aFirstParty, aSrcdoc, |
|
9216 aSourceDocShell, aBaseURI); |
|
9217 return NS_DispatchToCurrentThread(ev); |
|
9218 } |
|
9219 |
|
9220 // Just ignore this load attempt |
|
9221 return NS_OK; |
|
9222 } |
|
9223 |
|
9224 // If a source docshell has been passed, check to see if we are sandboxed |
|
9225 // from it as the result of an iframe or CSP sandbox. |
|
9226 if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) { |
|
9227 return NS_ERROR_DOM_INVALID_ACCESS_ERR; |
|
9228 } |
|
9229 |
|
9230 // If this docshell is owned by a frameloader, make sure to cancel |
|
9231 // possible frameloader initialization before loading a new page. |
|
9232 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
9233 GetParent(getter_AddRefs(parent)); |
|
9234 if (parent) { |
|
9235 nsCOMPtr<nsIDocument> doc = do_GetInterface(parent); |
|
9236 if (doc) { |
|
9237 doc->TryCancelFrameLoaderInitialization(this); |
|
9238 } |
|
9239 } |
|
9240 |
|
9241 // Before going any further vet loads initiated by external programs. |
|
9242 if (aLoadType == LOAD_NORMAL_EXTERNAL) { |
|
9243 // Disallow external chrome: loads targetted at content windows |
|
9244 bool isChrome = false; |
|
9245 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) { |
|
9246 NS_WARNING("blocked external chrome: url -- use '-chrome' option"); |
|
9247 return NS_ERROR_FAILURE; |
|
9248 } |
|
9249 |
|
9250 // clear the decks to prevent context bleed-through (bug 298255) |
|
9251 rv = CreateAboutBlankContentViewer(nullptr, nullptr); |
|
9252 if (NS_FAILED(rv)) |
|
9253 return NS_ERROR_FAILURE; |
|
9254 |
|
9255 // reset loadType so we don't have to add lots of tests for |
|
9256 // LOAD_NORMAL_EXTERNAL after this point |
|
9257 aLoadType = LOAD_NORMAL; |
|
9258 } |
|
9259 |
|
9260 mAllowKeywordFixup = |
|
9261 (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0; |
|
9262 mURIResultedInDocument = false; // reset the clock... |
|
9263 |
|
9264 if (aLoadType == LOAD_NORMAL || |
|
9265 aLoadType == LOAD_STOP_CONTENT || |
|
9266 LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) || |
|
9267 aLoadType == LOAD_HISTORY || |
|
9268 aLoadType == LOAD_LINK) { |
|
9269 |
|
9270 nsCOMPtr<nsIURI> currentURI = mCurrentURI; |
|
9271 // Split currentURI and aURI on the '#' character. Make sure we read |
|
9272 // the return values of SplitURIAtHash; if it fails, we don't want to |
|
9273 // allow a short-circuited navigation. |
|
9274 nsAutoCString curBeforeHash, curHash, newBeforeHash, newHash; |
|
9275 nsresult splitRv1, splitRv2; |
|
9276 splitRv1 = currentURI ? |
|
9277 nsContentUtils::SplitURIAtHash(currentURI, |
|
9278 curBeforeHash, curHash) : |
|
9279 NS_ERROR_FAILURE; |
|
9280 splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash); |
|
9281 |
|
9282 bool sameExceptHashes = NS_SUCCEEDED(splitRv1) && |
|
9283 NS_SUCCEEDED(splitRv2) && |
|
9284 curBeforeHash.Equals(newBeforeHash); |
|
9285 |
|
9286 if (!sameExceptHashes && sURIFixup && currentURI && |
|
9287 NS_SUCCEEDED(splitRv2)) { |
|
9288 // Maybe aURI came from the exposable form of currentURI? |
|
9289 nsCOMPtr<nsIURI> currentExposableURI; |
|
9290 rv = sURIFixup->CreateExposableURI(currentURI, |
|
9291 getter_AddRefs(currentExposableURI)); |
|
9292 NS_ENSURE_SUCCESS(rv, rv); |
|
9293 splitRv1 = nsContentUtils::SplitURIAtHash(currentExposableURI, |
|
9294 curBeforeHash, curHash); |
|
9295 sameExceptHashes = NS_SUCCEEDED(splitRv1) && |
|
9296 curBeforeHash.Equals(newBeforeHash); |
|
9297 } |
|
9298 |
|
9299 bool historyNavBetweenSameDoc = false; |
|
9300 if (mOSHE && aSHEntry) { |
|
9301 // We're doing a history load. |
|
9302 |
|
9303 mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc); |
|
9304 |
|
9305 #ifdef DEBUG |
|
9306 if (historyNavBetweenSameDoc) { |
|
9307 nsCOMPtr<nsIInputStream> currentPostData; |
|
9308 mOSHE->GetPostData(getter_AddRefs(currentPostData)); |
|
9309 NS_ASSERTION(currentPostData == aPostData, |
|
9310 "Different POST data for entries for the same page?"); |
|
9311 } |
|
9312 #endif |
|
9313 } |
|
9314 |
|
9315 // A short-circuited load happens when we navigate between two SHEntries |
|
9316 // for the same document. We do a short-circuited load under two |
|
9317 // circumstances. Either |
|
9318 // |
|
9319 // a) we're navigating between two different SHEntries which share a |
|
9320 // document, or |
|
9321 // |
|
9322 // b) we're navigating to a new shentry whose URI differs from the |
|
9323 // current URI only in its hash, the new hash is non-empty, and |
|
9324 // we're not doing a POST. |
|
9325 // |
|
9326 // The restriction tha the SHEntries in (a) must be different ensures |
|
9327 // that history.go(0) and the like trigger full refreshes, rather than |
|
9328 // short-circuited loads. |
|
9329 bool doShortCircuitedLoad = |
|
9330 (historyNavBetweenSameDoc && mOSHE != aSHEntry) || |
|
9331 (!aSHEntry && aPostData == nullptr && |
|
9332 sameExceptHashes && !newHash.IsEmpty()); |
|
9333 |
|
9334 if (doShortCircuitedLoad) { |
|
9335 // Save the position of the scrollers. |
|
9336 nscoord cx = 0, cy = 0; |
|
9337 GetCurScrollPos(ScrollOrientation_X, &cx); |
|
9338 GetCurScrollPos(ScrollOrientation_Y, &cy); |
|
9339 |
|
9340 // ScrollToAnchor doesn't necessarily cause us to scroll the window; |
|
9341 // the function decides whether a scroll is appropriate based on the |
|
9342 // arguments it receives. But even if we don't end up scrolling, |
|
9343 // ScrollToAnchor performs other important tasks, such as informing |
|
9344 // the presShell that we have a new hash. See bug 680257. |
|
9345 rv = ScrollToAnchor(curHash, newHash, aLoadType); |
|
9346 NS_ENSURE_SUCCESS(rv, rv); |
|
9347 |
|
9348 // Reset mLoadType to its original value once we exit this block, |
|
9349 // because this short-circuited load might have started after a |
|
9350 // normal, network load, and we don't want to clobber its load type. |
|
9351 // See bug 737307. |
|
9352 AutoRestore<uint32_t> loadTypeResetter(mLoadType); |
|
9353 |
|
9354 // If a non-short-circuit load (i.e., a network load) is pending, |
|
9355 // make this a replacement load, so that we don't add a SHEntry here |
|
9356 // and the network load goes into the SHEntry it expects to. |
|
9357 if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) { |
|
9358 mLoadType = LOAD_NORMAL_REPLACE; |
|
9359 } |
|
9360 else { |
|
9361 mLoadType = aLoadType; |
|
9362 } |
|
9363 |
|
9364 mURIResultedInDocument = true; |
|
9365 |
|
9366 nsCOMPtr<nsISHEntry> oldLSHE = mLSHE; |
|
9367 |
|
9368 /* we need to assign mLSHE to aSHEntry right here, so that on History loads, |
|
9369 * SetCurrentURI() called from OnNewURI() will send proper |
|
9370 * onLocationChange() notifications to the browser to update |
|
9371 * back/forward buttons. |
|
9372 */ |
|
9373 SetHistoryEntry(&mLSHE, aSHEntry); |
|
9374 |
|
9375 /* This is a anchor traversal with in the same page. |
|
9376 * call OnNewURI() so that, this traversal will be |
|
9377 * recorded in session and global history. |
|
9378 */ |
|
9379 nsCOMPtr<nsISupports> owner; |
|
9380 if (mOSHE) { |
|
9381 mOSHE->GetOwner(getter_AddRefs(owner)); |
|
9382 } |
|
9383 // Pass true for aCloneSHChildren, since we're not |
|
9384 // changing documents here, so all of our subframes are |
|
9385 // still relevant to the new session history entry. |
|
9386 // |
|
9387 // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT |
|
9388 // flag on firing onLocationChange(...). |
|
9389 // Anyway, aCloneSHChildren param is simply reflecting |
|
9390 // doShortCircuitedLoad in this scope. |
|
9391 OnNewURI(aURI, nullptr, owner, mLoadType, true, true, true); |
|
9392 |
|
9393 nsCOMPtr<nsIInputStream> postData; |
|
9394 nsCOMPtr<nsISupports> cacheKey; |
|
9395 |
|
9396 if (mOSHE) { |
|
9397 /* save current position of scroller(s) (bug 59774) */ |
|
9398 mOSHE->SetScrollPosition(cx, cy); |
|
9399 // Get the postdata and page ident from the current page, if |
|
9400 // the new load is being done via normal means. Note that |
|
9401 // "normal means" can be checked for just by checking for |
|
9402 // LOAD_CMD_NORMAL, given the loadType and allowScroll check |
|
9403 // above -- it filters out some LOAD_CMD_NORMAL cases that we |
|
9404 // wouldn't want here. |
|
9405 if (aLoadType & LOAD_CMD_NORMAL) { |
|
9406 mOSHE->GetPostData(getter_AddRefs(postData)); |
|
9407 mOSHE->GetCacheKey(getter_AddRefs(cacheKey)); |
|
9408 |
|
9409 // Link our new SHEntry to the old SHEntry's back/forward |
|
9410 // cache data, since the two SHEntries correspond to the |
|
9411 // same document. |
|
9412 if (mLSHE) |
|
9413 mLSHE->AdoptBFCacheEntry(mOSHE); |
|
9414 } |
|
9415 } |
|
9416 |
|
9417 /* Assign mOSHE to mLSHE. This will either be a new entry created |
|
9418 * by OnNewURI() for normal loads or aSHEntry for history loads. |
|
9419 */ |
|
9420 if (mLSHE) { |
|
9421 SetHistoryEntry(&mOSHE, mLSHE); |
|
9422 // Save the postData obtained from the previous page |
|
9423 // in to the session history entry created for the |
|
9424 // anchor page, so that any history load of the anchor |
|
9425 // page will restore the appropriate postData. |
|
9426 if (postData) |
|
9427 mOSHE->SetPostData(postData); |
|
9428 |
|
9429 // Make sure we won't just repost without hitting the |
|
9430 // cache first |
|
9431 if (cacheKey) |
|
9432 mOSHE->SetCacheKey(cacheKey); |
|
9433 } |
|
9434 |
|
9435 /* restore previous position of scroller(s), if we're moving |
|
9436 * back in history (bug 59774) |
|
9437 */ |
|
9438 if (mOSHE && (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)) |
|
9439 { |
|
9440 nscoord bx, by; |
|
9441 mOSHE->GetScrollPosition(&bx, &by); |
|
9442 SetCurScrollPosEx(bx, by); |
|
9443 } |
|
9444 |
|
9445 /* Restore the original LSHE if we were loading something |
|
9446 * while short-circuited load was initiated. |
|
9447 */ |
|
9448 SetHistoryEntry(&mLSHE, oldLSHE); |
|
9449 /* Set the title for the SH entry for this target url. so that |
|
9450 * SH menus in go/back/forward buttons won't be empty for this. |
|
9451 */ |
|
9452 if (mSessionHistory) { |
|
9453 int32_t index = -1; |
|
9454 mSessionHistory->GetIndex(&index); |
|
9455 nsCOMPtr<nsISHEntry> shEntry; |
|
9456 mSessionHistory->GetEntryAtIndex(index, false, |
|
9457 getter_AddRefs(shEntry)); |
|
9458 NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE); |
|
9459 shEntry->SetTitle(mTitle); |
|
9460 } |
|
9461 |
|
9462 /* Set the title for the Global History entry for this anchor url. |
|
9463 */ |
|
9464 if (mUseGlobalHistory && !mInPrivateBrowsing) { |
|
9465 nsCOMPtr<IHistory> history = services::GetHistoryService(); |
|
9466 if (history) { |
|
9467 history->SetURITitle(aURI, mTitle); |
|
9468 } |
|
9469 else if (mGlobalHistory) { |
|
9470 mGlobalHistory->SetPageTitle(aURI, mTitle); |
|
9471 } |
|
9472 } |
|
9473 |
|
9474 // Set the doc's URI according to the new history entry's URI. |
|
9475 nsCOMPtr<nsIDocument> doc = |
|
9476 do_GetInterface(GetAsSupports(this)); |
|
9477 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
|
9478 doc->SetDocumentURI(aURI); |
|
9479 |
|
9480 SetDocCurrentStateObj(mOSHE); |
|
9481 |
|
9482 // Dispatch the popstate and hashchange events, as appropriate. |
|
9483 // |
|
9484 // The event dispatch below can cause us to re-enter script and |
|
9485 // destroy the docshell, nulling out mScriptGlobal. Hold a stack |
|
9486 // reference to avoid null derefs. See bug 914521. |
|
9487 nsRefPtr<nsGlobalWindow> win = mScriptGlobal; |
|
9488 if (win) { |
|
9489 // Fire a hashchange event URIs differ, and only in their hashes. |
|
9490 bool doHashchange = sameExceptHashes && !curHash.Equals(newHash); |
|
9491 |
|
9492 if (historyNavBetweenSameDoc || doHashchange) { |
|
9493 win->DispatchSyncPopState(); |
|
9494 } |
|
9495 |
|
9496 if (doHashchange) { |
|
9497 // Note that currentURI hasn't changed because it's on the |
|
9498 // stack, so we can just use it directly as the old URI. |
|
9499 win->DispatchAsyncHashchange(currentURI, aURI); |
|
9500 } |
|
9501 } |
|
9502 |
|
9503 // Inform the favicon service that the favicon for oldURI also |
|
9504 // applies to aURI. |
|
9505 CopyFavicon(currentURI, aURI, mInPrivateBrowsing); |
|
9506 |
|
9507 return NS_OK; |
|
9508 } |
|
9509 } |
|
9510 |
|
9511 // mContentViewer->PermitUnload can destroy |this| docShell, which |
|
9512 // causes the next call of CanSavePresentation to crash. |
|
9513 // Hold onto |this| until we return, to prevent a crash from happening. |
|
9514 // (bug#331040) |
|
9515 nsCOMPtr<nsIDocShell> kungFuDeathGrip(this); |
|
9516 |
|
9517 // Don't init timing for javascript:, since it generally doesn't |
|
9518 // actually start a load or anything. If it does, we'll init |
|
9519 // timing then, from OnStateChange. |
|
9520 |
|
9521 // XXXbz mTiming should know what channel it's for, so we don't |
|
9522 // need this hackery. Note that this is still broken in cases |
|
9523 // when we're loading something that's not javascript: and the |
|
9524 // beforeunload handler denies the load. That will screw up |
|
9525 // timing for the next load! |
|
9526 if (!bIsJavascript) { |
|
9527 MaybeInitTiming(); |
|
9528 } |
|
9529 bool timeBeforeUnload = aFileName.IsVoid(); |
|
9530 if (mTiming && timeBeforeUnload) { |
|
9531 mTiming->NotifyBeforeUnload(); |
|
9532 } |
|
9533 // Check if the page doesn't want to be unloaded. The javascript: |
|
9534 // protocol handler deals with this for javascript: URLs. |
|
9535 if (!bIsJavascript && aFileName.IsVoid() && mContentViewer) { |
|
9536 bool okToUnload; |
|
9537 rv = mContentViewer->PermitUnload(false, &okToUnload); |
|
9538 |
|
9539 if (NS_SUCCEEDED(rv) && !okToUnload) { |
|
9540 // The user chose not to unload the page, interrupt the |
|
9541 // load. |
|
9542 return NS_OK; |
|
9543 } |
|
9544 } |
|
9545 |
|
9546 if (mTiming && timeBeforeUnload) { |
|
9547 mTiming->NotifyUnloadAccepted(mCurrentURI); |
|
9548 } |
|
9549 |
|
9550 // Check for saving the presentation here, before calling Stop(). |
|
9551 // This is necessary so that we can catch any pending requests. |
|
9552 // Since the new request has not been created yet, we pass null for the |
|
9553 // new request parameter. |
|
9554 // Also pass nullptr for the document, since it doesn't affect the return |
|
9555 // value for our purposes here. |
|
9556 bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr); |
|
9557 |
|
9558 // Don't stop current network activity for javascript: URL's since |
|
9559 // they might not result in any data, and thus nothing should be |
|
9560 // stopped in those cases. In the case where they do result in |
|
9561 // data, the javascript: URL channel takes care of stopping |
|
9562 // current network activity. |
|
9563 if (!bIsJavascript && aFileName.IsVoid()) { |
|
9564 // Stop any current network activity. |
|
9565 // Also stop content if this is a zombie doc. otherwise |
|
9566 // the onload will be delayed by other loads initiated in the |
|
9567 // background by the first document that |
|
9568 // didn't fully load before the next load was initiated. |
|
9569 // If not a zombie, don't stop content until data |
|
9570 // starts arriving from the new URI... |
|
9571 |
|
9572 nsCOMPtr<nsIContentViewer> zombieViewer; |
|
9573 if (mContentViewer) { |
|
9574 mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer)); |
|
9575 } |
|
9576 |
|
9577 if (zombieViewer || |
|
9578 LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) { |
|
9579 rv = Stop(nsIWebNavigation::STOP_ALL); |
|
9580 } else { |
|
9581 rv = Stop(nsIWebNavigation::STOP_NETWORK); |
|
9582 } |
|
9583 |
|
9584 if (NS_FAILED(rv)) |
|
9585 return rv; |
|
9586 } |
|
9587 |
|
9588 mLoadType = aLoadType; |
|
9589 |
|
9590 // mLSHE should be assigned to aSHEntry, only after Stop() has |
|
9591 // been called. But when loading an error page, do not clear the |
|
9592 // mLSHE for the real page. |
|
9593 if (mLoadType != LOAD_ERROR_PAGE) |
|
9594 SetHistoryEntry(&mLSHE, aSHEntry); |
|
9595 |
|
9596 mSavingOldViewer = savePresentation; |
|
9597 |
|
9598 // If we have a saved content viewer in history, restore and show it now. |
|
9599 if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) { |
|
9600 // Make sure our history ID points to the same ID as |
|
9601 // SHEntry's docshell ID. |
|
9602 aSHEntry->GetDocshellID(&mHistoryID); |
|
9603 |
|
9604 // It's possible that the previous viewer of mContentViewer is the |
|
9605 // viewer that will end up in aSHEntry when it gets closed. If that's |
|
9606 // the case, we need to go ahead and force it into its shentry so we |
|
9607 // can restore it. |
|
9608 if (mContentViewer) { |
|
9609 nsCOMPtr<nsIContentViewer> prevViewer; |
|
9610 mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer)); |
|
9611 if (prevViewer) { |
|
9612 #ifdef DEBUG |
|
9613 nsCOMPtr<nsIContentViewer> prevPrevViewer; |
|
9614 prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer)); |
|
9615 NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here"); |
|
9616 #endif |
|
9617 nsCOMPtr<nsISHEntry> viewerEntry; |
|
9618 prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry)); |
|
9619 if (viewerEntry == aSHEntry) { |
|
9620 // Make sure this viewer ends up in the right place |
|
9621 mContentViewer->SetPreviousViewer(nullptr); |
|
9622 prevViewer->Destroy(); |
|
9623 } |
|
9624 } |
|
9625 } |
|
9626 nsCOMPtr<nsISHEntry> oldEntry = mOSHE; |
|
9627 bool restoring; |
|
9628 rv = RestorePresentation(aSHEntry, &restoring); |
|
9629 if (restoring) |
|
9630 return rv; |
|
9631 |
|
9632 // We failed to restore the presentation, so clean up. |
|
9633 // Both the old and new history entries could potentially be in |
|
9634 // an inconsistent state. |
|
9635 if (NS_FAILED(rv)) { |
|
9636 if (oldEntry) |
|
9637 oldEntry->SyncPresentationState(); |
|
9638 |
|
9639 aSHEntry->SyncPresentationState(); |
|
9640 } |
|
9641 } |
|
9642 |
|
9643 nsAutoString srcdoc; |
|
9644 if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) |
|
9645 srcdoc = aSrcdoc; |
|
9646 else |
|
9647 srcdoc = NullString(); |
|
9648 |
|
9649 mozilla::net::SeerPredict(aURI, nullptr, nsINetworkSeer::PREDICT_LOAD, |
|
9650 this, nullptr); |
|
9651 |
|
9652 nsCOMPtr<nsIRequest> req; |
|
9653 rv = DoURILoad(aURI, aReferrer, |
|
9654 !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), |
|
9655 owner, aTypeHint, aFileName, aPostData, aHeadersData, |
|
9656 aFirstParty, aDocShell, getter_AddRefs(req), |
|
9657 (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0, |
|
9658 (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0, |
|
9659 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0, |
|
9660 srcdoc, aBaseURI); |
|
9661 if (req && aRequest) |
|
9662 NS_ADDREF(*aRequest = req); |
|
9663 |
|
9664 if (NS_FAILED(rv)) { |
|
9665 nsCOMPtr<nsIChannel> chan(do_QueryInterface(req)); |
|
9666 DisplayLoadError(rv, aURI, nullptr, chan); |
|
9667 } |
|
9668 |
|
9669 return rv; |
|
9670 } |
|
9671 |
|
9672 nsIPrincipal* |
|
9673 nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument) |
|
9674 { |
|
9675 nsCOMPtr<nsIDocument> document; |
|
9676 bool inheritedFromCurrent = false; |
|
9677 |
|
9678 if (aConsiderCurrentDocument && mContentViewer) { |
|
9679 document = mContentViewer->GetDocument(); |
|
9680 inheritedFromCurrent = true; |
|
9681 } |
|
9682 |
|
9683 if (!document) { |
|
9684 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
9685 GetSameTypeParent(getter_AddRefs(parentItem)); |
|
9686 if (parentItem) { |
|
9687 document = do_GetInterface(parentItem); |
|
9688 } |
|
9689 } |
|
9690 |
|
9691 if (!document) { |
|
9692 if (!aConsiderCurrentDocument) { |
|
9693 return nullptr; |
|
9694 } |
|
9695 |
|
9696 // Make sure we end up with _something_ as the principal no matter |
|
9697 // what. |
|
9698 EnsureContentViewer(); // If this fails, we'll just get a null |
|
9699 // docViewer and bail. |
|
9700 |
|
9701 if (!mContentViewer) |
|
9702 return nullptr; |
|
9703 document = mContentViewer->GetDocument(); |
|
9704 } |
|
9705 |
|
9706 //-- Get the document's principal |
|
9707 if (document) { |
|
9708 nsIPrincipal *docPrincipal = document->NodePrincipal(); |
|
9709 |
|
9710 // Don't allow loads in typeContent docShells to inherit the system |
|
9711 // principal from existing documents. |
|
9712 if (inheritedFromCurrent && |
|
9713 mItemType == typeContent && |
|
9714 nsContentUtils::IsSystemPrincipal(docPrincipal)) { |
|
9715 return nullptr; |
|
9716 } |
|
9717 |
|
9718 return docPrincipal; |
|
9719 } |
|
9720 |
|
9721 return nullptr; |
|
9722 } |
|
9723 |
|
9724 nsresult |
|
9725 nsDocShell::DoURILoad(nsIURI * aURI, |
|
9726 nsIURI * aReferrerURI, |
|
9727 bool aSendReferrer, |
|
9728 nsISupports * aOwner, |
|
9729 const char * aTypeHint, |
|
9730 const nsAString & aFileName, |
|
9731 nsIInputStream * aPostData, |
|
9732 nsIInputStream * aHeadersData, |
|
9733 bool aFirstParty, |
|
9734 nsIDocShell ** aDocShell, |
|
9735 nsIRequest ** aRequest, |
|
9736 bool aIsNewWindowTarget, |
|
9737 bool aBypassClassifier, |
|
9738 bool aForceAllowCookies, |
|
9739 const nsAString &aSrcdoc, |
|
9740 nsIURI * aBaseURI) |
|
9741 { |
|
9742 #ifdef MOZ_VISUAL_EVENT_TRACER |
|
9743 nsAutoCString urlSpec; |
|
9744 aURI->GetAsciiSpec(urlSpec); |
|
9745 MOZ_EVENT_TRACER_NAME_OBJECT(this, urlSpec.BeginReading()); |
|
9746 MOZ_EVENT_TRACER_EXEC(this, "docshell::pageload"); |
|
9747 #endif |
|
9748 |
|
9749 nsresult rv; |
|
9750 nsCOMPtr<nsIURILoader> uriLoader; |
|
9751 |
|
9752 uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv); |
|
9753 if (NS_FAILED(rv)) return rv; |
|
9754 |
|
9755 nsLoadFlags loadFlags = mDefaultLoadFlags; |
|
9756 if (aFirstParty) { |
|
9757 // tag first party URL loads |
|
9758 loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI; |
|
9759 } |
|
9760 |
|
9761 if (mLoadType == LOAD_ERROR_PAGE) { |
|
9762 // Error pages are LOAD_BACKGROUND |
|
9763 loadFlags |= nsIChannel::LOAD_BACKGROUND; |
|
9764 } |
|
9765 |
|
9766 // check for Content Security Policy to pass along with the |
|
9767 // new channel we are creating |
|
9768 nsCOMPtr<nsIChannelPolicy> channelPolicy; |
|
9769 if (IsFrame()) { |
|
9770 // check the parent docshell for a CSP |
|
9771 nsCOMPtr<nsIContentSecurityPolicy> csp; |
|
9772 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
9773 GetSameTypeParent(getter_AddRefs(parentItem)); |
|
9774 nsCOMPtr<nsIDocument> doc = do_GetInterface(parentItem); |
|
9775 if (doc) { |
|
9776 rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp)); |
|
9777 NS_ENSURE_SUCCESS(rv, rv); |
|
9778 if (csp) { |
|
9779 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); |
|
9780 channelPolicy->SetContentSecurityPolicy(csp); |
|
9781 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT); |
|
9782 } |
|
9783 } |
|
9784 |
|
9785 // Only allow view-source scheme in top-level docshells. view-source is |
|
9786 // the only scheme to which this applies at the moment due to potential |
|
9787 // timing attacks to read data from cross-origin iframes. If this widens |
|
9788 // we should add a protocol flag for whether the scheme is allowed in |
|
9789 // frames and use something like nsNetUtil::NS_URIChainHasFlags. |
|
9790 nsCOMPtr<nsIURI> tempURI = aURI; |
|
9791 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI); |
|
9792 while (nestedURI) { |
|
9793 // view-source should always be an nsINestedURI, loop and check the |
|
9794 // scheme on this and all inner URIs that are also nested URIs. |
|
9795 bool isViewSource = false; |
|
9796 rv = tempURI->SchemeIs("view-source", &isViewSource); |
|
9797 if (NS_FAILED(rv) || isViewSource) { |
|
9798 return NS_ERROR_UNKNOWN_PROTOCOL; |
|
9799 } |
|
9800 nestedURI->GetInnerURI(getter_AddRefs(tempURI)); |
|
9801 nestedURI = do_QueryInterface(tempURI); |
|
9802 } |
|
9803 } |
|
9804 |
|
9805 // open a channel for the url |
|
9806 nsCOMPtr<nsIChannel> channel; |
|
9807 |
|
9808 bool isSrcdoc = !aSrcdoc.IsVoid(); |
|
9809 if (!isSrcdoc) { |
|
9810 rv = NS_NewChannel(getter_AddRefs(channel), |
|
9811 aURI, |
|
9812 nullptr, |
|
9813 nullptr, |
|
9814 static_cast<nsIInterfaceRequestor *>(this), |
|
9815 loadFlags, |
|
9816 channelPolicy); |
|
9817 if (NS_FAILED(rv)) { |
|
9818 if (rv == NS_ERROR_UNKNOWN_PROTOCOL) { |
|
9819 // This is a uri with a protocol scheme we don't know how |
|
9820 // to handle. Embedders might still be interested in |
|
9821 // handling the load, though, so we fire a notification |
|
9822 // before throwing the load away. |
|
9823 bool abort = false; |
|
9824 nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort); |
|
9825 if (NS_SUCCEEDED(rv2) && abort) { |
|
9826 // Hey, they're handling the load for us! How convenient! |
|
9827 return NS_OK; |
|
9828 } |
|
9829 } |
|
9830 return rv; |
|
9831 } |
|
9832 if (aBaseURI) { |
|
9833 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel); |
|
9834 if (vsc) { |
|
9835 vsc->SetBaseURI(aBaseURI); |
|
9836 } |
|
9837 } |
|
9838 } |
|
9839 else { |
|
9840 nsAutoCString scheme; |
|
9841 rv = aURI->GetScheme(scheme); |
|
9842 NS_ENSURE_SUCCESS(rv,rv); |
|
9843 bool isViewSource; |
|
9844 aURI->SchemeIs("view-source",&isViewSource); |
|
9845 |
|
9846 if (isViewSource) { |
|
9847 nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance(); |
|
9848 NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE); |
|
9849 |
|
9850 rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, aBaseURI, |
|
9851 getter_AddRefs(channel)); |
|
9852 NS_ENSURE_SUCCESS(rv, rv); |
|
9853 } |
|
9854 else { |
|
9855 rv = NS_NewInputStreamChannel(getter_AddRefs(channel),aURI, |
|
9856 aSrcdoc, |
|
9857 NS_LITERAL_CSTRING("text/html"), |
|
9858 true); |
|
9859 NS_ENSURE_SUCCESS(rv, rv); |
|
9860 nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel); |
|
9861 MOZ_ASSERT(isc); |
|
9862 isc->SetBaseURI(aBaseURI); |
|
9863 } |
|
9864 } |
|
9865 |
|
9866 nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = |
|
9867 do_QueryInterface(channel); |
|
9868 if (appCacheChannel) { |
|
9869 // Any document load should not inherit application cache. |
|
9870 appCacheChannel->SetInheritApplicationCache(false); |
|
9871 |
|
9872 // Loads with the correct permissions should check for a matching |
|
9873 // application cache. |
|
9874 if (GeckoProcessType_Default != XRE_GetProcessType()) { |
|
9875 // Permission will be checked in the parent process |
|
9876 appCacheChannel->SetChooseApplicationCache(true); |
|
9877 } else { |
|
9878 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
9879 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
9880 |
|
9881 if (secMan) { |
|
9882 nsCOMPtr<nsIPrincipal> principal; |
|
9883 secMan->GetDocShellCodebasePrincipal(aURI, this, getter_AddRefs(principal)); |
|
9884 appCacheChannel->SetChooseApplicationCache( |
|
9885 NS_ShouldCheckAppCache(principal, mInPrivateBrowsing)); |
|
9886 } |
|
9887 } |
|
9888 } |
|
9889 |
|
9890 // Make sure to give the caller a channel if we managed to create one |
|
9891 // This is important for correct error page/session history interaction |
|
9892 if (aRequest) |
|
9893 NS_ADDREF(*aRequest = channel); |
|
9894 |
|
9895 channel->SetOriginalURI(aURI); |
|
9896 if (aTypeHint && *aTypeHint) { |
|
9897 channel->SetContentType(nsDependentCString(aTypeHint)); |
|
9898 mContentTypeHint = aTypeHint; |
|
9899 } else { |
|
9900 mContentTypeHint.Truncate(); |
|
9901 } |
|
9902 |
|
9903 if (!aFileName.IsVoid()) { |
|
9904 rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT); |
|
9905 NS_ENSURE_SUCCESS(rv, rv); |
|
9906 if (!aFileName.IsEmpty()) { |
|
9907 rv = channel->SetContentDispositionFilename(aFileName); |
|
9908 NS_ENSURE_SUCCESS(rv, rv); |
|
9909 } |
|
9910 } |
|
9911 |
|
9912 if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT || |
|
9913 mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) { |
|
9914 rv = SetMixedContentChannel(channel); |
|
9915 NS_ENSURE_SUCCESS(rv, rv); |
|
9916 } else if (mMixedContentChannel) { |
|
9917 /* |
|
9918 * If the user "Disables Protection on This Page", we call |
|
9919 * SetMixedContentChannel for the first time, otherwise |
|
9920 * mMixedContentChannel is still null. |
|
9921 * Later, if the new channel passes a same orign check, we remember the |
|
9922 * users decision by calling SetMixedContentChannel using the new channel. |
|
9923 * This way, the user does not have to click the disable protection button |
|
9924 * over and over for browsing the same site. |
|
9925 */ |
|
9926 rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel); |
|
9927 if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) { |
|
9928 SetMixedContentChannel(nullptr); |
|
9929 } |
|
9930 } |
|
9931 |
|
9932 //hack |
|
9933 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); |
|
9934 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel)); |
|
9935 if (httpChannelInternal) { |
|
9936 if (aForceAllowCookies) { |
|
9937 httpChannelInternal->SetForceAllowThirdPartyCookie(true); |
|
9938 } |
|
9939 if (aFirstParty) { |
|
9940 httpChannelInternal->SetDocumentURI(aURI); |
|
9941 } else { |
|
9942 httpChannelInternal->SetDocumentURI(aReferrerURI); |
|
9943 } |
|
9944 } |
|
9945 |
|
9946 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel)); |
|
9947 if (props) |
|
9948 { |
|
9949 // save true referrer for those who need it (e.g. xpinstall whitelisting) |
|
9950 // Currently only http and ftp channels support this. |
|
9951 props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), |
|
9952 aReferrerURI); |
|
9953 } |
|
9954 |
|
9955 // |
|
9956 // If this is a HTTP channel, then set up the HTTP specific information |
|
9957 // (ie. POST data, referrer, ...) |
|
9958 // |
|
9959 if (httpChannel) { |
|
9960 nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(httpChannel)); |
|
9961 /* Get the cache Key from SH */ |
|
9962 nsCOMPtr<nsISupports> cacheKey; |
|
9963 if (mLSHE) { |
|
9964 mLSHE->GetCacheKey(getter_AddRefs(cacheKey)); |
|
9965 } |
|
9966 else if (mOSHE) // for reload cases |
|
9967 mOSHE->GetCacheKey(getter_AddRefs(cacheKey)); |
|
9968 |
|
9969 // figure out if we need to set the post data stream on the channel... |
|
9970 // right now, this is only done for http channels..... |
|
9971 if (aPostData) { |
|
9972 // XXX it's a bit of a hack to rewind the postdata stream here but |
|
9973 // it has to be done in case the post data is being reused multiple |
|
9974 // times. |
|
9975 nsCOMPtr<nsISeekableStream> |
|
9976 postDataSeekable(do_QueryInterface(aPostData)); |
|
9977 if (postDataSeekable) { |
|
9978 rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); |
|
9979 NS_ENSURE_SUCCESS(rv, rv); |
|
9980 } |
|
9981 |
|
9982 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel)); |
|
9983 NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel"); |
|
9984 |
|
9985 // we really need to have a content type associated with this stream!! |
|
9986 uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1); |
|
9987 /* If there is a valid postdata *and* it is a History Load, |
|
9988 * set up the cache key on the channel, to retrieve the |
|
9989 * data *only* from the cache. If it is a normal reload, the |
|
9990 * cache is free to go to the server for updated postdata. |
|
9991 */ |
|
9992 if (cacheChannel && cacheKey) { |
|
9993 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) { |
|
9994 cacheChannel->SetCacheKey(cacheKey); |
|
9995 uint32_t loadFlags; |
|
9996 if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) |
|
9997 channel->SetLoadFlags(loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE); |
|
9998 } |
|
9999 else if (mLoadType == LOAD_RELOAD_NORMAL) |
|
10000 cacheChannel->SetCacheKey(cacheKey); |
|
10001 } |
|
10002 } |
|
10003 else { |
|
10004 /* If there is no postdata, set the cache key on the channel, and |
|
10005 * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel |
|
10006 * will be free to get it from net if it is not found in cache. |
|
10007 * New cache may use it creatively on CGI pages with GET |
|
10008 * method and even on those that say "no-cache" |
|
10009 */ |
|
10010 if (mLoadType == LOAD_HISTORY || mLoadType == LOAD_RELOAD_NORMAL |
|
10011 || mLoadType == LOAD_RELOAD_CHARSET_CHANGE) { |
|
10012 if (cacheChannel && cacheKey) |
|
10013 cacheChannel->SetCacheKey(cacheKey); |
|
10014 } |
|
10015 } |
|
10016 if (aHeadersData) { |
|
10017 rv = AddHeadersToChannel(aHeadersData, httpChannel); |
|
10018 } |
|
10019 // Set the referrer explicitly |
|
10020 if (aReferrerURI && aSendReferrer) { |
|
10021 // Referrer is currenly only set for link clicks here. |
|
10022 httpChannel->SetReferrer(aReferrerURI); |
|
10023 } |
|
10024 } |
|
10025 |
|
10026 nsCOMPtr<nsIPrincipal> ownerPrincipal; |
|
10027 |
|
10028 // If the content being loaded should be sandboxed with respect to origin |
|
10029 // we need to create a new null principal here, and then tell |
|
10030 // nsContentUtils::SetUpChannelOwner to force it to be set as the |
|
10031 // channel owner. |
|
10032 if (mSandboxFlags & SANDBOXED_ORIGIN) { |
|
10033 ownerPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1"); |
|
10034 } else { |
|
10035 // Not sandboxed - we allow the content to assume its natural owner. |
|
10036 ownerPrincipal = do_QueryInterface(aOwner); |
|
10037 } |
|
10038 |
|
10039 nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, true, |
|
10040 (mSandboxFlags & SANDBOXED_ORIGIN) || |
|
10041 isSrcdoc); |
|
10042 |
|
10043 nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel); |
|
10044 if (scriptChannel) { |
|
10045 // Allow execution against our context if the principals match |
|
10046 scriptChannel-> |
|
10047 SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL); |
|
10048 } |
|
10049 |
|
10050 if (aIsNewWindowTarget) { |
|
10051 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel); |
|
10052 if (props) { |
|
10053 props->SetPropertyAsBool( |
|
10054 NS_LITERAL_STRING("docshell.newWindowTarget"), |
|
10055 true); |
|
10056 } |
|
10057 } |
|
10058 |
|
10059 nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel)); |
|
10060 if (timedChannel) { |
|
10061 timedChannel->SetTimingEnabled(true); |
|
10062 if (IsFrame()) { |
|
10063 timedChannel->SetInitiatorType(NS_LITERAL_STRING("subdocument")); |
|
10064 } |
|
10065 } |
|
10066 |
|
10067 rv = DoChannelLoad(channel, uriLoader, aBypassClassifier); |
|
10068 |
|
10069 // |
|
10070 // If the channel load failed, we failed and nsIWebProgress just ain't |
|
10071 // gonna happen. |
|
10072 // |
|
10073 if (NS_SUCCEEDED(rv)) { |
|
10074 if (aDocShell) { |
|
10075 *aDocShell = this; |
|
10076 NS_ADDREF(*aDocShell); |
|
10077 } |
|
10078 } |
|
10079 |
|
10080 return rv; |
|
10081 } |
|
10082 |
|
10083 static NS_METHOD |
|
10084 AppendSegmentToString(nsIInputStream *in, |
|
10085 void *closure, |
|
10086 const char *fromRawSegment, |
|
10087 uint32_t toOffset, |
|
10088 uint32_t count, |
|
10089 uint32_t *writeCount) |
|
10090 { |
|
10091 // aFromSegment now contains aCount bytes of data. |
|
10092 |
|
10093 nsAutoCString *buf = static_cast<nsAutoCString *>(closure); |
|
10094 buf->Append(fromRawSegment, count); |
|
10095 |
|
10096 // Indicate that we have consumed all of aFromSegment |
|
10097 *writeCount = count; |
|
10098 return NS_OK; |
|
10099 } |
|
10100 |
|
10101 NS_IMETHODIMP |
|
10102 nsDocShell::AddHeadersToChannel(nsIInputStream *aHeadersData, |
|
10103 nsIChannel *aGenericChannel) |
|
10104 { |
|
10105 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel); |
|
10106 NS_ENSURE_STATE(httpChannel); |
|
10107 |
|
10108 uint32_t numRead; |
|
10109 nsAutoCString headersString; |
|
10110 nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString, |
|
10111 &headersString, |
|
10112 UINT32_MAX, |
|
10113 &numRead); |
|
10114 NS_ENSURE_SUCCESS(rv, rv); |
|
10115 |
|
10116 // used during the manipulation of the String from the InputStream |
|
10117 nsAutoCString headerName; |
|
10118 nsAutoCString headerValue; |
|
10119 int32_t crlf; |
|
10120 int32_t colon; |
|
10121 |
|
10122 // |
|
10123 // Iterate over the headersString: for each "\r\n" delimited chunk, |
|
10124 // add the value as a header to the nsIHttpChannel |
|
10125 // |
|
10126 |
|
10127 static const char kWhitespace[] = "\b\t\r\n "; |
|
10128 while (true) { |
|
10129 crlf = headersString.Find("\r\n"); |
|
10130 if (crlf == kNotFound) |
|
10131 return NS_OK; |
|
10132 |
|
10133 const nsCSubstring &oneHeader = StringHead(headersString, crlf); |
|
10134 |
|
10135 colon = oneHeader.FindChar(':'); |
|
10136 if (colon == kNotFound) |
|
10137 return NS_ERROR_UNEXPECTED; |
|
10138 |
|
10139 headerName = StringHead(oneHeader, colon); |
|
10140 headerValue = Substring(oneHeader, colon + 1); |
|
10141 |
|
10142 headerName.Trim(kWhitespace); |
|
10143 headerValue.Trim(kWhitespace); |
|
10144 |
|
10145 headersString.Cut(0, crlf + 2); |
|
10146 |
|
10147 // |
|
10148 // FINALLY: we can set the header! |
|
10149 // |
|
10150 |
|
10151 rv = httpChannel->SetRequestHeader(headerName, headerValue, true); |
|
10152 NS_ENSURE_SUCCESS(rv, rv); |
|
10153 } |
|
10154 |
|
10155 NS_NOTREACHED("oops"); |
|
10156 return NS_ERROR_UNEXPECTED; |
|
10157 } |
|
10158 |
|
10159 nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel, |
|
10160 nsIURILoader * aURILoader, |
|
10161 bool aBypassClassifier) |
|
10162 { |
|
10163 nsresult rv; |
|
10164 // Mark the channel as being a document URI and allow content sniffing... |
|
10165 nsLoadFlags loadFlags = 0; |
|
10166 (void) aChannel->GetLoadFlags(&loadFlags); |
|
10167 loadFlags |= nsIChannel::LOAD_DOCUMENT_URI | |
|
10168 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS; |
|
10169 |
|
10170 // Load attributes depend on load type... |
|
10171 switch (mLoadType) { |
|
10172 case LOAD_HISTORY: |
|
10173 { |
|
10174 // Only send VALIDATE_NEVER if mLSHE's URI was never changed via |
|
10175 // push/replaceState (bug 669671). |
|
10176 bool uriModified = false; |
|
10177 if (mLSHE) { |
|
10178 mLSHE->GetURIWasModified(&uriModified); |
|
10179 } |
|
10180 |
|
10181 if (!uriModified) |
|
10182 loadFlags |= nsIRequest::VALIDATE_NEVER; |
|
10183 } |
|
10184 break; |
|
10185 |
|
10186 case LOAD_RELOAD_CHARSET_CHANGE: |
|
10187 loadFlags |= nsIRequest::LOAD_FROM_CACHE; |
|
10188 break; |
|
10189 |
|
10190 case LOAD_RELOAD_NORMAL: |
|
10191 case LOAD_REFRESH: |
|
10192 loadFlags |= nsIRequest::VALIDATE_ALWAYS; |
|
10193 break; |
|
10194 |
|
10195 case LOAD_NORMAL_BYPASS_CACHE: |
|
10196 case LOAD_NORMAL_BYPASS_PROXY: |
|
10197 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE: |
|
10198 case LOAD_NORMAL_ALLOW_MIXED_CONTENT: |
|
10199 case LOAD_RELOAD_BYPASS_CACHE: |
|
10200 case LOAD_RELOAD_BYPASS_PROXY: |
|
10201 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: |
|
10202 case LOAD_RELOAD_ALLOW_MIXED_CONTENT: |
|
10203 case LOAD_REPLACE_BYPASS_CACHE: |
|
10204 loadFlags |= nsIRequest::LOAD_BYPASS_CACHE | |
|
10205 nsIRequest::LOAD_FRESH_CONNECTION; |
|
10206 break; |
|
10207 |
|
10208 case LOAD_NORMAL: |
|
10209 case LOAD_LINK: |
|
10210 // Set cache checking flags |
|
10211 switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) { |
|
10212 case 0: |
|
10213 loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION; |
|
10214 break; |
|
10215 case 1: |
|
10216 loadFlags |= nsIRequest::VALIDATE_ALWAYS; |
|
10217 break; |
|
10218 case 2: |
|
10219 loadFlags |= nsIRequest::VALIDATE_NEVER; |
|
10220 break; |
|
10221 } |
|
10222 break; |
|
10223 } |
|
10224 |
|
10225 if (!aBypassClassifier) { |
|
10226 loadFlags |= nsIChannel::LOAD_CLASSIFY_URI; |
|
10227 } |
|
10228 |
|
10229 (void) aChannel->SetLoadFlags(loadFlags); |
|
10230 |
|
10231 uint32_t openFlags = 0; |
|
10232 if (mLoadType == LOAD_LINK) { |
|
10233 openFlags |= nsIURILoader::IS_CONTENT_PREFERRED; |
|
10234 } |
|
10235 if (!mAllowContentRetargeting) { |
|
10236 openFlags |= nsIURILoader::DONT_RETARGET; |
|
10237 } |
|
10238 rv = aURILoader->OpenURI(aChannel, openFlags, this); |
|
10239 NS_ENSURE_SUCCESS(rv, rv); |
|
10240 |
|
10241 return NS_OK; |
|
10242 } |
|
10243 |
|
10244 nsresult |
|
10245 nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash, |
|
10246 uint32_t aLoadType) |
|
10247 { |
|
10248 if (!mCurrentURI) { |
|
10249 return NS_OK; |
|
10250 } |
|
10251 |
|
10252 nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
|
10253 if (!shell) { |
|
10254 // If we failed to get the shell, or if there is no shell, |
|
10255 // nothing left to do here. |
|
10256 return NS_OK; |
|
10257 } |
|
10258 |
|
10259 nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable(); |
|
10260 if (rootScroll) { |
|
10261 rootScroll->ClearDidHistoryRestore(); |
|
10262 } |
|
10263 |
|
10264 // If we have no new anchor, we do not want to scroll, unless there is a |
|
10265 // current anchor and we are doing a history load. So return if we have no |
|
10266 // new anchor, and there is no current anchor or the load is not a history |
|
10267 // load. |
|
10268 if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) && |
|
10269 aNewHash.IsEmpty()) { |
|
10270 return NS_OK; |
|
10271 } |
|
10272 |
|
10273 // Take the '#' off aNewHash to get the ref name. (aNewHash might be empty, |
|
10274 // but that's fine.) |
|
10275 nsDependentCSubstring newHashName(aNewHash, 1); |
|
10276 |
|
10277 // Both the new and current URIs refer to the same page. We can now |
|
10278 // browse to the hash stored in the new URI. |
|
10279 |
|
10280 if (!newHashName.IsEmpty()) { |
|
10281 // anchor is there, but if it's a load from history, |
|
10282 // we don't have any anchor jumping to do |
|
10283 bool scroll = aLoadType != LOAD_HISTORY && |
|
10284 aLoadType != LOAD_RELOAD_NORMAL; |
|
10285 |
|
10286 char *str = ToNewCString(newHashName); |
|
10287 if (!str) { |
|
10288 return NS_ERROR_OUT_OF_MEMORY; |
|
10289 } |
|
10290 |
|
10291 // nsUnescape modifies the string that is passed into it. |
|
10292 nsUnescape(str); |
|
10293 |
|
10294 // We assume that the bytes are in UTF-8, as it says in the |
|
10295 // spec: |
|
10296 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1 |
|
10297 |
|
10298 // We try the UTF-8 string first, and then try the document's |
|
10299 // charset (see below). If the string is not UTF-8, |
|
10300 // conversion will fail and give us an empty Unicode string. |
|
10301 // In that case, we should just fall through to using the |
|
10302 // page's charset. |
|
10303 nsresult rv = NS_ERROR_FAILURE; |
|
10304 NS_ConvertUTF8toUTF16 uStr(str); |
|
10305 if (!uStr.IsEmpty()) { |
|
10306 rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll); |
|
10307 } |
|
10308 nsMemory::Free(str); |
|
10309 |
|
10310 // Above will fail if the anchor name is not UTF-8. Need to |
|
10311 // convert from document charset to unicode. |
|
10312 if (NS_FAILED(rv)) { |
|
10313 |
|
10314 // Get a document charset |
|
10315 NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE); |
|
10316 nsIDocument* doc = mContentViewer->GetDocument(); |
|
10317 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
|
10318 const nsACString &aCharset = doc->GetDocumentCharacterSet(); |
|
10319 |
|
10320 nsCOMPtr<nsITextToSubURI> textToSubURI = |
|
10321 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); |
|
10322 NS_ENSURE_SUCCESS(rv, rv); |
|
10323 |
|
10324 // Unescape and convert to unicode |
|
10325 nsXPIDLString uStr; |
|
10326 |
|
10327 rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(), |
|
10328 PromiseFlatCString(newHashName).get(), |
|
10329 getter_Copies(uStr)); |
|
10330 NS_ENSURE_SUCCESS(rv, rv); |
|
10331 |
|
10332 // Ignore return value of GoToAnchor, since it will return an error |
|
10333 // if there is no such anchor in the document, which is actually a |
|
10334 // success condition for us (we want to update the session history |
|
10335 // with the new URI no matter whether we actually scrolled |
|
10336 // somewhere). |
|
10337 // |
|
10338 // When newHashName contains "%00", unescaped string may be empty. |
|
10339 // And GoToAnchor asserts if we ask it to scroll to an empty ref. |
|
10340 shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty()); |
|
10341 } |
|
10342 } |
|
10343 else { |
|
10344 |
|
10345 // Tell the shell it's at an anchor, without scrolling. |
|
10346 shell->GoToAnchor(EmptyString(), false); |
|
10347 |
|
10348 // An empty anchor was found, but if it's a load from history, |
|
10349 // we don't have to jump to the top of the page. Scrollbar |
|
10350 // position will be restored by the caller, based on positions |
|
10351 // stored in session history. |
|
10352 if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) |
|
10353 return NS_OK; |
|
10354 // An empty anchor. Scroll to the top of the page. Ignore the |
|
10355 // return value; failure to scroll here (e.g. if there is no |
|
10356 // root scrollframe) is not grounds for canceling the load! |
|
10357 SetCurScrollPosEx(0, 0); |
|
10358 } |
|
10359 |
|
10360 return NS_OK; |
|
10361 } |
|
10362 |
|
10363 void |
|
10364 nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel) |
|
10365 { |
|
10366 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
|
10367 if (httpChannel) { |
|
10368 nsCOMPtr<nsIURI> referrer; |
|
10369 nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer)); |
|
10370 if (NS_SUCCEEDED(rv)) { |
|
10371 SetReferrerURI(referrer); |
|
10372 } |
|
10373 } |
|
10374 } |
|
10375 |
|
10376 bool |
|
10377 nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, |
|
10378 uint32_t aLoadType, bool aFireOnLocationChange, |
|
10379 bool aAddToGlobalHistory, bool aCloneSHChildren) |
|
10380 { |
|
10381 NS_PRECONDITION(aURI, "uri is null"); |
|
10382 NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set"); |
|
10383 |
|
10384 #if defined(PR_LOGGING) && defined(DEBUG) |
|
10385 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) { |
|
10386 nsAutoCString spec; |
|
10387 aURI->GetSpec(spec); |
|
10388 |
|
10389 nsAutoCString chanName; |
|
10390 if (aChannel) |
|
10391 aChannel->GetName(chanName); |
|
10392 else |
|
10393 chanName.AssignLiteral("<no channel>"); |
|
10394 |
|
10395 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
10396 ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n", this, spec.get(), |
|
10397 chanName.get(), aLoadType)); |
|
10398 } |
|
10399 #endif |
|
10400 |
|
10401 bool equalUri = false; |
|
10402 |
|
10403 // Get the post data and the HTTP response code from the channel. |
|
10404 uint32_t responseStatus = 0; |
|
10405 nsCOMPtr<nsIInputStream> inputStream; |
|
10406 if (aChannel) { |
|
10407 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
|
10408 |
|
10409 // Check if the HTTPChannel is hiding under a multiPartChannel |
|
10410 if (!httpChannel) { |
|
10411 GetHttpChannel(aChannel, getter_AddRefs(httpChannel)); |
|
10412 } |
|
10413 |
|
10414 if (httpChannel) { |
|
10415 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel)); |
|
10416 if (uploadChannel) { |
|
10417 uploadChannel->GetUploadStream(getter_AddRefs(inputStream)); |
|
10418 } |
|
10419 |
|
10420 // If the response status indicates an error, unlink this session |
|
10421 // history entry from any entries sharing its document. |
|
10422 nsresult rv = httpChannel->GetResponseStatus(&responseStatus); |
|
10423 if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) { |
|
10424 mLSHE->AbandonBFCacheEntry(); |
|
10425 } |
|
10426 } |
|
10427 } |
|
10428 |
|
10429 // Determine if this type of load should update history. |
|
10430 bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY || |
|
10431 aLoadType == LOAD_ERROR_PAGE || |
|
10432 aLoadType & LOAD_CMD_HISTORY); |
|
10433 |
|
10434 // We don't update session history on reload. |
|
10435 bool updateSHistory = updateGHistory && (!(aLoadType & LOAD_CMD_RELOAD)); |
|
10436 |
|
10437 /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in |
|
10438 * the current frame or in the root docshell |
|
10439 */ |
|
10440 nsCOMPtr<nsISHistory> rootSH = mSessionHistory; |
|
10441 if (!rootSH) { |
|
10442 // Get the handle to SH from the root docshell |
|
10443 GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
10444 if (!rootSH) { |
|
10445 updateSHistory = false; |
|
10446 updateGHistory = false; // XXX Why global history too? |
|
10447 } |
|
10448 } // rootSH |
|
10449 |
|
10450 // Check if the url to be loaded is the same as the one already loaded. |
|
10451 if (mCurrentURI) |
|
10452 aURI->Equals(mCurrentURI, &equalUri); |
|
10453 |
|
10454 #ifdef DEBUG |
|
10455 bool shAvailable = (rootSH != nullptr); |
|
10456 |
|
10457 // XXX This log message is almost useless because |updateSHistory| |
|
10458 // and |updateGHistory| are not correct at this point. |
|
10459 |
|
10460 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
10461 (" shAvailable=%i updateSHistory=%i updateGHistory=%i" |
|
10462 " equalURI=%i\n", |
|
10463 shAvailable, updateSHistory, updateGHistory, equalUri)); |
|
10464 |
|
10465 if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) { |
|
10466 NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?"); |
|
10467 } |
|
10468 #endif |
|
10469 |
|
10470 /* If the url to be loaded is the same as the one already there, |
|
10471 * and the original loadType is LOAD_NORMAL, LOAD_LINK, or |
|
10472 * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that |
|
10473 * AddToSessionHistory() won't mess with the current SHEntry and |
|
10474 * if this page has any frame children, it also will be handled |
|
10475 * properly. see bug 83684 |
|
10476 * |
|
10477 * NB: If mOSHE is null but we have a current URI, then it means |
|
10478 * that we must be at the transient about:blank content viewer |
|
10479 * (asserted above) and we should let the normal load continue, |
|
10480 * since there's nothing to replace. |
|
10481 * |
|
10482 * XXX Hopefully changing the loadType at this time will not hurt |
|
10483 * anywhere. The other way to take care of sequentially repeating |
|
10484 * frameset pages is to add new methods to nsIDocShellTreeItem. |
|
10485 * Hopefully I don't have to do that. |
|
10486 */ |
|
10487 if (equalUri && |
|
10488 mOSHE && |
|
10489 (mLoadType == LOAD_NORMAL || |
|
10490 mLoadType == LOAD_LINK || |
|
10491 mLoadType == LOAD_STOP_CONTENT) && |
|
10492 !inputStream) |
|
10493 { |
|
10494 mLoadType = LOAD_NORMAL_REPLACE; |
|
10495 } |
|
10496 |
|
10497 // If this is a refresh to the currently loaded url, we don't |
|
10498 // have to update session or global history. |
|
10499 if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) { |
|
10500 SetHistoryEntry(&mLSHE, mOSHE); |
|
10501 } |
|
10502 |
|
10503 /* If the user pressed shift-reload, cache will create a new cache key |
|
10504 * for the page. Save the new cacheKey in Session History. |
|
10505 * see bug 90098 |
|
10506 */ |
|
10507 if (aChannel && |
|
10508 (aLoadType == LOAD_RELOAD_BYPASS_CACHE || |
|
10509 aLoadType == LOAD_RELOAD_BYPASS_PROXY || |
|
10510 aLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE || |
|
10511 aLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT)) { |
|
10512 NS_ASSERTION(!updateSHistory, |
|
10513 "We shouldn't be updating session history for forced" |
|
10514 " reloads!"); |
|
10515 |
|
10516 nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel)); |
|
10517 nsCOMPtr<nsISupports> cacheKey; |
|
10518 // Get the Cache Key and store it in SH. |
|
10519 if (cacheChannel) |
|
10520 cacheChannel->GetCacheKey(getter_AddRefs(cacheKey)); |
|
10521 // If we already have a loading history entry, store the new cache key |
|
10522 // in it. Otherwise, since we're doing a reload and won't be updating |
|
10523 // our history entry, store the cache key in our current history entry. |
|
10524 if (mLSHE) |
|
10525 mLSHE->SetCacheKey(cacheKey); |
|
10526 else if (mOSHE) |
|
10527 mOSHE->SetCacheKey(cacheKey); |
|
10528 |
|
10529 // Since we're force-reloading, clear all the sub frame history. |
|
10530 ClearFrameHistory(mLSHE); |
|
10531 ClearFrameHistory(mOSHE); |
|
10532 } |
|
10533 |
|
10534 if (aLoadType == LOAD_RELOAD_NORMAL) { |
|
10535 nsCOMPtr<nsISHEntry> currentSH; |
|
10536 bool oshe = false; |
|
10537 GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe); |
|
10538 bool dynamicallyAddedChild = false; |
|
10539 if (currentSH) { |
|
10540 currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild); |
|
10541 } |
|
10542 if (dynamicallyAddedChild) { |
|
10543 ClearFrameHistory(currentSH); |
|
10544 } |
|
10545 } |
|
10546 |
|
10547 if (aLoadType == LOAD_REFRESH) { |
|
10548 ClearFrameHistory(mLSHE); |
|
10549 ClearFrameHistory(mOSHE); |
|
10550 } |
|
10551 |
|
10552 if (updateSHistory) { |
|
10553 // Update session history if necessary... |
|
10554 if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) { |
|
10555 /* This is a fresh page getting loaded for the first time |
|
10556 *.Create a Entry for it and add it to SH, if this is the |
|
10557 * rootDocShell |
|
10558 */ |
|
10559 (void) AddToSessionHistory(aURI, aChannel, aOwner, aCloneSHChildren, |
|
10560 getter_AddRefs(mLSHE)); |
|
10561 } |
|
10562 } |
|
10563 |
|
10564 // If this is a POST request, we do not want to include this in global |
|
10565 // history. |
|
10566 if (updateGHistory && |
|
10567 aAddToGlobalHistory && |
|
10568 !ChannelIsPost(aChannel)) { |
|
10569 nsCOMPtr<nsIURI> previousURI; |
|
10570 uint32_t previousFlags = 0; |
|
10571 |
|
10572 if (aLoadType & LOAD_CMD_RELOAD) { |
|
10573 // On a reload request, we don't set redirecting flags. |
|
10574 previousURI = aURI; |
|
10575 } else { |
|
10576 ExtractLastVisit(aChannel, getter_AddRefs(previousURI), |
|
10577 &previousFlags); |
|
10578 } |
|
10579 |
|
10580 // Note: We don't use |referrer| when our global history is |
|
10581 // based on IHistory. |
|
10582 nsCOMPtr<nsIURI> referrer; |
|
10583 // Treat referrer as null if there is an error getting it. |
|
10584 (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer)); |
|
10585 |
|
10586 AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus); |
|
10587 } |
|
10588 |
|
10589 // If this was a history load or a refresh, |
|
10590 // update the index in SH. |
|
10591 if (rootSH && (mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD))) { |
|
10592 nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH)); |
|
10593 if (shInternal) { |
|
10594 rootSH->GetIndex(&mPreviousTransIndex); |
|
10595 shInternal->UpdateIndex(); |
|
10596 rootSH->GetIndex(&mLoadedTransIndex); |
|
10597 #ifdef DEBUG_PAGE_CACHE |
|
10598 printf("Previous index: %d, Loaded index: %d\n\n", |
|
10599 mPreviousTransIndex, mLoadedTransIndex); |
|
10600 #endif |
|
10601 } |
|
10602 } |
|
10603 |
|
10604 // aCloneSHChildren exactly means "we are not loading a new document". |
|
10605 uint32_t locationFlags = aCloneSHChildren? |
|
10606 uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0; |
|
10607 |
|
10608 bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel, |
|
10609 aFireOnLocationChange, |
|
10610 locationFlags); |
|
10611 // Make sure to store the referrer from the channel, if any |
|
10612 SetupReferrerFromChannel(aChannel); |
|
10613 return onLocationChangeNeeded; |
|
10614 } |
|
10615 |
|
10616 bool |
|
10617 nsDocShell::OnLoadingSite(nsIChannel * aChannel, bool aFireOnLocationChange, |
|
10618 bool aAddToGlobalHistory) |
|
10619 { |
|
10620 nsCOMPtr<nsIURI> uri; |
|
10621 // If this a redirect, use the final url (uri) |
|
10622 // else use the original url |
|
10623 // |
|
10624 // Note that this should match what documents do (see nsDocument::Reset). |
|
10625 NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); |
|
10626 NS_ENSURE_TRUE(uri, false); |
|
10627 |
|
10628 // Pass false for aCloneSHChildren, since we're loading a new page here. |
|
10629 return OnNewURI(uri, aChannel, nullptr, mLoadType, aFireOnLocationChange, |
|
10630 aAddToGlobalHistory, false); |
|
10631 |
|
10632 } |
|
10633 |
|
10634 void |
|
10635 nsDocShell::SetReferrerURI(nsIURI * aURI) |
|
10636 { |
|
10637 mReferrerURI = aURI; // This assigment addrefs |
|
10638 } |
|
10639 |
|
10640 //***************************************************************************** |
|
10641 // nsDocShell: Session History |
|
10642 //***************************************************************************** |
|
10643 |
|
10644 NS_IMETHODIMP |
|
10645 nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle, |
|
10646 const nsAString& aURL, bool aReplace, JSContext* aCx) |
|
10647 { |
|
10648 // Implements History.pushState and History.replaceState |
|
10649 |
|
10650 // Here's what we do, roughly in the order specified by HTML5: |
|
10651 // 1. Serialize aData using structured clone. |
|
10652 // 2. If the third argument is present, |
|
10653 // a. Resolve the url, relative to the first script's base URL |
|
10654 // b. If (a) fails, raise a SECURITY_ERR |
|
10655 // c. Compare the resulting absolute URL to the document's address. If |
|
10656 // any part of the URLs difer other than the <path>, <query>, and |
|
10657 // <fragment> components, raise a SECURITY_ERR and abort. |
|
10658 // 3. If !aReplace: |
|
10659 // Remove from the session history all entries after the current entry, |
|
10660 // as we would after a regular navigation, and save the current |
|
10661 // entry's scroll position (bug 590573). |
|
10662 // 4. As apropriate, either add a state object entry to the session history |
|
10663 // after the current entry with the following properties, or modify the |
|
10664 // current session history entry to set |
|
10665 // a. cloned data as the state object, |
|
10666 // b. if the third argument was present, the absolute URL found in |
|
10667 // step 2 |
|
10668 // Also clear the new history entry's POST data (see bug 580069). |
|
10669 // 5. If aReplace is false (i.e. we're doing a pushState instead of a |
|
10670 // replaceState), notify bfcache that we've navigated to a new page. |
|
10671 // 6. If the third argument is present, set the document's current address |
|
10672 // to the absolute URL found in step 2. |
|
10673 // |
|
10674 // It's important that this function not run arbitrary scripts after step 1 |
|
10675 // and before completing step 5. For example, if a script called |
|
10676 // history.back() before we completed step 5, bfcache might destroy an |
|
10677 // active content viewer. Since EvictOutOfRangeContentViewers at the end of |
|
10678 // step 5 might run script, we can't just put a script blocker around the |
|
10679 // critical section. |
|
10680 // |
|
10681 // Note that we completely ignore the aTitle parameter. |
|
10682 |
|
10683 nsresult rv; |
|
10684 |
|
10685 // Don't clobber the load type of an existing network load. |
|
10686 AutoRestore<uint32_t> loadTypeResetter(mLoadType); |
|
10687 |
|
10688 // pushState effectively becomes replaceState when we've started a network |
|
10689 // load but haven't adopted its document yet. This mirrors what we do with |
|
10690 // changes to the hash at this stage of the game. |
|
10691 if (JustStartedNetworkLoad()) { |
|
10692 aReplace = true; |
|
10693 } |
|
10694 |
|
10695 nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this)); |
|
10696 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); |
|
10697 |
|
10698 // Step 1: Serialize aData using structured clone. |
|
10699 nsCOMPtr<nsIStructuredCloneContainer> scContainer; |
|
10700 |
|
10701 // scContainer->Init might cause arbitrary JS to run, and this code might |
|
10702 // navigate the page we're on, potentially to a different origin! (bug |
|
10703 // 634834) To protect against this, we abort if our principal changes due |
|
10704 // to the InitFromJSVal() call. |
|
10705 { |
|
10706 nsCOMPtr<nsIDocument> origDocument = |
|
10707 do_GetInterface(GetAsSupports(this)); |
|
10708 if (!origDocument) |
|
10709 return NS_ERROR_DOM_SECURITY_ERR; |
|
10710 nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal(); |
|
10711 |
|
10712 scContainer = new nsStructuredCloneContainer(); |
|
10713 JSContext *cx = aCx; |
|
10714 nsCxPusher pusher; |
|
10715 if (!cx) { |
|
10716 cx = nsContentUtils::GetContextFromDocument(document); |
|
10717 pusher.Push(cx); |
|
10718 } |
|
10719 rv = scContainer->InitFromJSVal(aData, cx); |
|
10720 |
|
10721 // If we're running in the document's context and the structured clone |
|
10722 // failed, clear the context's pending exception. See bug 637116. |
|
10723 if (NS_FAILED(rv) && !aCx) { |
|
10724 JS_ClearPendingException(aCx); |
|
10725 } |
|
10726 NS_ENSURE_SUCCESS(rv, rv); |
|
10727 |
|
10728 nsCOMPtr<nsIDocument> newDocument = |
|
10729 do_GetInterface(GetAsSupports(this)); |
|
10730 if (!newDocument) |
|
10731 return NS_ERROR_DOM_SECURITY_ERR; |
|
10732 nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal(); |
|
10733 |
|
10734 bool principalsEqual = false; |
|
10735 origPrincipal->Equals(newPrincipal, &principalsEqual); |
|
10736 NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR); |
|
10737 } |
|
10738 |
|
10739 // Check that the state object isn't too long. |
|
10740 // Default max length: 640k bytes. |
|
10741 int32_t maxStateObjSize = |
|
10742 Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000); |
|
10743 if (maxStateObjSize < 0) { |
|
10744 maxStateObjSize = 0; |
|
10745 } |
|
10746 |
|
10747 uint64_t scSize; |
|
10748 rv = scContainer->GetSerializedNBytes(&scSize); |
|
10749 NS_ENSURE_SUCCESS(rv, rv); |
|
10750 |
|
10751 NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, |
|
10752 NS_ERROR_ILLEGAL_VALUE); |
|
10753 |
|
10754 // Step 2: Resolve aURL |
|
10755 bool equalURIs = true; |
|
10756 nsCOMPtr<nsIURI> currentURI; |
|
10757 if (sURIFixup && mCurrentURI) { |
|
10758 rv = sURIFixup->CreateExposableURI(mCurrentURI, |
|
10759 getter_AddRefs(currentURI)); |
|
10760 NS_ENSURE_SUCCESS(rv, rv); |
|
10761 } else { |
|
10762 currentURI = mCurrentURI; |
|
10763 } |
|
10764 nsCOMPtr<nsIURI> oldURI = currentURI; |
|
10765 nsCOMPtr<nsIURI> newURI; |
|
10766 if (aURL.Length() == 0) { |
|
10767 newURI = currentURI; |
|
10768 } |
|
10769 else { |
|
10770 // 2a: Resolve aURL relative to mURI |
|
10771 |
|
10772 nsIURI* docBaseURI = document->GetDocBaseURI(); |
|
10773 if (!docBaseURI) |
|
10774 return NS_ERROR_FAILURE; |
|
10775 |
|
10776 nsAutoCString spec; |
|
10777 docBaseURI->GetSpec(spec); |
|
10778 |
|
10779 nsAutoCString charset; |
|
10780 rv = docBaseURI->GetOriginCharset(charset); |
|
10781 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
|
10782 |
|
10783 rv = NS_NewURI(getter_AddRefs(newURI), aURL, |
|
10784 charset.get(), docBaseURI); |
|
10785 |
|
10786 // 2b: If 2a fails, raise a SECURITY_ERR |
|
10787 if (NS_FAILED(rv)) { |
|
10788 return NS_ERROR_DOM_SECURITY_ERR; |
|
10789 } |
|
10790 |
|
10791 // 2c: Same-origin check. |
|
10792 if (!nsContentUtils::URIIsLocalFile(newURI)) { |
|
10793 // In addition to checking that the security manager says that |
|
10794 // the new URI has the same origin as our current URI, we also |
|
10795 // check that the two URIs have the same userpass. (The |
|
10796 // security manager says that |http://foo.com| and |
|
10797 // |http://me@foo.com| have the same origin.) currentURI |
|
10798 // won't contain the password part of the userpass, so this |
|
10799 // means that it's never valid to specify a password in a |
|
10800 // pushState or replaceState URI. |
|
10801 |
|
10802 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
10803 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
10804 NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE); |
|
10805 |
|
10806 // It's very important that we check that newURI is of the same |
|
10807 // origin as currentURI, not docBaseURI, because a page can |
|
10808 // set docBaseURI arbitrarily to any domain. |
|
10809 nsAutoCString currentUserPass, newUserPass; |
|
10810 NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass), |
|
10811 NS_ERROR_FAILURE); |
|
10812 NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), |
|
10813 NS_ERROR_FAILURE); |
|
10814 if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, |
|
10815 newURI, true)) || |
|
10816 !currentUserPass.Equals(newUserPass)) { |
|
10817 |
|
10818 return NS_ERROR_DOM_SECURITY_ERR; |
|
10819 } |
|
10820 } |
|
10821 else { |
|
10822 // It's a file:// URI |
|
10823 nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj = |
|
10824 do_QueryInterface(document); |
|
10825 |
|
10826 if (!docScriptObj) { |
|
10827 return NS_ERROR_DOM_SECURITY_ERR; |
|
10828 } |
|
10829 |
|
10830 nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal(); |
|
10831 |
|
10832 if (!principal || |
|
10833 NS_FAILED(principal->CheckMayLoad(newURI, true, false))) { |
|
10834 |
|
10835 return NS_ERROR_DOM_SECURITY_ERR; |
|
10836 } |
|
10837 } |
|
10838 |
|
10839 if (currentURI) { |
|
10840 currentURI->Equals(newURI, &equalURIs); |
|
10841 } |
|
10842 else { |
|
10843 equalURIs = false; |
|
10844 } |
|
10845 |
|
10846 } // end of same-origin check |
|
10847 |
|
10848 // Step 3: Create a new entry in the session history. This will erase |
|
10849 // all SHEntries after the new entry and make this entry the current |
|
10850 // one. This operation may modify mOSHE, which we need later, so we |
|
10851 // keep a reference here. |
|
10852 NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE); |
|
10853 nsCOMPtr<nsISHEntry> oldOSHE = mOSHE; |
|
10854 |
|
10855 mLoadType = LOAD_PUSHSTATE; |
|
10856 |
|
10857 nsCOMPtr<nsISHEntry> newSHEntry; |
|
10858 if (!aReplace) { |
|
10859 // Save the current scroll position (bug 590573). |
|
10860 nscoord cx = 0, cy = 0; |
|
10861 GetCurScrollPos(ScrollOrientation_X, &cx); |
|
10862 GetCurScrollPos(ScrollOrientation_Y, &cy); |
|
10863 mOSHE->SetScrollPosition(cx, cy); |
|
10864 |
|
10865 // Since we're not changing which page we have loaded, pass |
|
10866 // true for aCloneChildren. |
|
10867 rv = AddToSessionHistory(newURI, nullptr, nullptr, true, |
|
10868 getter_AddRefs(newSHEntry)); |
|
10869 NS_ENSURE_SUCCESS(rv, rv); |
|
10870 |
|
10871 NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE); |
|
10872 |
|
10873 // Link the new SHEntry to the old SHEntry's BFCache entry, since the |
|
10874 // two entries correspond to the same document. |
|
10875 NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), |
|
10876 NS_ERROR_FAILURE); |
|
10877 |
|
10878 // Set the new SHEntry's title (bug 655273). |
|
10879 nsString title; |
|
10880 mOSHE->GetTitle(getter_Copies(title)); |
|
10881 newSHEntry->SetTitle(title); |
|
10882 |
|
10883 // AddToSessionHistory may not modify mOSHE. In case it doesn't, |
|
10884 // we'll just set mOSHE here. |
|
10885 mOSHE = newSHEntry; |
|
10886 |
|
10887 } else { |
|
10888 newSHEntry = mOSHE; |
|
10889 newSHEntry->SetURI(newURI); |
|
10890 } |
|
10891 |
|
10892 // Step 4: Modify new/original session history entry and clear its POST |
|
10893 // data, if there is any. |
|
10894 newSHEntry->SetStateData(scContainer); |
|
10895 newSHEntry->SetPostData(nullptr); |
|
10896 |
|
10897 // If this push/replaceState changed the document's current URI and the new |
|
10898 // URI differs from the old URI in more than the hash, or if the old |
|
10899 // SHEntry's URI was modified in this way by a push/replaceState call |
|
10900 // set URIWasModified to true for the current SHEntry (bug 669671). |
|
10901 bool sameExceptHashes = true, oldURIWasModified = false; |
|
10902 newURI->EqualsExceptRef(currentURI, &sameExceptHashes); |
|
10903 oldOSHE->GetURIWasModified(&oldURIWasModified); |
|
10904 newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified); |
|
10905 |
|
10906 // Step 5: If aReplace is false, indicating that we're doing a pushState |
|
10907 // rather than a replaceState, notify bfcache that we've added a page to |
|
10908 // the history so it can evict content viewers if appropriate. Otherwise |
|
10909 // call ReplaceEntry so that we notify nsIHistoryListeners that an entry |
|
10910 // was replaced. |
|
10911 nsCOMPtr<nsISHistory> rootSH; |
|
10912 GetRootSessionHistory(getter_AddRefs(rootSH)); |
|
10913 NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED); |
|
10914 |
|
10915 nsCOMPtr<nsISHistoryInternal> internalSH = |
|
10916 do_QueryInterface(rootSH); |
|
10917 NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED); |
|
10918 |
|
10919 if (!aReplace) { |
|
10920 int32_t curIndex = -1; |
|
10921 rv = rootSH->GetIndex(&curIndex); |
|
10922 if (NS_SUCCEEDED(rv) && curIndex > -1) { |
|
10923 internalSH->EvictOutOfRangeContentViewers(curIndex); |
|
10924 } |
|
10925 } else { |
|
10926 nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry); |
|
10927 |
|
10928 int32_t index = -1; |
|
10929 rv = rootSH->GetIndexOfEntry(rootSHEntry, &index); |
|
10930 if (NS_SUCCEEDED(rv) && index > -1) { |
|
10931 internalSH->ReplaceEntry(index, rootSHEntry); |
|
10932 } |
|
10933 } |
|
10934 |
|
10935 // Step 6: If the document's URI changed, update document's URI and update |
|
10936 // global history. |
|
10937 // |
|
10938 // We need to call FireOnLocationChange so that the browser's address bar |
|
10939 // gets updated and the back button is enabled, but we only need to |
|
10940 // explicitly call FireOnLocationChange if we're not calling SetCurrentURI, |
|
10941 // since SetCurrentURI will call FireOnLocationChange for us. |
|
10942 // |
|
10943 // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass |
|
10944 // nullptr for aRequest param to FireOnLocationChange(...). Such an update |
|
10945 // notification is allowed only when we know docshell is not loading a new |
|
10946 // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise, |
|
10947 // FireOnLocationChange(...) breaks security UI. |
|
10948 if (!equalURIs) { |
|
10949 SetCurrentURI(newURI, nullptr, true, LOCATION_CHANGE_SAME_DOCUMENT); |
|
10950 document->SetDocumentURI(newURI); |
|
10951 |
|
10952 AddURIVisit(newURI, oldURI, oldURI, 0); |
|
10953 |
|
10954 // AddURIVisit doesn't set the title for the new URI in global history, |
|
10955 // so do that here. |
|
10956 if (mUseGlobalHistory && !mInPrivateBrowsing) { |
|
10957 nsCOMPtr<IHistory> history = services::GetHistoryService(); |
|
10958 if (history) { |
|
10959 history->SetURITitle(newURI, mTitle); |
|
10960 } |
|
10961 else if (mGlobalHistory) { |
|
10962 mGlobalHistory->SetPageTitle(newURI, mTitle); |
|
10963 } |
|
10964 } |
|
10965 |
|
10966 // Inform the favicon service that our old favicon applies to this new |
|
10967 // URI. |
|
10968 CopyFavicon(oldURI, newURI, mInPrivateBrowsing); |
|
10969 } |
|
10970 else { |
|
10971 FireDummyOnLocationChange(); |
|
10972 } |
|
10973 document->SetStateObject(scContainer); |
|
10974 |
|
10975 return NS_OK; |
|
10976 } |
|
10977 |
|
10978 bool |
|
10979 nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI) |
|
10980 { |
|
10981 // I believe none of the about: urls should go in the history. But then |
|
10982 // that could just be me... If the intent is only deny about:blank then we |
|
10983 // should just do a spec compare, rather than two gets of the scheme and |
|
10984 // then the path. -Gagan |
|
10985 nsresult rv; |
|
10986 nsAutoCString buf, pref; |
|
10987 |
|
10988 rv = aURI->GetScheme(buf); |
|
10989 if (NS_FAILED(rv)) |
|
10990 return false; |
|
10991 |
|
10992 if (buf.Equals("about")) { |
|
10993 rv = aURI->GetPath(buf); |
|
10994 if (NS_FAILED(rv)) |
|
10995 return false; |
|
10996 |
|
10997 if (buf.Equals("blank")) { |
|
10998 return false; |
|
10999 } |
|
11000 } |
|
11001 |
|
11002 rv = Preferences::GetDefaultCString("browser.newtab.url", &pref); |
|
11003 |
|
11004 if (NS_FAILED(rv)) { |
|
11005 return true; |
|
11006 } |
|
11007 |
|
11008 rv = aURI->GetSpec(buf); |
|
11009 NS_ENSURE_SUCCESS(rv, true); |
|
11010 |
|
11011 return !buf.Equals(pref); |
|
11012 } |
|
11013 |
|
11014 nsresult |
|
11015 nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel, |
|
11016 nsISupports* aOwner, bool aCloneChildren, |
|
11017 nsISHEntry ** aNewEntry) |
|
11018 { |
|
11019 NS_PRECONDITION(aURI, "uri is null"); |
|
11020 NS_PRECONDITION(!aChannel || !aOwner, "Shouldn't have both set"); |
|
11021 |
|
11022 #if defined(PR_LOGGING) && defined(DEBUG) |
|
11023 if (PR_LOG_TEST(gDocShellLog, PR_LOG_DEBUG)) { |
|
11024 nsAutoCString spec; |
|
11025 aURI->GetSpec(spec); |
|
11026 |
|
11027 nsAutoCString chanName; |
|
11028 if (aChannel) |
|
11029 aChannel->GetName(chanName); |
|
11030 else |
|
11031 chanName.AssignLiteral("<no channel>"); |
|
11032 |
|
11033 PR_LOG(gDocShellLog, PR_LOG_DEBUG, |
|
11034 ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n", this, spec.get(), |
|
11035 chanName.get())); |
|
11036 } |
|
11037 #endif |
|
11038 |
|
11039 nsresult rv = NS_OK; |
|
11040 nsCOMPtr<nsISHEntry> entry; |
|
11041 bool shouldPersist; |
|
11042 |
|
11043 shouldPersist = ShouldAddToSessionHistory(aURI); |
|
11044 |
|
11045 // Get a handle to the root docshell |
|
11046 nsCOMPtr<nsIDocShellTreeItem> root; |
|
11047 GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
11048 /* |
|
11049 * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use |
|
11050 * the existing SH entry in the page and replace the url and |
|
11051 * other vitalities. |
|
11052 */ |
|
11053 if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) && |
|
11054 root != static_cast<nsIDocShellTreeItem *>(this)) { |
|
11055 // This is a subframe |
|
11056 entry = mOSHE; |
|
11057 nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry)); |
|
11058 if (shContainer) { |
|
11059 int32_t childCount = 0; |
|
11060 shContainer->GetChildCount(&childCount); |
|
11061 // Remove all children of this entry |
|
11062 for (int32_t i = childCount - 1; i >= 0; i--) { |
|
11063 nsCOMPtr<nsISHEntry> child; |
|
11064 shContainer->GetChildAt(i, getter_AddRefs(child)); |
|
11065 shContainer->RemoveChild(child); |
|
11066 } // for |
|
11067 entry->AbandonBFCacheEntry(); |
|
11068 } // shContainer |
|
11069 } |
|
11070 |
|
11071 // Create a new entry if necessary. |
|
11072 if (!entry) { |
|
11073 entry = do_CreateInstance(NS_SHENTRY_CONTRACTID); |
|
11074 |
|
11075 if (!entry) { |
|
11076 return NS_ERROR_OUT_OF_MEMORY; |
|
11077 } |
|
11078 } |
|
11079 |
|
11080 // Get the post data & referrer |
|
11081 nsCOMPtr<nsIInputStream> inputStream; |
|
11082 nsCOMPtr<nsIURI> referrerURI; |
|
11083 nsCOMPtr<nsISupports> cacheKey; |
|
11084 nsCOMPtr<nsISupports> owner = aOwner; |
|
11085 bool expired = false; |
|
11086 bool discardLayoutState = false; |
|
11087 nsCOMPtr<nsICachingChannel> cacheChannel; |
|
11088 if (aChannel) { |
|
11089 cacheChannel = do_QueryInterface(aChannel); |
|
11090 |
|
11091 /* If there is a caching channel, get the Cache Key and store it |
|
11092 * in SH. |
|
11093 */ |
|
11094 if (cacheChannel) { |
|
11095 cacheChannel->GetCacheKey(getter_AddRefs(cacheKey)); |
|
11096 } |
|
11097 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
|
11098 |
|
11099 // Check if the httpChannel is hiding under a multipartChannel |
|
11100 if (!httpChannel) { |
|
11101 GetHttpChannel(aChannel, getter_AddRefs(httpChannel)); |
|
11102 } |
|
11103 if (httpChannel) { |
|
11104 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel)); |
|
11105 if (uploadChannel) { |
|
11106 uploadChannel->GetUploadStream(getter_AddRefs(inputStream)); |
|
11107 } |
|
11108 httpChannel->GetReferrer(getter_AddRefs(referrerURI)); |
|
11109 |
|
11110 discardLayoutState = ShouldDiscardLayoutState(httpChannel); |
|
11111 } |
|
11112 aChannel->GetOwner(getter_AddRefs(owner)); |
|
11113 } |
|
11114 |
|
11115 //Title is set in nsDocShell::SetTitle() |
|
11116 entry->Create(aURI, // uri |
|
11117 EmptyString(), // Title |
|
11118 inputStream, // Post data stream |
|
11119 nullptr, // LayoutHistory state |
|
11120 cacheKey, // CacheKey |
|
11121 mContentTypeHint, // Content-type |
|
11122 owner, // Channel or provided owner |
|
11123 mHistoryID, |
|
11124 mDynamicallyCreated); |
|
11125 entry->SetReferrerURI(referrerURI); |
|
11126 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel); |
|
11127 if (inStrmChan) { |
|
11128 bool isSrcdocChannel; |
|
11129 inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel); |
|
11130 if (isSrcdocChannel) { |
|
11131 nsAutoString srcdoc; |
|
11132 inStrmChan->GetSrcdocData(srcdoc); |
|
11133 entry->SetSrcdocData(srcdoc); |
|
11134 nsCOMPtr<nsIURI> baseURI; |
|
11135 inStrmChan->GetBaseURI(getter_AddRefs(baseURI)); |
|
11136 entry->SetBaseURI(baseURI); |
|
11137 } |
|
11138 } |
|
11139 /* If cache got a 'no-store', ask SH not to store |
|
11140 * HistoryLayoutState. By default, SH will set this |
|
11141 * flag to true and save HistoryLayoutState. |
|
11142 */ |
|
11143 if (discardLayoutState) { |
|
11144 entry->SetSaveLayoutStateFlag(false); |
|
11145 } |
|
11146 if (cacheChannel) { |
|
11147 // Check if the page has expired from cache |
|
11148 uint32_t expTime = 0; |
|
11149 cacheChannel->GetCacheTokenExpirationTime(&expTime); |
|
11150 uint32_t now = PRTimeToSeconds(PR_Now()); |
|
11151 if (expTime <= now) |
|
11152 expired = true; |
|
11153 } |
|
11154 if (expired) |
|
11155 entry->SetExpirationStatus(true); |
|
11156 |
|
11157 |
|
11158 if (root == static_cast<nsIDocShellTreeItem *>(this) && mSessionHistory) { |
|
11159 // If we need to clone our children onto the new session |
|
11160 // history entry, do so now. |
|
11161 if (aCloneChildren && mOSHE) { |
|
11162 uint32_t cloneID; |
|
11163 mOSHE->GetID(&cloneID); |
|
11164 nsCOMPtr<nsISHEntry> newEntry; |
|
11165 CloneAndReplace(mOSHE, this, cloneID, entry, true, getter_AddRefs(newEntry)); |
|
11166 NS_ASSERTION(entry == newEntry, "The new session history should be in the new entry"); |
|
11167 } |
|
11168 |
|
11169 // This is the root docshell |
|
11170 if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) { |
|
11171 // Replace current entry in session history. |
|
11172 int32_t index = 0; |
|
11173 mSessionHistory->GetIndex(&index); |
|
11174 nsCOMPtr<nsISHistoryInternal> shPrivate(do_QueryInterface(mSessionHistory)); |
|
11175 // Replace the current entry with the new entry |
|
11176 if (shPrivate) |
|
11177 rv = shPrivate->ReplaceEntry(index, entry); |
|
11178 } |
|
11179 else { |
|
11180 // Add to session history |
|
11181 nsCOMPtr<nsISHistoryInternal> |
|
11182 shPrivate(do_QueryInterface(mSessionHistory)); |
|
11183 NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE); |
|
11184 mSessionHistory->GetIndex(&mPreviousTransIndex); |
|
11185 rv = shPrivate->AddEntry(entry, shouldPersist); |
|
11186 mSessionHistory->GetIndex(&mLoadedTransIndex); |
|
11187 #ifdef DEBUG_PAGE_CACHE |
|
11188 printf("Previous index: %d, Loaded index: %d\n\n", |
|
11189 mPreviousTransIndex, mLoadedTransIndex); |
|
11190 #endif |
|
11191 } |
|
11192 } |
|
11193 else { |
|
11194 // This is a subframe. |
|
11195 if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType, |
|
11196 LOAD_FLAGS_REPLACE_HISTORY)) |
|
11197 rv = DoAddChildSHEntry(entry, mChildOffset, aCloneChildren); |
|
11198 } |
|
11199 |
|
11200 // Return the new SH entry... |
|
11201 if (aNewEntry) { |
|
11202 *aNewEntry = nullptr; |
|
11203 if (NS_SUCCEEDED(rv)) { |
|
11204 *aNewEntry = entry; |
|
11205 NS_ADDREF(*aNewEntry); |
|
11206 } |
|
11207 } |
|
11208 |
|
11209 return rv; |
|
11210 } |
|
11211 |
|
11212 |
|
11213 NS_IMETHODIMP |
|
11214 nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType) |
|
11215 { |
|
11216 if (!IsNavigationAllowed()) { |
|
11217 return NS_OK; |
|
11218 } |
|
11219 |
|
11220 nsCOMPtr<nsIURI> uri; |
|
11221 nsCOMPtr<nsIInputStream> postData; |
|
11222 nsCOMPtr<nsIURI> referrerURI; |
|
11223 nsAutoCString contentType; |
|
11224 nsCOMPtr<nsISupports> owner; |
|
11225 |
|
11226 NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE); |
|
11227 |
|
11228 NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE); |
|
11229 NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)), |
|
11230 NS_ERROR_FAILURE); |
|
11231 NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)), |
|
11232 NS_ERROR_FAILURE); |
|
11233 NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE); |
|
11234 NS_ENSURE_SUCCESS(aEntry->GetOwner(getter_AddRefs(owner)), |
|
11235 NS_ERROR_FAILURE); |
|
11236 |
|
11237 // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if |
|
11238 // that's the only thing holding a ref to aEntry that will cause aEntry to |
|
11239 // die while we're loading it. So hold a strong ref to aEntry here, just |
|
11240 // in case. |
|
11241 nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry); |
|
11242 bool isJS; |
|
11243 nsresult rv = uri->SchemeIs("javascript", &isJS); |
|
11244 if (NS_FAILED(rv) || isJS) { |
|
11245 // We're loading a URL that will execute script from inside asyncOpen. |
|
11246 // Replace the current document with about:blank now to prevent |
|
11247 // anything from the current document from leaking into any JavaScript |
|
11248 // code in the URL. |
|
11249 nsCOMPtr<nsIPrincipal> prin = do_QueryInterface(owner); |
|
11250 // Don't cache the presentation if we're going to just reload the |
|
11251 // current entry. Caching would lead to trying to save the different |
|
11252 // content viewers in the same nsISHEntry object. |
|
11253 rv = CreateAboutBlankContentViewer(prin, nullptr, aEntry != mOSHE); |
|
11254 |
|
11255 if (NS_FAILED(rv)) { |
|
11256 // The creation of the intermittent about:blank content |
|
11257 // viewer failed for some reason (potentially because the |
|
11258 // user prevented it). Interrupt the history load. |
|
11259 return NS_OK; |
|
11260 } |
|
11261 |
|
11262 if (!owner) { |
|
11263 // Ensure that we have an owner. Otherwise javascript: URIs will |
|
11264 // pick it up from the about:blank page we just loaded, and we |
|
11265 // don't really want even that in this case. |
|
11266 owner = do_CreateInstance("@mozilla.org/nullprincipal;1"); |
|
11267 NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY); |
|
11268 } |
|
11269 } |
|
11270 |
|
11271 /* If there is a valid postdata *and* the user pressed |
|
11272 * reload or shift-reload, take user's permission before we |
|
11273 * repost the data to the server. |
|
11274 */ |
|
11275 if ((aLoadType & LOAD_CMD_RELOAD) && postData) { |
|
11276 bool repost; |
|
11277 rv = ConfirmRepost(&repost); |
|
11278 if (NS_FAILED(rv)) return rv; |
|
11279 |
|
11280 // If the user pressed cancel in the dialog, return. We're done here. |
|
11281 if (!repost) |
|
11282 return NS_BINDING_ABORTED; |
|
11283 } |
|
11284 |
|
11285 // Do not inherit owner from document (security-critical!); |
|
11286 uint32_t flags = INTERNAL_LOAD_FLAGS_NONE; |
|
11287 |
|
11288 nsAutoString srcdoc; |
|
11289 bool isSrcdoc; |
|
11290 nsCOMPtr<nsIURI> baseURI; |
|
11291 aEntry->GetIsSrcdocEntry(&isSrcdoc); |
|
11292 if (isSrcdoc) { |
|
11293 aEntry->GetSrcdocData(srcdoc); |
|
11294 aEntry->GetBaseURI(getter_AddRefs(baseURI)); |
|
11295 flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC; |
|
11296 } |
|
11297 else { |
|
11298 srcdoc = NullString(); |
|
11299 } |
|
11300 |
|
11301 // Passing nullptr as aSourceDocShell gives the same behaviour as before |
|
11302 // aSourceDocShell was introduced. According to spec we should be passing |
|
11303 // the source browsing context that was used when the history entry was |
|
11304 // first created. bug 947716 has been created to address this issue. |
|
11305 rv = InternalLoad(uri, |
|
11306 referrerURI, |
|
11307 owner, |
|
11308 flags, |
|
11309 nullptr, // No window target |
|
11310 contentType.get(), // Type hint |
|
11311 NullString(), // No forced file download |
|
11312 postData, // Post data stream |
|
11313 nullptr, // No headers stream |
|
11314 aLoadType, // Load type |
|
11315 aEntry, // SHEntry |
|
11316 true, |
|
11317 srcdoc, |
|
11318 nullptr, // Source docshell, see comment above |
|
11319 baseURI, |
|
11320 nullptr, // No nsIDocShell |
|
11321 nullptr); // No nsIRequest |
|
11322 return rv; |
|
11323 } |
|
11324 |
|
11325 NS_IMETHODIMP nsDocShell::GetShouldSaveLayoutState(bool* aShould) |
|
11326 { |
|
11327 *aShould = false; |
|
11328 if (mOSHE) { |
|
11329 // Don't capture historystate and save it in history |
|
11330 // if the page asked not to do so. |
|
11331 mOSHE->GetSaveLayoutStateFlag(aShould); |
|
11332 } |
|
11333 |
|
11334 return NS_OK; |
|
11335 } |
|
11336 |
|
11337 NS_IMETHODIMP nsDocShell::PersistLayoutHistoryState() |
|
11338 { |
|
11339 nsresult rv = NS_OK; |
|
11340 |
|
11341 if (mOSHE) { |
|
11342 nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
|
11343 if (shell) { |
|
11344 nsCOMPtr<nsILayoutHistoryState> layoutState; |
|
11345 rv = shell->CaptureHistoryState(getter_AddRefs(layoutState)); |
|
11346 } |
|
11347 } |
|
11348 |
|
11349 return rv; |
|
11350 } |
|
11351 |
|
11352 /* static */ nsresult |
|
11353 nsDocShell::WalkHistoryEntries(nsISHEntry *aRootEntry, |
|
11354 nsDocShell *aRootShell, |
|
11355 WalkHistoryEntriesFunc aCallback, |
|
11356 void *aData) |
|
11357 { |
|
11358 NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE); |
|
11359 |
|
11360 nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry)); |
|
11361 if (!container) |
|
11362 return NS_ERROR_FAILURE; |
|
11363 |
|
11364 int32_t childCount; |
|
11365 container->GetChildCount(&childCount); |
|
11366 for (int32_t i = 0; i < childCount; i++) { |
|
11367 nsCOMPtr<nsISHEntry> childEntry; |
|
11368 container->GetChildAt(i, getter_AddRefs(childEntry)); |
|
11369 if (!childEntry) { |
|
11370 // childEntry can be null for valid reasons, for example if the |
|
11371 // docshell at index i never loaded anything useful. |
|
11372 // Remember to clone also nulls in the child array (bug 464064). |
|
11373 aCallback(nullptr, nullptr, i, aData); |
|
11374 continue; |
|
11375 } |
|
11376 |
|
11377 nsDocShell *childShell = nullptr; |
|
11378 if (aRootShell) { |
|
11379 // Walk the children of aRootShell and see if one of them |
|
11380 // has srcChild as a SHEntry. |
|
11381 |
|
11382 nsTObserverArray<nsDocLoader*>::ForwardIterator iter(aRootShell->mChildList); |
|
11383 while (iter.HasMore()) { |
|
11384 nsDocShell *child = static_cast<nsDocShell*>(iter.GetNext()); |
|
11385 |
|
11386 if (child->HasHistoryEntry(childEntry)) { |
|
11387 childShell = child; |
|
11388 break; |
|
11389 } |
|
11390 } |
|
11391 } |
|
11392 nsresult rv = aCallback(childEntry, childShell, i, aData); |
|
11393 NS_ENSURE_SUCCESS(rv, rv); |
|
11394 } |
|
11395 |
|
11396 return NS_OK; |
|
11397 } |
|
11398 |
|
11399 // callback data for WalkHistoryEntries |
|
11400 struct MOZ_STACK_CLASS CloneAndReplaceData |
|
11401 { |
|
11402 CloneAndReplaceData(uint32_t aCloneID, nsISHEntry *aReplaceEntry, |
|
11403 bool aCloneChildren, nsISHEntry *aDestTreeParent) |
|
11404 : cloneID(aCloneID), |
|
11405 cloneChildren(aCloneChildren), |
|
11406 replaceEntry(aReplaceEntry), |
|
11407 destTreeParent(aDestTreeParent) { } |
|
11408 |
|
11409 uint32_t cloneID; |
|
11410 bool cloneChildren; |
|
11411 nsISHEntry *replaceEntry; |
|
11412 nsISHEntry *destTreeParent; |
|
11413 nsCOMPtr<nsISHEntry> resultEntry; |
|
11414 }; |
|
11415 |
|
11416 /* static */ nsresult |
|
11417 nsDocShell::CloneAndReplaceChild(nsISHEntry *aEntry, nsDocShell *aShell, |
|
11418 int32_t aEntryIndex, void *aData) |
|
11419 { |
|
11420 nsCOMPtr<nsISHEntry> dest; |
|
11421 |
|
11422 CloneAndReplaceData *data = static_cast<CloneAndReplaceData*>(aData); |
|
11423 uint32_t cloneID = data->cloneID; |
|
11424 nsISHEntry *replaceEntry = data->replaceEntry; |
|
11425 |
|
11426 nsCOMPtr<nsISHContainer> container = |
|
11427 do_QueryInterface(data->destTreeParent); |
|
11428 if (!aEntry) { |
|
11429 if (container) { |
|
11430 container->AddChild(nullptr, aEntryIndex); |
|
11431 } |
|
11432 return NS_OK; |
|
11433 } |
|
11434 |
|
11435 uint32_t srcID; |
|
11436 aEntry->GetID(&srcID); |
|
11437 |
|
11438 nsresult rv = NS_OK; |
|
11439 if (srcID == cloneID) { |
|
11440 // Replace the entry |
|
11441 dest = replaceEntry; |
|
11442 } else { |
|
11443 // Clone the SHEntry... |
|
11444 rv = aEntry->Clone(getter_AddRefs(dest)); |
|
11445 NS_ENSURE_SUCCESS(rv, rv); |
|
11446 } |
|
11447 dest->SetIsSubFrame(true); |
|
11448 |
|
11449 if (srcID != cloneID || data->cloneChildren) { |
|
11450 // Walk the children |
|
11451 CloneAndReplaceData childData(cloneID, replaceEntry, |
|
11452 data->cloneChildren, dest); |
|
11453 rv = WalkHistoryEntries(aEntry, aShell, |
|
11454 CloneAndReplaceChild, &childData); |
|
11455 NS_ENSURE_SUCCESS(rv, rv); |
|
11456 } |
|
11457 |
|
11458 if (srcID != cloneID && aShell) { |
|
11459 aShell->SwapHistoryEntries(aEntry, dest); |
|
11460 } |
|
11461 |
|
11462 if (container) |
|
11463 container->AddChild(dest, aEntryIndex); |
|
11464 |
|
11465 data->resultEntry = dest; |
|
11466 return rv; |
|
11467 } |
|
11468 |
|
11469 /* static */ nsresult |
|
11470 nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry, |
|
11471 nsDocShell *aSrcShell, |
|
11472 uint32_t aCloneID, |
|
11473 nsISHEntry *aReplaceEntry, |
|
11474 bool aCloneChildren, |
|
11475 nsISHEntry **aResultEntry) |
|
11476 { |
|
11477 NS_ENSURE_ARG_POINTER(aResultEntry); |
|
11478 NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE); |
|
11479 |
|
11480 CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr); |
|
11481 nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data); |
|
11482 |
|
11483 data.resultEntry.swap(*aResultEntry); |
|
11484 return rv; |
|
11485 } |
|
11486 |
|
11487 void |
|
11488 nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry) |
|
11489 { |
|
11490 if (aOldEntry == mOSHE) |
|
11491 mOSHE = aNewEntry; |
|
11492 |
|
11493 if (aOldEntry == mLSHE) |
|
11494 mLSHE = aNewEntry; |
|
11495 } |
|
11496 |
|
11497 |
|
11498 struct SwapEntriesData |
|
11499 { |
|
11500 nsDocShell *ignoreShell; // constant; the shell to ignore |
|
11501 nsISHEntry *destTreeRoot; // constant; the root of the dest tree |
|
11502 nsISHEntry *destTreeParent; // constant; the node under destTreeRoot |
|
11503 // whose children will correspond to aEntry |
|
11504 }; |
|
11505 |
|
11506 |
|
11507 nsresult |
|
11508 nsDocShell::SetChildHistoryEntry(nsISHEntry *aEntry, nsDocShell *aShell, |
|
11509 int32_t aEntryIndex, void *aData) |
|
11510 { |
|
11511 SwapEntriesData *data = static_cast<SwapEntriesData*>(aData); |
|
11512 nsDocShell *ignoreShell = data->ignoreShell; |
|
11513 |
|
11514 if (!aShell || aShell == ignoreShell) |
|
11515 return NS_OK; |
|
11516 |
|
11517 nsISHEntry *destTreeRoot = data->destTreeRoot; |
|
11518 |
|
11519 nsCOMPtr<nsISHEntry> destEntry; |
|
11520 nsCOMPtr<nsISHContainer> container = |
|
11521 do_QueryInterface(data->destTreeParent); |
|
11522 |
|
11523 if (container) { |
|
11524 // aEntry is a clone of some child of destTreeParent, but since the |
|
11525 // trees aren't necessarily in sync, we'll have to locate it. |
|
11526 // Note that we could set aShell's entry to null if we don't find a |
|
11527 // corresponding entry under destTreeParent. |
|
11528 |
|
11529 uint32_t targetID, id; |
|
11530 aEntry->GetID(&targetID); |
|
11531 |
|
11532 // First look at the given index, since this is the common case. |
|
11533 nsCOMPtr<nsISHEntry> entry; |
|
11534 container->GetChildAt(aEntryIndex, getter_AddRefs(entry)); |
|
11535 if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) { |
|
11536 destEntry.swap(entry); |
|
11537 } else { |
|
11538 int32_t childCount; |
|
11539 container->GetChildCount(&childCount); |
|
11540 for (int32_t i = 0; i < childCount; ++i) { |
|
11541 container->GetChildAt(i, getter_AddRefs(entry)); |
|
11542 if (!entry) |
|
11543 continue; |
|
11544 |
|
11545 entry->GetID(&id); |
|
11546 if (id == targetID) { |
|
11547 destEntry.swap(entry); |
|
11548 break; |
|
11549 } |
|
11550 } |
|
11551 } |
|
11552 } else { |
|
11553 destEntry = destTreeRoot; |
|
11554 } |
|
11555 |
|
11556 aShell->SwapHistoryEntries(aEntry, destEntry); |
|
11557 |
|
11558 // Now handle the children of aEntry. |
|
11559 SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry }; |
|
11560 return WalkHistoryEntries(aEntry, aShell, |
|
11561 SetChildHistoryEntry, &childData); |
|
11562 } |
|
11563 |
|
11564 |
|
11565 static nsISHEntry* |
|
11566 GetRootSHEntry(nsISHEntry *aEntry) |
|
11567 { |
|
11568 nsCOMPtr<nsISHEntry> rootEntry = aEntry; |
|
11569 nsISHEntry *result = nullptr; |
|
11570 while (rootEntry) { |
|
11571 result = rootEntry; |
|
11572 result->GetParent(getter_AddRefs(rootEntry)); |
|
11573 } |
|
11574 |
|
11575 return result; |
|
11576 } |
|
11577 |
|
11578 |
|
11579 void |
|
11580 nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry> *aPtr, nsISHEntry *aEntry) |
|
11581 { |
|
11582 // We need to sync up the docshell and session history trees for |
|
11583 // subframe navigation. If the load was in a subframe, we forward up to |
|
11584 // the root docshell, which will then recursively sync up all docshells |
|
11585 // to their corresponding entries in the new session history tree. |
|
11586 // If we don't do this, then we can cache a content viewer on the wrong |
|
11587 // cloned entry, and subsequently restore it at the wrong time. |
|
11588 |
|
11589 nsISHEntry *newRootEntry = GetRootSHEntry(aEntry); |
|
11590 if (newRootEntry) { |
|
11591 // newRootEntry is now the new root entry. |
|
11592 // Find the old root entry as well. |
|
11593 |
|
11594 // Need a strong ref. on |oldRootEntry| so it isn't destroyed when |
|
11595 // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639). |
|
11596 nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr); |
|
11597 if (oldRootEntry) { |
|
11598 nsCOMPtr<nsIDocShellTreeItem> rootAsItem; |
|
11599 GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); |
|
11600 nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem); |
|
11601 if (rootShell) { // if we're the root just set it, nothing to swap |
|
11602 SwapEntriesData data = { this, newRootEntry }; |
|
11603 nsIDocShell *rootIDocShell = |
|
11604 static_cast<nsIDocShell*>(rootShell); |
|
11605 nsDocShell *rootDocShell = static_cast<nsDocShell*> |
|
11606 (rootIDocShell); |
|
11607 |
|
11608 #ifdef DEBUG |
|
11609 nsresult rv = |
|
11610 #endif |
|
11611 SetChildHistoryEntry(oldRootEntry, rootDocShell, |
|
11612 0, &data); |
|
11613 NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed"); |
|
11614 } |
|
11615 } |
|
11616 } |
|
11617 |
|
11618 *aPtr = aEntry; |
|
11619 } |
|
11620 |
|
11621 |
|
11622 nsresult |
|
11623 nsDocShell::GetRootSessionHistory(nsISHistory ** aReturn) |
|
11624 { |
|
11625 nsresult rv; |
|
11626 |
|
11627 nsCOMPtr<nsIDocShellTreeItem> root; |
|
11628 //Get the root docshell |
|
11629 rv = GetSameTypeRootTreeItem(getter_AddRefs(root)); |
|
11630 // QI to nsIWebNavigation |
|
11631 nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root)); |
|
11632 if (rootAsWebnav) { |
|
11633 // Get the handle to SH from the root docshell |
|
11634 rv = rootAsWebnav->GetSessionHistory(aReturn); |
|
11635 } |
|
11636 return rv; |
|
11637 } |
|
11638 |
|
11639 nsresult |
|
11640 nsDocShell::GetHttpChannel(nsIChannel * aChannel, nsIHttpChannel ** aReturn) |
|
11641 { |
|
11642 NS_ENSURE_ARG_POINTER(aReturn); |
|
11643 if (!aChannel) |
|
11644 return NS_ERROR_FAILURE; |
|
11645 |
|
11646 nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel)); |
|
11647 if (multiPartChannel) { |
|
11648 nsCOMPtr<nsIChannel> baseChannel; |
|
11649 multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel)); |
|
11650 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel)); |
|
11651 *aReturn = httpChannel; |
|
11652 NS_IF_ADDREF(*aReturn); |
|
11653 } |
|
11654 return NS_OK; |
|
11655 } |
|
11656 |
|
11657 bool |
|
11658 nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel * aChannel) |
|
11659 { |
|
11660 // By default layout State will be saved. |
|
11661 if (!aChannel) |
|
11662 return false; |
|
11663 |
|
11664 // figure out if SH should be saving layout state |
|
11665 nsCOMPtr<nsISupports> securityInfo; |
|
11666 bool noStore = false, noCache = false; |
|
11667 aChannel->GetSecurityInfo(getter_AddRefs(securityInfo)); |
|
11668 aChannel->IsNoStoreResponse(&noStore); |
|
11669 aChannel->IsNoCacheResponse(&noCache); |
|
11670 |
|
11671 return (noStore || (noCache && securityInfo)); |
|
11672 } |
|
11673 |
|
11674 NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor) |
|
11675 { |
|
11676 NS_ENSURE_ARG_POINTER(aEditor); |
|
11677 |
|
11678 if (!mEditorData) { |
|
11679 *aEditor = nullptr; |
|
11680 return NS_OK; |
|
11681 } |
|
11682 |
|
11683 return mEditorData->GetEditor(aEditor); |
|
11684 } |
|
11685 |
|
11686 NS_IMETHODIMP nsDocShell::SetEditor(nsIEditor * aEditor) |
|
11687 { |
|
11688 nsresult rv = EnsureEditorData(); |
|
11689 if (NS_FAILED(rv)) return rv; |
|
11690 |
|
11691 return mEditorData->SetEditor(aEditor); |
|
11692 } |
|
11693 |
|
11694 |
|
11695 NS_IMETHODIMP nsDocShell::GetEditable(bool *aEditable) |
|
11696 { |
|
11697 NS_ENSURE_ARG_POINTER(aEditable); |
|
11698 *aEditable = mEditorData && mEditorData->GetEditable(); |
|
11699 return NS_OK; |
|
11700 } |
|
11701 |
|
11702 |
|
11703 NS_IMETHODIMP nsDocShell::GetHasEditingSession(bool *aHasEditingSession) |
|
11704 { |
|
11705 NS_ENSURE_ARG_POINTER(aHasEditingSession); |
|
11706 |
|
11707 if (mEditorData) |
|
11708 { |
|
11709 nsCOMPtr<nsIEditingSession> editingSession; |
|
11710 mEditorData->GetEditingSession(getter_AddRefs(editingSession)); |
|
11711 *aHasEditingSession = (editingSession.get() != nullptr); |
|
11712 } |
|
11713 else |
|
11714 { |
|
11715 *aHasEditingSession = false; |
|
11716 } |
|
11717 |
|
11718 return NS_OK; |
|
11719 } |
|
11720 |
|
11721 NS_IMETHODIMP nsDocShell::MakeEditable(bool inWaitForUriLoad) |
|
11722 { |
|
11723 nsresult rv = EnsureEditorData(); |
|
11724 if (NS_FAILED(rv)) return rv; |
|
11725 |
|
11726 return mEditorData->MakeEditable(inWaitForUriLoad); |
|
11727 } |
|
11728 |
|
11729 bool |
|
11730 nsDocShell::ChannelIsPost(nsIChannel* aChannel) |
|
11731 { |
|
11732 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel)); |
|
11733 if (!httpChannel) { |
|
11734 return false; |
|
11735 } |
|
11736 |
|
11737 nsAutoCString method; |
|
11738 httpChannel->GetRequestMethod(method); |
|
11739 return method.Equals("POST"); |
|
11740 } |
|
11741 |
|
11742 void |
|
11743 nsDocShell::ExtractLastVisit(nsIChannel* aChannel, |
|
11744 nsIURI** aURI, |
|
11745 uint32_t* aChannelRedirectFlags) |
|
11746 { |
|
11747 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel)); |
|
11748 if (!props) { |
|
11749 return; |
|
11750 } |
|
11751 |
|
11752 nsresult rv = props->GetPropertyAsInterface( |
|
11753 NS_LITERAL_STRING("docshell.previousURI"), |
|
11754 NS_GET_IID(nsIURI), |
|
11755 reinterpret_cast<void**>(aURI) |
|
11756 ); |
|
11757 |
|
11758 if (NS_FAILED(rv)) { |
|
11759 // There is no last visit for this channel, so this must be the first |
|
11760 // link. Link the visit to the referrer of this request, if any. |
|
11761 // Treat referrer as null if there is an error getting it. |
|
11762 (void)NS_GetReferrerFromChannel(aChannel, aURI); |
|
11763 } |
|
11764 else { |
|
11765 rv = props->GetPropertyAsUint32( |
|
11766 NS_LITERAL_STRING("docshell.previousFlags"), |
|
11767 aChannelRedirectFlags |
|
11768 ); |
|
11769 |
|
11770 NS_WARN_IF_FALSE( |
|
11771 NS_SUCCEEDED(rv), |
|
11772 "Could not fetch previous flags, URI will be treated like referrer" |
|
11773 ); |
|
11774 } |
|
11775 } |
|
11776 |
|
11777 void |
|
11778 nsDocShell::SaveLastVisit(nsIChannel* aChannel, |
|
11779 nsIURI* aURI, |
|
11780 uint32_t aChannelRedirectFlags) |
|
11781 { |
|
11782 nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel)); |
|
11783 if (!props || !aURI) { |
|
11784 return; |
|
11785 } |
|
11786 |
|
11787 props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"), |
|
11788 aURI); |
|
11789 props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"), |
|
11790 aChannelRedirectFlags); |
|
11791 } |
|
11792 |
|
11793 void |
|
11794 nsDocShell::AddURIVisit(nsIURI* aURI, |
|
11795 nsIURI* aReferrerURI, |
|
11796 nsIURI* aPreviousURI, |
|
11797 uint32_t aChannelRedirectFlags, |
|
11798 uint32_t aResponseStatus) |
|
11799 { |
|
11800 MOZ_ASSERT(aURI, "Visited URI is null!"); |
|
11801 MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE && |
|
11802 mLoadType != LOAD_BYPASS_HISTORY, |
|
11803 "Do not add error or bypass pages to global history"); |
|
11804 |
|
11805 // Only content-type docshells save URI visits. Also don't do |
|
11806 // anything here if we're not supposed to use global history. |
|
11807 if (mItemType != typeContent || !mUseGlobalHistory || mInPrivateBrowsing) { |
|
11808 return; |
|
11809 } |
|
11810 |
|
11811 nsCOMPtr<IHistory> history = services::GetHistoryService(); |
|
11812 |
|
11813 if (history) { |
|
11814 uint32_t visitURIFlags = 0; |
|
11815 |
|
11816 if (!IsFrame()) { |
|
11817 visitURIFlags |= IHistory::TOP_LEVEL; |
|
11818 } |
|
11819 |
|
11820 if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) { |
|
11821 visitURIFlags |= IHistory::REDIRECT_TEMPORARY; |
|
11822 } |
|
11823 else if (aChannelRedirectFlags & |
|
11824 nsIChannelEventSink::REDIRECT_PERMANENT) { |
|
11825 visitURIFlags |= IHistory::REDIRECT_PERMANENT; |
|
11826 } |
|
11827 |
|
11828 if (aResponseStatus >= 300 && aResponseStatus < 400) { |
|
11829 visitURIFlags |= IHistory::REDIRECT_SOURCE; |
|
11830 } |
|
11831 // Errors 400-501 and 505 are considered unrecoverable, in the sense a |
|
11832 // simple retry attempt by the user is unlikely to solve them. |
|
11833 // 408 is special cased, since may actually indicate a temporary |
|
11834 // connection problem. |
|
11835 else if (aResponseStatus != 408 && |
|
11836 ((aResponseStatus >= 400 && aResponseStatus <= 501) || |
|
11837 aResponseStatus == 505)) { |
|
11838 visitURIFlags |= IHistory::UNRECOVERABLE_ERROR; |
|
11839 } |
|
11840 |
|
11841 (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags); |
|
11842 } |
|
11843 else if (mGlobalHistory) { |
|
11844 // Falls back to sync global history interface. |
|
11845 (void)mGlobalHistory->AddURI(aURI, |
|
11846 !!aChannelRedirectFlags, |
|
11847 !IsFrame(), |
|
11848 aReferrerURI); |
|
11849 } |
|
11850 } |
|
11851 |
|
11852 //***************************************************************************** |
|
11853 // nsDocShell: Helper Routines |
|
11854 //***************************************************************************** |
|
11855 |
|
11856 NS_IMETHODIMP |
|
11857 nsDocShell::SetLoadType(uint32_t aLoadType) |
|
11858 { |
|
11859 mLoadType = aLoadType; |
|
11860 return NS_OK; |
|
11861 } |
|
11862 |
|
11863 NS_IMETHODIMP |
|
11864 nsDocShell::GetLoadType(uint32_t * aLoadType) |
|
11865 { |
|
11866 *aLoadType = mLoadType; |
|
11867 return NS_OK; |
|
11868 } |
|
11869 |
|
11870 nsresult |
|
11871 nsDocShell::ConfirmRepost(bool * aRepost) |
|
11872 { |
|
11873 nsCOMPtr<nsIPrompt> prompter; |
|
11874 CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter))); |
|
11875 if (!prompter) { |
|
11876 return NS_ERROR_NOT_AVAILABLE; |
|
11877 } |
|
11878 |
|
11879 nsCOMPtr<nsIStringBundleService> stringBundleService = |
|
11880 mozilla::services::GetStringBundleService(); |
|
11881 if (!stringBundleService) |
|
11882 return NS_ERROR_FAILURE; |
|
11883 |
|
11884 nsCOMPtr<nsIStringBundle> appBundle; |
|
11885 nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL, |
|
11886 getter_AddRefs(appBundle)); |
|
11887 NS_ENSURE_SUCCESS(rv, rv); |
|
11888 |
|
11889 nsCOMPtr<nsIStringBundle> brandBundle; |
|
11890 rv = stringBundleService->CreateBundle(kBrandBundleURL, getter_AddRefs(brandBundle)); |
|
11891 NS_ENSURE_SUCCESS(rv, rv); |
|
11892 |
|
11893 NS_ASSERTION(prompter && brandBundle && appBundle, |
|
11894 "Unable to set up repost prompter."); |
|
11895 |
|
11896 nsXPIDLString brandName; |
|
11897 rv = brandBundle->GetStringFromName(MOZ_UTF16("brandShortName"), |
|
11898 getter_Copies(brandName)); |
|
11899 |
|
11900 nsXPIDLString msgString, button0Title; |
|
11901 if (NS_FAILED(rv)) { // No brand, use the generic version. |
|
11902 rv = appBundle->GetStringFromName(MOZ_UTF16("confirmRepostPrompt"), |
|
11903 getter_Copies(msgString)); |
|
11904 } |
|
11905 else { |
|
11906 // Brand available - if the app has an override file with formatting, the app name will |
|
11907 // be included. Without an override, the prompt will look like the generic version. |
|
11908 const char16_t *formatStrings[] = { brandName.get() }; |
|
11909 rv = appBundle->FormatStringFromName(MOZ_UTF16("confirmRepostPrompt"), |
|
11910 formatStrings, ArrayLength(formatStrings), |
|
11911 getter_Copies(msgString)); |
|
11912 } |
|
11913 if (NS_FAILED(rv)) return rv; |
|
11914 |
|
11915 rv = appBundle->GetStringFromName(MOZ_UTF16("resendButton.label"), |
|
11916 getter_Copies(button0Title)); |
|
11917 if (NS_FAILED(rv)) return rv; |
|
11918 |
|
11919 int32_t buttonPressed; |
|
11920 // The actual value here is irrelevant, but we can't pass an invalid |
|
11921 // bool through XPConnect. |
|
11922 bool checkState = false; |
|
11923 rv = prompter-> |
|
11924 ConfirmEx(nullptr, msgString.get(), |
|
11925 (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) + |
|
11926 (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL), |
|
11927 button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed); |
|
11928 if (NS_FAILED(rv)) return rv; |
|
11929 |
|
11930 *aRepost = (buttonPressed == 0); |
|
11931 return NS_OK; |
|
11932 } |
|
11933 |
|
11934 NS_IMETHODIMP |
|
11935 nsDocShell::GetPromptAndStringBundle(nsIPrompt ** aPrompt, |
|
11936 nsIStringBundle ** aStringBundle) |
|
11937 { |
|
11938 NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void **) aPrompt), |
|
11939 NS_ERROR_FAILURE); |
|
11940 |
|
11941 nsCOMPtr<nsIStringBundleService> stringBundleService = |
|
11942 mozilla::services::GetStringBundleService(); |
|
11943 NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE); |
|
11944 |
|
11945 NS_ENSURE_SUCCESS(stringBundleService-> |
|
11946 CreateBundle(kAppstringsBundleURL, |
|
11947 aStringBundle), |
|
11948 NS_ERROR_FAILURE); |
|
11949 |
|
11950 return NS_OK; |
|
11951 } |
|
11952 |
|
11953 NS_IMETHODIMP |
|
11954 nsDocShell::GetChildOffset(nsIDOMNode * aChild, nsIDOMNode * aParent, |
|
11955 int32_t * aOffset) |
|
11956 { |
|
11957 NS_ENSURE_ARG_POINTER(aChild || aParent); |
|
11958 |
|
11959 nsCOMPtr<nsIDOMNodeList> childNodes; |
|
11960 NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)), |
|
11961 NS_ERROR_FAILURE); |
|
11962 NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE); |
|
11963 |
|
11964 int32_t i = 0; |
|
11965 |
|
11966 for (; true; i++) { |
|
11967 nsCOMPtr<nsIDOMNode> childNode; |
|
11968 NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)), |
|
11969 NS_ERROR_FAILURE); |
|
11970 NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE); |
|
11971 |
|
11972 if (childNode.get() == aChild) { |
|
11973 *aOffset = i; |
|
11974 return NS_OK; |
|
11975 } |
|
11976 } |
|
11977 |
|
11978 return NS_ERROR_FAILURE; |
|
11979 } |
|
11980 |
|
11981 nsIScrollableFrame * |
|
11982 nsDocShell::GetRootScrollFrame() |
|
11983 { |
|
11984 nsCOMPtr<nsIPresShell> shell = GetPresShell(); |
|
11985 NS_ENSURE_TRUE(shell, nullptr); |
|
11986 |
|
11987 return shell->GetRootScrollFrameAsScrollableExternal(); |
|
11988 } |
|
11989 |
|
11990 NS_IMETHODIMP |
|
11991 nsDocShell::EnsureScriptEnvironment() |
|
11992 { |
|
11993 if (mScriptGlobal) |
|
11994 return NS_OK; |
|
11995 |
|
11996 if (mIsBeingDestroyed) { |
|
11997 return NS_ERROR_NOT_AVAILABLE; |
|
11998 } |
|
11999 |
|
12000 #ifdef DEBUG |
|
12001 NS_ASSERTION(!mInEnsureScriptEnv, |
|
12002 "Infinite loop! Calling EnsureScriptEnvironment() from " |
|
12003 "within EnsureScriptEnvironment()!"); |
|
12004 |
|
12005 // Yeah, this isn't re-entrant safe, but that's ok since if we |
|
12006 // re-enter this method, we'll infinitely loop... |
|
12007 AutoRestore<bool> boolSetter(mInEnsureScriptEnv); |
|
12008 mInEnsureScriptEnv = true; |
|
12009 #endif |
|
12010 |
|
12011 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner)); |
|
12012 NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE); |
|
12013 |
|
12014 uint32_t chromeFlags; |
|
12015 browserChrome->GetChromeFlags(&chromeFlags); |
|
12016 |
|
12017 bool isModalContentWindow = (mItemType == typeContent) && |
|
12018 (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW); |
|
12019 // There can be various other content docshells associated with the |
|
12020 // top-level window, like sidebars. Make sure that we only create an |
|
12021 // nsGlobalModalWindow for the primary content shell. |
|
12022 if (isModalContentWindow) { |
|
12023 nsCOMPtr<nsIDocShellTreeItem> primaryItem; |
|
12024 nsresult rv = mTreeOwner->GetPrimaryContentShell(getter_AddRefs(primaryItem)); |
|
12025 NS_ENSURE_SUCCESS(rv, rv); |
|
12026 isModalContentWindow = (primaryItem == this); |
|
12027 } |
|
12028 |
|
12029 // If our window is modal and we're not opened as chrome, make |
|
12030 // this window a modal content window. |
|
12031 mScriptGlobal = |
|
12032 NS_NewScriptGlobalObject(mItemType == typeChrome, isModalContentWindow); |
|
12033 MOZ_ASSERT(mScriptGlobal); |
|
12034 |
|
12035 mScriptGlobal->SetDocShell(this); |
|
12036 |
|
12037 // Ensure the script object is set up to run script. |
|
12038 return mScriptGlobal->EnsureScriptEnvironment(); |
|
12039 } |
|
12040 |
|
12041 |
|
12042 NS_IMETHODIMP |
|
12043 nsDocShell::EnsureEditorData() |
|
12044 { |
|
12045 bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor(); |
|
12046 if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) { |
|
12047 // We shouldn't recreate the editor data if it already exists, or |
|
12048 // we're shutting down, or we already have a detached editor data |
|
12049 // stored in the session history. We should only have one editordata |
|
12050 // per docshell. |
|
12051 mEditorData = new nsDocShellEditorData(this); |
|
12052 } |
|
12053 |
|
12054 return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE; |
|
12055 } |
|
12056 |
|
12057 nsresult |
|
12058 nsDocShell::EnsureTransferableHookData() |
|
12059 { |
|
12060 if (!mTransferableHookData) { |
|
12061 mTransferableHookData = new nsTransferableHookData(); |
|
12062 if (!mTransferableHookData) return NS_ERROR_OUT_OF_MEMORY; |
|
12063 } |
|
12064 |
|
12065 return NS_OK; |
|
12066 } |
|
12067 |
|
12068 |
|
12069 NS_IMETHODIMP nsDocShell::EnsureFind() |
|
12070 { |
|
12071 nsresult rv; |
|
12072 if (!mFind) |
|
12073 { |
|
12074 mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv); |
|
12075 if (NS_FAILED(rv)) return rv; |
|
12076 } |
|
12077 |
|
12078 // we promise that the nsIWebBrowserFind that we return has been set |
|
12079 // up to point to the focused, or content window, so we have to |
|
12080 // set that up each time. |
|
12081 |
|
12082 nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject(); |
|
12083 NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED); |
|
12084 |
|
12085 // default to our window |
|
12086 nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(scriptGO); |
|
12087 nsCOMPtr<nsPIDOMWindow> windowToSearch; |
|
12088 nsFocusManager::GetFocusedDescendant(ourWindow, true, getter_AddRefs(windowToSearch)); |
|
12089 |
|
12090 nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind); |
|
12091 if (!findInFrames) return NS_ERROR_NO_INTERFACE; |
|
12092 |
|
12093 rv = findInFrames->SetRootSearchFrame(ourWindow); |
|
12094 if (NS_FAILED(rv)) return rv; |
|
12095 rv = findInFrames->SetCurrentSearchFrame(windowToSearch); |
|
12096 if (NS_FAILED(rv)) return rv; |
|
12097 |
|
12098 return NS_OK; |
|
12099 } |
|
12100 |
|
12101 bool |
|
12102 nsDocShell::IsFrame() |
|
12103 { |
|
12104 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
12105 GetSameTypeParent(getter_AddRefs(parent)); |
|
12106 return !!parent; |
|
12107 } |
|
12108 |
|
12109 /* boolean IsBeingDestroyed (); */ |
|
12110 NS_IMETHODIMP |
|
12111 nsDocShell::IsBeingDestroyed(bool *aDoomed) |
|
12112 { |
|
12113 NS_ENSURE_ARG(aDoomed); |
|
12114 *aDoomed = mIsBeingDestroyed; |
|
12115 return NS_OK; |
|
12116 } |
|
12117 |
|
12118 |
|
12119 NS_IMETHODIMP |
|
12120 nsDocShell::GetIsExecutingOnLoadHandler(bool *aResult) |
|
12121 { |
|
12122 NS_ENSURE_ARG(aResult); |
|
12123 *aResult = mIsExecutingOnLoadHandler; |
|
12124 return NS_OK; |
|
12125 } |
|
12126 |
|
12127 NS_IMETHODIMP |
|
12128 nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState **aLayoutHistoryState) |
|
12129 { |
|
12130 if (mOSHE) |
|
12131 mOSHE->GetLayoutHistoryState(aLayoutHistoryState); |
|
12132 return NS_OK; |
|
12133 } |
|
12134 |
|
12135 NS_IMETHODIMP |
|
12136 nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState) |
|
12137 { |
|
12138 if (mOSHE) |
|
12139 mOSHE->SetLayoutHistoryState(aLayoutHistoryState); |
|
12140 return NS_OK; |
|
12141 } |
|
12142 |
|
12143 //***************************************************************************** |
|
12144 //*** nsRefreshTimer: Object Management |
|
12145 //***************************************************************************** |
|
12146 |
|
12147 nsRefreshTimer::nsRefreshTimer() |
|
12148 : mDelay(0), mRepeat(false), mMetaRefresh(false) |
|
12149 { |
|
12150 } |
|
12151 |
|
12152 nsRefreshTimer::~nsRefreshTimer() |
|
12153 { |
|
12154 } |
|
12155 |
|
12156 //***************************************************************************** |
|
12157 // nsRefreshTimer::nsISupports |
|
12158 //***************************************************************************** |
|
12159 |
|
12160 NS_IMPL_ADDREF(nsRefreshTimer) |
|
12161 NS_IMPL_RELEASE(nsRefreshTimer) |
|
12162 |
|
12163 NS_INTERFACE_MAP_BEGIN(nsRefreshTimer) |
|
12164 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback) |
|
12165 NS_INTERFACE_MAP_ENTRY(nsITimerCallback) |
|
12166 NS_INTERFACE_MAP_END_THREADSAFE |
|
12167 |
|
12168 ///***************************************************************************** |
|
12169 // nsRefreshTimer::nsITimerCallback |
|
12170 //****************************************************************************** |
|
12171 NS_IMETHODIMP |
|
12172 nsRefreshTimer::Notify(nsITimer * aTimer) |
|
12173 { |
|
12174 NS_ASSERTION(mDocShell, "DocShell is somehow null"); |
|
12175 |
|
12176 if (mDocShell && aTimer) { |
|
12177 // Get the delay count to determine load type |
|
12178 uint32_t delay = 0; |
|
12179 aTimer->GetDelay(&delay); |
|
12180 mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer); |
|
12181 } |
|
12182 return NS_OK; |
|
12183 } |
|
12184 |
|
12185 //***************************************************************************** |
|
12186 // nsDocShell::InterfaceRequestorProxy |
|
12187 //***************************************************************************** |
|
12188 nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(nsIInterfaceRequestor* p) |
|
12189 { |
|
12190 if (p) { |
|
12191 mWeakPtr = do_GetWeakReference(p); |
|
12192 } |
|
12193 } |
|
12194 |
|
12195 nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy() |
|
12196 { |
|
12197 mWeakPtr = nullptr; |
|
12198 } |
|
12199 |
|
12200 NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor) |
|
12201 |
|
12202 NS_IMETHODIMP |
|
12203 nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID & aIID, void **aSink) |
|
12204 { |
|
12205 NS_ENSURE_ARG_POINTER(aSink); |
|
12206 nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr); |
|
12207 if (ifReq) { |
|
12208 return ifReq->GetInterface(aIID, aSink); |
|
12209 } |
|
12210 *aSink = nullptr; |
|
12211 return NS_NOINTERFACE; |
|
12212 } |
|
12213 |
|
12214 nsresult |
|
12215 nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer) |
|
12216 { |
|
12217 if (!aContentViewer) |
|
12218 return NS_ERROR_FAILURE; |
|
12219 |
|
12220 nsCOMPtr<nsIURI> baseURI; |
|
12221 nsresult rv = NS_ERROR_NOT_AVAILABLE; |
|
12222 |
|
12223 if (sURIFixup) |
|
12224 rv = sURIFixup->CreateExposableURI(mCurrentURI, |
|
12225 getter_AddRefs(baseURI)); |
|
12226 |
|
12227 // Get the current document and set the base uri |
|
12228 if (baseURI) { |
|
12229 nsIDocument* document = aContentViewer->GetDocument(); |
|
12230 if (document) { |
|
12231 rv = document->SetBaseURI(baseURI); |
|
12232 } |
|
12233 } |
|
12234 return rv; |
|
12235 } |
|
12236 |
|
12237 //***************************************************************************** |
|
12238 // nsDocShell::nsIAuthPromptProvider |
|
12239 //***************************************************************************** |
|
12240 |
|
12241 NS_IMETHODIMP |
|
12242 nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid, |
|
12243 void** aResult) |
|
12244 { |
|
12245 // a priority prompt request will override a false mAllowAuth setting |
|
12246 bool priorityPrompt = (aPromptReason == PROMPT_PROXY); |
|
12247 |
|
12248 if (!mAllowAuth && !priorityPrompt) |
|
12249 return NS_ERROR_NOT_AVAILABLE; |
|
12250 |
|
12251 // we're either allowing auth, or it's a proxy request |
|
12252 nsresult rv; |
|
12253 nsCOMPtr<nsIPromptFactory> wwatch = |
|
12254 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); |
|
12255 NS_ENSURE_SUCCESS(rv, rv); |
|
12256 |
|
12257 rv = EnsureScriptEnvironment(); |
|
12258 NS_ENSURE_SUCCESS(rv, rv); |
|
12259 |
|
12260 // Get the an auth prompter for our window so that the parenting |
|
12261 // of the dialogs works as it should when using tabs. |
|
12262 |
|
12263 return wwatch->GetPrompt(mScriptGlobal, iid, |
|
12264 reinterpret_cast<void**>(aResult)); |
|
12265 } |
|
12266 |
|
12267 //***************************************************************************** |
|
12268 // nsDocShell::nsILoadContext |
|
12269 //***************************************************************************** |
|
12270 NS_IMETHODIMP |
|
12271 nsDocShell::GetAssociatedWindow(nsIDOMWindow** aWindow) |
|
12272 { |
|
12273 CallGetInterface(this, aWindow); |
|
12274 return NS_OK; |
|
12275 } |
|
12276 |
|
12277 NS_IMETHODIMP |
|
12278 nsDocShell::GetTopWindow(nsIDOMWindow** aWindow) |
|
12279 { |
|
12280 nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this)); |
|
12281 if (win) { |
|
12282 win->GetTop(aWindow); |
|
12283 } |
|
12284 return NS_OK; |
|
12285 } |
|
12286 |
|
12287 NS_IMETHODIMP |
|
12288 nsDocShell::GetTopFrameElement(nsIDOMElement** aElement) |
|
12289 { |
|
12290 *aElement = nullptr; |
|
12291 nsCOMPtr<nsIDOMWindow> win = do_GetInterface(GetAsSupports(this)); |
|
12292 if (!win) { |
|
12293 return NS_OK; |
|
12294 } |
|
12295 |
|
12296 nsCOMPtr<nsIDOMWindow> top; |
|
12297 win->GetScriptableTop(getter_AddRefs(top)); |
|
12298 NS_ENSURE_TRUE(top, NS_ERROR_FAILURE); |
|
12299 |
|
12300 // GetFrameElement, /not/ GetScriptableFrameElement -- if |top| is inside |
|
12301 // <iframe mozbrowser>, we want to return the iframe, not null. |
|
12302 return top->GetFrameElement(aElement); |
|
12303 } |
|
12304 |
|
12305 NS_IMETHODIMP |
|
12306 nsDocShell::IsAppOfType(uint32_t aAppType, bool *aIsOfType) |
|
12307 { |
|
12308 nsCOMPtr<nsIDocShell> shell = this; |
|
12309 while (shell) { |
|
12310 uint32_t type; |
|
12311 shell->GetAppType(&type); |
|
12312 if (type == aAppType) { |
|
12313 *aIsOfType = true; |
|
12314 return NS_OK; |
|
12315 } |
|
12316 nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(shell); |
|
12317 nsCOMPtr<nsIDocShellTreeItem> parent; |
|
12318 item->GetParent(getter_AddRefs(parent)); |
|
12319 shell = do_QueryInterface(parent); |
|
12320 } |
|
12321 |
|
12322 *aIsOfType = false; |
|
12323 return NS_OK; |
|
12324 } |
|
12325 |
|
12326 NS_IMETHODIMP |
|
12327 nsDocShell::GetIsContent(bool *aIsContent) |
|
12328 { |
|
12329 *aIsContent = (mItemType == typeContent); |
|
12330 return NS_OK; |
|
12331 } |
|
12332 |
|
12333 bool |
|
12334 nsDocShell::IsOKToLoadURI(nsIURI* aURI) |
|
12335 { |
|
12336 NS_PRECONDITION(aURI, "Must have a URI!"); |
|
12337 |
|
12338 if (!mFiredUnloadEvent) { |
|
12339 return true; |
|
12340 } |
|
12341 |
|
12342 if (!mLoadingURI) { |
|
12343 return false; |
|
12344 } |
|
12345 |
|
12346 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
12347 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
12348 return |
|
12349 secMan && |
|
12350 NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false)); |
|
12351 } |
|
12352 |
|
12353 // |
|
12354 // Routines for selection and clipboard |
|
12355 // |
|
12356 nsresult |
|
12357 nsDocShell::GetControllerForCommand(const char * inCommand, |
|
12358 nsIController** outController) |
|
12359 { |
|
12360 NS_ENSURE_ARG_POINTER(outController); |
|
12361 *outController = nullptr; |
|
12362 |
|
12363 NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE); |
|
12364 |
|
12365 nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot(); |
|
12366 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); |
|
12367 |
|
12368 return root->GetControllerForCommand(inCommand, outController); |
|
12369 } |
|
12370 |
|
12371 NS_IMETHODIMP |
|
12372 nsDocShell::IsCommandEnabled(const char * inCommand, bool* outEnabled) |
|
12373 { |
|
12374 NS_ENSURE_ARG_POINTER(outEnabled); |
|
12375 *outEnabled = false; |
|
12376 |
|
12377 nsresult rv = NS_ERROR_FAILURE; |
|
12378 |
|
12379 nsCOMPtr<nsIController> controller; |
|
12380 rv = GetControllerForCommand (inCommand, getter_AddRefs(controller)); |
|
12381 if (controller) |
|
12382 rv = controller->IsCommandEnabled(inCommand, outEnabled); |
|
12383 |
|
12384 return rv; |
|
12385 } |
|
12386 |
|
12387 NS_IMETHODIMP |
|
12388 nsDocShell::DoCommand(const char * inCommand) |
|
12389 { |
|
12390 nsresult rv = NS_ERROR_FAILURE; |
|
12391 |
|
12392 nsCOMPtr<nsIController> controller; |
|
12393 rv = GetControllerForCommand(inCommand, getter_AddRefs(controller)); |
|
12394 if (controller) |
|
12395 rv = controller->DoCommand(inCommand); |
|
12396 |
|
12397 return rv; |
|
12398 } |
|
12399 |
|
12400 nsresult |
|
12401 nsDocShell::EnsureCommandHandler() |
|
12402 { |
|
12403 if (!mCommandManager) |
|
12404 { |
|
12405 nsCOMPtr<nsPICommandUpdater> commandUpdater = |
|
12406 do_CreateInstance("@mozilla.org/embedcomp/command-manager;1"); |
|
12407 if (!commandUpdater) return NS_ERROR_OUT_OF_MEMORY; |
|
12408 |
|
12409 nsCOMPtr<nsIDOMWindow> domWindow = |
|
12410 do_GetInterface(static_cast<nsIInterfaceRequestor *>(this)); |
|
12411 |
|
12412 nsresult rv = commandUpdater->Init(domWindow); |
|
12413 if (NS_SUCCEEDED(rv)) |
|
12414 mCommandManager = do_QueryInterface(commandUpdater); |
|
12415 } |
|
12416 |
|
12417 return mCommandManager ? NS_OK : NS_ERROR_FAILURE; |
|
12418 } |
|
12419 |
|
12420 NS_IMETHODIMP |
|
12421 nsDocShell::CanCutSelection(bool* aResult) |
|
12422 { |
|
12423 return IsCommandEnabled("cmd_cut", aResult); |
|
12424 } |
|
12425 |
|
12426 NS_IMETHODIMP |
|
12427 nsDocShell::CanCopySelection(bool* aResult) |
|
12428 { |
|
12429 return IsCommandEnabled("cmd_copy", aResult); |
|
12430 } |
|
12431 |
|
12432 NS_IMETHODIMP |
|
12433 nsDocShell::CanCopyLinkLocation(bool* aResult) |
|
12434 { |
|
12435 return IsCommandEnabled("cmd_copyLink", aResult); |
|
12436 } |
|
12437 |
|
12438 NS_IMETHODIMP |
|
12439 nsDocShell::CanCopyImageLocation(bool* aResult) |
|
12440 { |
|
12441 return IsCommandEnabled("cmd_copyImageLocation", |
|
12442 aResult); |
|
12443 } |
|
12444 |
|
12445 NS_IMETHODIMP |
|
12446 nsDocShell::CanCopyImageContents(bool* aResult) |
|
12447 { |
|
12448 return IsCommandEnabled("cmd_copyImageContents", |
|
12449 aResult); |
|
12450 } |
|
12451 |
|
12452 NS_IMETHODIMP |
|
12453 nsDocShell::CanPaste(bool* aResult) |
|
12454 { |
|
12455 return IsCommandEnabled("cmd_paste", aResult); |
|
12456 } |
|
12457 |
|
12458 NS_IMETHODIMP |
|
12459 nsDocShell::CutSelection(void) |
|
12460 { |
|
12461 return DoCommand ( "cmd_cut" ); |
|
12462 } |
|
12463 |
|
12464 NS_IMETHODIMP |
|
12465 nsDocShell::CopySelection(void) |
|
12466 { |
|
12467 return DoCommand ( "cmd_copy" ); |
|
12468 } |
|
12469 |
|
12470 NS_IMETHODIMP |
|
12471 nsDocShell::CopyLinkLocation(void) |
|
12472 { |
|
12473 return DoCommand ( "cmd_copyLink" ); |
|
12474 } |
|
12475 |
|
12476 NS_IMETHODIMP |
|
12477 nsDocShell::CopyImageLocation(void) |
|
12478 { |
|
12479 return DoCommand ( "cmd_copyImageLocation" ); |
|
12480 } |
|
12481 |
|
12482 NS_IMETHODIMP |
|
12483 nsDocShell::CopyImageContents(void) |
|
12484 { |
|
12485 return DoCommand ( "cmd_copyImageContents" ); |
|
12486 } |
|
12487 |
|
12488 NS_IMETHODIMP |
|
12489 nsDocShell::Paste(void) |
|
12490 { |
|
12491 return DoCommand ( "cmd_paste" ); |
|
12492 } |
|
12493 |
|
12494 NS_IMETHODIMP |
|
12495 nsDocShell::SelectAll(void) |
|
12496 { |
|
12497 return DoCommand ( "cmd_selectAll" ); |
|
12498 } |
|
12499 |
|
12500 // |
|
12501 // SelectNone |
|
12502 // |
|
12503 // Collapses the current selection, insertion point ends up at beginning |
|
12504 // of previous selection. |
|
12505 // |
|
12506 NS_IMETHODIMP |
|
12507 nsDocShell::SelectNone(void) |
|
12508 { |
|
12509 return DoCommand ( "cmd_selectNone" ); |
|
12510 } |
|
12511 |
|
12512 //---------------------------------------------------------------------- |
|
12513 |
|
12514 // link handling |
|
12515 |
|
12516 class OnLinkClickEvent : public nsRunnable { |
|
12517 public: |
|
12518 OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, |
|
12519 nsIURI* aURI, |
|
12520 const char16_t* aTargetSpec, |
|
12521 const nsAString& aFileName, |
|
12522 nsIInputStream* aPostDataStream, |
|
12523 nsIInputStream* aHeadersDataStream, |
|
12524 bool aIsTrusted); |
|
12525 |
|
12526 NS_IMETHOD Run() { |
|
12527 nsAutoPopupStatePusher popupStatePusher(mPopupState); |
|
12528 |
|
12529 nsCxPusher pusher; |
|
12530 if (mIsTrusted || pusher.Push(mContent)) { |
|
12531 mHandler->OnLinkClickSync(mContent, mURI, |
|
12532 mTargetSpec.get(), mFileName, |
|
12533 mPostDataStream, mHeadersDataStream, |
|
12534 nullptr, nullptr); |
|
12535 } |
|
12536 return NS_OK; |
|
12537 } |
|
12538 |
|
12539 private: |
|
12540 nsRefPtr<nsDocShell> mHandler; |
|
12541 nsCOMPtr<nsIURI> mURI; |
|
12542 nsString mTargetSpec; |
|
12543 nsString mFileName; |
|
12544 nsCOMPtr<nsIInputStream> mPostDataStream; |
|
12545 nsCOMPtr<nsIInputStream> mHeadersDataStream; |
|
12546 nsCOMPtr<nsIContent> mContent; |
|
12547 PopupControlState mPopupState; |
|
12548 bool mIsTrusted; |
|
12549 }; |
|
12550 |
|
12551 OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, |
|
12552 nsIContent *aContent, |
|
12553 nsIURI* aURI, |
|
12554 const char16_t* aTargetSpec, |
|
12555 const nsAString& aFileName, |
|
12556 nsIInputStream* aPostDataStream, |
|
12557 nsIInputStream* aHeadersDataStream, |
|
12558 bool aIsTrusted) |
|
12559 : mHandler(aHandler) |
|
12560 , mURI(aURI) |
|
12561 , mTargetSpec(aTargetSpec) |
|
12562 , mFileName(aFileName) |
|
12563 , mPostDataStream(aPostDataStream) |
|
12564 , mHeadersDataStream(aHeadersDataStream) |
|
12565 , mContent(aContent) |
|
12566 , mPopupState(mHandler->mScriptGlobal->GetPopupControlState()) |
|
12567 , mIsTrusted(aIsTrusted) |
|
12568 { |
|
12569 } |
|
12570 |
|
12571 //---------------------------------------- |
|
12572 |
|
12573 NS_IMETHODIMP |
|
12574 nsDocShell::OnLinkClick(nsIContent* aContent, |
|
12575 nsIURI* aURI, |
|
12576 const char16_t* aTargetSpec, |
|
12577 const nsAString& aFileName, |
|
12578 nsIInputStream* aPostDataStream, |
|
12579 nsIInputStream* aHeadersDataStream, |
|
12580 bool aIsTrusted) |
|
12581 { |
|
12582 NS_ASSERTION(NS_IsMainThread(), "wrong thread"); |
|
12583 |
|
12584 if (!IsOKToLoadURI(aURI)) { |
|
12585 return NS_OK; |
|
12586 } |
|
12587 |
|
12588 // On history navigation through Back/Forward buttons, don't execute |
|
12589 // automatic JavaScript redirection such as |anchorElement.click()| or |
|
12590 // |formElement.submit()|. |
|
12591 // |
|
12592 // XXX |formElement.submit()| bypasses this checkpoint because it calls |
|
12593 // nsDocShell::OnLinkClickSync(...) instead. |
|
12594 if (ShouldBlockLoadingForBackButton()) { |
|
12595 return NS_OK; |
|
12596 } |
|
12597 |
|
12598 if (aContent->IsEditable()) { |
|
12599 return NS_OK; |
|
12600 } |
|
12601 |
|
12602 nsresult rv = NS_ERROR_FAILURE; |
|
12603 nsAutoString target; |
|
12604 |
|
12605 nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner); |
|
12606 if (browserChrome3) { |
|
12607 nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent); |
|
12608 nsAutoString oldTarget(aTargetSpec); |
|
12609 rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI, |
|
12610 linkNode, mIsAppTab, target); |
|
12611 } |
|
12612 |
|
12613 if (NS_FAILED(rv)) |
|
12614 target = aTargetSpec; |
|
12615 |
|
12616 nsCOMPtr<nsIRunnable> ev = |
|
12617 new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName, |
|
12618 aPostDataStream, aHeadersDataStream, aIsTrusted); |
|
12619 return NS_DispatchToCurrentThread(ev); |
|
12620 } |
|
12621 |
|
12622 NS_IMETHODIMP |
|
12623 nsDocShell::OnLinkClickSync(nsIContent *aContent, |
|
12624 nsIURI* aURI, |
|
12625 const char16_t* aTargetSpec, |
|
12626 const nsAString& aFileName, |
|
12627 nsIInputStream* aPostDataStream, |
|
12628 nsIInputStream* aHeadersDataStream, |
|
12629 nsIDocShell** aDocShell, |
|
12630 nsIRequest** aRequest) |
|
12631 { |
|
12632 // Initialize the DocShell / Request |
|
12633 if (aDocShell) { |
|
12634 *aDocShell = nullptr; |
|
12635 } |
|
12636 if (aRequest) { |
|
12637 *aRequest = nullptr; |
|
12638 } |
|
12639 |
|
12640 if (!IsOKToLoadURI(aURI)) { |
|
12641 return NS_OK; |
|
12642 } |
|
12643 |
|
12644 // XXX When the linking node was HTMLFormElement, it is synchronous event. |
|
12645 // That is, the caller of this method is not |OnLinkClickEvent::Run()| |
|
12646 // but |HTMLFormElement::SubmitSubmission(...)|. |
|
12647 if (nsGkAtoms::form == aContent->Tag() && ShouldBlockLoadingForBackButton()) { |
|
12648 return NS_OK; |
|
12649 } |
|
12650 |
|
12651 if (aContent->IsEditable()) { |
|
12652 return NS_OK; |
|
12653 } |
|
12654 |
|
12655 { |
|
12656 // defer to an external protocol handler if necessary... |
|
12657 nsCOMPtr<nsIExternalProtocolService> extProtService = |
|
12658 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID); |
|
12659 if (extProtService) { |
|
12660 nsAutoCString scheme; |
|
12661 aURI->GetScheme(scheme); |
|
12662 if (!scheme.IsEmpty()) { |
|
12663 // if the URL scheme does not correspond to an exposed protocol, then we |
|
12664 // need to hand this link click over to the external protocol handler. |
|
12665 bool isExposed; |
|
12666 nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed); |
|
12667 if (NS_SUCCEEDED(rv) && !isExposed) { |
|
12668 return extProtService->LoadURI(aURI, this); |
|
12669 } |
|
12670 } |
|
12671 } |
|
12672 } |
|
12673 |
|
12674 // Get the owner document of the link that was clicked, this will be |
|
12675 // the document that the link is in, or the last document that the |
|
12676 // link was in. From that document, we'll get the URI to use as the |
|
12677 // referer, since the current URI in this docshell may be a |
|
12678 // new document that we're in the process of loading. |
|
12679 nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc(); |
|
12680 NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED); |
|
12681 |
|
12682 // Now check that the refererDoc's inner window is the current inner |
|
12683 // window for mScriptGlobal. If it's not, then we don't want to |
|
12684 // follow this link. |
|
12685 nsPIDOMWindow* refererInner = refererDoc->GetInnerWindow(); |
|
12686 NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED); |
|
12687 if (!mScriptGlobal || |
|
12688 mScriptGlobal->GetCurrentInnerWindow() != refererInner) { |
|
12689 // We're no longer the current inner window |
|
12690 return NS_OK; |
|
12691 } |
|
12692 |
|
12693 nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI(); |
|
12694 |
|
12695 // referer could be null here in some odd cases, but that's ok, |
|
12696 // we'll just load the link w/o sending a referer in those cases. |
|
12697 |
|
12698 nsAutoString target(aTargetSpec); |
|
12699 |
|
12700 // If this is an anchor element, grab its type property to use as a hint |
|
12701 nsAutoString typeHint; |
|
12702 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent)); |
|
12703 if (anchor) { |
|
12704 anchor->GetType(typeHint); |
|
12705 NS_ConvertUTF16toUTF8 utf8Hint(typeHint); |
|
12706 nsAutoCString type, dummy; |
|
12707 NS_ParseContentType(utf8Hint, type, dummy); |
|
12708 CopyUTF8toUTF16(type, typeHint); |
|
12709 } |
|
12710 |
|
12711 // Clone the URI now, in case a content policy or something messes |
|
12712 // with it under InternalLoad; we do _not_ want to change the URI |
|
12713 // our caller passed in. |
|
12714 nsCOMPtr<nsIURI> clonedURI; |
|
12715 aURI->Clone(getter_AddRefs(clonedURI)); |
|
12716 if (!clonedURI) { |
|
12717 return NS_ERROR_OUT_OF_MEMORY; |
|
12718 } |
|
12719 |
|
12720 nsresult rv = InternalLoad(clonedURI, // New URI |
|
12721 referer, // Referer URI |
|
12722 aContent->NodePrincipal(), // Owner is our node's |
|
12723 // principal |
|
12724 INTERNAL_LOAD_FLAGS_NONE, |
|
12725 target.get(), // Window target |
|
12726 NS_LossyConvertUTF16toASCII(typeHint).get(), |
|
12727 aFileName, // Download as file |
|
12728 aPostDataStream, // Post data stream |
|
12729 aHeadersDataStream, // Headers stream |
|
12730 LOAD_LINK, // Load type |
|
12731 nullptr, // No SHEntry |
|
12732 true, // first party site |
|
12733 NullString(), // No srcdoc |
|
12734 this, // We are the source |
|
12735 nullptr, // baseURI not needed |
|
12736 aDocShell, // DocShell out-param |
|
12737 aRequest); // Request out-param |
|
12738 if (NS_SUCCEEDED(rv)) { |
|
12739 DispatchPings(aContent, aURI, referer); |
|
12740 } |
|
12741 return rv; |
|
12742 } |
|
12743 |
|
12744 NS_IMETHODIMP |
|
12745 nsDocShell::OnOverLink(nsIContent* aContent, |
|
12746 nsIURI* aURI, |
|
12747 const char16_t* aTargetSpec) |
|
12748 { |
|
12749 if (aContent->IsEditable()) { |
|
12750 return NS_OK; |
|
12751 } |
|
12752 |
|
12753 nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner); |
|
12754 nsresult rv = NS_ERROR_FAILURE; |
|
12755 |
|
12756 nsCOMPtr<nsIWebBrowserChrome> browserChrome; |
|
12757 if (!browserChrome2) { |
|
12758 browserChrome = do_GetInterface(mTreeOwner); |
|
12759 if (!browserChrome) |
|
12760 return rv; |
|
12761 } |
|
12762 |
|
12763 nsCOMPtr<nsITextToSubURI> textToSubURI = |
|
12764 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); |
|
12765 if (NS_FAILED(rv)) |
|
12766 return rv; |
|
12767 |
|
12768 // use url origin charset to unescape the URL |
|
12769 nsAutoCString charset; |
|
12770 rv = aURI->GetOriginCharset(charset); |
|
12771 NS_ENSURE_SUCCESS(rv, rv); |
|
12772 |
|
12773 nsAutoCString spec; |
|
12774 rv = aURI->GetSpec(spec); |
|
12775 NS_ENSURE_SUCCESS(rv, rv); |
|
12776 |
|
12777 nsAutoString uStr; |
|
12778 rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr); |
|
12779 NS_ENSURE_SUCCESS(rv, rv); |
|
12780 |
|
12781 mozilla::net::SeerPredict(aURI, mCurrentURI, nsINetworkSeer::PREDICT_LINK, |
|
12782 this, nullptr); |
|
12783 |
|
12784 if (browserChrome2) { |
|
12785 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent); |
|
12786 rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK, |
|
12787 uStr, element); |
|
12788 } else { |
|
12789 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get()); |
|
12790 } |
|
12791 return rv; |
|
12792 } |
|
12793 |
|
12794 NS_IMETHODIMP |
|
12795 nsDocShell::OnLeaveLink() |
|
12796 { |
|
12797 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner)); |
|
12798 nsresult rv = NS_ERROR_FAILURE; |
|
12799 |
|
12800 if (browserChrome) { |
|
12801 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, |
|
12802 EmptyString().get()); |
|
12803 } |
|
12804 return rv; |
|
12805 } |
|
12806 |
|
12807 bool |
|
12808 nsDocShell::ShouldBlockLoadingForBackButton() |
|
12809 { |
|
12810 if (!(mLoadType & LOAD_CMD_HISTORY) || |
|
12811 EventStateManager::IsHandlingUserInput() || |
|
12812 !Preferences::GetBool("accessibility.blockjsredirection")) { |
|
12813 return false; |
|
12814 } |
|
12815 |
|
12816 bool canGoForward = false; |
|
12817 GetCanGoForward(&canGoForward); |
|
12818 return canGoForward; |
|
12819 } |
|
12820 |
|
12821 bool |
|
12822 nsDocShell::PluginsAllowedInCurrentDoc() |
|
12823 { |
|
12824 bool pluginsAllowed = false; |
|
12825 |
|
12826 if (!mContentViewer) { |
|
12827 return false; |
|
12828 } |
|
12829 |
|
12830 nsIDocument* doc = mContentViewer->GetDocument(); |
|
12831 if (!doc) { |
|
12832 return false; |
|
12833 } |
|
12834 |
|
12835 doc->GetAllowPlugins(&pluginsAllowed); |
|
12836 return pluginsAllowed; |
|
12837 } |
|
12838 |
|
12839 //---------------------------------------------------------------------- |
|
12840 // Web Shell Services API |
|
12841 |
|
12842 //This functions is only called when a new charset is detected in loading a document. |
|
12843 //Its name should be changed to "CharsetReloadDocument" |
|
12844 NS_IMETHODIMP |
|
12845 nsDocShell::ReloadDocument(const char* aCharset, |
|
12846 int32_t aSource) |
|
12847 { |
|
12848 |
|
12849 // XXX hack. keep the aCharset and aSource wait to pick it up |
|
12850 nsCOMPtr<nsIContentViewer> cv; |
|
12851 NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE); |
|
12852 if (cv) |
|
12853 { |
|
12854 nsCOMPtr<nsIMarkupDocumentViewer> muDV = do_QueryInterface(cv); |
|
12855 if (muDV) |
|
12856 { |
|
12857 int32_t hint; |
|
12858 muDV->GetHintCharacterSetSource(&hint); |
|
12859 if (aSource > hint) |
|
12860 { |
|
12861 nsCString charset(aCharset); |
|
12862 muDV->SetHintCharacterSet(charset); |
|
12863 muDV->SetHintCharacterSetSource(aSource); |
|
12864 if(eCharsetReloadRequested != mCharsetReloadState) |
|
12865 { |
|
12866 mCharsetReloadState = eCharsetReloadRequested; |
|
12867 return Reload(LOAD_FLAGS_CHARSET_CHANGE); |
|
12868 } |
|
12869 } |
|
12870 } |
|
12871 } |
|
12872 //return failure if this request is not accepted due to mCharsetReloadState |
|
12873 return NS_ERROR_DOCSHELL_REQUEST_REJECTED; |
|
12874 } |
|
12875 |
|
12876 |
|
12877 NS_IMETHODIMP |
|
12878 nsDocShell::StopDocumentLoad(void) |
|
12879 { |
|
12880 if(eCharsetReloadRequested != mCharsetReloadState) |
|
12881 { |
|
12882 Stop(nsIWebNavigation::STOP_ALL); |
|
12883 return NS_OK; |
|
12884 } |
|
12885 //return failer if this request is not accepted due to mCharsetReloadState |
|
12886 return NS_ERROR_DOCSHELL_REQUEST_REJECTED; |
|
12887 } |
|
12888 |
|
12889 NS_IMETHODIMP |
|
12890 nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview) |
|
12891 { |
|
12892 *aPrintPreview = nullptr; |
|
12893 #if NS_PRINT_PREVIEW |
|
12894 nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer); |
|
12895 if (!print || !print->IsInitializedForPrintPreview()) { |
|
12896 Stop(nsIWebNavigation::STOP_ALL); |
|
12897 nsCOMPtr<nsIPrincipal> principal = |
|
12898 do_CreateInstance("@mozilla.org/nullprincipal;1"); |
|
12899 NS_ENSURE_STATE(principal); |
|
12900 nsresult rv = CreateAboutBlankContentViewer(principal, nullptr); |
|
12901 NS_ENSURE_SUCCESS(rv, rv); |
|
12902 print = do_QueryInterface(mContentViewer); |
|
12903 NS_ENSURE_STATE(print); |
|
12904 print->InitializeForPrintPreview(); |
|
12905 } |
|
12906 nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print); |
|
12907 result.forget(aPrintPreview); |
|
12908 return NS_OK; |
|
12909 #else |
|
12910 return NS_ERROR_NOT_IMPLEMENTED; |
|
12911 #endif |
|
12912 } |
|
12913 |
|
12914 |
|
12915 #ifdef DEBUG |
|
12916 unsigned long nsDocShell::gNumberOfDocShells = 0; |
|
12917 #endif |
|
12918 |
|
12919 NS_IMETHODIMP |
|
12920 nsDocShell::GetCanExecuteScripts(bool *aResult) |
|
12921 { |
|
12922 *aResult = mCanExecuteScripts; |
|
12923 return NS_OK; |
|
12924 } |
|
12925 |
|
12926 NS_IMETHODIMP |
|
12927 nsDocShell::SetIsApp(uint32_t aOwnAppId) |
|
12928 { |
|
12929 mOwnOrContainingAppId = aOwnAppId; |
|
12930 if (aOwnAppId != nsIScriptSecurityManager::NO_APP_ID && |
|
12931 aOwnAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
12932 mFrameType = eFrameTypeApp; |
|
12933 } else { |
|
12934 mFrameType = eFrameTypeRegular; |
|
12935 } |
|
12936 |
|
12937 return NS_OK; |
|
12938 } |
|
12939 |
|
12940 NS_IMETHODIMP |
|
12941 nsDocShell::SetIsBrowserInsideApp(uint32_t aContainingAppId) |
|
12942 { |
|
12943 mOwnOrContainingAppId = aContainingAppId; |
|
12944 mFrameType = eFrameTypeBrowser; |
|
12945 return NS_OK; |
|
12946 } |
|
12947 |
|
12948 /* [infallible] */ NS_IMETHODIMP |
|
12949 nsDocShell::GetIsBrowserElement(bool* aIsBrowser) |
|
12950 { |
|
12951 *aIsBrowser = (mFrameType == eFrameTypeBrowser); |
|
12952 return NS_OK; |
|
12953 } |
|
12954 |
|
12955 /* [infallible] */ NS_IMETHODIMP |
|
12956 nsDocShell::GetIsApp(bool* aIsApp) |
|
12957 { |
|
12958 *aIsApp = (mFrameType == eFrameTypeApp); |
|
12959 return NS_OK; |
|
12960 } |
|
12961 |
|
12962 /* [infallible] */ NS_IMETHODIMP |
|
12963 nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp) |
|
12964 { |
|
12965 switch (mFrameType) { |
|
12966 case eFrameTypeRegular: |
|
12967 *aIsBrowserOrApp = false; |
|
12968 break; |
|
12969 case eFrameTypeBrowser: |
|
12970 case eFrameTypeApp: |
|
12971 *aIsBrowserOrApp = true; |
|
12972 break; |
|
12973 } |
|
12974 |
|
12975 return NS_OK; |
|
12976 } |
|
12977 |
|
12978 nsDocShell::FrameType |
|
12979 nsDocShell::GetInheritedFrameType() |
|
12980 { |
|
12981 if (mFrameType != eFrameTypeRegular) { |
|
12982 return mFrameType; |
|
12983 } |
|
12984 |
|
12985 nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
|
12986 GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
12987 |
|
12988 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem); |
|
12989 if (!parent) { |
|
12990 return eFrameTypeRegular; |
|
12991 } |
|
12992 |
|
12993 return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType(); |
|
12994 } |
|
12995 |
|
12996 /* [infallible] */ NS_IMETHODIMP |
|
12997 nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement) |
|
12998 { |
|
12999 *aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser); |
|
13000 return NS_OK; |
|
13001 } |
|
13002 |
|
13003 /* [infallible] */ NS_IMETHODIMP |
|
13004 nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp) |
|
13005 { |
|
13006 switch (GetInheritedFrameType()) { |
|
13007 case eFrameTypeRegular: |
|
13008 *aIsInBrowserOrApp = false; |
|
13009 break; |
|
13010 case eFrameTypeBrowser: |
|
13011 case eFrameTypeApp: |
|
13012 *aIsInBrowserOrApp = true; |
|
13013 break; |
|
13014 } |
|
13015 |
|
13016 return NS_OK; |
|
13017 } |
|
13018 |
|
13019 /* [infallible] */ NS_IMETHODIMP |
|
13020 nsDocShell::GetAppId(uint32_t* aAppId) |
|
13021 { |
|
13022 if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
13023 *aAppId = mOwnOrContainingAppId; |
|
13024 return NS_OK; |
|
13025 } |
|
13026 |
|
13027 nsCOMPtr<nsIDocShell> parent; |
|
13028 GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent)); |
|
13029 |
|
13030 if (!parent) { |
|
13031 *aAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
13032 return NS_OK; |
|
13033 } |
|
13034 |
|
13035 return parent->GetAppId(aAppId); |
|
13036 } |
|
13037 |
|
13038 NS_IMETHODIMP |
|
13039 nsDocShell::GetAppManifestURL(nsAString& aAppManifestURL) |
|
13040 { |
|
13041 uint32_t appId; |
|
13042 GetAppId(&appId); |
|
13043 |
|
13044 if (appId != nsIScriptSecurityManager::NO_APP_ID && |
|
13045 appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
13046 nsCOMPtr<nsIAppsService> appsService = |
|
13047 do_GetService(APPS_SERVICE_CONTRACTID); |
|
13048 NS_ASSERTION(appsService, "No AppsService available"); |
|
13049 appsService->GetManifestURLByLocalId(appId, aAppManifestURL); |
|
13050 } else { |
|
13051 aAppManifestURL.SetLength(0); |
|
13052 } |
|
13053 |
|
13054 return NS_OK; |
|
13055 } |
|
13056 |
|
13057 NS_IMETHODIMP |
|
13058 nsDocShell::GetAsyncPanZoomEnabled(bool* aOut) |
|
13059 { |
|
13060 if (TabChild* tabChild = TabChild::GetFrom(this)) { |
|
13061 *aOut = tabChild->IsAsyncPanZoomEnabled(); |
|
13062 return NS_OK; |
|
13063 } |
|
13064 *aOut = false; |
|
13065 return NS_OK; |
|
13066 } |
|
13067 |
|
13068 bool |
|
13069 nsDocShell::HasUnloadedParent() |
|
13070 { |
|
13071 nsCOMPtr<nsIDocShellTreeItem> currentTreeItem = this; |
|
13072 while (currentTreeItem) { |
|
13073 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem; |
|
13074 currentTreeItem->GetParent(getter_AddRefs(parentTreeItem)); |
|
13075 nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentTreeItem); |
|
13076 if (parent) { |
|
13077 bool inUnload = false; |
|
13078 parent->GetIsInUnload(&inUnload); |
|
13079 if (inUnload) { |
|
13080 return true; |
|
13081 } |
|
13082 } |
|
13083 currentTreeItem.swap(parentTreeItem); |
|
13084 } |
|
13085 return false; |
|
13086 } |
|
13087 |
|
13088 bool |
|
13089 nsDocShell::IsInvisible() |
|
13090 { |
|
13091 return mInvisible; |
|
13092 } |
|
13093 |
|
13094 void |
|
13095 nsDocShell::SetInvisible(bool aInvisible) |
|
13096 { |
|
13097 mInvisible = aInvisible; |
|
13098 } |