blob: 03f39a7485d71321945a41ee9a05c0f0818c4d27 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_LOADER_KEEP_ALIVE_URL_LOADER_H_
#define CONTENT_BROWSER_LOADER_KEEP_ALIVE_URL_LOADER_H_
#include <stdint.h>
#include "base/functional/callback.h"
#include "base/types/pass_key.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/gurl.h"
namespace network {
class SharedURLLoaderFactory;
}
namespace content {
class KeepAliveURLLoaderService;
// A URLLoader for loading a fetch keepalive request via the browser process,
// including both `fetch(..., {keepalive: true})` and `navigator.sendBeacon()`
// requests.
//
// To load a keepalive request initiated by a renderer, this loader performs the
// following logic:
// 1. Forwards all request loading actions received from a remote of
// `mojom::URLLoader` in a renderer to a receiver of `mojom::URLLoader` in
// the network service connected by `loader_`.
// 2. Receives request loading results from the network service, i.e. the remote
// of `loader_receiver_`. The URLLoaderClient overrides will be triggered to
// process results:
// A. For redirect, perform security checks and ask the network service to
// follow all subsequent redirects.
// B. For non-redirect,
// a. If the renderer is still alive, i.e. `forwarding_client_` is
// connected, ask it to process the results instead.
// b. If the renderer is dead, drop the results.
//
// Instances of this class must only be constructed and run within the browser
// process, such that the lifetime of the corresponding requests can be
// maintained by the browser instead of by a renderer.
//
// Design Doc:
// https://docs.google.com/document/d/1ZzxMMBvpqn8VZBZKnb7Go8TWjnrGcXuLS_USwVVRUvY/edit#
class CONTENT_EXPORT KeepAliveURLLoader
: public network::mojom::URLLoader,
public network::mojom::URLLoaderClient {
public:
// Deletes this loader immediately.
using OnDeleteCallback = base::OnceCallback<void(void)>;
// Must only be constructed by a `KeepAliveURLLoaderService`.
// `resource_request` must be a keepalive request from a renderer.
// `forwarding_client` should handle request loading results from the network
// service if it is still connected.
// `delete_callback` is a callback to delete this object.
KeepAliveURLLoader(
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
base::PassKey<KeepAliveURLLoaderService>);
~KeepAliveURLLoader() override;
// Not copyable.
KeepAliveURLLoader(const KeepAliveURLLoader&) = delete;
KeepAliveURLLoader& operator=(const KeepAliveURLLoader&) = delete;
// Sets the callback to be invoked on errors which require closing the pipe.
// Callback will also immediately delete `this`.
// Not an argument to constructor because the Mojo ReceiverId needs to be
// bound to the callback, but can only get that after creating the worklet.
// Must be called immediately after creating a KeepAliveLoader.
void set_on_delete_callback(OnDeleteCallback on_delete_callback);
private:
// Receives actions from renderer.
// `network::mojom::URLLoader` overrides:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const absl::optional<GURL>& new_url) override;
void SetPriority(net::RequestPriority priority,
int intra_priority_value) override;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
// Receives actions from network service.
// `network::mojom::URLLoaderClient` overrides:
void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
void OnReceiveResponse(
network::mojom::URLResponseHeadPtr head,
mojo::ScopedDataPipeConsumerHandle body,
absl::optional<mojo_base::BigBuffer> cached_metadata) override;
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
network::mojom::URLResponseHeadPtr head) override;
void OnUploadProgress(int64_t current_position,
int64_t total_size,
base::OnceCallback<void()> callback) override;
void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
void OnComplete(
const network::URLLoaderCompletionStatus& completion_status) override;
void OnNetworkConnectionError();
void OnRendererConnectionError();
// The ID to identify the request being loaded by this loader.
int32_t request_id_;
// Connection with the network service:
// Connects to the receiver network::URLLoader implemented in the network
// service that performs actual request loading.
mojo::Remote<network::mojom::URLLoader> loader_;
// Connection with the network service:
// Receives the result of the request loaded by `loader_` from the network
// service.
mojo::Receiver<network::mojom::URLLoaderClient> loader_receiver_{this};
// Connection with a renderer:
// Connects to the receiver URLLoaderClient implemented in the renderer.
// It is the client to forward the URLLoader response from the network
// service to.
// It may be disconnected if the renderer is dead.
mojo::Remote<network::mojom::URLLoaderClient> forwarding_client_;
// A callback to delete this loader object and clean up resource.
OnDeleteCallback on_delete_callback_;
// Whether `OnReceiveResponse()` has been called.
bool has_received_response_ = false;
};
} // namespace content
#endif // CONTENT_BROWSER_LOADER_KEEP_ALIVE_URL_LOADER_H_