Move URL from WebCore to WTF
[WebKit-https.git] / Source / WTF / wtf / URL.h
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2013 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include <wtf/Forward.h>
29 #include <wtf/RetainPtr.h>
30 #include <wtf/text/WTFString.h>
31
32 #if USE(CF)
33 typedef const struct __CFURL* CFURLRef;
34 #endif
35
36 #if USE(SOUP)
37 #include <wtf/glib/GUniquePtrSoup.h>
38 #endif
39
40 #if USE(FOUNDATION)
41 OBJC_CLASS NSURL;
42 #endif
43
44 namespace WTF {
45 class TextStream;
46
47 class URLTextEncoding {
48 public:
49     virtual Vector<uint8_t> encodeForURLParsing(StringView) const = 0;
50     virtual ~URLTextEncoding() { };
51 };
52
53 struct URLHash;
54
55 class WTF_EXPORT_PRIVATE URL {
56 public:
57     // Generates a URL which contains a null string.
58     URL() { invalidate(); }
59
60     explicit URL(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { }
61     bool isHashTableDeletedValue() const { return string().isHashTableDeletedValue(); }
62
63     // Resolves the relative URL with the given base URL. If provided, the
64     // URLTextEncoding is used to encode non-ASCII characers. The base URL can be
65     // null or empty, in which case the relative URL will be interpreted as
66     // absolute.
67     // FIXME: If the base URL is invalid, this always creates an invalid
68     // URL. Instead I think it would be better to treat all invalid base URLs
69     // the same way we treate null and empty base URLs.
70     URL(const URL& base, const String& relative, const URLTextEncoding* = nullptr);
71
72     static URL fakeURLWithRelativePart(const String&);
73     static URL fileURLWithFileSystemPath(const String&);
74
75     String strippedForUseAsReferrer() const;
76
77     // FIXME: The above functions should be harmonized so that passing a
78     // base of null or the empty string gives the same result as the
79     // standard String constructor.
80
81     // Makes a deep copy. Helpful only if you need to use a URL on another
82     // thread. Since the underlying StringImpl objects are immutable, there's
83     // no other reason to ever prefer isolatedCopy() over plain old assignment.
84     URL isolatedCopy() const;
85
86     bool isNull() const;
87     bool isEmpty() const;
88     bool isValid() const;
89
90     // Returns true if you can set the host and port for the URL.
91     // Non-hierarchical URLs don't have a host and port.
92     bool canSetHostOrPort() const { return isHierarchical(); }
93
94     bool canSetPathname() const { return isHierarchical(); }
95     bool isHierarchical() const;
96
97     const String& string() const { return m_string; }
98
99     String stringCenterEllipsizedToLength(unsigned length = 1024) const;
100
101     StringView protocol() const;
102     StringView host() const;
103     std::optional<uint16_t> port() const;
104     String hostAndPort() const;
105     String protocolHostAndPort() const;
106     String user() const;
107     String pass() const;
108     String path() const;
109     String lastPathComponent() const;
110     String query() const;
111     String fragmentIdentifier() const;
112     bool hasFragmentIdentifier() const;
113
114     bool hasUsername() const;
115     bool hasPassword() const;
116     bool hasQuery() const;
117     bool hasFragment() const;
118     bool hasPath() const;
119
120     // Unlike user() and pass(), these functions don't decode escape sequences.
121     // This is necessary for accurate round-tripping, because encoding doesn't encode '%' characters.
122     String encodedUser() const;
123     String encodedPass() const;
124
125     String baseAsString() const;
126
127     String fileSystemPath() const;
128
129     // Returns true if the current URL's protocol is the same as the null-
130     // terminated ASCII argument. The argument must be lower-case.
131     bool protocolIs(const char*) const;
132     bool protocolIs(StringView) const;
133     bool protocolIsBlob() const { return protocolIs("blob"); }
134     bool protocolIsData() const { return protocolIs("data"); }
135     bool protocolIsAbout() const;
136     bool protocolIsInHTTPFamily() const;
137     bool isLocalFile() const;
138     bool isBlankURL() const;
139     bool cannotBeABaseURL() const { return m_cannotBeABaseURL; }
140
141     bool isMatchingDomain(const String&) const;
142
143     bool setProtocol(const String&);
144     void setHost(const String&);
145
146     void removePort();
147     void setPort(unsigned short);
148
149     // Input is like "foo.com" or "foo.com:8000".
150     void setHostAndPort(const String&);
151
152     void setUser(const String&);
153     void setPass(const String&);
154
155     // If you pass an empty path for HTTP or HTTPS URLs, the resulting path
156     // will be "/".
157     void setPath(const String&);
158
159     // The query may begin with a question mark, or, if not, one will be added
160     // for you. Setting the query to the empty string will leave a "?" in the
161     // URL (with nothing after it). To clear the query, pass a null string.
162     void setQuery(const String&);
163
164     void setFragmentIdentifier(StringView);
165     void removeFragmentIdentifier();
166
167     void removeQueryAndFragmentIdentifier();
168
169     static bool hostIsIPAddress(StringView);
170
171     unsigned pathStart() const;
172     unsigned pathEnd() const;
173     unsigned pathAfterLastSlash() const;
174
175     operator const String&() const { return string(); }
176
177 #if USE(CF)
178     URL(CFURLRef);
179     RetainPtr<CFURLRef> createCFURL() const;
180 #endif
181
182 #if USE(SOUP)
183     URL(SoupURI*);
184     GUniquePtr<SoupURI> createSoupURI() const;
185 #endif
186
187 #if USE(FOUNDATION)
188     URL(NSURL*);
189     operator NSURL*() const;
190 #endif
191 #ifdef __OBJC__
192     operator NSString*() const { return string(); }
193 #endif
194
195 #ifndef NDEBUG
196     void print() const;
197 #endif
198
199     template <class Encoder> void encode(Encoder&) const;
200     template <class Decoder> static bool decode(Decoder&, URL&);
201     template <class Decoder> static std::optional<URL> decode(Decoder&);
202
203 private:
204     friend class URLParser;
205     void invalidate();
206     static bool protocolIs(const String&, const char*);
207     void copyToBuffer(Vector<char, 512>& buffer) const;
208     unsigned hostStart() const;
209
210     friend WTF_EXPORT_PRIVATE bool equalIgnoringFragmentIdentifier(const URL&, const URL&);
211     friend WTF_EXPORT_PRIVATE bool protocolHostAndPortAreEqual(const URL&, const URL&);
212     friend WTF_EXPORT_PRIVATE bool hostsAreEqual(const URL&, const URL&);
213
214     String m_string;
215
216     unsigned m_isValid : 1;
217     unsigned m_protocolIsInHTTPFamily : 1;
218     unsigned m_cannotBeABaseURL : 1;
219
220     // This is out of order to align the bits better. The port is after the host.
221     unsigned m_portLength : 3;
222     static constexpr unsigned maxPortLength = (1 << 3) - 1;
223
224     static constexpr unsigned maxSchemeLength = (1 << 26) - 1;
225     unsigned m_schemeEnd : 26;
226     unsigned m_userStart;
227     unsigned m_userEnd;
228     unsigned m_passwordEnd;
229     unsigned m_hostEnd;
230     unsigned m_pathAfterLastSlash;
231     unsigned m_pathEnd;
232     unsigned m_queryEnd;
233 };
234
235 static_assert(sizeof(URL) == sizeof(String) + 8 * sizeof(unsigned), "URL should stay small");
236
237 template <class Encoder>
238 void URL::encode(Encoder& encoder) const
239 {
240     encoder << m_string;
241 }
242
243 template <class Decoder>
244 bool URL::decode(Decoder& decoder, URL& url)
245 {
246     auto optionalURL = URL::decode(decoder);
247     if (!optionalURL)
248         return false;
249     url = WTFMove(*optionalURL);
250     return true;
251 }
252
253 template <class Decoder>
254 std::optional<URL> URL::decode(Decoder& decoder)
255 {
256     String string;
257     if (!decoder.decode(string))
258         return std::nullopt;
259     return URL(URL(), string);
260 }
261
262 WTF_EXPORT_PRIVATE bool equalIgnoringFragmentIdentifier(const URL&, const URL&);
263 WTF_EXPORT_PRIVATE bool equalIgnoringQueryAndFragment(const URL&, const URL&);
264 WTF_EXPORT_PRIVATE bool protocolHostAndPortAreEqual(const URL&, const URL&);
265 WTF_EXPORT_PRIVATE bool hostsAreEqual(const URL&, const URL&);
266
267 WTF_EXPORT_PRIVATE const URL& blankURL();
268
269 // Functions to do URL operations on strings.
270 // These are operations that aren't faster on a parsed URL.
271 // These are also different from the URL functions in that they don't require the string to be a valid and parsable URL.
272 // This is especially important because valid javascript URLs are not necessarily considered valid by URL.
273
274 WTF_EXPORT_PRIVATE bool protocolIs(const String& url, const char* protocol);
275 WTF_EXPORT_PRIVATE bool protocolIsJavaScript(const String& url);
276 WTF_EXPORT_PRIVATE bool protocolIsJavaScript(StringView url);
277 WTF_EXPORT_PRIVATE bool protocolIsInHTTPFamily(const String& url);
278
279 WTF_EXPORT_PRIVATE std::optional<uint16_t> defaultPortForProtocol(StringView protocol);
280 WTF_EXPORT_PRIVATE bool isDefaultPortForProtocol(uint16_t port, StringView protocol);
281 WTF_EXPORT_PRIVATE bool portAllowed(const URL&); // Blacklist ports that should never be used for Web resources.
282
283 WTF_EXPORT_PRIVATE void registerDefaultPortForProtocolForTesting(uint16_t port, const String& protocol);
284 WTF_EXPORT_PRIVATE void clearDefaultPortForProtocolMapForTesting();
285
286 WTF_EXPORT_PRIVATE bool isValidProtocol(const String&);
287
288 WTF_EXPORT_PRIVATE String mimeTypeFromDataURL(const String& url);
289
290 // FIXME: This is a wrong concept to expose, different parts of a URL need different escaping per the URL Standard.
291 WTF_EXPORT_PRIVATE String encodeWithURLEscapeSequences(const String&);
292
293 // Inlines.
294
295 inline bool operator==(const URL& a, const URL& b)
296 {
297     return a.string() == b.string();
298 }
299
300 inline bool operator==(const URL& a, const String& b)
301 {
302     return a.string() == b;
303 }
304
305 inline bool operator==(const String& a, const URL& b)
306 {
307     return a == b.string();
308 }
309
310 inline bool operator!=(const URL& a, const URL& b)
311 {
312     return a.string() != b.string();
313 }
314
315 inline bool operator!=(const URL& a, const String& b)
316 {
317     return a.string() != b;
318 }
319
320 inline bool operator!=(const String& a, const URL& b)
321 {
322     return a != b.string();
323 }
324
325 // Inline versions of some non-GoogleURL functions so we can get inlining
326 // without having to have a lot of ugly ifdefs in the class definition.
327
328 inline bool URL::isNull() const
329 {
330     return m_string.isNull();
331 }
332
333 inline bool URL::isEmpty() const
334 {
335     return m_string.isEmpty();
336 }
337
338 inline bool URL::isValid() const
339 {
340     return m_isValid;
341 }
342
343 inline bool URL::hasPath() const
344 {
345     return m_pathEnd != m_hostEnd + m_portLength;
346 }
347
348 inline bool URL::hasUsername() const
349 {
350     return m_userEnd > m_userStart;
351 }
352
353 inline bool URL::hasPassword() const
354 {
355     return m_passwordEnd > (m_userEnd + 1);
356 }
357
358 inline bool URL::hasQuery() const
359 {
360     return m_queryEnd > m_pathEnd;
361 }
362
363 inline bool URL::hasFragment() const
364 {
365     return m_isValid && m_string.length() > m_queryEnd;
366 }
367
368 inline bool URL::protocolIsInHTTPFamily() const
369 {
370     return m_protocolIsInHTTPFamily;
371 }
372
373 inline unsigned URL::pathStart() const
374 {
375     return m_hostEnd + m_portLength;
376 }
377
378 inline unsigned URL::pathEnd() const
379 {
380     return m_pathEnd;
381 }
382
383 inline unsigned URL::pathAfterLastSlash() const
384 {
385     return m_pathAfterLastSlash;
386 }
387
388 WTF_EXPORT_PRIVATE WTF::TextStream& operator<<(WTF::TextStream&, const URL&);
389
390 template<> struct DefaultHash<URL>;
391 template<> struct HashTraits<URL>;
392
393 } // namespace WTF