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