url_canon_mailtourl.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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
  3. // found in the LICENSE file.
  4. // Functions for canonicalizing "mailto:" URLs.
  5. #include "url/url_canon.h"
  6. #include "url/url_canon_internal.h"
  7. #include "url/url_file.h"
  8. #include "url/url_parse_internal.h"
  9. namespace url {
  10. namespace {
  11. // Certain characters should be percent-encoded when they appear in the path
  12. // component of a mailto URL, to improve compatibility and mitigate against
  13. // command-injection attacks on mailto handlers. See https://crbug.com/711020.
  14. template <typename UCHAR>
  15. bool ShouldEncodeMailboxCharacter(UCHAR uch) {
  16. if (uch < 0x21 || // space & control characters.
  17. uch > 0x7e || // high-ascii characters.
  18. uch == 0x22 || // quote.
  19. uch == 0x3c || uch == 0x3e || // angle brackets.
  20. uch == 0x60 || // backtick.
  21. uch == 0x7b || uch == 0x7c || uch == 0x7d // braces and pipe.
  22. ) {
  23. return true;
  24. }
  25. return false;
  26. }
  27. template <typename CHAR, typename UCHAR>
  28. bool DoCanonicalizeMailtoURL(const URLComponentSource<CHAR>& source,
  29. const Parsed& parsed,
  30. CanonOutput* output,
  31. Parsed* new_parsed) {
  32. // mailto: only uses {scheme, path, query} -- clear the rest.
  33. new_parsed->username = Component();
  34. new_parsed->password = Component();
  35. new_parsed->host = Component();
  36. new_parsed->port = Component();
  37. new_parsed->ref = Component();
  38. // Scheme (known, so we don't bother running it through the more
  39. // complicated scheme canonicalizer).
  40. new_parsed->scheme.begin = output->length();
  41. output->Append("mailto:", 7);
  42. new_parsed->scheme.len = 6;
  43. bool success = true;
  44. // Path
  45. if (parsed.path.is_valid()) {
  46. new_parsed->path.begin = output->length();
  47. // Copy the path using path URL's more lax escaping rules.
  48. // We convert to UTF-8 and escape non-ASCII, but leave most
  49. // ASCII characters alone.
  50. size_t end = static_cast<size_t>(parsed.path.end());
  51. for (size_t i = static_cast<size_t>(parsed.path.begin); i < end; ++i) {
  52. UCHAR uch = static_cast<UCHAR>(source.path[i]);
  53. if (ShouldEncodeMailboxCharacter<UCHAR>(uch))
  54. success &= AppendUTF8EscapedChar(source.path, &i, end, output);
  55. else
  56. output->push_back(static_cast<char>(uch));
  57. }
  58. new_parsed->path.len = output->length() - new_parsed->path.begin;
  59. } else {
  60. // No path at all
  61. new_parsed->path.reset();
  62. }
  63. // Query -- always use the default UTF8 charset converter.
  64. CanonicalizeQuery(source.query, parsed.query, NULL,
  65. output, &new_parsed->query);
  66. return success;
  67. }
  68. } // namespace
  69. bool CanonicalizeMailtoURL(const char* spec,
  70. int spec_len,
  71. const Parsed& parsed,
  72. CanonOutput* output,
  73. Parsed* new_parsed) {
  74. return DoCanonicalizeMailtoURL<char, unsigned char>(
  75. URLComponentSource<char>(spec), parsed, output, new_parsed);
  76. }
  77. bool CanonicalizeMailtoURL(const char16_t* spec,
  78. int spec_len,
  79. const Parsed& parsed,
  80. CanonOutput* output,
  81. Parsed* new_parsed) {
  82. return DoCanonicalizeMailtoURL<char16_t, char16_t>(
  83. URLComponentSource<char16_t>(spec), parsed, output, new_parsed);
  84. }
  85. bool ReplaceMailtoURL(const char* base,
  86. const Parsed& base_parsed,
  87. const Replacements<char>& replacements,
  88. CanonOutput* output,
  89. Parsed* new_parsed) {
  90. URLComponentSource<char> source(base);
  91. Parsed parsed(base_parsed);
  92. SetupOverrideComponents(base, replacements, &source, &parsed);
  93. return DoCanonicalizeMailtoURL<char, unsigned char>(
  94. source, parsed, output, new_parsed);
  95. }
  96. bool ReplaceMailtoURL(const char* base,
  97. const Parsed& base_parsed,
  98. const Replacements<char16_t>& replacements,
  99. CanonOutput* output,
  100. Parsed* new_parsed) {
  101. RawCanonOutput<1024> utf8;
  102. URLComponentSource<char> source(base);
  103. Parsed parsed(base_parsed);
  104. SetupUTF16OverrideComponents(base, replacements, &utf8, &source, &parsed);
  105. return DoCanonicalizeMailtoURL<char, unsigned char>(
  106. source, parsed, output, new_parsed);
  107. }
  108. } // namespace url