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/check.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(
131       const std::vector<std::string>& removed_headers,
132       const net::HttpRequestHeaders& modified_headers,
133       const net::HttpRequestHeaders& modified_cors_exempt_headers,
134       const base::Optional<GURL>& new_url) override;
135   void SetPriority(net::RequestPriority priority,
136                    int32_t intra_priority_value) override;
137   void PauseReadingBodyFromNet() override;
138   void ResumeReadingBodyFromNet() override;
139 
140   void DeleteIfNeeded();
141 
142  private:
is_range_request()143   bool is_range_request() const { return range_requested_.IsValid(); }
144 
145   void InitializeRangeRequestInfo(const net::HttpRequestHeaders& headers);
146   void SetupRangeResponse();
147 
148   // Invokes the loader callback which is expected to setup the mojo binding.
149   void CallLoaderCallback(base::OnceClosure continuation);
150 
151   // AppCacheStorage::Delegate:
152   void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
153                             int64_t response_id) override;
154 
155   void ContinueOnResponseInfoLoaded(
156       scoped_refptr<AppCacheResponseInfo> response_info);
157 
158   // AppCacheResponseReader completion callback.
159   void OnReadComplete(int result);
160 
161   // Callback invoked when the data pipe can be written to.
162   void OnResponseBodyStreamReady(MojoResult result);
163 
164   // Schedules a task to delete self with some clean-ups. This is also used as
165   // a mojo binding error handler.
166   void DeleteSoon();
167 
168   void SendResponseInfo();
169   void ReadMore();
170   void NotifyCompleted(int error_code);
171 
172   // True if the AppCache entry is not found.
173   bool cache_entry_not_found_ = false;
174 
175   // The loader's delivery status.
176   DeliveryType delivery_type_ = DeliveryType::kAwaitingDeliverCall;
177 
178   // Byte range request if any.
179   net::HttpByteRange range_requested_;
180 
181   std::unique_ptr<net::HttpResponseInfo> range_response_info_;
182 
183   // The response details.
184   scoped_refptr<AppCacheResponseInfo> info_;
185 
186   // Used to read the cache.
187   std::unique_ptr<AppCacheResponseReader> reader_;
188 
189   base::WeakPtr<AppCacheStorage> storage_;
190 
191   // Time when the request started.
192   base::TimeTicks start_time_tick_;
193 
194   // Timing information for the most recent request.  Its start times are
195   // populated in DeliverAppCachedResponse().
196   net::LoadTimingInfo load_timing_info_;
197 
198   GURL manifest_url_;
199   int64_t cache_id_ = blink::mojom::kAppCacheNoCacheId;
200   AppCacheEntry entry_;
201   bool is_fallback_ = false;
202 
203   // Receiver of the URLLoaderClient with us.
204   mojo::Receiver<network::mojom::URLLoader> receiver_{this};
205 
206   // The URLLoaderClient remote. We call this interface with notifications
207   // about the URL load
208   mojo::Remote<network::mojom::URLLoaderClient> client_;
209 
210   // The data pipe used to transfer AppCache data to the client.
211   mojo::ScopedDataPipeConsumerHandle consumer_handle_;
212   mojo::ScopedDataPipeProducerHandle response_body_stream_;
213   scoped_refptr<network::NetToMojoPendingBuffer> pending_write_;
214   mojo::SimpleWatcher writable_handle_watcher_;
215 
216   // The Callback to be invoked in the network service land to indicate if
217   // the resource request can be serviced via the AppCache.
218   AppCacheRequestHandler::AppCacheLoaderCallback loader_callback_;
219 
220   // The AppCacheRequest instance, used to inform the loader job about range
221   // request headers. Not owned by this class.
222   const base::WeakPtr<AppCacheRequest> appcache_request_;
223 
224   bool is_deleting_soon_ = false;
225 
226   SEQUENCE_CHECKER(sequence_checker_);
227 
228   base::WeakPtrFactory<AppCacheURLLoader> weak_factory_{this};
229   DISALLOW_COPY_AND_ASSIGN(AppCacheURLLoader);
230 };
231 
232 }  // namespace content
233 
234 #endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_URL_LOADER_H_
235