1 // Copyright 2020 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_APPCACHE_APPCACHE_URL_LOADER_H_
6 #define CONTENT_BROWSER_APPCACHE_APPCACHE_URL_LOADER_H_
7 
8 #include <memory>
9 
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/sequence_checker.h"
14 #include "base/time/time.h"
15 #include "content/browser/appcache/appcache_entry.h"
16 #include "content/browser/appcache/appcache_request_handler.h"
17 #include "content/browser/appcache/appcache_storage.h"
18 #include "content/common/content_export.h"
19 #include "mojo/public/cpp/bindings/pending_receiver.h"
20 #include "mojo/public/cpp/bindings/pending_remote.h"
21 #include "mojo/public/cpp/bindings/receiver.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 #include "mojo/public/cpp/system/data_pipe.h"
24 #include "net/http/http_byte_range.h"
25 #include "services/network/public/mojom/url_loader.mojom-forward.h"
26 #include "third_party/blink/public/mojom/appcache/appcache_info.mojom-forward.h"
27 #include "url/gurl.h"
28 
29 namespace net {
30 class HttpRequestHeaders;
31 class HttpResponseInfo;
32 }  // namespace net
33 
34 namespace network {
35 class NetToMojoPendingBuffer;
36 }
37 
38 namespace content {
39 
40 class AppCacheRequest;
41 class AppCacheResponseInfo;
42 class AppCacheResponseReader;
43 
44 // network::mojom::URLLoader that retrieves responses stored in an AppCache.
45 class CONTENT_EXPORT AppCacheURLLoader : public AppCacheStorage::Delegate,
46                                          public network::mojom::URLLoader {
47  public:
48   enum class DeliveryType {
49     kAwaitingDeliverCall,
50     kAppCached,
51     kNetwork,
52     kError,
53   };
54 
55   // Use AppCacheRequestHandler::CreateJob() instead of calling the constructor
56   // directly.
57   //
58   // The constructor is exposed for std::make_unique.
59   AppCacheURLLoader(
60       AppCacheRequest* appcache_request,
61       AppCacheStorage* storage,
62       AppCacheRequestHandler::AppCacheLoaderCallback loader_callback);
63 
64   ~AppCacheURLLoader() override;
65 
66   // Sets up the bindings.
67   void Start(base::OnceClosure continuation,
68              const network::ResourceRequest& resource_request,
69              mojo::PendingReceiver<network::mojom::URLLoader> receiver,
70              mojo::PendingRemote<network::mojom::URLLoaderClient> client);
71 
72   // True if the loader was started.
73   bool IsStarted() const;
74 
75   // True if the loader is waiting for instructions.
IsWaiting()76   bool IsWaiting() const {
77     return delivery_type_ == DeliveryType::kAwaitingDeliverCall;
78   }
79 
80   // True if the loader is delivering a response from the cache.
IsDeliveringAppCacheResponse()81   bool IsDeliveringAppCacheResponse() const {
82     return delivery_type_ == DeliveryType::kAppCached;
83   }
84 
85   // True if the loader is delivering a response from the network.
IsDeliveringNetworkResponse()86   bool IsDeliveringNetworkResponse() const {
87     return delivery_type_ == DeliveryType::kNetwork;
88   }
89 
90   // True if the loader is delivering an error response.
IsDeliveringErrorResponse()91   bool IsDeliveringErrorResponse() const {
92     return delivery_type_ == DeliveryType::kError;
93   }
94 
set_delivery_type(DeliveryType delivery_type)95   void set_delivery_type(DeliveryType delivery_type) {
96     delivery_type_ = delivery_type;
97   }
98 
99   // True if the cache entry was not found in the cache.
IsCacheEntryNotFound()100   bool IsCacheEntryNotFound() const { return cache_entry_not_found_; }
101 
102   // Informs the loader of what response it should deliver.
103   //
104   // Each loader should receive exactly one call to a Deliver*() method. Loaders
105   // will sit idle and wait indefinitely until one of the Deliver*() methods is
106   // called.
107   void DeliverAppCachedResponse(const GURL& manifest_url,
108                                 int64_t cache_id,
109                                 const AppCacheEntry& entry,
110                                 bool is_fallback);
111 
112   // Informs the loader that it should deliver the response from the network.
113   // This is generally controlled by the entries in the manifest file.
114   //
115   // Each loader should receive exactly one call to a Deliver*() method. Loaders
116   // will sit idle and wait indefinitely until one of the Deliver*() methods is
117   // called.
118   void DeliverNetworkResponse();
119 
120   // Informs the loader that it should deliver an error response.
121   //
122   // Each loader should receive exactly one call to a Deliver*() method. Loaders
123   // will sit idle and wait indefinitely until one of the Deliver*() methods is
124   // called.
125   void DeliverErrorResponse();
126 
127   base::WeakPtr<AppCacheURLLoader> GetWeakPtr();
128 
129   // network::mojom::URLLoader:
130   void FollowRedirect(const std::vector<std::string>& removed_headers,
131                       const net::HttpRequestHeaders& modified_headers,
132                       const base::Optional<GURL>& new_url) override;
133   void SetPriority(net::RequestPriority priority,
134                    int32_t intra_priority_value) override;
135   void PauseReadingBodyFromNet() override;
136   void ResumeReadingBodyFromNet() override;
137 
138   void DeleteIfNeeded();
139 
140  private:
is_range_request()141   bool is_range_request() const { return range_requested_.IsValid(); }
142 
143   void InitializeRangeRequestInfo(const net::HttpRequestHeaders& headers);
144   void SetupRangeResponse();
145 
146   // Invokes the loader callback which is expected to setup the mojo binding.
147   void CallLoaderCallback(base::OnceClosure continuation);
148 
149   // AppCacheStorage::Delegate:
150   void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
151                             int64_t response_id) override;
152 
153   void ContinueOnResponseInfoLoaded(
154       scoped_refptr<AppCacheResponseInfo> response_info);
155 
156   // AppCacheResponseReader completion callback.
157   void OnReadComplete(int result);
158 
159   // Callback invoked when the data pipe can be written to.
160   void OnResponseBodyStreamReady(MojoResult result);
161 
162   // Schedules a task to delete self with some clean-ups. This is also used as
163   // a mojo binding error handler.
164   void DeleteSoon();
165 
166   void SendResponseInfo();
167   void ReadMore();
168   void NotifyCompleted(int error_code);
169 
170   // True if the AppCache entry is not found.
171   bool cache_entry_not_found_ = false;
172 
173   // The loader's delivery status.
174   DeliveryType delivery_type_ = DeliveryType::kAwaitingDeliverCall;
175 
176   // Byte range request if any.
177   net::HttpByteRange range_requested_;
178 
179   std::unique_ptr<net::HttpResponseInfo> range_response_info_;
180 
181   // The response details.
182   scoped_refptr<AppCacheResponseInfo> info_;
183 
184   // Used to read the cache.
185   std::unique_ptr<AppCacheResponseReader> reader_;
186 
187   base::WeakPtr<AppCacheStorage> storage_;
188 
189   // Time when the request started.
190   base::TimeTicks start_time_tick_;
191 
192   // Timing information for the most recent request.  Its start times are
193   // populated in DeliverAppCachedResponse().
194   net::LoadTimingInfo load_timing_info_;
195 
196   GURL manifest_url_;
197   int64_t cache_id_ = blink::mojom::kAppCacheNoCacheId;
198   AppCacheEntry entry_;
199   bool is_fallback_ = false;
200 
201   // Receiver of the URLLoaderClient with us.
202   mojo::Receiver<network::mojom::URLLoader> receiver_{this};
203 
204   // The URLLoaderClient remote. We call this interface with notifications
205   // about the URL load
206   mojo::Remote<network::mojom::URLLoaderClient> client_;
207 
208   // The data pipe used to transfer AppCache data to the client.
209   mojo::ScopedDataPipeConsumerHandle consumer_handle_;
210   mojo::ScopedDataPipeProducerHandle response_body_stream_;
211   scoped_refptr<network::NetToMojoPendingBuffer> pending_write_;
212   mojo::SimpleWatcher writable_handle_watcher_;
213 
214   // The Callback to be invoked in the network service land to indicate if
215   // the resource request can be serviced via the AppCache.
216   AppCacheRequestHandler::AppCacheLoaderCallback loader_callback_;
217 
218   // The AppCacheRequest instance, used to inform the loader job about range
219   // request headers. Not owned by this class.
220   const base::WeakPtr<AppCacheRequest> appcache_request_;
221 
222   bool is_deleting_soon_ = false;
223   const bool is_main_resource_load_;
224 
225   SEQUENCE_CHECKER(sequence_checker_);
226 
227   base::WeakPtrFactory<AppCacheURLLoader> weak_factory_{this};
228   DISALLOW_COPY_AND_ASSIGN(AppCacheURLLoader);
229 };
230 
231 }  // namespace content
232 
233 #endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_URL_LOADER_H_
234