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