1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sw=2 et tw=78: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Travis Bogard <travis@netscape.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsHistory.h"
41 :
42 : #include "nsCOMPtr.h"
43 : #include "nscore.h"
44 : #include "nsPIDOMWindow.h"
45 : #include "nsIScriptGlobalObject.h"
46 : #include "nsIDOMDocument.h"
47 : #include "nsIDocument.h"
48 : #include "nsIPresShell.h"
49 : #include "nsPresContext.h"
50 : #include "nsIDocShell.h"
51 : #include "nsIDocShellTreeItem.h"
52 : #include "nsIWebNavigation.h"
53 : #include "nsIHistoryEntry.h"
54 : #include "nsIURI.h"
55 : #include "nsIServiceManager.h"
56 : #include "nsIInterfaceRequestorUtils.h"
57 : #include "nsXPIDLString.h"
58 : #include "nsReadableUtils.h"
59 : #include "nsDOMClassInfoID.h"
60 : #include "nsContentUtils.h"
61 : #include "nsISHistoryInternal.h"
62 : #include "mozilla/Preferences.h"
63 :
64 : using namespace mozilla;
65 :
66 : static const char* sAllowPushStatePrefStr =
67 : "browser.history.allowPushState";
68 : static const char* sAllowReplaceStatePrefStr =
69 : "browser.history.allowReplaceState";
70 :
71 : //
72 : // History class implementation
73 : //
74 0 : nsHistory::nsHistory(nsPIDOMWindow* aInnerWindow)
75 0 : : mInnerWindow(do_GetWeakReference(aInnerWindow))
76 : {
77 0 : }
78 :
79 0 : nsHistory::~nsHistory()
80 : {
81 0 : }
82 :
83 :
84 : DOMCI_DATA(History, nsHistory)
85 :
86 : // QueryInterface implementation for nsHistory
87 0 : NS_INTERFACE_MAP_BEGIN(nsHistory)
88 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMHistory)
89 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMHistory)
90 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(History)
91 0 : NS_INTERFACE_MAP_END
92 :
93 :
94 0 : NS_IMPL_ADDREF(nsHistory)
95 0 : NS_IMPL_RELEASE(nsHistory)
96 :
97 :
98 : NS_IMETHODIMP
99 0 : nsHistory::GetLength(PRInt32* aLength)
100 : {
101 0 : nsCOMPtr<nsISHistory> sHistory;
102 :
103 : // Get session History from docshell
104 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
105 0 : NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
106 0 : return sHistory->GetCount(aLength);
107 : }
108 :
109 : NS_IMETHODIMP
110 0 : nsHistory::GetCurrent(nsAString& aCurrent)
111 : {
112 0 : if (!nsContentUtils::IsCallerTrustedForRead())
113 0 : return NS_ERROR_DOM_SECURITY_ERR;
114 :
115 0 : PRInt32 curIndex=0;
116 0 : nsCAutoString curURL;
117 0 : nsCOMPtr<nsISHistory> sHistory;
118 :
119 : // Get SessionHistory from docshell
120 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
121 0 : NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
122 :
123 : // Get the current index at session History
124 0 : sHistory->GetIndex(&curIndex);
125 0 : nsCOMPtr<nsIHistoryEntry> curEntry;
126 0 : nsCOMPtr<nsIURI> uri;
127 :
128 : // Get the SH entry for the current index
129 0 : sHistory->GetEntryAtIndex(curIndex, false, getter_AddRefs(curEntry));
130 0 : NS_ENSURE_TRUE(curEntry, NS_ERROR_FAILURE);
131 :
132 : // Get the URI for the current entry
133 0 : curEntry->GetURI(getter_AddRefs(uri));
134 0 : NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
135 0 : uri->GetSpec(curURL);
136 0 : CopyUTF8toUTF16(curURL, aCurrent);
137 :
138 0 : return NS_OK;
139 : }
140 :
141 : NS_IMETHODIMP
142 0 : nsHistory::GetPrevious(nsAString& aPrevious)
143 : {
144 0 : if (!nsContentUtils::IsCallerTrustedForRead())
145 0 : return NS_ERROR_DOM_SECURITY_ERR;
146 :
147 : PRInt32 curIndex;
148 0 : nsCAutoString prevURL;
149 0 : nsCOMPtr<nsISHistory> sHistory;
150 :
151 : // Get session History from docshell
152 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
153 0 : NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
154 :
155 : // Get the current index at session History
156 0 : sHistory->GetIndex(&curIndex);
157 0 : nsCOMPtr<nsIHistoryEntry> prevEntry;
158 0 : nsCOMPtr<nsIURI> uri;
159 :
160 : // Get the previous SH entry
161 0 : sHistory->GetEntryAtIndex((curIndex-1), false, getter_AddRefs(prevEntry));
162 0 : NS_ENSURE_TRUE(prevEntry, NS_ERROR_FAILURE);
163 :
164 : // Get the URI for the previous entry
165 0 : prevEntry->GetURI(getter_AddRefs(uri));
166 0 : NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
167 0 : uri->GetSpec(prevURL);
168 0 : CopyUTF8toUTF16(prevURL, aPrevious);
169 :
170 0 : return NS_OK;
171 : }
172 :
173 : NS_IMETHODIMP
174 0 : nsHistory::GetNext(nsAString& aNext)
175 : {
176 0 : if (!nsContentUtils::IsCallerTrustedForRead())
177 0 : return NS_ERROR_DOM_SECURITY_ERR;
178 :
179 : PRInt32 curIndex;
180 0 : nsCAutoString nextURL;
181 0 : nsCOMPtr<nsISHistory> sHistory;
182 :
183 : // Get session History from docshell
184 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
185 0 : NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
186 :
187 : // Get the current index at session History
188 0 : sHistory->GetIndex(&curIndex);
189 0 : nsCOMPtr<nsIHistoryEntry> nextEntry;
190 0 : nsCOMPtr<nsIURI> uri;
191 :
192 : // Get the next SH entry
193 0 : sHistory->GetEntryAtIndex((curIndex+1), false, getter_AddRefs(nextEntry));
194 0 : NS_ENSURE_TRUE(nextEntry, NS_ERROR_FAILURE);
195 :
196 : // Get the URI for the next entry
197 0 : nextEntry->GetURI(getter_AddRefs(uri));
198 0 : NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
199 0 : uri->GetSpec(nextURL);
200 0 : CopyUTF8toUTF16(nextURL, aNext);
201 :
202 0 : return NS_OK;
203 : }
204 :
205 : NS_IMETHODIMP
206 0 : nsHistory::Back()
207 : {
208 0 : nsCOMPtr<nsISHistory> sHistory;
209 :
210 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
211 0 : NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
212 :
213 : //QI SHistory to WebNavigation
214 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
215 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
216 0 : webNav->GoBack();
217 :
218 0 : return NS_OK;
219 : }
220 :
221 : NS_IMETHODIMP
222 0 : nsHistory::Forward()
223 : {
224 0 : nsCOMPtr<nsISHistory> sHistory;
225 :
226 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(sHistory));
227 0 : NS_ENSURE_TRUE(sHistory, NS_ERROR_FAILURE);
228 :
229 : //QI SHistory to WebNavigation
230 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(sHistory));
231 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
232 0 : webNav->GoForward();
233 :
234 0 : return NS_OK;
235 : }
236 :
237 : NS_IMETHODIMP
238 0 : nsHistory::Go(PRInt32 aDelta)
239 : {
240 0 : if (aDelta == 0) {
241 0 : nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(GetDocShell()));
242 :
243 0 : if (window && window->IsHandlingResizeEvent()) {
244 : // history.go(0) (aka location.reload()) was called on a window
245 : // that is handling a resize event. Sites do this since Netscape
246 : // 4.x needed it, but we don't, and it's a horrible experience
247 : // for nothing. In stead of reloading the page, just clear
248 : // style data and reflow the page since some sites may use this
249 : // trick to work around gecko reflow bugs, and this should have
250 : // the same effect.
251 :
252 : nsCOMPtr<nsIDocument> doc =
253 0 : do_QueryInterface(window->GetExtantDocument());
254 :
255 : nsIPresShell *shell;
256 : nsPresContext *pcx;
257 0 : if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
258 0 : pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
259 : }
260 :
261 0 : return NS_OK;
262 : }
263 : }
264 :
265 0 : nsCOMPtr<nsISHistory> session_history;
266 :
267 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(session_history));
268 0 : NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE);
269 :
270 : // QI SHistory to nsIWebNavigation
271 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
272 0 : NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
273 :
274 0 : PRInt32 curIndex=-1;
275 0 : PRInt32 len = 0;
276 0 : nsresult rv = session_history->GetIndex(&curIndex);
277 0 : rv = session_history->GetCount(&len);
278 :
279 0 : PRInt32 index = curIndex + aDelta;
280 0 : if (index > -1 && index < len)
281 0 : webnav->GotoIndex(index);
282 :
283 : // We always want to return a NS_OK, since returning errors
284 : // from GotoIndex() can lead to exceptions and a possible leak
285 : // of history length
286 :
287 0 : return NS_OK;
288 : }
289 :
290 : NS_IMETHODIMP
291 0 : nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
292 : const nsAString& aURL, JSContext* aCx)
293 : {
294 : // Check that PushState hasn't been pref'ed off.
295 0 : if (!Preferences::GetBool(sAllowPushStatePrefStr, false)) {
296 0 : return NS_OK;
297 : }
298 :
299 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
300 0 : if (!win)
301 0 : return NS_ERROR_NOT_AVAILABLE;
302 :
303 0 : if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
304 0 : return NS_ERROR_DOM_SECURITY_ERR;
305 :
306 : // AddState might run scripts, so we need to hold a strong reference to the
307 : // docShell here to keep it from going away.
308 0 : nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
309 :
310 0 : NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
311 :
312 : // false tells the docshell to add a new history entry instead of
313 : // modifying the current one.
314 0 : nsresult rv = docShell->AddState(aData, aTitle, aURL, false, aCx);
315 0 : NS_ENSURE_SUCCESS(rv, rv);
316 :
317 0 : return NS_OK;
318 : }
319 :
320 : NS_IMETHODIMP
321 0 : nsHistory::ReplaceState(nsIVariant *aData, const nsAString& aTitle,
322 : const nsAString& aURL, JSContext* aCx)
323 : {
324 : // Check that ReplaceState hasn't been pref'ed off
325 0 : if (!Preferences::GetBool(sAllowReplaceStatePrefStr, false)) {
326 0 : return NS_OK;
327 : }
328 :
329 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
330 0 : if (!win)
331 0 : return NS_ERROR_NOT_AVAILABLE;
332 :
333 0 : if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
334 0 : return NS_ERROR_DOM_SECURITY_ERR;
335 :
336 : // AddState might run scripts, so we need to hold a strong reference to the
337 : // docShell here to keep it from going away.
338 0 : nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
339 :
340 0 : NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
341 :
342 : // true tells the docshell to modify the current SHEntry, rather than
343 : // create a new one.
344 0 : return docShell->AddState(aData, aTitle, aURL, true, aCx);
345 : }
346 :
347 : NS_IMETHODIMP
348 0 : nsHistory::GetState(nsIVariant **aState)
349 : {
350 0 : *aState = nsnull;
351 :
352 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
353 0 : if (!win)
354 0 : return NS_ERROR_NOT_AVAILABLE;
355 :
356 0 : if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow()))
357 0 : return NS_ERROR_DOM_SECURITY_ERR;
358 :
359 : nsCOMPtr<nsIDocument> doc =
360 0 : do_QueryInterface(win->GetExtantDocument());
361 0 : if (!doc)
362 0 : return NS_ERROR_NOT_AVAILABLE;
363 :
364 0 : return doc->GetStateObject(aState);
365 : }
366 :
367 : NS_IMETHODIMP
368 0 : nsHistory::Item(PRUint32 aIndex, nsAString& aReturn)
369 : {
370 0 : aReturn.Truncate();
371 0 : if (!nsContentUtils::IsCallerTrustedForRead()) {
372 0 : return NS_ERROR_DOM_SECURITY_ERR;
373 : }
374 :
375 0 : nsresult rv = NS_OK;
376 0 : nsCOMPtr<nsISHistory> session_history;
377 :
378 0 : GetSessionHistoryFromDocShell(GetDocShell(), getter_AddRefs(session_history));
379 0 : NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE);
380 :
381 0 : nsCOMPtr<nsIHistoryEntry> sh_entry;
382 0 : nsCOMPtr<nsIURI> uri;
383 :
384 0 : rv = session_history->GetEntryAtIndex(aIndex, false,
385 0 : getter_AddRefs(sh_entry));
386 :
387 0 : if (sh_entry) {
388 0 : rv = sh_entry->GetURI(getter_AddRefs(uri));
389 : }
390 :
391 0 : if (uri) {
392 0 : nsCAutoString urlCString;
393 0 : rv = uri->GetSpec(urlCString);
394 :
395 0 : CopyUTF8toUTF16(urlCString, aReturn);
396 : }
397 :
398 0 : return rv;
399 : }
400 :
401 : nsresult
402 0 : nsHistory::GetSessionHistoryFromDocShell(nsIDocShell * aDocShell,
403 : nsISHistory ** aReturn)
404 : {
405 :
406 0 : NS_ENSURE_TRUE(aDocShell, NS_ERROR_FAILURE);
407 : /* The docshell we have may or may not be
408 : * the root docshell. So, get a handle to
409 : * SH from the root docshell
410 : */
411 :
412 : // QI mDocShell to nsIDocShellTreeItem
413 0 : nsCOMPtr<nsIDocShellTreeItem> dsTreeItem(do_QueryInterface(aDocShell));
414 0 : NS_ENSURE_TRUE(dsTreeItem, NS_ERROR_FAILURE);
415 :
416 : // Get the root DocShell from it
417 0 : nsCOMPtr<nsIDocShellTreeItem> root;
418 0 : dsTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
419 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
420 :
421 : //QI root to nsIWebNavigation
422 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(root));
423 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
424 :
425 : //Get SH from nsIWebNavigation
426 0 : return webNav->GetSessionHistory(aReturn);
427 :
428 : }
429 :
|