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 "Document.h"
34 #include "ExceptionCode.h"
35 #include "Frame.h"
36 #include "FrameLoader.h"
37 #include "KURL.h"
38 #include "SecurityOrigin.h"
39 
40 namespace WebCore {
41 
Location(Frame * frame)42 Location::Location(Frame* frame)
43     : m_frame(frame)
44 {
45 }
46 
disconnectFrame()47 void Location::disconnectFrame()
48 {
49     m_frame = 0;
50 }
51 
url() const52 inline const KURL& Location::url() const
53 {
54     ASSERT(m_frame);
55 
56     const KURL& url = m_frame->document()->url();
57     if (!url.isValid())
58         return blankURL(); // Use "about:blank" while the page is still loading (before we have a frame).
59 
60     return url;
61 }
62 
href() const63 String Location::href() const
64 {
65     if (!m_frame)
66         return String();
67 
68     const KURL& url = this->url();
69     return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
70 }
71 
protocol() const72 String Location::protocol() const
73 {
74     if (!m_frame)
75         return String();
76 
77     return url().protocol() + ":";
78 }
79 
host() const80 String Location::host() const
81 {
82     if (!m_frame)
83         return String();
84 
85     // Note: this is the IE spec. The NS spec swaps the two, it says
86     // "The hostname property is the concatenation of the host and port properties, separated by a colon."
87     const KURL& url = this->url();
88     return url.port() ? url.host() + ":" + String::number(url.port()) : url.host();
89 }
90 
hostname() const91 String Location::hostname() const
92 {
93     if (!m_frame)
94         return String();
95 
96     return url().host();
97 }
98 
port() const99 String Location::port() const
100 {
101     if (!m_frame)
102         return String();
103 
104     const KURL& url = this->url();
105     return url.port() ? String::number(url.port()) : "";
106 }
107 
pathname() const108 String Location::pathname() const
109 {
110     if (!m_frame)
111         return String();
112 
113     const KURL& url = this->url();
114     return url.path().isEmpty() ? "/" : url.path();
115 }
116 
search() const117 String Location::search() const
118 {
119     if (!m_frame)
120         return String();
121 
122     const KURL& url = this->url();
123     return url.query().isEmpty() ? "" : "?" + url.query();
124 }
125 
origin() const126 String Location::origin() const
127 {
128     if (!m_frame)
129         return String();
130     return SecurityOrigin::create(url())->toString();
131 }
132 
hash() const133 String Location::hash() const
134 {
135     if (!m_frame)
136         return String();
137 
138     const String& fragmentIdentifier = url().fragmentIdentifier();
139     return fragmentIdentifier.isEmpty() ? "" : "#" + fragmentIdentifier;
140 }
141 
getParameter(const String & name) const142 String Location::getParameter(const String& name) const
143 {
144     if (!m_frame)
145         return String();
146 
147     ParsedURLParameters parameters;
148     url().copyParsedQueryTo(parameters);
149     return parameters.get(name);
150 }
151 
toString() const152 String Location::toString() const
153 {
154     if (!m_frame)
155         return String();
156 
157     const KURL& url = this->url();
158     return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
159 }
160 
setHref(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)161 void Location::setHref(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
162 {
163     if (!m_frame)
164         return;
165     m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
166 }
167 
setProtocol(const String & protocol,DOMWindow * activeWindow,DOMWindow * firstWindow,ExceptionCode & ec)168 void Location::setProtocol(const String& protocol, DOMWindow* activeWindow, DOMWindow* firstWindow, ExceptionCode& ec)
169 {
170     if (!m_frame)
171         return;
172     KURL url = m_frame->document()->url();
173     if (!url.setProtocol(protocol)) {
174         ec = SYNTAX_ERR;
175         return;
176     }
177     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
178 }
179 
setHost(const String & host,DOMWindow * activeWindow,DOMWindow * firstWindow)180 void Location::setHost(const String& host, DOMWindow* activeWindow, DOMWindow* firstWindow)
181 {
182     if (!m_frame)
183         return;
184     KURL url = m_frame->document()->url();
185     url.setHostAndPort(host);
186     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
187 }
188 
setHostname(const String & hostname,DOMWindow * activeWindow,DOMWindow * firstWindow)189 void Location::setHostname(const String& hostname, DOMWindow* activeWindow, DOMWindow* firstWindow)
190 {
191     if (!m_frame)
192         return;
193     KURL url = m_frame->document()->url();
194     url.setHost(hostname);
195     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
196 }
197 
setPort(const String & portString,DOMWindow * activeWindow,DOMWindow * firstWindow)198 void Location::setPort(const String& portString, DOMWindow* activeWindow, DOMWindow* firstWindow)
199 {
200     if (!m_frame)
201         return;
202     KURL url = m_frame->document()->url();
203     int port = portString.toInt();
204     if (port < 0 || port > 0xFFFF)
205         url.removePort();
206     else
207         url.setPort(port);
208     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
209 }
210 
setPathname(const String & pathname,DOMWindow * activeWindow,DOMWindow * firstWindow)211 void Location::setPathname(const String& pathname, DOMWindow* activeWindow, DOMWindow* firstWindow)
212 {
213     if (!m_frame)
214         return;
215     KURL url = m_frame->document()->url();
216     url.setPath(pathname);
217     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
218 }
219 
setSearch(const String & search,DOMWindow * activeWindow,DOMWindow * firstWindow)220 void Location::setSearch(const String& search, DOMWindow* activeWindow, DOMWindow* firstWindow)
221 {
222     if (!m_frame)
223         return;
224     KURL url = m_frame->document()->url();
225     url.setQuery(search);
226     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
227 }
228 
setHash(const String & hash,DOMWindow * activeWindow,DOMWindow * firstWindow)229 void Location::setHash(const String& hash, DOMWindow* activeWindow, DOMWindow* firstWindow)
230 {
231     if (!m_frame)
232         return;
233     KURL url = m_frame->document()->url();
234     String oldFragmentIdentifier = url.fragmentIdentifier();
235     String newFragmentIdentifier = hash;
236     if (hash[0] == '#')
237         newFragmentIdentifier = hash.substring(1);
238     url.setFragmentIdentifier(newFragmentIdentifier);
239     // Note that by parsing the URL and *then* comparing fragments, we are
240     // comparing fragments post-canonicalization, and so this handles the
241     // cases where fragment identifiers are ignored or invalid.
242     if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
243         return;
244     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
245 }
246 
assign(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)247 void Location::assign(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
248 {
249     if (!m_frame)
250         return;
251     m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
252 }
253 
replace(const String & urlString,DOMWindow * activeWindow,DOMWindow * firstWindow)254 void Location::replace(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
255 {
256     if (!m_frame)
257         return;
258     m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow, LockHistoryAndBackForwardList);
259 }
260 
reload(DOMWindow * activeWindow)261 void Location::reload(DOMWindow* activeWindow)
262 {
263     if (!m_frame)
264         return;
265     // FIXME: It's not clear this cross-origin security check is valuable.
266     // We allow one page to change the location of another. Why block attempts to reload?
267     // Other location operations simply block use of JavaScript URLs cross origin.
268     DOMWindow* targetWindow = m_frame->domWindow();
269     if (!activeWindow->securityOrigin()->canAccess(targetWindow->securityOrigin())) {
270         targetWindow->printErrorMessage(targetWindow->crossDomainAccessErrorMessage(activeWindow));
271         return;
272     }
273     if (protocolIsJavaScript(m_frame->document()->url()))
274         return;
275     m_frame->navigationScheduler()->scheduleRefresh();
276 }
277 
278 } // namespace WebCore
279