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/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);
+        }
+      }
     }
   }