[WPE][GTK] Build failure with ENABLE_ACCESSIBILITY=OFF
[WebKit-https.git] / Source / WebCore / html / URLUtils.h
1 /*
2  * Copyright (C) 2014 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  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "SecurityOrigin.h"
29
30 namespace WebCore {
31
32 template <typename T>
33 class URLUtils {
34 public:
35     URL href() const { return static_cast<const T*>(this)->href(); }
36     void setHref(const String& url) { static_cast<T*>(this)->setHref(url); }
37
38     String toString() const;
39     String toJSON() const;
40
41     String origin() const;
42
43     String protocol() const;
44     void setProtocol(const String&);
45
46     String username() const;
47     void setUsername(const String&);
48
49     String password() const;
50     void setPassword(const String&);
51
52     String host() const;
53     void setHost(const String&);
54
55     String hostname() const;
56     void setHostname(const String&);
57
58     String port() const;
59     void setPort(const String&);
60
61     String pathname() const;
62     void setPathname(const String&);
63
64     String search() const;
65     void setSearch(const String&);
66
67     String hash() const;
68     void setHash(const String&);
69 };
70
71 template <typename T>
72 String URLUtils<T>::toString() const
73 {
74     return href().string();
75 }
76
77 template <typename T>
78 String URLUtils<T>::toJSON() const
79 {
80     return href().string();
81 }
82
83 template <typename T>
84 String URLUtils<T>::origin() const
85 {
86     auto origin = SecurityOrigin::create(href());
87     return origin->toString();
88 }
89
90 template <typename T>
91 String URLUtils<T>::protocol() const
92 {
93     if (WTF::protocolIsJavaScript(href()))
94         return "javascript:"_s;
95     return makeString(href().protocol(), ':');
96 }
97
98 template <typename T>
99 void URLUtils<T>::setProtocol(const String& value)
100 {
101     URL url = href();
102     url.setProtocol(value);
103     setHref(url.string());
104 }
105
106 template <typename T>
107 String URLUtils<T>::username() const
108 {
109     return href().encodedUser();
110 }
111
112 template <typename T>
113 void URLUtils<T>::setUsername(const String& user)
114 {
115     URL url = href();
116     if (url.cannotBeABaseURL())
117         return;
118     url.setUser(user);
119     setHref(url);
120 }
121
122 template <typename T>
123 String URLUtils<T>::password() const
124 {
125     return href().encodedPass();
126 }
127
128 template <typename T>
129 void URLUtils<T>::setPassword(const String& pass)
130 {
131     URL url = href();
132     if (url.cannotBeABaseURL())
133         return;
134     url.setPass(pass);
135     setHref(url);
136 }
137
138 template <typename T>
139 String URLUtils<T>::host() const
140 {
141     return href().hostAndPort();
142 }
143
144 // This function does not allow leading spaces before the port number.
145 static inline unsigned parsePortFromStringPosition(const String& value, unsigned portStart, unsigned& portEnd)
146 {
147     portEnd = portStart;
148     while (isASCIIDigit(value[portEnd]))
149         ++portEnd;
150     return value.substring(portStart, portEnd - portStart).toUInt();
151 }
152
153 template <typename T>
154 void URLUtils<T>::setHost(const String& value)
155 {
156     if (value.isEmpty())
157         return;
158     URL url = href();
159     if (url.cannotBeABaseURL())
160         return;
161     if (!url.canSetHostOrPort())
162         return;
163
164     size_t separator = value.find(':');
165     if (!separator)
166         return;
167
168     if (separator == notFound)
169         url.setHostAndPort(value);
170     else {
171         unsigned portEnd;
172         unsigned port = parsePortFromStringPosition(value, separator + 1, portEnd);
173         if (!port) {
174             // http://dev.w3.org/html5/spec/infrastructure.html#url-decomposition-idl-attributes
175             // specifically goes against RFC 3986 (p3.2) and
176             // requires setting the port to "0" if it is set to empty string.
177             url.setHostAndPort(value.substring(0, separator + 1) + '0');
178         } else {
179             if (WTF::isDefaultPortForProtocol(port, url.protocol()))
180                 url.setHostAndPort(value.substring(0, separator));
181             else
182                 url.setHostAndPort(value.substring(0, portEnd));
183         }
184     }
185     setHref(url.string());
186 }
187
188 template <typename T>
189 String URLUtils<T>::hostname() const
190 {
191     return href().host().toString();
192 }
193
194 template <typename T>
195 void URLUtils<T>::setHostname(const String& value)
196 {
197     // Before setting new value:
198     // Remove all leading U+002F SOLIDUS ("/") characters.
199     unsigned i = 0;
200     unsigned hostLength = value.length();
201     while (value[i] == '/')
202         i++;
203
204     if (i == hostLength)
205         return;
206
207     URL url = href();
208     if (url.cannotBeABaseURL())
209         return;
210     if (!url.canSetHostOrPort())
211         return;
212
213     url.setHost(value.substring(i));
214     setHref(url.string());
215 }
216
217 template <typename T>
218 String URLUtils<T>::port() const
219 {
220     if (href().port())
221         return String::number(href().port().value());
222
223     return emptyString();
224 }
225
226 template <typename T>
227 void URLUtils<T>::setPort(const String& value)
228 {
229     URL url = href();
230     if (url.cannotBeABaseURL() || url.protocolIs("file"))
231         return;
232     if (!url.canSetHostOrPort())
233         return;
234
235     // http://dev.w3.org/html5/spec/infrastructure.html#url-decomposition-idl-attributes
236     // specifically goes against RFC 3986 (p3.2) and
237     // requires setting the port to "0" if it is set to empty string.
238     // FIXME: http://url.spec.whatwg.org/ doesn't appear to require this; test what browsers do
239     unsigned port = value.toUInt();
240     if (WTF::isDefaultPortForProtocol(port, url.protocol()))
241         url.removePort();
242     else
243         url.setPort(port);
244
245     setHref(url.string());
246 }
247
248 template <typename T>
249 String URLUtils<T>::pathname() const
250 {
251     return href().path();
252 }
253
254 template <typename T>
255 void URLUtils<T>::setPathname(const String& value)
256 {
257     URL url = href();
258     if (url.cannotBeABaseURL())
259         return;
260     if (!url.canSetPathname())
261         return;
262
263     if (value[0U] == '/')
264         url.setPath(value);
265     else
266         url.setPath("/" + value);
267
268     setHref(url.string());
269 }
270
271 template <typename T>
272 String URLUtils<T>::search() const
273 {
274     String query = href().query();
275     return query.isEmpty() ? emptyString() : "?" + query;
276 }
277
278 template <typename T>
279 void URLUtils<T>::setSearch(const String& value)
280 {
281     URL url = href();
282     if (value.isEmpty()) {
283         // If the given value is the empty string, set url's query to null.
284         url.setQuery({ });
285     } else {
286         String newSearch = (value[0U] == '?') ? value.substring(1) : value;
287         // Make sure that '#' in the query does not leak to the hash.
288         url.setQuery(newSearch.replaceWithLiteral('#', "%23"));
289     }
290
291     setHref(url.string());
292 }
293
294 template <typename T>
295 String URLUtils<T>::hash() const
296 {
297     String fragmentIdentifier = href().fragmentIdentifier();
298     if (fragmentIdentifier.isEmpty())
299         return emptyString();
300     return AtomString(String("#" + fragmentIdentifier));
301 }
302
303 template <typename T>
304 void URLUtils<T>::setHash(const String& value)
305 {
306     URL url = href();
307     String newFragment = value[0U] == '#' ? value.substring(1) : value;
308     if (newFragment.isEmpty())
309         url.removeFragmentIdentifier();
310     else
311         url.setFragmentIdentifier(newFragment);
312     setHref(url.string());
313 }
314
315 } // namespace WebCore