1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 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 #include <algorithm>
6*6777b538SAndroid Build Coastguard Worker #include <string>
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker #include "base/strings/escape.h"
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
13*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker namespace {
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker struct EscapeCase {
19*6777b538SAndroid Build Coastguard Worker const char* input;
20*6777b538SAndroid Build Coastguard Worker const char* output;
21*6777b538SAndroid Build Coastguard Worker };
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker struct EscapeForHTMLCase {
24*6777b538SAndroid Build Coastguard Worker const char* input;
25*6777b538SAndroid Build Coastguard Worker const char* expected_output;
26*6777b538SAndroid Build Coastguard Worker };
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker struct UnescapeURLCase {
29*6777b538SAndroid Build Coastguard Worker const char* input;
30*6777b538SAndroid Build Coastguard Worker UnescapeRule::Type rules;
31*6777b538SAndroid Build Coastguard Worker const char* output;
32*6777b538SAndroid Build Coastguard Worker };
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker struct UnescapeAndDecodeCase {
35*6777b538SAndroid Build Coastguard Worker const char* input;
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker // The expected output when run through UnescapeURL.
38*6777b538SAndroid Build Coastguard Worker const char* url_unescaped;
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker // The expected output when run through UnescapeQuery.
41*6777b538SAndroid Build Coastguard Worker const char* query_unescaped;
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker // The expected output when run through UnescapeAndDecodeURLComponent.
44*6777b538SAndroid Build Coastguard Worker const wchar_t* decoded;
45*6777b538SAndroid Build Coastguard Worker };
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker struct AdjustOffsetCase {
48*6777b538SAndroid Build Coastguard Worker const char* input;
49*6777b538SAndroid Build Coastguard Worker size_t input_offset;
50*6777b538SAndroid Build Coastguard Worker size_t output_offset;
51*6777b538SAndroid Build Coastguard Worker };
52*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapeTextForFormSubmission)53*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapeTextForFormSubmission) {
54*6777b538SAndroid Build Coastguard Worker const EscapeCase escape_cases[] = {
55*6777b538SAndroid Build Coastguard Worker {"foo", "foo"}, {"foo bar", "foo+bar"}, {"foo++", "foo%2B%2B"}};
56*6777b538SAndroid Build Coastguard Worker for (const auto& escape_case : escape_cases) {
57*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(escape_case.output,
58*6777b538SAndroid Build Coastguard Worker EscapeQueryParamValue(escape_case.input, true));
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker const EscapeCase escape_cases_no_plus[] = {
62*6777b538SAndroid Build Coastguard Worker {"foo", "foo"}, {"foo bar", "foo%20bar"}, {"foo++", "foo%2B%2B"}};
63*6777b538SAndroid Build Coastguard Worker for (const auto& escape_case : escape_cases_no_plus) {
64*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(escape_case.output,
65*6777b538SAndroid Build Coastguard Worker EscapeQueryParamValue(escape_case.input, false));
66*6777b538SAndroid Build Coastguard Worker }
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker // Test all the values in we're supposed to be escaping.
69*6777b538SAndroid Build Coastguard Worker const std::string no_escape(
70*6777b538SAndroid Build Coastguard Worker "abcdefghijklmnopqrstuvwxyz"
71*6777b538SAndroid Build Coastguard Worker "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
72*6777b538SAndroid Build Coastguard Worker "0123456789"
73*6777b538SAndroid Build Coastguard Worker "!'()*-._~");
74*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 256; ++i) {
75*6777b538SAndroid Build Coastguard Worker std::string in;
76*6777b538SAndroid Build Coastguard Worker in.push_back(i);
77*6777b538SAndroid Build Coastguard Worker std::string out = EscapeQueryParamValue(in, true);
78*6777b538SAndroid Build Coastguard Worker if (0 == i) {
79*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out, std::string("%00"));
80*6777b538SAndroid Build Coastguard Worker } else if (32 == i) {
81*6777b538SAndroid Build Coastguard Worker // Spaces are plus escaped like web forms.
82*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out, std::string("+"));
83*6777b538SAndroid Build Coastguard Worker } else if (no_escape.find(in) == std::string::npos) {
84*6777b538SAndroid Build Coastguard Worker // Check %hex escaping
85*6777b538SAndroid Build Coastguard Worker std::string expected = StringPrintf("%%%02X", i);
86*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(expected, out);
87*6777b538SAndroid Build Coastguard Worker } else {
88*6777b538SAndroid Build Coastguard Worker // No change for things in the no_escape list.
89*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out, in);
90*6777b538SAndroid Build Coastguard Worker }
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapePath)94*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapePath) {
95*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(
96*6777b538SAndroid Build Coastguard Worker // Most of the character space we care about, un-escaped
97*6777b538SAndroid Build Coastguard Worker EscapePath("\x02\n\x1d !\"#$%&'()*+,-./0123456789:;"
98*6777b538SAndroid Build Coastguard Worker "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
99*6777b538SAndroid Build Coastguard Worker "[\\]^_`abcdefghijklmnopqrstuvwxyz"
100*6777b538SAndroid Build Coastguard Worker "{|}~\x7f\x80\xff"),
101*6777b538SAndroid Build Coastguard Worker // Escaped
102*6777b538SAndroid Build Coastguard Worker "%02%0A%1D%20!%22%23$%25&'()*+,-./0123456789%3A;"
103*6777b538SAndroid Build Coastguard Worker "%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
104*6777b538SAndroid Build Coastguard Worker "%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz"
105*6777b538SAndroid Build Coastguard Worker "%7B%7C%7D~%7F%80%FF");
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapeUrlEncodedData)108*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapeUrlEncodedData) {
109*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(
110*6777b538SAndroid Build Coastguard Worker // Most of the character space we care about, un-escaped
111*6777b538SAndroid Build Coastguard Worker EscapeUrlEncodedData("\x02\n\x1d !\"#$%&'()*+,-./0123456789:;"
112*6777b538SAndroid Build Coastguard Worker "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
113*6777b538SAndroid Build Coastguard Worker "[\\]^_`abcdefghijklmnopqrstuvwxyz"
114*6777b538SAndroid Build Coastguard Worker "{|}~\x7f\x80\xff",
115*6777b538SAndroid Build Coastguard Worker true),
116*6777b538SAndroid Build Coastguard Worker // Escaped
117*6777b538SAndroid Build Coastguard Worker "%02%0A%1D+!%22%23%24%25%26%27()*%2B,-./0123456789:%3B"
118*6777b538SAndroid Build Coastguard Worker "%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ"
119*6777b538SAndroid Build Coastguard Worker "%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz"
120*6777b538SAndroid Build Coastguard Worker "%7B%7C%7D~%7F%80%FF");
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapeUrlEncodedDataSpace)123*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapeUrlEncodedDataSpace) {
124*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(EscapeUrlEncodedData("a b", true), "a+b");
125*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(EscapeUrlEncodedData("a b", false), "a%20b");
126*6777b538SAndroid Build Coastguard Worker }
127*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapeForHTML)128*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapeForHTML) {
129*6777b538SAndroid Build Coastguard Worker const EscapeForHTMLCase tests[] = {
130*6777b538SAndroid Build Coastguard Worker {"hello", "hello"},
131*6777b538SAndroid Build Coastguard Worker {"<hello>", "<hello>"},
132*6777b538SAndroid Build Coastguard Worker {"don\'t mess with me", "don't mess with me"},
133*6777b538SAndroid Build Coastguard Worker };
134*6777b538SAndroid Build Coastguard Worker for (const auto& test : tests) {
135*6777b538SAndroid Build Coastguard Worker std::string result = EscapeForHTML(std::string(test.input));
136*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(test.expected_output), result);
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,UnescapeForHTML)140*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, UnescapeForHTML) {
141*6777b538SAndroid Build Coastguard Worker const EscapeForHTMLCase tests[] = {
142*6777b538SAndroid Build Coastguard Worker {"", ""},
143*6777b538SAndroid Build Coastguard Worker {"<hello>", "<hello>"},
144*6777b538SAndroid Build Coastguard Worker {"don't mess with me", "don\'t mess with me"},
145*6777b538SAndroid Build Coastguard Worker {"<>&"'", "<>&\"'"},
146*6777b538SAndroid Build Coastguard Worker {"& lt; & ; &; '", "& lt; & ; &; '"},
147*6777b538SAndroid Build Coastguard Worker {"&", "&"},
148*6777b538SAndroid Build Coastguard Worker {""", "\""},
149*6777b538SAndroid Build Coastguard Worker {"'", "'"},
150*6777b538SAndroid Build Coastguard Worker {"<", "<"},
151*6777b538SAndroid Build Coastguard Worker {">", ">"},
152*6777b538SAndroid Build Coastguard Worker {"& &", "& &"},
153*6777b538SAndroid Build Coastguard Worker };
154*6777b538SAndroid Build Coastguard Worker for (const auto& test : tests) {
155*6777b538SAndroid Build Coastguard Worker std::u16string result = UnescapeForHTML(ASCIIToUTF16(test.input));
156*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(ASCIIToUTF16(test.expected_output), result);
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker }
159*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapeExternalHandlerValue)160*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapeExternalHandlerValue) {
161*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(
162*6777b538SAndroid Build Coastguard Worker // Escaped
163*6777b538SAndroid Build Coastguard Worker "%02%0A%1D%20!%22#$%25&'()*+,-./0123456789:;"
164*6777b538SAndroid Build Coastguard Worker "%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
165*6777b538SAndroid Build Coastguard Worker "[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz"
166*6777b538SAndroid Build Coastguard Worker "%7B%7C%7D~%7F%80%FF",
167*6777b538SAndroid Build Coastguard Worker // Most of the character space we care about, un-escaped
168*6777b538SAndroid Build Coastguard Worker EscapeExternalHandlerValue("\x02\n\x1d !\"#$%&'()*+,-./0123456789:;"
169*6777b538SAndroid Build Coastguard Worker "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
170*6777b538SAndroid Build Coastguard Worker "[\\]^_`abcdefghijklmnopqrstuvwxyz"
171*6777b538SAndroid Build Coastguard Worker "{|}~\x7f\x80\xff"));
172*6777b538SAndroid Build Coastguard Worker
173*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(
174*6777b538SAndroid Build Coastguard Worker "!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_"
175*6777b538SAndroid Build Coastguard Worker "abcdefghijklmnopqrstuvwxyz~",
176*6777b538SAndroid Build Coastguard Worker EscapeExternalHandlerValue(
177*6777b538SAndroid Build Coastguard Worker "!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_"
178*6777b538SAndroid Build Coastguard Worker "abcdefghijklmnopqrstuvwxyz~"));
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("%258k", EscapeExternalHandlerValue("%8k"));
181*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("a%25", EscapeExternalHandlerValue("a%"));
182*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("%25a", EscapeExternalHandlerValue("%a"));
183*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("a%258", EscapeExternalHandlerValue("a%8"));
184*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("%ab", EscapeExternalHandlerValue("%ab"));
185*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("%AB", EscapeExternalHandlerValue("%AB"));
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("http://example.com/path/sub?q=a%7Cb%7Cc&q=1%7C2%7C3#ref%7C",
188*6777b538SAndroid Build Coastguard Worker EscapeExternalHandlerValue(
189*6777b538SAndroid Build Coastguard Worker "http://example.com/path/sub?q=a|b|c&q=1|2|3#ref|"));
190*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("http://example.com/path/sub?q=a%7Cb%7Cc&q=1%7C2%7C3#ref%7C",
191*6777b538SAndroid Build Coastguard Worker EscapeExternalHandlerValue(
192*6777b538SAndroid Build Coastguard Worker "http://example.com/path/sub?q=a%7Cb%7Cc&q=1%7C2%7C3#ref%7C"));
193*6777b538SAndroid Build Coastguard Worker ASSERT_EQ("http://[2001:db8:0:1]:80",
194*6777b538SAndroid Build Coastguard Worker EscapeExternalHandlerValue("http://[2001:db8:0:1]:80"));
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,EscapeNonASCII)197*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, EscapeNonASCII) {
198*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("abc\n%2580%80", EscapeNonASCIIAndPercent("abc\n%80\x80"));
199*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("abc\n%80%80", EscapeNonASCII("abc\n%80\x80"));
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,DataURLWithAccentedCharacters)202*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, DataURLWithAccentedCharacters) {
203*6777b538SAndroid Build Coastguard Worker const std::string url =
204*6777b538SAndroid Build Coastguard Worker "text/html;charset=utf-8,%3Chtml%3E%3Cbody%3ETonton,%20ton%20th%C3"
205*6777b538SAndroid Build Coastguard Worker "%A9%20t'a-t-il%20%C3%B4t%C3%A9%20ta%20toux%20";
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker OffsetAdjuster::Adjustments adjustments;
208*6777b538SAndroid Build Coastguard Worker UnescapeAndDecodeUTF8URLComponentWithAdjustments(url, UnescapeRule::SPACES,
209*6777b538SAndroid Build Coastguard Worker &adjustments);
210*6777b538SAndroid Build Coastguard Worker }
211*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,UnescapeURLComponent)212*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, UnescapeURLComponent) {
213*6777b538SAndroid Build Coastguard Worker const UnescapeURLCase kUnescapeCases[] = {
214*6777b538SAndroid Build Coastguard Worker {"", UnescapeRule::NORMAL, ""},
215*6777b538SAndroid Build Coastguard Worker {"%2", UnescapeRule::NORMAL, "%2"},
216*6777b538SAndroid Build Coastguard Worker {"%%%%%%", UnescapeRule::NORMAL, "%%%%%%"},
217*6777b538SAndroid Build Coastguard Worker {"Don't escape anything", UnescapeRule::NORMAL, "Don't escape anything"},
218*6777b538SAndroid Build Coastguard Worker {"Invalid %escape %2", UnescapeRule::NORMAL, "Invalid %escape %2"},
219*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%2dOK", UnescapeRule::NONE,
220*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%2dOK"},
221*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
222*6777b538SAndroid Build Coastguard Worker "Some%20random text %25-OK"},
223*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E1%A6", UnescapeRule::NORMAL,
224*6777b538SAndroid Build Coastguard Worker "Some%20random text %25\xE1\xA6"},
225*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E1%A6OK", UnescapeRule::NORMAL,
226*6777b538SAndroid Build Coastguard Worker "Some%20random text %25\xE1\xA6OK"},
227*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E1%A6%99OK", UnescapeRule::NORMAL,
228*6777b538SAndroid Build Coastguard Worker "Some%20random text %25\xE1\xA6\x99OK"},
229*6777b538SAndroid Build Coastguard Worker
230*6777b538SAndroid Build Coastguard Worker // BiDi Control characters should not be unescaped.
231*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%D8%9COK", UnescapeRule::NORMAL,
232*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%D8%9COK"},
233*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%80%8EOK", UnescapeRule::NORMAL,
234*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%80%8EOK"},
235*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%80%8FOK", UnescapeRule::NORMAL,
236*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%80%8FOK"},
237*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%80%AAOK", UnescapeRule::NORMAL,
238*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%80%AAOK"},
239*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%80%ABOK", UnescapeRule::NORMAL,
240*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%80%ABOK"},
241*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%80%AEOK", UnescapeRule::NORMAL,
242*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%80%AEOK"},
243*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%81%A6OK", UnescapeRule::NORMAL,
244*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%81%A6OK"},
245*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%E2%81%A9OK", UnescapeRule::NORMAL,
246*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%E2%81%A9OK"},
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker // Certain banned characters should not be unescaped.
249*6777b538SAndroid Build Coastguard Worker // U+1F50F LOCK WITH INK PEN
250*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%F0%9F%94%8FOK", UnescapeRule::NORMAL,
251*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%F0%9F%94%8FOK"},
252*6777b538SAndroid Build Coastguard Worker // U+1F510 CLOSED LOCK WITH KEY
253*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%F0%9F%94%90OK", UnescapeRule::NORMAL,
254*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%F0%9F%94%90OK"},
255*6777b538SAndroid Build Coastguard Worker // U+1F512 LOCK
256*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%F0%9F%94%92OK", UnescapeRule::NORMAL,
257*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%F0%9F%94%92OK"},
258*6777b538SAndroid Build Coastguard Worker // U+1F513 OPEN LOCK
259*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%F0%9F%94%93OK", UnescapeRule::NORMAL,
260*6777b538SAndroid Build Coastguard Worker "Some%20random text %25%F0%9F%94%93OK"},
261*6777b538SAndroid Build Coastguard Worker
262*6777b538SAndroid Build Coastguard Worker // Spaces
263*6777b538SAndroid Build Coastguard Worker {"(%C2%85)(%C2%A0)(%E1%9A%80)(%E2%80%80)", UnescapeRule::NORMAL,
264*6777b538SAndroid Build Coastguard Worker "(%C2%85)(%C2%A0)(%E1%9A%80)(%E2%80%80)"},
265*6777b538SAndroid Build Coastguard Worker {"(%E2%80%81)(%E2%80%82)(%E2%80%83)(%E2%80%84)", UnescapeRule::NORMAL,
266*6777b538SAndroid Build Coastguard Worker "(%E2%80%81)(%E2%80%82)(%E2%80%83)(%E2%80%84)"},
267*6777b538SAndroid Build Coastguard Worker {"(%E2%80%85)(%E2%80%86)(%E2%80%87)(%E2%80%88)", UnescapeRule::NORMAL,
268*6777b538SAndroid Build Coastguard Worker "(%E2%80%85)(%E2%80%86)(%E2%80%87)(%E2%80%88)"},
269*6777b538SAndroid Build Coastguard Worker {"(%E2%80%89)(%E2%80%8A)(%E2%80%A8)(%E2%80%A9)", UnescapeRule::NORMAL,
270*6777b538SAndroid Build Coastguard Worker "(%E2%80%89)(%E2%80%8A)(%E2%80%A8)(%E2%80%A9)"},
271*6777b538SAndroid Build Coastguard Worker {"(%E2%80%AF)(%E2%81%9F)(%E3%80%80)", UnescapeRule::NORMAL,
272*6777b538SAndroid Build Coastguard Worker "(%E2%80%AF)(%E2%81%9F)(%E3%80%80)"},
273*6777b538SAndroid Build Coastguard Worker {"(%E2%A0%80)", UnescapeRule::NORMAL, "(%E2%A0%80)"},
274*6777b538SAndroid Build Coastguard Worker
275*6777b538SAndroid Build Coastguard Worker // Default Ignorable and Formatting characters should not be unescaped.
276*6777b538SAndroid Build Coastguard Worker {"(%E2%81%A5)(%EF%BF%B0)(%EF%BF%B8)", UnescapeRule::NORMAL,
277*6777b538SAndroid Build Coastguard Worker "(%E2%81%A5)(%EF%BF%B0)(%EF%BF%B8)"},
278*6777b538SAndroid Build Coastguard Worker {"(%F3%A0%82%80)(%F3%A0%83%BF)(%F3%A0%87%B0)", UnescapeRule::NORMAL,
279*6777b538SAndroid Build Coastguard Worker "(%F3%A0%82%80)(%F3%A0%83%BF)(%F3%A0%87%B0)"},
280*6777b538SAndroid Build Coastguard Worker {"(%F3%A0%BF%BF)(%C2%AD)(%CD%8F)", UnescapeRule::NORMAL,
281*6777b538SAndroid Build Coastguard Worker "(%F3%A0%BF%BF)(%C2%AD)(%CD%8F)"},
282*6777b538SAndroid Build Coastguard Worker {"(%D8%80%20)(%D8%85)(%DB%9D)(%DC%8F)(%E0%A3%A2)", UnescapeRule::NORMAL,
283*6777b538SAndroid Build Coastguard Worker "(%D8%80%20)(%D8%85)(%DB%9D)(%DC%8F)(%E0%A3%A2)"},
284*6777b538SAndroid Build Coastguard Worker {"(%E1%85%9F)(%E1%85%A0)(%E1%9E%B4)(%E1%9E%B5)", UnescapeRule::NORMAL,
285*6777b538SAndroid Build Coastguard Worker "(%E1%85%9F)(%E1%85%A0)(%E1%9E%B4)(%E1%9E%B5)"},
286*6777b538SAndroid Build Coastguard Worker {"(%E1%A0%8B)(%E1%A0%8C)(%E1%A0%8D)(%E1%A0%8E)", UnescapeRule::NORMAL,
287*6777b538SAndroid Build Coastguard Worker "(%E1%A0%8B)(%E1%A0%8C)(%E1%A0%8D)(%E1%A0%8E)"},
288*6777b538SAndroid Build Coastguard Worker {"(%E2%80%8B)(%E2%80%8C)(%E2%80%8D)(%E2%81%A0)", UnescapeRule::NORMAL,
289*6777b538SAndroid Build Coastguard Worker "(%E2%80%8B)(%E2%80%8C)(%E2%80%8D)(%E2%81%A0)"},
290*6777b538SAndroid Build Coastguard Worker {"(%E2%81%A1)(%E2%81%A2)(%E2%81%A3)(%E2%81%A4)", UnescapeRule::NORMAL,
291*6777b538SAndroid Build Coastguard Worker "(%E2%81%A1)(%E2%81%A2)(%E2%81%A3)(%E2%81%A4)"},
292*6777b538SAndroid Build Coastguard Worker {"(%E3%85%A4)(%EF%BB%BF)(%EF%BE%A0)(%EF%BF%B9)", UnescapeRule::NORMAL,
293*6777b538SAndroid Build Coastguard Worker "(%E3%85%A4)(%EF%BB%BF)(%EF%BE%A0)(%EF%BF%B9)"},
294*6777b538SAndroid Build Coastguard Worker {"(%EF%BF%BB)(%F0%91%82%BD)(%F0%91%83%8D)", UnescapeRule::NORMAL,
295*6777b538SAndroid Build Coastguard Worker "(%EF%BF%BB)(%F0%91%82%BD)(%F0%91%83%8D)"},
296*6777b538SAndroid Build Coastguard Worker {"(%F0%93%90%B0)(%F0%93%90%B8)", UnescapeRule::NORMAL,
297*6777b538SAndroid Build Coastguard Worker "(%F0%93%90%B0)(%F0%93%90%B8)"},
298*6777b538SAndroid Build Coastguard Worker // General Punctuation - Deprecated (U+206A--206F)
299*6777b538SAndroid Build Coastguard Worker {"(%E2%81%AA)(%E2%81%AD)(%E2%81%AF)", UnescapeRule::NORMAL,
300*6777b538SAndroid Build Coastguard Worker "(%E2%81%AA)(%E2%81%AD)(%E2%81%AF)"},
301*6777b538SAndroid Build Coastguard Worker // Variation selectors (U+FE00--FE0F)
302*6777b538SAndroid Build Coastguard Worker {"(%EF%B8%80)(%EF%B8%8C)(%EF%B8%8D)", UnescapeRule::NORMAL,
303*6777b538SAndroid Build Coastguard Worker "(%EF%B8%80)(%EF%B8%8C)(%EF%B8%8D)"},
304*6777b538SAndroid Build Coastguard Worker // Shorthand format controls (U+1BCA0--1BCA3)
305*6777b538SAndroid Build Coastguard Worker {"(%F0%9B%B2%A0)(%F0%9B%B2%A1)(%F0%9B%B2%A3)", UnescapeRule::NORMAL,
306*6777b538SAndroid Build Coastguard Worker "(%F0%9B%B2%A0)(%F0%9B%B2%A1)(%F0%9B%B2%A3)"},
307*6777b538SAndroid Build Coastguard Worker // Musical symbols beams and slurs (U+1D173--1D17A)
308*6777b538SAndroid Build Coastguard Worker {"(%F0%9D%85%B3)(%F0%9D%85%B9)(%F0%9D%85%BA)", UnescapeRule::NORMAL,
309*6777b538SAndroid Build Coastguard Worker "(%F0%9D%85%B3)(%F0%9D%85%B9)(%F0%9D%85%BA)"},
310*6777b538SAndroid Build Coastguard Worker // Tags block (U+E0000--E007F), includes unassigned points
311*6777b538SAndroid Build Coastguard Worker {"(%F3%A0%80%80)(%F3%A0%80%81)(%F3%A0%81%8F)", UnescapeRule::NORMAL,
312*6777b538SAndroid Build Coastguard Worker "(%F3%A0%80%80)(%F3%A0%80%81)(%F3%A0%81%8F)"},
313*6777b538SAndroid Build Coastguard Worker // Ideographic-specific variation selectors (U+E0100--E01EF)
314*6777b538SAndroid Build Coastguard Worker {"(%F3%A0%84%80)(%F3%A0%84%90)(%F3%A0%87%AF)", UnescapeRule::NORMAL,
315*6777b538SAndroid Build Coastguard Worker "(%F3%A0%84%80)(%F3%A0%84%90)(%F3%A0%87%AF)"},
316*6777b538SAndroid Build Coastguard Worker
317*6777b538SAndroid Build Coastguard Worker // Two spoofing characters in a row should not be unescaped.
318*6777b538SAndroid Build Coastguard Worker {"%D8%9C%D8%9C", UnescapeRule::NORMAL, "%D8%9C%D8%9C"},
319*6777b538SAndroid Build Coastguard Worker // Non-spoofing characters surrounded by spoofing characters should be
320*6777b538SAndroid Build Coastguard Worker // unescaped.
321*6777b538SAndroid Build Coastguard Worker {"%D8%9C%C2%A1%D8%9C%C2%A1", UnescapeRule::NORMAL,
322*6777b538SAndroid Build Coastguard Worker "%D8%9C\xC2\xA1%D8%9C\xC2\xA1"},
323*6777b538SAndroid Build Coastguard Worker // Invalid UTF-8 characters surrounded by spoofing characters should be
324*6777b538SAndroid Build Coastguard Worker // unescaped.
325*6777b538SAndroid Build Coastguard Worker {"%D8%9C%85%D8%9C%85", UnescapeRule::NORMAL, "%D8%9C\x85%D8%9C\x85"},
326*6777b538SAndroid Build Coastguard Worker // Test with enough trail bytes to overflow the CBU8_MAX_LENGTH-byte
327*6777b538SAndroid Build Coastguard Worker // buffer. The first two bytes are a spoofing character as well.
328*6777b538SAndroid Build Coastguard Worker {"%D8%9C%9C%9C%9C%9C%9C%9C%9C%9C%9C", UnescapeRule::NORMAL,
329*6777b538SAndroid Build Coastguard Worker "%D8%9C\x9C\x9C\x9C\x9C\x9C\x9C\x9C\x9C\x9C"},
330*6777b538SAndroid Build Coastguard Worker
331*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%2dOK", UnescapeRule::SPACES,
332*6777b538SAndroid Build Coastguard Worker "Some random text %25-OK"},
333*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%2dOK", UnescapeRule::PATH_SEPARATORS,
334*6777b538SAndroid Build Coastguard Worker "Some%20random text %25-OK"},
335*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%2dOK",
336*6777b538SAndroid Build Coastguard Worker UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
337*6777b538SAndroid Build Coastguard Worker "Some%20random text %-OK"},
338*6777b538SAndroid Build Coastguard Worker {"Some%20random text %25%2dOK",
339*6777b538SAndroid Build Coastguard Worker UnescapeRule::SPACES |
340*6777b538SAndroid Build Coastguard Worker UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
341*6777b538SAndroid Build Coastguard Worker "Some random text %-OK"},
342*6777b538SAndroid Build Coastguard Worker {"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL, "\xA0\xB1\xC2\xD3\xE4\xF5"},
343*6777b538SAndroid Build Coastguard Worker {"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL, "\xAa\xBb\xCc\xDd\xEe\xFf"},
344*6777b538SAndroid Build Coastguard Worker // Certain URL-sensitive characters should not be unescaped unless asked.
345*6777b538SAndroid Build Coastguard Worker {"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
346*6777b538SAndroid Build Coastguard Worker UnescapeRule::SPACES, "Hello %13%10world %23# %3F? %3D= %26& %25% %2B+"},
347*6777b538SAndroid Build Coastguard Worker {"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
348*6777b538SAndroid Build Coastguard Worker UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
349*6777b538SAndroid Build Coastguard Worker "Hello%20%13%10world ## ?? == && %% ++"},
350*6777b538SAndroid Build Coastguard Worker // We can neither escape nor unescape '@' since some websites expect it to
351*6777b538SAndroid Build Coastguard Worker // be preserved as either '@' or "%40".
352*6777b538SAndroid Build Coastguard Worker // See http://b/996720 and http://crbug.com/23933 .
353*6777b538SAndroid Build Coastguard Worker {"me@my%40example", UnescapeRule::NORMAL, "me@my%40example"},
354*6777b538SAndroid Build Coastguard Worker // Control characters.
355*6777b538SAndroid Build Coastguard Worker {"%01%02%03%04%05%06%07%08%09 %25",
356*6777b538SAndroid Build Coastguard Worker UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
357*6777b538SAndroid Build Coastguard Worker "%01%02%03%04%05%06%07%08%09 %"},
358*6777b538SAndroid Build Coastguard Worker {"Hello%20%13%10%02", UnescapeRule::SPACES, "Hello %13%10%02"},
359*6777b538SAndroid Build Coastguard Worker
360*6777b538SAndroid Build Coastguard Worker // '/' and '\\' should only be unescaped by PATH_SEPARATORS.
361*6777b538SAndroid Build Coastguard Worker {"%2F%5C", UnescapeRule::PATH_SEPARATORS, "/\\"},
362*6777b538SAndroid Build Coastguard Worker };
363*6777b538SAndroid Build Coastguard Worker
364*6777b538SAndroid Build Coastguard Worker for (const auto unescape_case : kUnescapeCases) {
365*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(unescape_case.output,
366*6777b538SAndroid Build Coastguard Worker UnescapeURLComponent(unescape_case.input, unescape_case.rules));
367*6777b538SAndroid Build Coastguard Worker }
368*6777b538SAndroid Build Coastguard Worker
369*6777b538SAndroid Build Coastguard Worker // Test NULL character unescaping, which can't be tested above since those are
370*6777b538SAndroid Build Coastguard Worker // just char pointers.
371*6777b538SAndroid Build Coastguard Worker std::string input("Null");
372*6777b538SAndroid Build Coastguard Worker input.push_back(0); // Also have a NULL in the input.
373*6777b538SAndroid Build Coastguard Worker input.append("%00%39Test");
374*6777b538SAndroid Build Coastguard Worker
375*6777b538SAndroid Build Coastguard Worker std::string expected = "Null";
376*6777b538SAndroid Build Coastguard Worker expected.push_back(0);
377*6777b538SAndroid Build Coastguard Worker expected.append("%009Test");
378*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(expected, UnescapeURLComponent(input, UnescapeRule::NORMAL));
379*6777b538SAndroid Build Coastguard Worker }
380*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,UnescapeAndDecodeUTF8URLComponentWithAdjustments)381*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, UnescapeAndDecodeUTF8URLComponentWithAdjustments) {
382*6777b538SAndroid Build Coastguard Worker const UnescapeAndDecodeCase unescape_cases[] = {
383*6777b538SAndroid Build Coastguard Worker {"%", "%", "%", L"%"},
384*6777b538SAndroid Build Coastguard Worker {"+", "+", " ", L"+"},
385*6777b538SAndroid Build Coastguard Worker {"%2+", "%2+", "%2 ", L"%2+"},
386*6777b538SAndroid Build Coastguard Worker {"+%%%+%%%", "+%%%+%%%", " %%% %%%", L"+%%%+%%%"},
387*6777b538SAndroid Build Coastguard Worker {"Don't escape anything", "Don't escape anything",
388*6777b538SAndroid Build Coastguard Worker "Don't escape anything", L"Don't escape anything"},
389*6777b538SAndroid Build Coastguard Worker {"+Invalid %escape %2+", "+Invalid %escape %2+", " Invalid %escape %2 ",
390*6777b538SAndroid Build Coastguard Worker L"+Invalid %escape %2+"},
391*6777b538SAndroid Build Coastguard Worker {"Some random text %25%2dOK", "Some random text %25-OK",
392*6777b538SAndroid Build Coastguard Worker "Some random text %25-OK", L"Some random text %25-OK"},
393*6777b538SAndroid Build Coastguard Worker {"%01%02%03%04%05%06%07%08%09", "%01%02%03%04%05%06%07%08%09",
394*6777b538SAndroid Build Coastguard Worker "%01%02%03%04%05%06%07%08%09", L"%01%02%03%04%05%06%07%08%09"},
395*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BD", "\xE4\xBD\xA0+\xE5\xA5\xBD",
396*6777b538SAndroid Build Coastguard Worker "\xE4\xBD\xA0 \xE5\xA5\xBD", L"\x4f60+\x597d"},
397*6777b538SAndroid Build Coastguard Worker {"%ED%ED", // Invalid UTF-8.
398*6777b538SAndroid Build Coastguard Worker "\xED\xED", "\xED\xED", L"%ED%ED"}, // Invalid UTF-8 -> kept unescaped.
399*6777b538SAndroid Build Coastguard Worker };
400*6777b538SAndroid Build Coastguard Worker
401*6777b538SAndroid Build Coastguard Worker for (const auto& unescape_case : unescape_cases) {
402*6777b538SAndroid Build Coastguard Worker std::string unescaped =
403*6777b538SAndroid Build Coastguard Worker UnescapeURLComponent(unescape_case.input, UnescapeRule::NORMAL);
404*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(unescape_case.url_unescaped), unescaped);
405*6777b538SAndroid Build Coastguard Worker
406*6777b538SAndroid Build Coastguard Worker unescaped = UnescapeURLComponent(unescape_case.input,
407*6777b538SAndroid Build Coastguard Worker UnescapeRule::REPLACE_PLUS_WITH_SPACE);
408*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(unescape_case.query_unescaped), unescaped);
409*6777b538SAndroid Build Coastguard Worker
410*6777b538SAndroid Build Coastguard Worker // The adjustments argument is covered by the next test.
411*6777b538SAndroid Build Coastguard Worker //
412*6777b538SAndroid Build Coastguard Worker // TODO: Need to test unescape_spaces and unescape_percent.
413*6777b538SAndroid Build Coastguard Worker std::u16string decoded = UnescapeAndDecodeUTF8URLComponentWithAdjustments(
414*6777b538SAndroid Build Coastguard Worker unescape_case.input, UnescapeRule::NORMAL, nullptr);
415*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(WideToUTF16(unescape_case.decoded), decoded);
416*6777b538SAndroid Build Coastguard Worker }
417*6777b538SAndroid Build Coastguard Worker }
418*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,AdjustOffset)419*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, AdjustOffset) {
420*6777b538SAndroid Build Coastguard Worker const AdjustOffsetCase adjust_cases[] = {
421*6777b538SAndroid Build Coastguard Worker {"", 0, 0},
422*6777b538SAndroid Build Coastguard Worker {"test", 0, 0},
423*6777b538SAndroid Build Coastguard Worker {"test", 2, 2},
424*6777b538SAndroid Build Coastguard Worker {"test", 4, 4},
425*6777b538SAndroid Build Coastguard Worker {"test", std::string::npos, std::string::npos},
426*6777b538SAndroid Build Coastguard Worker {"%2dtest", 6, 4},
427*6777b538SAndroid Build Coastguard Worker {"%2dtest", 3, 1},
428*6777b538SAndroid Build Coastguard Worker {"%2dtest", 2, std::string::npos},
429*6777b538SAndroid Build Coastguard Worker {"%2dtest", 1, std::string::npos},
430*6777b538SAndroid Build Coastguard Worker {"%2dtest", 0, 0},
431*6777b538SAndroid Build Coastguard Worker {"test%2d", 2, 2},
432*6777b538SAndroid Build Coastguard Worker {"test%2e", 2, 2},
433*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BD", 9, 1},
434*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BD", 6, std::string::npos},
435*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BD", 0, 0},
436*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BD", 10, 2},
437*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BD", 19, 3},
438*6777b538SAndroid Build Coastguard Worker
439*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 18, 8},
440*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 15, std::string::npos},
441*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 9, 7},
442*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 19, 9},
443*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 28, 10},
444*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 0, 0},
445*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 2, 2},
446*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 3, std::string::npos},
447*6777b538SAndroid Build Coastguard Worker {"hi%41test%E4%BD%A0+%E5%A5%BD", 5, 3},
448*6777b538SAndroid Build Coastguard Worker
449*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 9, 1},
450*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 6, std::string::npos},
451*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 0, 0},
452*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 10, 2},
453*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 19, 3},
454*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 21, 5},
455*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 22, std::string::npos},
456*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 24, 6},
457*6777b538SAndroid Build Coastguard Worker {"%E4%BD%A0+%E5%A5%BDhi%41test", 28, 10},
458*6777b538SAndroid Build Coastguard Worker
459*6777b538SAndroid Build Coastguard Worker {"%ED%B0%80+%E5%A5%BD", 6, 6}, // not convertible to UTF-8
460*6777b538SAndroid Build Coastguard Worker };
461*6777b538SAndroid Build Coastguard Worker
462*6777b538SAndroid Build Coastguard Worker for (const auto& adjust_case : adjust_cases) {
463*6777b538SAndroid Build Coastguard Worker size_t offset = adjust_case.input_offset;
464*6777b538SAndroid Build Coastguard Worker OffsetAdjuster::Adjustments adjustments;
465*6777b538SAndroid Build Coastguard Worker UnescapeAndDecodeUTF8URLComponentWithAdjustments(
466*6777b538SAndroid Build Coastguard Worker adjust_case.input, UnescapeRule::NORMAL, &adjustments);
467*6777b538SAndroid Build Coastguard Worker OffsetAdjuster::AdjustOffset(adjustments, &offset);
468*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(adjust_case.output_offset, offset)
469*6777b538SAndroid Build Coastguard Worker << "input=" << adjust_case.input
470*6777b538SAndroid Build Coastguard Worker << " offset=" << adjust_case.input_offset;
471*6777b538SAndroid Build Coastguard Worker }
472*6777b538SAndroid Build Coastguard Worker }
473*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,UnescapeBinaryURLComponent)474*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, UnescapeBinaryURLComponent) {
475*6777b538SAndroid Build Coastguard Worker const UnescapeURLCase kTestCases[] = {
476*6777b538SAndroid Build Coastguard Worker // Check that ASCII characters with special handling in
477*6777b538SAndroid Build Coastguard Worker // UnescapeURLComponent() are still unescaped.
478*6777b538SAndroid Build Coastguard Worker {"%09%20%25foo%2F", UnescapeRule::NORMAL, "\x09 %foo/"},
479*6777b538SAndroid Build Coastguard Worker
480*6777b538SAndroid Build Coastguard Worker // UTF-8 Characters banned by UnescapeURLComponent() should also be
481*6777b538SAndroid Build Coastguard Worker // unescaped.
482*6777b538SAndroid Build Coastguard Worker {"Some random text %D8%9COK", UnescapeRule::NORMAL,
483*6777b538SAndroid Build Coastguard Worker "Some random text \xD8\x9COK"},
484*6777b538SAndroid Build Coastguard Worker {"Some random text %F0%9F%94%8FOK", UnescapeRule::NORMAL,
485*6777b538SAndroid Build Coastguard Worker "Some random text \xF0\x9F\x94\x8FOK"},
486*6777b538SAndroid Build Coastguard Worker
487*6777b538SAndroid Build Coastguard Worker // As should invalid UTF-8 characters.
488*6777b538SAndroid Build Coastguard Worker {"%A0%A0%E9%E9%A0%A0%A0%A0", UnescapeRule::NORMAL,
489*6777b538SAndroid Build Coastguard Worker "\xA0\xA0\xE9\xE9\xA0\xA0\xA0\xA0"},
490*6777b538SAndroid Build Coastguard Worker
491*6777b538SAndroid Build Coastguard Worker // And valid UTF-8 characters that are not banned by
492*6777b538SAndroid Build Coastguard Worker // UnescapeURLComponent() should be unescaped, too!
493*6777b538SAndroid Build Coastguard Worker {"%C2%A1%C2%A1", UnescapeRule::NORMAL, "\xC2\xA1\xC2\xA1"},
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker // '+' should be left alone by default
496*6777b538SAndroid Build Coastguard Worker {"++%2B++", UnescapeRule::NORMAL, "+++++"},
497*6777b538SAndroid Build Coastguard Worker // But should magically be turned into a space if requested.
498*6777b538SAndroid Build Coastguard Worker {"++%2B++", UnescapeRule::REPLACE_PLUS_WITH_SPACE, " + "},
499*6777b538SAndroid Build Coastguard Worker };
500*6777b538SAndroid Build Coastguard Worker
501*6777b538SAndroid Build Coastguard Worker for (const auto& test_case : kTestCases) {
502*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test_case.output,
503*6777b538SAndroid Build Coastguard Worker UnescapeBinaryURLComponent(test_case.input, test_case.rules));
504*6777b538SAndroid Build Coastguard Worker }
505*6777b538SAndroid Build Coastguard Worker
506*6777b538SAndroid Build Coastguard Worker // Test NULL character unescaping, which can't be tested above since those are
507*6777b538SAndroid Build Coastguard Worker // just char pointers.
508*6777b538SAndroid Build Coastguard Worker std::string input("Null");
509*6777b538SAndroid Build Coastguard Worker input.push_back(0); // Also have a NULL in the input.
510*6777b538SAndroid Build Coastguard Worker input.append("%00%39Test");
511*6777b538SAndroid Build Coastguard Worker
512*6777b538SAndroid Build Coastguard Worker std::string expected("Null");
513*6777b538SAndroid Build Coastguard Worker expected.push_back(0);
514*6777b538SAndroid Build Coastguard Worker expected.push_back(0);
515*6777b538SAndroid Build Coastguard Worker expected.append("9Test");
516*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(expected, UnescapeBinaryURLComponent(input));
517*6777b538SAndroid Build Coastguard Worker }
518*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,UnescapeBinaryURLComponentSafe)519*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, UnescapeBinaryURLComponentSafe) {
520*6777b538SAndroid Build Coastguard Worker const struct TestCase {
521*6777b538SAndroid Build Coastguard Worker const char* input;
522*6777b538SAndroid Build Coastguard Worker // Expected output. Null if call is expected to fail when
523*6777b538SAndroid Build Coastguard Worker // |fail_on_path_separators| is false.
524*6777b538SAndroid Build Coastguard Worker const char* expected_output;
525*6777b538SAndroid Build Coastguard Worker // Whether |input| has any escaped path separators.
526*6777b538SAndroid Build Coastguard Worker bool has_path_separators;
527*6777b538SAndroid Build Coastguard Worker } kTestCases[] = {
528*6777b538SAndroid Build Coastguard Worker // Spaces, percents, and invalid UTF-8 characters are all successfully
529*6777b538SAndroid Build Coastguard Worker // unescaped.
530*6777b538SAndroid Build Coastguard Worker {"%20%25foo%81", " %foo\x81", false},
531*6777b538SAndroid Build Coastguard Worker
532*6777b538SAndroid Build Coastguard Worker // Characters disallowed unconditionally.
533*6777b538SAndroid Build Coastguard Worker {"foo%00", nullptr, false},
534*6777b538SAndroid Build Coastguard Worker {"foo%01", nullptr, false},
535*6777b538SAndroid Build Coastguard Worker {"foo%0A", nullptr, false},
536*6777b538SAndroid Build Coastguard Worker {"foo%0D", nullptr, false},
537*6777b538SAndroid Build Coastguard Worker
538*6777b538SAndroid Build Coastguard Worker // Path separators.
539*6777b538SAndroid Build Coastguard Worker {"foo%2F", "foo/", true},
540*6777b538SAndroid Build Coastguard Worker {"foo%5C", "foo\\", true},
541*6777b538SAndroid Build Coastguard Worker
542*6777b538SAndroid Build Coastguard Worker // Characters that are considered invalid to escape are ignored if passed
543*6777b538SAndroid Build Coastguard Worker // in unescaped.
544*6777b538SAndroid Build Coastguard Worker {"foo\x01\r/\\", "foo\x01\r/\\", false},
545*6777b538SAndroid Build Coastguard Worker };
546*6777b538SAndroid Build Coastguard Worker
547*6777b538SAndroid Build Coastguard Worker for (const auto& test_case : kTestCases) {
548*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(test_case.input);
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Worker std::string output = "foo";
551*6777b538SAndroid Build Coastguard Worker if (!test_case.expected_output) {
552*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(UnescapeBinaryURLComponentSafe(
553*6777b538SAndroid Build Coastguard Worker test_case.input, false /* fail_on_path_separators */, &output));
554*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(output.empty());
555*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(UnescapeBinaryURLComponentSafe(
556*6777b538SAndroid Build Coastguard Worker test_case.input, true /* fail_on_path_separators */, &output));
557*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(output.empty());
558*6777b538SAndroid Build Coastguard Worker continue;
559*6777b538SAndroid Build Coastguard Worker }
560*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(UnescapeBinaryURLComponentSafe(
561*6777b538SAndroid Build Coastguard Worker test_case.input, false /* fail_on_path_separators */, &output));
562*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test_case.expected_output, output);
563*6777b538SAndroid Build Coastguard Worker if (test_case.has_path_separators) {
564*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(UnescapeBinaryURLComponentSafe(
565*6777b538SAndroid Build Coastguard Worker test_case.input, true /* fail_on_path_separators */, &output));
566*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(output.empty());
567*6777b538SAndroid Build Coastguard Worker } else {
568*6777b538SAndroid Build Coastguard Worker output = "foo";
569*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(UnescapeBinaryURLComponentSafe(
570*6777b538SAndroid Build Coastguard Worker test_case.input, true /* fail_on_path_separators */, &output));
571*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test_case.expected_output, output);
572*6777b538SAndroid Build Coastguard Worker }
573*6777b538SAndroid Build Coastguard Worker }
574*6777b538SAndroid Build Coastguard Worker }
575*6777b538SAndroid Build Coastguard Worker
TEST(EscapeTest,ContainsEncodedBytes)576*6777b538SAndroid Build Coastguard Worker TEST(EscapeTest, ContainsEncodedBytes) {
577*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(ContainsEncodedBytes("abc/def", {'/', '\\'}));
578*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(ContainsEncodedBytes("abc%2Fdef", {'%'}));
579*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(ContainsEncodedBytes("abc%252Fdef", {'%'}));
580*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(ContainsEncodedBytes("abc%2Fdef", {'/', '\\'}));
581*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(ContainsEncodedBytes("abc%5Cdef", {'/', '\\'}));
582*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(ContainsEncodedBytes("abc%2fdef", {'/', '\\'}));
583*6777b538SAndroid Build Coastguard Worker
584*6777b538SAndroid Build Coastguard Worker // Should be looking for byte values, not UTF-8 character values.
585*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(
586*6777b538SAndroid Build Coastguard Worker ContainsEncodedBytes("caf%C3%A9", {static_cast<uint8_t>('\xc3')}));
587*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(
588*6777b538SAndroid Build Coastguard Worker ContainsEncodedBytes("caf%C3%A9", {static_cast<uint8_t>('\xe9')}));
589*6777b538SAndroid Build Coastguard Worker }
590*6777b538SAndroid Build Coastguard Worker
591*6777b538SAndroid Build Coastguard Worker } // namespace
592*6777b538SAndroid Build Coastguard Worker } // namespace base
593