Integrate most of GoogleURL in WTFURL
[WebKit-https.git] / Source / WTF / wtf / url / src / URLCanonEtc.cpp
1 /*
2  * Copyright 2007 Google Inc. All rights reserved.
3  * Copyright 2012 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 // Canonicalizers for random bits that aren't big enough for their own files.
33
34 #include "config.h"
35 #include "URLCanon.h"
36
37 #include "URLCanonInternal.h"
38 #include <wtf/ASCIICType.h>
39
40 #if USE(WTFURL)
41
42 namespace WTF {
43
44 namespace URLCanonicalizer {
45
46 namespace {
47
48 // Returns true if the given character should be removed from the middle of a
49 // URL.
50 inline bool isRemovableURLWhitespace(int character)
51 {
52     return character == '\r' || character == '\n' || character == '\t';
53 }
54
55 // Backend for removeURLWhitespace (see declaration in URLCanon.h).
56 // It sucks that we have to do this, since this takes about 13% of the total URL
57 // canonicalization time.
58 template<typename CharacterType>
59 const CharacterType* doRemoveURLWhitespace(const CharacterType* input, int inputLength, URLBuffer<CharacterType>& buffer, int& outputLength)
60 {
61     // Fast verification that there's nothing that needs removal. This is the 99%
62     // case, so we want it to be fast and don't care about impacting the speed
63     // when we do find whitespace.
64     bool foundWhitespace = false;
65     for (int i = 0; i < inputLength; ++i) {
66         if (!isRemovableURLWhitespace(input[i]))
67             continue;
68         foundWhitespace = true;
69         break;
70     }
71
72     if (!foundWhitespace) {
73         // Didn't find any whitespace, we don't need to do anything. We can just
74         // return the input as the output.
75         outputLength = inputLength;
76         return input;
77     }
78
79     // Remove the whitespace into the new buffer and return it.
80     for (int i = 0; i < inputLength; i++) {
81         if (!isRemovableURLWhitespace(input[i]))
82             buffer.append(input[i]);
83     }
84     outputLength = buffer.length();
85     return buffer.data();
86 }
87
88 // Contains the canonical version of each possible input letter in the scheme
89 // (basically, lower-cased). The corresponding entry will be 0 if the letter
90 // is not allowed in a scheme.
91 const char kSchemeCanonical[0x80] = {
92 // 00-1f: all are invalid
93      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
94      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
95 //  ' '   !    "    #    $    %    &    '    (    )    *    +    ,    -    .    /
96      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  '+',  0,  '-', '.',  0,
97 //   0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ?
98     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
99 //   @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O
100      0 , 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
101 //   P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _
102     'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',  0,   0 ,  0,   0 ,  0,
103 //   `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o
104      0 , 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
105 //   p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~
106     'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',  0 ,  0 ,  0 ,  0 ,  0 };
107
108 // This could be a table lookup as well by setting the high bit for each
109 // valid character, but it's only called once per URL, and it makes the lookup
110 // table easier to read not having extra stuff in it.
111 inline bool isSchemeFirstChar(unsigned char character)
112 {
113     return isASCIIAlpha(character);
114 }
115
116 template<typename CharacterType, typename UCHAR>
117 bool doScheme(const CharacterType* spec, const URLComponent& scheme, URLBuffer<char>& output, URLComponent& outputScheme)
118 {
119     if (scheme.length() <= 0) {
120         // Scheme is unspecified or empty, convert to empty by appending a colon.
121         outputScheme = URLComponent(output.length(), 0);
122         output.append(':');
123         return true;
124     }
125
126     // The output scheme starts from the current position.
127     outputScheme.setBegin(outputScheme.begin() + output.length());
128
129     // Danger: it's important that this code does not strip any characters: it
130     // only emits the canonical version (be it valid or escaped) of each of
131     // the input characters. Stripping would put it out of sync with
132     // URLUtilities::FindAndCompareScheme, which could cause some security checks on
133     // schemes to be incorrect.
134     bool success = true;
135     int end = scheme.end();
136     for (int i = scheme.begin(); i < end; ++i) {
137         UCHAR character = static_cast<UCHAR>(spec[i]);
138         char replacement = 0;
139         if (character < 0x80) {
140             if (i == scheme.begin()) {
141                 // Need to do a special check for the first letter of the scheme.
142                 if (isSchemeFirstChar(static_cast<unsigned char>(character)))
143                     replacement = kSchemeCanonical[character];
144             } else
145                 replacement = kSchemeCanonical[character];
146         }
147
148         if (replacement)
149             output.append(replacement);
150         else if (character == '%') {
151             // Canonicalizing the scheme multiple times should lead to the same
152             // result. Since invalid characters will be escaped, we need to preserve
153             // the percent to avoid multiple escaping. The scheme will be invalid.
154             success = false;
155             output.append('%');
156         } else {
157             // Invalid character, store it but mark this scheme as invalid.
158             success = false;
159
160             // This will escape the output and also handle encoding issues.
161             // Ignore the return value since we already failed.
162             AppendUTF8EscapedChar(spec, &i, end, output);
163         }
164     }
165
166     // The output scheme ends with the the current position, before appending
167     // the colon.
168     outputScheme.setLength(output.length() - outputScheme.begin());
169     output.append(':');
170     return success;
171 }
172
173 // The username and password components reference ranges in the corresponding
174 // *_spec strings. Typically, these specs will be the same (we're
175 // canonicalizing a single source string), but may be different when
176 // replacing components.
177 template<typename CharacterType, typename UCHAR>
178 bool doUserInfo(const CharacterType* usernameSpec,
179                 const URLComponent& username,
180                 const CharacterType* passwordSpec,
181                 const URLComponent& password,
182                 URLBuffer<char>& output,
183                 URLComponent& outputUsername,
184                 URLComponent& outputPassword)
185 {
186     if (username.length() <= 0 && password.length() <= 0) {
187         // Common case: no user info. We strip empty username/passwords.
188         outputUsername = URLComponent();
189         outputPassword = URLComponent();
190         return true;
191     }
192
193     // Write the username.
194     outputUsername.setBegin(output.length());
195     if (username.length() > 0) {
196         // This will escape characters not valid for the username.
197         appendStringOfType(&usernameSpec[username.begin()], username.length(), URLCharacterTypes::UserInfoCharacter, output);
198     }
199     outputUsername.setLength(output.length() - outputUsername.begin());
200
201     // When there is a password, we need the separator. Note that we strip
202     // empty but specified passwords.
203     if (password.length() > 0) {
204         output.append(':');
205         outputPassword.setBegin(output.length());
206         appendStringOfType(&passwordSpec[password.begin()], password.length(), URLCharacterTypes::UserInfoCharacter, output);
207         outputPassword.setLength(output.length() - outputPassword.begin());
208     } else
209         outputPassword = URLComponent();
210
211     output.append('@');
212     return true;
213 }
214
215 // Helper functions for converting port integers to strings.
216 inline void writePortInt(char* output, int outputLength, int port)
217 {
218     _itoa_s(port, output, outputLength, 10);
219 }
220
221 // This function will prepend the colon if there will be a port.
222 template<typename CharacterType, typename UCHAR>
223 bool doPort(const CharacterType* spec,
224             const URLComponent& port,
225             int defaultPortForScheme,
226             URLBuffer<char>& output,
227             URLComponent& outputPortComponent)
228 {
229     int portNumber = URLParser::ParsePort(spec, port);
230     if (portNumber == URLParser::PORT_UNSPECIFIED || portNumber == defaultPortForScheme) {
231         outputPortComponent = URLComponent();
232         return true; // Leave port empty.
233     }
234
235     if (portNumber == URLParser::PORT_INVALID) {
236         // Invalid port: We'll copy the text from the input so the user can see
237         // what the error was, and mark the URL as invalid by returning false.
238         output.append(':');
239         outputPortComponent.setBegin(output.length());
240         AppendInvalidNarrowString(spec, port.begin(), port.end(), output);
241         outputPortComponent.setLength(output.length() - outputPortComponent.begin());
242         return false;
243     }
244
245     // Convert port number back to an integer. Max port value is 5 digits, and
246     // the Parsed::ExtractPort will have made sure the integer is in range.
247     const int bufferSize = 6;
248     char buffer[bufferSize];
249     writePortInt(buffer, bufferSize, portNumber);
250
251     // Append the port number to the output, preceeded by a colon.
252     output.append(':');
253     outputPortComponent.setBegin(output.length());
254     for (int i = 0; i < bufferSize && buffer[i]; ++i)
255         output.append(buffer[i]);
256
257     outputPortComponent.setLength(output.length() - outputPortComponent.begin());
258     return true;
259 }
260
261 template<typename CharacterType, typename UCHAR>
262 void doCanonicalizeFragment(const CharacterType* spec, const URLComponent& fragment, URLBuffer<char>& output, URLComponent& outputFragment)
263 {
264     if (fragment.length() < 0) {
265         // Common case of no fragment.
266         outputFragment = URLComponent();
267         return;
268     }
269
270     // Append the fragment separator. Note that we need to do this even when the fragment
271     // is empty but present.
272     output.append('#');
273     outputFragment.setBegin(output.length());
274
275     // Now iterate through all the characters, converting to UTF-8 and validating.
276     int end = fragment.end();
277     for (int i = fragment.begin(); i < end; ++i) {
278         if (!spec[i]) {
279             // IE just strips NULLs, so we do too.
280             continue;
281         }
282         if (static_cast<UCHAR>(spec[i]) < 0x20) {
283             // Unline IE seems to, we escape control characters. This will probably
284             // make the reference fragment unusable on a web page, but people
285             // shouldn't be using control characters in their anchor names.
286             appendURLEscapedCharacter(static_cast<unsigned char>(spec[i]), output);
287         } else if (static_cast<UCHAR>(spec[i]) < 0x80) {
288             // Normal ASCII characters are just appended.
289             output.append(static_cast<char>(spec[i]));
290         } else {
291             // Non-ASCII characters are appended unescaped, but only when they are
292             // valid. Invalid Unicode characters are replaced with the "invalid
293             // character" as IE seems to (readUTFChar puts the unicode replacement
294             // character in the output on failure for us).
295             unsigned codePoint;
296             readUTFChar(spec, &i, end, &codePoint);
297             AppendUTF8Value(codePoint, output);
298         }
299     }
300
301     outputFragment.setLength(output.length() - outputFragment.begin());
302 }
303
304 } // namespace
305
306 const char* removeURLWhitespace(const char* input, int inputLength, URLBuffer<char>& buffer, int& outputLength)
307 {
308     return doRemoveURLWhitespace(input, inputLength, buffer, outputLength);
309 }
310
311 const UChar* removeURLWhitespace(const UChar* input, int inputLength, URLBuffer<UChar>& buffer, int& outputLength)
312 {
313     return doRemoveURLWhitespace(input, inputLength, buffer, outputLength);
314 }
315
316 char canonicalSchemeChar(UChar character)
317 {
318     if (character >= 0x80)
319         return 0; // Non-ASCII is not supported by schemes.
320     return kSchemeCanonical[character];
321 }
322
323 bool canonicalizeScheme(const char* spec, const URLComponent& scheme, URLBuffer<char>& output, URLComponent& outputScheme)
324 {
325     return doScheme<char, unsigned char>(spec, scheme, output, outputScheme);
326 }
327
328 bool canonicalizeScheme(const UChar* spec, const URLComponent& scheme, URLBuffer<char>& output, URLComponent& outputScheme)
329 {
330     return doScheme<UChar, UChar>(spec, scheme, output, outputScheme);
331 }
332
333 bool canonicalizeUserInfo(const char* usernameSource, const URLComponent& username, const char* passwordSource, const URLComponent& password,
334                           URLBuffer<char>& output, URLComponent& outputUsername, URLComponent& outputPassword)
335 {
336     return doUserInfo<char, unsigned char>(usernameSource, username, passwordSource, password, output, outputUsername, outputPassword);
337 }
338
339 bool canonicalizeUserInfo(const UChar* usernameSource, const URLComponent& username, const UChar* passwordSource, const URLComponent& password,
340                           URLBuffer<char>& output, URLComponent& outputUsername, URLComponent& outputPassword)
341 {
342     return doUserInfo<UChar, UChar>(usernameSource, username, passwordSource, password, output, outputUsername, outputPassword);
343 }
344
345 bool canonicalizePort(const char* spec, const URLComponent& port, int defaultPortForScheme,
346                       URLBuffer<char>& output, URLComponent& outputPortComponent)
347 {
348     return doPort<char, unsigned char>(spec, port,
349                                        defaultPortForScheme,
350                                        output, outputPortComponent);
351 }
352
353 bool canonicalizePort(const UChar* spec, const URLComponent& port, int defaultPortForScheme,
354                       URLBuffer<char>& output, URLComponent& outputPortComponent)
355 {
356     return doPort<UChar, UChar>(spec, port, defaultPortForScheme,
357                                 output, outputPortComponent);
358 }
359
360 void canonicalizeFragment(const char* spec, const URLComponent& ref, URLBuffer<char>& output, URLComponent& outputFragment)
361 {
362     doCanonicalizeFragment<char, unsigned char>(spec, ref, output, outputFragment);
363 }
364
365 void canonicalizeFragment(const UChar* spec, const URLComponent& ref, URLBuffer<char>& output, URLComponent& outputFragment)
366 {
367     doCanonicalizeFragment<UChar, UChar>(spec, ref, output, outputFragment);
368 }
369
370 } // namespace URLCanonicalizer
371
372 } // namespace WTF
373
374 #endif // USE(WTFURL)