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