blob: fde8afe3cff1299ad2e151db29781f943e5745e6 [file] [log] [blame]
// Copyright 2019 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 <utility>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "content/common/content_export.h"
#include "content/public/common/resource_load_info.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "third_party/blink/public/platform/web_navigation_body_loader.h"
namespace network {
struct URLLoaderCompletionStatus;
} // namespace network
namespace content {
class CodeCacheLoaderImpl;
// Navigation request is started in the browser process, and all redirects
// and final response are received there. Then we pass URLLoader and
// URLLoaderClient bindings to the renderer process, and create an instance
// of this class. It receives the response body, completion status and cached
// metadata, and dispatches them to Blink. It also ensures that completion
// status comes to Blink after the whole body was read and cached code metadata
// was received.
class CONTENT_EXPORT NavigationBodyLoader
: public blink::WebNavigationBodyLoader,
public network::mojom::URLLoaderClient {
mojom::ResourceLoadInfoPtr resource_load_info,
const network::ResourceResponseHead& head,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
int render_frame_id);
~NavigationBodyLoader() override;
// The loading flow is outlined below. NavigationBodyLoader can be safely
// deleted at any moment, and it will record cancelation stats, but will not
// notify the client.
// StartLoadingBody
// request code cache
// CodeCacheReceived
// notify client about cache
// BindURLLoaderAndContinue
// OnStartLoadingResponseBody
// start reading from the pipe
// OnReadable (zero or more times)
// notify client about data
// OnComplete (this might come before the whole body data is read,
// for example due to different mojo pipes being used
// without a relative order guarantee)
// save status for later use
// OnReadable (zero or more times)
// notify client about data
// NotifyCompletionIfAppropriate
// notify client about completion
// blink::WebNavigationBodyLoader
void SetDefersLoading(bool defers) override;
void StartLoadingBody(WebNavigationBodyLoader::Client* client,
bool use_isolated_code_cache) override;
// network::mojom::URLLoaderClient
void OnReceiveResponse(const network::ResourceResponseHead& head) override;
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
const network::ResourceResponseHead& head) override;
void OnUploadProgress(int64_t current_position,
int64_t total_size,
OnUploadProgressCallback callback) override;
void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
void OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle handle) override;
void OnComplete(const network::URLLoaderCompletionStatus& status) override;
void CodeCacheReceived(const base::Time& response_time,
const std::vector<uint8_t>& data);
void BindURLLoaderAndContinue();
void OnConnectionClosed();
void OnReadable(MojoResult unused);
// This method reads data from the pipe in a cycle and dispatches
// BodyDataReceived synchronously.
void ReadFromDataPipe();
void NotifyCompletionIfAppropriate();
mojom::ResourceLoadInfoPtr resource_load_info_;
network::ResourceResponseHead head_;
network::mojom::URLLoaderClientEndpointsPtr endpoints_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
int render_frame_id_;
// These bindings are live while loading the response.
network::mojom::URLLoaderPtr url_loader_;
mojo::Binding<network::mojom::URLLoaderClient> url_loader_client_binding_;
WebNavigationBodyLoader::Client* client_ = nullptr;
// The handle and watcher are live while loading the body.
mojo::ScopedDataPipeConsumerHandle handle_;
mojo::SimpleWatcher handle_watcher_;
// This loader is live while retrieving the code cache.
std::unique_ptr<CodeCacheLoaderImpl> code_cache_loader_;
// The final status received from network or cancelation status if aborted.
network::URLLoaderCompletionStatus status_;
// Whether we got the body handle to read data from.
bool has_received_body_handle_ = false;
// Whether we got the final status.
bool has_received_completion_ = false;
// Whether we got all the body data.
bool has_seen_end_of_data_ = false;
// Deferred body loader does not send any notifications to the client
// and tries not to read from the body pipe.
bool is_deferred_ = false;
// This protects against reentrancy into OnReadable,
// which can happen due to nested message loop triggered
// from iniside BodyDataReceived client notification.
bool is_in_on_readable_ = false;
base::WeakPtrFactory<NavigationBodyLoader> weak_factory_;
} // namespace content