be185f957595e668af83185ba17b96a8c6f1ce41
[WebKit-https.git] / Source / WebCore / page / Location.cpp
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
40 Location::Location(Frame* frame)
41     : m_frame(frame)
42 {
43 }
44
45 void Location::disconnectFrame()
46 {
47     m_frame = 0;
48 }
49
50 inline const KURL& Location::url() const
51 {
52     ASSERT(m_frame);
53
54     const KURL& url = m_frame->loader()->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
61 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
70 String Location::protocol() const
71 {
72     if (!m_frame)
73         return String();
74
75     return url().protocol() + ":";
76 }
77
78 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
89 String Location::hostname() const
90 {
91     if (!m_frame)
92         return String();
93
94     return url().host();
95 }
96
97 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
106 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
115 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
124 String Location::origin() const
125 {
126     if (!m_frame)
127         return String();
128     return SecurityOrigin::create(url())->toString();
129 }
130
131 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
140 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
150 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
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
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->loader()->url();
171     if (!url.setProtocol(protocol)) {
172         ec = SYNTAX_ERR;
173         return;
174     }
175     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
176 }
177
178 void Location::setHost(const String& host, DOMWindow* activeWindow, DOMWindow* firstWindow)
179 {
180     if (!m_frame)
181         return;
182     KURL url = m_frame->loader()->url();
183     url.setHostAndPort(host);
184     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
185 }
186
187 void Location::setHostname(const String& hostname, DOMWindow* activeWindow, DOMWindow* firstWindow)
188 {
189     if (!m_frame)
190         return;
191     KURL url = m_frame->loader()->url();
192     url.setHost(hostname);
193     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
194 }
195
196 void Location::setPort(const String& portString, DOMWindow* activeWindow, DOMWindow* firstWindow)
197 {
198     if (!m_frame)
199         return;
200     KURL url = m_frame->loader()->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
209 void Location::setPathname(const String& pathname, DOMWindow* activeWindow, DOMWindow* firstWindow)
210 {
211     if (!m_frame)
212         return;
213     KURL url = m_frame->loader()->url();
214     url.setPath(pathname);
215     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
216 }
217
218 void Location::setSearch(const String& search, DOMWindow* activeWindow, DOMWindow* firstWindow)
219 {
220     if (!m_frame)
221         return;
222     KURL url = m_frame->loader()->url();
223     url.setQuery(search);
224     m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
225 }
226
227 void Location::setHash(const String& hash, DOMWindow* activeWindow, DOMWindow* firstWindow)
228 {
229     if (!m_frame)
230         return;
231     KURL url = m_frame->loader()->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
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
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
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->loader()->url()))
272         return;
273     m_frame->navigationScheduler()->scheduleRefresh();
274 }
275
276 } // namespace WebCore