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 return url().string();
67 }
68
protocol() const69 String Location::protocol() const
70 {
71 if (!m_frame)
72 return String();
73
74 return url().protocol() + ":";
75 }
76
host() const77 String Location::host() const
78 {
79 if (!m_frame)
80 return String();
81
82 // Note: this is the IE spec. The NS spec swaps the two, it says
83 // "The hostname property is the concatenation of the host and port properties, separated by a colon."
84 const KURL& url = this->url();
85 return url.hasPort() ? url.host() + ":" + String::number(url.port()) : url.host();
86 }
87
hostname() const88 String Location::hostname() const
89 {
90 if (!m_frame)
91 return String();
92
93 return url().host();
94 }
95
port() const96 String Location::port() const
97 {
98 if (!m_frame)
99 return String();
100
101 const KURL& url = this->url();
102 return url.hasPort() ? String::number(url.port()) : "";
103 }
104
pathname() const105 String Location::pathname() const
106 {
107 if (!m_frame)
108 return String();
109
110 const KURL& url = this->url();
111 return url.path().isEmpty() ? "/" : url.path();
112 }
113
search() const114 String Location::search() const
115 {
116 if (!m_frame)
117 return String();
118
119 const KURL& url = this->url();
120 return url.query().isEmpty() ? "" : "?" + url.query();
121 }
122
origin() const123 String Location::origin() const
124 {
125 if (!m_frame)
126 return String();
127 return SecurityOrigin::create(url())->toString();
128 }
129
hash() const130 String Location::hash() const
131 {
132 if (!m_frame)
133 return String();
134
135 const String& fragmentIdentifier = url().fragmentIdentifier();
136 return fragmentIdentifier.isEmpty() ? "" : "#" + fragmentIdentifier;
137 }
138
getParameter(const String & name) const139 String Location::getParameter(const String& name) const
140 {
141 if (!m_frame)
142 return String();
143
144 ParsedURLParameters parameters;
145 url().copyParsedQueryTo(parameters);
146 return parameters.get(name);
147 }
148
setHref(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)149 void Location::setHref(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
150 {
151 if (!m_frame)
152 return;
153 m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
154 }
155
setProtocol(const String & protocol,DOMWindow * activeWindow,DOMWindow * firstWindow,ExceptionCode & ec)156 void Location::setProtocol(const String& protocol, DOMWindow* activeWindow, DOMWindow* firstWindow, ExceptionCode& ec)
157 {
158 if (!m_frame)
159 return;
160 KURL url = m_frame->document()->url();
161 if (!url.setProtocol(protocol)) {
162 ec = SYNTAX_ERR;
163 return;
164 }
165 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
166 }
167
setHost(const String & host,DOMWindow * activeWindow,DOMWindow * firstWindow)168 void Location::setHost(const String& host, DOMWindow* activeWindow, DOMWindow* firstWindow)
169 {
170 if (!m_frame)
171 return;
172 KURL url = m_frame->document()->url();
173 url.setHostAndPort(host);
174 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
175 }
176
setHostname(const String & hostname,DOMWindow * activeWindow,DOMWindow * firstWindow)177 void Location::setHostname(const String& hostname, DOMWindow* activeWindow, DOMWindow* firstWindow)
178 {
179 if (!m_frame)
180 return;
181 KURL url = m_frame->document()->url();
182 url.setHost(hostname);
183 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
184 }
185
setPort(const String & portString,DOMWindow * activeWindow,DOMWindow * firstWindow)186 void Location::setPort(const String& portString, DOMWindow* activeWindow, DOMWindow* firstWindow)
187 {
188 if (!m_frame)
189 return;
190 KURL url = m_frame->document()->url();
191 int port = portString.toInt();
192 if (port < 0 || port > 0xFFFF || portString.isEmpty())
193 url.removePort();
194 else
195 url.setPort(port);
196 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
197 }
198
setPathname(const String & pathname,DOMWindow * activeWindow,DOMWindow * firstWindow)199 void Location::setPathname(const String& pathname, DOMWindow* activeWindow, DOMWindow* firstWindow)
200 {
201 if (!m_frame)
202 return;
203 KURL url = m_frame->document()->url();
204 url.setPath(pathname);
205 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
206 }
207
setSearch(const String & search,DOMWindow * activeWindow,DOMWindow * firstWindow)208 void Location::setSearch(const String& search, DOMWindow* activeWindow, DOMWindow* firstWindow)
209 {
210 if (!m_frame)
211 return;
212 KURL url = m_frame->document()->url();
213 url.setQuery(search);
214 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
215 }
216
setHash(const String & hash,DOMWindow * activeWindow,DOMWindow * firstWindow)217 void Location::setHash(const String& hash, DOMWindow* activeWindow, DOMWindow* firstWindow)
218 {
219 if (!m_frame)
220 return;
221 KURL url = m_frame->document()->url();
222 String oldFragmentIdentifier = url.fragmentIdentifier();
223 String newFragmentIdentifier = hash;
224 if (hash[0] == '#')
225 newFragmentIdentifier = hash.substring(1);
226 url.setFragmentIdentifier(newFragmentIdentifier);
227 // Note that by parsing the URL and *then* comparing fragments, we are
228 // comparing fragments post-canonicalization, and so this handles the
229 // cases where fragment identifiers are ignored or invalid.
230 if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
231 return;
232 m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
233 }
234
assign(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)235 void Location::assign(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
236 {
237 if (!m_frame)
238 return;
239 m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
240 }
241
replace(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)242 void Location::replace(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
243 {
244 if (!m_frame)
245 return;
246 m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow, LockHistoryAndBackForwardList);
247 }
248
reload(DOMWindow * activeWindow)249 void Location::reload(DOMWindow* activeWindow)
250 {
251 if (!m_frame)
252 return;
253 // FIXME: It's not clear this cross-origin security check is valuable.
254 // We allow one page to change the location of another. Why block attempts to reload?
255 // Other location operations simply block use of JavaScript URLs cross origin.
256 DOMWindow* targetWindow = m_frame->domWindow();
257 if (!activeWindow->securityOrigin()->canAccess(targetWindow->securityOrigin())) {
258 targetWindow->printErrorMessage(targetWindow->crossDomainAccessErrorMessage(activeWindow));
259 return;
260 }
261 if (protocolIsJavaScript(m_frame->document()->url()))
262 return;
263 m_frame->navigationScheduler()->scheduleRefresh();
264 }
265
266 } // namespace WebCore
267