Reland “De-obfuscate X-Client-Data header values in Network tab”
Reland of: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2316062
Screenshot: https://i.imgur.com/LJHFIp9.png
Note that the screenshot shows this as a response header instead of a
request header, since that was easier to test. In real-world scenarios
it would be a request header instead, but the UI looks the same.
CL preparing the ClientVariationsParser for use in the DevTools UI:
https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2316065
[email protected],[email protected],[email protected],[email protected]
Bug: chromium:1103854
Change-Id: I6b959a1d57bcbc84f8571257a88fcbec805bf330
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2318257
Reviewed-by: Mathias Bynens <[email protected]>
Reviewed-by: Ilya Sherman <[email protected]>
Reviewed-by: Paul Lewis <[email protected]>
Commit-Queue: Mathias Bynens <[email protected]>
diff --git a/BUILD.gn b/BUILD.gn
index 24e4008..a1a3d06 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -157,9 +157,9 @@
generated_non_autostart_non_remote_modules = [
"$resources_out_dir/accessibility/accessibility_module.js",
"$resources_out_dir/animation/animation_module.js",
- "$resources_out_dir/lighthouse/lighthouse_module.js",
"$resources_out_dir/browser_debugger/browser_debugger_module.js",
"$resources_out_dir/changes/changes_module.js",
+ "$resources_out_dir/client_variations/client_variations_module.js",
"$resources_out_dir/cm_modes/cm_modes_module.js",
"$resources_out_dir/cm/cm_module.js",
"$resources_out_dir/color_picker/color_picker_module.js",
@@ -182,6 +182,7 @@
"$resources_out_dir/js_profiler/js_profiler_module.js",
"$resources_out_dir/layer_viewer/layer_viewer_module.js",
"$resources_out_dir/layers/layers_module.js",
+ "$resources_out_dir/lighthouse/lighthouse_module.js",
"$resources_out_dir/marked/marked_module.js",
"$resources_out_dir/media/media_module.js",
"$resources_out_dir/network/network_module.js",
diff --git a/all_devtools_files.gni b/all_devtools_files.gni
index 6e4ba5a..78ceb6c 100644
--- a/all_devtools_files.gni
+++ b/all_devtools_files.gni
@@ -49,6 +49,7 @@
"front_end/changes/changesSidebar.css",
"front_end/changes/changesView.css",
"front_end/changes/module.json",
+ "front_end/client_variations/module.json",
"front_end/cm_headless/module.json",
"front_end/cm_modes/module.json",
"front_end/cm/codemirror.css",
diff --git a/all_devtools_modules.gni b/all_devtools_modules.gni
index 05448e2..bf844ff 100644
--- a/all_devtools_modules.gni
+++ b/all_devtools_modules.gni
@@ -501,9 +501,6 @@
"elements/StylePropertyHighlighter.js",
"elements/StylePropertyTreeElement.js",
"elements/StylesSidebarPane.js",
- "formatter/FormatterWorkerPool.js",
- "formatter/ScriptFormatter.js",
- "formatter/SourceFormatter.js",
"formatter_worker/AcornTokenizer.js",
"formatter_worker/CSSFormatter.js",
"formatter_worker/CSSRuleParser.js",
@@ -514,9 +511,15 @@
"formatter_worker/IdentityFormatter.js",
"formatter_worker/JavaScriptFormatter.js",
"formatter_worker/JavaScriptOutline.js",
+ "formatter/FormatterWorkerPool.js",
+ "formatter/ScriptFormatter.js",
+ "formatter/SourceFormatter.js",
"generated/ARIAProperties.js",
"generated/InspectorBackendCommands.js",
"generated/SupportedCSSProperties.js",
+ "har_importer/HARFormat.js",
+ "har_importer/HARImporter.js",
+ "heap_snapshot_model/HeapSnapshotModel.js",
"host/InspectorFrontendHost.js",
"host/InspectorFrontendHostAPI.js",
"host/Platform.js",
@@ -525,6 +528,8 @@
"issues/IssueAggregator.js",
"issues/IssueRevealer.js",
"issues/IssuesPane.js",
+ "javascript_metadata/JavaScriptMetadata.js",
+ "javascript_metadata/NativeFunctions.js",
"platform/array-utilities.js",
"platform/date-utilities.js",
"platform/number-utilities.js",
@@ -605,13 +610,11 @@
"text_utils/TextCursor.js",
"text_utils/TextRange.js",
"text_utils/TextUtils.js",
- "workspace/FileManager.js",
- "workspace/UISourceCode.js",
- "workspace/WorkspaceImpl.js",
"third_party/acorn-logical-assignment/package/dist/acorn-logical-assignment.mjs",
"third_party/acorn-loose/package/dist/acorn-loose.mjs",
"third_party/acorn-numeric-separator/package/dist/acorn-numeric-separator.mjs",
"third_party/acorn/package/dist/acorn.mjs",
+ "third_party/chromium/client-variations/ClientVariationsParser.js",
"third_party/codemirror/package/addon/comment/comment.js",
"third_party/codemirror/package/addon/edit/closebrackets.js",
"third_party/codemirror/package/addon/edit/matchbrackets.js",
@@ -661,13 +664,10 @@
"timeline_model/TimelineModelFilter.js",
"timeline_model/TimelineProfileTree.js",
"timeline_model/TracingLayerTree.js",
- "workspace_diff/WorkspaceDiff.js",
"worker_service/ServiceDispatcher.js",
- "har_importer/HARFormat.js",
- "har_importer/HARImporter.js",
- "heap_snapshot_model/HeapSnapshotModel.js",
- "javascript_metadata/JavaScriptMetadata.js",
- "javascript_metadata/NativeFunctions.js",
+ "workspace/FileManager.js",
+ "workspace/UISourceCode.js",
+ "workspace/WorkspaceImpl.js",
]
foreach(module, all_typescript_modules) {
diff --git a/devtools_module_entrypoints.gni b/devtools_module_entrypoints.gni
index a61c710..143d7f9 100644
--- a/devtools_module_entrypoints.gni
+++ b/devtools_module_entrypoints.gni
@@ -160,6 +160,7 @@
"$resources_out_dir/third_party/acorn/acorn.js",
"$resources_out_dir/third_party/lit-html/lit-html.js",
"$resources_out_dir/marked/marked.js",
+ "$resources_out_dir/client_variations/client_variations.js",
"$resources_out_dir/root/root.js",
"$resources_out_dir/sdk/sdk.js",
"$resources_out_dir/search/search.js",
diff --git a/front_end/BUILD.gn b/front_end/BUILD.gn
index d9faa65..b316be3 100644
--- a/front_end/BUILD.gn
+++ b/front_end/BUILD.gn
@@ -12,6 +12,7 @@
"accessibility:bundle",
"bindings:bundle",
"browser_sdk:bundle",
+ "client_variations:bundle",
"color_picker:bundle",
"common:bundle",
"component_docs",
diff --git a/front_end/client_variations/BUILD.gn b/front_end/client_variations/BUILD.gn
new file mode 100644
index 0000000..f9174a9
--- /dev/null
+++ b/front_end/client_variations/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2020 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.
+
+import("../../scripts/build/ninja/devtools_entrypoint.gni")
+
+devtools_entrypoint("bundle") {
+ entrypoint = "client_variations.js"
+
+ is_legacy_javascript_entrypoint = [ "crbug.com/1011811" ]
+
+ deps = [ "../third_party/chromium" ]
+}
diff --git a/front_end/client_variations/client_variations.js b/front_end/client_variations/client_variations.js
new file mode 100644
index 0000000..5c67eea
--- /dev/null
+++ b/front_end/client_variations/client_variations.js
@@ -0,0 +1,7 @@
+// Copyright 2020 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.
+
+import * as ClientVariationsParser from '../third_party/chromium/client-variations/ClientVariationsParser.js';
+
+export const parseClientVariations = ClientVariationsParser.parseClientVariations;
diff --git a/front_end/client_variations/module.json b/front_end/client_variations/module.json
new file mode 100644
index 0000000..0d413f5
--- /dev/null
+++ b/front_end/client_variations/module.json
@@ -0,0 +1,10 @@
+{
+ "skip_rollup": true,
+ "modules": [
+ "client_variations.js",
+ "../third_party/chromium/client-variations/ClientVariationsParser.js"
+ ],
+ "skip_compilation": [
+ "../third_party/chromium/client-variations/ClientVariationsParser.js"
+ ]
+}
diff --git a/front_end/network/RequestHeadersView.js b/front_end/network/RequestHeadersView.js
index 44a8c3f..3c10522 100644
--- a/front_end/network/RequestHeadersView.js
+++ b/front_end/network/RequestHeadersView.js
@@ -29,6 +29,7 @@
*/
import * as BrowserSDK from '../browser_sdk/browser_sdk.js';
+import * as ClientVariationsParser from '../client_variations/client_variations.js';
import * as Common from '../common/common.js';
import * as Host from '../host/host.js';
import * as ObjectUI from '../object_ui/object_ui.js';
@@ -736,7 +737,7 @@
if (this._request.cachedInMemory() || this._request.cached()) {
cautionText = ls`Provisional headers are shown. Disable cache to see full headers.`;
cautionTitle = ls
- `Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn't store the original request headers. Disable cache to see full request headers.`;
+ `Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn’t store the original request headers. Disable cache to see full request headers.`;
} else {
cautionText = ls`Provisional headers are shown`;
}
@@ -757,12 +758,14 @@
}
headersTreeElement.hidden = !length && !provisionalHeaders;
- for (let i = 0; i < length; ++i) {
- const headerTreeElement = new UI.TreeOutline.TreeElement(this._formatHeaderObject(headers[i]));
- headerTreeElement[_headerNameSymbol] = headers[i].name;
+ for (const header of headers) {
+ const headerTreeElement = new UI.TreeOutline.TreeElement(this._formatHeaderObject(header));
+ headerTreeElement[_headerNameSymbol] = header.name;
- if (headers[i].name.toLowerCase() === 'set-cookie') {
- const matchingBlockedReasons = blockedCookieLineToReasons.get(headers[i].value);
+ const headerId = header.name.toLowerCase();
+
+ if (headerId === 'set-cookie') {
+ const matchingBlockedReasons = blockedCookieLineToReasons.get(header.value);
if (matchingBlockedReasons) {
const icon = UI.Icon.Icon.create('smallicon-warning', '');
headerTreeElement.listItemElement.appendChild(icon);
@@ -779,6 +782,25 @@
}
headersTreeElement.appendChild(headerTreeElement);
+
+ if (headerId === 'x-client-data') {
+ // https://source.chromium.org/chromium/chromium/src/+/master:components/variations/proto/client_variations.proto;l=14-21
+ const {variationIds, triggerVariationIds} = ClientVariationsParser.parseClientVariations(header.value);
+ if (variationIds.length || triggerVariationIds.length) {
+ const element = createElement('div');
+ element.classList.add('x-client-data-details');
+ if (variationIds.length) {
+ element.createChild('div').textContent =
+ ls`Active client experiment variation IDs: ${variationIds.join(', ')}`;
+ }
+ if (triggerVariationIds.length) {
+ element.createChild('div').textContent =
+ ls`Active client experiment variation IDs that trigger server-side behavior: ${
+ triggerVariationIds.join(', ')}`;
+ }
+ headerTreeElement.listItemElement.appendChild(element);
+ }
+ }
}
}
diff --git a/front_end/network/module.json b/front_end/network/module.json
index 2df8cde..f53a3ce 100644
--- a/front_end/network/module.json
+++ b/front_end/network/module.json
@@ -176,6 +176,7 @@
],
"dependencies": [
"browser_sdk",
+ "client_variations",
"common",
"components",
"cookie_table",
diff --git a/front_end/network/network_strings.grdp b/front_end/network/network_strings.grdp
index add97b6..af310c8 100644
--- a/front_end/network/network_strings.grdp
+++ b/front_end/network/network_strings.grdp
@@ -48,6 +48,9 @@
<message name="IDS_DEVTOOLS_0db377921f4ce762c62526131097968f" desc="Text in Request Headers View of the Network panel">
General
</message>
+ <message name="IDS_DEVTOOLS_0edec22265ba6e09745b283f6f54ceba" desc="Text for X-Client-Data HTTP headers in Headers View of the Network panel">
+ Active client experiment variation IDs: <ph name="VARIATION_IDS">$1s<ex>111, 222, 333</ex></ph>
+ </message>
<message name="IDS_DEVTOOLS_0f591b1d87c91e77d4fa11dc6e44288c" desc="Text in Network Item View of the Network panel">
Request and response timeline
</message>
@@ -141,9 +144,6 @@
<message name="IDS_DEVTOOLS_2ad7f735dd6d0dedb0d010a612854a17" desc="An option in the user agent dropdown menu in the Network conditions tool">
<ph name="LOCKED_1">Internet Explorer 8</ph>
</message>
- <message name="IDS_DEVTOOLS_2cc979d2cc5eda80f702a242ad5242cf" desc="Tooltip to explain lack of raw headers for a particular network request">
- Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn't store the original request headers. Disable cache to see full request headers.
- </message>
<message name="IDS_DEVTOOLS_2d13df6f8b5e4c5af9f87e0dc39df69d" desc="Text in Network Data Grid Node of the Network panel">
Pending
</message>
@@ -168,6 +168,9 @@
<message name="IDS_DEVTOOLS_324c6483c84f17f8af6b9a0d20145dda" desc="Text in Network Log View of the Network panel">
<ph name="RESOURCESIZE">$1s<ex>10</ex></ph> B resources loaded by the page
</message>
+ <message name="IDS_DEVTOOLS_32ac16c44f3339f7da811c289390d4fe" desc="Text for X-Client-Data HTTP headers in Headers View of the Network panel">
+ Active client experiment variation IDs that trigger server-side behavior: <ph name="TRIGGER_VARIATION_IDS">$1s<ex>111, 222, 333</ex></ph>
+ </message>
<message name="IDS_DEVTOOLS_336439019ce67912717a20d54298bf24" desc="Text in Request Timing View of the Network panel">
Receiving Push
</message>
@@ -432,6 +435,9 @@
<message name="IDS_DEVTOOLS_9b5e92790ca7fec879dfd28355a224d1" desc="Text used to show that serviceworker fetch response source is HTTP cache">
From HTTP cache
</message>
+ <message name="IDS_DEVTOOLS_a1725c50b8a42b8b7af43912a64eb7d2" desc="Tooltip to explain lack of raw headers for a particular network request">
+ Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn’t store the original request headers. Disable cache to see full request headers.
+ </message>
<message name="IDS_DEVTOOLS_bb9fd331bd610fd877425ceff23708a7" desc="Time at which a response was retrieved">
Retrieval Time: <ph name="THIS__REQUEST_RESPONSERETRIEVALTIME">$1s<ex>Fri Apr 10 2020 17:20:27 GMT-0700 (Pacific Daylight Time)</ex></ph>
</message>
diff --git a/front_end/network/requestHeadersTree.css b/front_end/network/requestHeadersTree.css
index 99237dc..9b2a30c 100644
--- a/front_end/network/requestHeadersTree.css
+++ b/front_end/network/requestHeadersTree.css
@@ -161,6 +161,12 @@
background-color: #ffff78;
}
+.x-client-data-details {
+ padding-left: 10px;
+ word-break: break-word;
+ white-space: initial;
+}
+
@media (forced-colors: active) {
:host-context(.request-headers-tree) ol.tree-outline:not(.hide-selection-when-blurred) li.selected:focus {
background: Highlight;
diff --git a/front_end/shell.json b/front_end/shell.json
index 66b3fd3..085258b 100644
--- a/front_end/shell.json
+++ b/front_end/shell.json
@@ -1,6 +1,7 @@
{
"modules" : [
{ "name": "bindings", "type": "autostart" },
+ { "name": "browser_sdk", "type": "autostart" },
{ "name": "common", "type": "autostart" },
{ "name": "components", "type": "autostart"},
{ "name": "console_counters", "type": "autostart" },
@@ -11,17 +12,17 @@
{ "name": "persistence", "type": "autostart" },
{ "name": "platform", "type": "autostart" },
{ "name": "protocol_client", "type": "autostart" },
- { "name": "sdk", "type": "autostart" },
- { "name": "browser_sdk", "type": "autostart" },
{ "name": "root", "type": "autostart" },
+ { "name": "sdk", "type": "autostart" },
{ "name": "services", "type": "autostart" },
{ "name": "text_utils", "type": "autostart" },
{ "name": "ui", "type": "autostart" },
{ "name": "workspace", "type": "autostart" },
{ "name": "changes" },
- { "name": "cm" },
+ { "name": "client_variations" },
{ "name": "cm_modes" },
+ { "name": "cm" },
{ "name": "color_picker" },
{ "name": "console" },
{ "name": "coverage" },
@@ -31,10 +32,13 @@
{ "name": "formatter" },
{ "name": "heap_snapshot_model" },
{ "name": "inline_editor" },
+ { "name": "input"},
{ "name": "javascript_metadata" },
+ { "name": "marked" },
{ "name": "object_ui" },
{ "name": "perf_ui" },
{ "name": "profiler" },
+ { "name": "protocol_monitor"},
{ "name": "quick_open" },
{ "name": "search" },
{ "name": "settings" },
@@ -42,9 +46,6 @@
{ "name": "source_frame" },
{ "name": "sources" },
{ "name": "text_editor" },
- { "name": "workspace_diff" },
- { "name": "protocol_monitor"},
- { "name": "input"},
- { "name": "marked" }
+ { "name": "workspace_diff" }
]
}
diff --git a/scripts/eslint_rules/lib/es_modules_import.js b/scripts/eslint_rules/lib/es_modules_import.js
index bc5c658..63e58a9 100644
--- a/scripts/eslint_rules/lib/es_modules_import.js
+++ b/scripts/eslint_rules/lib/es_modules_import.js
@@ -24,6 +24,8 @@
path.join(FRONT_END_DIRECTORY, 'third_party', 'acorn-loose'),
// marked is exempt as it doesn't expose all its modules from the root file
path.join(FRONT_END_DIRECTORY, 'third_party', 'marked'),
+ // client-variations is exempt as it doesn't expose all its modules from the root file
+ path.join(FRONT_END_DIRECTORY, 'third_party', 'chromium', 'client-variations'),
]);
const CROSS_NAMESPACE_MESSAGE =
diff --git a/test/unittests/front_end/common/BUILD.gn b/test/unittests/front_end/common/BUILD.gn
index b0506b9..17e9554 100644
--- a/test/unittests/front_end/common/BUILD.gn
+++ b/test/unittests/front_end/common/BUILD.gn
@@ -23,7 +23,7 @@
]
deps = [
+ "../../../../front_end/client_variations:bundle",
"../../../../front_end/common:bundle",
- "../../../../front_end/third_party/chromium",
]
}
diff --git a/test/unittests/front_end/common/ClientVariationsParser_test.ts b/test/unittests/front_end/common/ClientVariationsParser_test.ts
index 08764e5..7cddab5 100644
--- a/test/unittests/front_end/common/ClientVariationsParser_test.ts
+++ b/test/unittests/front_end/common/ClientVariationsParser_test.ts
@@ -4,7 +4,7 @@
const {assert} = chai;
-import {parseClientVariations} from '../../../../front_end/third_party/chromium/client-variations/ClientVariationsParser.js';
+import {parseClientVariations} from '../../../../front_end/client_variations/client_variations.js';
describe('parseClientVariations', () => {
it('returns empty lists for unparseable text', () => {