blob: ac641af3bfa0615d7a13cc61665ece63f9b1855b [file] [log] [blame]
// Copyright 2020 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 <stddef.h>
#include <stdint.h>
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/containers/circular_deque.h"
#include "base/containers/span.h"
#include "base/memory/weak_ptr.h"
#include "pdf/ppapi_migration/callback.h"
#include "ppapi/cpp/instance_handle.h"
#include "ppapi/cpp/url_loader.h"
#include "third_party/blink/public/web/web_associated_url_loader_client.h"
namespace blink {
class WebAssociatedURLLoader;
class WebString;
class WebURL;
class WebURLRequest;
struct WebAssociatedURLLoaderOptions;
} // namespace blink
namespace net {
class SiteForCookies;
} // namespace net
namespace chrome_pdf {
// Properties for making a URL request.
struct UrlRequest final {
UrlRequest(const UrlRequest& other);
UrlRequest(UrlRequest&& other) noexcept;
UrlRequest& operator=(const UrlRequest& other);
UrlRequest& operator=(UrlRequest&& other) noexcept;
// Request URL.
std::string url;
// HTTP method.
std::string method;
// Whether to ignore redirects. By default, redirects are followed
// automatically.
bool ignore_redirects = false;
// Custom referrer URL.
std::string custom_referrer_url;
// HTTP headers as a single string of `\n`-delimited key-value pairs.
std::string headers;
// Request body.
std::string body;
// Thresholds for throttling filling of the loader's internal buffer. Filling
// will stop after exceeding the upper threshold, and resume after dropping
// below the lower threshold.
// Default values taken from `ppapi/shared_impl/`. The
// PDF viewer never changes the defaults in production, so these fields mostly
// exist for testing purposes.
size_t buffer_lower_threshold = 50 * 1000 * 1000;
size_t buffer_upper_threshold = 100 * 1000 * 1000;
// Properties returned from a URL request. Does not include the response body.
struct UrlResponse final {
UrlResponse(const UrlResponse& other);
UrlResponse(UrlResponse&& other) noexcept;
UrlResponse& operator=(const UrlResponse& other);
UrlResponse& operator=(UrlResponse&& other) noexcept;
// HTTP status code.
int32_t status_code = 0;
// HTTP headers as a single string of `\n`-delimited key-value pairs.
std::string headers;
// Abstraction for a Blink or Pepper URL loader.
class UrlLoader {
UrlLoader(const UrlLoader&) = delete;
UrlLoader& operator=(const UrlLoader&) = delete;
virtual ~UrlLoader();
// Tries to grant the loader the capability to make unrestricted cross-origin
// requests ("universal access," in `blink::SecurityOrigin` terms). Must be
// called before `Open()`.
virtual void GrantUniversalAccess() = 0;
// Mimic `pp::URLLoader`:
virtual void Open(const UrlRequest& request, ResultCallback callback) = 0;
virtual void ReadResponseBody(base::span<char> buffer,
ResultCallback callback) = 0;
virtual void Close() = 0;
// Returns the URL response (not including the body). Only valid after
// `Open()` completes.
const UrlResponse& response() const { return response_; }
UrlResponse& mutable_response() { return response_; }
UrlResponse response_;
// A Blink URL loader. This implementation tries to emulate a combination of
// `content::PepperURLLoaderHost` and `ppapi::proxy::URLLoaderResource`.
class BlinkUrlLoader final : public UrlLoader,
public blink::WebAssociatedURLLoaderClient {
// Client interface required by `BlinkUrlLoader`. Instances should be passed
// using weak pointers, as the loader can be shared, and may outlive the
// client.
class Client {
// Returns `true` if the client is still usable. The client may require
// resources that can become unavailable, such as a local frame. Rather than
// handling missing resources separately for each method, callers can just
// verify validity once, before making any other calls.
virtual bool IsValid() const = 0;
// Completes `partial_url` using the current document.
virtual blink::WebURL CompleteURL(
const blink::WebString& partial_url) const = 0;
// Gets the site-for-cookies for the current document.
virtual net::SiteForCookies SiteForCookies() const = 0;
// Sets the referrer on `request` to `referrer_url` using the current frame.
virtual void SetReferrerForRequest(blink::WebURLRequest& request,
const blink::WebURL& referrer_url) = 0;
// Returns a new `blink::WebAssociatedURLLoader` from the current frame.
virtual std::unique_ptr<blink::WebAssociatedURLLoader>
const blink::WebAssociatedURLLoaderOptions& options) = 0;
~Client() = default;
explicit BlinkUrlLoader(base::WeakPtr<Client> client);
BlinkUrlLoader(const BlinkUrlLoader&) = delete;
BlinkUrlLoader& operator=(const BlinkUrlLoader&) = delete;
~BlinkUrlLoader() override;
// UrlLoader:
void GrantUniversalAccess() override;
void Open(const UrlRequest& request, ResultCallback callback) override;
void ReadResponseBody(base::span<char> buffer,
ResultCallback callback) override;
void Close() override;
// blink::WebAssociatedURLLoaderClient:
bool WillFollowRedirect(
const blink::WebURL& new_url,
const blink::WebURLResponse& redirect_response) override;
void DidSendData(uint64_t bytes_sent,
uint64_t total_bytes_to_be_sent) override;
void DidReceiveResponse(const blink::WebURLResponse& response) override;
void DidDownloadData(uint64_t data_length) override;
void DidReceiveData(const char* data, int data_length) override;
void DidFinishLoading() override;
void DidFail(const blink::WebURLError& error) override;
enum class LoadingState {
// Before calling `Open()`.
// After calling `Open()`, but before `DidReceiveResponse()` or `DidFail()`.
// After `DidReceiveResponse()`, but before `DidFinishLoading()` or
// `DidFail()`. Zero or more calls allowed to `DidReceiveData()`.
// After `DidFinishLoading()` or `DidFail()`, or forced by `Close()`.
// Details about how the load completed are in `complete_result_`.
// Aborts the load with `result`. Runs callback if pending.
void AbortLoad(int32_t result);
// Runs callback for `ReadResponseBody()` if pending.
void RunReadCallback();
void SetLoadComplete(int32_t result);
base::WeakPtr<Client> client_;
bool grant_universal_access_ = false;
LoadingState state_ = LoadingState::kWaitingToOpen;
int32_t complete_result_ = 0;
std::unique_ptr<blink::WebAssociatedURLLoader> blink_loader_;
bool ignore_redirects_ = false;
ResultCallback open_callback_;
// Thresholds control buffer throttling, as defined in `UrlRequest`.
size_t buffer_lower_threshold_ = 0;
size_t buffer_upper_threshold_ = 0;
bool deferring_loading_ = false;
base::circular_deque<char> buffer_;
ResultCallback read_callback_;
base::span<char> client_buffer_;
// A Pepper URL loader.
class PepperUrlLoader final : public UrlLoader {
explicit PepperUrlLoader(pp::InstanceHandle plugin_instance);
PepperUrlLoader(const PepperUrlLoader&) = delete;
PepperUrlLoader& operator=(const PepperUrlLoader&) = delete;
~PepperUrlLoader() override;
// UrlLoader:
void GrantUniversalAccess() override;
void Open(const UrlRequest& request, ResultCallback callback) override;
void ReadResponseBody(base::span<char> buffer,
ResultCallback callback) override;
void Close() override;
void DidOpen(ResultCallback callback, int32_t result);
pp::InstanceHandle plugin_instance_;
pp::URLLoader pepper_loader_;
base::WeakPtrFactory<PepperUrlLoader> weak_factory_{this};
} // namespace chrome_pdf