Skip to content

Commit

Permalink
[Payments] Allow at most three redirects when downloading payment met…
Browse files Browse the repository at this point in the history
…hods manifests

Bug: 847572
Change-Id: Ibe089ddb6aff0e0f1b424bf830a4092cb1f2c295
Reviewed-on: https://chromium-review.googlesource.com/1079149
Reviewed-by: Mathieu Perreault <[email protected]>
Commit-Queue: Ganggui Tang <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#563106}(cherry picked from commit 932bd30)
Reviewed-on: https://chromium-review.googlesource.com/1082451
Reviewed-by: Ganggui Tang <[email protected]>
Cr-Commit-Position: refs/branch-heads/3440@{#84}
Cr-Branched-From: 010ddcf-refs/heads/master@{#561733}
  • Loading branch information
gogerald authored and Ganggui Tang committed Jun 1, 2018
1 parent 552c7bf commit c1d1d4e
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 11 deletions.
54 changes: 44 additions & 10 deletions components/payments/core/payment_manifest_downloader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,29 @@ GURL ParseResponseHeader(const net::URLFetcher* source) {
return GURL();
}

bool IsValidManifestUrl(const GURL& url) {
return url.is_valid() &&
(url.SchemeIs(url::kHttpsScheme) ||
(url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url)));
}

GURL ParseRedirectUrlFromResponseHeader(const net::URLFetcher* source) {
// Do not follow net::HTTP_MULTIPLE_CHOICES, net::HTTP_NOT_MODIFIED and
// net::HTTP_USE_PROXY redirects.
if (source->GetResponseCode() != net::HTTP_MOVED_PERMANENTLY &&
source->GetResponseCode() != net::HTTP_FOUND &&
source->GetResponseCode() != net::HTTP_SEE_OTHER &&
source->GetResponseCode() != net::HTTP_TEMPORARY_REDIRECT &&
source->GetResponseCode() != net::HTTP_PERMANENT_REDIRECT) {
return GURL();
}

if (!IsValidManifestUrl(source->GetURL()))
return GURL();

return source->GetURL();
}

std::string ParseResponseContent(const net::URLFetcher* source) {
std::string content;
if (source->GetResponseCode() != net::HTTP_OK) {
Expand All @@ -99,14 +122,17 @@ void PaymentManifestDownloader::DownloadPaymentMethodManifest(
const GURL& url,
PaymentManifestDownloadCallback callback) {
DCHECK(IsValidManifestUrl(url));
InitiateDownload(url, net::URLFetcher::HEAD, std::move(callback));
// Restrict number of redirects for efficiency and breaking circle.
InitiateDownload(url, net::URLFetcher::HEAD,
/*allowed_number_of_redirects=*/3, std::move(callback));
}

void PaymentManifestDownloader::DownloadWebAppManifest(
const GURL& url,
PaymentManifestDownloadCallback callback) {
DCHECK(IsValidManifestUrl(url));
InitiateDownload(url, net::URLFetcher::GET, std::move(callback));
InitiateDownload(url, net::URLFetcher::GET, /*allowed_number_of_redirects=*/0,
std::move(callback));
}

PaymentManifestDownloader::Download::Download() {}
Expand All @@ -122,13 +148,25 @@ void PaymentManifestDownloader::OnURLFetchComplete(
downloads_.erase(download_it);

if (download->request_type == net::URLFetcher::HEAD) {
// Manually follow some type of redirects.
if (download->allowed_number_of_redirects > 0) {
GURL redirect_url = ParseRedirectUrlFromResponseHeader(source);
if (!redirect_url.is_empty()) {
InitiateDownload(redirect_url, net::URLFetcher::HEAD,
--download->allowed_number_of_redirects,
std::move(download->callback));
return;
}
}

GURL url = ParseResponseHeader(source);
if (IsValidManifestUrl(url)) {
InitiateDownload(url, net::URLFetcher::GET,
/*allowed_number_of_redirects=*/0,
std::move(download->callback));
} else {
// If the URL is empty, then ParseResponseHeader() has already printed an
// explanation.
// If the URL is empty, then ParseResponseHeader() has already printed
// an explanation.
if (!url.is_empty())
LOG(ERROR) << url << " is not a valid payment method manifest URL.";
std::move(download->callback).Run(std::string());
Expand All @@ -141,6 +179,7 @@ void PaymentManifestDownloader::OnURLFetchComplete(
void PaymentManifestDownloader::InitiateDownload(
const GURL& url,
net::URLFetcher::RequestType request_type,
int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback) {
DCHECK(IsValidManifestUrl(url));

Expand Down Expand Up @@ -178,17 +217,12 @@ void PaymentManifestDownloader::InitiateDownload(
download->request_type = request_type;
download->fetcher = std::move(fetcher);
download->callback = std::move(callback);
download->allowed_number_of_redirects = allowed_number_of_redirects;

const net::URLFetcher* identifier = download->fetcher.get();
auto insert_result =
downloads_.insert(std::make_pair(identifier, std::move(download)));
DCHECK(insert_result.second); // Whether the insert has succeeded.
}

bool PaymentManifestDownloader::IsValidManifestUrl(const GURL& url) {
return url.is_valid() &&
(url.SchemeIs(url::kHttpsScheme) ||
(url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url)));
}

} // namespace payments
3 changes: 2 additions & 1 deletion components/payments/core/payment_manifest_downloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class PaymentManifestDownloader : public net::URLFetcherDelegate {
Download();
~Download();

int allowed_number_of_redirects = 0;
net::URLFetcher::RequestType request_type;
std::unique_ptr<net::URLFetcher> fetcher;
PaymentManifestDownloadCallback callback;
Expand All @@ -98,8 +99,8 @@ class PaymentManifestDownloader : public net::URLFetcherDelegate {

void InitiateDownload(const GURL& url,
net::URLFetcher::RequestType request_type,
int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback);
bool IsValidManifestUrl(const GURL& url);

scoped_refptr<net::URLRequestContextGetter> context_;

Expand Down
139 changes: 139 additions & 0 deletions components/payments/core/payment_manifest_downloader_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,145 @@ TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) {
fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, 300IsUnsupportedRedirect) {
fetcher()->set_response_code(300);
fetcher()->set_url(GURL("https://alicepay.com"));

EXPECT_CALL(*this, OnManifestDownload(std::string()));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, 301And302AreSupportedRedirects) {
fetcher()->set_response_code(301);
fetcher()->set_url(GURL("https://alicepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));

fetcher()->set_response_code(302);
fetcher()->set_url(GURL("https://charliepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));

scoped_refptr<net::HttpResponseHeaders> headers(
new net::HttpResponseHeaders(std::string()));
headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
fetcher()->set_response_headers(headers);
fetcher()->set_response_code(200);
fetcher()->delegate()->OnURLFetchComplete(fetcher());
fetcher()->SetResponseString("manifest content");
fetcher()->set_response_code(200);

EXPECT_CALL(*this, OnManifestDownload("manifest content"));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, 302And303AreSupportedRedirects) {
fetcher()->set_response_code(302);
fetcher()->set_url(GURL("https://alicepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));

fetcher()->set_response_code(303);
fetcher()->set_url(GURL("https://charliepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));

scoped_refptr<net::HttpResponseHeaders> headers(
new net::HttpResponseHeaders(std::string()));
headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
fetcher()->set_response_headers(headers);
fetcher()->set_response_code(200);
fetcher()->delegate()->OnURLFetchComplete(fetcher());
fetcher()->SetResponseString("manifest content");
fetcher()->set_response_code(200);

EXPECT_CALL(*this, OnManifestDownload("manifest content"));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, 304IsUnsupportedRedirect) {
fetcher()->set_response_code(304);
fetcher()->set_url(GURL("https://alicepay.com"));

EXPECT_CALL(*this, OnManifestDownload(std::string()));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, 305IsUnsupportedRedirect) {
fetcher()->set_response_code(305);
fetcher()->set_url(GURL("https://alicepay.com"));

EXPECT_CALL(*this, OnManifestDownload(std::string()));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, 307And308AreSupportedRedirects) {
fetcher()->set_response_code(307);
fetcher()->set_url(GURL("https://alicepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));

fetcher()->set_response_code(308);
fetcher()->set_url(GURL("https://charliepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));

scoped_refptr<net::HttpResponseHeaders> headers(
new net::HttpResponseHeaders(std::string()));
headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
fetcher()->set_response_headers(headers);
fetcher()->set_response_code(200);
fetcher()->delegate()->OnURLFetchComplete(fetcher());
fetcher()->SetResponseString("manifest content");
fetcher()->set_response_code(200);

EXPECT_CALL(*this, OnManifestDownload("manifest content"));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, NoMoreThanThreeRediects) {
fetcher()->set_response_code(301);
fetcher()->set_url(GURL("https://alicepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));

fetcher()->set_response_code(302);
fetcher()->set_url(GURL("https://charliepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));

fetcher()->set_response_code(308);
fetcher()->set_url(GURL("https://davepay.com"));
fetcher()->delegate()->OnURLFetchComplete(fetcher());

EXPECT_CALL(*this, OnManifestDownload(std::string()));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

TEST_F(PaymentMethodManifestDownloaderTest, InvalidRedirectUrlIsFailure) {
fetcher()->set_response_code(308);
fetcher()->set_url(GURL("alicepay.com"));

EXPECT_CALL(*this, OnManifestDownload(std::string()));

fetcher()->delegate()->OnURLFetchComplete(fetcher());
}

class WebAppManifestDownloaderTest : public testing::Test {
public:
WebAppManifestDownloaderTest()
Expand Down

0 comments on commit c1d1d4e

Please sign in to comment.