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