Location.cpp revision 2fc2651226baac27029e38c9d6ef883fa32084db
1/*
2 * Copyright (C) 2008, 2010 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "Location.h"
31
32#include "DOMWindow.h"
33#include "ExceptionCode.h"
34#include "Frame.h"
35#include "FrameLoader.h"
36#include "KURL.h"
37
38namespace WebCore {
39
40Location::Location(Frame* frame)
41    : m_frame(frame)
42{
43}
44
45void Location::disconnectFrame()
46{
47    m_frame = 0;
48}
49
50inline const KURL& Location::url() const
51{
52    ASSERT(m_frame);
53
54    const KURL& url = m_frame->document()->url();
55    if (!url.isValid())
56        return blankURL(); // Use "about:blank" while the page is still loading (before we have a frame).
57
58    return url;
59}
60
61String Location::href() const
62{
63    if (!m_frame)
64        return String();
65
66    const KURL& url = this->url();
67    return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
68}
69
70String Location::protocol() const
71{
72    if (!m_frame)
73        return String();
74
75    return url().protocol() + ":";
76}
77
78String Location::host() const
79{
80    if (!m_frame)
81        return String();
82
83    // Note: this is the IE spec. The NS spec swaps the two, it says
84    // "The hostname property is the concatenation of the host and port properties, separated by a colon."
85    const KURL& url = this->url();
86    return url.port() ? url.host() + ":" + String::number(url.port()) : url.host();
87}
88
89String Location::hostname() const
90{
91    if (!m_frame)
92        return String();
93
94    return url().host();
95}
96
97String Location::port() const
98{
99    if (!m_frame)
100        return String();
101
102    const KURL& url = this->url();
103    return url.port() ? String::number(url.port()) : "";
104}
105
106String Location::pathname() const
107{
108    if (!m_frame)
109        return String();
110
111    const KURL& url = this->url();
112    return url.path().isEmpty() ? "/" : url.path();
113}
114
115String Location::search() const
116{
117    if (!m_frame)
118        return String();
119
120    const KURL& url = this->url();
121    return url.query().isEmpty() ? "" : "?" + url.query();
122}
123
124String Location::origin() const
125{
126    if (!m_frame)
127        return String();
128    return SecurityOrigin::create(url())->toString();
129}
130
131String Location::hash() const
132{
133    if (!m_frame)
134        return String();
135
136    const String& fragmentIdentifier = url().fragmentIdentifier();
137    return fragmentIdentifier.isEmpty() ? "" : "#" + fragmentIdentifier;
138}
139
140String Location::getParameter(const String& name) const
141{
142    if (!m_frame)
143        return String();
144
145    ParsedURLParameters parameters;
146    url().copyParsedQueryTo(parameters);
147    return parameters.get(name);
148}
149
150String Location::toString() const
151{
152    if (!m_frame)
153        return String();
154
155    const KURL& url = this->url();
156    return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
157}
158
159void Location::setHref(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
160{
161    if (!m_frame)
162        return;
163    m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
164}
165
166void Location::setProtocol(const String& protocol, DOMWindow* activeWindow, DOMWindow* firstWindow, ExceptionCode& ec)
167{
168    if (!m_frame)
169        return;
170    KURL url = m_frame->document()->url();
171    if (!url.setProtocol(protocol)) {
172        ec = SYNTAX_ERR;
173        return;
174    }
175    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
176}
177
178void Location::setHost(const String& host, DOMWindow* activeWindow, DOMWindow* firstWindow)
179{
180    if (!m_frame)
181        return;
182    KURL url = m_frame->document()->url();
183    url.setHostAndPort(host);
184    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
185}
186
187void Location::setHostname(const String& hostname, DOMWindow* activeWindow, DOMWindow* firstWindow)
188{
189    if (!m_frame)
190        return;
191    KURL url = m_frame->document()->url();
192    url.setHost(hostname);
193    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
194}
195
196void Location::setPort(const String& portString, DOMWindow* activeWindow, DOMWindow* firstWindow)
197{
198    if (!m_frame)
199        return;
200    KURL url = m_frame->document()->url();
201    int port = portString.toInt();
202    if (port < 0 || port > 0xFFFF)
203        url.removePort();
204    else
205        url.setPort(port);
206    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
207}
208
209void Location::setPathname(const String& pathname, DOMWindow* activeWindow, DOMWindow* firstWindow)
210{
211    if (!m_frame)
212        return;
213    KURL url = m_frame->document()->url();
214    url.setPath(pathname);
215    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
216}
217
218void Location::setSearch(const String& search, DOMWindow* activeWindow, DOMWindow* firstWindow)
219{
220    if (!m_frame)
221        return;
222    KURL url = m_frame->document()->url();
223    url.setQuery(search);
224    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
225}
226
227void Location::setHash(const String& hash, DOMWindow* activeWindow, DOMWindow* firstWindow)
228{
229    if (!m_frame)
230        return;
231    KURL url = m_frame->document()->url();
232    String oldFragmentIdentifier = url.fragmentIdentifier();
233    String newFragmentIdentifier = hash;
234    if (hash[0] == '#')
235        newFragmentIdentifier = hash.substring(1);
236    url.setFragmentIdentifier(newFragmentIdentifier);
237    // Note that by parsing the URL and *then* comparing fragments, we are
238    // comparing fragments post-canonicalization, and so this handles the
239    // cases where fragment identifiers are ignored or invalid.
240    if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
241        return;
242    m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
243}
244
245void Location::assign(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
246{
247    if (!m_frame)
248        return;
249    m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
250}
251
252void Location::replace(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
253{
254    if (!m_frame)
255        return;
256    m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow, LockHistoryAndBackForwardList);
257}
258
259void Location::reload(DOMWindow* activeWindow)
260{
261    if (!m_frame)
262        return;
263    // FIXME: It's not clear this cross-origin security check is valuable.
264    // We allow one page to change the location of another. Why block attempts to reload?
265    // Other location operations simply block use of JavaScript URLs cross origin.
266    DOMWindow* targetWindow = m_frame->domWindow();
267    if (!activeWindow->securityOrigin()->canAccess(targetWindow->securityOrigin())) {
268        targetWindow->printErrorMessage(targetWindow->crossDomainAccessErrorMessage(activeWindow));
269        return;
270    }
271    if (protocolIsJavaScript(m_frame->document()->url()))
272        return;
273    m_frame->navigationScheduler()->scheduleRefresh();
274}
275
276} // namespace WebCore
277