910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_WEB_BUNDLE_PARSER_H_
#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_WEB_BUNDLE_PARSER_H_

#include <memory>
#include <optional>

#include "base/containers/flat_map.h"
#include "base/files/file.h"
#include "base/functional/callback.h"
#include "components/web_package/mojom/web_bundle_parser.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "url/gurl.h"

namespace data_decoder {

// This interface specifies the requirements how a
// `web_package::mojom::BundleDataSource` should be created.
class DataSourceCreatingStrategy {
 public:
  virtual ~DataSourceCreatingStrategy() {}

  // Checks if the connection can be established. E.g. if the source of the
  // data is readable, etc.
  virtual base::expected<void, std::string> ExpectReady() const = 0;

  // Creates DataSource. The WebBundleParserFactory is used to bind the
  // appropriate receiver on the side of the data decoder process.
  // The return result will be used to create a parser.
  virtual mojo::PendingRemote<web_package::mojom::BundleDataSource>
  CreateDataSource(web_package::mojom::WebBundleParserFactory* binder) = 0;

  // Closes the underlying source of data (e.g. file). The callback must
  // be called when the source of data is closed.
  virtual void Close(base::OnceClosure callback) = 0;
};

// This class is used for safe parsing of the Web Bundles. Even though it
// internally uses parsing in the data decoder process by means of
// mojo and IPC, the aim of this class is to isolate users from any knowledge
// about mojo and IPC.
//
// Every parsing method will try to reestablish the IPC connection (if
// necessary) before returning an error.
//
// It is safe to delete this object from within the callbacks passed to its
// methods.
class SafeWebBundleParser {
 public:
  // Returns the strategy that lets the provided signed web bundle file
  // be a data source for parsing.
  static std::unique_ptr<DataSourceCreatingStrategy> GetFileStrategy(
      base::File file);

  SafeWebBundleParser(
      std::optional<GURL> base_url,
      std::unique_ptr<DataSourceCreatingStrategy> data_source_creator);

  SafeWebBundleParser(const SafeWebBundleParser&) = delete;
  SafeWebBundleParser& operator=(const SafeWebBundleParser&) = delete;

  // Remaining callbacks on flight will be dropped.
  ~SafeWebBundleParser();

  // Parses the integrity block of a Signed Web Bundle. See
  // `web_package::mojom::WebBundleParser::ParseIntegrityBlock` for
  // details. This method fails when it's called before the previous call
  // finishes.
  void ParseIntegrityBlock(
      web_package::mojom::WebBundleParser::ParseIntegrityBlockCallback
          callback);

  // Parses metadata of a (Signed) Web Bundle. If `offset` is specified, then
  // parsing of the metadata starts at that offset. If `offset` is not set, then
  // parsing either starts at offset 0 for non-random-access data sources, or at
  // a position based on the `length` field of the Web Bundle for random access
  // data sources. See `web_package::mojom::WebBundleParser::ParseMetadata` for
  // details. This method fails when it's called before the previous call
  // finishes.
  void ParseMetadata(
      std::optional<uint64_t> offset,
      web_package::mojom::WebBundleParser::ParseMetadataCallback callback);

  // Parses a response from a (Signed) Web Bundle. See
  // `web_package::mojom::WebBundleParser::ParseResponse` for details.
  void ParseResponse(
      uint64_t response_offset,
      uint64_t response_length,
      web_package::mojom::WebBundleParser::ParseResponseCallback callback);

  // Closes the data source this class is reading from by calling
  // `DataSourceCreatingStrategy::Close`.
  // One can use this function to know the point after which the source file
  // is closed and can be removed.
  // If the caller doesn't care when the file is closed, then it is fine
  // to destroy the instance of this class without calling this function.
  // The callback will not be called if the instance of this class
  // is destroyed.
  void Close(base::OnceClosure callback);

 private:
  web_package::mojom::WebBundleParserFactory* GetFactory();
  void OnDisconnect();
  void OnIntegrityBlockParsed(
      web_package::mojom::BundleIntegrityBlockPtr integrity_block,
      web_package::mojom::BundleIntegrityBlockParseErrorPtr error);
  void OnMetadataParsed(web_package::mojom::BundleMetadataPtr metadata,
                        web_package::mojom::BundleMetadataParseErrorPtr error);
  void OnResponseParsed(size_t callback_id,
                        web_package::mojom::BundleResponsePtr response,
                        web_package::mojom::BundleResponseParseErrorPtr error);

  base::expected<void, std::string> ConnectIfNecessary();
  void CloseDataSourceCreator();
  void ReplyClosed();

  struct Connection {
    Connection();
    ~Connection();
    DataDecoder data_decoder_;
    mojo::Remote<web_package::mojom::WebBundleParserFactory> factory_;
    mojo::Remote<web_package::mojom::WebBundleParser> parser_;
  };

  bool is_connected() const { return connection_.get(); }

  std::unique_ptr<Connection> connection_;
  std::unique_ptr<DataSourceCreatingStrategy> data_source_creator_;

  web_package::mojom::WebBundleParser::ParseIntegrityBlockCallback
      integrity_block_callback_;
  web_package::mojom::WebBundleParser::ParseMetadataCallback metadata_callback_;
  base::flat_map<size_t,
                 web_package::mojom::WebBundleParser::ParseResponseCallback>
      response_callbacks_;
  base::OnceClosure close_callback_;
  size_t response_callback_next_id_ = 0;

  std::optional<GURL> base_url_;

  base::WeakPtrFactory<SafeWebBundleParser> weak_factory_{this};
};

}  // namespace data_decoder

#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_WEB_BUNDLE_PARSER_H_