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
5// Functions for canonicalizing "mailto:" URLs.
6
7#include "url/url_canon.h"
8#include "url/url_canon_internal.h"
9#include "url/url_file.h"
10#include "url/url_parse_internal.h"
11
12namespace url {
13
14namespace {
15
16template <typename CHAR, typename UCHAR>
17bool DoCanonicalizeMailtoURL(const URLComponentSource<CHAR>& source,
18                             const Parsed& parsed,
19                             CanonOutput* output,
20                             Parsed* new_parsed) {
21  // mailto: only uses {scheme, path, query} -- clear the rest.
22  new_parsed->username = Component();
23  new_parsed->password = Component();
24  new_parsed->host = Component();
25  new_parsed->port = Component();
26  new_parsed->ref = Component();
27
28  // Scheme (known, so we don't bother running it through the more
29  // complicated scheme canonicalizer).
30  new_parsed->scheme.begin = output->length();
31  output->Append("mailto:", 7);
32  new_parsed->scheme.len = 6;
33
34  bool success = true;
35
36  // Path
37  if (parsed.path.is_valid()) {
38    new_parsed->path.begin = output->length();
39
40    // Copy the path using path URL's more lax escaping rules.
41    // We convert to UTF-8 and escape non-ASCII, but leave all
42    // ASCII characters alone.
43    int end = parsed.path.end();
44    for (int i = parsed.path.begin; i < end; ++i) {
45      UCHAR uch = static_cast<UCHAR>(source.path[i]);
46      if (uch < 0x20 || uch >= 0x80)
47        success &= AppendUTF8EscapedChar(source.path, &i, end, output);
48      else
49        output->push_back(static_cast<char>(uch));
50    }
51
52    new_parsed->path.len = output->length() - new_parsed->path.begin;
53  } else {
54    // No path at all
55    new_parsed->path.reset();
56  }
57
58  // Query -- always use the default utf8 charset converter.
59  CanonicalizeQuery(source.query, parsed.query, NULL,
60                    output, &new_parsed->query);
61
62  return success;
63}
64
65} // namespace
66
67bool CanonicalizeMailtoURL(const char* spec,
68                           int spec_len,
69                           const Parsed& parsed,
70                           CanonOutput* output,
71                           Parsed* new_parsed) {
72  return DoCanonicalizeMailtoURL<char, unsigned char>(
73      URLComponentSource<char>(spec), parsed, output, new_parsed);
74}
75
76bool CanonicalizeMailtoURL(const base::char16* spec,
77                           int spec_len,
78                           const Parsed& parsed,
79                           CanonOutput* output,
80                           Parsed* new_parsed) {
81  return DoCanonicalizeMailtoURL<base::char16, base::char16>(
82      URLComponentSource<base::char16>(spec), parsed, output, new_parsed);
83}
84
85bool 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
97bool ReplaceMailtoURL(const char* base,
98                      const Parsed& base_parsed,
99                      const Replacements<base::char16>& replacements,
100                      CanonOutput* output,
101                      Parsed* new_parsed) {
102  RawCanonOutput<1024> utf8;
103  URLComponentSource<char> source(base);
104  Parsed parsed(base_parsed);
105  SetupUTF16OverrideComponents(base, replacements, &utf8, &source, &parsed);
106  return DoCanonicalizeMailtoURL<char, unsigned char>(
107      source, parsed, output, new_parsed);
108}
109
110}  // namespace url
111