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