OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "url/url_util.h" | 5 #include "url/url_util.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <vector> | |
10 | 9 |
11 #include "base/debug/leak_annotations.h" | 10 #include "base/debug/leak_annotations.h" |
12 #include "base/logging.h" | 11 #include "base/logging.h" |
13 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
14 #include "url/url_canon_internal.h" | 13 #include "url/url_canon_internal.h" |
| 14 #include "url/url_constants.h" |
15 #include "url/url_file.h" | 15 #include "url/url_file.h" |
16 #include "url/url_util_internal.h" | 16 #include "url/url_util_internal.h" |
17 | 17 |
18 namespace url { | 18 namespace url { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 // Pass this enum through for methods which would like to know if whitespace | 22 // Pass this enum through for methods which would like to know if whitespace |
23 // removal is necessary. | 23 // removal is necessary. |
24 enum WhitespaceRemovalPolicy { | 24 enum WhitespaceRemovalPolicy { |
25 REMOVE_WHITESPACE, | 25 REMOVE_WHITESPACE, |
26 DO_NOT_REMOVE_WHITESPACE, | 26 DO_NOT_REMOVE_WHITESPACE, |
27 }; | 27 }; |
28 | 28 |
29 const int kNumStandardURLSchemes = 10; | 29 const SchemeWithType kStandardURLSchemes[] = { |
30 const SchemeWithType kStandardURLSchemes[kNumStandardURLSchemes] = { | |
31 {kHttpScheme, SCHEME_WITH_PORT}, | 30 {kHttpScheme, SCHEME_WITH_PORT}, |
32 {kHttpsScheme, SCHEME_WITH_PORT}, | 31 {kHttpsScheme, SCHEME_WITH_PORT}, |
33 // Yes, file URLs can have a hostname, so file URLs should be handled as | 32 // Yes, file URLs can have a hostname, so file URLs should be handled as |
34 // "standard". File URLs never have a port as specified by the SchemeType | 33 // "standard". File URLs never have a port as specified by the SchemeType |
35 // field. | 34 // field. |
36 {kFileScheme, SCHEME_WITHOUT_PORT}, | 35 {kFileScheme, SCHEME_WITHOUT_PORT}, |
37 {kFtpScheme, SCHEME_WITH_PORT}, | 36 {kFtpScheme, SCHEME_WITH_PORT}, |
38 {kGopherScheme, SCHEME_WITH_PORT}, | 37 {kGopherScheme, SCHEME_WITH_PORT}, |
39 {kWsScheme, SCHEME_WITH_PORT}, // WebSocket. | 38 {kWsScheme, SCHEME_WITH_PORT}, // WebSocket. |
40 {kWssScheme, SCHEME_WITH_PORT}, // WebSocket secure. | 39 {kWssScheme, SCHEME_WITH_PORT}, // WebSocket secure. |
41 {kFileSystemScheme, SCHEME_WITHOUT_AUTHORITY}, | 40 {kFileSystemScheme, SCHEME_WITHOUT_AUTHORITY}, |
42 {kHttpSuboriginScheme, SCHEME_WITH_PORT}, | 41 {kHttpSuboriginScheme, SCHEME_WITH_PORT}, |
43 {kHttpsSuboriginScheme, SCHEME_WITH_PORT}, | 42 {kHttpsSuboriginScheme, SCHEME_WITH_PORT}, |
44 }; | 43 }; |
45 | 44 |
46 const int kNumReferrerURLSchemes = 4; | 45 const SchemeWithType kReferrerURLSchemes[] = { |
47 const SchemeWithType kReferrerURLSchemes[kNumReferrerURLSchemes] = { | |
48 {kHttpScheme, SCHEME_WITH_PORT}, | 46 {kHttpScheme, SCHEME_WITH_PORT}, |
49 {kHttpsScheme, SCHEME_WITH_PORT}, | 47 {kHttpsScheme, SCHEME_WITH_PORT}, |
50 {kHttpSuboriginScheme, SCHEME_WITH_PORT}, | 48 {kHttpSuboriginScheme, SCHEME_WITH_PORT}, |
51 {kHttpsSuboriginScheme, SCHEME_WITH_PORT}, | 49 {kHttpsSuboriginScheme, SCHEME_WITH_PORT}, |
52 }; | 50 }; |
53 | 51 |
| 52 const char* kSecureSchemes[] = { |
| 53 kHttpsScheme, |
| 54 kAboutScheme, |
| 55 kDataScheme, |
| 56 kWssScheme, |
| 57 }; |
| 58 |
| 59 const char* kLocalSchemes[] = { |
| 60 kFileScheme, |
| 61 }; |
| 62 |
| 63 const char* kNoAccessSchemes[] = { |
| 64 kAboutScheme, |
| 65 kJavaScriptScheme, |
| 66 kDataScheme, |
| 67 }; |
| 68 |
| 69 const char* kCORSEnabledSchemes[] = { |
| 70 kHttpScheme, |
| 71 kHttpsScheme, |
| 72 kDataScheme, |
| 73 }; |
| 74 |
| 75 bool initialized = false; |
| 76 |
54 // Lists of the currently installed standard and referrer schemes. These lists | 77 // Lists of the currently installed standard and referrer schemes. These lists |
55 // are lazily initialized by InitStandardSchemes and InitReferrerSchemes and are | 78 // are lazily initialized by Initialize and are leaked on shutdown to prevent |
56 // leaked on shutdown to prevent any destructors from being called that will | 79 // any destructors from being called that will slow us down or cause problems. |
57 // slow us down or cause problems. | |
58 std::vector<SchemeWithType>* standard_schemes = nullptr; | 80 std::vector<SchemeWithType>* standard_schemes = nullptr; |
59 std::vector<SchemeWithType>* referrer_schemes = nullptr; | 81 std::vector<SchemeWithType>* referrer_schemes = nullptr; |
60 | 82 |
| 83 // Similar to above, initialized by the Init*Schemes methods. |
| 84 std::vector<std::string>* secure_schemes = nullptr; |
| 85 std::vector<std::string>* local_schemes = nullptr; |
| 86 std::vector<std::string>* no_access_schemes = nullptr; |
| 87 std::vector<std::string>* cors_enabled_schemes = nullptr; |
| 88 |
61 // See the LockSchemeRegistries declaration in the header. | 89 // See the LockSchemeRegistries declaration in the header. |
62 bool scheme_registries_locked = false; | 90 bool scheme_registries_locked = false; |
63 | 91 |
64 // This template converts a given character type to the corresponding | 92 // This template converts a given character type to the corresponding |
65 // StringPiece type. | 93 // StringPiece type. |
66 template<typename CHAR> struct CharToStringPiece { | 94 template<typename CHAR> struct CharToStringPiece { |
67 }; | 95 }; |
68 template<> struct CharToStringPiece<char> { | 96 template<> struct CharToStringPiece<char> { |
69 typedef base::StringPiece Piece; | 97 typedef base::StringPiece Piece; |
70 }; | 98 }; |
71 template<> struct CharToStringPiece<base::char16> { | 99 template<> struct CharToStringPiece<base::char16> { |
72 typedef base::StringPiece16 Piece; | 100 typedef base::StringPiece16 Piece; |
73 }; | 101 }; |
74 | 102 |
75 void InitSchemes(std::vector<SchemeWithType>** schemes, | 103 void InitSchemes(std::vector<std::string>** schemes, |
76 const SchemeWithType* initial_schemes, | 104 const char** initial_schemes, |
77 size_t size) { | 105 size_t size) { |
78 if (*schemes) | 106 *schemes = new std::vector<std::string>(size); |
79 return; | |
80 *schemes = new std::vector<SchemeWithType>(size); | |
81 for (size_t i = 0; i < size; i++) { | 107 for (size_t i = 0; i < size; i++) { |
82 (*schemes)->push_back(initial_schemes[i]); | 108 (*(*schemes))[i] = initial_schemes[i]; |
83 } | 109 } |
84 } | 110 } |
85 | 111 |
86 // Ensures that the standard_schemes list is initialized, does nothing if | 112 void InitSchemesWithType(std::vector<SchemeWithType>** schemes, |
87 // it already has values. | 113 const SchemeWithType* initial_schemes, |
88 void InitStandardSchemes() { | 114 size_t size) { |
89 InitSchemes(&standard_schemes, kStandardURLSchemes, kNumStandardURLSchemes); | 115 *schemes = new std::vector<SchemeWithType>(size); |
90 } | 116 for (size_t i = 0; i < size; i++) { |
91 | 117 (*(*schemes))[i] = initial_schemes[i]; |
92 // Ensures that the referrer_schemes list is initialized, does nothing if | 118 } |
93 // it already has values. | |
94 void InitReferrerSchemes() { | |
95 InitSchemes(&referrer_schemes, kReferrerURLSchemes, kNumReferrerURLSchemes); | |
96 } | 119 } |
97 | 120 |
98 // Given a string and a range inside the string, compares it to the given | 121 // Given a string and a range inside the string, compares it to the given |
99 // lower-case |compare_to| buffer. | 122 // lower-case |compare_to| buffer. |
100 template<typename CHAR> | 123 template<typename CHAR> |
101 inline bool DoCompareSchemeComponent(const CHAR* spec, | 124 inline bool DoCompareSchemeComponent(const CHAR* spec, |
102 const Component& component, | 125 const Component& component, |
103 const char* compare_to) { | 126 const char* compare_to) { |
104 if (!component.is_nonempty()) | 127 if (!component.is_nonempty()) |
105 return compare_to[0] == 0; // When component is empty, match empty scheme. | 128 return compare_to[0] == 0; // When component is empty, match empty scheme. |
(...skipping 19 matching lines...) Expand all Loading... |
125 scheme_with_type.scheme)) { | 148 scheme_with_type.scheme)) { |
126 *type = scheme_with_type.type; | 149 *type = scheme_with_type.type; |
127 return true; | 150 return true; |
128 } | 151 } |
129 } | 152 } |
130 return false; | 153 return false; |
131 } | 154 } |
132 | 155 |
133 template<typename CHAR> | 156 template<typename CHAR> |
134 bool DoIsStandard(const CHAR* spec, const Component& scheme, SchemeType* type) { | 157 bool DoIsStandard(const CHAR* spec, const Component& scheme, SchemeType* type) { |
135 InitStandardSchemes(); | 158 Initialize(); |
136 return DoIsInSchemes(spec, scheme, type, *standard_schemes); | 159 return DoIsInSchemes(spec, scheme, type, *standard_schemes); |
137 } | 160 } |
138 | 161 |
139 | 162 |
140 template<typename CHAR> | 163 template<typename CHAR> |
141 bool DoFindAndCompareScheme(const CHAR* str, | 164 bool DoFindAndCompareScheme(const CHAR* str, |
142 int str_len, | 165 int str_len, |
143 const char* compare, | 166 const char* compare, |
144 Component* found_scheme) { | 167 Component* found_scheme) { |
145 // Before extracting scheme, canonicalize the URL to remove any whitespace. | 168 // Before extracting scheme, canonicalize the URL to remove any whitespace. |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 output, out_parsed); | 419 output, out_parsed); |
397 } | 420 } |
398 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) { | 421 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) { |
399 return ReplaceMailtoURL(spec, parsed, replacements, output, out_parsed); | 422 return ReplaceMailtoURL(spec, parsed, replacements, output, out_parsed); |
400 } | 423 } |
401 | 424 |
402 // Default is a path URL. | 425 // Default is a path URL. |
403 return ReplacePathURL(spec, parsed, replacements, output, out_parsed); | 426 return ReplacePathURL(spec, parsed, replacements, output, out_parsed); |
404 } | 427 } |
405 | 428 |
406 void DoAddScheme(const char* new_scheme, | 429 void DoAddScheme(const char* new_scheme, std::vector<std::string>* schemes) { |
407 SchemeType type, | |
408 std::vector<SchemeWithType>* schemes) { | |
409 DCHECK(schemes); | 430 DCHECK(schemes); |
410 // If this assert triggers, it means you've called Add*Scheme after | 431 // If this assert triggers, it means you've called Add*Scheme after |
411 // LockSchemeRegistries has been called (see the header file for | 432 // LockSchemeRegistries has been called (see the header file for |
412 // LockSchemeRegistries for more). | 433 // LockSchemeRegistries for more). |
413 // | 434 // |
414 // This normally means you're trying to set up a new scheme too late in your | 435 // This normally means you're trying to set up a new scheme too late in your |
415 // application's init process. Locate where your app does this initialization | 436 // application's init process. Locate where your app does this initialization |
416 // and calls LockSchemeRegistries, and add your new scheme there. | 437 // and calls LockSchemeRegistries, and add your new scheme there. |
417 DCHECK(!scheme_registries_locked) | 438 DCHECK(!scheme_registries_locked) |
418 << "Trying to add a scheme after the lists have been locked."; | 439 << "Trying to add a scheme after the lists have been locked."; |
419 | 440 |
420 size_t scheme_len = strlen(new_scheme); | 441 size_t scheme_len = strlen(new_scheme); |
421 if (scheme_len == 0) | 442 if (scheme_len == 0) |
422 return; | 443 return; |
423 | 444 |
| 445 DCHECK_EQ(base::ToLowerASCII(new_scheme), new_scheme); |
| 446 schemes->push_back(std::string(new_scheme)); |
| 447 } |
| 448 |
| 449 void DoAddSchemeWithType(const char* new_scheme, |
| 450 SchemeType type, |
| 451 std::vector<SchemeWithType>* schemes) { |
| 452 DCHECK(schemes); |
| 453 // If this assert triggers, it means you've called Add*Scheme after |
| 454 // LockSchemeRegistries has been called (see the header file for |
| 455 // LockSchemeRegistries for more). |
| 456 // |
| 457 // This normally means you're trying to set up a new scheme too late in your |
| 458 // application's init process. Locate where your app does this initialization |
| 459 // and calls LockSchemeRegistries, and add your new scheme there. |
| 460 DCHECK(!scheme_registries_locked) |
| 461 << "Trying to add a scheme after the lists have been locked."; |
| 462 |
| 463 size_t scheme_len = strlen(new_scheme); |
| 464 if (scheme_len == 0) |
| 465 return; |
| 466 |
| 467 DCHECK_EQ(base::ToLowerASCII(new_scheme), new_scheme); |
424 // Duplicate the scheme into a new buffer and add it to the list of standard | 468 // Duplicate the scheme into a new buffer and add it to the list of standard |
425 // schemes. This pointer will be leaked on shutdown. | 469 // schemes. This pointer will be leaked on shutdown. |
426 char* dup_scheme = new char[scheme_len + 1]; | 470 char* dup_scheme = new char[scheme_len + 1]; |
427 ANNOTATE_LEAKING_OBJECT_PTR(dup_scheme); | 471 ANNOTATE_LEAKING_OBJECT_PTR(dup_scheme); |
428 memcpy(dup_scheme, new_scheme, scheme_len + 1); | 472 memcpy(dup_scheme, new_scheme, scheme_len + 1); |
429 | 473 |
430 SchemeWithType scheme_with_type; | 474 SchemeWithType scheme_with_type; |
431 scheme_with_type.scheme = dup_scheme; | 475 scheme_with_type.scheme = dup_scheme; |
432 scheme_with_type.type = type; | 476 scheme_with_type.type = type; |
433 schemes->push_back(scheme_with_type); | 477 schemes->push_back(scheme_with_type); |
434 } | 478 } |
435 | 479 |
436 } // namespace | 480 } // namespace |
437 | 481 |
438 void Initialize() { | 482 void Initialize() { |
439 InitStandardSchemes(); | 483 if (initialized) |
440 InitReferrerSchemes(); | 484 return; |
| 485 InitSchemesWithType(&standard_schemes, kStandardURLSchemes, |
| 486 arraysize(kStandardURLSchemes)); |
| 487 InitSchemesWithType(&referrer_schemes, kReferrerURLSchemes, |
| 488 arraysize(kReferrerURLSchemes)); |
| 489 InitSchemes(&secure_schemes, kSecureSchemes, arraysize(kSecureSchemes)); |
| 490 InitSchemes(&local_schemes, kLocalSchemes, arraysize(kLocalSchemes)); |
| 491 InitSchemes(&no_access_schemes, kNoAccessSchemes, |
| 492 arraysize(kNoAccessSchemes)); |
| 493 InitSchemes(&cors_enabled_schemes, kCORSEnabledSchemes, |
| 494 arraysize(kCORSEnabledSchemes)); |
| 495 initialized = true; |
441 } | 496 } |
442 | 497 |
443 void Shutdown() { | 498 void Shutdown() { |
444 if (standard_schemes) { | 499 initialized = false; |
445 delete standard_schemes; | 500 delete standard_schemes; |
446 standard_schemes = NULL; | 501 standard_schemes = nullptr; |
447 } | 502 delete referrer_schemes; |
448 if (referrer_schemes) { | 503 referrer_schemes = nullptr; |
449 delete referrer_schemes; | 504 delete secure_schemes; |
450 referrer_schemes = NULL; | 505 secure_schemes = nullptr; |
451 } | 506 delete local_schemes; |
| 507 local_schemes = nullptr; |
| 508 delete no_access_schemes; |
| 509 no_access_schemes = nullptr; |
| 510 delete cors_enabled_schemes; |
| 511 cors_enabled_schemes = nullptr; |
452 } | 512 } |
453 | 513 |
454 void AddStandardScheme(const char* new_scheme, SchemeType type) { | 514 void AddStandardScheme(const char* new_scheme, SchemeType type) { |
455 InitStandardSchemes(); | 515 Initialize(); |
456 DoAddScheme(new_scheme, type, standard_schemes); | 516 DoAddSchemeWithType(new_scheme, type, standard_schemes); |
457 } | 517 } |
458 | 518 |
459 void AddReferrerScheme(const char* new_scheme, SchemeType type) { | 519 void AddReferrerScheme(const char* new_scheme, SchemeType type) { |
460 InitReferrerSchemes(); | 520 Initialize(); |
461 DoAddScheme(new_scheme, type, referrer_schemes); | 521 DoAddSchemeWithType(new_scheme, type, referrer_schemes); |
| 522 } |
| 523 |
| 524 void AddSecureScheme(const char* new_scheme) { |
| 525 Initialize(); |
| 526 DoAddScheme(new_scheme, secure_schemes); |
| 527 } |
| 528 |
| 529 const std::vector<std::string>& GetSecureSchemes() { |
| 530 Initialize(); |
| 531 return *secure_schemes; |
| 532 } |
| 533 |
| 534 void AddLocalScheme(const char* new_scheme) { |
| 535 Initialize(); |
| 536 DoAddScheme(new_scheme, local_schemes); |
| 537 } |
| 538 |
| 539 const std::vector<std::string>& GetLocalSchemes() { |
| 540 Initialize(); |
| 541 return *local_schemes; |
| 542 } |
| 543 |
| 544 void AddNoAccessScheme(const char* new_scheme) { |
| 545 Initialize(); |
| 546 DoAddScheme(new_scheme, no_access_schemes); |
| 547 } |
| 548 |
| 549 const std::vector<std::string>& GetNoAccessSchemes() { |
| 550 Initialize(); |
| 551 return *no_access_schemes; |
| 552 } |
| 553 |
| 554 void AddCORSEnabledScheme(const char* new_scheme) { |
| 555 Initialize(); |
| 556 DoAddScheme(new_scheme, cors_enabled_schemes); |
| 557 } |
| 558 |
| 559 const std::vector<std::string>& GetCORSEnabledSchemes() { |
| 560 Initialize(); |
| 561 return *cors_enabled_schemes; |
462 } | 562 } |
463 | 563 |
464 void LockSchemeRegistries() { | 564 void LockSchemeRegistries() { |
465 scheme_registries_locked = true; | 565 scheme_registries_locked = true; |
466 } | 566 } |
467 | 567 |
468 bool IsStandard(const char* spec, const Component& scheme) { | 568 bool IsStandard(const char* spec, const Component& scheme) { |
469 SchemeType unused_scheme_type; | 569 SchemeType unused_scheme_type; |
470 return DoIsStandard(spec, scheme, &unused_scheme_type); | 570 return DoIsStandard(spec, scheme, &unused_scheme_type); |
471 } | 571 } |
472 | 572 |
473 bool GetStandardSchemeType(const char* spec, | 573 bool GetStandardSchemeType(const char* spec, |
474 const Component& scheme, | 574 const Component& scheme, |
475 SchemeType* type) { | 575 SchemeType* type) { |
476 return DoIsStandard(spec, scheme, type); | 576 return DoIsStandard(spec, scheme, type); |
477 } | 577 } |
478 | 578 |
479 bool IsStandard(const base::char16* spec, const Component& scheme) { | 579 bool IsStandard(const base::char16* spec, const Component& scheme) { |
480 SchemeType unused_scheme_type; | 580 SchemeType unused_scheme_type; |
481 return DoIsStandard(spec, scheme, &unused_scheme_type); | 581 return DoIsStandard(spec, scheme, &unused_scheme_type); |
482 } | 582 } |
483 | 583 |
484 bool IsReferrerScheme(const char* spec, const Component& scheme) { | 584 bool IsReferrerScheme(const char* spec, const Component& scheme) { |
485 InitReferrerSchemes(); | 585 Initialize(); |
486 SchemeType unused_scheme_type; | 586 SchemeType unused_scheme_type; |
487 return DoIsInSchemes(spec, scheme, &unused_scheme_type, *referrer_schemes); | 587 return DoIsInSchemes(spec, scheme, &unused_scheme_type, *referrer_schemes); |
488 } | 588 } |
489 | 589 |
490 bool FindAndCompareScheme(const char* str, | 590 bool FindAndCompareScheme(const char* str, |
491 int str_len, | 591 int str_len, |
492 const char* compare, | 592 const char* compare, |
493 Component* found_scheme) { | 593 Component* found_scheme) { |
494 return DoFindAndCompareScheme(str, str_len, compare, found_scheme); | 594 return DoFindAndCompareScheme(str, str_len, compare, found_scheme); |
495 } | 595 } |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 return DoCompareSchemeComponent(spec, component, compare_to); | 780 return DoCompareSchemeComponent(spec, component, compare_to); |
681 } | 781 } |
682 | 782 |
683 bool CompareSchemeComponent(const base::char16* spec, | 783 bool CompareSchemeComponent(const base::char16* spec, |
684 const Component& component, | 784 const Component& component, |
685 const char* compare_to) { | 785 const char* compare_to) { |
686 return DoCompareSchemeComponent(spec, component, compare_to); | 786 return DoCompareSchemeComponent(spec, component, compare_to); |
687 } | 787 } |
688 | 788 |
689 } // namespace url | 789 } // namespace url |
OLD | NEW |