1 /* Based on nsURLParsers.cc from Mozilla
2 * -------------------------------------
3 * The contents of this file are subject to the Mozilla Public License Version
4 * 1.1 (the "License"); you may not use this file except in compliance with
5 * the License. You may obtain a copy of the License at
6 * http://www.mozilla.org/MPL/
7 *
8 * Software distributed under the License is distributed on an "AS IS" basis,
9 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10 * for the specific language governing rights and limitations under the
11 * License.
12 *
13 * The Original Code is mozilla.org code.
14 *
15 * The Initial Developer of the Original Code is
16 * Netscape Communications Corporation.
17 * Portions created by the Initial Developer are Copyright (C) 1998
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Darin Fisher (original author)
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36
37 #include "googleurl/src/url_parse.h"
38
39 #include <stdlib.h>
40
41 #include "base/logging.h"
42 #include "googleurl/src/url_parse_internal.h"
43
44 namespace url_parse {
45
46 namespace {
47
48 // Returns true if the given character is a valid digit to use in a port.
IsPortDigit(char16 ch)49 inline bool IsPortDigit(char16 ch) {
50 return ch >= '0' && ch <= '9';
51 }
52
53 // Returns the offset of the next authority terminator in the input starting
54 // from start_offset. If no terminator is found, the return value will be equal
55 // to spec_len.
56 template<typename CHAR>
FindNextAuthorityTerminator(const CHAR * spec,int start_offset,int spec_len)57 int FindNextAuthorityTerminator(const CHAR* spec,
58 int start_offset,
59 int spec_len) {
60 for (int i = start_offset; i < spec_len; i++) {
61 if (IsAuthorityTerminator(spec[i]))
62 return i;
63 }
64 return spec_len; // Not found.
65 }
66
67 template<typename CHAR>
ParseUserInfo(const CHAR * spec,const Component & user,Component * username,Component * password)68 void ParseUserInfo(const CHAR* spec,
69 const Component& user,
70 Component* username,
71 Component* password) {
72 // Find the first colon in the user section, which separates the username and
73 // password.
74 int colon_offset = 0;
75 while (colon_offset < user.len && spec[user.begin + colon_offset] != ':')
76 colon_offset++;
77
78 if (colon_offset < user.len) {
79 // Found separator: <username>:<password>
80 *username = Component(user.begin, colon_offset);
81 *password = MakeRange(user.begin + colon_offset + 1,
82 user.begin + user.len);
83 } else {
84 // No separator, treat everything as the username
85 *username = user;
86 *password = Component();
87 }
88 }
89
90 template<typename CHAR>
ParseServerInfo(const CHAR * spec,const Component & serverinfo,Component * hostname,Component * port_num)91 void ParseServerInfo(const CHAR* spec,
92 const Component& serverinfo,
93 Component* hostname,
94 Component* port_num) {
95 if (serverinfo.len == 0) {
96 // No server info, host name is empty.
97 hostname->reset();
98 port_num->reset();
99 return;
100 }
101
102 // If the host starts with a left-bracket, assume the entire host is an
103 // IPv6 literal. Otherwise, assume none of the host is an IPv6 literal.
104 // This assumption will be overridden if we find a right-bracket.
105 //
106 // Our IPv6 address canonicalization code requires both brackets to exist,
107 // but the ability to locate an incomplete address can still be useful.
108 int ipv6_terminator = spec[serverinfo.begin] == '[' ? serverinfo.end() : -1;
109 int colon = -1;
110
111 // Find the last right-bracket, and the last colon.
112 for (int i = serverinfo.begin; i < serverinfo.end(); i++) {
113 switch (spec[i]) {
114 case ']':
115 ipv6_terminator = i;
116 break;
117 case ':':
118 colon = i;
119 break;
120 }
121 }
122
123 if (colon > ipv6_terminator) {
124 // Found a port number: <hostname>:<port>
125 *hostname = MakeRange(serverinfo.begin, colon);
126 if (hostname->len == 0)
127 hostname->reset();
128 *port_num = MakeRange(colon + 1, serverinfo.end());
129 } else {
130 // No port: <hostname>
131 *hostname = serverinfo;
132 port_num->reset();
133 }
134 }
135
136 // Given an already-identified auth section, breaks it into its consituent
137 // parts. The port number will be parsed and the resulting integer will be
138 // filled into the given *port variable, or -1 if there is no port number or it
139 // is invalid.
140 template<typename CHAR>
DoParseAuthority(const CHAR * spec,const Component & auth,Component * username,Component * password,Component * hostname,Component * port_num)141 void DoParseAuthority(const CHAR* spec,
142 const Component& auth,
143 Component* username,
144 Component* password,
145 Component* hostname,
146 Component* port_num) {
147 DCHECK(auth.is_valid()) << "We should always get an authority";
148 if (auth.len == 0) {
149 username->reset();
150 password->reset();
151 hostname->reset();
152 port_num->reset();
153 return;
154 }
155
156 // Search backwards for @, which is the separator between the user info and
157 // the server info.
158 int i = auth.begin + auth.len - 1;
159 while (i > auth.begin && spec[i] != '@')
160 i--;
161
162 if (spec[i] == '@') {
163 // Found user info: <user-info>@<server-info>
164 ParseUserInfo(spec, Component(auth.begin, i - auth.begin),
165 username, password);
166 ParseServerInfo(spec, MakeRange(i + 1, auth.begin + auth.len),
167 hostname, port_num);
168 } else {
169 // No user info, everything is server info.
170 username->reset();
171 password->reset();
172 ParseServerInfo(spec, auth, hostname, port_num);
173 }
174 }
175
176 template<typename CHAR>
ParsePath(const CHAR * spec,const Component & path,Component * filepath,Component * query,Component * ref)177 void ParsePath(const CHAR* spec,
178 const Component& path,
179 Component* filepath,
180 Component* query,
181 Component* ref) {
182 // path = [/]<segment1>/<segment2>/<...>/<segmentN>;<param>?<query>#<ref>
183
184 // Special case when there is no path.
185 if (path.len == -1) {
186 filepath->reset();
187 query->reset();
188 ref->reset();
189 return;
190 }
191 DCHECK(path.len > 0) << "We should never have 0 length paths";
192
193 // Search for first occurrence of either ? or #.
194 int path_end = path.begin + path.len;
195
196 int query_separator = -1; // Index of the '?'
197 int ref_separator = -1; // Index of the '#'
198 for (int i = path.begin; i < path_end; i++) {
199 switch (spec[i]) {
200 case '?':
201 // Only match the query string if it precedes the reference fragment
202 // and when we haven't found one already.
203 if (ref_separator < 0 && query_separator < 0)
204 query_separator = i;
205 break;
206 case '#':
207 // Record the first # sign only.
208 if (ref_separator < 0)
209 ref_separator = i;
210 break;
211 }
212 }
213
214 // Markers pointing to the character after each of these corresponding
215 // components. The code below words from the end back to the beginning,
216 // and will update these indices as it finds components that exist.
217 int file_end, query_end;
218
219 // Ref fragment: from the # to the end of the path.
220 if (ref_separator >= 0) {
221 file_end = query_end = ref_separator;
222 *ref = MakeRange(ref_separator + 1, path_end);
223 } else {
224 file_end = query_end = path_end;
225 ref->reset();
226 }
227
228 // Query fragment: everything from the ? to the next boundary (either the end
229 // of the path or the ref fragment).
230 if (query_separator >= 0) {
231 file_end = query_separator;
232 *query = MakeRange(query_separator + 1, query_end);
233 } else {
234 query->reset();
235 }
236
237 // File path: treat an empty file path as no file path.
238 if (file_end != path.begin)
239 *filepath = MakeRange(path.begin, file_end);
240 else
241 filepath->reset();
242 }
243
244 template<typename CHAR>
DoExtractScheme(const CHAR * url,int url_len,Component * scheme)245 bool DoExtractScheme(const CHAR* url,
246 int url_len,
247 Component* scheme) {
248 // Skip leading whitespace and control characters.
249 int begin = 0;
250 while (begin < url_len && ShouldTrimFromURL(url[begin]))
251 begin++;
252 if (begin == url_len)
253 return false; // Input is empty or all whitespace.
254
255 // Find the first colon character.
256 for (int i = begin; i < url_len; i++) {
257 if (url[i] == ':') {
258 *scheme = MakeRange(begin, i);
259 return true;
260 }
261 }
262 return false; // No colon found: no scheme
263 }
264
265 // Fills in all members of the Parsed structure except for the scheme.
266 //
267 // |spec| is the full spec being parsed, of length |spec_len|.
268 // |after_scheme| is the character immediately following the scheme (after the
269 // colon) where we'll begin parsing.
270 //
271 // Compatability data points. I list "host", "path" extracted:
272 // Input IE6 Firefox Us
273 // ----- -------------- -------------- --------------
274 // http://foo.com/ "foo.com", "/" "foo.com", "/" "foo.com", "/"
275 // http:foo.com/ "foo.com", "/" "foo.com", "/" "foo.com", "/"
276 // http:/foo.com/ fail(*) "foo.com", "/" "foo.com", "/"
277 // http:\foo.com/ fail(*) "\foo.com", "/"(fail) "foo.com", "/"
278 // http:////foo.com/ "foo.com", "/" "foo.com", "/" "foo.com", "/"
279 //
280 // (*) Interestingly, although IE fails to load these URLs, its history
281 // canonicalizer handles them, meaning if you've been to the corresponding
282 // "http://foo.com/" link, it will be colored.
283 template <typename CHAR>
DoParseAfterScheme(const CHAR * spec,int spec_len,int after_scheme,Parsed * parsed)284 void DoParseAfterScheme(const CHAR* spec,
285 int spec_len,
286 int after_scheme,
287 Parsed* parsed) {
288 int num_slashes = CountConsecutiveSlashes(spec, after_scheme, spec_len);
289 int after_slashes = after_scheme + num_slashes;
290
291 // First split into two main parts, the authority (username, password, host,
292 // and port) and the full path (path, query, and reference).
293 Component authority;
294 Component full_path;
295
296 // Found "//<some data>", looks like an authority section. Treat everything
297 // from there to the next slash (or end of spec) to be the authority. Note
298 // that we ignore the number of slashes and treat it as the authority.
299 int end_auth = FindNextAuthorityTerminator(spec, after_slashes, spec_len);
300 authority = Component(after_slashes, end_auth - after_slashes);
301
302 if (end_auth == spec_len) // No beginning of path found.
303 full_path = Component();
304 else // Everything starting from the slash to the end is the path.
305 full_path = Component(end_auth, spec_len - end_auth);
306
307 // Now parse those two sub-parts.
308 DoParseAuthority(spec, authority, &parsed->username, &parsed->password,
309 &parsed->host, &parsed->port);
310 ParsePath(spec, full_path, &parsed->path, &parsed->query, &parsed->ref);
311 }
312
313 // The main parsing function for standard URLs. Standard URLs have a scheme,
314 // host, path, etc.
315 template<typename CHAR>
DoParseStandardURL(const CHAR * spec,int spec_len,Parsed * parsed)316 void DoParseStandardURL(const CHAR* spec, int spec_len, Parsed* parsed) {
317 DCHECK(spec_len >= 0);
318
319 // Strip leading & trailing spaces and control characters.
320 int begin = 0;
321 TrimURL(spec, &begin, &spec_len);
322
323 int after_scheme;
324 if (DoExtractScheme(spec, spec_len, &parsed->scheme)) {
325 after_scheme = parsed->scheme.end() + 1; // Skip past the colon.
326 } else {
327 // Say there's no scheme when there is no colon. We could also say that
328 // everything is the scheme. Both would produce an invalid URL, but this way
329 // seems less wrong in more cases.
330 parsed->scheme.reset();
331 after_scheme = begin;
332 }
333 DoParseAfterScheme(spec, spec_len, after_scheme, parsed);
334 }
335
336 // Initializes a path URL which is merely a scheme followed by a path. Examples
337 // include "about:foo" and "javascript:alert('bar');"
338 template<typename CHAR>
DoParsePathURL(const CHAR * spec,int spec_len,Parsed * parsed)339 void DoParsePathURL(const CHAR* spec, int spec_len, Parsed* parsed) {
340 // Get the non-path and non-scheme parts of the URL out of the way, we never
341 // use them.
342 parsed->username.reset();
343 parsed->password.reset();
344 parsed->host.reset();
345 parsed->port.reset();
346 parsed->query.reset();
347 parsed->ref.reset();
348
349 // Strip leading & trailing spaces and control characters.
350 int begin = 0;
351 TrimURL(spec, &begin, &spec_len);
352
353 // Handle empty specs or ones that contain only whitespace or control chars.
354 if (begin == spec_len) {
355 parsed->scheme.reset();
356 parsed->path.reset();
357 return;
358 }
359
360 // Extract the scheme, with the path being everything following. We also
361 // handle the case where there is no scheme.
362 if (ExtractScheme(&spec[begin], spec_len - begin, &parsed->scheme)) {
363 // Offset the results since we gave ExtractScheme a substring.
364 parsed->scheme.begin += begin;
365
366 // For compatability with the standard URL parser, we treat no path as
367 // -1, rather than having a length of 0 (we normally wouldn't care so
368 // much for these non-standard URLs).
369 if (parsed->scheme.end() == spec_len - 1)
370 parsed->path.reset();
371 else
372 parsed->path = MakeRange(parsed->scheme.end() + 1, spec_len);
373 } else {
374 // No scheme found, just path.
375 parsed->scheme.reset();
376 parsed->path = MakeRange(begin, spec_len);
377 }
378 }
379
380 template<typename CHAR>
DoParseMailtoURL(const CHAR * spec,int spec_len,Parsed * parsed)381 void DoParseMailtoURL(const CHAR* spec, int spec_len, Parsed* parsed) {
382 DCHECK(spec_len >= 0);
383
384 // Get the non-path and non-scheme parts of the URL out of the way, we never
385 // use them.
386 parsed->username.reset();
387 parsed->password.reset();
388 parsed->host.reset();
389 parsed->port.reset();
390 parsed->ref.reset();
391 parsed->query.reset(); // May use this; reset for convenience.
392
393 // Strip leading & trailing spaces and control characters.
394 int begin = 0;
395 TrimURL(spec, &begin, &spec_len);
396
397 // Handle empty specs or ones that contain only whitespace or control chars.
398 if (begin == spec_len) {
399 parsed->scheme.reset();
400 parsed->path.reset();
401 return;
402 }
403
404 int path_begin = -1;
405 int path_end = -1;
406
407 // Extract the scheme, with the path being everything following. We also
408 // handle the case where there is no scheme.
409 if (ExtractScheme(&spec[begin], spec_len - begin, &parsed->scheme)) {
410 // Offset the results since we gave ExtractScheme a substring.
411 parsed->scheme.begin += begin;
412
413 if (parsed->scheme.end() != spec_len - 1) {
414 path_begin = parsed->scheme.end() + 1;
415 path_end = spec_len;
416 }
417 } else {
418 // No scheme found, just path.
419 parsed->scheme.reset();
420 path_begin = begin;
421 path_end = spec_len;
422 }
423
424 // Split [path_begin, path_end) into a path + query.
425 for (int i = path_begin; i < path_end; ++i) {
426 if (spec[i] == '?') {
427 parsed->query = MakeRange(i + 1, path_end);
428 path_end = i;
429 break;
430 }
431 }
432
433 // For compatability with the standard URL parser, treat no path as
434 // -1, rather than having a length of 0
435 if (path_begin == path_end) {
436 parsed->path.reset();
437 } else {
438 parsed->path = MakeRange(path_begin, path_end);
439 }
440 }
441
442 // Converts a port number in a string to an integer. We'd like to just call
443 // sscanf but our input is not NULL-terminated, which sscanf requires. Instead,
444 // we copy the digits to a small stack buffer (since we know the maximum number
445 // of digits in a valid port number) that we can NULL terminate.
446 template<typename CHAR>
DoParsePort(const CHAR * spec,const Component & component)447 int DoParsePort(const CHAR* spec, const Component& component) {
448 // Easy success case when there is no port.
449 const int kMaxDigits = 5;
450 if (!component.is_nonempty())
451 return PORT_UNSPECIFIED;
452
453 // Skip over any leading 0s.
454 Component digits_comp(component.end(), 0);
455 for (int i = 0; i < component.len; i++) {
456 if (spec[component.begin + i] != '0') {
457 digits_comp = MakeRange(component.begin + i, component.end());
458 break;
459 }
460 }
461 if (digits_comp.len == 0)
462 return 0; // All digits were 0.
463
464 // Verify we don't have too many digits (we'll be copying to our buffer so
465 // we need to double-check).
466 if (digits_comp.len > kMaxDigits)
467 return PORT_INVALID;
468
469 // Copy valid digits to the buffer.
470 char digits[kMaxDigits + 1]; // +1 for null terminator
471 for (int i = 0; i < digits_comp.len; i++) {
472 CHAR ch = spec[digits_comp.begin + i];
473 if (!IsPortDigit(ch)) {
474 // Invalid port digit, fail.
475 return PORT_INVALID;
476 }
477 digits[i] = static_cast<char>(ch);
478 }
479
480 // Null-terminate the string and convert to integer. Since we guarantee
481 // only digits, atoi's lack of error handling is OK.
482 digits[digits_comp.len] = 0;
483 int port = atoi(digits);
484 if (port > 65535)
485 return PORT_INVALID; // Out of range.
486 return port;
487 }
488
489 template<typename CHAR>
DoExtractFileName(const CHAR * spec,const Component & path,Component * file_name)490 void DoExtractFileName(const CHAR* spec,
491 const Component& path,
492 Component* file_name) {
493 // Handle empty paths: they have no file names.
494 if (!path.is_nonempty()) {
495 file_name->reset();
496 return;
497 }
498
499 // Search backwards for a parameter, which is a normally unused field in a
500 // URL delimited by a semicolon. We parse the parameter as part of the
501 // path, but here, we don't want to count it. The last semicolon is the
502 // parameter. The path should start with a slash, so we don't need to check
503 // the first one.
504 int file_end = path.end();
505 for (int i = path.end() - 1; i > path.begin; i--) {
506 if (spec[i] == ';') {
507 file_end = i;
508 break;
509 }
510 }
511
512 // Now search backwards from the filename end to the previous slash
513 // to find the beginning of the filename.
514 for (int i = file_end - 1; i >= path.begin; i--) {
515 if (IsURLSlash(spec[i])) {
516 // File name is everything following this character to the end
517 *file_name = MakeRange(i + 1, file_end);
518 return;
519 }
520 }
521
522 // No slash found, this means the input was degenerate (generally paths
523 // will start with a slash). Let's call everything the file name.
524 *file_name = MakeRange(path.begin, file_end);
525 return;
526 }
527
528 template<typename CHAR>
DoExtractQueryKeyValue(const CHAR * spec,Component * query,Component * key,Component * value)529 bool DoExtractQueryKeyValue(const CHAR* spec,
530 Component* query,
531 Component* key,
532 Component* value) {
533 if (!query->is_nonempty())
534 return false;
535
536 int start = query->begin;
537 int cur = start;
538 int end = query->end();
539
540 // We assume the beginning of the input is the beginning of the "key" and we
541 // skip to the end of it.
542 key->begin = cur;
543 while (cur < end && spec[cur] != '&' && spec[cur] != '=')
544 cur++;
545 key->len = cur - key->begin;
546
547 // Skip the separator after the key (if any).
548 if (cur < end && spec[cur] == '=')
549 cur++;
550
551 // Find the value part.
552 value->begin = cur;
553 while (cur < end && spec[cur] != '&')
554 cur++;
555 value->len = cur - value->begin;
556
557 // Finally skip the next separator if any
558 if (cur < end && spec[cur] == '&')
559 cur++;
560
561 // Save the new query
562 *query = url_parse::MakeRange(cur, end);
563 return true;
564 }
565
566 } // namespace
567
Parsed()568 Parsed::Parsed() {
569 }
570
Length() const571 int Parsed::Length() const {
572 if (ref.is_valid())
573 return ref.end();
574 return CountCharactersBefore(REF, false);
575 }
576
CountCharactersBefore(ComponentType type,bool include_delimiter) const577 int Parsed::CountCharactersBefore(ComponentType type,
578 bool include_delimiter) const {
579 if (type == SCHEME)
580 return scheme.begin;
581
582 // There will be some characters after the scheme like "://" and we don't
583 // know how many. Search forwards for the next thing until we find one.
584 int cur = 0;
585 if (scheme.is_valid())
586 cur = scheme.end() + 1; // Advance over the ':' at the end of the scheme.
587
588 if (username.is_valid()) {
589 if (type <= USERNAME)
590 return username.begin;
591 cur = username.end() + 1; // Advance over the '@' or ':' at the end.
592 }
593
594 if (password.is_valid()) {
595 if (type <= PASSWORD)
596 return password.begin;
597 cur = password.end() + 1; // Advance over the '@' at the end.
598 }
599
600 if (host.is_valid()) {
601 if (type <= HOST)
602 return host.begin;
603 cur = host.end();
604 }
605
606 if (port.is_valid()) {
607 if (type < PORT || (type == PORT && include_delimiter))
608 return port.begin - 1; // Back over delimiter.
609 if (type == PORT)
610 return port.begin; // Don't want delimiter counted.
611 cur = port.end();
612 }
613
614 if (path.is_valid()) {
615 if (type <= PATH)
616 return path.begin;
617 cur = path.end();
618 }
619
620 if (query.is_valid()) {
621 if (type < QUERY || (type == QUERY && include_delimiter))
622 return query.begin - 1; // Back over delimiter.
623 if (type == QUERY)
624 return query.begin; // Don't want delimiter counted.
625 cur = query.end();
626 }
627
628 if (ref.is_valid()) {
629 if (type == REF && !include_delimiter)
630 return ref.begin; // Back over delimiter.
631
632 // When there is a ref and we get here, the component we wanted was before
633 // this and not found, so we always know the beginning of the ref is right.
634 return ref.begin - 1; // Don't want delimiter counted.
635 }
636
637 return cur;
638 }
639
ExtractScheme(const char * url,int url_len,Component * scheme)640 bool ExtractScheme(const char* url, int url_len, Component* scheme) {
641 return DoExtractScheme(url, url_len, scheme);
642 }
643
ExtractScheme(const char16 * url,int url_len,Component * scheme)644 bool ExtractScheme(const char16* url, int url_len, Component* scheme) {
645 return DoExtractScheme(url, url_len, scheme);
646 }
647
648 // This handles everything that may be an authority terminator, including
649 // backslash. For special backslash handling see DoParseAfterScheme.
IsAuthorityTerminator(char16 ch)650 bool IsAuthorityTerminator(char16 ch) {
651 return IsURLSlash(ch) || ch == '?' || ch == '#';
652 }
653
ExtractFileName(const char * url,const Component & path,Component * file_name)654 void ExtractFileName(const char* url,
655 const Component& path,
656 Component* file_name) {
657 DoExtractFileName(url, path, file_name);
658 }
659
ExtractFileName(const char16 * url,const Component & path,Component * file_name)660 void ExtractFileName(const char16* url,
661 const Component& path,
662 Component* file_name) {
663 DoExtractFileName(url, path, file_name);
664 }
665
ExtractQueryKeyValue(const char * url,Component * query,Component * key,Component * value)666 bool ExtractQueryKeyValue(const char* url,
667 Component* query,
668 Component* key,
669 Component* value) {
670 return DoExtractQueryKeyValue(url, query, key, value);
671 }
672
ExtractQueryKeyValue(const char16 * url,Component * query,Component * key,Component * value)673 bool ExtractQueryKeyValue(const char16* url,
674 Component* query,
675 Component* key,
676 Component* value) {
677 return DoExtractQueryKeyValue(url, query, key, value);
678 }
679
ParseAuthority(const char * spec,const Component & auth,Component * username,Component * password,Component * hostname,Component * port_num)680 void ParseAuthority(const char* spec,
681 const Component& auth,
682 Component* username,
683 Component* password,
684 Component* hostname,
685 Component* port_num) {
686 DoParseAuthority(spec, auth, username, password, hostname, port_num);
687 }
688
ParseAuthority(const char16 * spec,const Component & auth,Component * username,Component * password,Component * hostname,Component * port_num)689 void ParseAuthority(const char16* spec,
690 const Component& auth,
691 Component* username,
692 Component* password,
693 Component* hostname,
694 Component* port_num) {
695 DoParseAuthority(spec, auth, username, password, hostname, port_num);
696 }
697
ParsePort(const char * url,const Component & port)698 int ParsePort(const char* url, const Component& port) {
699 return DoParsePort(url, port);
700 }
701
ParsePort(const char16 * url,const Component & port)702 int ParsePort(const char16* url, const Component& port) {
703 return DoParsePort(url, port);
704 }
705
ParseStandardURL(const char * url,int url_len,Parsed * parsed)706 void ParseStandardURL(const char* url, int url_len, Parsed* parsed) {
707 DoParseStandardURL(url, url_len, parsed);
708 }
709
ParseStandardURL(const char16 * url,int url_len,Parsed * parsed)710 void ParseStandardURL(const char16* url, int url_len, Parsed* parsed) {
711 DoParseStandardURL(url, url_len, parsed);
712 }
713
ParsePathURL(const char * url,int url_len,Parsed * parsed)714 void ParsePathURL(const char* url, int url_len, Parsed* parsed) {
715 DoParsePathURL(url, url_len, parsed);
716 }
717
ParsePathURL(const char16 * url,int url_len,Parsed * parsed)718 void ParsePathURL(const char16* url, int url_len, Parsed* parsed) {
719 DoParsePathURL(url, url_len, parsed);
720 }
721
ParseMailtoURL(const char * url,int url_len,Parsed * parsed)722 void ParseMailtoURL(const char* url, int url_len, Parsed* parsed) {
723 DoParseMailtoURL(url, url_len, parsed);
724 }
725
ParseMailtoURL(const char16 * url,int url_len,Parsed * parsed)726 void ParseMailtoURL(const char16* url, int url_len, Parsed* parsed) {
727 DoParseMailtoURL(url, url_len, parsed);
728 }
729
ParsePathInternal(const char * spec,const Component & path,Component * filepath,Component * query,Component * ref)730 void ParsePathInternal(const char* spec,
731 const Component& path,
732 Component* filepath,
733 Component* query,
734 Component* ref) {
735 ParsePath(spec, path, filepath, query, ref);
736 }
737
ParsePathInternal(const char16 * spec,const Component & path,Component * filepath,Component * query,Component * ref)738 void ParsePathInternal(const char16* spec,
739 const Component& path,
740 Component* filepath,
741 Component* query,
742 Component* ref) {
743 ParsePath(spec, path, filepath, query, ref);
744 }
745
ParseAfterScheme(const char * spec,int spec_len,int after_scheme,Parsed * parsed)746 void ParseAfterScheme(const char* spec,
747 int spec_len,
748 int after_scheme,
749 Parsed* parsed) {
750 DoParseAfterScheme(spec, spec_len, after_scheme, parsed);
751 }
752
ParseAfterScheme(const char16 * spec,int spec_len,int after_scheme,Parsed * parsed)753 void ParseAfterScheme(const char16* spec,
754 int spec_len,
755 int after_scheme,
756 Parsed* parsed) {
757 DoParseAfterScheme(spec, spec_len, after_scheme, parsed);
758 }
759
760 } // namespace url_parse
761