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