dbdfa366ff8ae37d38ebc926b40c4cddb74fa1c7
[WebKit-https.git] / Source / WebCore / inspector / agents / InspectorPageAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "InspectorPageAgent.h"
34
35 #include "CachedResource.h"
36 #include "CachedResourceLoader.h"
37 #include "Cookie.h"
38 #include "CookieJar.h"
39 #include "Document.h"
40 #include "DocumentLoader.h"
41 #include "Frame.h"
42 #include "FrameLoadRequest.h"
43 #include "FrameLoader.h"
44 #include "FrameSnapshotting.h"
45 #include "FrameView.h"
46 #include "HTMLFrameOwnerElement.h"
47 #include "HTMLNames.h"
48 #include "ImageBuffer.h"
49 #include "InspectorClient.h"
50 #include "InspectorDOMAgent.h"
51 #include "InspectorNetworkAgent.h"
52 #include "InspectorOverlay.h"
53 #include "InstrumentingAgents.h"
54 #include "MIMETypeRegistry.h"
55 #include "MemoryCache.h"
56 #include "Page.h"
57 #include "RenderObject.h"
58 #include "RenderTheme.h"
59 #include "ScriptController.h"
60 #include "SecurityOrigin.h"
61 #include "Settings.h"
62 #include "StyleScope.h"
63 #include "TextEncoding.h"
64 #include "UserGestureIndicator.h"
65 #include <JavaScriptCore/ContentSearchUtilities.h>
66 #include <JavaScriptCore/IdentifiersFactory.h>
67 #include <JavaScriptCore/RegularExpression.h>
68 #include <wtf/ListHashSet.h>
69 #include <wtf/Stopwatch.h>
70 #include <wtf/text/Base64.h>
71 #include <wtf/text/StringBuilder.h>
72
73 #if ENABLE(APPLICATION_MANIFEST)
74 #include "CachedApplicationManifest.h"
75 #endif
76
77 #if ENABLE(WEB_ARCHIVE) && USE(CF)
78 #include "LegacyWebArchive.h"
79 #endif
80
81
82 namespace WebCore {
83
84 using namespace Inspector;
85
86 // Keep this in sync with Page.Setting
87 #define FOR_EACH_INSPECTOR_OVERRIDE_SETTING(macro) \
88     macro(AuthorAndUserStylesEnabled) \
89     macro(ICECandidateFilteringEnabled) \
90     macro(ImagesEnabled) \
91     macro(MediaCaptureRequiresSecureConnection) \
92     macro(MockCaptureDevicesEnabled) \
93     macro(NeedsSiteSpecificQuirks) \
94     macro(ScriptEnabled) \
95     macro(WebSecurityEnabled)
96
97 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
98 {
99     if (buffer) {
100         TextEncoding encoding(textEncodingName);
101         if (!encoding.isValid())
102             encoding = WindowsLatin1Encoding();
103         *result = encoding.decode(buffer, size);
104         return true;
105     }
106     return false;
107 }
108
109 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
110 {
111     RefPtr<SharedBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
112     if (!buffer)
113         return false;
114     return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), frame->document()->encoding(), withBase64Encode, result);
115 }
116
117 bool InspectorPageAgent::sharedBufferContent(RefPtr<SharedBuffer>&& buffer, const String& textEncodingName, bool withBase64Encode, String* result)
118 {
119     return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
120 }
121
122 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
123 {
124     if (withBase64Encode) {
125         *result = base64Encode(data, size);
126         return true;
127     }
128
129     return decodeBuffer(data, size, textEncodingName, result);
130 }
131
132 Vector<CachedResource*> InspectorPageAgent::cachedResourcesForFrame(Frame* frame)
133 {
134     Vector<CachedResource*> result;
135
136     for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader().allCachedResources().values()) {
137         auto* cachedResource = cachedResourceHandle.get();
138         if (cachedResource->resourceRequest().hiddenFromInspector())
139             continue;
140
141         switch (cachedResource->type()) {
142         case CachedResource::Type::ImageResource:
143             // Skip images that were not auto loaded (images disabled in the user agent).
144 #if ENABLE(SVG_FONTS)
145         case CachedResource::Type::SVGFontResource:
146 #endif
147         case CachedResource::Type::FontResource:
148             // Skip fonts that were referenced in CSS but never used/downloaded.
149             if (cachedResource->stillNeedsLoad())
150                 continue;
151             break;
152         default:
153             // All other CachedResource types download immediately.
154             break;
155         }
156
157         result.append(cachedResource);
158     }
159
160     return result;
161 }
162
163 void InspectorPageAgent::resourceContent(ErrorString& errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
164 {
165     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
166     if (!loader)
167         return;
168
169     RefPtr<SharedBuffer> buffer;
170     bool success = false;
171     if (equalIgnoringFragmentIdentifier(url, loader->url())) {
172         *base64Encoded = false;
173         success = mainResourceContent(frame, *base64Encoded, result);
174     }
175
176     if (!success) {
177         if (auto* resource = cachedResource(frame, url))
178             success = InspectorNetworkAgent::cachedResourceContent(*resource, result, base64Encoded);
179     }
180
181     if (!success)
182         errorString = "No resource with given URL found"_s;
183 }
184
185 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
186 {
187     if (!cachedResource)
188         return String();
189
190     // Scripts are handled in a separate path.
191     if (cachedResource->type() != CachedResource::Type::CSSStyleSheet)
192         return String();
193
194     String sourceMapHeader = cachedResource->response().httpHeaderField(HTTPHeaderName::SourceMap);
195     if (!sourceMapHeader.isEmpty())
196         return sourceMapHeader;
197
198     sourceMapHeader = cachedResource->response().httpHeaderField(HTTPHeaderName::XSourceMap);
199     if (!sourceMapHeader.isEmpty())
200         return sourceMapHeader;
201
202     String content;
203     bool base64Encoded;
204     if (InspectorNetworkAgent::cachedResourceContent(*cachedResource, &content, &base64Encoded) && !base64Encoded)
205         return ContentSearchUtilities::findStylesheetSourceMapURL(content);
206
207     return String();
208 }
209
210 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
211 {
212     if (url.isNull())
213         return nullptr;
214
215     CachedResource* cachedResource = frame->document()->cachedResourceLoader().cachedResource(MemoryCache::removeFragmentIdentifierIfNeeded(url));
216     if (!cachedResource) {
217         ResourceRequest request(url);
218         request.setDomainForCachePartition(frame->document()->domainForCachePartition());
219         cachedResource = MemoryCache::singleton().resourceForRequest(request, frame->page()->sessionID());
220     }
221
222     return cachedResource;
223 }
224
225 Inspector::Protocol::Page::ResourceType InspectorPageAgent::resourceTypeJSON(InspectorPageAgent::ResourceType resourceType)
226 {
227     switch (resourceType) {
228     case DocumentResource:
229         return Inspector::Protocol::Page::ResourceType::Document;
230     case ImageResource:
231         return Inspector::Protocol::Page::ResourceType::Image;
232     case FontResource:
233         return Inspector::Protocol::Page::ResourceType::Font;
234     case StylesheetResource:
235         return Inspector::Protocol::Page::ResourceType::Stylesheet;
236     case ScriptResource:
237         return Inspector::Protocol::Page::ResourceType::Script;
238     case XHRResource:
239         return Inspector::Protocol::Page::ResourceType::XHR;
240     case FetchResource:
241         return Inspector::Protocol::Page::ResourceType::Fetch;
242     case PingResource:
243         return Inspector::Protocol::Page::ResourceType::Ping;
244     case BeaconResource:
245         return Inspector::Protocol::Page::ResourceType::Beacon;
246     case WebSocketResource:
247         return Inspector::Protocol::Page::ResourceType::WebSocket;
248     case OtherResource:
249         return Inspector::Protocol::Page::ResourceType::Other;
250 #if ENABLE(APPLICATION_MANIFEST)
251     case ApplicationManifestResource:
252         break;
253 #endif
254     }
255     return Inspector::Protocol::Page::ResourceType::Other;
256 }
257
258 InspectorPageAgent::ResourceType InspectorPageAgent::inspectorResourceType(CachedResource::Type type)
259 {
260     switch (type) {
261     case CachedResource::Type::ImageResource:
262         return InspectorPageAgent::ImageResource;
263 #if ENABLE(SVG_FONTS)
264     case CachedResource::Type::SVGFontResource:
265 #endif
266     case CachedResource::Type::FontResource:
267         return InspectorPageAgent::FontResource;
268 #if ENABLE(XSLT)
269     case CachedResource::Type::XSLStyleSheet:
270 #endif
271     case CachedResource::Type::CSSStyleSheet:
272         return InspectorPageAgent::StylesheetResource;
273     case CachedResource::Type::Script:
274         return InspectorPageAgent::ScriptResource;
275     case CachedResource::Type::MainResource:
276         return InspectorPageAgent::DocumentResource;
277     case CachedResource::Type::Beacon:
278         return InspectorPageAgent::BeaconResource;
279 #if ENABLE(APPLICATION_MANIFEST)
280     case CachedResource::Type::ApplicationManifest:
281         return InspectorPageAgent::ApplicationManifestResource;
282 #endif
283     case CachedResource::Type::MediaResource:
284     case CachedResource::Type::Icon:
285     case CachedResource::Type::RawResource:
286     default:
287         return InspectorPageAgent::OtherResource;
288     }
289 }
290
291 InspectorPageAgent::ResourceType InspectorPageAgent::inspectorResourceType(const CachedResource& cachedResource)
292 {
293     if (cachedResource.type() == CachedResource::Type::RawResource) {
294         switch (cachedResource.resourceRequest().requester()) {
295         case ResourceRequest::Requester::Fetch:
296             return InspectorPageAgent::FetchResource;
297         case ResourceRequest::Requester::Main:
298             return InspectorPageAgent::DocumentResource;
299         default:
300             return InspectorPageAgent::XHRResource;
301         }
302     }
303
304     return inspectorResourceType(cachedResource.type());
305 }
306
307 Inspector::Protocol::Page::ResourceType InspectorPageAgent::cachedResourceTypeJSON(const CachedResource& cachedResource)
308 {
309     return resourceTypeJSON(inspectorResourceType(cachedResource));
310 }
311
312 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(Page& page, const String& originRawString)
313 {
314     for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
315         if (frame->document()->securityOrigin().toRawString() == originRawString)
316             return frame;
317     }
318     return nullptr;
319 }
320
321 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString& errorString, Frame* frame)
322 {
323     FrameLoader& frameLoader = frame->loader();
324     DocumentLoader* documentLoader = frameLoader.documentLoader();
325     if (!documentLoader)
326         errorString = "No documentLoader for given frame found"_s;
327     return documentLoader;
328 }
329
330 InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClient* client, InspectorOverlay* overlay)
331     : InspectorAgentBase("Page"_s, context)
332     , m_frontendDispatcher(std::make_unique<Inspector::PageFrontendDispatcher>(context.frontendRouter))
333     , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this))
334     , m_inspectedPage(context.inspectedPage)
335     , m_client(client)
336     , m_overlay(overlay)
337 {
338 }
339
340 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
341 {
342 }
343
344 void InspectorPageAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
345 {
346     ErrorString unused;
347     disable(unused);
348 }
349
350 double InspectorPageAgent::timestamp()
351 {
352     return m_environment.executionStopwatch()->elapsedTime().seconds();
353 }
354
355 void InspectorPageAgent::enable(ErrorString&)
356 {
357     if (m_instrumentingAgents.inspectorPageAgent() == this)
358         return;
359
360     m_instrumentingAgents.setInspectorPageAgent(this);
361
362     auto stopwatch = m_environment.executionStopwatch();
363     stopwatch->reset();
364     stopwatch->start();
365
366 #if HAVE(OS_DARK_MODE_SUPPORT)
367     defaultAppearanceDidChange(m_inspectedPage.defaultUseDarkAppearance());
368 #endif
369 }
370
371 void InspectorPageAgent::disable(ErrorString&)
372 {
373     ErrorString unused;
374     setShowPaintRects(unused, false);
375     setShowRulers(unused, false);
376     overrideUserAgent(unused, nullptr);
377     setEmulatedMedia(unused, emptyString());
378     setForcedAppearance(unused, emptyString());
379
380 #define DISABLE_INSPECTOR_OVERRIDE_SETTING(name) \
381     m_inspectedPage.settings().set##name##InspectorOverride(WTF::nullopt);
382
383     FOR_EACH_INSPECTOR_OVERRIDE_SETTING(DISABLE_INSPECTOR_OVERRIDE_SETTING)
384
385 #undef DISABLE_INSPECTOR_OVERRIDE_SETTING
386
387     m_instrumentingAgents.setInspectorPageAgent(nullptr);
388 }
389
390 void InspectorPageAgent::reload(ErrorString&, const bool* optionalReloadFromOrigin, const bool* optionalRevalidateAllResources)
391 {
392     bool reloadFromOrigin = optionalReloadFromOrigin && *optionalReloadFromOrigin;
393     bool revalidateAllResources = optionalRevalidateAllResources && *optionalRevalidateAllResources;
394
395     OptionSet<ReloadOption> reloadOptions;
396     if (reloadFromOrigin)
397         reloadOptions.add(ReloadOption::FromOrigin);
398     if (!revalidateAllResources)
399         reloadOptions.add(ReloadOption::ExpiredOnly);
400
401     m_inspectedPage.mainFrame().loader().reload(reloadOptions);
402 }
403
404 void InspectorPageAgent::navigate(ErrorString&, const String& url)
405 {
406     UserGestureIndicator indicator { ProcessingUserGesture };
407     Frame& frame = m_inspectedPage.mainFrame();
408
409     ResourceRequest resourceRequest { frame.document()->completeURL(url) };
410     FrameLoadRequest frameLoadRequest { *frame.document(), frame.document()->securityOrigin(), resourceRequest, "_self"_s, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown };
411     frame.loader().changeLocation(WTFMove(frameLoadRequest));
412 }
413
414 void InspectorPageAgent::overrideUserAgent(ErrorString&, const String* value)
415 {
416     m_userAgentOverride = value ? *value : String();
417 }
418
419 void InspectorPageAgent::overrideSetting(ErrorString& errorString, const String& settingString, const bool* value)
420 {
421     if (settingString.isEmpty()) {
422         errorString = "Preference is empty"_s;
423         return;
424     }
425
426     auto setting = Inspector::Protocol::InspectorHelpers::parseEnumValueFromString<Inspector::Protocol::Page::Setting>(settingString);
427     if (!setting) {
428         errorString = makeString("Unknown setting: "_s, settingString);
429         return;
430     }
431
432     switch (setting.value()) {
433 #define CASE_INSPECTOR_OVERRIDE_SETTING(name) \
434     case Inspector::Protocol::Page::Setting::name: { \
435         if (value) \
436             m_inspectedPage.settings().set##name##InspectorOverride(*value); \
437         else \
438             m_inspectedPage.settings().set##name##InspectorOverride(WTF::nullopt); \
439         return; \
440     } \
441
442     FOR_EACH_INSPECTOR_OVERRIDE_SETTING(CASE_INSPECTOR_OVERRIDE_SETTING)
443
444 #undef CASE_INSPECTOR_OVERRIDE_SETTING
445     }
446
447     ASSERT_NOT_REACHED();
448 }
449
450 static Inspector::Protocol::Page::CookieSameSitePolicy cookieSameSitePolicyJSON(Cookie::SameSitePolicy policy)
451 {
452     switch (policy) {
453     case Cookie::SameSitePolicy::None:
454         return Inspector::Protocol::Page::CookieSameSitePolicy::None;
455     case Cookie::SameSitePolicy::Lax:
456         return Inspector::Protocol::Page::CookieSameSitePolicy::Lax;
457     case Cookie::SameSitePolicy::Strict:
458         return Inspector::Protocol::Page::CookieSameSitePolicy::Strict;
459     }
460     ASSERT_NOT_REACHED();
461     return Inspector::Protocol::Page::CookieSameSitePolicy::None;
462 }
463
464 static Ref<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
465 {
466     return Inspector::Protocol::Page::Cookie::create()
467         .setName(cookie.name)
468         .setValue(cookie.value)
469         .setDomain(cookie.domain)
470         .setPath(cookie.path)
471         .setExpires(cookie.expires)
472         .setSize((cookie.name.length() + cookie.value.length()))
473         .setHttpOnly(cookie.httpOnly)
474         .setSecure(cookie.secure)
475         .setSession(cookie.session)
476         .setSameSite(cookieSameSitePolicyJSON(cookie.sameSite))
477         .release();
478 }
479
480 static Ref<JSON::ArrayOf<Inspector::Protocol::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
481 {
482     auto cookies = JSON::ArrayOf<Inspector::Protocol::Page::Cookie>::create();
483
484     for (const auto& cookie : cookiesList)
485         cookies->addItem(buildObjectForCookie(cookie));
486
487     return cookies;
488 }
489
490 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
491 {
492     Vector<URL> result;
493
494     result.append(frame->loader().documentLoader()->url());
495
496     for (auto* cachedResource : InspectorPageAgent::cachedResourcesForFrame(frame))
497         result.append(cachedResource->url());
498
499     return result;
500 }
501
502 void InspectorPageAgent::getCookies(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::Cookie>>& cookies)
503 {
504     // If we can get raw cookies.
505     ListHashSet<Cookie> rawCookiesList;
506
507     // If we can't get raw cookies - fall back to String representation
508     StringBuilder stringCookiesList;
509
510     // Return value to getRawCookies should be the same for every call because
511     // the return value is platform/network backend specific, and the call will
512     // always return the same true/false value.
513     bool rawCookiesImplemented = false;
514
515     for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) {
516         Document* document = frame->document();
517         if (!document || !document->page())
518             continue;
519
520         for (auto& url : allResourcesURLsForFrame(frame)) {
521             Vector<Cookie> docCookiesList;
522             rawCookiesImplemented = document->page()->cookieJar().getRawCookies(*document, URL({ }, url), docCookiesList);
523
524             if (!rawCookiesImplemented) {
525                 // FIXME: We need duplication checking for the String representation of cookies.
526                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
527                 // because "document" is the document of the main frame of the page.
528                 stringCookiesList.append(document->cookie().releaseReturnValue());
529             } else {
530                 for (auto& cookie : docCookiesList)
531                     rawCookiesList.add(cookie);
532             }
533         }
534     }
535
536     // FIXME: Do not return empty string/empty array. Make returns optional instead. https://bugs.webkit.org/show_bug.cgi?id=80855
537     if (rawCookiesImplemented)
538         cookies = buildArrayForCookies(rawCookiesList);
539     else
540         cookies = JSON::ArrayOf<Inspector::Protocol::Page::Cookie>::create();
541 }
542
543 void InspectorPageAgent::deleteCookie(ErrorString&, const String& cookieName, const String& url)
544 {
545     URL parsedURL({ }, url);
546     for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) {
547         if (auto* document = frame->document()) {
548             if (auto* page = document->page())
549                 page->cookieJar().deleteCookie(*document, parsedURL, cookieName);
550         }
551     }
552 }
553
554 void InspectorPageAgent::getResourceTree(ErrorString&, RefPtr<Inspector::Protocol::Page::FrameResourceTree>& object)
555 {
556     object = buildObjectForFrameTree(&m_inspectedPage.mainFrame());
557 }
558
559 void InspectorPageAgent::getResourceContent(ErrorString& errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
560 {
561     Frame* frame = assertFrame(errorString, frameId);
562     if (!frame)
563         return;
564
565     resourceContent(errorString, frame, URL({ }, url), content, base64Encoded);
566 }
567
568 void InspectorPageAgent::searchInResource(ErrorString& errorString, const String& frameId, const String& url, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, const String* optionalRequestId, RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>>& results)
569 {
570     results = JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>::create();
571
572     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
573     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
574
575     if (optionalRequestId) {
576         if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent()) {
577             networkAgent->searchInRequest(errorString, *optionalRequestId, query, caseSensitive, isRegex, results);
578             return;
579         }
580     }
581
582     Frame* frame = assertFrame(errorString, frameId);
583     if (!frame)
584         return;
585
586     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
587     if (!loader)
588         return;
589
590     URL kurl({ }, url);
591
592     String content;
593     bool success = false;
594     if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
595         success = mainResourceContent(frame, false, &content);
596
597     if (!success) {
598         if (auto* resource = cachedResource(frame, kurl)) {
599             if (auto textContent = InspectorNetworkAgent::textContentForCachedResource(*resource)) {
600                 content = *textContent;
601                 success = true;
602             }
603         }
604     }
605
606     if (!success)
607         return;
608
609     results = ContentSearchUtilities::searchInTextByLines(content, query, caseSensitive, isRegex);
610 }
611
612 static Ref<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
613 {
614     return Inspector::Protocol::Page::SearchResult::create()
615         .setUrl(url)
616         .setFrameId(frameId)
617         .setMatchesCount(matchesCount)
618         .release();
619 }
620
621 void InspectorPageAgent::searchInResources(ErrorString&, const String& text, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>& result)
622 {
623     result = JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>::create();
624
625     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
626     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
627     JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
628
629     for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) {
630         for (auto* cachedResource : cachedResourcesForFrame(frame)) {
631             if (auto textContent = InspectorNetworkAgent::textContentForCachedResource(*cachedResource)) {
632                 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, *textContent);
633                 if (matchesCount)
634                     result->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
635             }
636         }
637     }
638
639     if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent())
640         networkAgent->searchOtherRequests(regex, result);
641 }
642
643 void InspectorPageAgent::setShowRulers(ErrorString&, bool showRulers)
644 {
645     m_overlay->setShowRulers(showRulers);
646 }
647
648 void InspectorPageAgent::setShowPaintRects(ErrorString&, bool show)
649 {
650     m_showPaintRects = show;
651     m_client->setShowPaintRects(show);
652
653     if (m_client->overridesShowPaintRects())
654         return;
655
656     m_overlay->setShowPaintRects(show);
657 }
658
659 void InspectorPageAgent::domContentEventFired()
660 {
661     m_isFirstLayoutAfterOnLoad = true;
662     m_frontendDispatcher->domContentEventFired(timestamp());
663 }
664
665 void InspectorPageAgent::loadEventFired()
666 {
667     m_frontendDispatcher->loadEventFired(timestamp());
668 }
669
670 void InspectorPageAgent::frameNavigated(Frame& frame)
671 {
672     m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame));
673 }
674
675 void InspectorPageAgent::frameDetached(Frame& frame)
676 {
677     auto identifier = m_frameToIdentifier.take(&frame);
678     if (identifier.isNull())
679         return;
680     m_frontendDispatcher->frameDetached(identifier);
681     m_identifierToFrame.remove(identifier);
682 }
683
684 Frame* InspectorPageAgent::frameForId(const String& frameId)
685 {
686     return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
687 }
688
689 String InspectorPageAgent::frameId(Frame* frame)
690 {
691     if (!frame)
692         return emptyString();
693     return m_frameToIdentifier.ensure(frame, [this, frame] {
694         auto identifier = IdentifiersFactory::createIdentifier();
695         m_identifierToFrame.set(identifier, frame);
696         return identifier;
697     }).iterator->value;
698 }
699
700 String InspectorPageAgent::loaderId(DocumentLoader* loader)
701 {
702     if (!loader)
703         return emptyString();
704     return m_loaderToIdentifier.ensure(loader, [] {
705         return IdentifiersFactory::createIdentifier();
706     }).iterator->value;
707 }
708
709 Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId)
710 {
711     Frame* frame = frameForId(frameId);
712     if (!frame)
713         errorString = "No frame for given id found"_s;
714     return frame;
715 }
716
717 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader)
718 {
719     m_loaderToIdentifier.remove(&loader);
720 }
721
722 void InspectorPageAgent::frameStartedLoading(Frame& frame)
723 {
724     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
725 }
726
727 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
728 {
729     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
730 }
731
732 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay)
733 {
734     m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value());
735 }
736
737 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
738 {
739     m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
740 }
741
742 void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance)
743 {
744     m_frontendDispatcher->defaultAppearanceDidChange(useDarkAppearance ? Inspector::Protocol::Page::Appearance::Dark : Inspector::Protocol::Page::Appearance::Light);
745 }
746
747 void InspectorPageAgent::didPaint(RenderObject& renderer, const LayoutRect& rect)
748 {
749     if (!m_showPaintRects)
750         return;
751
752     LayoutRect absoluteRect = LayoutRect(renderer.localToAbsoluteQuad(FloatRect(rect)).boundingBox());
753     FrameView* view = renderer.document().view();
754
755     LayoutRect rootRect = absoluteRect;
756     if (!view->frame().isMainFrame()) {
757         IntRect rootViewRect = view->contentsToRootView(snappedIntRect(absoluteRect));
758         rootRect = view->frame().mainFrame().view()->rootViewToContents(rootViewRect);
759     }
760
761     if (m_client->overridesShowPaintRects()) {
762         m_client->showPaintRect(rootRect);
763         return;
764     }
765
766     m_overlay->showPaintRect(rootRect);
767 }
768
769 void InspectorPageAgent::didLayout()
770 {
771     bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
772     if (isFirstLayout)
773         m_isFirstLayoutAfterOnLoad = false;
774
775     m_overlay->update();
776 }
777
778 void InspectorPageAgent::didScroll()
779 {
780     m_overlay->update();
781 }
782
783 void InspectorPageAgent::didRecalculateStyle()
784 {
785     m_overlay->update();
786 }
787
788 Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
789 {
790     ASSERT_ARG(frame, frame);
791
792     auto frameObject = Inspector::Protocol::Page::Frame::create()
793         .setId(frameId(frame))
794         .setLoaderId(loaderId(frame->loader().documentLoader()))
795         .setUrl(frame->document()->url().string())
796         .setMimeType(frame->loader().documentLoader()->responseMIMEType())
797         .setSecurityOrigin(frame->document()->securityOrigin().toRawString())
798         .release();
799     if (frame->tree().parent())
800         frameObject->setParentId(frameId(frame->tree().parent()));
801     if (frame->ownerElement()) {
802         String name = frame->ownerElement()->getNameAttribute();
803         if (name.isEmpty())
804             name = frame->ownerElement()->attributeWithoutSynchronization(HTMLNames::idAttr);
805         frameObject->setName(name);
806     }
807
808     return frameObject;
809 }
810
811 Ref<Inspector::Protocol::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
812 {
813     ASSERT_ARG(frame, frame);
814
815     Ref<Inspector::Protocol::Page::Frame> frameObject = buildObjectForFrame(frame);
816     auto subresources = JSON::ArrayOf<Inspector::Protocol::Page::FrameResource>::create();
817     auto result = Inspector::Protocol::Page::FrameResourceTree::create()
818         .setFrame(WTFMove(frameObject))
819         .setResources(subresources.copyRef())
820         .release();
821
822     for (auto* cachedResource : cachedResourcesForFrame(frame)) {
823         auto resourceObject = Inspector::Protocol::Page::FrameResource::create()
824             .setUrl(cachedResource->url())
825             .setType(cachedResourceTypeJSON(*cachedResource))
826             .setMimeType(cachedResource->response().mimeType())
827             .release();
828         if (cachedResource->wasCanceled())
829             resourceObject->setCanceled(true);
830         else if (cachedResource->status() == CachedResource::LoadError || cachedResource->status() == CachedResource::DecodeError)
831             resourceObject->setFailed(true);
832         String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
833         if (!sourceMappingURL.isEmpty())
834             resourceObject->setSourceMapURL(sourceMappingURL);
835         String targetId = cachedResource->resourceRequest().initiatorIdentifier();
836         if (!targetId.isEmpty())
837             resourceObject->setTargetId(targetId);
838         subresources->addItem(WTFMove(resourceObject));
839     }
840
841     RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::FrameResourceTree>> childrenArray;
842     for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
843         if (!childrenArray) {
844             childrenArray = JSON::ArrayOf<Inspector::Protocol::Page::FrameResourceTree>::create();
845             result->setChildFrames(childrenArray);
846         }
847         childrenArray->addItem(buildObjectForFrameTree(child));
848     }
849     return result;
850 }
851
852 void InspectorPageAgent::setEmulatedMedia(ErrorString&, const String& media)
853 {
854     if (media == m_emulatedMedia)
855         return;
856
857     m_emulatedMedia = media;
858
859     m_inspectedPage.updateStyleAfterChangeInEnvironment();
860
861     if (auto* document = m_inspectedPage.mainFrame().document())
862         document->updateLayout();
863 }
864
865 void InspectorPageAgent::setForcedAppearance(ErrorString&, const String& appearance)
866 {
867     if (appearance == m_forcedAppearance)
868         return;
869
870     m_forcedAppearance = appearance;
871
872     if (appearance == "Light"_s)
873         m_inspectedPage.setUseDarkAppearanceOverride(false);
874     else if (appearance == "Dark"_s)
875         m_inspectedPage.setUseDarkAppearanceOverride(true);
876     else
877         m_inspectedPage.setUseDarkAppearanceOverride(WTF::nullopt);
878 }
879
880 void InspectorPageAgent::applyUserAgentOverride(String& userAgent)
881 {
882     if (!m_userAgentOverride.isEmpty())
883         userAgent = m_userAgentOverride;
884 }
885
886 void InspectorPageAgent::applyEmulatedMedia(String& media)
887 {
888     if (!m_emulatedMedia.isEmpty())
889         media = m_emulatedMedia;
890 }
891
892 void InspectorPageAgent::getCompositingBordersVisible(ErrorString&, bool* outParam)
893 {
894     *outParam = m_inspectedPage.settings().showDebugBorders() || m_inspectedPage.settings().showRepaintCounter();
895 }
896
897 void InspectorPageAgent::setCompositingBordersVisible(ErrorString&, bool visible)
898 {
899     m_inspectedPage.settings().setShowDebugBorders(visible);
900     m_inspectedPage.settings().setShowRepaintCounter(visible);
901 }
902
903 void InspectorPageAgent::snapshotNode(ErrorString& errorString, int nodeId, String* outDataURL)
904 {
905     InspectorDOMAgent* domAgent = m_instrumentingAgents.inspectorDOMAgent();
906     ASSERT(domAgent);
907     Node* node = domAgent->assertNode(errorString, nodeId);
908     if (!node)
909         return;
910
911     std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(m_inspectedPage.mainFrame(), *node);
912     if (!snapshot) {
913         errorString = "Could not capture snapshot"_s;
914         return;
915     }
916
917     *outDataURL = snapshot->toDataURL("image/png"_s, WTF::nullopt, PreserveResolution::Yes);
918 }
919
920 void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
921 {
922     SnapshotOptions options = SnapshotOptionsNone;
923     if (coordinateSystem == "Viewport")
924         options |= SnapshotOptionsInViewCoordinates;
925
926     IntRect rectangle(x, y, width, height);
927     std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(m_inspectedPage.mainFrame(), rectangle, options);
928
929     if (!snapshot) {
930         errorString = "Could not capture snapshot"_s;
931         return;
932     }
933
934     *outDataURL = snapshot->toDataURL("image/png"_s, WTF::nullopt, PreserveResolution::Yes);
935 }
936
937 void InspectorPageAgent::archive(ErrorString& errorString, String* data)
938 {
939 #if ENABLE(WEB_ARCHIVE) && USE(CF)
940     auto archive = LegacyWebArchive::create(m_inspectedPage.mainFrame());
941     if (!archive) {
942         errorString = "Could not create web archive for main frame"_s;
943         return;
944     }
945
946     RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
947     *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
948 #else
949     UNUSED_PARAM(data);
950     errorString = "No support for creating archives"_s;
951 #endif
952 }
953
954 } // namespace WebCore