1/*
2 * Copyright (C) 2007 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "core/frame/History.h"
28
29#include "bindings/core/v8/ExceptionState.h"
30#include "core/dom/Document.h"
31#include "core/dom/ExceptionCode.h"
32#include "core/frame/LocalFrame.h"
33#include "core/loader/DocumentLoader.h"
34#include "core/loader/FrameLoader.h"
35#include "core/loader/FrameLoaderClient.h"
36#include "core/loader/HistoryItem.h"
37#include "core/page/BackForwardClient.h"
38#include "core/page/Page.h"
39#include "platform/weborigin/KURL.h"
40#include "platform/weborigin/SecurityOrigin.h"
41#include "wtf/MainThread.h"
42
43namespace blink {
44
45History::History(LocalFrame* frame)
46    : DOMWindowProperty(frame)
47    , m_lastStateObjectRequested(nullptr)
48{
49}
50
51void History::trace(Visitor* visitor)
52{
53    DOMWindowProperty::trace(visitor);
54}
55
56unsigned History::length() const
57{
58    if (!m_frame)
59        return 0;
60    if (!m_frame->page())
61        return 0;
62    return m_frame->page()->backForward().backForwardListCount();
63}
64
65SerializedScriptValue* History::state()
66{
67    m_lastStateObjectRequested = stateInternal();
68    return m_lastStateObjectRequested.get();
69}
70
71SerializedScriptValue* History::stateInternal() const
72{
73    if (!m_frame)
74        return 0;
75
76    if (HistoryItem* historyItem = m_frame->loader().currentItem())
77        return historyItem->stateObject();
78
79    return 0;
80}
81
82bool History::stateChanged() const
83{
84    return m_lastStateObjectRequested != stateInternal();
85}
86
87bool History::isSameAsCurrentState(SerializedScriptValue* state) const
88{
89    return state == stateInternal();
90}
91
92void History::back(ExecutionContext* context)
93{
94    go(context, -1);
95}
96
97void History::forward(ExecutionContext* context)
98{
99    go(context, 1);
100}
101
102void History::go(ExecutionContext* context, int distance)
103{
104    if (!m_frame)
105        return;
106
107    ASSERT(isMainThread());
108    Document* activeDocument = toDocument(context);
109    if (!activeDocument)
110        return;
111
112    if (!activeDocument->canNavigate(*m_frame))
113        return;
114
115    m_frame->navigationScheduler().scheduleHistoryNavigation(distance);
116}
117
118KURL History::urlForState(const String& urlString)
119{
120    Document* document = m_frame->document();
121
122    if (urlString.isNull())
123        return document->url();
124    if (urlString.isEmpty())
125        return document->baseURL();
126
127    return KURL(document->baseURL(), urlString);
128}
129
130void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& /* title */, const String& urlString, FrameLoadType type, ExceptionState& exceptionState)
131{
132    if (!m_frame || !m_frame->page() || !m_frame->loader().documentLoader())
133        return;
134
135    KURL fullURL = urlForState(urlString);
136    if (!fullURL.isValid() || !m_frame->document()->securityOrigin()->canRequest(fullURL)) {
137        // We can safely expose the URL to JavaScript, as a) no redirection takes place: JavaScript already had this URL, b) JavaScript can only access a same-origin History object.
138        exceptionState.throwSecurityError("A history state object with URL '" + fullURL.elidedString() + "' cannot be created in a document with origin '" + m_frame->document()->securityOrigin()->toString() + "'.");
139        return;
140    }
141    m_frame->loader().updateForSameDocumentNavigation(fullURL, SameDocumentNavigationHistoryApi, data, type);
142}
143
144} // namespace blink
145