2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2015 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "InspectorPageAgent.h"
35 #include "CachedCSSStyleSheet.h"
36 #include "CachedFont.h"
37 #include "CachedImage.h"
38 #include "CachedResource.h"
39 #include "CachedResourceLoader.h"
40 #include "CachedScript.h"
42 #include "CookieJar.h"
43 #include "DOMPatchSupport.h"
44 #include "DOMWrapperWorld.h"
46 #include "DocumentLoader.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"
64 #include "RenderObject.h"
65 #include "ScriptController.h"
66 #include "SecurityOrigin.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>
81 #if ENABLE(WEB_ARCHIVE) && USE(CF)
82 #include "LegacyWebArchive.h"
85 using namespace Inspector;
89 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
92 TextEncoding encoding(textEncodingName);
93 if (!encoding.isValid())
94 encoding = WindowsLatin1Encoding();
95 *result = encoding.decode(buffer, size);
101 static bool prepareCachedResourceBuffer(CachedResource* cachedResource, bool* hasZeroSize)
103 *hasZeroSize = false;
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()) {
116 static bool hasTextContent(CachedResource* cachedResource)
118 InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
119 return type == InspectorPageAgent::DocumentResource
120 || type == InspectorPageAgent::StylesheetResource
121 || type == InspectorPageAgent::ScriptResource
122 || type == InspectorPageAgent::XHRResource;
125 static RefPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName)
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");
136 decoder = TextResourceDecoder::create("text/plain", "UTF-8");
140 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
142 // FIXME: result should be a String& and base64Encoded should be a bool&.
144 bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize);
148 *base64Encoded = !hasTextContent(cachedResource);
149 if (*base64Encoded) {
154 if (auto* buffer = cachedResource->resourceBuffer()) {
155 *result = base64Encode(buffer->data(), buffer->size());
162 *result = emptyString();
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();
175 case CachedResource::MediaResource:
176 case CachedResource::RawResource: {
177 auto* buffer = cachedResource->resourceBuffer();
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.
184 *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
188 auto* buffer = cachedResource->resourceBuffer();
189 return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
195 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
197 RefPtr<SharedBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
200 return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), frame->document()->encoding(), withBase64Encode, result);
204 bool InspectorPageAgent::sharedBufferContent(RefPtr<SharedBuffer>&& buffer, const String& textEncodingName, bool withBase64Encode, String* result)
206 return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
209 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
211 if (withBase64Encode) {
212 *result = base64Encode(data, size);
216 return decodeBuffer(data, size, textEncodingName, result);
220 void InspectorPageAgent::resourceContent(ErrorString& errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
222 DocumentLoader* loader = assertDocumentLoader(errorString, frame);
226 RefPtr<SharedBuffer> buffer;
227 bool success = false;
228 if (equalIgnoringFragmentIdentifier(url, loader->url())) {
229 *base64Encoded = false;
230 success = mainResourceContent(frame, *base64Encoded, result);
234 success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
237 errorString = ASCIILiteral("No resource with given URL found");
241 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
243 static NeverDestroyed<String> sourceMapHTTPHeader(ASCIILiteral("SourceMap"));
244 static NeverDestroyed<String> sourceMapHTTPHeaderDeprecated(ASCIILiteral("X-SourceMap"));
249 // Scripts are handled in a separate path.
250 if (cachedResource->type() != CachedResource::CSSStyleSheet)
253 String sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeader);
254 if (!sourceMapHeader.isEmpty())
255 return sourceMapHeader;
257 sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
258 if (!sourceMapHeader.isEmpty())
259 return sourceMapHeader;
263 if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
264 return ContentSearchUtilities::findStylesheetSourceMapURL(content);
269 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
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());
280 cachedResource = MemoryCache::singleton().resourceForRequest(request, frame->page()->sessionID());
283 return cachedResource;
286 Inspector::Protocol::Page::ResourceType InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
288 switch (resourceType) {
289 case DocumentResource:
290 return Inspector::Protocol::Page::ResourceType::Document;
292 return Inspector::Protocol::Page::ResourceType::Image;
294 return Inspector::Protocol::Page::ResourceType::Font;
295 case StylesheetResource:
296 return Inspector::Protocol::Page::ResourceType::Stylesheet;
298 return Inspector::Protocol::Page::ResourceType::Script;
300 return Inspector::Protocol::Page::ResourceType::XHR;
301 case WebSocketResource:
302 return Inspector::Protocol::Page::ResourceType::WebSocket;
304 return Inspector::Protocol::Page::ResourceType::Other;
306 return Inspector::Protocol::Page::ResourceType::Other;
309 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
311 switch (cachedResource.type()) {
312 case CachedResource::ImageResource:
313 return InspectorPageAgent::ImageResource;
314 #if ENABLE(SVG_FONTS)
315 case CachedResource::SVGFontResource:
317 case CachedResource::FontResource:
318 return InspectorPageAgent::FontResource;
319 case CachedResource::CSSStyleSheet:
322 case CachedResource::XSLStyleSheet:
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;
335 return InspectorPageAgent::OtherResource;
338 Inspector::Protocol::Page::ResourceType InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
340 return resourceTypeJson(cachedResourceType(cachedResource));
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)
353 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
357 void InspectorPageAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
361 #if ENABLE(TOUCH_EVENTS)
362 updateTouchEventEmulationInPage(false);
366 double InspectorPageAgent::timestamp()
368 return m_environment.executionStopwatch()->elapsedTime();
371 void InspectorPageAgent::enable(ErrorString&)
374 m_instrumentingAgents.setInspectorPageAgent(this);
376 auto stopwatch = m_environment.executionStopwatch();
380 m_originalScriptExecutionDisabled = !mainFrame().settings().isScriptEnabled();
383 void InspectorPageAgent::disable(ErrorString&)
386 m_scriptsToEvaluateOnLoad = nullptr;
387 m_instrumentingAgents.setInspectorPageAgent(nullptr);
390 setScriptExecutionDisabled(unused, m_originalScriptExecutionDisabled);
391 setShowPaintRects(unused, false);
392 setEmulatedMedia(unused, emptyString());
395 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString&, const String& source, String* identifier)
397 if (!m_scriptsToEvaluateOnLoad)
398 m_scriptsToEvaluateOnLoad = InspectorObject::create();
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.
403 *identifier = String::number(++m_lastScriptIdentifier);
404 } while (m_scriptsToEvaluateOnLoad->find(*identifier) != m_scriptsToEvaluateOnLoad->end());
406 m_scriptsToEvaluateOnLoad->setString(*identifier, source);
409 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString& error, const String& identifier)
411 if (!m_scriptsToEvaluateOnLoad || m_scriptsToEvaluateOnLoad->find(identifier) == m_scriptsToEvaluateOnLoad->end()) {
412 error = ASCIILiteral("Script not found");
416 m_scriptsToEvaluateOnLoad->remove(identifier);
419 void InspectorPageAgent::reload(ErrorString&, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
421 m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : emptyString();
422 m_page.mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
425 void InspectorPageAgent::navigate(ErrorString&, const String& url)
427 UserGestureIndicator indicator(ProcessingUserGesture);
428 Frame& frame = m_page.mainFrame();
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);
435 static Ref<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
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)
450 static Ref<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
452 auto cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
454 for (const auto& cookie : cookiesList)
455 cookies->addItem(buildObjectForCookie(cookie));
460 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
462 Vector<CachedResource*> result;
464 for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader().allCachedResources().values()) {
465 auto* cachedResource = cachedResourceHandle.get();
466 if (cachedResource->resourceRequest().hiddenFromInspector())
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:
475 case CachedResource::FontResource:
476 // Skip fonts that were referenced in CSS but never used/downloaded.
477 if (cachedResource->stillNeedsLoad())
481 // All other CachedResource types download immediately.
485 result.append(cachedResource);
491 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
495 result.append(frame->loader().documentLoader()->url());
497 for (auto* cachedResource : cachedResourcesForFrame(frame))
498 result.append(cachedResource->url());
503 void InspectorPageAgent::getCookies(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>>& cookies)
505 // If we can get raw cookies.
506 ListHashSet<Cookie> rawCookiesList;
508 // If we can't get raw cookies - fall back to String representation
509 StringBuilder stringCookiesList;
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;
516 for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
517 Document* document = frame->document();
521 for (auto& url : allResourcesURLsForFrame(frame)) {
522 Vector<Cookie> docCookiesList;
523 rawCookiesImplemented = getRawCookies(*document, URL(ParsedURLString, url), docCookiesList);
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());
531 for (auto& cookie : docCookiesList) {
532 if (!rawCookiesList.contains(cookie))
533 rawCookiesList.add(cookie);
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);
543 cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
546 void InspectorPageAgent::deleteCookie(ErrorString&, const String& cookieName, const String& url)
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);
555 void InspectorPageAgent::getResourceTree(ErrorString&, RefPtr<Inspector::Protocol::Page::FrameResourceTree>& object)
557 object = buildObjectForFrameTree(&m_page.mainFrame());
560 void InspectorPageAgent::getResourceContent(ErrorString& errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
562 Frame* frame = assertFrame(errorString, frameId);
566 resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
569 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
571 if (hasTextContent(cachedResource)) {
574 if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
575 ASSERT(!base64Encoded);
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)
584 results = Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>::create();
586 bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
587 bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
589 if (optionalRequestId) {
590 if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent()) {
591 networkAgent->searchInRequest(errorString, *optionalRequestId, query, caseSensitive, isRegex, results);
596 Frame* frame = assertFrame(errorString, frameId);
600 DocumentLoader* loader = assertDocumentLoader(errorString, frame);
604 URL kurl(ParsedURLString, url);
607 bool success = false;
608 if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
609 success = mainResourceContent(frame, false, &content);
612 CachedResource* resource = cachedResource(frame, kurl);
614 success = textContentForCachedResource(resource, &content);
620 results = ContentSearchUtilities::searchInTextByLines(content, query, caseSensitive, isRegex);
623 static Ref<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
625 return Inspector::Protocol::Page::SearchResult::create()
628 .setMatchesCount(matchesCount)
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)
634 result = Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>::create();
636 bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
637 bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
638 JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
640 for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
643 for (auto* cachedResource : cachedResourcesForFrame(frame)) {
644 if (textContentForCachedResource(cachedResource, &content)) {
645 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
647 result->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
651 if (mainResourceContent(frame, false, &content)) {
652 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
654 result->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
658 if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent())
659 networkAgent->searchOtherRequests(regex, result);
662 void InspectorPageAgent::setDocumentContent(ErrorString& errorString, const String& frameId, const String& html)
664 Frame* frame = assertFrame(errorString, frameId);
668 Document* document = frame->document();
670 errorString = ASCIILiteral("No Document instance to set HTML for");
673 DOMPatchSupport::patchDocument(*document, html);
676 void InspectorPageAgent::setShowPaintRects(ErrorString&, bool show)
678 m_showPaintRects = show;
679 m_client->setShowPaintRects(show);
681 if (m_client->overridesShowPaintRects())
684 m_overlay->setShowingPaintRects(show);
687 void InspectorPageAgent::getScriptExecutionStatus(ErrorString&, Inspector::PageBackendDispatcherHandler::Result* status)
689 bool disabledByScriptController = false;
690 bool disabledInSettings = false;
691 disabledByScriptController = mainFrame().script().canExecuteScripts(NotAboutToExecuteScript);
692 disabledInSettings = !mainFrame().settings().isScriptEnabled();
694 if (!disabledByScriptController) {
695 *status = Inspector::PageBackendDispatcherHandler::Result::Allowed;
699 if (disabledInSettings)
700 *status = Inspector::PageBackendDispatcherHandler::Result::Disabled;
702 *status = Inspector::PageBackendDispatcherHandler::Result::Forbidden;
705 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString&, bool value)
707 m_ignoreScriptsEnabledNotification = true;
708 mainFrame().settings().setScriptEnabled(!value);
709 m_ignoreScriptsEnabledNotification = false;
712 void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld& world)
714 if (&world != &mainThreadNormalWorld())
717 if (m_scriptsToEvaluateOnLoad) {
718 for (auto& keyValuePair : *m_scriptsToEvaluateOnLoad) {
720 if (keyValuePair.value->asString(scriptText))
721 frame->script().executeScript(scriptText);
725 if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
726 frame->script().executeScript(m_scriptToEvaluateOnLoadOnce);
729 void InspectorPageAgent::domContentEventFired()
731 m_isFirstLayoutAfterOnLoad = true;
732 m_frontendDispatcher->domContentEventFired(timestamp());
735 void InspectorPageAgent::loadEventFired()
737 m_frontendDispatcher->loadEventFired(timestamp());
740 void InspectorPageAgent::frameNavigated(Frame& frame)
742 if (frame.isMainFrame()) {
743 m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
744 m_pendingScriptToEvaluateOnLoadOnce = String();
746 m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame));
749 void InspectorPageAgent::frameDetached(Frame& frame)
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);
759 MainFrame& InspectorPageAgent::mainFrame()
761 return m_page.mainFrame();
764 Frame* InspectorPageAgent::frameForId(const String& frameId)
766 return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
769 String InspectorPageAgent::frameId(Frame* 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);
782 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
784 return frame && m_frameToIdentifier.contains(frame);
787 String InspectorPageAgent::loaderId(DocumentLoader* 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);
799 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
801 for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
802 RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
803 if (documentOrigin->toRawString() == originRawString)
809 Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId)
811 Frame* frame = frameForId(frameId);
813 errorString = ASCIILiteral("No frame for given id found");
818 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString& errorString, Frame* frame)
820 FrameLoader& frameLoader = frame->loader();
821 DocumentLoader* documentLoader = frameLoader.documentLoader();
823 errorString = ASCIILiteral("No documentLoader for given frame found");
824 return documentLoader;
827 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader)
829 m_loaderToIdentifier.remove(&loader);
832 void InspectorPageAgent::frameStartedLoading(Frame& frame)
834 m_frontendDispatcher->frameStartedLoading(frameId(&frame));
837 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
839 m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
842 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, double delay)
844 m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay);
847 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
849 m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
852 void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
854 m_frontendDispatcher->javascriptDialogOpening(message);
857 void InspectorPageAgent::didRunJavaScriptDialog()
859 m_frontendDispatcher->javascriptDialogClosed();
862 void InspectorPageAgent::didPaint(RenderObject& renderer, const LayoutRect& rect)
864 if (!m_enabled || !m_showPaintRects)
867 LayoutRect absoluteRect = LayoutRect(renderer.localToAbsoluteQuad(FloatRect(rect)).boundingBox());
868 FrameView* view = renderer.document().view();
870 LayoutRect rootRect = absoluteRect;
871 if (!view->frame().isMainFrame()) {
872 IntRect rootViewRect = view->contentsToRootView(snappedIntRect(absoluteRect));
873 rootRect = view->frame().mainFrame().view()->rootViewToContents(rootViewRect);
876 if (m_client->overridesShowPaintRects()) {
877 m_client->showPaintRect(rootRect);
881 m_overlay->showPaintRect(rootRect);
884 void InspectorPageAgent::didLayout()
886 bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
888 m_isFirstLayoutAfterOnLoad = false;
896 void InspectorPageAgent::didScroll()
902 void InspectorPageAgent::didRecalculateStyle()
908 void InspectorPageAgent::scriptsEnabled(bool isEnabled)
910 if (m_ignoreScriptsEnabledNotification)
913 m_frontendDispatcher->scriptsEnabled(isEnabled);
916 Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
918 ASSERT_ARG(frame, frame);
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())
927 if (frame->tree().parent())
928 frameObject->setParentId(frameId(frame->tree().parent()));
929 if (frame->ownerElement()) {
930 String name = frame->ownerElement()->getNameAttribute();
932 name = frame->ownerElement()->attributeWithoutSynchronization(HTMLNames::idAttr);
933 frameObject->setName(name);
939 Ref<Inspector::Protocol::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
941 ASSERT_ARG(frame, frame);
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())
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())
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));
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);
975 childrenArray->addItem(buildObjectForFrameTree(child));
980 #if ENABLE(TOUCH_EVENTS)
981 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
983 mainFrame().settings().setTouchEventEmulationEnabled(enabled);
987 void InspectorPageAgent::setTouchEmulationEnabled(ErrorString& error, bool enabled)
989 #if ENABLE(TOUCH_EVENTS)
991 updateTouchEventEmulationInPage(enabled);
993 error = ASCIILiteral("Touch events emulation not supported");
994 UNUSED_PARAM(enabled);
998 void InspectorPageAgent::setEmulatedMedia(ErrorString&, const String& media)
1000 if (media == m_emulatedMedia)
1003 m_emulatedMedia = media;
1004 Document* document = m_page.mainFrame().document();
1006 document->styleScope().didChangeStyleSheetEnvironment();
1007 document->updateLayout();
1011 void InspectorPageAgent::applyEmulatedMedia(String& media)
1013 if (!m_emulatedMedia.isEmpty())
1014 media = m_emulatedMedia;
1017 void InspectorPageAgent::getCompositingBordersVisible(ErrorString&, bool* outParam)
1019 *outParam = m_page.settings().showDebugBorders() || m_page.settings().showRepaintCounter();
1022 void InspectorPageAgent::setCompositingBordersVisible(ErrorString&, bool visible)
1024 m_page.settings().setShowDebugBorders(visible);
1025 m_page.settings().setShowRepaintCounter(visible);
1028 void InspectorPageAgent::snapshotNode(ErrorString& errorString, int nodeId, String* outDataURL)
1030 Frame& frame = mainFrame();
1032 InspectorDOMAgent* domAgent = m_instrumentingAgents.inspectorDOMAgent();
1034 Node* node = domAgent->assertNode(errorString, nodeId);
1038 std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(frame, *node);
1040 errorString = ASCIILiteral("Could not capture snapshot");
1044 *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1047 void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
1049 Frame& frame = mainFrame();
1051 SnapshotOptions options = SnapshotOptionsNone;
1052 if (coordinateSystem == "Viewport")
1053 options |= SnapshotOptionsInViewCoordinates;
1055 IntRect rectangle(x, y, width, height);
1056 std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(frame, rectangle, options);
1059 errorString = ASCIILiteral("Could not capture snapshot");
1063 *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1066 void InspectorPageAgent::handleJavaScriptDialog(ErrorString& errorString, bool accept, const String* promptText)
1068 if (!m_client->handleJavaScriptDialog(accept, promptText))
1069 errorString = ASCIILiteral("Could not handle JavaScript dialog");
1072 void InspectorPageAgent::archive(ErrorString& errorString, String* data)
1074 #if ENABLE(WEB_ARCHIVE) && USE(CF)
1075 Frame& frame = mainFrame();
1076 RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
1078 errorString = ASCIILiteral("Could not create web archive for main frame");
1082 RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
1083 *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
1086 errorString = ASCIILiteral("No support for creating archives");
1090 } // namespace WebCore