1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PDF_PPAPI_MIGRATION_URL_LOADER_H_
6 #define PDF_PPAPI_MIGRATION_URL_LOADER_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <memory>
12 #include <string>
13 
14 #include "base/callback.h"
15 #include "base/containers/circular_deque.h"
16 #include "base/containers/span.h"
17 #include "base/memory/weak_ptr.h"
18 #include "pdf/ppapi_migration/callback.h"
19 #include "ppapi/cpp/instance_handle.h"
20 #include "ppapi/cpp/url_loader.h"
21 #include "third_party/blink/public/web/web_associated_url_loader_client.h"
22 
23 namespace blink {
24 class WebAssociatedURLLoader;
25 class WebString;
26 class WebURL;
27 class WebURLRequest;
28 struct WebAssociatedURLLoaderOptions;
29 }  // namespace blink
30 
31 namespace net {
32 class SiteForCookies;
33 }  // namespace net
34 
35 namespace chrome_pdf {
36 
37 // Properties for making a URL request.
38 struct UrlRequest final {
39   UrlRequest();
40   UrlRequest(const UrlRequest& other);
41   UrlRequest(UrlRequest&& other) noexcept;
42   UrlRequest& operator=(const UrlRequest& other);
43   UrlRequest& operator=(UrlRequest&& other) noexcept;
44   ~UrlRequest();
45 
46   // Request URL.
47   std::string url;
48 
49   // HTTP method.
50   std::string method;
51 
52   // Whether to ignore redirects. By default, redirects are followed
53   // automatically.
54   bool ignore_redirects = false;
55 
56   // Custom referrer URL.
57   std::string custom_referrer_url;
58 
59   // HTTP headers as a single string of `\n`-delimited key-value pairs.
60   std::string headers;
61 
62   // Request body.
63   std::string body;
64 
65   // Thresholds for throttling filling of the loader's internal buffer. Filling
66   // will stop after exceeding the upper threshold, and resume after dropping
67   // below the lower threshold.
68   //
69   // Default values taken from `ppapi/shared_impl/url_request_info_data.cc`. The
70   // PDF viewer never changes the defaults in production, so these fields mostly
71   // exist for testing purposes.
72   size_t buffer_lower_threshold = 50 * 1000 * 1000;
73   size_t buffer_upper_threshold = 100 * 1000 * 1000;
74 };
75 
76 // Properties returned from a URL request. Does not include the response body.
77 struct UrlResponse final {
78   UrlResponse();
79   UrlResponse(const UrlResponse& other);
80   UrlResponse(UrlResponse&& other) noexcept;
81   UrlResponse& operator=(const UrlResponse& other);
82   UrlResponse& operator=(UrlResponse&& other) noexcept;
83   ~UrlResponse();
84 
85   // HTTP status code.
86   int32_t status_code = 0;
87 
88   // HTTP headers as a single string of `\n`-delimited key-value pairs.
89   std::string headers;
90 };
91 
92 // Abstraction for a Blink or Pepper URL loader.
93 class UrlLoader {
94  public:
95   UrlLoader(const UrlLoader&) = delete;
96   UrlLoader& operator=(const UrlLoader&) = delete;
97   virtual ~UrlLoader();
98 
99   // Tries to grant the loader the capability to make unrestricted cross-origin
100   // requests ("universal access," in `blink::SecurityOrigin` terms). Must be
101   // called before `Open()`.
102   virtual void GrantUniversalAccess() = 0;
103 
104   // Mimic `pp::URLLoader`:
105   virtual void Open(const UrlRequest& request, ResultCallback callback) = 0;
106   virtual void ReadResponseBody(base::span<char> buffer,
107                                 ResultCallback callback) = 0;
108   virtual void Close() = 0;
109 
110   // Returns the URL response (not including the body). Only valid after
111   // `Open()` completes.
response()112   const UrlResponse& response() const { return response_; }
113 
114  protected:
115   UrlLoader();
116 
mutable_response()117   UrlResponse& mutable_response() { return response_; }
118 
119  private:
120   UrlResponse response_;
121 };
122 
123 // A Blink URL loader. This implementation tries to emulate a combination of
124 // `content::PepperURLLoaderHost` and `ppapi::proxy::URLLoaderResource`.
125 class BlinkUrlLoader final : public UrlLoader,
126                              public blink::WebAssociatedURLLoaderClient {
127  public:
128   // Client interface required by `BlinkUrlLoader`. Instances should be passed
129   // using weak pointers, as the loader can be shared, and may outlive the
130   // client.
131   class Client {
132    public:
133     // Returns `true` if the client is still usable. The client may require
134     // resources that can become unavailable, such as a local frame. Rather than
135     // handling missing resources separately for each method, callers can just
136     // verify validity once, before making any other calls.
137     virtual bool IsValid() const = 0;
138 
139     // Completes `partial_url` using the current document.
140     virtual blink::WebURL CompleteURL(
141         const blink::WebString& partial_url) const = 0;
142 
143     // Gets the site-for-cookies for the current document.
144     virtual net::SiteForCookies SiteForCookies() const = 0;
145 
146     // Sets the referrer on `request` to `referrer_url` using the current frame.
147     virtual void SetReferrerForRequest(blink::WebURLRequest& request,
148                                        const blink::WebURL& referrer_url) = 0;
149 
150     // Returns a new `blink::WebAssociatedURLLoader` from the current frame.
151     virtual std::unique_ptr<blink::WebAssociatedURLLoader>
152     CreateAssociatedURLLoader(
153         const blink::WebAssociatedURLLoaderOptions& options) = 0;
154 
155    protected:
156     ~Client() = default;
157   };
158 
159   explicit BlinkUrlLoader(base::WeakPtr<Client> client);
160   BlinkUrlLoader(const BlinkUrlLoader&) = delete;
161   BlinkUrlLoader& operator=(const BlinkUrlLoader&) = delete;
162   ~BlinkUrlLoader() override;
163 
164   // UrlLoader:
165   void GrantUniversalAccess() override;
166   void Open(const UrlRequest& request, ResultCallback callback) override;
167   void ReadResponseBody(base::span<char> buffer,
168                         ResultCallback callback) override;
169   void Close() override;
170 
171   // blink::WebAssociatedURLLoaderClient:
172   bool WillFollowRedirect(
173       const blink::WebURL& new_url,
174       const blink::WebURLResponse& redirect_response) override;
175   void DidSendData(uint64_t bytes_sent,
176                    uint64_t total_bytes_to_be_sent) override;
177   void DidReceiveResponse(const blink::WebURLResponse& response) override;
178   void DidDownloadData(uint64_t data_length) override;
179   void DidReceiveData(const char* data, int data_length) override;
180   void DidFinishLoading() override;
181   void DidFail(const blink::WebURLError& error) override;
182 
183  private:
184   enum class LoadingState {
185     // Before calling `Open()`.
186     kWaitingToOpen,
187 
188     // After calling `Open()`, but before `DidReceiveResponse()` or `DidFail()`.
189     kOpening,
190 
191     // After `DidReceiveResponse()`, but before `DidFinishLoading()` or
192     // `DidFail()`. Zero or more calls allowed to `DidReceiveData()`.
193     kStreamingData,
194 
195     // After `DidFinishLoading()` or `DidFail()`, or forced by `Close()`.
196     // Details about how the load completed are in `complete_result_`.
197     kLoadComplete,
198   };
199 
200   // Aborts the load with `result`. Runs callback if pending.
201   void AbortLoad(int32_t result);
202 
203   // Runs callback for `ReadResponseBody()` if pending.
204   void RunReadCallback();
205 
206   void SetLoadComplete(int32_t result);
207 
208   base::WeakPtr<Client> client_;
209   bool grant_universal_access_ = false;
210 
211   LoadingState state_ = LoadingState::kWaitingToOpen;
212   int32_t complete_result_ = 0;
213 
214   std::unique_ptr<blink::WebAssociatedURLLoader> blink_loader_;
215 
216   bool ignore_redirects_ = false;
217   ResultCallback open_callback_;
218 
219   // Thresholds control buffer throttling, as defined in `UrlRequest`.
220   size_t buffer_lower_threshold_ = 0;
221   size_t buffer_upper_threshold_ = 0;
222   bool deferring_loading_ = false;
223   base::circular_deque<char> buffer_;
224 
225   ResultCallback read_callback_;
226   base::span<char> client_buffer_;
227 };
228 
229 // A Pepper URL loader.
230 class PepperUrlLoader final : public UrlLoader {
231  public:
232   explicit PepperUrlLoader(pp::InstanceHandle plugin_instance);
233   PepperUrlLoader(const PepperUrlLoader&) = delete;
234   PepperUrlLoader& operator=(const PepperUrlLoader&) = delete;
235   ~PepperUrlLoader() override;
236 
237   // UrlLoader:
238   void GrantUniversalAccess() override;
239   void Open(const UrlRequest& request, ResultCallback callback) override;
240   void ReadResponseBody(base::span<char> buffer,
241                         ResultCallback callback) override;
242   void Close() override;
243 
244  private:
245   void DidOpen(ResultCallback callback, int32_t result);
246 
247   pp::InstanceHandle plugin_instance_;
248   pp::URLLoader pepper_loader_;
249 
250   base::WeakPtrFactory<PepperUrlLoader> weak_factory_{this};
251 };
252 
253 }  // namespace chrome_pdf
254 
255 #endif  // PDF_PPAPI_MIGRATION_URL_LOADER_H_
256