blob: 7e438a645bc53158ad9d973dc3aa4ebb6f96823c [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.
#ifndef CONTENT_BROWSER_WEB_PACKAGE_WEB_BUNDLE_READER_H_
#define CONTENT_BROWSER_WEB_PACKAGE_WEB_BUNDLE_READER_H_
#include <string>
#include "base/containers/flat_map.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_context.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe_producer.h"
#include "net/base/net_errors.h"
#include "services/data_decoder/public/cpp/safe_web_bundle_parser.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "url/gurl.h"
namespace content {
class WebBundleSource;
class WebBundleBlobDataSource;
// A class to handle a Web Bundle that is specified by |source|.
// It asks the utility process to parse metadata and response structures, and
// provides body data based on parsed information.
// This class is typically owned by WebBundleURLLoaderFactory, and also
// could be co-owned by WebBundleHandleTracker during navigations.
// Running on the UI thread.
class CONTENT_EXPORT WebBundleReader final
: public base::RefCounted<WebBundleReader> {
public:
explicit WebBundleReader(std::unique_ptr<WebBundleSource> source);
WebBundleReader(std::unique_ptr<WebBundleSource> source,
int64_t content_length,
mojo::ScopedDataPipeConsumerHandle outer_response_body,
network::mojom::URLLoaderClientEndpointsPtr endpoints,
BrowserContext::BlobContextGetter blob_context_getter);
// Starts parsing, and runs |callback| when meta data gets to be available.
// |error| is set only on failures.
// Other methods below are only available after this |callback| invocation.
using MetadataCallback = base::OnceCallback<void(
web_package::mojom::BundleMetadataParseErrorPtr error)>;
void ReadMetadata(MetadataCallback callback);
// Gets web_package::mojom::BundleResponsePtr for the given |url| that
// contains response headers and range information for its body.
// Should be called after ReadMetadata finishes.
using ResponseCallback =
base::OnceCallback<void(web_package::mojom::BundleResponsePtr,
web_package::mojom::BundleResponseParseErrorPtr)>;
void ReadResponse(const network::ResourceRequest& resource_request,
const std::string& accept_langs,
ResponseCallback callback);
// Starts loading response body. |response| should be obtained by
// ReadResponse above beforehand. Body will be written into |producer_handle|.
// After all body data is written, |callback| will be invoked.
using BodyCompletionCallback = base::OnceCallback<void(net::Error net_error)>;
void ReadResponseBody(web_package::mojom::BundleResponsePtr response,
mojo::ScopedDataPipeProducerHandle producer_handle,
BodyCompletionCallback callback);
// Returns true if the WebBundleSource this object was constructed with
// contains an exchange for |url|.
// Should be called after ReadMetadata finishes.
bool HasEntry(const GURL& url) const;
// Returns the bundle's primary URL.
// Should be called after ReadMetadata finishes.
const GURL& GetPrimaryURL() const;
// Returns the WebBundleSource.
const WebBundleSource& source() const;
base::WeakPtr<WebBundleReader> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
friend class base::RefCounted<WebBundleReader>;
// A simple wrapper class to share a single base::File instance among multiple
// SharedFileDataSource instances.
class SharedFile final : public base::RefCountedThreadSafe<SharedFile> {
public:
explicit SharedFile(std::unique_ptr<WebBundleSource> source);
void DuplicateFile(base::OnceCallback<void(base::File)> callback);
base::File* operator->();
private:
friend class base::RefCountedThreadSafe<SharedFile>;
~SharedFile();
void SetFile(std::unique_ptr<base::File> file);
base::FilePath file_path_;
std::unique_ptr<base::File> file_;
base::OnceCallback<void(base::File)> duplicate_callback_;
DISALLOW_COPY_AND_ASSIGN(SharedFile);
};
class SharedFileDataSource;
enum class State {
kInitial,
kMetadataReady,
kDisconnected,
};
~WebBundleReader();
void ReadMetadataInternal(MetadataCallback callback, base::File file);
void ReadResponseInternal(
web_package::mojom::BundleResponseLocationPtr location,
ResponseCallback callback);
void OnMetadataParsed(MetadataCallback callback,
web_package::mojom::BundleMetadataPtr metadata,
web_package::mojom::BundleMetadataParseErrorPtr error);
void OnResponseParsed(ResponseCallback callback,
web_package::mojom::BundleResponsePtr response,
web_package::mojom::BundleResponseParseErrorPtr error);
void OnParserDisconnected();
void Reconnect();
void ReconnectForFile(base::File file);
void DidReconnect(base::Optional<std::string> error);
SEQUENCE_CHECKER(sequence_checker_);
State state_ = State::kInitial;
const std::unique_ptr<WebBundleSource> source_;
std::unique_ptr<data_decoder::SafeWebBundleParser> parser_;
// Used when loading a web bundle from file.
scoped_refptr<SharedFile> file_;
// Used when loading a web bundle from network.
std::unique_ptr<WebBundleBlobDataSource> blob_data_source_;
GURL primary_url_;
base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> entries_;
// Accumulates ReadResponse() requests while the parser is disconnected.
std::vector<std::pair<web_package::mojom::BundleResponseLocationPtr,
ResponseCallback>>
pending_read_responses_;
base::WeakPtrFactory<WebBundleReader> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(WebBundleReader);
};
} // namespace content
#endif // CONTENT_BROWSER_WEB_PACKAGE_WEB_BUNDLE_READER_H_