Web Inspector: Include Beacon and Ping requests in Network tab
[WebKit-https.git] / Source / WebCore / inspector / InspectorPageAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2015-2017 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 "Document.h"
44 #include "DocumentLoader.h"
45 #include "Frame.h"
46 #include "FrameLoadRequest.h"
47 #include "FrameLoader.h"
48 #include "FrameSnapshotting.h"
49 #include "FrameView.h"
50 #include "HTMLFrameOwnerElement.h"
51 #include "HTMLNames.h"
52 #include "ImageBuffer.h"
53 #include "InspectorClient.h"
54 #include "InspectorDOMAgent.h"
55 #include "InspectorNetworkAgent.h"
56 #include "InspectorOverlay.h"
57 #include "InstrumentingAgents.h"
58 #include "MIMETypeRegistry.h"
59 #include "MainFrame.h"
60 #include "MemoryCache.h"
61 #include "Page.h"
62 #include "RenderObject.h"
63 #include "ScriptController.h"
64 #include "SecurityOrigin.h"
65 #include "Settings.h"
66 #include "StyleScope.h"
67 #include "TextEncoding.h"
68 #include "TextResourceDecoder.h"
69 #include "UserGestureIndicator.h"
70 #include <inspector/ContentSearchUtilities.h>
71 #include <inspector/IdentifiersFactory.h>
72 #include <inspector/InspectorValues.h>
73 #include <wtf/ListHashSet.h>
74 #include <wtf/Stopwatch.h>
75 #include <wtf/text/Base64.h>
76 #include <wtf/text/StringBuilder.h>
77 #include <yarr/RegularExpression.h>
78
79 #if ENABLE(WEB_ARCHIVE) && USE(CF)
80 #include "LegacyWebArchive.h"
81 #endif
82
83 using namespace Inspector;
84
85 namespace WebCore {
86
87 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
88 {
89     if (buffer) {
90         TextEncoding encoding(textEncodingName);
91         if (!encoding.isValid())
92             encoding = WindowsLatin1Encoding();
93         *result = encoding.decode(buffer, size);
94         return true;
95     }
96     return false;
97 }
98
99 static bool hasTextContent(CachedResource* cachedResource)
100 {
101     // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
102     // We should not assume XHR / Fetch have text content.
103
104     InspectorPageAgent::ResourceType type = InspectorPageAgent::inspectorResourceType(*cachedResource);
105     return type == InspectorPageAgent::DocumentResource
106         || type == InspectorPageAgent::StylesheetResource
107         || type == InspectorPageAgent::ScriptResource
108         || type == InspectorPageAgent::XHRResource
109         || type == InspectorPageAgent::FetchResource;
110 }
111
112 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
113 {
114     if (!cachedResource)
115         return false;
116
117     *base64Encoded = !hasTextContent(cachedResource);
118
119     if (!cachedResource->encodedSize()) {
120         *result = emptyString();
121         return true;
122     }
123
124     if (*base64Encoded) {
125         if (auto* buffer = cachedResource->resourceBuffer()) {
126             *result = base64Encode(buffer->data(), buffer->size());
127             return true;
128         }
129         return false;
130     }
131
132     if (cachedResource) {
133         switch (cachedResource->type()) {
134         case CachedResource::CSSStyleSheet:
135             // This can return a null String if the MIME type is invalid.
136             *result = downcast<CachedCSSStyleSheet>(*cachedResource).sheetText();
137             return !result->isNull();
138         case CachedResource::Script:
139             *result = downcast<CachedScript>(*cachedResource).script().toString();
140             return true;
141         case CachedResource::MediaResource:
142         case CachedResource::Icon:
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(MAKE_STATIC_STRING_IMPL("SourceMap"));
209     static NeverDestroyed<String> sourceMapHTTPHeaderDeprecated(MAKE_STATIC_STRING_IMPL("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 PingResource:
267         return Inspector::Protocol::Page::ResourceType::Ping;
268     case BeaconResource:
269         return Inspector::Protocol::Page::ResourceType::Beacon;
270     case WebSocketResource:
271         return Inspector::Protocol::Page::ResourceType::WebSocket;
272     case OtherResource:
273         return Inspector::Protocol::Page::ResourceType::Other;
274     }
275     return Inspector::Protocol::Page::ResourceType::Other;
276 }
277
278 InspectorPageAgent::ResourceType InspectorPageAgent::inspectorResourceType(CachedResource::Type type)
279 {
280     switch (type) {
281     case CachedResource::ImageResource:
282         return InspectorPageAgent::ImageResource;
283 #if ENABLE(SVG_FONTS)
284     case CachedResource::SVGFontResource:
285 #endif
286     case CachedResource::FontResource:
287         return InspectorPageAgent::FontResource;
288 #if ENABLE(XSLT)
289     case CachedResource::XSLStyleSheet:
290 #endif
291     case CachedResource::CSSStyleSheet:
292         return InspectorPageAgent::StylesheetResource;
293     case CachedResource::Script:
294         return InspectorPageAgent::ScriptResource;
295     case CachedResource::MainResource:
296         return InspectorPageAgent::DocumentResource;
297     case CachedResource::Beacon:
298         return InspectorPageAgent::BeaconResource;
299     case CachedResource::MediaResource:
300     case CachedResource::Icon:
301     case CachedResource::RawResource:
302     default:
303         return InspectorPageAgent::OtherResource;
304     }
305 }
306
307 InspectorPageAgent::ResourceType InspectorPageAgent::inspectorResourceType(const CachedResource& cachedResource)
308 {
309     if (cachedResource.type() == CachedResource::RawResource) {
310         switch (cachedResource.resourceRequest().requester()) {
311         case ResourceRequest::Requester::Fetch:
312             return InspectorPageAgent::FetchResource;
313         case ResourceRequest::Requester::Main:
314             return InspectorPageAgent::DocumentResource;
315         default:
316             return InspectorPageAgent::XHRResource;
317         }
318     }
319
320     return inspectorResourceType(cachedResource.type());
321 }
322
323 Inspector::Protocol::Page::ResourceType InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
324 {
325     return resourceTypeJson(inspectorResourceType(cachedResource));
326 }
327
328 RefPtr<TextResourceDecoder> InspectorPageAgent::createTextDecoder(const String& mimeType, const String& textEncodingName)
329 {
330     if (!textEncodingName.isEmpty())
331         return TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncodingName);
332
333     if (MIMETypeRegistry::isTextMIMEType(mimeType))
334         return TextResourceDecoder::create(mimeType, "UTF-8");
335
336     if (MIMETypeRegistry::isXMLMIMEType(mimeType)) {
337         RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(ASCIILiteral("application/xml"));
338         decoder->useLenientXMLDecoding();
339         return decoder;
340     }
341
342     return TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8");
343 }
344
345 InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClient* client, InspectorOverlay* overlay)
346     : InspectorAgentBase(ASCIILiteral("Page"), context)
347     , m_frontendDispatcher(std::make_unique<Inspector::PageFrontendDispatcher>(context.frontendRouter))
348     , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this))
349     , m_page(context.inspectedPage)
350     , m_client(client)
351     , m_overlay(overlay)
352 {
353 }
354
355 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
356 {
357 }
358
359 void InspectorPageAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
360 {
361     ErrorString unused;
362     disable(unused);
363 }
364
365 double InspectorPageAgent::timestamp()
366 {
367     return m_environment.executionStopwatch()->elapsedTime();
368 }
369
370 void InspectorPageAgent::enable(ErrorString&)
371 {
372     m_enabled = true;
373     m_instrumentingAgents.setInspectorPageAgent(this);
374
375     auto stopwatch = m_environment.executionStopwatch();
376     stopwatch->reset();
377     stopwatch->start();
378 }
379
380 void InspectorPageAgent::disable(ErrorString&)
381 {
382     m_enabled = false;
383     m_instrumentingAgents.setInspectorPageAgent(nullptr);
384
385     ErrorString unused;
386     setShowPaintRects(unused, false);
387     setEmulatedMedia(unused, emptyString());
388 }
389
390 void InspectorPageAgent::reload(ErrorString&, const bool* const optionalReloadFromOrigin, const bool* const optionalRevalidateAllResources)
391 {
392     bool reloadFromOrigin = optionalReloadFromOrigin && *optionalReloadFromOrigin;
393     bool revalidateAllResources = optionalRevalidateAllResources && *optionalRevalidateAllResources;
394
395     OptionSet<ReloadOption> reloadOptions;
396     if (reloadFromOrigin)
397         reloadOptions |= ReloadOption::FromOrigin;
398     if (!revalidateAllResources)
399         reloadOptions |= ReloadOption::ExpiredOnly;
400
401     m_page.mainFrame().loader().reload(reloadOptions);
402 }
403
404 void InspectorPageAgent::navigate(ErrorString&, const String& url)
405 {
406     UserGestureIndicator indicator { ProcessingUserGesture };
407     Frame& frame = m_page.mainFrame();
408
409     ResourceRequest resourceRequest { frame.document()->completeURL(url) };
410     FrameLoadRequest frameLoadRequest { *frame.document(), frame.document()->securityOrigin(), resourceRequest, ASCIILiteral("_self"), LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown };
411     frame.loader().changeLocation(WTFMove(frameLoadRequest));
412 }
413
414 static Ref<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
415 {
416     return Inspector::Protocol::Page::Cookie::create()
417         .setName(cookie.name)
418         .setValue(cookie.value)
419         .setDomain(cookie.domain)
420         .setPath(cookie.path)
421         .setExpires(cookie.expires)
422         .setSize((cookie.name.length() + cookie.value.length()))
423         .setHttpOnly(cookie.httpOnly)
424         .setSecure(cookie.secure)
425         .setSession(cookie.session)
426         .release();
427 }
428
429 static Ref<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
430 {
431     auto cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
432
433     for (const auto& cookie : cookiesList)
434         cookies->addItem(buildObjectForCookie(cookie));
435
436     return cookies;
437 }
438
439 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
440 {
441     Vector<CachedResource*> result;
442
443     for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader().allCachedResources().values()) {
444         auto* cachedResource = cachedResourceHandle.get();
445         if (cachedResource->resourceRequest().hiddenFromInspector())
446             continue;
447
448         switch (cachedResource->type()) {
449         case CachedResource::ImageResource:
450             // Skip images that were not auto loaded (images disabled in the user agent).
451 #if ENABLE(SVG_FONTS)
452         case CachedResource::SVGFontResource:
453 #endif
454         case CachedResource::FontResource:
455             // Skip fonts that were referenced in CSS but never used/downloaded.
456             if (cachedResource->stillNeedsLoad())
457                 continue;
458             break;
459         default:
460             // All other CachedResource types download immediately.
461             break;
462         }
463
464         result.append(cachedResource);
465     }
466
467     return result;
468 }
469
470 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
471 {
472     Vector<URL> result;
473
474     result.append(frame->loader().documentLoader()->url());
475
476     for (auto* cachedResource : cachedResourcesForFrame(frame))
477         result.append(cachedResource->url());
478
479     return result;
480 }
481
482 void InspectorPageAgent::getCookies(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>>& cookies)
483 {
484     // If we can get raw cookies.
485     ListHashSet<Cookie> rawCookiesList;
486
487     // If we can't get raw cookies - fall back to String representation
488     StringBuilder stringCookiesList;
489
490     // Return value to getRawCookies should be the same for every call because
491     // the return value is platform/network backend specific, and the call will
492     // always return the same true/false value.
493     bool rawCookiesImplemented = false;
494
495     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
496         Document* document = frame->document();
497         if (!document)
498             continue;
499
500         for (auto& url : allResourcesURLsForFrame(frame)) {
501             Vector<Cookie> docCookiesList;
502             rawCookiesImplemented = getRawCookies(*document, URL(ParsedURLString, url), docCookiesList);
503
504             if (!rawCookiesImplemented) {
505                 // FIXME: We need duplication checking for the String representation of cookies.
506                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
507                 // because "document" is the document of the main frame of the page.
508                 stringCookiesList.append(document->cookie().releaseReturnValue());
509             } else {
510                 for (auto& cookie : docCookiesList) {
511                     if (!rawCookiesList.contains(cookie))
512                         rawCookiesList.add(cookie);
513                 }
514             }
515         }
516     }
517
518     // FIXME: Do not return empty string/empty array. Make returns optional instead. https://bugs.webkit.org/show_bug.cgi?id=80855
519     if (rawCookiesImplemented)
520         cookies = buildArrayForCookies(rawCookiesList);
521     else
522         cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
523 }
524
525 void InspectorPageAgent::deleteCookie(ErrorString&, const String& cookieName, const String& url)
526 {
527     URL parsedURL(ParsedURLString, url);
528     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
529         if (auto* document = frame->document())
530             WebCore::deleteCookie(*document, parsedURL, cookieName);
531     }
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         bool base64Encoded;
552         if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
553             ASSERT(!base64Encoded);
554             return true;
555         }
556     }
557     return false;
558 }
559
560 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)
561 {
562     results = Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>::create();
563
564     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
565     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
566
567     if (optionalRequestId) {
568         if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent()) {
569             networkAgent->searchInRequest(errorString, *optionalRequestId, query, caseSensitive, isRegex, results);
570             return;
571         }
572     }
573
574     Frame* frame = assertFrame(errorString, frameId);
575     if (!frame)
576         return;
577
578     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
579     if (!loader)
580         return;
581
582     URL kurl(ParsedURLString, url);
583
584     String content;
585     bool success = false;
586     if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
587         success = mainResourceContent(frame, false, &content);
588
589     if (!success) {
590         CachedResource* resource = cachedResource(frame, kurl);
591         if (resource)
592             success = textContentForCachedResource(resource, &content);
593     }
594
595     if (!success)
596         return;
597
598     results = ContentSearchUtilities::searchInTextByLines(content, query, caseSensitive, isRegex);
599 }
600
601 static Ref<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
602 {
603     return Inspector::Protocol::Page::SearchResult::create()
604         .setUrl(url)
605         .setFrameId(frameId)
606         .setMatchesCount(matchesCount)
607         .release();
608 }
609
610 void InspectorPageAgent::searchInResources(ErrorString&, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>>& result)
611 {
612     result = Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>::create();
613
614     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
615     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
616     JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
617
618     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
619         String content;
620
621         for (auto* cachedResource : cachedResourcesForFrame(frame)) {
622             if (textContentForCachedResource(cachedResource, &content)) {
623                 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
624                 if (matchesCount)
625                     result->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
626             }
627         }
628
629         if (mainResourceContent(frame, false, &content)) {
630             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
631             if (matchesCount)
632                 result->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
633         }
634     }
635
636     if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent())
637         networkAgent->searchOtherRequests(regex, result);
638 }
639
640 void InspectorPageAgent::setShowPaintRects(ErrorString&, bool show)
641 {
642     m_showPaintRects = show;
643     m_client->setShowPaintRects(show);
644
645     if (m_client->overridesShowPaintRects())
646         return;
647
648     m_overlay->setShowingPaintRects(show);
649 }
650
651 void InspectorPageAgent::domContentEventFired()
652 {
653     m_isFirstLayoutAfterOnLoad = true;
654     m_frontendDispatcher->domContentEventFired(timestamp());
655 }
656
657 void InspectorPageAgent::loadEventFired()
658 {
659     m_frontendDispatcher->loadEventFired(timestamp());
660 }
661
662 void InspectorPageAgent::frameNavigated(Frame& frame)
663 {
664     m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame));
665 }
666
667 void InspectorPageAgent::frameDetached(Frame& frame)
668 {
669     HashMap<Frame*, String>::iterator iterator = m_frameToIdentifier.find(&frame);
670     if (iterator != m_frameToIdentifier.end()) {
671         m_frontendDispatcher->frameDetached(iterator->value);
672         m_identifierToFrame.remove(iterator->value);
673         m_frameToIdentifier.remove(iterator);
674     }
675 }
676
677 MainFrame& InspectorPageAgent::mainFrame()
678 {
679     return m_page.mainFrame();
680 }
681
682 Frame* InspectorPageAgent::frameForId(const String& frameId)
683 {
684     return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
685 }
686
687 String InspectorPageAgent::frameId(Frame* frame)
688 {
689     if (!frame)
690         return emptyString();
691     String identifier = m_frameToIdentifier.get(frame);
692     if (identifier.isNull()) {
693         identifier = IdentifiersFactory::createIdentifier();
694         m_frameToIdentifier.set(frame, identifier);
695         m_identifierToFrame.set(identifier, frame);
696     }
697     return identifier;
698 }
699
700 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
701 {
702     return frame && m_frameToIdentifier.contains(frame);
703 }
704
705 String InspectorPageAgent::loaderId(DocumentLoader* loader)
706 {
707     if (!loader)
708         return emptyString();
709     String identifier = m_loaderToIdentifier.get(loader);
710     if (identifier.isNull()) {
711         identifier = IdentifiersFactory::createIdentifier();
712         m_loaderToIdentifier.set(loader, identifier);
713     }
714     return identifier;
715 }
716
717 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
718 {
719     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
720         Ref<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
721         if (documentOrigin->toRawString() == originRawString)
722             return frame;
723     }
724     return nullptr;
725 }
726
727 Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId)
728 {
729     Frame* frame = frameForId(frameId);
730     if (!frame)
731         errorString = ASCIILiteral("No frame for given id found");
732     return frame;
733 }
734
735 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString& errorString, Frame* frame)
736 {
737     FrameLoader& frameLoader = frame->loader();
738     DocumentLoader* documentLoader = frameLoader.documentLoader();
739     if (!documentLoader)
740         errorString = ASCIILiteral("No documentLoader for given frame found");
741     return documentLoader;
742 }
743
744 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader)
745 {
746     m_loaderToIdentifier.remove(&loader);
747 }
748
749 void InspectorPageAgent::frameStartedLoading(Frame& frame)
750 {
751     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
752 }
753
754 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
755 {
756     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
757 }
758
759 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay)
760 {
761     m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value());
762 }
763
764 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
765 {
766     m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
767 }
768
769 void InspectorPageAgent::didPaint(RenderObject& renderer, const LayoutRect& rect)
770 {
771     if (!m_enabled || !m_showPaintRects)
772         return;
773
774     LayoutRect absoluteRect = LayoutRect(renderer.localToAbsoluteQuad(FloatRect(rect)).boundingBox());
775     FrameView* view = renderer.document().view();
776
777     LayoutRect rootRect = absoluteRect;
778     if (!view->frame().isMainFrame()) {
779         IntRect rootViewRect = view->contentsToRootView(snappedIntRect(absoluteRect));
780         rootRect = view->frame().mainFrame().view()->rootViewToContents(rootViewRect);
781     }
782
783     if (m_client->overridesShowPaintRects()) {
784         m_client->showPaintRect(rootRect);
785         return;
786     }
787
788     m_overlay->showPaintRect(rootRect);
789 }
790
791 void InspectorPageAgent::didLayout()
792 {
793     bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
794     if (isFirstLayout)
795         m_isFirstLayoutAfterOnLoad = false;
796
797     if (!m_enabled)
798         return;
799
800     m_overlay->update();
801 }
802
803 void InspectorPageAgent::didScroll()
804 {
805     if (m_enabled)
806         m_overlay->update();
807 }
808
809 void InspectorPageAgent::didRecalculateStyle()
810 {
811     if (m_enabled)
812         m_overlay->update();
813 }
814
815 Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
816 {
817     ASSERT_ARG(frame, frame);
818
819     auto frameObject = Inspector::Protocol::Page::Frame::create()
820         .setId(frameId(frame))
821         .setLoaderId(loaderId(frame->loader().documentLoader()))
822         .setUrl(frame->document()->url().string())
823         .setMimeType(frame->loader().documentLoader()->responseMIMEType())
824         .setSecurityOrigin(frame->document()->securityOrigin().toRawString())
825         .release();
826     if (frame->tree().parent())
827         frameObject->setParentId(frameId(frame->tree().parent()));
828     if (frame->ownerElement()) {
829         String name = frame->ownerElement()->getNameAttribute();
830         if (name.isEmpty())
831             name = frame->ownerElement()->attributeWithoutSynchronization(HTMLNames::idAttr);
832         frameObject->setName(name);
833     }
834
835     return frameObject;
836 }
837
838 Ref<Inspector::Protocol::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
839 {
840     ASSERT_ARG(frame, frame);
841
842     Ref<Inspector::Protocol::Page::Frame> frameObject = buildObjectForFrame(frame);
843     auto subresources = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResource>::create();
844     auto result = Inspector::Protocol::Page::FrameResourceTree::create()
845         .setFrame(WTFMove(frameObject))
846         .setResources(subresources.copyRef())
847         .release();
848
849     for (auto* cachedResource : cachedResourcesForFrame(frame)) {
850         auto resourceObject = Inspector::Protocol::Page::FrameResource::create()
851             .setUrl(cachedResource->url())
852             .setType(cachedResourceTypeJson(*cachedResource))
853             .setMimeType(cachedResource->response().mimeType())
854             .release();
855         if (cachedResource->wasCanceled())
856             resourceObject->setCanceled(true);
857         else if (cachedResource->status() == CachedResource::LoadError || cachedResource->status() == CachedResource::DecodeError)
858             resourceObject->setFailed(true);
859         String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
860         if (!sourceMappingURL.isEmpty())
861             resourceObject->setSourceMapURL(sourceMappingURL);
862         String targetId = cachedResource->resourceRequest().initiatorIdentifier();
863         if (!targetId.isEmpty())
864             resourceObject->setTargetId(targetId);
865         subresources->addItem(WTFMove(resourceObject));
866     }
867
868     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>> childrenArray;
869     for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
870         if (!childrenArray) {
871             childrenArray = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>::create();
872             result->setChildFrames(childrenArray);
873         }
874         childrenArray->addItem(buildObjectForFrameTree(child));
875     }
876     return result;
877 }
878
879 void InspectorPageAgent::setEmulatedMedia(ErrorString&, const String& media)
880 {
881     if (media == m_emulatedMedia)
882         return;
883
884     m_emulatedMedia = media;
885     Document* document = m_page.mainFrame().document();
886     if (document) {
887         document->styleScope().didChangeStyleSheetEnvironment();
888         document->updateLayout();
889     }
890 }
891
892 void InspectorPageAgent::applyEmulatedMedia(String& media)
893 {
894     if (!m_emulatedMedia.isEmpty())
895         media = m_emulatedMedia;
896 }
897
898 void InspectorPageAgent::getCompositingBordersVisible(ErrorString&, bool* outParam)
899 {
900     *outParam = m_page.settings().showDebugBorders() || m_page.settings().showRepaintCounter();
901 }
902
903 void InspectorPageAgent::setCompositingBordersVisible(ErrorString&, bool visible)
904 {
905     m_page.settings().setShowDebugBorders(visible);
906     m_page.settings().setShowRepaintCounter(visible);
907 }
908
909 void InspectorPageAgent::snapshotNode(ErrorString& errorString, int nodeId, String* outDataURL)
910 {
911     Frame& frame = mainFrame();
912
913     InspectorDOMAgent* domAgent = m_instrumentingAgents.inspectorDOMAgent();
914     ASSERT(domAgent);
915     Node* node = domAgent->assertNode(errorString, nodeId);
916     if (!node)
917         return;
918
919     std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(frame, *node);
920     if (!snapshot) {
921         errorString = ASCIILiteral("Could not capture snapshot");
922         return;
923     }
924
925     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
926 }
927
928 void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
929 {
930     Frame& frame = mainFrame();
931
932     SnapshotOptions options = SnapshotOptionsNone;
933     if (coordinateSystem == "Viewport")
934         options |= SnapshotOptionsInViewCoordinates;
935
936     IntRect rectangle(x, y, width, height);
937     std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(frame, rectangle, options);
938
939     if (!snapshot) {
940         errorString = ASCIILiteral("Could not capture snapshot");
941         return;
942     }
943
944     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
945 }
946
947 void InspectorPageAgent::archive(ErrorString& errorString, String* data)
948 {
949 #if ENABLE(WEB_ARCHIVE) && USE(CF)
950     Frame& frame = mainFrame();
951     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
952     if (!archive) {
953         errorString = ASCIILiteral("Could not create web archive for main frame");
954         return;
955     }
956
957     RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
958     *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
959 #else
960     UNUSED_PARAM(data);
961     errorString = ASCIILiteral("No support for creating archives");
962 #endif
963 }
964
965 } // namespace WebCore