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) { ...@@ -31,24 +31,14 @@ bool IsIdentifier(char c) {
return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || c == '-' || c == '_'; return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || c == '-' || c == '_';
} }
} // namespace // Returns to |out| the result of running the "replace placeholders" algorithm
// on |template_string|. The algorithm is specified at
ShareServiceImpl::ShareServiceImpl() : weak_factory_(this) {} // https://wicg.github.io/web-share-target/#dfn-replace-placeholders
ShareServiceImpl::~ShareServiceImpl() = default; bool ReplacePlaceholders(base::StringPiece template_string,
base::StringPiece title,
// static base::StringPiece text,
void ShareServiceImpl::Create( const GURL& share_url,
blink::mojom::ShareServiceRequest request) { std::string* out) {
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) {
constexpr char kTitlePlaceholder[] = "title"; constexpr char kTitlePlaceholder[] = "title";
constexpr char kTextPlaceholder[] = "text"; constexpr char kTextPlaceholder[] = "text";
constexpr char kUrlPlaceholder[] = "url"; constexpr char kUrlPlaceholder[] = "url";
...@@ -64,10 +54,10 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template, ...@@ -64,10 +54,10 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
std::vector<base::StringPiece> split_template; std::vector<base::StringPiece> split_template;
bool last_saw_open = false; bool last_saw_open = false;
size_t start_index_to_copy = 0; 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 (last_saw_open) {
if (url_template[i] == '}') { if (template_string[i] == '}') {
base::StringPiece placeholder = url_template.substr( base::StringPiece placeholder = template_string.substr(
start_index_to_copy + 1, i - 1 - start_index_to_copy); start_index_to_copy + 1, i - 1 - start_index_to_copy);
auto it = placeholder_to_data.find(placeholder); auto it = placeholder_to_data.find(placeholder);
if (it != placeholder_to_data.end()) { if (it != placeholder_to_data.end()) {
...@@ -77,17 +67,17 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template, ...@@ -77,17 +67,17 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
last_saw_open = false; last_saw_open = false;
start_index_to_copy = i + 1; 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. // Error: Non-identifier character seen after open.
return false; return false;
} }
} else { } else {
if (url_template[i] == '}') { if (template_string[i] == '}') {
// Error: Saw close, with no corresponding open. // Error: Saw close, with no corresponding open.
return false; return false;
} else if (url_template[i] == '{') { } else if (template_string[i] == '{') {
split_template.push_back( split_template.push_back(template_string.substr(
url_template.substr(start_index_to_copy, i - start_index_to_copy)); start_index_to_copy, i - start_index_to_copy));
last_saw_open = true; last_saw_open = true;
start_index_to_copy = i; start_index_to_copy = i;
...@@ -98,10 +88,47 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template, ...@@ -98,10 +88,47 @@ bool ShareServiceImpl::ReplacePlaceholders(base::StringPiece url_template,
// Error: Saw open that was never closed. // Error: Saw open that was never closed.
return false; return false;
} }
split_template.push_back(url_template.substr( split_template.push_back(template_string.substr(
start_index_to_copy, url_template.size() - start_index_to_copy)); 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; return true;
} }
...@@ -195,13 +222,9 @@ void ShareServiceImpl::OnPickerClosed(const std::string& title, ...@@ -195,13 +222,9 @@ void ShareServiceImpl::OnPickerClosed(const std::string& title,
return; return;
} }
// This will only replace placeholders found in the query and the fragment GURL url_template_filled;
// parts of the URL. This happens implicitly, because '{' and '}' found in the if (!ReplaceUrlPlaceholders(result->url_template(), title, text, share_url,
// path will have been escaped during URL parsing, and thus won't be seen as &url_template_filled)) {
// placeholders by ReplacePlaceholders().
std::string url_template_filled;
if (!ReplacePlaceholders(result->url_template().spec(), title, text,
share_url, &url_template_filled)) {
// TODO(mgiuca): This error should not be possible at share time, because // TODO(mgiuca): This error should not be possible at share time, because
// targets with invalid templates should not be chooseable. Fix // targets with invalid templates should not be chooseable. Fix
// https://crbug.com/694380 and replace this with a DCHECK. // https://crbug.com/694380 and replace this with a DCHECK.
...@@ -209,12 +232,11 @@ void ShareServiceImpl::OnPickerClosed(const std::string& title, ...@@ -209,12 +232,11 @@ void ShareServiceImpl::OnPickerClosed(const std::string& title,
return; return;
} }
const GURL target(url_template_filled);
// User should not be able to cause an invalid target URL. The replaced pieces // 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 // are escaped. If somehow we slip through this DCHECK, it will just open
// about:blank. // about:blank.
DCHECK(target.is_valid()); DCHECK(url_template_filled.is_valid());
OpenTargetURL(target); OpenTargetURL(url_template_filled);
std::move(callback).Run(blink::mojom::ShareError::OK); std::move(callback).Run(blink::mojom::ShareError::OK);
} }
...@@ -39,7 +39,11 @@ class ShareServiceImpl : public blink::mojom::ShareService { ...@@ -39,7 +39,11 @@ class ShareServiceImpl : public blink::mojom::ShareService {
ShareCallback callback) override; ShareCallback callback) override;
private: 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(); Browser* GetBrowser();
...@@ -70,18 +74,18 @@ class ShareServiceImpl : public blink::mojom::ShareService { ...@@ -70,18 +74,18 @@ class ShareServiceImpl : public blink::mojom::ShareService {
std::vector<WebShareTarget> GetTargetsWithSufficientEngagement(); std::vector<WebShareTarget> GetTargetsWithSufficientEngagement();
// Writes to |url_template_filled|, a copy of |url_template| with all // Writes to |url_template_filled|, a copy of |url_template| with all
// instances of "{title}", "{text}", and "{url}" replaced with // instances of "{title}", "{text}", and "{url}" in the query and fragment
// |title|, |text|, and |url| respectively. // parts of the URL replaced with |title|, |text|, and |url| respectively.
// Replaces instances of "{X}" where "X" is any string besides "title", // Replaces instances of "{X}" where "X" is any string besides "title",
// "text", and "url", with an empty string, for forwards compatibility. // "text", and "url", with an empty string, for forwards compatibility.
// Returns false, if there are badly nested placeholders. // Returns false, if there are badly nested placeholders.
// This includes any case in which two "{" occur before a "}", or a "}" // This includes any case in which two "{" occur before a "}", or a "}"
// occurs with no preceding "{". // occurs with no preceding "{".
static bool ReplacePlaceholders(base::StringPiece url_template, static bool ReplaceUrlPlaceholders(const GURL& url_template,
base::StringPiece title, base::StringPiece title,
base::StringPiece text, base::StringPiece text,
const GURL& share_url, const GURL& share_url,
std::string* url_template_filled); GURL* url_template_filled);
void OnPickerClosed(const std::string& title, void OnPickerClosed(const std::string& title,
const std::string& text, const std::string& text,
......
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