| // 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/WebElementCollection.h" |
| #include "third_party/WebKit/public/web/WebFrame.h" |
| #include "third_party/WebKit/public/web/WebView.h" |
| |
| namespace safe_browsing { |
| |
| namespace { |
| |
| // Handler for the various HTML elements that we extract URLs from. |
| void HandleElement( |
| const blink::WebElement& element, |
| SafeBrowsingHostMsg_MalwareDOMDetails_Node* parent_node, |
| std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>* resources) { |
| if (!element.hasAttribute("src")) |
| return; |
| |
| // Retrieve the link and resolve the link in case it's relative. |
| blink::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 |
| |
| // 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<SafeBrowsingHostMsg_MalwareDOMDetails_Node> resources; |
| ExtractResources(&resources); |
| // Notify the browser. |
| render_view()->Send(new SafeBrowsingHostMsg_MalwareDOMDetails( |
| render_view()->GetRoutingID(), resources)); |
| } |
| |
| void MalwareDOMDetails::ExtractResources( |
| std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>* resources) { |
| blink::WebView* web_view = render_view()->GetWebView(); |
| if (!web_view) { |
| NOTREACHED(); |
| return; |
| } |
| blink::WebFrame* frame = web_view->mainFrame(); |
| for (; frame; frame = frame->traverseNext(false /* don't wrap */)) { |
| DCHECK(frame); |
| SafeBrowsingHostMsg_MalwareDOMDetails_Node details_node; |
| blink::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; |
| } |
| |
| blink::WebElementCollection elements = document.all(); |
| blink::WebElement element = elements.firstItem(); |
| for (; !element.isNull(); element = elements.nextItem()) { |
| if (element.hasHTMLTagName("iframe") || element.hasHTMLTagName("frame") || |
| element.hasHTMLTagName("embed") || element.hasHTMLTagName("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); |
| } |
| } |
| |
| } // namespace safe_browsing |