1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CONTENT_BROWSER_WEB_PACKAGE_WEB_BUNDLE_READER_H_
6 #define CONTENT_BROWSER_WEB_PACKAGE_WEB_BUNDLE_READER_H_
7 
8 #include <string>
9 
10 #include "base/containers/flat_map.h"
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/optional.h"
17 #include "base/sequence_checker.h"
18 #include "base/sequenced_task_runner.h"
19 #include "content/common/content_export.h"
20 #include "content/public/browser/browser_context.h"
21 #include "mojo/public/cpp/bindings/pending_remote.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 #include "mojo/public/cpp/system/data_pipe_producer.h"
24 #include "net/base/net_errors.h"
25 #include "services/data_decoder/public/cpp/safe_web_bundle_parser.h"
26 #include "services/network/public/mojom/url_loader.mojom.h"
27 #include "url/gurl.h"
28 
29 namespace content {
30 
31 class WebBundleSource;
32 class WebBundleBlobDataSource;
33 
34 // A class to handle a Web Bundle that is specified by |source|.
35 // It asks the utility process to parse metadata and response structures, and
36 // provides body data based on parsed information.
37 // This class is typically owned by WebBundleURLLoaderFactory, and also
38 // could be co-owned by WebBundleHandleTracker during navigations.
39 // Running on the UI thread.
40 class CONTENT_EXPORT WebBundleReader final
41     : public base::RefCounted<WebBundleReader> {
42  public:
43   explicit WebBundleReader(std::unique_ptr<WebBundleSource> source);
44   WebBundleReader(std::unique_ptr<WebBundleSource> source,
45                   int64_t content_length,
46                   mojo::ScopedDataPipeConsumerHandle outer_response_body,
47                   network::mojom::URLLoaderClientEndpointsPtr endpoints,
48                   BrowserContext::BlobContextGetter blob_context_getter);
49 
50   // Starts parsing, and runs |callback| when meta data gets to be available.
51   // |error| is set only on failures.
52   // Other methods below are only available after this |callback| invocation.
53   using MetadataCallback = base::OnceCallback<void(
54       web_package::mojom::BundleMetadataParseErrorPtr error)>;
55   void ReadMetadata(MetadataCallback callback);
56 
57   // Gets web_package::mojom::BundleResponsePtr for the given |url| that
58   // contains response headers and range information for its body.
59   // Should be called after ReadMetadata finishes.
60   using ResponseCallback =
61       base::OnceCallback<void(web_package::mojom::BundleResponsePtr,
62                               web_package::mojom::BundleResponseParseErrorPtr)>;
63   void ReadResponse(const network::ResourceRequest& resource_request,
64                     const std::string& accept_langs,
65                     ResponseCallback callback);
66 
67   // Starts loading response body. |response| should be obtained by
68   // ReadResponse above beforehand. Body will be written into |producer_handle|.
69   // After all body data is written, |callback| will be invoked.
70   using BodyCompletionCallback = base::OnceCallback<void(net::Error net_error)>;
71   void ReadResponseBody(web_package::mojom::BundleResponsePtr response,
72                         mojo::ScopedDataPipeProducerHandle producer_handle,
73                         BodyCompletionCallback callback);
74 
75   // Returns true if the WebBundleSource this object was constructed with
76   // contains an exchange for |url|.
77   // Should be called after ReadMetadata finishes.
78   bool HasEntry(const GURL& url) const;
79 
80   // Returns the bundle's primary URL.
81   // Should be called after ReadMetadata finishes.
82   const GURL& GetPrimaryURL() const;
83 
84   // Returns the WebBundleSource.
85   const WebBundleSource& source() const;
86 
GetWeakPtr()87   base::WeakPtr<WebBundleReader> GetWeakPtr() {
88     return weak_ptr_factory_.GetWeakPtr();
89   }
90 
91  private:
92   friend class base::RefCounted<WebBundleReader>;
93 
94   // A simple wrapper class to share a single base::File instance among multiple
95   // SharedFileDataSource instances.
96   class SharedFile final : public base::RefCountedThreadSafe<SharedFile> {
97    public:
98     explicit SharedFile(std::unique_ptr<WebBundleSource> source);
99     void DuplicateFile(base::OnceCallback<void(base::File)> callback);
100     base::File* operator->();
101 
102    private:
103     friend class base::RefCountedThreadSafe<SharedFile>;
104     ~SharedFile();
105 
106     void SetFile(std::unique_ptr<base::File> file);
107 
108     base::FilePath file_path_;
109     std::unique_ptr<base::File> file_;
110     base::OnceCallback<void(base::File)> duplicate_callback_;
111 
112     DISALLOW_COPY_AND_ASSIGN(SharedFile);
113   };
114   class SharedFileDataSource;
115 
116   enum class State {
117     kInitial,
118     kMetadataReady,
119     kDisconnected,
120   };
121 
122   ~WebBundleReader();
123 
124   void ReadMetadataInternal(MetadataCallback callback, base::File file);
125   void ReadResponseInternal(
126       web_package::mojom::BundleResponseLocationPtr location,
127       ResponseCallback callback);
128 
129   void OnMetadataParsed(MetadataCallback callback,
130                         web_package::mojom::BundleMetadataPtr metadata,
131                         web_package::mojom::BundleMetadataParseErrorPtr error);
132   void OnResponseParsed(ResponseCallback callback,
133                         web_package::mojom::BundleResponsePtr response,
134                         web_package::mojom::BundleResponseParseErrorPtr error);
135   void OnParserDisconnected();
136   void Reconnect();
137   void ReconnectForFile(base::File file);
138   void DidReconnect(base::Optional<std::string> error);
139 
140   SEQUENCE_CHECKER(sequence_checker_);
141 
142   State state_ = State::kInitial;
143   const std::unique_ptr<WebBundleSource> source_;
144 
145   std::unique_ptr<data_decoder::SafeWebBundleParser> parser_;
146   // Used when loading a web bundle from file.
147   scoped_refptr<SharedFile> file_;
148   // Used when loading a web bundle from network.
149   std::unique_ptr<WebBundleBlobDataSource> blob_data_source_;
150 
151   GURL primary_url_;
152   base::flat_map<GURL, web_package::mojom::BundleIndexValuePtr> entries_;
153   // Accumulates ReadResponse() requests while the parser is disconnected.
154   std::vector<std::pair<web_package::mojom::BundleResponseLocationPtr,
155                         ResponseCallback>>
156       pending_read_responses_;
157 
158   base::WeakPtrFactory<WebBundleReader> weak_ptr_factory_{this};
159 
160   DISALLOW_COPY_AND_ASSIGN(WebBundleReader);
161 };
162 
163 }  // namespace content
164 
165 #endif  // CONTENT_BROWSER_WEB_PACKAGE_WEB_BUNDLE_READER_H_
166