Commit 07af09a4 authored by Hidy Han's avatar Hidy Han Committed by Commit Bot

Tag generated dom nodes with script url ("origin url").

Change-Id: I0643ca9e2d4e5d75cad3a76d8d005a6916c2fd13
Reviewed-on: https://chromium-review.googlesource.com/1063250
Commit-Queue: Hidy Han <hidyhan@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#560314}
parent 0e4865df
...@@ -3,6 +3,7 @@ Test that each agent could be enabled/disabled separately. ...@@ -3,6 +3,7 @@ Test that each agent could be enabled/disabled separately.
Animation.disable finished successfully Animation.disable finished successfully
CSS.disable finished successfully CSS.disable finished successfully
DOM.disable finished successfully DOM.disable finished successfully
DOMSnapshot.disable finished with error DOM snapshot agent hasn't been enabled.
DOMStorage.disable finished successfully DOMStorage.disable finished successfully
Database.disable finished successfully Database.disable finished successfully
Debugger.disable finished successfully Debugger.disable finished successfully
...@@ -26,6 +27,9 @@ CSS.disable finished successfully ...@@ -26,6 +27,9 @@ CSS.disable finished successfully
DOM.enable finished successfully DOM.enable finished successfully
DOM.disable finished successfully DOM.disable finished successfully
DOMSnapshot.enable finished successfully
DOMSnapshot.disable finished successfully
DOMStorage.enable finished successfully DOMStorage.enable finished successfully
DOMStorage.disable finished successfully DOMStorage.disable finished successfully
......
// Expected DOM structure:
// Note: unrelated elements like script, \n text nodes are omitted.
// For originUrl:
// * denotes dom-snapshot-origin-url-3.js.
// ** denotes dom-snapshot-origin-url.html, aka document inlined javascript.
// *** denotes dom-snapshot-origin-url-1.js.
// **** denoates dom-snapshot-origin-url-2.js.
// <img***>
// <firstChild**>
// <testWrite <html**** <p<text>> <span*<p<text>>> <p*<text>>>>
// <testInnerText <'New content'*>>
// <testInnerHtml1 <'Hello'**>>
// <testInnerHtml2 <p* <span <'Inner World'>>>>
// <p* <span <'Outer World'>>> (used to be testOuterHtml)
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank('Tests that DOMSnapshot.getSnapshot records origin url of dom nodes generated by script.');
await dp.DOMSnapshot.enable();
await page.navigate('../resources/dom-snapshot-origin-url.html');
function stabilize(key, value) {
var unstableKeys = ['documentURL', 'baseURL', 'frameId', 'backendNodeId', 'layoutTreeNodes'];
if (unstableKeys.indexOf(key) !== -1)
return '<' + typeof(value) + '>';
if (typeof value === 'string' && value.indexOf('file://') !== -1)
value = value.substring(value.lastIndexOf('/') + 1);
return value;
}
var response = await dp.DOMSnapshot.getSnapshot({'computedStyleWhitelist': [], 'includeEventListeners': true});
if (response.error)
testRunner.log(response);
else
testRunner.log(JSON.stringify(response.result, stabilize, 2));
testRunner.completeTest();
})
<html>
<body>
<script>
function createImage() {
let img = new Image(0, 0);
let sibling = document.getElementById('firstChild');
sibling.parentNode.insertBefore(img, sibling);
}
//# sourceURL=inspector-dom-origin-url-1.js
</script>
<script>
let firstChild = document.body.appendChild(document.createElement('span'));
firstChild.setAttribute('id', 'firstChild');
createImage();
</script>
<iframe name='testWrite'></iframe>
<span id='testInnerText'>Original content.</span>
<div id='testInnerHtml1'></div>
<script>document.getElementById('testInnerHtml1').innerHTML = 'Hello';</script>
<span id='testInnerHtml2'></span>
<div id='testOuterHtml'></div>
<script>
testWrite.document.write('<p>Top html node has an origin url.</p>');
//# sourceURL=inspector-dom-origin-url-2.js
</script>
<script>
testWrite.document.write('<span><p>Only top node has an origin url.</p></span><p>And sibling top node.</p>');
document.getElementById('testInnerText').innerText = 'New content.';
eval("document.getElementById('testInnerHtml2').innerHTML = '<p><span>Inner World</span></p>'");
document.getElementById('testOuterHtml').outerHTML = '<p><span>Outer World</span></p>';
//# sourceURL=inspector-dom-origin-url-3.js
</script>
</body>
</html>
...@@ -2028,6 +2028,8 @@ experimental domain DOMSnapshot ...@@ -2028,6 +2028,8 @@ experimental domain DOMSnapshot
optional array of DOMDebugger.EventListener eventListeners optional array of DOMDebugger.EventListener eventListeners
# The selected url for nodes with a srcset attribute. # The selected url for nodes with a srcset attribute.
optional string currentSourceURL optional string currentSourceURL
# The url of the script (if any) that generates this node.
optional string originURL
# Details of post layout rendered text positions. The exact layout should not be regarded as # Details of post layout rendered text positions. The exact layout should not be regarded as
# stable and may change between versions. # stable and may change between versions.
...@@ -2074,6 +2076,12 @@ experimental domain DOMSnapshot ...@@ -2074,6 +2076,12 @@ experimental domain DOMSnapshot
# Attribute/property value. # Attribute/property value.
string value string value
# Disables DOM snapshot agent for the given page.
command disable
# Enables DOM snapshot agent for the given page.
command enable
# Returns a document snapshot, including the full DOM tree of the root node (including iframes, # Returns a document snapshot, including the full DOM tree of the root node (including iframes,
# template contents, and imported documents) in a flattened array, as well as layout and # template contents, and imported documents) in a flattened array, as well as layout and
# white-listed computed style information for the nodes. Shadow DOM in the returned DOM tree is # white-listed computed style information for the nodes. Shadow DOM in the returned DOM tree is
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h" #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/dom/attribute.h" #include "third_party/blink/renderer/core/dom/attribute.h"
#include "third_party/blink/renderer/core/dom/attribute_collection.h" #include "third_party/blink/renderer/core/dom/attribute_collection.h"
#include "third_party/blink/renderer/core/dom/character_data.h"
#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_type.h" #include "third_party/blink/renderer/core/dom/document_type.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h" #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include "third_party/blink/renderer/core/inspector/inspected_frames.h" #include "third_party/blink/renderer/core/inspector/inspected_frames.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h"
#include "third_party/blink/renderer/core/inspector/thread_debugger.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_text.h" #include "third_party/blink/renderer/core/layout/layout_text.h"
...@@ -38,12 +40,17 @@ ...@@ -38,12 +40,17 @@
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_stacking_node.h" #include "third_party/blink/renderer/core/paint/paint_layer_stacking_node.h"
#include "third_party/blink/renderer/core/paint/paint_layer_stacking_node_iterator.h" #include "third_party/blink/renderer/core/paint/paint_layer_stacking_node_iterator.h"
#include "v8/include/v8-inspector.h"
namespace blink { namespace blink {
using protocol::Maybe; using protocol::Maybe;
using protocol::Response; using protocol::Response;
namespace DOMSnapshotAgentState {
static const char kDomSnapshotAgentEnabled[] = "DOMSnapshotAgentEnabled";
};
namespace { namespace {
std::unique_ptr<protocol::DOM::Rect> BuildRectForFloatRect( std::unique_ptr<protocol::DOM::Rect> BuildRectForFloatRect(
...@@ -114,6 +121,78 @@ InspectorDOMSnapshotAgent::InspectorDOMSnapshotAgent( ...@@ -114,6 +121,78 @@ InspectorDOMSnapshotAgent::InspectorDOMSnapshotAgent(
InspectorDOMSnapshotAgent::~InspectorDOMSnapshotAgent() = default; InspectorDOMSnapshotAgent::~InspectorDOMSnapshotAgent() = default;
bool InspectorDOMSnapshotAgent::Enabled() const {
return state_->booleanProperty(
DOMSnapshotAgentState::kDomSnapshotAgentEnabled, false);
}
void InspectorDOMSnapshotAgent::GetOriginUrl(String* origin_url_ptr,
const Node* node) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
ThreadDebugger* debugger = ThreadDebugger::From(isolate);
if (!isolate || !isolate->InContext() || !debugger) {
origin_url_ptr = nullptr;
return;
}
// First try searching in one frame, since grabbing full trace is
// expensive.
auto trace = debugger->GetV8Inspector()->captureStackTrace(false);
if (!trace) {
origin_url_ptr = nullptr;
return;
}
if (!trace->firstNonEmptySourceURL().length())
trace = debugger->GetV8Inspector()->captureStackTrace(true);
String origin_url = ToCoreString(trace->firstNonEmptySourceURL());
if (origin_url.IsEmpty()) {
// Fall back to document url.
origin_url = node->GetDocument().Url().GetString();
}
*origin_url_ptr = origin_url;
}
void InspectorDOMSnapshotAgent::CharacterDataModified(
CharacterData* character_data) {
String origin_url;
GetOriginUrl(&origin_url, character_data);
if (origin_url)
origin_url_map_->insert(DOMNodeIds::IdForNode(character_data), origin_url);
}
void InspectorDOMSnapshotAgent::DidInsertDOMNode(Node* node) {
String origin_url;
GetOriginUrl(&origin_url, node);
if (origin_url)
origin_url_map_->insert(DOMNodeIds::IdForNode(node), origin_url);
}
void InspectorDOMSnapshotAgent::InnerEnable() {
state_->setBoolean(DOMSnapshotAgentState::kDomSnapshotAgentEnabled, true);
origin_url_map_ = std::make_unique<OriginUrlMap>();
instrumenting_agents_->addInspectorDOMSnapshotAgent(this);
}
void InspectorDOMSnapshotAgent::Restore() {
if (!Enabled())
return;
InnerEnable();
}
Response InspectorDOMSnapshotAgent::enable() {
if (!Enabled())
InnerEnable();
return Response::OK();
}
Response InspectorDOMSnapshotAgent::disable() {
if (!Enabled())
return Response::Error("DOM snapshot agent hasn't been enabled.");
state_->setBoolean(DOMSnapshotAgentState::kDomSnapshotAgentEnabled, false);
origin_url_map_.reset();
instrumenting_agents_->removeInspectorDOMSnapshotAgent(this);
return Response::OK();
}
Response InspectorDOMSnapshotAgent::getSnapshot( Response InspectorDOMSnapshotAgent::getSnapshot(
std::unique_ptr<protocol::Array<String>> style_whitelist, std::unique_ptr<protocol::Array<String>> style_whitelist,
protocol::Maybe<bool> include_event_listeners, protocol::Maybe<bool> include_event_listeners,
...@@ -200,6 +279,17 @@ int InspectorDOMSnapshotAgent::VisitNode(Node* node, ...@@ -200,6 +279,17 @@ int InspectorDOMSnapshotAgent::VisitNode(Node* node,
.setNodeValue(node_value) .setNodeValue(node_value)
.setBackendNodeId(DOMNodeIds::IdForNode(node)) .setBackendNodeId(DOMNodeIds::IdForNode(node))
.build(); .build();
if (origin_url_map_ &&
origin_url_map_->Contains(owned_value->getBackendNodeId())) {
String origin_url = origin_url_map_->at(owned_value->getBackendNodeId());
// In common cases, it is implicit that a child node would have the same
// origin url as its parent, so no need to mark twice.
if (!node->parentNode() || origin_url_map_->at(DOMNodeIds::IdForNode(
node->parentNode())) != origin_url) {
owned_value->setOriginURL(
origin_url_map_->at(owned_value->getBackendNodeId()));
}
}
protocol::DOMSnapshot::DOMNode* value = owned_value.get(); protocol::DOMSnapshot::DOMNode* value = owned_value.get();
int index = dom_nodes_->length(); int index = dom_nodes_->length();
dom_nodes_->addItem(std::move(owned_value)); dom_nodes_->addItem(std::move(owned_value));
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "third_party/blink/renderer/core/css_property_names.h" #include "third_party/blink/renderer/core/css_property_names.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
#include "third_party/blink/renderer/core/inspector/protocol/DOMSnapshot.h" #include "third_party/blink/renderer/core/inspector/protocol/DOMSnapshot.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h"
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
namespace blink { namespace blink {
class CharacterData;
class Document; class Document;
class Element; class Element;
class InspectedFrames; class InspectedFrames;
...@@ -32,6 +34,10 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final ...@@ -32,6 +34,10 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final
~InspectorDOMSnapshotAgent() override; ~InspectorDOMSnapshotAgent() override;
void Trace(blink::Visitor*) override; void Trace(blink::Visitor*) override;
void Restore() override;
protocol::Response enable() override;
protocol::Response disable() override;
protocol::Response getSnapshot( protocol::Response getSnapshot(
std::unique_ptr<protocol::Array<String>> style_whitelist, std::unique_ptr<protocol::Array<String>> style_whitelist,
protocol::Maybe<bool> include_event_listeners, protocol::Maybe<bool> include_event_listeners,
...@@ -44,8 +50,15 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final ...@@ -44,8 +50,15 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final
std::unique_ptr<protocol::Array<protocol::DOMSnapshot::ComputedStyle>>* std::unique_ptr<protocol::Array<protocol::DOMSnapshot::ComputedStyle>>*
computed_styles) override; computed_styles) override;
bool Enabled() const;
// InspectorInstrumentation API.
void CharacterDataModified(CharacterData*);
void DidInsertDOMNode(Node*);
private: private:
InspectorDOMSnapshotAgent(InspectedFrames*, InspectorDOMDebuggerAgent*); InspectorDOMSnapshotAgent(InspectedFrames*, InspectorDOMDebuggerAgent*);
void InnerEnable();
// Adds a DOMNode for the given Node to |dom_nodes_| and returns its index. // Adds a DOMNode for the given Node to |dom_nodes_| and returns its index.
int VisitNode(Node*, int VisitNode(Node*,
...@@ -86,6 +99,8 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final ...@@ -86,6 +99,8 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final
void TraversePaintLayerTree(Document*); void TraversePaintLayerTree(Document*);
void VisitPaintLayer(PaintLayer*); void VisitPaintLayer(PaintLayer*);
void GetOriginUrl(String*, const Node*);
struct VectorStringHashTraits; struct VectorStringHashTraits;
using ComputedStylesMap = WTF::HashMap<Vector<String>, using ComputedStylesMap = WTF::HashMap<Vector<String>,
int, int,
...@@ -93,6 +108,7 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final ...@@ -93,6 +108,7 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final
VectorStringHashTraits>; VectorStringHashTraits>;
using CSSPropertyWhitelist = Vector<std::pair<String, CSSPropertyID>>; using CSSPropertyWhitelist = Vector<std::pair<String, CSSPropertyID>>;
using PaintOrderMap = WTF::HashMap<PaintLayer*, int>; using PaintOrderMap = WTF::HashMap<PaintLayer*, int>;
using OriginUrlMap = WTF::HashMap<DOMNodeId, String>;
// State of current snapshot. // State of current snapshot.
std::unique_ptr<protocol::Array<protocol::DOMSnapshot::DOMNode>> dom_nodes_; std::unique_ptr<protocol::Array<protocol::DOMSnapshot::DOMNode>> dom_nodes_;
...@@ -108,6 +124,9 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final ...@@ -108,6 +124,9 @@ class CORE_EXPORT InspectorDOMSnapshotAgent final
// Maps a PaintLayer to its paint order index. // Maps a PaintLayer to its paint order index.
std::unique_ptr<PaintOrderMap> paint_order_map_; std::unique_ptr<PaintOrderMap> paint_order_map_;
int next_paint_order_index_ = 0; int next_paint_order_index_ = 0;
// Maps a backend node id to the url of the script (if any) that generates
// the corresponding node.
std::unique_ptr<OriginUrlMap> origin_url_map_;
Member<InspectedFrames> inspected_frames_; Member<InspectedFrames> inspected_frames_;
Member<InspectorDOMDebuggerAgent> dom_debugger_agent_; Member<InspectorDOMDebuggerAgent> dom_debugger_agent_;
......
...@@ -80,6 +80,12 @@ ...@@ -80,6 +80,12 @@
"willSendXMLHttpOrFetchNetworkRequest", "willSendXMLHttpOrFetchNetworkRequest",
] ]
}, },
DOMSnapshot: {
probes: [
"characterDataModified",
"didInsertDOMNode",
]
},
Emulation: { Emulation: {
probes: [ probes: [
"frameStartedLoading", "frameStartedLoading",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment