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