| 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 |