1 // Copyright 2014 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 #include "third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10 #include "base/macros.h"
11 #include "base/memory/scoped_refptr.h"
12 #include "mojo/public/cpp/bindings/associated_remote.h"
13 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
14 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
15 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
16 #include "third_party/blink/public/common/cache_storage/cache_storage_utils.h"
17 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
18 #include "third_party/blink/public/platform/platform.h"
19 #include "third_party/blink/public/platform/web_security_origin.h"
20 #include "third_party/blink/public/platform/web_string.h"
21 #include "third_party/blink/public/platform/web_url.h"
22 #include "third_party/blink/public/platform/web_vector.h"
23 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
24 #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
25 #include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
26 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
27 #include "third_party/blink/renderer/core/frame/local_frame.h"
28 #include "third_party/blink/renderer/core/inspector/inspected_frames.h"
29 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
30 #include "third_party/blink/renderer/platform/blob/blob_data.h"
31 #include "third_party/blink/renderer/platform/heap/handle.h"
32 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
33 #include "third_party/blink/renderer/platform/network/http_header_map.h"
34 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
35 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
36 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
37 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
38 #include "third_party/blink/renderer/platform/wtf/functional.h"
39 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
40 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
41 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
42 #include "third_party/blink/renderer/platform/wtf/vector.h"
43 
44 using blink::protocol::Array;
45 // Renaming Cache since there is another blink::Cache.
46 using ProtocolCache = blink::protocol::CacheStorage::Cache;
47 using blink::protocol::CacheStorage::Cache;
48 using blink::protocol::CacheStorage::CachedResponse;
49 using blink::protocol::CacheStorage::CachedResponseType;
50 using blink::protocol::CacheStorage::DataEntry;
51 using blink::protocol::CacheStorage::Header;
52 // Renaming Response since there is another blink::Response.
53 using ProtocolResponse = blink::protocol::Response;
54 
55 using DeleteCacheCallback =
56     blink::protocol::CacheStorage::Backend::DeleteCacheCallback;
57 using DeleteEntryCallback =
58     blink::protocol::CacheStorage::Backend::DeleteEntryCallback;
59 using RequestCacheNamesCallback =
60     blink::protocol::CacheStorage::Backend::RequestCacheNamesCallback;
61 using RequestEntriesCallback =
62     blink::protocol::CacheStorage::Backend::RequestEntriesCallback;
63 using RequestCachedResponseCallback =
64     blink::protocol::CacheStorage::Backend::RequestCachedResponseCallback;
65 
66 namespace blink {
67 
68 namespace {
69 
BuildCacheId(const String & security_origin,const String & cache_name)70 String BuildCacheId(const String& security_origin, const String& cache_name) {
71   StringBuilder id;
72   id.Append(security_origin);
73   id.Append('|');
74   id.Append(cache_name);
75   return id.ToString();
76 }
77 
ParseCacheId(const String & id,String * security_origin,String * cache_name)78 ProtocolResponse ParseCacheId(const String& id,
79                               String* security_origin,
80                               String* cache_name) {
81   wtf_size_t pipe = id.find('|');
82   if (pipe == WTF::kNotFound)
83     return ProtocolResponse::ServerError("Invalid cache id.");
84   *security_origin = id.Substring(0, pipe);
85   *cache_name = id.Substring(pipe + 1);
86   return ProtocolResponse::Success();
87 }
88 
GetExecutionContext(InspectedFrames * frames,const String & security_origin,ExecutionContext ** context)89 ProtocolResponse GetExecutionContext(InspectedFrames* frames,
90                                      const String& security_origin,
91                                      ExecutionContext** context) {
92   LocalFrame* frame = frames->FrameWithSecurityOrigin(security_origin);
93   if (!frame) {
94     String msg = "No frame with origin " + security_origin;
95     return ProtocolResponse::ServerError(msg.Utf8());
96   }
97 
98   *context = frame->DomWindow();
99 
100   return ProtocolResponse::Success();
101 }
102 
AssertCacheStorage(const String & security_origin,InspectedFrames * frames,InspectorCacheStorageAgent::CachesMap * caches,mojom::blink::CacheStorage ** result)103 ProtocolResponse AssertCacheStorage(
104     const String& security_origin,
105     InspectedFrames* frames,
106     InspectorCacheStorageAgent::CachesMap* caches,
107     mojom::blink::CacheStorage** result) {
108   scoped_refptr<const SecurityOrigin> sec_origin =
109       SecurityOrigin::CreateFromString(security_origin);
110 
111   // Cache Storage API is restricted to trustworthy origins.
112   if (!sec_origin->IsPotentiallyTrustworthy()) {
113     return ProtocolResponse::ServerError(
114         sec_origin->IsPotentiallyTrustworthyErrorMessage().Utf8());
115   }
116 
117   ExecutionContext* context = nullptr;
118   ProtocolResponse response =
119       GetExecutionContext(frames, security_origin, &context);
120   if (!response.IsSuccess())
121     return response;
122 
123   auto it = caches->find(security_origin);
124 
125   if (it == caches->end()) {
126     mojo::Remote<mojom::blink::CacheStorage> cache_storage_remote;
127     context->GetBrowserInterfaceBroker().GetInterface(
128         cache_storage_remote.BindNewPipeAndPassReceiver());
129     *result = cache_storage_remote.get();
130     caches->Set(security_origin, std::move(cache_storage_remote));
131   } else {
132     *result = it->value.get();
133   }
134 
135   return ProtocolResponse::Success();
136 }
137 
AssertCacheStorageAndNameForId(const String & cache_id,InspectedFrames * frames,String * cache_name,InspectorCacheStorageAgent::CachesMap * caches,mojom::blink::CacheStorage ** result)138 ProtocolResponse AssertCacheStorageAndNameForId(
139     const String& cache_id,
140     InspectedFrames* frames,
141     String* cache_name,
142     InspectorCacheStorageAgent::CachesMap* caches,
143     mojom::blink::CacheStorage** result) {
144   String security_origin;
145   ProtocolResponse response =
146       ParseCacheId(cache_id, &security_origin, cache_name);
147   if (!response.IsSuccess())
148     return response;
149   return AssertCacheStorage(security_origin, frames, caches, result);
150 }
151 
CacheStorageErrorString(mojom::blink::CacheStorageError error)152 const char* CacheStorageErrorString(mojom::blink::CacheStorageError error) {
153   switch (error) {
154     case mojom::blink::CacheStorageError::kErrorNotImplemented:
155       return "not implemented.";
156     case mojom::blink::CacheStorageError::kErrorNotFound:
157       return "not found.";
158     case mojom::blink::CacheStorageError::kErrorExists:
159       return "cache already exists.";
160     case mojom::blink::CacheStorageError::kErrorQuotaExceeded:
161       return "quota exceeded.";
162     case mojom::blink::CacheStorageError::kErrorCacheNameNotFound:
163       return "cache not found.";
164     case mojom::blink::CacheStorageError::kErrorQueryTooLarge:
165       return "operation too large.";
166     case mojom::blink::CacheStorageError::kErrorStorage:
167       return "storage failure.";
168     case mojom::blink::CacheStorageError::kErrorDuplicateOperation:
169       return "duplicate operation.";
170     case mojom::blink::CacheStorageError::kErrorCrossOriginResourcePolicy:
171       return "failed Cross-Origin-Resource-Policy check.";
172     case mojom::blink::CacheStorageError::kSuccess:
173       // This function should only be called upon error.
174       break;
175   }
176   NOTREACHED();
177   return "";
178 }
179 
ResponseTypeToString(network::mojom::FetchResponseType type)180 CachedResponseType ResponseTypeToString(
181     network::mojom::FetchResponseType type) {
182   switch (type) {
183     case network::mojom::FetchResponseType::kBasic:
184       return protocol::CacheStorage::CachedResponseTypeEnum::Basic;
185     case network::mojom::FetchResponseType::kCors:
186       return protocol::CacheStorage::CachedResponseTypeEnum::Cors;
187     case network::mojom::FetchResponseType::kDefault:
188       return protocol::CacheStorage::CachedResponseTypeEnum::Default;
189     case network::mojom::FetchResponseType::kError:
190       return protocol::CacheStorage::CachedResponseTypeEnum::Error;
191     case network::mojom::FetchResponseType::kOpaque:
192       return protocol::CacheStorage::CachedResponseTypeEnum::OpaqueResponse;
193     case network::mojom::FetchResponseType::kOpaqueRedirect:
194       return protocol::CacheStorage::CachedResponseTypeEnum::OpaqueRedirect;
195   }
196   NOTREACHED();
197   return "";
198 }
199 
200 struct DataRequestParams {
201   String cache_name;
202   int skip_count;
203   // If set to -1, pagination is disabled and all available requests are
204   // returned.
205   int page_size;
206   String path_filter;
207 };
208 
209 struct RequestResponse {
210   String request_url;
211   String request_method;
212   HTTPHeaderMap request_headers;
213   int response_status;
214   String response_status_text;
215   double response_time;
216   network::mojom::FetchResponseType response_type;
217   HTTPHeaderMap response_headers;
218 };
219 
220 class ResponsesAccumulator : public RefCounted<ResponsesAccumulator> {
221  public:
ResponsesAccumulator(wtf_size_t num_responses,const DataRequestParams & params,mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache> cache_pending_remote,std::unique_ptr<RequestEntriesCallback> callback)222   ResponsesAccumulator(
223       wtf_size_t num_responses,
224       const DataRequestParams& params,
225       mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache>
226           cache_pending_remote,
227       std::unique_ptr<RequestEntriesCallback> callback)
228       : params_(params),
229         num_responses_left_(num_responses),
230         cache_remote_(std::move(cache_pending_remote)),
231         callback_(std::move(callback)) {}
232 
Dispatch(Vector<mojom::blink::FetchAPIRequestPtr> old_requests)233   void Dispatch(Vector<mojom::blink::FetchAPIRequestPtr> old_requests) {
234     int64_t trace_id = blink::cache_storage::CreateTraceId();
235     TRACE_EVENT_WITH_FLOW0("CacheStorage", "ResponsesAccumulator::Dispatch",
236                            TRACE_ID_GLOBAL(trace_id),
237                            TRACE_EVENT_FLAG_FLOW_OUT);
238 
239     Vector<mojom::blink::FetchAPIRequestPtr> requests;
240     if (params_.path_filter.IsEmpty()) {
241       requests = std::move(old_requests);
242     } else {
243       for (auto& request : old_requests) {
244         String urlPath(request->url.GetPath());
245         if (!urlPath.Contains(params_.path_filter,
246                               WTF::kTextCaseUnicodeInsensitive))
247           continue;
248         requests.push_back(std::move(request));
249       }
250     }
251     wtf_size_t requestSize = requests.size();
252     if (!requestSize) {
253       callback_->sendSuccess(std::make_unique<Array<DataEntry>>(), 0);
254       return;
255     }
256 
257     responses_ = Vector<RequestResponse>(requestSize);
258     num_responses_left_ = requestSize;
259     for (auto& request : requests) {
260       // All FetchAPIRequests in cache_storage code are supposed to not contain
261       // a body.
262       DCHECK(!request->blob && request->body.IsEmpty());
263       auto request_clone_without_body = mojom::blink::FetchAPIRequest::New(
264           request->mode, request->is_main_resource_load, request->destination,
265           request->frame_type, request->url, request->method, request->headers,
266           nullptr /* blob */, ResourceRequestBody(), request->referrer.Clone(),
267           request->credentials_mode, request->cache_mode,
268           request->redirect_mode, request->integrity, request->priority,
269           request->fetch_window_id, request->keepalive, request->is_reload,
270           request->is_history_navigation, request->devtools_stack_id);
271       cache_remote_->Match(
272           std::move(request), mojom::blink::CacheQueryOptions::New(),
273           false /* in_related_fetch_event */, trace_id,
274           WTF::Bind(
275               [](scoped_refptr<ResponsesAccumulator> accumulator,
276                  mojom::blink::FetchAPIRequestPtr request,
277                  mojom::blink::MatchResultPtr result) {
278                 if (result->is_status()) {
279                   accumulator->SendFailure(result->get_status());
280                 } else {
281                   accumulator->AddRequestResponsePair(request,
282                                                       result->get_response());
283                 }
284               },
285               scoped_refptr<ResponsesAccumulator>(this),
286               std::move(request_clone_without_body)));
287     }
288   }
289 
AddRequestResponsePair(const mojom::blink::FetchAPIRequestPtr & request,const mojom::blink::FetchAPIResponsePtr & response)290   void AddRequestResponsePair(
291       const mojom::blink::FetchAPIRequestPtr& request,
292       const mojom::blink::FetchAPIResponsePtr& response) {
293     DCHECK_GT(num_responses_left_, 0);
294     RequestResponse& next_request_response =
295         responses_.at(responses_.size() - num_responses_left_);
296 
297     next_request_response.request_url = request->url.GetString();
298     next_request_response.request_method = request->method;
299     for (const auto& header : request->headers) {
300       next_request_response.request_headers.Set(AtomicString(header.key),
301                                                 AtomicString(header.value));
302     }
303 
304     next_request_response.response_status = response->status_code;
305     next_request_response.response_status_text = response->status_text;
306     next_request_response.response_time = response->response_time.ToDoubleT();
307     next_request_response.response_type = response->response_type;
308     for (const auto& header : response->headers) {
309       next_request_response.response_headers.Set(AtomicString(header.key),
310                                                  AtomicString(header.value));
311     }
312 
313     if (--num_responses_left_ != 0)
314       return;
315 
316     std::sort(responses_.begin(), responses_.end(),
317               [](const RequestResponse& a, const RequestResponse& b) {
318                 return WTF::CodeUnitCompareLessThan(a.request_url,
319                                                     b.request_url);
320               });
321     size_t returned_entries_count = responses_.size();
322     if (params_.skip_count > 0)
323       responses_.EraseAt(0, params_.skip_count);
324     if (params_.page_size != -1 &&
325         static_cast<size_t>(params_.page_size) < responses_.size()) {
326       responses_.EraseAt(params_.page_size,
327                          responses_.size() - params_.page_size);
328     }
329     auto array = std::make_unique<protocol::Array<DataEntry>>();
330     for (const auto& request_response : responses_) {
331       std::unique_ptr<DataEntry> entry =
332           DataEntry::create()
333               .setRequestURL(request_response.request_url)
334               .setRequestMethod(request_response.request_method)
335               .setRequestHeaders(
336                   SerializeHeaders(request_response.request_headers))
337               .setResponseStatus(request_response.response_status)
338               .setResponseStatusText(request_response.response_status_text)
339               .setResponseTime(request_response.response_time)
340               .setResponseType(
341                   ResponseTypeToString(request_response.response_type))
342               .setResponseHeaders(
343                   SerializeHeaders(request_response.response_headers))
344               .build();
345       array->emplace_back(std::move(entry));
346     }
347 
348     callback_->sendSuccess(std::move(array), returned_entries_count);
349   }
350 
SendFailure(const mojom::blink::CacheStorageError & error)351   void SendFailure(const mojom::blink::CacheStorageError& error) {
352     callback_->sendFailure(ProtocolResponse::ServerError(
353         String::Format("Error requesting responses for cache %s : %s",
354                        params_.cache_name.Latin1().c_str(),
355                        CacheStorageErrorString(error))
356             .Utf8()));
357   }
358 
SerializeHeaders(const HTTPHeaderMap & headers)359   std::unique_ptr<Array<Header>> SerializeHeaders(
360       const HTTPHeaderMap& headers) {
361     auto result = std::make_unique<protocol::Array<Header>>();
362     for (HTTPHeaderMap::const_iterator it = headers.begin(),
363                                        end = headers.end();
364          it != end; ++it) {
365       result->emplace_back(
366           Header::create().setName(it->key).setValue(it->value).build());
367     }
368     return result;
369   }
370 
371  private:
372   DataRequestParams params_;
373   int num_responses_left_;
374   Vector<RequestResponse> responses_;
375   mojo::AssociatedRemote<mojom::blink::CacheStorageCache> cache_remote_;
376   std::unique_ptr<RequestEntriesCallback> callback_;
377 
378   DISALLOW_COPY_AND_ASSIGN(ResponsesAccumulator);
379 };
380 
381 class GetCacheKeysForRequestData {
382   USING_FAST_MALLOC(GetCacheKeysForRequestData);
383 
384  public:
GetCacheKeysForRequestData(const DataRequestParams & params,mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache> cache_pending_remote,std::unique_ptr<RequestEntriesCallback> callback)385   GetCacheKeysForRequestData(
386       const DataRequestParams& params,
387       mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache>
388           cache_pending_remote,
389       std::unique_ptr<RequestEntriesCallback> callback)
390       : params_(params), callback_(std::move(callback)) {
391     cache_remote_.Bind(std::move(cache_pending_remote));
392   }
393 
Dispatch(std::unique_ptr<GetCacheKeysForRequestData> self)394   void Dispatch(std::unique_ptr<GetCacheKeysForRequestData> self) {
395     int64_t trace_id = blink::cache_storage::CreateTraceId();
396     TRACE_EVENT_WITH_FLOW0(
397         "CacheStorage", "GetCacheKeysForRequestData::Dispatch",
398         TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
399     cache_remote_->Keys(
400         nullptr /* request */, mojom::blink::CacheQueryOptions::New(), trace_id,
401         WTF::Bind(
402             [](DataRequestParams params,
403                std::unique_ptr<GetCacheKeysForRequestData> self,
404                mojom::blink::CacheKeysResultPtr result) {
405               if (result->is_status()) {
406                 self->callback_->sendFailure(ProtocolResponse::ServerError(
407                     String::Format(
408                         "Error requesting requests for cache %s: %s",
409                         params.cache_name.Latin1().c_str(),
410                         CacheStorageErrorString(result->get_status()))
411                         .Utf8()));
412               } else {
413                 if (result->get_keys().IsEmpty()) {
414                   auto array = std::make_unique<protocol::Array<DataEntry>>();
415                   self->callback_->sendSuccess(std::move(array), 0);
416                   return;
417                 }
418                 scoped_refptr<ResponsesAccumulator> accumulator =
419                     base::AdoptRef(new ResponsesAccumulator(
420                         result->get_keys().size(), params,
421                         self->cache_remote_.Unbind(),
422                         std::move(self->callback_)));
423                 accumulator->Dispatch(std::move(result->get_keys()));
424               }
425             },
426             params_, std::move(self)));
427   }
428 
429  private:
430   DataRequestParams params_;
431   mojo::AssociatedRemote<mojom::blink::CacheStorageCache> cache_remote_;
432   std::unique_ptr<RequestEntriesCallback> callback_;
433 
434   DISALLOW_COPY_AND_ASSIGN(GetCacheKeysForRequestData);
435 };
436 
437 class CachedResponseFileReaderLoaderClient final
438     : private FileReaderLoaderClient {
439  public:
Load(scoped_refptr<BlobDataHandle> blob,std::unique_ptr<RequestCachedResponseCallback> callback)440   static void Load(scoped_refptr<BlobDataHandle> blob,
441                    std::unique_ptr<RequestCachedResponseCallback> callback) {
442     new CachedResponseFileReaderLoaderClient(std::move(blob),
443                                              std::move(callback));
444   }
445 
DidStartLoading()446   void DidStartLoading() override {}
447 
DidFinishLoading()448   void DidFinishLoading() override {
449     std::unique_ptr<CachedResponse> response =
450         CachedResponse::create()
451             .setBody(protocol::Binary::fromSharedBuffer(data_))
452             .build();
453     callback_->sendSuccess(std::move(response));
454     dispose();
455   }
456 
DidFail(FileErrorCode error)457   void DidFail(FileErrorCode error) override {
458     callback_->sendFailure(ProtocolResponse::ServerError(
459         String::Format("Unable to read the cached response, error code: %d",
460                        error)
461             .Utf8()));
462     dispose();
463   }
464 
DidReceiveDataForClient(const char * data,unsigned data_length)465   void DidReceiveDataForClient(const char* data,
466                                unsigned data_length) override {
467     data_->Append(data, data_length);
468   }
469 
470  private:
CachedResponseFileReaderLoaderClient(scoped_refptr<BlobDataHandle> && blob,std::unique_ptr<RequestCachedResponseCallback> && callback)471   CachedResponseFileReaderLoaderClient(
472       scoped_refptr<BlobDataHandle>&& blob,
473       std::unique_ptr<RequestCachedResponseCallback>&& callback)
474       // TODO(hajimehoshi): Use a per-ExecutionContext task runner of
475       // TaskType::kFileReading
476       : loader_(std::make_unique<FileReaderLoader>(
477             FileReaderLoader::kReadByClient,
478             static_cast<FileReaderLoaderClient*>(this),
479             ThreadScheduler::Current()->DeprecatedDefaultTaskRunner())),
480         callback_(std::move(callback)),
481         data_(SharedBuffer::Create()) {
482     loader_->Start(std::move(blob));
483   }
484 
485   ~CachedResponseFileReaderLoaderClient() override = default;
486 
dispose()487   void dispose() { delete this; }
488 
489   std::unique_ptr<FileReaderLoader> loader_;
490   std::unique_ptr<RequestCachedResponseCallback> callback_;
491   scoped_refptr<SharedBuffer> data_;
492 
493   DISALLOW_COPY_AND_ASSIGN(CachedResponseFileReaderLoaderClient);
494 };
495 
496 }  // namespace
497 
InspectorCacheStorageAgent(InspectedFrames * frames)498 InspectorCacheStorageAgent::InspectorCacheStorageAgent(InspectedFrames* frames)
499     : frames_(frames) {}
500 
501 InspectorCacheStorageAgent::~InspectorCacheStorageAgent() = default;
502 
Trace(Visitor * visitor) const503 void InspectorCacheStorageAgent::Trace(Visitor* visitor) const {
504   visitor->Trace(frames_);
505   InspectorBaseAgent::Trace(visitor);
506 }
507 
requestCacheNames(const String & security_origin,std::unique_ptr<RequestCacheNamesCallback> callback)508 void InspectorCacheStorageAgent::requestCacheNames(
509     const String& security_origin,
510     std::unique_ptr<RequestCacheNamesCallback> callback) {
511   int64_t trace_id = blink::cache_storage::CreateTraceId();
512   TRACE_EVENT_WITH_FLOW0("CacheStorage",
513                          "InspectorCacheStorageAgent::requestCacheNames",
514                          TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
515 
516   scoped_refptr<const SecurityOrigin> sec_origin =
517       SecurityOrigin::CreateFromString(security_origin);
518 
519   // Cache Storage API is restricted to trustworthy origins.
520   if (!sec_origin->IsPotentiallyTrustworthy()) {
521     // Don't treat this as an error, just don't attempt to open and enumerate
522     // the caches.
523     callback->sendSuccess(std::make_unique<protocol::Array<ProtocolCache>>());
524     return;
525   }
526 
527   mojom::blink::CacheStorage* cache_storage = nullptr;
528 
529   ProtocolResponse response =
530       AssertCacheStorage(security_origin, frames_, &caches_, &cache_storage);
531   if (!response.IsSuccess()) {
532     callback->sendFailure(response);
533     return;
534   }
535 
536   cache_storage->Keys(
537       trace_id,
538       WTF::Bind(
539           [](String security_origin,
540              std::unique_ptr<RequestCacheNamesCallback> callback,
541              const Vector<String>& caches) {
542             auto array = std::make_unique<protocol::Array<ProtocolCache>>();
543             for (auto& cache : caches) {
544               array->emplace_back(
545                   ProtocolCache::create()
546                       .setSecurityOrigin(security_origin)
547                       .setCacheName(cache)
548                       .setCacheId(BuildCacheId(security_origin, cache))
549                       .build());
550             }
551             callback->sendSuccess(std::move(array));
552           },
553           security_origin, std::move(callback)));
554 }
555 
requestEntries(const String & cache_id,protocol::Maybe<int> skip_count,protocol::Maybe<int> page_size,protocol::Maybe<String> path_filter,std::unique_ptr<RequestEntriesCallback> callback)556 void InspectorCacheStorageAgent::requestEntries(
557     const String& cache_id,
558     protocol::Maybe<int> skip_count,
559     protocol::Maybe<int> page_size,
560     protocol::Maybe<String> path_filter,
561     std::unique_ptr<RequestEntriesCallback> callback) {
562   int64_t trace_id = blink::cache_storage::CreateTraceId();
563   TRACE_EVENT_WITH_FLOW0("CacheStorage",
564                          "InspectorCacheStorageAgent::requestEntries",
565                          TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
566 
567   String cache_name;
568   mojom::blink::CacheStorage* cache_storage = nullptr;
569   ProtocolResponse response = AssertCacheStorageAndNameForId(
570       cache_id, frames_, &cache_name, &caches_, &cache_storage);
571   if (!response.IsSuccess()) {
572     callback->sendFailure(response);
573     return;
574   }
575   DataRequestParams params;
576   params.cache_name = cache_name;
577   params.page_size = page_size.fromMaybe(-1);
578   params.skip_count = skip_count.fromMaybe(0);
579   params.path_filter = path_filter.fromMaybe("");
580 
581   cache_storage->Open(
582       cache_name, trace_id,
583       WTF::Bind(
584           [](DataRequestParams params,
585              std::unique_ptr<RequestEntriesCallback> callback,
586              mojom::blink::OpenResultPtr result) {
587             if (result->is_status()) {
588               callback->sendFailure(ProtocolResponse::ServerError(
589                   String::Format("Error requesting cache %s: %s",
590                                  params.cache_name.Latin1().c_str(),
591                                  CacheStorageErrorString(result->get_status()))
592                       .Utf8()));
593             } else {
594               auto request = std::make_unique<GetCacheKeysForRequestData>(
595                   params, std::move(result->get_cache()), std::move(callback));
596               auto* request_ptr = request.get();
597               request_ptr->Dispatch(std::move(request));
598             }
599           },
600           params, std::move(callback)));
601 }
602 
deleteCache(const String & cache_id,std::unique_ptr<DeleteCacheCallback> callback)603 void InspectorCacheStorageAgent::deleteCache(
604     const String& cache_id,
605     std::unique_ptr<DeleteCacheCallback> callback) {
606   int64_t trace_id = blink::cache_storage::CreateTraceId();
607   TRACE_EVENT_WITH_FLOW0("CacheStorage",
608                          "InspectorCacheStorageAgent::deleteCache",
609                          TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
610 
611   String cache_name;
612   mojom::blink::CacheStorage* cache_storage = nullptr;
613   ProtocolResponse response = AssertCacheStorageAndNameForId(
614       cache_id, frames_, &cache_name, &caches_, &cache_storage);
615   if (!response.IsSuccess()) {
616     callback->sendFailure(response);
617     return;
618   }
619   cache_storage->Delete(
620       cache_name, trace_id,
621       WTF::Bind(
622           [](std::unique_ptr<DeleteCacheCallback> callback,
623              mojom::blink::CacheStorageError error) {
624             if (error == mojom::blink::CacheStorageError::kSuccess) {
625               callback->sendSuccess();
626             } else {
627               callback->sendFailure(ProtocolResponse::ServerError(
628                   String::Format("Error requesting cache names: %s",
629                                  CacheStorageErrorString(error))
630                       .Utf8()));
631             }
632           },
633           std::move(callback)));
634 }
635 
deleteEntry(const String & cache_id,const String & request,std::unique_ptr<DeleteEntryCallback> callback)636 void InspectorCacheStorageAgent::deleteEntry(
637     const String& cache_id,
638     const String& request,
639     std::unique_ptr<DeleteEntryCallback> callback) {
640   int64_t trace_id = blink::cache_storage::CreateTraceId();
641   TRACE_EVENT_WITH_FLOW0("CacheStorage",
642                          "InspectorCacheStorageAgent::deleteEntry",
643                          TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
644 
645   String cache_name;
646   mojom::blink::CacheStorage* cache_storage = nullptr;
647   ProtocolResponse response = AssertCacheStorageAndNameForId(
648       cache_id, frames_, &cache_name, &caches_, &cache_storage);
649   if (!response.IsSuccess()) {
650     callback->sendFailure(response);
651     return;
652   }
653   cache_storage->Open(
654       cache_name, trace_id,
655       WTF::Bind(
656           [](String cache_name, String request, int64_t trace_id,
657              std::unique_ptr<DeleteEntryCallback> callback,
658              mojom::blink::OpenResultPtr result) {
659             if (result->is_status()) {
660               callback->sendFailure(ProtocolResponse::ServerError(
661                   String::Format("Error requesting cache %s: %s",
662                                  cache_name.Latin1().c_str(),
663                                  CacheStorageErrorString(result->get_status()))
664                       .Utf8()));
665             } else {
666               Vector<mojom::blink::BatchOperationPtr> batch_operations;
667               batch_operations.push_back(mojom::blink::BatchOperation::New());
668               auto& operation = batch_operations.back();
669               operation->operation_type = mojom::blink::OperationType::kDelete;
670               operation->request = mojom::blink::FetchAPIRequest::New();
671               operation->request->url = KURL(request);
672               operation->request->method = String("GET");
673 
674               mojo::AssociatedRemote<mojom::blink::CacheStorageCache>
675                   cache_remote;
676               cache_remote.Bind(std::move(result->get_cache()));
677               auto* cache = cache_remote.get();
678               cache->Batch(
679                   std::move(batch_operations), trace_id,
680                   WTF::Bind(
681                       [](mojo::AssociatedRemote<mojom::blink::CacheStorageCache>
682                              cache_remote,
683                          std::unique_ptr<DeleteEntryCallback> callback,
684                          mojom::blink::CacheStorageVerboseErrorPtr error) {
685                         if (error->value !=
686                             mojom::blink::CacheStorageError::kSuccess) {
687                           callback->sendFailure(ProtocolResponse::ServerError(
688                               String::Format(
689                                   "Error deleting cache entry: %s",
690                                   CacheStorageErrorString(error->value))
691                                   .Utf8()));
692                         } else {
693                           callback->sendSuccess();
694                         }
695                       },
696                       std::move(cache_remote), std::move(callback)));
697             }
698           },
699           cache_name, request, trace_id, std::move(callback)));
700 }
701 
requestCachedResponse(const String & cache_id,const String & request_url,const std::unique_ptr<protocol::Array<protocol::CacheStorage::Header>> request_headers,std::unique_ptr<RequestCachedResponseCallback> callback)702 void InspectorCacheStorageAgent::requestCachedResponse(
703     const String& cache_id,
704     const String& request_url,
705     const std::unique_ptr<protocol::Array<protocol::CacheStorage::Header>>
706         request_headers,
707     std::unique_ptr<RequestCachedResponseCallback> callback) {
708   int64_t trace_id = blink::cache_storage::CreateTraceId();
709   TRACE_EVENT_WITH_FLOW0("CacheStorage",
710                          "InspectorCacheStorageAgent::requestCachedResponse",
711                          TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT);
712 
713   String cache_name;
714   mojom::blink::CacheStorage* cache_storage = nullptr;
715   ProtocolResponse response = AssertCacheStorageAndNameForId(
716       cache_id, frames_, &cache_name, &caches_, &cache_storage);
717   if (!response.IsSuccess()) {
718     callback->sendFailure(response);
719     return;
720   }
721   auto request = mojom::blink::FetchAPIRequest::New();
722   request->url = KURL(request_url);
723   request->method = String("GET");
724   for (const std::unique_ptr<protocol::CacheStorage::Header>& header :
725        *request_headers) {
726     request->headers.insert(header->getName(), header->getValue());
727   }
728 
729   auto multi_query_options = mojom::blink::MultiCacheQueryOptions::New();
730   multi_query_options->query_options = mojom::blink::CacheQueryOptions::New();
731   multi_query_options->cache_name = cache_name;
732 
733   cache_storage->Match(
734       std::move(request), std::move(multi_query_options),
735       false /* in_related_fetch_event */, trace_id,
736       WTF::Bind(
737           [](std::unique_ptr<RequestCachedResponseCallback> callback,
738              mojom::blink::MatchResultPtr result) {
739             if (result->is_status()) {
740               callback->sendFailure(ProtocolResponse::ServerError(
741                   String::Format("Unable to read cached response: %s",
742                                  CacheStorageErrorString(result->get_status()))
743                       .Utf8()));
744             } else {
745               std::unique_ptr<protocol::DictionaryValue> headers =
746                   protocol::DictionaryValue::create();
747               if (!result->get_response()->blob) {
748                 callback->sendSuccess(CachedResponse::create()
749                                           .setBody(protocol::Binary())
750                                           .build());
751                 return;
752               }
753               CachedResponseFileReaderLoaderClient::Load(
754                   std::move(result->get_response()->blob), std::move(callback));
755             }
756           },
757           std::move(callback)));
758 }
759 }  // namespace blink
760