// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/renderer/safe_browsing/malware_dom_details.h" #include "base/compiler_specific.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/safe_browsing/safebrowsing_messages.h" #include "content/public/renderer/render_view.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebNodeCollection.h" #include "third_party/WebKit/public/web/WebView.h" namespace safe_browsing { // An upper limit on the number of nodes we collect. uint32 MalwareDOMDetails::kMaxNodes = 500; // static MalwareDOMDetails* MalwareDOMDetails::Create(content::RenderView* render_view) { // Private constructor and public static Create() method to facilitate // stubbing out this class for binary-size reduction purposes. return new MalwareDOMDetails(render_view); } MalwareDOMDetails::MalwareDOMDetails(content::RenderView* render_view) : content::RenderViewObserver(render_view) { } MalwareDOMDetails::~MalwareDOMDetails() { } bool MalwareDOMDetails::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(MalwareDOMDetails, message) IPC_MESSAGE_HANDLER(SafeBrowsingMsg_GetMalwareDOMDetails, OnGetMalwareDOMDetails) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void MalwareDOMDetails::OnGetMalwareDOMDetails() { std::vector resources; ExtractResources(&resources); // Notify the browser. render_view()->Send(new SafeBrowsingHostMsg_MalwareDOMDetails( render_view()->GetRoutingID(), resources)); } void MalwareDOMDetails::ExtractResources( std::vector* resources) { WebKit::WebView* web_view = render_view()->GetWebView(); if (!web_view) { NOTREACHED(); return; } WebKit::WebFrame* frame = web_view->mainFrame(); for (; frame; frame = frame->traverseNext(false /* don't wrap */)) { DCHECK(frame); SafeBrowsingHostMsg_MalwareDOMDetails_Node details_node; WebKit::WebDocument document = frame->document(); details_node.url = GURL(document.url()); if (document.isNull()) { // Nothing in this frame, move on to the next one. resources->push_back(details_node); continue; } WebKit::WebNodeCollection elements = document.all(); WebKit::WebNode cur_node = elements.firstItem(); for (; !cur_node.isNull(); cur_node = elements.nextItem()) { if (!cur_node.isElementNode()) { continue; } WebKit::WebElement element = cur_node.to(); if (element.hasTagName("iframe") || element.hasTagName("frame") || element.hasTagName("embed") || element.hasTagName("script")) { HandleElement(element, &details_node, resources); if (resources->size() >= kMaxNodes) { // We have reached kMaxNodes, exit early. resources->push_back(details_node); return; } } } resources->push_back(details_node); } } void MalwareDOMDetails::HandleElement( const WebKit::WebElement& element, SafeBrowsingHostMsg_MalwareDOMDetails_Node* parent_node, std::vector* resources) { if (!element.hasAttribute("src")) { return; } // Retrieve the link and resolve the link in case it's relative. WebKit::WebURL full_url = element.document().completeURL( element.getAttribute("src")); const GURL& child_url = GURL(full_url); // Add to the parent node. parent_node->children.push_back(child_url); // Create the child node. SafeBrowsingHostMsg_MalwareDOMDetails_Node child_node; child_node.url = child_url; child_node.tag_name = element.tagName().utf8(); child_node.parent = parent_node->url; resources->push_back(child_node); } } // namespace safe_browsing