f9b2b213fa40efb5e4b37d71e93e8536f129f663
[WebKit-https.git] / Source / WebCore / inspector / InspectorPageAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "InspectorPageAgent.h"
33
34 #if ENABLE(INSPECTOR)
35
36 #include "CachedCSSStyleSheet.h"
37 #include "CachedFont.h"
38 #include "CachedImage.h"
39 #include "CachedResource.h"
40 #include "CachedResourceLoader.h"
41 #include "CachedScript.h"
42 #include "Cookie.h"
43 #include "CookieJar.h"
44 #include "DOMImplementation.h"
45 #include "DOMPatchSupport.h"
46 #include "DOMWrapperWorld.h"
47 #include "Document.h"
48 #include "DocumentLoader.h"
49 #include "Frame.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 "InspectorInstrumentation.h"
59 #include "InspectorOverlay.h"
60 #include "InspectorTimelineAgent.h"
61 #include "InstrumentingAgents.h"
62 #include "MainFrame.h"
63 #include "MemoryCache.h"
64 #include "Page.h"
65 #include "ScriptController.h"
66 #include "SecurityOrigin.h"
67 #include "Settings.h"
68 #include "TextEncoding.h"
69 #include "TextResourceDecoder.h"
70 #include "UserGestureIndicator.h"
71 #include <bindings/ScriptValue.h>
72 #include <inspector/ContentSearchUtilities.h>
73 #include <inspector/IdentifiersFactory.h>
74 #include <inspector/InspectorValues.h>
75 #include <wtf/ListHashSet.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 PassRefPtr<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             *result = downcast<CachedCSSStyleSheet>(*cachedResource).sheetText(false);
161             return true;
162         case CachedResource::Script:
163             *result = downcast<CachedScript>(*cachedResource).script();
164             return true;
165         case CachedResource::RawResource: {
166             auto* buffer = cachedResource->resourceBuffer();
167             if (!buffer)
168                 return false;
169             RefPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
170             // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
171             if (!decoder)
172                 return false;
173             *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
174             return true;
175         }
176         default:
177             auto* buffer = cachedResource->resourceBuffer();
178             return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
179         }
180     }
181     return false;
182 }
183
184 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
185 {
186     RefPtr<SharedBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
187     if (!buffer)
188         return false;
189     return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), frame->document()->inputEncoding(), withBase64Encode, result);
190 }
191
192 // static
193 bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result)
194 {
195     return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
196 }
197
198 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
199 {
200     if (withBase64Encode) {
201         *result = base64Encode(data, size);
202         return true;
203     }
204
205     return decodeBuffer(data, size, textEncodingName, result);
206 }
207
208 // static
209 void InspectorPageAgent::resourceContent(ErrorString& errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
210 {
211     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
212     if (!loader)
213         return;
214
215     RefPtr<SharedBuffer> buffer;
216     bool success = false;
217     if (equalIgnoringFragmentIdentifier(url, loader->url())) {
218         *base64Encoded = false;
219         success = mainResourceContent(frame, *base64Encoded, result);
220     }
221
222     if (!success)
223         success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
224
225     if (!success)
226         errorString = ASCIILiteral("No resource with given URL found");
227 }
228
229 //static
230 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
231 {
232     DEPRECATED_DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeader, (ASCIILiteral("SourceMap")));
233     DEPRECATED_DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeaderDeprecated, (ASCIILiteral("X-SourceMap")));
234
235     if (!cachedResource)
236         return String();
237
238     // Scripts are handled in a separate path.
239     if (cachedResource->type() != CachedResource::CSSStyleSheet)
240         return String();
241
242     String sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeader);
243     if (!sourceMapHeader.isEmpty())
244         return sourceMapHeader;
245
246     sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
247     if (!sourceMapHeader.isEmpty())
248         return sourceMapHeader;
249
250     String content;
251     bool base64Encoded;
252     if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
253         return ContentSearchUtilities::findStylesheetSourceMapURL(content);
254
255     return String();
256 }
257
258 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
259 {
260     CachedResource* cachedResource = frame->document()->cachedResourceLoader()->cachedResource(url);
261     if (!cachedResource) {
262         ResourceRequest request(url);
263 #if ENABLE(CACHE_PARTITIONING)
264         request.setDomainForCachePartition(frame->document()->topOrigin()->domainForCachePartition());
265 #endif
266         cachedResource = memoryCache()->resourceForRequest(request, frame->page()->sessionID());
267     }
268
269     return cachedResource;
270 }
271
272 Inspector::Protocol::Page::ResourceType InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
273 {
274     switch (resourceType) {
275     case DocumentResource:
276         return Inspector::Protocol::Page::ResourceType::Document;
277     case ImageResource:
278         return Inspector::Protocol::Page::ResourceType::Image;
279     case FontResource:
280         return Inspector::Protocol::Page::ResourceType::Font;
281     case StylesheetResource:
282         return Inspector::Protocol::Page::ResourceType::Stylesheet;
283     case ScriptResource:
284         return Inspector::Protocol::Page::ResourceType::Script;
285     case XHRResource:
286         return Inspector::Protocol::Page::ResourceType::XHR;
287     case WebSocketResource:
288         return Inspector::Protocol::Page::ResourceType::WebSocket;
289     case OtherResource:
290         return Inspector::Protocol::Page::ResourceType::Other;
291     }
292     return Inspector::Protocol::Page::ResourceType::Other;
293 }
294
295 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
296 {
297     switch (cachedResource.type()) {
298     case CachedResource::ImageResource:
299         return InspectorPageAgent::ImageResource;
300     case CachedResource::FontResource:
301         return InspectorPageAgent::FontResource;
302     case CachedResource::CSSStyleSheet:
303         // Fall through.
304 #if ENABLE(XSLT)
305     case CachedResource::XSLStyleSheet:
306 #endif
307         return InspectorPageAgent::StylesheetResource;
308     case CachedResource::Script:
309         return InspectorPageAgent::ScriptResource;
310     case CachedResource::RawResource:
311         return InspectorPageAgent::XHRResource;
312     case CachedResource::MainResource:
313         return InspectorPageAgent::DocumentResource;
314     default:
315         break;
316     }
317     return InspectorPageAgent::OtherResource;
318 }
319
320 Inspector::Protocol::Page::ResourceType InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
321 {
322     return resourceTypeJson(cachedResourceType(cachedResource));
323 }
324
325 InspectorPageAgent::InspectorPageAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorClient* client, InspectorOverlay* overlay)
326     : InspectorAgentBase(ASCIILiteral("Page"), instrumentingAgents)
327     , m_page(page)
328     , m_client(client)
329     , m_overlay(overlay)
330     , m_lastScriptIdentifier(0)
331     , m_enabled(false)
332     , m_isFirstLayoutAfterOnLoad(false)
333     , m_originalScriptExecutionDisabled(false)
334     , m_ignoreScriptsEnabledNotification(false)
335     , m_showPaintRects(false)
336 {
337 }
338
339 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
340 {
341     m_frontendDispatcher = std::make_unique<InspectorPageFrontendDispatcher>(frontendChannel);
342     m_backendDispatcher = InspectorPageBackendDispatcher::create(backendDispatcher, this);
343 }
344
345 void InspectorPageAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
346 {
347     m_frontendDispatcher = nullptr;
348     m_backendDispatcher.clear();
349
350     ErrorString unused;
351     disable(unused);
352 #if ENABLE(TOUCH_EVENTS)
353     updateTouchEventEmulationInPage(false);
354 #endif
355 }
356
357 double InspectorPageAgent::timestamp()
358 {
359     return m_instrumentingAgents->inspectorEnvironment().executionStopwatch()->elapsedTime();
360 }
361
362 void InspectorPageAgent::enable(ErrorString&)
363 {
364     m_enabled = true;
365     m_instrumentingAgents->setInspectorPageAgent(this);
366
367     if (Frame* frame = mainFrame())
368         m_originalScriptExecutionDisabled = !frame->settings().isScriptEnabled();
369 }
370
371 void InspectorPageAgent::disable(ErrorString&)
372 {
373     m_enabled = false;
374     m_scriptsToEvaluateOnLoad.clear();
375     m_instrumentingAgents->setInspectorPageAgent(nullptr);
376
377     ErrorString unused;
378     setScriptExecutionDisabled(unused, m_originalScriptExecutionDisabled);
379     setShowPaintRects(unused, false);
380     setEmulatedMedia(unused, emptyString());
381 }
382
383 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString&, const String& source, String* identifier)
384 {
385     if (!m_scriptsToEvaluateOnLoad)
386         m_scriptsToEvaluateOnLoad = InspectorObject::create();
387
388     // Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual
389     // scripts once we restored the scripts from the cookie during navigation.
390     do {
391         *identifier = String::number(++m_lastScriptIdentifier);
392     } while (m_scriptsToEvaluateOnLoad->find(*identifier) != m_scriptsToEvaluateOnLoad->end());
393
394     m_scriptsToEvaluateOnLoad->setString(*identifier, source);
395 }
396
397 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString& error, const String& identifier)
398 {
399     if (!m_scriptsToEvaluateOnLoad || m_scriptsToEvaluateOnLoad->find(identifier) == m_scriptsToEvaluateOnLoad->end()) {
400         error = ASCIILiteral("Script not found");
401         return;
402     }
403
404     m_scriptsToEvaluateOnLoad->remove(identifier);
405 }
406
407 void InspectorPageAgent::reload(ErrorString&, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
408 {
409     m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
410     m_page->mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
411 }
412
413 void InspectorPageAgent::navigate(ErrorString&, const String& url)
414 {
415     UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
416     Frame& frame = m_page->mainFrame();
417     frame.loader().changeLocation(frame.document()->securityOrigin(), frame.document()->completeURL(url), "", LockHistory::No, LockBackForwardList::No);
418 }
419
420 static PassRefPtr<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
421 {
422     return Inspector::Protocol::Page::Cookie::create()
423         .setName(cookie.name)
424         .setValue(cookie.value)
425         .setDomain(cookie.domain)
426         .setPath(cookie.path)
427         .setExpires(cookie.expires)
428         .setSize((cookie.name.length() + cookie.value.length()))
429         .setHttpOnly(cookie.httpOnly)
430         .setSecure(cookie.secure)
431         .setSession(cookie.session)
432         .release();
433 }
434
435 static PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
436 {
437     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
438
439     for (auto& cookie : cookiesList)
440         cookies->addItem(buildObjectForCookie(cookie));
441
442     return cookies;
443 }
444
445 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
446 {
447     Vector<CachedResource*> result;
448
449     for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader()->allCachedResources().values()) {
450         auto* cachedResource = cachedResourceHandle.get();
451         if (cachedResource->resourceRequest().hiddenFromInspector())
452             continue;
453
454         switch (cachedResource->type()) {
455         case CachedResource::ImageResource:
456             // Skip images that were not auto loaded (images disabled in the user agent).
457         case CachedResource::FontResource:
458             // Skip fonts that were referenced in CSS but never used/downloaded.
459             if (cachedResource->stillNeedsLoad())
460                 continue;
461             break;
462         default:
463             // All other CachedResource types download immediately.
464             break;
465         }
466
467         result.append(cachedResource);
468     }
469
470     return result;
471 }
472
473 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
474 {
475     Vector<URL> result;
476
477     result.append(frame->loader().documentLoader()->url());
478
479     for (auto* cachedResource : cachedResourcesForFrame(frame))
480         result.append(cachedResource->url());
481
482     return result;
483 }
484
485 void InspectorPageAgent::getCookies(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>>& cookies)
486 {
487     // If we can get raw cookies.
488     ListHashSet<Cookie> rawCookiesList;
489
490     // If we can't get raw cookies - fall back to String representation
491     StringBuilder stringCookiesList;
492
493     // Return value to getRawCookies should be the same for every call because
494     // the return value is platform/network backend specific, and the call will
495     // always return the same true/false value.
496     bool rawCookiesImplemented = false;
497
498     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext(mainFrame())) {
499         Document* document = frame->document();
500
501         for (auto& url : allResourcesURLsForFrame(frame)) {
502             Vector<Cookie> docCookiesList;
503             rawCookiesImplemented = getRawCookies(document, URL(ParsedURLString, url), docCookiesList);
504
505             if (!rawCookiesImplemented) {
506                 // FIXME: We need duplication checking for the String representation of cookies.
507                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
508                 // because "document" is the document of the main frame of the page.
509                 stringCookiesList.append(document->cookie(ASSERT_NO_EXCEPTION));
510             } else {
511                 int cookiesSize = docCookiesList.size();
512                 for (int i = 0; i < cookiesSize; i++) {
513                     if (!rawCookiesList.contains(docCookiesList[i]))
514                         rawCookiesList.add(docCookiesList[i]);
515                 }
516             }
517         }
518     }
519
520     // FIXME: Do not return empty string/empty array. Make returns optional instead. https://bugs.webkit.org/show_bug.cgi?id=80855
521     if (rawCookiesImplemented)
522         cookies = buildArrayForCookies(rawCookiesList);
523     else
524         cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
525 }
526
527 void InspectorPageAgent::deleteCookie(ErrorString&, const String& cookieName, const String& url)
528 {
529     URL parsedURL(ParsedURLString, url);
530     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame()))
531         WebCore::deleteCookie(frame->document(), parsedURL, cookieName);
532 }
533
534 void InspectorPageAgent::getResourceTree(ErrorString&, RefPtr<Inspector::Protocol::Page::FrameResourceTree>& object)
535 {
536     object = buildObjectForFrameTree(&m_page->mainFrame());
537 }
538
539 void InspectorPageAgent::getResourceContent(ErrorString& errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
540 {
541     Frame* frame = assertFrame(errorString, frameId);
542     if (!frame)
543         return;
544
545     resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
546 }
547
548 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
549 {
550     if (hasTextContent(cachedResource)) {
551         String content;
552         bool base64Encoded;
553         if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
554             ASSERT(!base64Encoded);
555             return true;
556         }
557     }
558     return false;
559 }
560
561 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)
562 {
563     results = Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>::create();
564
565     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
566     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
567
568     Frame* frame = frameForId(frameId);
569     if (!frame)
570         return;
571
572     DocumentLoader* loader = frame->loader().documentLoader();
573     if (!loader)
574         return;
575
576     URL kurl(ParsedURLString, url);
577
578     String content;
579     bool success = false;
580     if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
581         success = mainResourceContent(frame, false, &content);
582
583     if (!success) {
584         CachedResource* resource = cachedResource(frame, kurl);
585         if (resource)
586             success = textContentForCachedResource(resource, &content);
587     }
588
589     if (!success)
590         return;
591
592     results = ContentSearchUtilities::searchInTextByLines(content, query, caseSensitive, isRegex);
593 }
594
595 static PassRefPtr<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
596 {
597     return Inspector::Protocol::Page::SearchResult::create()
598         .setUrl(url)
599         .setFrameId(frameId)
600         .setMatchesCount(matchesCount)
601         .release();
602 }
603
604 void InspectorPageAgent::searchInResources(ErrorString&, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>>& results)
605 {
606     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>> searchResults = Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>::create();
607
608     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
609     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
610     JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
611
612     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame())) {
613         String content;
614
615         for (auto* cachedResource : cachedResourcesForFrame(frame)) {
616             if (textContentForCachedResource(cachedResource, &content)) {
617                 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
618                 if (matchesCount)
619                     searchResults->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
620             }
621         }
622
623         if (mainResourceContent(frame, false, &content)) {
624             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
625             if (matchesCount)
626                 searchResults->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
627         }
628     }
629
630     results = searchResults;
631 }
632
633 void InspectorPageAgent::setDocumentContent(ErrorString& errorString, const String& frameId, const String& html)
634 {
635     Frame* frame = assertFrame(errorString, frameId);
636     if (!frame)
637         return;
638
639     Document* document = frame->document();
640     if (!document) {
641         errorString = ASCIILiteral("No Document instance to set HTML for");
642         return;
643     }
644     DOMPatchSupport::patchDocument(document, html);
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->setShowingPaintRects(show);
656 }
657
658 void InspectorPageAgent::getScriptExecutionStatus(ErrorString&, InspectorPageBackendDispatcherHandler::Result* status)
659 {
660     bool disabledByScriptController = false;
661     bool disabledInSettings = false;
662     Frame* frame = mainFrame();
663     if (frame) {
664         disabledByScriptController = !frame->script().canExecuteScripts(NotAboutToExecuteScript);
665         disabledInSettings = !frame->settings().isScriptEnabled();
666     }
667
668     if (!disabledByScriptController) {
669         *status = InspectorPageBackendDispatcherHandler::Result::Allowed;
670         return;
671     }
672
673     if (disabledInSettings)
674         *status = InspectorPageBackendDispatcherHandler::Result::Disabled;
675     else
676         *status = InspectorPageBackendDispatcherHandler::Result::Forbidden;
677 }
678
679 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString&, bool value)
680 {
681     if (!mainFrame())
682         return;
683
684     m_ignoreScriptsEnabledNotification = true;
685     mainFrame()->settings().setScriptEnabled(!value);
686     m_ignoreScriptsEnabledNotification = false;
687 }
688
689 void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld& world)
690 {
691     if (&world != &mainThreadNormalWorld())
692         return;
693
694     if (!m_frontendDispatcher)
695         return;
696
697     if (m_scriptsToEvaluateOnLoad) {
698         for (auto& keyValuePair : *m_scriptsToEvaluateOnLoad) {
699             String scriptText;
700             if (keyValuePair.value->asString(scriptText))
701                 frame->script().executeScript(scriptText);
702         }
703     }
704
705     if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
706         frame->script().executeScript(m_scriptToEvaluateOnLoadOnce);
707 }
708
709 void InspectorPageAgent::domContentEventFired()
710 {
711     m_isFirstLayoutAfterOnLoad = true;
712     m_frontendDispatcher->domContentEventFired(timestamp());
713 }
714
715 void InspectorPageAgent::loadEventFired()
716 {
717     m_frontendDispatcher->loadEventFired(timestamp());
718 }
719
720 void InspectorPageAgent::frameNavigated(DocumentLoader* loader)
721 {
722     if (loader->frame()->isMainFrame()) {
723         m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
724         m_pendingScriptToEvaluateOnLoadOnce = String();
725     }
726     m_frontendDispatcher->frameNavigated(buildObjectForFrame(loader->frame()));
727 }
728
729 void InspectorPageAgent::frameDetached(Frame* frame)
730 {
731     HashMap<Frame*, String>::iterator iterator = m_frameToIdentifier.find(frame);
732     if (iterator != m_frameToIdentifier.end()) {
733         m_frontendDispatcher->frameDetached(iterator->value);
734         m_identifierToFrame.remove(iterator->value);
735         m_frameToIdentifier.remove(iterator);
736     }
737 }
738
739 Frame* InspectorPageAgent::mainFrame()
740 {
741     // FIXME: This should return a Frame&
742     return &m_page->mainFrame();
743 }
744
745 Frame* InspectorPageAgent::frameForId(const String& frameId)
746 {
747     return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
748 }
749
750 String InspectorPageAgent::frameId(Frame* frame)
751 {
752     if (!frame)
753         return "";
754     String identifier = m_frameToIdentifier.get(frame);
755     if (identifier.isNull()) {
756         identifier = IdentifiersFactory::createIdentifier();
757         m_frameToIdentifier.set(frame, identifier);
758         m_identifierToFrame.set(identifier, frame);
759     }
760     return identifier;
761 }
762
763 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
764 {
765     return frame && m_frameToIdentifier.contains(frame);
766 }
767
768 String InspectorPageAgent::loaderId(DocumentLoader* loader)
769 {
770     if (!loader)
771         return "";
772     String identifier = m_loaderToIdentifier.get(loader);
773     if (identifier.isNull()) {
774         identifier = IdentifiersFactory::createIdentifier();
775         m_loaderToIdentifier.set(loader, identifier);
776     }
777     return identifier;
778 }
779
780 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
781 {
782     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
783         RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
784         if (documentOrigin->toRawString() == originRawString)
785             return frame;
786     }
787     return nullptr;
788 }
789
790 Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId)
791 {
792     Frame* frame = frameForId(frameId);
793     if (!frame)
794         errorString = ASCIILiteral("No frame for given id found");
795     return frame;
796 }
797
798 // static
799 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString& errorString, Frame* frame)
800 {
801     FrameLoader& frameLoader = frame->loader();
802     DocumentLoader* documentLoader = frameLoader.documentLoader();
803     if (!documentLoader)
804         errorString = ASCIILiteral("No documentLoader for given frame found");
805     return documentLoader;
806 }
807
808 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader)
809 {
810     m_loaderToIdentifier.remove(loader);
811 }
812
813 void InspectorPageAgent::frameStartedLoading(Frame& frame)
814 {
815     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
816 }
817
818 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
819 {
820     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
821 }
822
823 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, double delay)
824 {
825     m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay);
826 }
827
828 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
829 {
830     m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
831 }
832
833 void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
834 {
835     m_frontendDispatcher->javascriptDialogOpening(message);
836 }
837
838 void InspectorPageAgent::didRunJavaScriptDialog()
839 {
840     m_frontendDispatcher->javascriptDialogClosed();
841 }
842
843 void InspectorPageAgent::didPaint(RenderObject* renderer, const LayoutRect& rect)
844 {
845     if (!m_enabled || !m_showPaintRects)
846         return;
847
848     LayoutRect absoluteRect = LayoutRect(renderer->localToAbsoluteQuad(FloatRect(rect)).boundingBox());
849     FrameView* view = renderer->document().view();
850     
851     LayoutRect rootRect = absoluteRect;
852     if (!view->frame().isMainFrame()) {
853         IntRect rootViewRect = view->contentsToRootView(snappedIntRect(absoluteRect));
854         rootRect = view->frame().mainFrame().view()->rootViewToContents(rootViewRect);
855     }
856     
857     if (m_client->overridesShowPaintRects()) {
858         m_client->showPaintRect(rootRect);
859         return;
860     }
861
862     m_overlay->showPaintRect(rootRect);
863 }
864
865 void InspectorPageAgent::didLayout()
866 {
867     bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
868     if (isFirstLayout)
869         m_isFirstLayoutAfterOnLoad = false;
870
871     if (!m_enabled)
872         return;
873
874     m_overlay->update();
875 }
876
877 void InspectorPageAgent::didScroll()
878 {
879     if (m_enabled)
880         m_overlay->update();
881 }
882
883 void InspectorPageAgent::didRecalculateStyle()
884 {
885     if (m_enabled)
886         m_overlay->update();
887 }
888
889 void InspectorPageAgent::scriptsEnabled(bool isEnabled)
890 {
891     if (m_ignoreScriptsEnabledNotification)
892         return;
893
894     m_frontendDispatcher->scriptsEnabled(isEnabled);
895 }
896
897 PassRefPtr<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
898 {
899     RefPtr<Inspector::Protocol::Page::Frame> frameObject = Inspector::Protocol::Page::Frame::create()
900         .setId(frameId(frame))
901         .setLoaderId(loaderId(frame->loader().documentLoader()))
902         .setUrl(frame->document()->url().string())
903         .setMimeType(frame->loader().documentLoader()->responseMIMEType())
904         .setSecurityOrigin(frame->document()->securityOrigin()->toRawString());
905     if (frame->tree().parent())
906         frameObject->setParentId(frameId(frame->tree().parent()));
907     if (frame->ownerElement()) {
908         String name = frame->ownerElement()->getNameAttribute();
909         if (name.isEmpty())
910             name = frame->ownerElement()->getAttribute(HTMLNames::idAttr);
911         frameObject->setName(name);
912     }
913
914     return frameObject;
915 }
916
917 PassRefPtr<Inspector::Protocol::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
918 {
919     RefPtr<Inspector::Protocol::Page::Frame> frameObject = buildObjectForFrame(frame);
920     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResource>> subresources = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResource>::create();
921     RefPtr<Inspector::Protocol::Page::FrameResourceTree> result = Inspector::Protocol::Page::FrameResourceTree::create()
922          .setFrame(frameObject)
923          .setResources(subresources);
924
925     for (auto* cachedResource : cachedResourcesForFrame(frame)) {
926         RefPtr<Inspector::Protocol::Page::FrameResource> resourceObject = Inspector::Protocol::Page::FrameResource::create()
927             .setUrl(cachedResource->url())
928             .setType(cachedResourceTypeJson(*cachedResource))
929             .setMimeType(cachedResource->response().mimeType());
930         if (cachedResource->wasCanceled())
931             resourceObject->setCanceled(true);
932         else if (cachedResource->status() == CachedResource::LoadError)
933             resourceObject->setFailed(true);
934         String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
935         if (!sourceMappingURL.isEmpty())
936             resourceObject->setSourceMapURL(sourceMappingURL);
937         subresources->addItem(resourceObject);
938     }
939
940     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>> childrenArray;
941     for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
942         if (!childrenArray) {
943             childrenArray = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>::create();
944             result->setChildFrames(childrenArray);
945         }
946         childrenArray->addItem(buildObjectForFrameTree(child));
947     }
948     return result;
949 }
950
951 #if ENABLE(TOUCH_EVENTS)
952 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
953 {
954     if (mainFrame())
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     ASSERT(frame);
1004
1005     InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
1006     ASSERT(domAgent);
1007     Node* node = domAgent->assertNode(errorString, nodeId);
1008     if (!node)
1009         return;
1010
1011     std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(*frame, *node);
1012     if (!snapshot) {
1013         errorString = ASCIILiteral("Could not capture snapshot");
1014         return;
1015     }
1016
1017     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1018 }
1019
1020 void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
1021 {
1022     Frame* frame = mainFrame();
1023     ASSERT(frame);
1024
1025     SnapshotOptions options = SnapshotOptionsNone;
1026     if (coordinateSystem == "Viewport")
1027         options |= SnapshotOptionsInViewCoordinates;
1028
1029     IntRect rectangle(x, y, width, height);
1030     std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(*frame, rectangle, options);
1031
1032     if (!snapshot) {
1033         errorString = ASCIILiteral("Could not capture snapshot");
1034         return;
1035     }
1036
1037     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1038 }
1039
1040 void InspectorPageAgent::handleJavaScriptDialog(ErrorString& errorString, bool accept, const String* promptText)
1041 {
1042     if (!m_client->handleJavaScriptDialog(accept, promptText))
1043         errorString = ASCIILiteral("Could not handle JavaScript dialog");
1044 }
1045
1046 void InspectorPageAgent::archive(ErrorString& errorString, String* data)
1047 {
1048     Frame* frame = mainFrame();
1049     if (!frame) {
1050         errorString = ASCIILiteral("No main frame");
1051         return;
1052     }
1053
1054 #if ENABLE(WEB_ARCHIVE) && USE(CF)
1055     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
1056     if (!archive) {
1057         errorString = ASCIILiteral("Could not create web archive for main frame");
1058         return;
1059     }
1060
1061     RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
1062     *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
1063 #else
1064     UNUSED_PARAM(data);
1065     errorString = ASCIILiteral("No support for creating archives");
1066 #endif
1067 }
1068
1069 } // namespace WebCore
1070
1071 #endif // ENABLE(INSPECTOR)