6f3d8ad16470c8e53ef6d71d0e2c9cadcb6d7121
[WebKit-https.git] / Source / WebCore / inspector / InspectorPageAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2015 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 "CachedCSSStyleSheet.h"
36 #include "CachedFont.h"
37 #include "CachedImage.h"
38 #include "CachedResource.h"
39 #include "CachedResourceLoader.h"
40 #include "CachedScript.h"
41 #include "Cookie.h"
42 #include "CookieJar.h"
43 #include "DOMPatchSupport.h"
44 #include "DOMWrapperWorld.h"
45 #include "Document.h"
46 #include "DocumentLoader.h"
47 #include "Frame.h"
48 #include "FrameLoadRequest.h"
49 #include "FrameLoader.h"
50 #include "FrameSnapshotting.h"
51 #include "FrameView.h"
52 #include "HTMLFrameOwnerElement.h"
53 #include "HTMLNames.h"
54 #include "ImageBuffer.h"
55 #include "InspectorClient.h"
56 #include "InspectorDOMAgent.h"
57 #include "InspectorNetworkAgent.h"
58 #include "InspectorOverlay.h"
59 #include "InspectorTimelineAgent.h"
60 #include "InstrumentingAgents.h"
61 #include "MIMETypeRegistry.h"
62 #include "MainFrame.h"
63 #include "MemoryCache.h"
64 #include "Page.h"
65 #include "RenderObject.h"
66 #include "ScriptController.h"
67 #include "SecurityOrigin.h"
68 #include "Settings.h"
69 #include "StyleScope.h"
70 #include "TextEncoding.h"
71 #include "TextResourceDecoder.h"
72 #include "UserGestureIndicator.h"
73 #include <inspector/ContentSearchUtilities.h>
74 #include <inspector/IdentifiersFactory.h>
75 #include <inspector/InspectorValues.h>
76 #include <wtf/ListHashSet.h>
77 #include <wtf/Stopwatch.h>
78 #include <wtf/text/Base64.h>
79 #include <wtf/text/StringBuilder.h>
80 #include <yarr/RegularExpression.h>
81
82 #if ENABLE(WEB_ARCHIVE) && USE(CF)
83 #include "LegacyWebArchive.h"
84 #endif
85
86 using namespace Inspector;
87
88 namespace WebCore {
89
90 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
91 {
92     if (buffer) {
93         TextEncoding encoding(textEncodingName);
94         if (!encoding.isValid())
95             encoding = WindowsLatin1Encoding();
96         *result = encoding.decode(buffer, size);
97         return true;
98     }
99     return false;
100 }
101
102 static bool prepareCachedResourceBuffer(CachedResource* cachedResource, bool* hasZeroSize)
103 {
104     *hasZeroSize = false;
105     if (!cachedResource)
106         return false;
107
108     // Zero-sized resources don't have data at all -- so fake the empty buffer, instead of indicating error by returning 0.
109     if (!cachedResource->encodedSize()) {
110         *hasZeroSize = true;
111         return true;
112     }
113
114     return true;
115 }
116
117 static bool hasTextContent(CachedResource* cachedResource)
118 {
119     InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
120     return type == InspectorPageAgent::DocumentResource
121         || type == InspectorPageAgent::StylesheetResource
122         || type == InspectorPageAgent::ScriptResource
123         || type == InspectorPageAgent::XHRResource;
124 }
125
126 static RefPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName)
127 {
128     RefPtr<TextResourceDecoder> decoder;
129     if (!textEncodingName.isEmpty())
130         decoder = TextResourceDecoder::create("text/plain", textEncodingName);
131     else if (MIMETypeRegistry::isXMLMIMEType(mimeType)) {
132         decoder = TextResourceDecoder::create("application/xml");
133         decoder->useLenientXMLDecoding();
134     } else if (equalLettersIgnoringASCIICase(mimeType, "text/html"))
135         decoder = TextResourceDecoder::create("text/html", "UTF-8");
136     else
137         decoder = TextResourceDecoder::create("text/plain", "UTF-8");
138     return decoder;
139 }
140
141 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
142 {
143     // FIXME: result should be a String& and base64Encoded should be a bool&.
144     bool hasZeroSize;
145     bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize);
146     if (!prepared)
147         return false;
148
149     *base64Encoded = !hasTextContent(cachedResource);
150     if (*base64Encoded) {
151         if (hasZeroSize) {
152             *result = { };
153             return true;
154         }
155         if (auto* buffer = cachedResource->resourceBuffer()) {
156             *result = base64Encode(buffer->data(), buffer->size());
157             return true;
158         }
159         return false;
160     }
161
162     if (hasZeroSize) {
163         *result = emptyString();
164         return true;
165     }
166
167     if (cachedResource) {
168         switch (cachedResource->type()) {
169         case CachedResource::CSSStyleSheet:
170             // This can return a null String if the MIME type is invalid.
171             *result = downcast<CachedCSSStyleSheet>(*cachedResource).sheetText();
172             return !result->isNull();
173         case CachedResource::Script:
174             *result = downcast<CachedScript>(*cachedResource).script().toString();
175             return true;
176         case CachedResource::MediaResource:
177         case CachedResource::RawResource: {
178             auto* buffer = cachedResource->resourceBuffer();
179             if (!buffer)
180                 return false;
181             RefPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
182             // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
183             if (!decoder)
184                 return false;
185             *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
186             return true;
187         }
188         default:
189             auto* buffer = cachedResource->resourceBuffer();
190             return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
191         }
192     }
193     return false;
194 }
195
196 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
197 {
198     RefPtr<SharedBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
199     if (!buffer)
200         return false;
201     return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), frame->document()->encoding(), withBase64Encode, result);
202 }
203
204 // static
205 bool InspectorPageAgent::sharedBufferContent(RefPtr<SharedBuffer>&& buffer, const String& textEncodingName, bool withBase64Encode, String* result)
206 {
207     return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
208 }
209
210 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
211 {
212     if (withBase64Encode) {
213         *result = base64Encode(data, size);
214         return true;
215     }
216
217     return decodeBuffer(data, size, textEncodingName, result);
218 }
219
220 // static
221 void InspectorPageAgent::resourceContent(ErrorString& errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
222 {
223     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
224     if (!loader)
225         return;
226
227     RefPtr<SharedBuffer> buffer;
228     bool success = false;
229     if (equalIgnoringFragmentIdentifier(url, loader->url())) {
230         *base64Encoded = false;
231         success = mainResourceContent(frame, *base64Encoded, result);
232     }
233
234     if (!success)
235         success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
236
237     if (!success)
238         errorString = ASCIILiteral("No resource with given URL found");
239 }
240
241 //static
242 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
243 {
244     static NeverDestroyed<String> sourceMapHTTPHeader(ASCIILiteral("SourceMap"));
245     static NeverDestroyed<String> sourceMapHTTPHeaderDeprecated(ASCIILiteral("X-SourceMap"));
246
247     if (!cachedResource)
248         return String();
249
250     // Scripts are handled in a separate path.
251     if (cachedResource->type() != CachedResource::CSSStyleSheet)
252         return String();
253
254     String sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeader);
255     if (!sourceMapHeader.isEmpty())
256         return sourceMapHeader;
257
258     sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
259     if (!sourceMapHeader.isEmpty())
260         return sourceMapHeader;
261
262     String content;
263     bool base64Encoded;
264     if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
265         return ContentSearchUtilities::findStylesheetSourceMapURL(content);
266
267     return String();
268 }
269
270 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
271 {
272     if (url.isNull())
273         return nullptr;
274
275     CachedResource* cachedResource = frame->document()->cachedResourceLoader().cachedResource(MemoryCache::removeFragmentIdentifierIfNeeded(url));
276     if (!cachedResource) {
277         ResourceRequest request(url);
278 #if ENABLE(CACHE_PARTITIONING)
279         request.setDomainForCachePartition(frame->document()->topOrigin()->domainForCachePartition());
280 #endif
281         cachedResource = MemoryCache::singleton().resourceForRequest(request, frame->page()->sessionID());
282     }
283
284     return cachedResource;
285 }
286
287 Inspector::Protocol::Page::ResourceType InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
288 {
289     switch (resourceType) {
290     case DocumentResource:
291         return Inspector::Protocol::Page::ResourceType::Document;
292     case ImageResource:
293         return Inspector::Protocol::Page::ResourceType::Image;
294     case FontResource:
295         return Inspector::Protocol::Page::ResourceType::Font;
296     case StylesheetResource:
297         return Inspector::Protocol::Page::ResourceType::Stylesheet;
298     case ScriptResource:
299         return Inspector::Protocol::Page::ResourceType::Script;
300     case XHRResource:
301         return Inspector::Protocol::Page::ResourceType::XHR;
302     case WebSocketResource:
303         return Inspector::Protocol::Page::ResourceType::WebSocket;
304     case OtherResource:
305         return Inspector::Protocol::Page::ResourceType::Other;
306     }
307     return Inspector::Protocol::Page::ResourceType::Other;
308 }
309
310 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
311 {
312     switch (cachedResource.type()) {
313     case CachedResource::ImageResource:
314         return InspectorPageAgent::ImageResource;
315 #if ENABLE(SVG_FONTS)
316     case CachedResource::SVGFontResource:
317 #endif
318     case CachedResource::FontResource:
319         return InspectorPageAgent::FontResource;
320     case CachedResource::CSSStyleSheet:
321         // Fall through.
322 #if ENABLE(XSLT)
323     case CachedResource::XSLStyleSheet:
324 #endif
325         return InspectorPageAgent::StylesheetResource;
326     case CachedResource::Script:
327         return InspectorPageAgent::ScriptResource;
328     case CachedResource::MediaResource:
329     case CachedResource::RawResource:
330         return InspectorPageAgent::XHRResource;
331     case CachedResource::MainResource:
332         return InspectorPageAgent::DocumentResource;
333     default:
334         break;
335     }
336     return InspectorPageAgent::OtherResource;
337 }
338
339 Inspector::Protocol::Page::ResourceType InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
340 {
341     return resourceTypeJson(cachedResourceType(cachedResource));
342 }
343
344 InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClient* client, InspectorOverlay* overlay)
345     : InspectorAgentBase(ASCIILiteral("Page"), context)
346     , m_frontendDispatcher(std::make_unique<Inspector::PageFrontendDispatcher>(context.frontendRouter))
347     , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this))
348     , m_page(context.inspectedPage)
349     , m_client(client)
350     , m_overlay(overlay)
351 {
352 }
353
354 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
355 {
356 }
357
358 void InspectorPageAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
359 {
360     ErrorString unused;
361     disable(unused);
362 #if ENABLE(TOUCH_EVENTS)
363     updateTouchEventEmulationInPage(false);
364 #endif
365 }
366
367 double InspectorPageAgent::timestamp()
368 {
369     return m_environment.executionStopwatch()->elapsedTime();
370 }
371
372 void InspectorPageAgent::enable(ErrorString&)
373 {
374     m_enabled = true;
375     m_instrumentingAgents.setInspectorPageAgent(this);
376
377     auto stopwatch = m_environment.executionStopwatch();
378     stopwatch->reset();
379     stopwatch->start();
380
381     m_originalScriptExecutionDisabled = !mainFrame().settings().isScriptEnabled();
382 }
383
384 void InspectorPageAgent::disable(ErrorString&)
385 {
386     m_enabled = false;
387     m_scriptsToEvaluateOnLoad = nullptr;
388     m_instrumentingAgents.setInspectorPageAgent(nullptr);
389
390     ErrorString unused;
391     setScriptExecutionDisabled(unused, m_originalScriptExecutionDisabled);
392     setShowPaintRects(unused, false);
393     setEmulatedMedia(unused, emptyString());
394 }
395
396 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString&, const String& source, String* identifier)
397 {
398     if (!m_scriptsToEvaluateOnLoad)
399         m_scriptsToEvaluateOnLoad = InspectorObject::create();
400
401     // Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual
402     // scripts once we restored the scripts from the cookie during navigation.
403     do {
404         *identifier = String::number(++m_lastScriptIdentifier);
405     } while (m_scriptsToEvaluateOnLoad->find(*identifier) != m_scriptsToEvaluateOnLoad->end());
406
407     m_scriptsToEvaluateOnLoad->setString(*identifier, source);
408 }
409
410 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString& error, const String& identifier)
411 {
412     if (!m_scriptsToEvaluateOnLoad || m_scriptsToEvaluateOnLoad->find(identifier) == m_scriptsToEvaluateOnLoad->end()) {
413         error = ASCIILiteral("Script not found");
414         return;
415     }
416
417     m_scriptsToEvaluateOnLoad->remove(identifier);
418 }
419
420 void InspectorPageAgent::reload(ErrorString&, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
421 {
422     m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : emptyString();
423     m_page.mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
424 }
425
426 void InspectorPageAgent::navigate(ErrorString&, const String& url)
427 {
428     UserGestureIndicator indicator(ProcessingUserGesture);
429     Frame& frame = m_page.mainFrame();
430
431     ResourceRequest resourceRequest(frame.document()->completeURL(url));
432     FrameLoadRequest frameRequest(frame.document()->securityOrigin(), resourceRequest, "_self", LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldReplaceDocumentIfJavaScriptURL::ReplaceDocumentIfJavaScriptURL, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
433     frame.loader().changeLocation(frameRequest);
434 }
435
436 static Ref<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
437 {
438     return Inspector::Protocol::Page::Cookie::create()
439         .setName(cookie.name)
440         .setValue(cookie.value)
441         .setDomain(cookie.domain)
442         .setPath(cookie.path)
443         .setExpires(cookie.expires)
444         .setSize((cookie.name.length() + cookie.value.length()))
445         .setHttpOnly(cookie.httpOnly)
446         .setSecure(cookie.secure)
447         .setSession(cookie.session)
448         .release();
449 }
450
451 static Ref<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
452 {
453     auto cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
454
455     for (const auto& cookie : cookiesList)
456         cookies->addItem(buildObjectForCookie(cookie));
457
458     return cookies;
459 }
460
461 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
462 {
463     Vector<CachedResource*> result;
464
465     for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader().allCachedResources().values()) {
466         auto* cachedResource = cachedResourceHandle.get();
467         if (cachedResource->resourceRequest().hiddenFromInspector())
468             continue;
469
470         switch (cachedResource->type()) {
471         case CachedResource::ImageResource:
472             // Skip images that were not auto loaded (images disabled in the user agent).
473 #if ENABLE(SVG_FONTS)
474         case CachedResource::SVGFontResource:
475 #endif
476         case CachedResource::FontResource:
477             // Skip fonts that were referenced in CSS but never used/downloaded.
478             if (cachedResource->stillNeedsLoad())
479                 continue;
480             break;
481         default:
482             // All other CachedResource types download immediately.
483             break;
484         }
485
486         result.append(cachedResource);
487     }
488
489     return result;
490 }
491
492 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
493 {
494     Vector<URL> result;
495
496     result.append(frame->loader().documentLoader()->url());
497
498     for (auto* cachedResource : cachedResourcesForFrame(frame))
499         result.append(cachedResource->url());
500
501     return result;
502 }
503
504 void InspectorPageAgent::getCookies(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>>& cookies)
505 {
506     // If we can get raw cookies.
507     ListHashSet<Cookie> rawCookiesList;
508
509     // If we can't get raw cookies - fall back to String representation
510     StringBuilder stringCookiesList;
511
512     // Return value to getRawCookies should be the same for every call because
513     // the return value is platform/network backend specific, and the call will
514     // always return the same true/false value.
515     bool rawCookiesImplemented = false;
516
517     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
518         Document* document = frame->document();
519         if (!document)
520             continue;
521
522         for (auto& url : allResourcesURLsForFrame(frame)) {
523             Vector<Cookie> docCookiesList;
524             rawCookiesImplemented = getRawCookies(*document, URL(ParsedURLString, url), docCookiesList);
525
526             if (!rawCookiesImplemented) {
527                 // FIXME: We need duplication checking for the String representation of cookies.
528                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
529                 // because "document" is the document of the main frame of the page.
530                 stringCookiesList.append(document->cookie().releaseReturnValue());
531             } else {
532                 for (auto& cookie : docCookiesList) {
533                     if (!rawCookiesList.contains(cookie))
534                         rawCookiesList.add(cookie);
535                 }
536             }
537         }
538     }
539
540     // FIXME: Do not return empty string/empty array. Make returns optional instead. https://bugs.webkit.org/show_bug.cgi?id=80855
541     if (rawCookiesImplemented)
542         cookies = buildArrayForCookies(rawCookiesList);
543     else
544         cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
545 }
546
547 void InspectorPageAgent::deleteCookie(ErrorString&, const String& cookieName, const String& url)
548 {
549     URL parsedURL(ParsedURLString, url);
550     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
551         if (auto* document = frame->document())
552             WebCore::deleteCookie(*document, parsedURL, cookieName);
553     }
554 }
555
556 void InspectorPageAgent::getResourceTree(ErrorString&, RefPtr<Inspector::Protocol::Page::FrameResourceTree>& object)
557 {
558     object = buildObjectForFrameTree(&m_page.mainFrame());
559 }
560
561 void InspectorPageAgent::getResourceContent(ErrorString& errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
562 {
563     Frame* frame = assertFrame(errorString, frameId);
564     if (!frame)
565         return;
566
567     resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
568 }
569
570 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
571 {
572     if (hasTextContent(cachedResource)) {
573         String content;
574         bool base64Encoded;
575         if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
576             ASSERT(!base64Encoded);
577             return true;
578         }
579     }
580     return false;
581 }
582
583 void InspectorPageAgent::searchInResource(ErrorString& errorString, const String& frameId, const String& url, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, const String* optionalRequestId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>>& results)
584 {
585     results = Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>::create();
586
587     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
588     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
589
590     if (optionalRequestId) {
591         if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent()) {
592             networkAgent->searchInRequest(errorString, *optionalRequestId, query, caseSensitive, isRegex, results);
593             return;
594         }
595     }
596
597     Frame* frame = assertFrame(errorString, frameId);
598     if (!frame)
599         return;
600
601     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
602     if (!loader)
603         return;
604
605     URL kurl(ParsedURLString, url);
606
607     String content;
608     bool success = false;
609     if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
610         success = mainResourceContent(frame, false, &content);
611
612     if (!success) {
613         CachedResource* resource = cachedResource(frame, kurl);
614         if (resource)
615             success = textContentForCachedResource(resource, &content);
616     }
617
618     if (!success)
619         return;
620
621     results = ContentSearchUtilities::searchInTextByLines(content, query, caseSensitive, isRegex);
622 }
623
624 static Ref<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
625 {
626     return Inspector::Protocol::Page::SearchResult::create()
627         .setUrl(url)
628         .setFrameId(frameId)
629         .setMatchesCount(matchesCount)
630         .release();
631 }
632
633 void InspectorPageAgent::searchInResources(ErrorString&, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>>& result)
634 {
635     result = Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>::create();
636
637     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
638     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
639     JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
640
641     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
642         String content;
643
644         for (auto* cachedResource : cachedResourcesForFrame(frame)) {
645             if (textContentForCachedResource(cachedResource, &content)) {
646                 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
647                 if (matchesCount)
648                     result->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
649             }
650         }
651
652         if (mainResourceContent(frame, false, &content)) {
653             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
654             if (matchesCount)
655                 result->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
656         }
657     }
658
659     if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent())
660         networkAgent->searchOtherRequests(regex, result);
661 }
662
663 void InspectorPageAgent::setDocumentContent(ErrorString& errorString, const String& frameId, const String& html)
664 {
665     Frame* frame = assertFrame(errorString, frameId);
666     if (!frame)
667         return;
668
669     Document* document = frame->document();
670     if (!document) {
671         errorString = ASCIILiteral("No Document instance to set HTML for");
672         return;
673     }
674     DOMPatchSupport::patchDocument(*document, html);
675 }
676
677 void InspectorPageAgent::setShowPaintRects(ErrorString&, bool show)
678 {
679     m_showPaintRects = show;
680     m_client->setShowPaintRects(show);
681
682     if (m_client->overridesShowPaintRects())
683         return;
684
685     m_overlay->setShowingPaintRects(show);
686 }
687
688 void InspectorPageAgent::getScriptExecutionStatus(ErrorString&, Inspector::PageBackendDispatcherHandler::Result* status)
689 {
690     bool disabledByScriptController = false;
691     bool disabledInSettings = false;
692     disabledByScriptController = mainFrame().script().canExecuteScripts(NotAboutToExecuteScript);
693     disabledInSettings = !mainFrame().settings().isScriptEnabled();
694
695     if (!disabledByScriptController) {
696         *status = Inspector::PageBackendDispatcherHandler::Result::Allowed;
697         return;
698     }
699
700     if (disabledInSettings)
701         *status = Inspector::PageBackendDispatcherHandler::Result::Disabled;
702     else
703         *status = Inspector::PageBackendDispatcherHandler::Result::Forbidden;
704 }
705
706 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString&, bool value)
707 {
708     m_ignoreScriptsEnabledNotification = true;
709     mainFrame().settings().setScriptEnabled(!value);
710     m_ignoreScriptsEnabledNotification = false;
711 }
712
713 void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld& world)
714 {
715     if (&world != &mainThreadNormalWorld())
716         return;
717
718     if (m_scriptsToEvaluateOnLoad) {
719         for (auto& keyValuePair : *m_scriptsToEvaluateOnLoad) {
720             String scriptText;
721             if (keyValuePair.value->asString(scriptText))
722                 frame->script().executeScript(scriptText);
723         }
724     }
725
726     if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
727         frame->script().executeScript(m_scriptToEvaluateOnLoadOnce);
728 }
729
730 void InspectorPageAgent::domContentEventFired()
731 {
732     m_isFirstLayoutAfterOnLoad = true;
733     m_frontendDispatcher->domContentEventFired(timestamp());
734 }
735
736 void InspectorPageAgent::loadEventFired()
737 {
738     m_frontendDispatcher->loadEventFired(timestamp());
739 }
740
741 void InspectorPageAgent::frameNavigated(Frame& frame)
742 {
743     if (frame.isMainFrame()) {
744         m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
745         m_pendingScriptToEvaluateOnLoadOnce = String();
746     }
747     m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame));
748 }
749
750 void InspectorPageAgent::frameDetached(Frame& frame)
751 {
752     HashMap<Frame*, String>::iterator iterator = m_frameToIdentifier.find(&frame);
753     if (iterator != m_frameToIdentifier.end()) {
754         m_frontendDispatcher->frameDetached(iterator->value);
755         m_identifierToFrame.remove(iterator->value);
756         m_frameToIdentifier.remove(iterator);
757     }
758 }
759
760 MainFrame& InspectorPageAgent::mainFrame()
761 {
762     return m_page.mainFrame();
763 }
764
765 Frame* InspectorPageAgent::frameForId(const String& frameId)
766 {
767     return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
768 }
769
770 String InspectorPageAgent::frameId(Frame* frame)
771 {
772     if (!frame)
773         return emptyString();
774     String identifier = m_frameToIdentifier.get(frame);
775     if (identifier.isNull()) {
776         identifier = IdentifiersFactory::createIdentifier();
777         m_frameToIdentifier.set(frame, identifier);
778         m_identifierToFrame.set(identifier, frame);
779     }
780     return identifier;
781 }
782
783 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
784 {
785     return frame && m_frameToIdentifier.contains(frame);
786 }
787
788 String InspectorPageAgent::loaderId(DocumentLoader* loader)
789 {
790     if (!loader)
791         return emptyString();
792     String identifier = m_loaderToIdentifier.get(loader);
793     if (identifier.isNull()) {
794         identifier = IdentifiersFactory::createIdentifier();
795         m_loaderToIdentifier.set(loader, identifier);
796     }
797     return identifier;
798 }
799
800 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
801 {
802     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
803         RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
804         if (documentOrigin->toRawString() == originRawString)
805             return frame;
806     }
807     return nullptr;
808 }
809
810 Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId)
811 {
812     Frame* frame = frameForId(frameId);
813     if (!frame)
814         errorString = ASCIILiteral("No frame for given id found");
815     return frame;
816 }
817
818 // static
819 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString& errorString, Frame* frame)
820 {
821     FrameLoader& frameLoader = frame->loader();
822     DocumentLoader* documentLoader = frameLoader.documentLoader();
823     if (!documentLoader)
824         errorString = ASCIILiteral("No documentLoader for given frame found");
825     return documentLoader;
826 }
827
828 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader)
829 {
830     m_loaderToIdentifier.remove(&loader);
831 }
832
833 void InspectorPageAgent::frameStartedLoading(Frame& frame)
834 {
835     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
836 }
837
838 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
839 {
840     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
841 }
842
843 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, double delay)
844 {
845     m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay);
846 }
847
848 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
849 {
850     m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
851 }
852
853 void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
854 {
855     m_frontendDispatcher->javascriptDialogOpening(message);
856 }
857
858 void InspectorPageAgent::didRunJavaScriptDialog()
859 {
860     m_frontendDispatcher->javascriptDialogClosed();
861 }
862
863 void InspectorPageAgent::didPaint(RenderObject& renderer, const LayoutRect& rect)
864 {
865     if (!m_enabled || !m_showPaintRects)
866         return;
867
868     LayoutRect absoluteRect = LayoutRect(renderer.localToAbsoluteQuad(FloatRect(rect)).boundingBox());
869     FrameView* view = renderer.document().view();
870
871     LayoutRect rootRect = absoluteRect;
872     if (!view->frame().isMainFrame()) {
873         IntRect rootViewRect = view->contentsToRootView(snappedIntRect(absoluteRect));
874         rootRect = view->frame().mainFrame().view()->rootViewToContents(rootViewRect);
875     }
876
877     if (m_client->overridesShowPaintRects()) {
878         m_client->showPaintRect(rootRect);
879         return;
880     }
881
882     m_overlay->showPaintRect(rootRect);
883 }
884
885 void InspectorPageAgent::didLayout()
886 {
887     bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
888     if (isFirstLayout)
889         m_isFirstLayoutAfterOnLoad = false;
890
891     if (!m_enabled)
892         return;
893
894     m_overlay->update();
895 }
896
897 void InspectorPageAgent::didScroll()
898 {
899     if (m_enabled)
900         m_overlay->update();
901 }
902
903 void InspectorPageAgent::didRecalculateStyle()
904 {
905     if (m_enabled)
906         m_overlay->update();
907 }
908
909 void InspectorPageAgent::scriptsEnabled(bool isEnabled)
910 {
911     if (m_ignoreScriptsEnabledNotification)
912         return;
913
914     m_frontendDispatcher->scriptsEnabled(isEnabled);
915 }
916
917 Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
918 {
919     ASSERT_ARG(frame, frame);
920
921     auto frameObject = Inspector::Protocol::Page::Frame::create()
922         .setId(frameId(frame))
923         .setLoaderId(loaderId(frame->loader().documentLoader()))
924         .setUrl(frame->document()->url().string())
925         .setMimeType(frame->loader().documentLoader()->responseMIMEType())
926         .setSecurityOrigin(frame->document()->securityOrigin()->toRawString())
927         .release();
928     if (frame->tree().parent())
929         frameObject->setParentId(frameId(frame->tree().parent()));
930     if (frame->ownerElement()) {
931         String name = frame->ownerElement()->getNameAttribute();
932         if (name.isEmpty())
933             name = frame->ownerElement()->attributeWithoutSynchronization(HTMLNames::idAttr);
934         frameObject->setName(name);
935     }
936
937     return frameObject;
938 }
939
940 Ref<Inspector::Protocol::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
941 {
942     ASSERT_ARG(frame, frame);
943
944     Ref<Inspector::Protocol::Page::Frame> frameObject = buildObjectForFrame(frame);
945     auto subresources = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResource>::create();
946     auto result = Inspector::Protocol::Page::FrameResourceTree::create()
947         .setFrame(WTFMove(frameObject))
948         .setResources(subresources.copyRef())
949         .release();
950
951     for (auto* cachedResource : cachedResourcesForFrame(frame)) {
952         auto resourceObject = Inspector::Protocol::Page::FrameResource::create()
953             .setUrl(cachedResource->url())
954             .setType(cachedResourceTypeJson(*cachedResource))
955             .setMimeType(cachedResource->response().mimeType())
956             .release();
957         if (cachedResource->wasCanceled())
958             resourceObject->setCanceled(true);
959         else if (cachedResource->status() == CachedResource::LoadError)
960             resourceObject->setFailed(true);
961         String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
962         if (!sourceMappingURL.isEmpty())
963             resourceObject->setSourceMapURL(sourceMappingURL);
964         String targetId = cachedResource->resourceRequest().initiatorIdentifier();
965         if (!targetId.isEmpty())
966             resourceObject->setTargetId(targetId);
967         subresources->addItem(WTFMove(resourceObject));
968     }
969
970     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>> childrenArray;
971     for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
972         if (!childrenArray) {
973             childrenArray = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>::create();
974             result->setChildFrames(childrenArray);
975         }
976         childrenArray->addItem(buildObjectForFrameTree(child));
977     }
978     return result;
979 }
980
981 #if ENABLE(TOUCH_EVENTS)
982 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
983 {
984     mainFrame().settings().setTouchEventEmulationEnabled(enabled);
985 }
986 #endif
987
988 void InspectorPageAgent::setTouchEmulationEnabled(ErrorString& error, bool enabled)
989 {
990 #if ENABLE(TOUCH_EVENTS)
991     UNUSED_PARAM(error);
992     updateTouchEventEmulationInPage(enabled);
993 #else
994     error = ASCIILiteral("Touch events emulation not supported");
995     UNUSED_PARAM(enabled);
996 #endif
997 }
998
999 void InspectorPageAgent::setEmulatedMedia(ErrorString&, const String& media)
1000 {
1001     if (media == m_emulatedMedia)
1002         return;
1003
1004     m_emulatedMedia = media;
1005     Document* document = m_page.mainFrame().document();
1006     if (document) {
1007         document->styleScope().didChangeStyleSheetEnvironment();
1008         document->updateLayout();
1009     }
1010 }
1011
1012 void InspectorPageAgent::applyEmulatedMedia(String& media)
1013 {
1014     if (!m_emulatedMedia.isEmpty())
1015         media = m_emulatedMedia;
1016 }
1017
1018 void InspectorPageAgent::getCompositingBordersVisible(ErrorString&, bool* outParam)
1019 {
1020     *outParam = m_page.settings().showDebugBorders() || m_page.settings().showRepaintCounter();
1021 }
1022
1023 void InspectorPageAgent::setCompositingBordersVisible(ErrorString&, bool visible)
1024 {
1025     m_page.settings().setShowDebugBorders(visible);
1026     m_page.settings().setShowRepaintCounter(visible);
1027 }
1028
1029 void InspectorPageAgent::snapshotNode(ErrorString& errorString, int nodeId, String* outDataURL)
1030 {
1031     Frame& frame = mainFrame();
1032
1033     InspectorDOMAgent* domAgent = m_instrumentingAgents.inspectorDOMAgent();
1034     ASSERT(domAgent);
1035     Node* node = domAgent->assertNode(errorString, nodeId);
1036     if (!node)
1037         return;
1038
1039     std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(frame, *node);
1040     if (!snapshot) {
1041         errorString = ASCIILiteral("Could not capture snapshot");
1042         return;
1043     }
1044
1045     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1046 }
1047
1048 void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
1049 {
1050     Frame& frame = mainFrame();
1051
1052     SnapshotOptions options = SnapshotOptionsNone;
1053     if (coordinateSystem == "Viewport")
1054         options |= SnapshotOptionsInViewCoordinates;
1055
1056     IntRect rectangle(x, y, width, height);
1057     std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(frame, rectangle, options);
1058
1059     if (!snapshot) {
1060         errorString = ASCIILiteral("Could not capture snapshot");
1061         return;
1062     }
1063
1064     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1065 }
1066
1067 void InspectorPageAgent::handleJavaScriptDialog(ErrorString& errorString, bool accept, const String* promptText)
1068 {
1069     if (!m_client->handleJavaScriptDialog(accept, promptText))
1070         errorString = ASCIILiteral("Could not handle JavaScript dialog");
1071 }
1072
1073 void InspectorPageAgent::archive(ErrorString& errorString, String* data)
1074 {
1075 #if ENABLE(WEB_ARCHIVE) && USE(CF)
1076     Frame& frame = mainFrame();
1077     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
1078     if (!archive) {
1079         errorString = ASCIILiteral("Could not create web archive for main frame");
1080         return;
1081     }
1082
1083     RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
1084     *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
1085 #else
1086     UNUSED_PARAM(data);
1087     errorString = ASCIILiteral("No support for creating archives");
1088 #endif
1089 }
1090
1091 } // namespace WebCore