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