Integrate most of GoogleURL in WTFURL
[WebKit-https.git] / Source / WTF / wtf / url / src / URLCanonInternal.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 #include "config.h"
33 #include "URLCanonInternal.h"
34
35 #include <cstdio>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <string>
39
40 #if USE(WTFURL)
41
42 namespace WTF {
43
44 namespace URLCanonicalizer {
45
46 namespace {
47
48 template<typename CharacterType, typename UCHAR>
49 void doAppendStringOfType(const CharacterType* source, int length, URLCharacterTypes::CharacterTypes type, URLBuffer<char>& output)
50 {
51     for (int i = 0; i < length; ++i) {
52         if (static_cast<UCHAR>(source[i]) >= 0x80) {
53             // ReadChar will fill the code point with kUnicodeReplacementCharacter
54             // when the input is invalid, which is what we want.
55             unsigned codePoint;
56             readUTFChar(source, &i, length, &codePoint);
57             AppendUTF8EscapedValue(codePoint, output);
58         } else {
59             // Just append the 7-bit character, possibly escaping it.
60             unsigned char uch = static_cast<unsigned char>(source[i]);
61             if (!URLCharacterTypes::isCharacterOfType(uch, type))
62                 appendURLEscapedCharacter(uch, output);
63             else
64                 output.append(uch);
65         }
66     }
67 }
68
69 // This function assumes the input values are all contained in 8-bit,
70 // although it allows any type. Returns true if input is valid, false if not.
71 template<typename CharacterType, typename UCHAR>
72 void doAppendInvalidNarrowString(const CharacterType* spec, int begin, int end, URLBuffer<char>& output)
73 {
74     for (int i = begin; i < end; ++i) {
75         UCHAR uch = static_cast<UCHAR>(spec[i]);
76         if (uch >= 0x80) {
77             // Handle UTF-8/16 encodings. This call will correctly handle the error
78             // case by appending the invalid character.
79             AppendUTF8EscapedChar(spec, &i, end, output);
80         } else if (uch <= ' ' || uch == 0x7f) {
81             // This function is for error handling, so we escape all control
82             // characters and spaces, but not anything else since we lack
83             // context to do something more specific.
84             appendURLEscapedCharacter(static_cast<unsigned char>(uch), output);
85         } else
86             output.append(static_cast<char>(uch));
87     }
88 }
89
90 // Overrides one component, see the URLCanonicalizer::Replacements structure for
91 // what the various combionations of source pointer and component mean.
92 void doOverrideComponent(const char* overrideSource, const URLComponent& overrideComponent, const char*& destination, URLComponent& destinationComponent)
93 {
94     if (overrideSource) {
95         destination = overrideSource;
96         destinationComponent = overrideComponent;
97     }
98 }
99
100 // Similar to doOverrideComponent except that it takes a UTF-16 input and does
101 // not actually set the output character pointer.
102 //
103 // The input is converted to UTF-8 at the end of the given buffer as a temporary
104 // holding place. The component indentifying the portion of the buffer used in
105 // the |utf8Buffer| will be specified in |*destinationComponent|.
106 //
107 // This will not actually set any |dest| pointer like doOverrideComponent
108 // does because all of the pointers will point into the |utf8Buffer|, which
109 // may get resized while we're overriding a subsequent component. Instead, the
110 // caller should use the beginning of the |utf8Buffer| as the string pointer
111 // for all components once all overrides have been prepared.
112 bool PrepareUTF16OverrideComponent(const UChar* overrideSource,
113                                    const URLComponent& overrideComponent,
114                                    URLBuffer<char>& utf8Buffer,
115                                    URLComponent* destinationComponent)
116 {
117     bool success = true;
118     if (overrideSource) {
119         if (!overrideComponent.isValid()) {
120             // Non-"valid" component (means delete), so we need to preserve that.
121             *destinationComponent = URLComponent();
122         } else {
123             // Convert to UTF-8.
124             destinationComponent->setBegin(utf8Buffer.length());
125             success = ConvertUTF16ToUTF8(&overrideSource[overrideComponent.begin()],
126                                          overrideComponent.length(), utf8Buffer);
127             destinationComponent->setLength(utf8Buffer.length() - destinationComponent->begin());
128         }
129     }
130     return success;
131 }
132
133 } // namespace
134
135 const char kCharToHexLookup[8] = {
136     0, // 0x00 - 0x1f
137     '0', // 0x20 - 0x3f: digits 0 - 9 are 0x30 - 0x39
138     'A' - 10, // 0x40 - 0x5f: letters A - F are 0x41 - 0x46
139     'a' - 10, // 0x60 - 0x7f: letters a - f are 0x61 - 0x66
140     0, // 0x80 - 0x9F
141     0, // 0xA0 - 0xBF
142     0, // 0xC0 - 0xDF
143     0, // 0xE0 - 0xFF
144 };
145
146 const UChar kUnicodeReplacementCharacter = 0xfffd;
147
148 void appendStringOfType(const char* source, int length, URLCharacterTypes::CharacterTypes urlComponentType, URLBuffer<char>& output)
149 {
150     doAppendStringOfType<char, unsigned char>(source, length, urlComponentType, output);
151 }
152
153 void appendStringOfType(const UChar* source, int length, URLCharacterTypes::CharacterTypes urlComponentType, URLBuffer<char>& output)
154 {
155     doAppendStringOfType<UChar, UChar>(source, length, urlComponentType, output);
156 }
157
158 void AppendInvalidNarrowString(const char* spec, int begin, int end, URLBuffer<char>& output)
159 {
160     doAppendInvalidNarrowString<char, unsigned char>(spec, begin, end, output);
161 }
162
163 void AppendInvalidNarrowString(const UChar* spec, int begin, int end, URLBuffer<char>& output)
164 {
165     doAppendInvalidNarrowString<UChar, UChar>(spec, begin, end, output);
166 }
167
168 bool ConvertUTF16ToUTF8(const UChar* input, int inputLength, URLBuffer<char>& output)
169 {
170     bool success = true;
171     for (int i = 0; i < inputLength; ++i) {
172         unsigned codePoint;
173         success &= readUTFChar(input, &i, inputLength, &codePoint);
174         AppendUTF8Value(codePoint, output);
175     }
176     return success;
177 }
178
179 bool ConvertUTF8ToUTF16(const char* input, int inputLength, URLBuffer<UChar>& output)
180 {
181     bool success = true;
182     for (int i = 0; i < inputLength; i++) {
183         unsigned codePoint;
184         success &= readUTFChar(input, &i, inputLength, &codePoint);
185         AppendUTF16Value(codePoint, output);
186     }
187     return success;
188 }
189
190 void SetupOverrideComponents(const char* /* base */,
191                              const Replacements<char>& repl,
192                              URLComponentSource<char>* source,
193                              URLSegments* parsed)
194 {
195     // Get the source and parsed structures of the things we are replacing.
196     const URLComponentSource<char>& replSource = repl.sources();
197     const URLSegments& replParsed = repl.components();
198
199     doOverrideComponent(replSource.scheme, replParsed.scheme, source->scheme, parsed->scheme);
200     doOverrideComponent(replSource.username, replParsed.username, source->username, parsed->username);
201     doOverrideComponent(replSource.password, replParsed.password, source->password, parsed->password);
202
203     // Our host should be empty if not present, so override the default setup.
204     doOverrideComponent(replSource.host, replParsed.host, source->host, parsed->host);
205     if (parsed->host.length() == -1)
206         parsed->host.setLength(0);
207
208     doOverrideComponent(replSource.port, replParsed.port, source->port, parsed->port);
209     doOverrideComponent(replSource.path, replParsed.path, source->path, parsed->path);
210     doOverrideComponent(replSource.query, replParsed.query, source->query, parsed->query);
211     doOverrideComponent(replSource.ref, replParsed.fragment, source->ref, parsed->fragment);
212 }
213
214 bool SetupUTF16OverrideComponents(const char* /* base */,
215                                   const Replacements<UChar>& repl,
216                                   URLBuffer<char>& utf8Buffer,
217                                   URLComponentSource<char>* source,
218                                   URLSegments* parsed)
219     {
220         bool success = true;
221
222         // Get the source and parsed structures of the things we are replacing.
223         const URLComponentSource<UChar>& replSource = repl.sources();
224         const URLSegments& replParsed = repl.components();
225
226         success &= PrepareUTF16OverrideComponent(replSource.scheme, replParsed.scheme,
227                                                  utf8Buffer, &parsed->scheme);
228         success &= PrepareUTF16OverrideComponent(replSource.username, replParsed.username,
229                                                  utf8Buffer, &parsed->username);
230         success &= PrepareUTF16OverrideComponent(replSource.password, replParsed.password,
231                                                  utf8Buffer, &parsed->password);
232         success &= PrepareUTF16OverrideComponent(replSource.host, replParsed.host,
233                                                  utf8Buffer, &parsed->host);
234         success &= PrepareUTF16OverrideComponent(replSource.port, replParsed.port,
235                                                  utf8Buffer, &parsed->port);
236         success &= PrepareUTF16OverrideComponent(replSource.path, replParsed.path,
237                                                  utf8Buffer, &parsed->path);
238         success &= PrepareUTF16OverrideComponent(replSource.query, replParsed.query,
239                                                  utf8Buffer, &parsed->query);
240         success &= PrepareUTF16OverrideComponent(replSource.ref, replParsed.fragment,
241                                                  utf8Buffer, &parsed->fragment);
242
243         // PrepareUTF16OverrideComponent will not have set the data pointer since the
244         // buffer could be resized, invalidating the pointers. We set the data
245         // pointers for affected components now that the buffer is finalized.
246         if (replSource.scheme)
247             source->scheme = utf8Buffer.data();
248         if (replSource.username)
249             source->username = utf8Buffer.data();
250         if (replSource.password)
251             source->password = utf8Buffer.data();
252         if (replSource.host)
253             source->host = utf8Buffer.data();
254         if (replSource.port)
255             source->port = utf8Buffer.data();
256         if (replSource.path)
257             source->path = utf8Buffer.data();
258         if (replSource.query)
259             source->query = utf8Buffer.data();
260         if (replSource.ref)
261             source->ref = utf8Buffer.data();
262
263         return success;
264 }
265
266 #if !OS(WINDOWS)
267 int _itoa_s(int value, char* buffer, size_t sizeInChars, int radix)
268 {
269     int written;
270     if (radix == 10)
271         written = snprintf(buffer, sizeInChars, "%d", value);
272     else if (radix == 16)
273         written = snprintf(buffer, sizeInChars, "%x", value);
274     else
275         return EINVAL;
276
277     if (static_cast<size_t>(written) >= sizeInChars) {
278         // Output was truncated, or written was negative.
279         return EINVAL;
280     }
281     return 0;
282 }
283
284 int _itow_s(int value, UChar* buffer, size_t sizeInChars, int radix)
285 {
286     if (radix != 10)
287         return EINVAL;
288
289     // No more than 12 characters will be required for a 32-bit integer.
290     // Add an extra byte for the terminating null.
291     char temp[13];
292     int written = snprintf(temp, sizeof(temp), "%d", value);
293     if (static_cast<size_t>(written) >= sizeInChars) {
294         // Output was truncated, or written was negative.
295         return EINVAL;
296     }
297
298     for (int i = 0; i < written; ++i)
299         buffer[i] = static_cast<UChar>(temp[i]);
300     buffer[written] = '\0';
301     return 0;
302 }
303
304 #endif // !OS(WINDOWS)
305
306 } // namespace URLCanonicalizer
307
308 } // namespace WTF
309
310 #endif // USE(WTFURL)