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
38 namespace WebCore {
39
Location(Frame * frame)40 Location::Location(Frame* frame)
41 : m_frame(frame)
42 {
43 }
44
disconnectFrame()45 void Location::disconnectFrame()
46 {
47 m_frame = 0;
48 }
49
url() const50 inline 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
href() const61 String 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
protocol() const70 String Location::protocol() const
71 {
72 if (!m_frame)
73 return String();
74
75 return url().protocol() + ":";
76 }
77
host() const78 String 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
hostname() const89 String Location::hostname() const
90 {
91 if (!m_frame)
92 return String();
93
94 return url().host();
95 }
96
port() const97 String 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
pathname() const106 String 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
search() const115 String 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
origin() const124 String Location::origin() const
125 {
126 if (!m_frame)
127 return String();
128 return SecurityOrigin::create(url())->toString();
129 }
130
hash() const131 String 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
getParameter(const String & name) const140 String 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
toString() const150 String 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
setHref(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)159 void 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
setProtocol(const String & protocol,DOMWindow * activeWindow,DOMWindow * firstWindow,ExceptionCode & ec)166 void 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
setHost(const String & host,DOMWindow * activeWindow,DOMWindow * firstWindow)178 void 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
setHostname(const String & hostname,DOMWindow * activeWindow,DOMWindow * firstWindow)187 void 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
setPort(const String & portString,DOMWindow * activeWindow,DOMWindow * firstWindow)196 void 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
setPathname(const String & pathname,DOMWindow * activeWindow,DOMWindow * firstWindow)209 void 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
setSearch(const String & search,DOMWindow * activeWindow,DOMWindow * firstWindow)218 void 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
setHash(const String & hash,DOMWindow * activeWindow,DOMWindow * firstWindow)227 void 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
assign(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)245 void 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
replace(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)252 void 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
reload(DOMWindow * activeWindow)259 void 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