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