File: payment_manifest_downloader.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (220 lines) | stat: -rw-r--r-- 8,527 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_MANIFEST_DOWNLOADER_H_
#define COMPONENTS_PAYMENTS_CORE_PAYMENT_MANIFEST_DOWNLOADER_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace net {
class HttpResponseHeaders;
struct RedirectInfo;
}  // namespace net

namespace network {
class SharedURLLoaderFactory;
class SimpleURLLoader;
}  // namespace network

namespace payments {

class CSPChecker;
class ErrorLogger;

// Called on completed download of a manifest |contents| from |url|, which is
// the final URL after following the redirects, if any.
//
// Download failure results in empty contents. Failure to download the manifest
// can happen because of the following reasons:
//  - HTTP response code is not 200. (204 is also allowed for payment method
//    manifest.)
//
// In the case of a payment method manifest download, can also fail when:
//  - More than three redirects.
//  - Cross-site redirects.
//  - HTTP GET on the manifest URL returns empty content and:
//      - HTTP response headers are absent.
//      - HTTP response headers do not contain Link headers.
//      - Link header does not contain rel="payment-method-manifest".
//      - Link header does not contain a valid URL of the same origin.
//  - After following the Link header:
//      - There's a redirect.
//      - HTTP GET returns empty content.
//
// In the case of a web app manifest download, can also also fail when:
//  - There's a redirect.
//  - HTTP GET on the manifest URL returns empty content.
using PaymentManifestDownloadCallback =
    base::OnceCallback<void(const GURL& url,
                            const std::string& contents,
                            const std::string& error_message)>;

// Downloader of the payment method manifest and web-app manifest based on the
// payment method name that is a URL with HTTPS scheme, e.g.,
// https://bobpay.com.
//
// The downloader follows up to three redirects for the payment method manifest
// request only. Three is enough for known legitimate use cases and seems like a
// good upper bound.
//
// The command line must be initialized to use this class in tests, because it
// checks for --unsafely-treat-insecure-origin-as-secure=<origin> flag. For
// example:
//  base::CommandLine::Init(0, nullptr);
class PaymentManifestDownloader {
 public:
  PaymentManifestDownloader(
      std::unique_ptr<ErrorLogger> log,
      base::WeakPtr<CSPChecker> csp_checker,
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);

  PaymentManifestDownloader(const PaymentManifestDownloader&) = delete;
  PaymentManifestDownloader& operator=(const PaymentManifestDownloader&) =
      delete;

  virtual ~PaymentManifestDownloader();

  // Download a payment method manifest from |url| via a GET. The HTTP response
  // header is parsed for Link header. If there is no Link header, then the body
  // is returned. If there's a Link header, then it is followed exactly once.
  // Example header:
  //
  //      Link: <data/payment-manifest.json>; rel="payment-method-manifest"
  //
  // (This is relative to the payment method URL.) Example of an absolute
  // location:
  //
  //      Link: <https://bobpay.com/data/payment-manifest.json>;
  //      rel="payment-method-manifest"
  //
  // The absolute location must use HTTPS scheme.
  //
  // |merchant_origin| should be the origin of the iframe that created the
  // PaymentRequest object. It is used by security features like
  // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
  //
  // |url| should be valid according to UrlUtil::IsValidManifestUrl() to
  // download.
  void DownloadPaymentMethodManifest(const url::Origin& merchant_origin,
                                     const GURL& url,
                                     PaymentManifestDownloadCallback callback);

  // Download a web app manifest from |url| via a single HTTP request:
  //
  // 1) GET request for the payment method name.
  //
  // |payment_method_manifest_origin| should be the origin of the payment method
  // manifest that is pointing to this web app manifest. It is used for security
  // features like 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
  //
  // |url| should be valid according to UrlUtil::IsValidManifestUrl() to
  // download.
  void DownloadWebAppManifest(const url::Origin& payment_method_manifest_origin,
                              const GURL& url,
                              PaymentManifestDownloadCallback callback);

  // Overridden in TestDownloader to convert |url| to a test server URL. The
  // default implementation here simply returns |url|.
  virtual GURL FindTestServerURL(const GURL& url) const;

  // Overridden in TestDownloader to allow modifying CSP. Should not be called
  // in production.
  virtual void SetCSPCheckerForTesting(base::WeakPtr<CSPChecker> csp_checker);

 private:
  friend class PaymentManifestDownloaderTestBase;
  friend class TestDownloader;

  // Information about an ongoing download request.
  struct Download {
    enum class Type {
      LINK_HEADER_WITH_FALLBACK_TO_RESPONSE_BODY,
      FALLBACK_TO_RESPONSE_BODY,
      RESPONSE_BODY,
    };

    Download();
    ~Download();

    // Returns true if this download is an HTTP HEAD request for a payment
    // manifest.
    bool IsLinkHeaderDownload() const;

    // Returns true if this download is an HTTP GET request either for payment
    // method manifest or for a web app manifest file.
    bool IsResponseBodyDownload() const;

    int allowed_number_of_redirects = 0;
    Type type = Type::RESPONSE_BODY;
    url::Origin request_initiator;
    GURL original_url;
    GURL url_before_redirects;
    bool did_follow_redirect = false;
    std::unique_ptr<network::SimpleURLLoader> loader;
    PaymentManifestDownloadCallback callback;
  };

  // Called by SimpleURLLoader on a redirect.
  void OnURLLoaderRedirect(network::SimpleURLLoader* url_loader,
                           const GURL& url_before_redirect,
                           const net::RedirectInfo& redirect_info,
                           const network::mojom::URLResponseHead& response_head,
                           std::vector<std::string>* to_be_removed_headers);

  // Called by SimpleURLLoader on completion.
  void OnURLLoaderComplete(network::SimpleURLLoader* url_loader,
                           std::optional<std::string> response_body);

  // Internally called by OnURLLoaderComplete, exposed to ease unit tests.
  void OnURLLoaderCompleteInternal(
      network::SimpleURLLoader* url_loader,
      const GURL& final_url,
      const std::string& response_body,
      scoped_refptr<net::HttpResponseHeaders> headers,
      int net_error);

  // Called by unittests to get the one in-progress loader.
  network::SimpleURLLoader* GetLoaderForTesting();

  // Called by unittests to get the original URL of the in-progress loader.
  GURL GetLoaderOriginalURLForTesting();

  // Overridden in TestDownloader.
  virtual void InitiateDownload(const url::Origin& request_initiator,
                                const GURL& url,
                                const GURL& url_before_redirects,
                                bool did_follow_redirect,
                                Download::Type download_type,
                                int allowed_number_of_redirects,
                                PaymentManifestDownloadCallback callback);

  void OnCSPCheck(std::unique_ptr<Download> download, bool csp_allowed);

  std::unique_ptr<ErrorLogger> log_;
  base::WeakPtr<CSPChecker> csp_checker_;
  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;

  // Downloads are identified by network::SimpleURLLoader pointers, because
  // that's the only unique piece of information that OnURLLoaderComplete()
  // receives. Can't rely on the URL of the download, because of possible
  // collision between HEAD and GET requests.
  std::map<const network::SimpleURLLoader*, std::unique_ptr<Download>>
      downloads_;

  base::WeakPtrFactory<PaymentManifestDownloader> weak_ptr_factory_{this};
};

}  // namespace payments

#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENT_MANIFEST_DOWNLOADER_H_