| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/payments/core/payment_manifest_downloader.h" |
| |
| #include "base/bind.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "components/payments/core/error_logger.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "services/network/public/cpp/simple_url_loader.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace payments { |
| namespace { |
| |
| using testing::_; |
| |
| static const char kNoError[] = ""; |
| |
| } // namespace |
| |
| class PaymentMethodManifestDownloaderTest : public testing::Test { |
| public: |
| PaymentMethodManifestDownloaderTest() |
| : test_url_("https://bobpay.com"), |
| shared_url_loader_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_factory_)), |
| downloader_(std::make_unique<ErrorLogger>(), |
| shared_url_loader_factory_) { |
| downloader_.DownloadPaymentMethodManifest( |
| test_url_, |
| base::BindOnce(&PaymentMethodManifestDownloaderTest::OnManifestDownload, |
| base::Unretained(this))); |
| } |
| |
| ~PaymentMethodManifestDownloaderTest() override {} |
| |
| MOCK_METHOD3(OnManifestDownload, |
| void(const GURL& unused_url_after_redirects, |
| const std::string& content, |
| const std::string& error_message)); |
| |
| void CallComplete(int response_code = 200, |
| const std::string& link_header = std::string(), |
| const std::string& response_body = std::string(), |
| bool send_headers = true) { |
| scoped_refptr<net::HttpResponseHeaders> headers; |
| if (send_headers) { |
| headers = base::MakeRefCounted<net::HttpResponseHeaders>(std::string()); |
| headers->ReplaceStatusLine(base::StringPrintf( |
| "HTTP/1.1 %d %s", response_code, |
| net::GetHttpReasonPhrase( |
| static_cast<net::HttpStatusCode>(response_code)))); |
| } |
| |
| if (!link_header.empty()) |
| headers->AddHeader(link_header); |
| downloader_.OnURLLoaderCompleteInternal( |
| downloader_.GetLoaderForTesting(), |
| downloader_.GetLoaderOriginalURLForTesting(), response_body, headers, |
| net::OK); |
| } |
| |
| void CallRedirect(int redirect_code, const GURL& new_url) { |
| net::RedirectInfo redirect_info; |
| redirect_info.status_code = redirect_code; |
| redirect_info.new_url = new_url; |
| std::vector<std::string> to_be_removed_headers; |
| |
| downloader_.OnURLLoaderRedirect( |
| downloader_.GetLoaderForTesting(), redirect_info, |
| network::ResourceResponseHead(), &to_be_removed_headers); |
| } |
| |
| GURL GetOriginalURL() { return downloader_.GetLoaderOriginalURLForTesting(); } |
| |
| private: |
| GURL test_url_; |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| network::TestURLLoaderFactory test_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; |
| PaymentManifestDownloader downloader_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PaymentMethodManifestDownloaderTest); |
| }; |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, HttpHeadResponse404IsFailure) { |
| EXPECT_CALL(*this, |
| OnManifestDownload( |
| _, std::string(), |
| "Unable to make a HEAD request to \"https://bobpay.com/\" " |
| "for payment method manifest.")); |
| |
| CallComplete(404); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, NoHttpHeadersIsFailure) { |
| EXPECT_CALL( |
| *this, OnManifestDownload(_, std::string(), |
| "No \"Link: rel=payment-method-manifest\" HTTP " |
| "header found at \"https://bobpay.com/\".")); |
| |
| CallComplete(200, std::string(), std::string(), false); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpHeaderIsFailure) { |
| EXPECT_CALL( |
| *this, OnManifestDownload(_, std::string(), |
| "No \"Link: rel=payment-method-manifest\" HTTP " |
| "header found at \"https://bobpay.com/\".")); |
| |
| CallComplete(200); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpLinkHeaderIsFailure) { |
| scoped_refptr<net::HttpResponseHeaders> headers( |
| new net::HttpResponseHeaders(std::string())); |
| EXPECT_CALL( |
| *this, OnManifestDownload(_, std::string(), |
| "No \"Link: rel=payment-method-manifest\" HTTP " |
| "header found at \"https://bobpay.com/\".")); |
| |
| CallComplete(200, "Link:"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, NoRelInHttpLinkHeaderIsFailure) { |
| EXPECT_CALL( |
| *this, OnManifestDownload(_, std::string(), |
| "No \"Link: rel=payment-method-manifest\" HTTP " |
| "header found at \"https://bobpay.com/\".")); |
| |
| CallComplete(200, "Link: <manifest.json>"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, NoUrlInHttpLinkHeaderIsFailure) { |
| EXPECT_CALL( |
| *this, OnManifestDownload(_, std::string(), |
| "No \"Link: rel=payment-method-manifest\" HTTP " |
| "header found at \"https://bobpay.com/\".")); |
| |
| CallComplete(200, "Link: rel=payment-method-manifest"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, |
| NoManifestRellInHttpLinkHeaderIsFailure) { |
| EXPECT_CALL( |
| *this, OnManifestDownload(_, std::string(), |
| "No \"Link: rel=payment-method-manifest\" HTTP " |
| "header found at \"https://bobpay.com/\".")); |
| |
| CallComplete(200, "Link: <manifest.json>; rel=web-app-manifest"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, HttpGetResponse404IsFailure) { |
| scoped_refptr<net::HttpResponseHeaders> headers( |
| new net::HttpResponseHeaders(std::string())); |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, |
| OnManifestDownload(_, std::string(), |
| "Unable to download payment manifest " |
| "\"https://bobpay.com/manifest.json\".")); |
| |
| CallComplete(404); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpGetResponseIsFailure) { |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, |
| OnManifestDownload(_, std::string(), |
| "Unable to download payment manifest " |
| "\"https://bobpay.com/manifest.json\".")); |
| |
| CallComplete(200, std::string(), std::string(), false); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) { |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); |
| |
| CallComplete(200, std::string(), "manifest content"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, HeaderResponseCode204IsSuccess) { |
| CallComplete(204, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); |
| |
| CallComplete(200, std::string(), "manifest content"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, RelativeHttpHeaderLinkUrl) { |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_EQ("https://bobpay.com/manifest.json", GetOriginalURL()); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpsHeaderLinkUrl) { |
| CallComplete(200, |
| "Link: <https://bobpay.com/manifest.json>; " |
| "rel=payment-method-manifest"); |
| |
| EXPECT_EQ("https://bobpay.com/manifest.json", GetOriginalURL()); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) { |
| EXPECT_CALL( |
| *this, |
| OnManifestDownload( |
| _, std::string(), |
| "\"http://bobpay.com/manifest.json\" is not a valid payment manifest " |
| "URL with HTTPS scheme (or HTTP scheme for localhost).")); |
| |
| CallComplete(200, |
| "Link: <http://bobpay.com/manifest.json>; " |
| "rel=payment-method-manifest"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, 300IsUnsupportedRedirect) { |
| EXPECT_CALL(*this, |
| OnManifestDownload( |
| _, std::string(), |
| "HTTP status code 300 \"Multiple Choices\" not allowed for " |
| "payment method manifest \"https://bobpay.com/\".")); |
| |
| CallRedirect(300, GURL("https://pay.bobpay.com")); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, 301And302AreSupportedRedirects) { |
| CallRedirect(301, GURL("https://pay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com")); |
| |
| CallRedirect(302, GURL("https://newpay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com")); |
| |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); |
| |
| CallComplete(200, std::string(), "manifest content"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, 302And303AreSupportedRedirects) { |
| CallRedirect(302, GURL("https://pay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com")); |
| |
| CallRedirect(303, GURL("https://newpay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com")); |
| |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); |
| |
| CallComplete(200, std::string(), "manifest content"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, 304IsUnsupportedRedirect) { |
| EXPECT_CALL(*this, |
| OnManifestDownload( |
| _, std::string(), |
| "HTTP status code 304 \"Not Modified\" not allowed for " |
| "payment method manifest \"https://bobpay.com/\".")); |
| |
| CallRedirect(304, GURL("https://pay.bobpay.com")); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, 305IsUnsupportedRedirect) { |
| EXPECT_CALL(*this, OnManifestDownload( |
| _, std::string(), |
| "HTTP status code 305 \"Use Proxy\" not allowed for " |
| "payment method manifest \"https://bobpay.com/\".")); |
| |
| CallRedirect(305, GURL("https://pay.bobpay.com")); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, 307And308AreSupportedRedirects) { |
| CallRedirect(307, GURL("https://pay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com")); |
| |
| CallRedirect(308, GURL("https://newpay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com")); |
| |
| CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); |
| |
| EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); |
| |
| CallComplete(200, std::string(), "manifest content"); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, NoMoreThanThreeRedirects) { |
| CallRedirect(301, GURL("https://pay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com")); |
| |
| CallRedirect(302, GURL("https://oldpay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://oldpay.bobpay.com")); |
| |
| CallRedirect(308, GURL("https://newpay.bobpay.com")); |
| |
| EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com")); |
| |
| EXPECT_CALL(*this, OnManifestDownload( |
| _, std::string(), |
| "Unable to download the payment manifest because " |
| "reached the maximum number of redirects.")); |
| |
| CallRedirect(308, GURL("https://newpay.bobpay.com")); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, InvalidRedirectUrlIsFailure) { |
| EXPECT_CALL(*this, OnManifestDownload( |
| _, std::string(), |
| "\"\" is not a valid payment manifest URL with HTTPS " |
| "scheme (or HTTP scheme for localhost).")); |
| |
| CallRedirect(308, GURL("pay.bobpay.com")); |
| } |
| |
| TEST_F(PaymentMethodManifestDownloaderTest, NotAllowCrossSiteRedirects) { |
| EXPECT_CALL( |
| *this, |
| OnManifestDownload( |
| _, std::string(), |
| "Cross-site redirect from \"https://bobpay.com/\" to " |
| "\"https://alicepay.com/\" not allowed for payment manifests.")); |
| |
| CallRedirect(301, GURL("https://alicepay.com")); |
| } |
| |
| class WebAppManifestDownloaderTest : public testing::Test { |
| public: |
| WebAppManifestDownloaderTest() |
| : test_url_("https://bobpay.com"), |
| shared_url_loader_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_factory_)), |
| downloader_(std::make_unique<ErrorLogger>(), |
| shared_url_loader_factory_) { |
| downloader_.DownloadWebAppManifest( |
| test_url_, |
| base::BindOnce(&WebAppManifestDownloaderTest::OnManifestDownload, |
| base::Unretained(this))); |
| } |
| |
| ~WebAppManifestDownloaderTest() override {} |
| |
| MOCK_METHOD3(OnManifestDownload, |
| void(const GURL& url, |
| const std::string& content, |
| const std::string& error_message)); |
| |
| void CallComplete(int response_code, |
| const std::string& response_body = std::string()) { |
| scoped_refptr<net::HttpResponseHeaders> headers = |
| base::MakeRefCounted<net::HttpResponseHeaders>(std::string()); |
| headers->ReplaceStatusLine(base::StringPrintf( |
| "HTTP/1.1 %d %s", response_code, |
| net::GetHttpReasonPhrase( |
| static_cast<net::HttpStatusCode>(response_code)))); |
| downloader_.OnURLLoaderCompleteInternal(downloader_.GetLoaderForTesting(), |
| test_url_, response_body, headers, |
| net::OK); |
| } |
| |
| private: |
| GURL test_url_; |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| network::TestURLLoaderFactory test_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; |
| PaymentManifestDownloader downloader_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebAppManifestDownloaderTest); |
| }; |
| |
| TEST_F(WebAppManifestDownloaderTest, HttpGetResponse404IsFailure) { |
| EXPECT_CALL( |
| *this, |
| OnManifestDownload( |
| _, std::string(), |
| "Unable to download payment manifest \"https://bobpay.com/\".")); |
| |
| CallComplete(404); |
| } |
| |
| TEST_F(WebAppManifestDownloaderTest, EmptyHttpGetResponseIsFailure) { |
| EXPECT_CALL(*this, OnManifestDownload(_, std::string(), kNoError)); |
| |
| CallComplete(200); |
| } |
| |
| TEST_F(WebAppManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) { |
| EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); |
| |
| CallComplete(200, "manifest content"); |
| } |
| |
| } // namespace payments |