Commit 20f515cc authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[WebShare] Only parse placeholders in the query and fragment part 2

This CL refactors ReplacePlaceholders() to make it clearer that only
placeholders in the url_template query and fragment are replaced.

BUG=694380, 788191

Change-Id: I62672ae9e8386ef53ff532cf20a0d312fcba600f
Reviewed-on: https://chromium-review.googlesource.com/925648
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarMatt Giuca <mgiuca@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541673}
parent 9762fe19
......@@ -31,24 +31,14 @@ bool IsIdentifier(char c) {
return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || c == '-' || c == '_';
}
} // namespace
ShareServiceImpl::ShareServiceImpl() : weak_factory_(this) {}
ShareServiceImpl::~ShareServiceImpl() = default;
// static
void ShareServiceImpl::Create(
blink::mojom::ShareServiceRequest request) {
mojo::MakeStrongBinding(std::make_unique<ShareServiceImpl>(),
std::move(request));
}
// static
bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
base::StringPiece title,
base::StringPiece text,
const GURL& share_url,
std::string* url_template_filled) {
// Returns to |out| the result of running the "replace placeholders" algorithm
// on |template_string|. The algorithm is specified at
// https://wicg.github.io/web-share-target/#dfn-replace-placeholders
bool ReplacePlaceholders(base::StringPiece template_string,
base::StringPiece title,
base::StringPiece text,
const GURL& share_url,
std::string* out) {
constexpr char kTitlePlaceholder[] = "title";
constexpr char kTextPlaceholder[] = "text";
constexpr char kUrlPlaceholder[] = "url";
......@@ -64,10 +54,10 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
std::vector<base::StringPiece> split_template;
bool last_saw_open = false;
size_t start_index_to_copy = 0;
for (size_t i = 0; i < url_template.size(); ++i) {
for (size_t i = 0; i < template_string.size(); ++i) {
if (last_saw_open) {
if (url_template[i] == '}') {
base::StringPiece placeholder = url_template.substr(
if (template_string[i] == '}') {
base::StringPiece placeholder = template_string.substr(
start_index_to_copy + 1, i - 1 - start_index_to_copy);
auto it = placeholder_to_data.find(placeholder);
if (it != placeholder_to_data.end()) {
......@@ -77,17 +67,17 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
last_saw_open = false;
start_index_to_copy = i + 1;
} else if (!IsIdentifier(url_template[i])) {
} else if (!IsIdentifier(template_string[i])) {
// Error: Non-identifier character seen after open.
return false;
}
} else {
if (url_template[i] == '}') {
if (template_string[i] == '}') {
// Error: Saw close, with no corresponding open.
return false;
} else if (url_template[i] == '{') {
split_template.push_back(
url_template.substr(start_index_to_copy, i - start_index_to_copy));
} else if (template_string[i] == '{') {
split_template.push_back(template_string.substr(
start_index_to_copy, i - start_index_to_copy));
last_saw_open = true;
start_index_to_copy = i;
......@@ -98,10 +88,47 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
// Error: Saw open that was never closed.
return false;
}
split_template.push_back(url_template.substr(
start_index_to_copy, url_template.size() - start_index_to_copy));
split_template.push_back(template_string.substr(
start_index_to_copy, template_string.size() - start_index_to_copy));
*out = base::StrCat(split_template);
return true;
}
} // namespace
ShareServiceImpl::ShareServiceImpl() : weak_factory_(this) {}
ShareServiceImpl::~ShareServiceImpl() = default;
// static
void ShareServiceImpl::Create(blink::mojom::ShareServiceRequest request) {
mojo::MakeStrongBinding(std::make_unique<ShareServiceImpl>(),
std::move(request));
}
// static
bool ShareServiceImpl::ReplaceUrlPlaceholders(const GURL& url_template,
base::StringPiece title,
base::StringPiece text,
const GURL& share_url,
GURL* url_template_filled) {
std::string new_query;
std::string new_ref;
if (!ReplacePlaceholders(url_template.query_piece(), title, text, share_url,
&new_query) ||
!ReplacePlaceholders(url_template.ref_piece(), title, text, share_url,
&new_ref)) {
return false;
}
*url_template_filled = base::StrCat(split_template);
// Check whether |url_template| has a query in order to preserve the '?' in a
// URL with an empty query. e.g. http://www.google.com/?
GURL::Replacements url_replacements;
if (url_template.has_query())
url_replacements.SetQueryStr(new_query);
if (url_template.has_ref())
url_replacements.SetRefStr(new_ref);
*url_template_filled = url_template.ReplaceComponents(url_replacements);
return true;
}
......@@ -195,13 +222,9 @@ void ShareServiceImpl::OnPickerClosed(const std::string& title,
return;
}
// This will only replace placeholders found in the query and the fragment
// parts of the URL. This happens implicitly, because '{' and '}' found in the
// path will have been escaped during URL parsing, and thus won't be seen as
// placeholders by ReplacePlaceholders().
std::string url_template_filled;
if (!ReplacePlaceholders(result->url_template().spec(), title, text,
share_url, &url_template_filled)) {
GURL url_template_filled;
if (!ReplaceUrlPlaceholders(result->url_template(), title, text, share_url,
&url_template_filled)) {
// TODO(mgiuca): This error should not be possible at share time, because
// targets with invalid templates should not be chooseable. Fix
// https://crbug.com/694380 and replace this with a DCHECK.
......@@ -209,12 +232,11 @@ void ShareServiceImpl::OnPickerClosed(const std::string& title,
return;
}
const GURL target(url_template_filled);
// User should not be able to cause an invalid target URL. The replaced pieces
// are escaped. If somehow we slip through this DCHECK, it will just open
// about:blank.
DCHECK(target.is_valid());
OpenTargetURL(target);
DCHECK(url_template_filled.is_valid());
OpenTargetURL(url_template_filled);
std::move(callback).Run(blink::mojom::ShareError::OK);
}
......@@ -39,7 +39,11 @@ class ShareServiceImpl : public blink::mojom::ShareService {
ShareCallback callback) override;
private:
FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest, ReplacePlaceholders);
FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest,
ReplaceUrlPlaceholdersInvalidTemplate);
FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest, ReplaceUrlPlaceholders);
FRIEND_TEST_ALL_PREFIXES(ShareServiceImplUnittest,
ReplaceUrlPlaceholders_Escaping);
Browser* GetBrowser();
......@@ -70,18 +74,18 @@ class ShareServiceImpl : public blink::mojom::ShareService {
std::vector<WebShareTarget> GetTargetsWithSufficientEngagement();
// Writes to |url_template_filled|, a copy of |url_template| with all
// instances of "{title}", "{text}", and "{url}" replaced with
// |title|, |text|, and |url| respectively.
// instances of "{title}", "{text}", and "{url}" in the query and fragment
// parts of the URL replaced with |title|, |text|, and |url| respectively.
// Replaces instances of "{X}" where "X" is any string besides "title",
// "text", and "url", with an empty string, for forwards compatibility.
// Returns false, if there are badly nested placeholders.
// This includes any case in which two "{" occur before a "}", or a "}"
// occurs with no preceding "{".
static bool ReplacePlaceholders(base::StringPiece url_template,
base::StringPiece title,
base::StringPiece text,
const GURL& share_url,
std::string* url_template_filled);
static bool ReplaceUrlPlaceholders(const GURL& url_template,
base::StringPiece title,
base::StringPiece text,
const GURL& share_url,
GURL* url_template_filled);
void OnPickerClosed(const std::string& title,
const std::string& text,
......
......@@ -381,206 +381,239 @@ TEST_F(ShareServiceImplUnittest, ShareServiceDeletion) {
std::move(picker_callback).Run(&expected_targets[0]);
}
// Replace various numbers of placeholders in various orders. Placeholders are
// adjacent to eachother; there are no padding characters.
TEST_F(ShareServiceImplUnittest, ReplacePlaceholders) {
const GURL url(kUrlSpec);
std::string url_template_filled;
bool succeeded;
TEST_F(ShareServiceImplUnittest, ReplaceUrlPlaceholdersInvalidTemplate) {
const GURL kUrl(kUrlSpec);
GURL url_template_filled;
// Badly nested placeholders.
GURL url_template = GURL("http://example.com/?q={");
bool succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = GURL("http://example.com/?q={title");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = GURL("http://example.com/?q={title{text}}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = GURL("http://example.com/?q={title{}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = GURL("http://example.com/?q={{title}}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
// No placeholders
std::string url_template = "blank";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
// Placeholder with non-identifier character.
url_template = GURL("http://example.com/?q={title?}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
// Invalid placeholder in URL fragment.
url_template = GURL("http://example.com/#{title?}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_FALSE(succeeded);
}
TEST_F(ShareServiceImplUnittest, ReplaceUrlPlaceholders) {
const GURL kUrl(kUrlSpec);
// No placeholders.
GURL url_template = GURL("http://example.com/?q=a#a");
GURL url_template_filled;
bool succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("blank", url_template_filled);
EXPECT_EQ(url_template, url_template_filled);
// Empty |url_template|
url_template = "";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL();
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("", url_template_filled);
EXPECT_EQ(GURL(), url_template_filled);
// One title placeholder.
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{title}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("My%20title", url_template_filled);
EXPECT_EQ("http://example.com/#My%20title", url_template_filled.spec());
// One text placeholder.
url_template = "{text}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{text}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("My%20text", url_template_filled);
EXPECT_EQ("http://example.com/#My%20text", url_template_filled.spec());
// One url placeholder.
url_template = "{url}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{url}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("https%3A%2F%2Fwww.google.com%2F", url_template_filled);
EXPECT_EQ("http://example.com/#https%3A%2F%2Fwww.google.com%2F",
url_template_filled.spec());
// One of each placeholder, in title, text, url order.
url_template = "{title}{text}{url}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{title}{text}{url}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("My%20titleMy%20texthttps%3A%2F%2Fwww.google.com%2F",
url_template_filled);
EXPECT_EQ(
"http://example.com/#My%20titleMy%20texthttps%3A%2F%2Fwww.google.com%2F",
url_template_filled.spec());
// One of each placeholder, in url, text, title order.
url_template = "{url}{text}{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{url}{text}{title}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("https%3A%2F%2Fwww.google.com%2FMy%20textMy%20title",
url_template_filled);
EXPECT_EQ(
"http://example.com/#https%3A%2F%2Fwww.google.com%2FMy%20textMy%20title",
url_template_filled.spec());
// Two of each placeholder, some next to each other, others not.
url_template = "{title}{url}{text}{text}{title}{url}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template =
GURL("http://example.com/#{title}{url}{text}{text}{title}{url}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ(
"My%20titlehttps%3A%2F%2Fwww.google.com%2FMy%20textMy%20textMy%20"
"titlehttps%3A%2F%2Fwww.google.com%2F",
url_template_filled);
"http://example.com/"
"#My%20titlehttps%3A%2F%2Fwww.google.com%2FMy%20textMy%20textMy%"
"20titlehttps%3A%2F%2Fwww.google.com%2F",
url_template_filled.spec());
// Placeholders are in a query string, as values. The expected use case.
// Two of each placeholder, some next to each other, others not.
url_template =
"?title={title}&url={url}&text={text}&text={text}&"
"title={title}&url={url}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL(
"http://example.com?title={title}&url={url}&text={text}&text={text}&"
"title={title}&url={url}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ(
"?title=My%20title&url=https%3A%2F%2Fwww.google.com%2F&text=My%20text&"
"http://"
"example.com/?title=My%20title&url=https%3A%2F%2Fwww.google.com%2F&"
"text=My%20text&"
"text=My%20text&title=My%20title&url=https%3A%2F%2Fwww.google.com%2F",
url_template_filled);
// Badly nested placeholders.
url_template = "{";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = "{title";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = "{title{text}}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = "{title{}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template = "{title}}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
EXPECT_FALSE(succeeded);
// Placeholder with non-identifier character.
url_template = "{title?}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
EXPECT_FALSE(succeeded);
url_template_filled.spec());
// Placeholder with digit character.
url_template = "{title1}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{title1}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("", url_template_filled);
EXPECT_EQ("http://example.com/#", url_template_filled.spec());
// Empty placeholder.
url_template = "{}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("", url_template_filled);
EXPECT_EQ("http://example.com/#", url_template_filled.spec());
// Unexpected placeholders.
url_template = "{nonexistentplaceholder}";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com/#{nonexistentplaceholder}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("http://example.com/#", url_template_filled.spec());
// Placeholders should only be replaced in query and fragment.
url_template = GURL("http://example.com/subpath{title}/?q={title}#{title}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("http://example.com/subpath%7Btitle%7D/?q=My%20title#My%20title",
url_template_filled.spec());
// Braces in the path, which would be invalid, but should parse fine as they
// are escaped.
url_template = GURL("http://example.com/subpath{/?q={title}");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("", url_template_filled);
EXPECT_EQ("http://example.com/subpath%7B/?q=My%20title",
url_template_filled.spec());
// |url_template| with % escapes.
url_template = "%20{title}%20";
succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText,
url, &url_template_filled);
url_template = GURL("http://example.com#%20{title}%20");
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
url_template, kTitle, kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("%20My%20title%20", url_template_filled);
EXPECT_EQ("http://example.com/#%20My%20title%20", url_template_filled.spec());
}
// Test URL escaping done by ReplaceUrlPlaceholders().
TEST_F(ShareServiceImplUnittest, ReplaceUrlPlaceholders_Escaping) {
const GURL kUrl(kUrlSpec);
const GURL kUrlTemplate("http://example.com/#{title}");
// Share data that contains percent escapes.
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(
url_template, "My%20title", kText, url, &url_template_filled);
GURL url_template_filled;
bool succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate, "My%20title", kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("My%2520title", url_template_filled);
EXPECT_EQ("http://example.com/#My%2520title", url_template_filled.spec());
// Share data that contains placeholders. These should not be replaced.
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(
url_template, "{title}", kText, url, &url_template_filled);
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate, "{title}", kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("%7Btitle%7D", url_template_filled);
EXPECT_EQ("http://example.com/#%7Btitle%7D", url_template_filled.spec());
// All characters that shouldn't be escaped.
url_template = "{title}";
succeeded =
ShareServiceImpl::ReplacePlaceholders(url_template,
"-_.!~*'()0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz",
kText, url, &url_template_filled);
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate,
"-_.!~*'()0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz",
kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ(
"-_.!~*'()0123456789"
"http://example.com/#-_.!~*'()0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz",
url_template_filled);
url_template_filled.spec());
// All characters that should be escaped.
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(
url_template, " \"#$%&+,/:;<=>?@[\\]^`{|}", kText, url,
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate, " \"#$%&+,/:;<=>?@[\\]^`{|}", kText, kUrl,
&url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ(
"%20%22%23%24%25%26%2B%2C%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%60%7B%7C%"
"http://example.com/"
"#%20%22%23%24%25%26%2B%2C%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%60%7B%7C%"
"7D",
url_template_filled);
url_template_filled.spec());
// Unicode chars.
// U+263B
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(
url_template, "\xe2\x98\xbb", kText, url, &url_template_filled);
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate, "\xe2\x98\xbb", kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("%E2%98%BB", url_template_filled);
EXPECT_EQ("http://example.com/#%E2%98%BB", url_template_filled.spec());
// U+00E9
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(
url_template, "\xc3\xa9", kText, url, &url_template_filled);
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate, "\xc3\xa9", kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("%C3%A9", url_template_filled);
EXPECT_EQ("http://example.com/#%C3%A9", url_template_filled.spec());
// U+1F4A9
url_template = "{title}";
succeeded = ShareServiceImpl::ReplacePlaceholders(
url_template, "\xf0\x9f\x92\xa9", kText, url, &url_template_filled);
succeeded = ShareServiceImpl::ReplaceUrlPlaceholders(
kUrlTemplate, "\xf0\x9f\x92\xa9", kText, kUrl, &url_template_filled);
EXPECT_TRUE(succeeded);
EXPECT_EQ("%F0%9F%92%A9", url_template_filled);
EXPECT_EQ("http://example.com/#%F0%9F%92%A9", url_template_filled.spec());
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment