Title: [232318] trunk
Revision
232318
Author
[email protected]
Date
2018-05-30 16:42:36 -0700 (Wed, 30 May 2018)

Log Message

Web Inspector: Annotate Same-Site cookies
https://bugs.webkit.org/show_bug.cgi?id=184897
<rdar://problem/35178209>

Reviewed by Brian Burg.

Source/_javascript_Core:

Update protocol to include cookie Same-Site policy.

* inspector/protocol/Page.json:

Source/WebCore:

Store and retrieve the Same-Site cookie policy from CFNetwork.

* inspector/agents/InspectorPageAgent.cpp:
(WebCore::cookieSameSitePolicyJSON): Added.
(WebCore::buildObjectForCookie): Modified to include cookie Same-Site policy.
* platform/Cookie.h:
(WebCore::Cookie::encode const): Encode Same-Site policy.
(WebCore::Cookie::decode): Decode Same-Site policy.
* platform/network/cocoa/CookieCocoa.mm:
(WebCore::portStringFromVector):
(WebCore::coreSameSitePolicy):
(WebCore::nsSameSitePolicy):
(WebCore::Cookie::operator NSHTTPCookie * _Nullable  const):
(WebCore::Cookie::operator NSHTTPCookie * const): Deleted.

Source/WebInspectorUI:

Add a new column for the value of the Same-Site cookie attribute to the resource cookie content
view (shown for a resource under the Network tab) and cookie storage content view (shown under
the Storage tab).

The SameSite column in the resource cookie content view reflects the parsing of the Same-Site
attribute from the HTTP response by Web Inspector. This parsing is materially consistent with
the parsing of the SameSite atttribute in CFNetwork. The Same-Site column in the cookie storage
content view reflects the Same-Site cookie policy associated with the cookies provided by the
network stack, if supported. This column will be blank on systems whose network stack does not
support Same-Site cookies (e.g libsoup).

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Controllers/HARBuilder.js:
(WI.HARBuilder.cookies):
* UserInterface/Models/Cookie.js:
(WI.Cookie):
(WI.Cookie.displayNameForSameSiteType):
(WI.Cookie.parseSameSiteAttributeValue):
(WI.Cookie.parseSetCookieResponseHeader):
* UserInterface/Views/CookieStorageContentView.js:
(WI.CookieStorageContentView.prototype._rebuildTable):
(WI.CookieStorageContentView.prototype._sortDataGrid):
* UserInterface/Views/ResourceCookiesContentView.js:
(WI.ResourceCookiesContentView.prototype.tablePopulateCell):
(WI.ResourceCookiesContentView.prototype._generateSortComparator):
(WI.ResourceCookiesContentView.prototype._refreshResponseCookiesSection):

LayoutTests:

Update an existing test to ensure we include cookie details in the HTTP Archive (HAR) report.

* http/tests/inspector/network/har/har-page-expected.txt:
* http/tests/inspector/network/har/har-page.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (232317 => 232318)


--- trunk/LayoutTests/ChangeLog	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/LayoutTests/ChangeLog	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,3 +1,16 @@
+2018-05-30  Daniel Bates  <[email protected]>
+
+        Web Inspector: Annotate Same-Site cookies
+        https://bugs.webkit.org/show_bug.cgi?id=184897
+        <rdar://problem/35178209>
+
+        Reviewed by Brian Burg.
+
+        Update an existing test to ensure we include cookie details in the HTTP Archive (HAR) report.
+
+        * http/tests/inspector/network/har/har-page-expected.txt:
+        * http/tests/inspector/network/har/har-page.html:
+
 2018-05-30  John Wilander  <[email protected]>
 
         Add console logging to grant-storage-access-under-opener.html to assess its flakiness

Modified: trunk/LayoutTests/http/tests/inspector/network/har/har-page-expected.txt (232317 => 232318)


--- trunk/LayoutTests/http/tests/inspector/network/har/har-page-expected.txt	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/LayoutTests/http/tests/inspector/network/har/har-page-expected.txt	2018-05-30 23:42:36 UTC (rev 232318)
@@ -103,6 +103,641 @@
           "wait": "<filtered>",
           "receive": "<filtered>"
         }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/cookie-utilities.js",
+          "httpVersion": "<filtered>",
+          "cookies": [],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "application/x-_javascript_",
+            "text": "<filtered>"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "simple",
+              "value": "simple",
+              "expires": "",
+              "httpOnly": false,
+              "secure": false
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "simple",
+              "value": "simple"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "path",
+              "value": "path",
+              "path": "/A/B/C",
+              "expires": "",
+              "httpOnly": false,
+              "secure": false
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "simple",
+              "value": "simple"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "secure",
+              "value": "secure",
+              "expires": "",
+              "httpOnly": false,
+              "secure": true
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "simple",
+              "value": "simple"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "secure-and-http-only",
+              "value": "secure-and-http-only",
+              "expires": "",
+              "httpOnly": true,
+              "secure": true
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "simple",
+              "value": "simple"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "with-expiration",
+              "value": "with-expiration",
+              "expires": "5000-01-04T08:00:00.000Z",
+              "httpOnly": false,
+              "secure": false
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "simple",
+              "value": "simple"
+            },
+            {
+              "name": "with-expiration",
+              "value": "with-expiration"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "http-only",
+              "value": "http-only",
+              "expires": "",
+              "httpOnly": true,
+              "secure": false
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "http-only",
+              "value": "http-only"
+            },
+            {
+              "name": "simple",
+              "value": "simple"
+            },
+            {
+              "name": "with-expiration",
+              "value": "with-expiration"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "same-site-strict",
+              "value": "same-site-strict",
+              "path": "/",
+              "expires": "",
+              "httpOnly": false,
+              "secure": false,
+              "sameSite": "Strict"
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "http-only",
+              "value": "http-only"
+            },
+            {
+              "name": "simple",
+              "value": "simple"
+            },
+            {
+              "name": "with-expiration",
+              "value": "with-expiration"
+            },
+            {
+              "name": "same-site-strict",
+              "value": "same-site-strict"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "same-site-implicit-strict",
+              "value": "same-site-implicit-strict",
+              "path": "/",
+              "expires": "",
+              "httpOnly": false,
+              "secure": false,
+              "sameSite": "Strict"
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "http-only",
+              "value": "http-only"
+            },
+            {
+              "name": "simple",
+              "value": "simple"
+            },
+            {
+              "name": "with-expiration",
+              "value": "with-expiration"
+            },
+            {
+              "name": "same-site-implicit-strict",
+              "value": "same-site-implicit-strict"
+            },
+            {
+              "name": "same-site-strict",
+              "value": "same-site-strict"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "same-site-strict-because-invalid-SameSite-value",
+              "value": "same-site-strict-because-invalid-SameSite-value",
+              "path": "/",
+              "expires": "",
+              "httpOnly": false,
+              "secure": false,
+              "sameSite": "Strict"
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
+      },
+      {
+        "pageref": "page_0",
+        "startedDateTime": "<filtered>",
+        "time": "<filtered>",
+        "request": {
+          "method": "GET",
+          "url": "http://127.0.0.1:8000/cookies/resources/setCookies.cgi",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "http-only",
+              "value": "http-only"
+            },
+            {
+              "name": "simple",
+              "value": "simple"
+            },
+            {
+              "name": "with-expiration",
+              "value": "with-expiration"
+            },
+            {
+              "name": "same-site-implicit-strict",
+              "value": "same-site-implicit-strict"
+            },
+            {
+              "name": "same-site-strict",
+              "value": "same-site-strict"
+            },
+            {
+              "name": "same-site-strict-because-invalid-SameSite-value",
+              "value": "same-site-strict-because-invalid-SameSite-value"
+            }
+          ],
+          "headers": "<filtered>",
+          "queryString": [],
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "response": {
+          "status": 200,
+          "statusText": "OK",
+          "httpVersion": "<filtered>",
+          "cookies": [
+            {
+              "name": "same-site-lax",
+              "value": "same-site-lax",
+              "path": "/",
+              "expires": "",
+              "httpOnly": false,
+              "secure": false,
+              "sameSite": "Lax"
+            }
+          ],
+          "headers": "<filtered>",
+          "content": {
+            "size": "<filtered>",
+            "compression": 0,
+            "mimeType": "text/plain"
+          },
+          "redirectURL": "",
+          "headersSize": "<filtered>",
+          "bodySize": "<filtered>"
+        },
+        "cache": {},
+        "timings": {
+          "blocked": "<filtered>",
+          "dns": "<filtered>",
+          "connect": "<filtered>",
+          "ssl": -1,
+          "send": "<filtered>",
+          "wait": "<filtered>",
+          "receive": "<filtered>"
+        }
       }
     ]
   }

Modified: trunk/LayoutTests/http/tests/inspector/network/har/har-page.html (232317 => 232318)


--- trunk/LayoutTests/http/tests/inspector/network/har/har-page.html	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/LayoutTests/http/tests/inspector/network/har/har-page.html	2018-05-30 23:42:36 UTC (rev 232318)
@@ -3,6 +3,7 @@
 <head>
 <meta charset="utf-8">
 <script src=""
+<script src=""
 <script>
 function test()
 {
@@ -49,6 +50,10 @@
             return "<filtered>";
         }
 
+        // Sort cookies by name to make cookie order deterministic between test runs.
+        if (key === "cookies")
+            value.sort((a, b) => { return a.name - b.name; });
+
         // Since cache may or may not be used, timing data may be variable.
         // NOTE: SSL should always be -1 for this test case.
         if (key === "time")
@@ -77,10 +82,14 @@
         async test() {
             InspectorTest.reloadPage({ignoreCache: true});
             await InspectorTest.awaitEvent("LoadComplete");
+            InspectorTest.evaluateInPage("setup()");
+            await InspectorTest.awaitEvent("SetupComplete");
 
             let resources = [WI.frameResourceManager.mainFrame.mainResource, ...WI.frameResourceManager.mainFrame.resourceCollection];
             let har = await WI.HARBuilder.buildArchive(resources);
             InspectorTest.json(har, HARJSONFilter);
+            InspectorTest.evaluateInPage("cleanup()");
+            await InspectorTest.awaitEvent("CleanComplete");
         }
     });
 
@@ -91,6 +100,31 @@
 <body _onload_="runTest()">
 <p>HAR Page Test.</p>
 <script>
+async function setup()
+{
+    await resetCookies();
+    await setCookie("simple", "simple");
+    await setCookie("path", "path", {"path": "/A/B/C"}); // This cookie will not be sent in subsequent requests from this page.
+
+    // Secure cookies will only be sent in subsequent requests from this page if the page was served over HTTPS.
+    await setCookie("secure", "secure", {"secure": null});
+    await setCookie("secure-and-http-only", "secure-and-http-only", {"secure": null, "HttpOnly": null});
+
+    await setCookie("with-expiration", "with-expiration", {"Expires": new Date("01/04/5000").toGMTString()});
+    await setCookie("http-only", "http-only", {"HttpOnly": null});
+    await setCookie("same-site-strict", "same-site-strict", {"SameSite": "Strict", "path": "/"});
+    await setCookie("same-site-implicit-strict", "same-site-implicit-strict", {"SameSite": null, "path": "/"});
+    await setCookie("same-site-strict-because-invalid-SameSite-value", "same-site-strict-because-invalid-SameSite-value", {"SameSite": "invalid", "path": "/"});
+    await setCookie("same-site-lax", "same-site-lax", {"SameSite": "Lax", "path": "/"});
+    TestPage.dispatchEventToFrontend("SetupComplete");
+}
+
+async function cleanup()
+{
+    await resetCookies();
+    TestPage.dispatchEventToFrontend("CleanComplete");
+}
+
 window.addEventListener("load", () => {
     TestPage.dispatchEventToFrontend("LoadComplete");
 });

Modified: trunk/Source/_javascript_Core/ChangeLog (232317 => 232318)


--- trunk/Source/_javascript_Core/ChangeLog	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,3 +1,15 @@
+2018-05-30  Daniel Bates  <[email protected]>
+
+        Web Inspector: Annotate Same-Site cookies
+        https://bugs.webkit.org/show_bug.cgi?id=184897
+        <rdar://problem/35178209>
+
+        Reviewed by Brian Burg.
+
+        Update protocol to include cookie Same-Site policy.
+
+        * inspector/protocol/Page.json:
+
 2018-05-29  Keith Miller  <[email protected]>
 
         Error instances should not strongly hold onto StackFrames

Modified: trunk/Source/_javascript_Core/inspector/protocol/Page.json (232317 => 232318)


--- trunk/Source/_javascript_Core/inspector/protocol/Page.json	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/_javascript_Core/inspector/protocol/Page.json	2018-05-30 23:42:36 UTC (rev 232318)
@@ -16,6 +16,12 @@
             "description": "Coordinate system used by supplied coordinates."
         },
         {
+            "id": "CookieSameSitePolicy",
+            "type": "string",
+            "enum": ["None", "Lax", "Strict"],
+            "description": "Same-Site policy of a cookie."
+        },
+        {
             "id": "Frame",
             "type": "object",
             "description": "Information about the Frame on the page.",
@@ -76,7 +82,8 @@
                 { "name": "size", "type": "integer", "description": "Cookie size." },
                 { "name": "httpOnly", "type": "boolean", "description": "True if cookie is http-only." },
                 { "name": "secure", "type": "boolean", "description": "True if cookie is secure." },
-                { "name": "session", "type": "boolean", "description": "True in case of session cookie." }
+                { "name": "session", "type": "boolean", "description": "True in case of session cookie." },
+                { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." }
             ]
         }
     ],

Modified: trunk/Source/WebCore/ChangeLog (232317 => 232318)


--- trunk/Source/WebCore/ChangeLog	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebCore/ChangeLog	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,5 +1,28 @@
 2018-05-30  Daniel Bates  <[email protected]>
 
+        Web Inspector: Annotate Same-Site cookies
+        https://bugs.webkit.org/show_bug.cgi?id=184897
+        <rdar://problem/35178209>
+
+        Reviewed by Brian Burg.
+
+        Store and retrieve the Same-Site cookie policy from CFNetwork.
+
+        * inspector/agents/InspectorPageAgent.cpp:
+        (WebCore::cookieSameSitePolicyJSON): Added.
+        (WebCore::buildObjectForCookie): Modified to include cookie Same-Site policy. 
+        * platform/Cookie.h:
+        (WebCore::Cookie::encode const): Encode Same-Site policy.
+        (WebCore::Cookie::decode): Decode Same-Site policy.
+        * platform/network/cocoa/CookieCocoa.mm:
+        (WebCore::portStringFromVector):
+        (WebCore::coreSameSitePolicy):
+        (WebCore::nsSameSitePolicy):
+        (WebCore::Cookie::operator NSHTTPCookie * _Nullable  const):
+        (WebCore::Cookie::operator NSHTTPCookie * const): Deleted.
+
+2018-05-30  Daniel Bates  <[email protected]>
+
         NavigationAction does not need to hold initiating DOM Event
         https://bugs.webkit.org/show_bug.cgi?id=185958
         <rdar://problem/40531539>

Modified: trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp (232317 => 232318)


--- trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp	2018-05-30 23:42:36 UTC (rev 232318)
@@ -336,6 +336,20 @@
     frame.loader().changeLocation(WTFMove(frameLoadRequest));
 }
 
+static Inspector::Protocol::Page::CookieSameSitePolicy cookieSameSitePolicyJSON(Cookie::SameSitePolicy policy)
+{
+    switch (policy) {
+    case Cookie::SameSitePolicy::None:
+        return Inspector::Protocol::Page::CookieSameSitePolicy::None;
+    case Cookie::SameSitePolicy::Lax:
+        return Inspector::Protocol::Page::CookieSameSitePolicy::Lax;
+    case Cookie::SameSitePolicy::Strict:
+        return Inspector::Protocol::Page::CookieSameSitePolicy::Strict;
+    }
+    ASSERT_NOT_REACHED();
+    return Inspector::Protocol::Page::CookieSameSitePolicy::None;
+}
+
 static Ref<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
 {
     return Inspector::Protocol::Page::Cookie::create()
@@ -348,6 +362,7 @@
         .setHttpOnly(cookie.httpOnly)
         .setSecure(cookie.secure)
         .setSession(cookie.session)
+        .setSameSite(cookieSameSitePolicyJSON(cookie.sameSite))
         .release();
 }
 

Modified: trunk/Source/WebCore/platform/Cookie.h (232317 => 232318)


--- trunk/Source/WebCore/platform/Cookie.h	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebCore/platform/Cookie.h	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Joseph Pecoraro. All rights reserved.
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 #pragma once
 
 #include "URL.h"
+#include <wtf/EnumTraits.h>
 #include <wtf/text/StringHash.h>
 #include <wtf/text/WTFString.h>
 
@@ -85,6 +86,9 @@
     String comment;
     URL commentURL;
     Vector<uint16_t> ports;
+
+    enum class SameSitePolicy { None, Lax, Strict };
+    SameSitePolicy sameSite { SameSitePolicy::None };
 };
 
 struct CookieHash {
@@ -115,6 +119,7 @@
     encoder << comment;
     encoder << commentURL;
     encoder << ports;
+    encoder << sameSite;
 }
 
 template<class Decoder>
@@ -145,6 +150,8 @@
         return std::nullopt;
     if (!decoder.decode(cookie.ports))
         return std::nullopt;
+    if (!decoder.decode(cookie.sameSite))
+        return std::nullopt;
     return cookie;
 }
 
@@ -160,4 +167,12 @@
         static void constructDeletedValue(WebCore::Cookie& slot) { slot = WebCore::Cookie(WTF::HashTableDeletedValue); }
         static bool isDeletedValue(const WebCore::Cookie& slot) { return slot.name.isHashTableDeletedValue(); }
     };
+    template<> struct EnumTraits<WebCore::Cookie::SameSitePolicy> {
+    using values = EnumValues<
+        WebCore::Cookie::SameSitePolicy,
+        WebCore::Cookie::SameSitePolicy::None,
+        WebCore::Cookie::SameSitePolicy::Lax,
+        WebCore::Cookie::SameSitePolicy::Strict
+    >;
+};
 }

Modified: trunk/Source/WebCore/platform/network/cocoa/CookieCocoa.mm (232317 => 232318)


--- trunk/Source/WebCore/platform/network/cocoa/CookieCocoa.mm	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebCore/platform/network/cocoa/CookieCocoa.mm	2018-05-30 23:42:36 UTC (rev 232318)
@@ -26,6 +26,19 @@
 #import "config.h"
 #import "Cookie.h"
 
+// FIXME: Remove NS_ASSUME_NONNULL_BEGIN/END and all _Nullable annotations once we remove the NSHTTPCookie forward declaration below.
+NS_ASSUME_NONNULL_BEGIN
+
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 && __MAC_OS_X_VERSION_MAX_ALLOWED < 101500) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000 && __IPHONE_OS_VERSION_MAX_ALLOWED < 130000)
+typedef NSString * NSHTTPCookieStringPolicy;
+@interface NSHTTPCookie (Staging)
+@property (nullable, readonly, copy) NSHTTPCookieStringPolicy sameSitePolicy;
+@end
+
+static NSString * const NSHTTPCookieSameSiteLax = @"lax";
+static NSString * const NSHTTPCookieSameSiteStrict = @"strict";
+#endif
+
 namespace WebCore {
 
 static Vector<uint16_t> portVectorFromList(NSArray<NSNumber *> *portList)
@@ -39,7 +52,7 @@
     return ports;
 }
 
-static NSString *portStringFromVector(const Vector<uint16_t>& ports)
+static NSString * _Nullable portStringFromVector(const Vector<uint16_t>& ports)
 {
     if (ports.isEmpty())
         return nil;
@@ -71,6 +84,32 @@
     return 0;
 }
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
+static Cookie::SameSitePolicy coreSameSitePolicy(NSHTTPCookieStringPolicy _Nullable policy)
+{
+    if (!policy)
+        return Cookie::SameSitePolicy::None;
+    if ([policy isEqualToString:NSHTTPCookieSameSiteLax])
+        return Cookie::SameSitePolicy::Lax;
+    if ([policy isEqualToString:NSHTTPCookieSameSiteStrict])
+        return Cookie::SameSitePolicy::Strict;
+    ASSERT_NOT_REACHED();
+    return Cookie::SameSitePolicy::None;
+}
+
+static NSHTTPCookieStringPolicy _Nullable nsSameSitePolicy(Cookie::SameSitePolicy policy)
+{
+    switch (policy) {
+    case Cookie::SameSitePolicy::None:
+        return nil;
+    case Cookie::SameSitePolicy::Lax:
+        return NSHTTPCookieSameSiteLax;
+    case Cookie::SameSitePolicy::Strict:
+        return NSHTTPCookieSameSiteStrict;
+    }
+}
+#endif
+
 Cookie::Cookie(NSHTTPCookie *cookie)
     : name { cookie.name }
     , value { cookie.value }
@@ -85,14 +124,18 @@
     , commentURL { cookie.commentURL }
     , ports { portVectorFromList(cookie.portList) }
 {
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
+    if ([cookie respondsToSelector:@selector(sameSitePolicy)])
+        sameSite = coreSameSitePolicy(cookie.sameSitePolicy);
+#endif
 }
 
-Cookie::operator NSHTTPCookie *() const
+Cookie::operator NSHTTPCookie * _Nullable () const
 {
     if (isNull())
         return nil;
 
-    NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:13];
+    NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:14];
 
     if (!comment.isNull())
         [properties setObject:(NSString *)comment forKey:NSHTTPCookieComment];
@@ -134,6 +177,11 @@
     if (httpOnly)
         [properties setObject:@YES forKey:@"HttpOnly"];
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
+    if (auto* sameSitePolicy = nsSameSitePolicy(sameSite))
+        [properties setObject:sameSitePolicy forKey:@"SameSite"];
+#endif
+
     [properties setObject:@"1" forKey:NSHTTPCookieVersion];
 
     return [NSHTTPCookie cookieWithProperties:properties];
@@ -156,4 +204,6 @@
     return static_cast<NSHTTPCookie *>(*this).hash;
 }
 
+NS_ASSUME_NONNULL_END
+
 } // namespace WebCore

Modified: trunk/Source/WebInspectorUI/ChangeLog (232317 => 232318)


--- trunk/Source/WebInspectorUI/ChangeLog	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebInspectorUI/ChangeLog	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,3 +1,38 @@
+2018-05-30  Daniel Bates  <[email protected]>
+
+        Web Inspector: Annotate Same-Site cookies
+        https://bugs.webkit.org/show_bug.cgi?id=184897
+        <rdar://problem/35178209>
+
+        Reviewed by Brian Burg.
+
+        Add a new column for the value of the Same-Site cookie attribute to the resource cookie content
+        view (shown for a resource under the Network tab) and cookie storage content view (shown under
+        the Storage tab).
+
+        The SameSite column in the resource cookie content view reflects the parsing of the Same-Site
+        attribute from the HTTP response by Web Inspector. This parsing is materially consistent with
+        the parsing of the SameSite atttribute in CFNetwork. The Same-Site column in the cookie storage
+        content view reflects the Same-Site cookie policy associated with the cookies provided by the
+        network stack, if supported. This column will be blank on systems whose network stack does not
+        support Same-Site cookies (e.g libsoup).
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Controllers/HARBuilder.js:
+        (WI.HARBuilder.cookies):
+        * UserInterface/Models/Cookie.js:
+        (WI.Cookie):
+        (WI.Cookie.displayNameForSameSiteType):
+        (WI.Cookie.parseSameSiteAttributeValue):
+        (WI.Cookie.parseSetCookieResponseHeader):
+        * UserInterface/Views/CookieStorageContentView.js:
+        (WI.CookieStorageContentView.prototype._rebuildTable):
+        (WI.CookieStorageContentView.prototype._sortDataGrid):
+        * UserInterface/Views/ResourceCookiesContentView.js:
+        (WI.ResourceCookiesContentView.prototype.tablePopulateCell):
+        (WI.ResourceCookiesContentView.prototype._generateSortComparator):
+        (WI.ResourceCookiesContentView.prototype._refreshResponseCookiesSection):
+
 2018-05-25  Matt Baker  <[email protected]>
 
         Web Inspector: Popover dismissed while attempting to move cursor inside

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (232317 => 232318)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-05-30 23:42:36 UTC (rev 232318)
@@ -811,6 +811,7 @@
 localizedStrings["Right"] = "Right";
 localizedStrings["Role"] = "Role";
 localizedStrings["Rule"] = "Rule";
+localizedStrings["Same-Site"] = "Same-Site";
 localizedStrings["Samples"] = "Samples";
 localizedStrings["Save File"] = "Save File";
 localizedStrings["Save Selected"] = "Save Selected";

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/HARBuilder.js (232317 => 232318)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/HARBuilder.js	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/HARBuilder.js	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -177,6 +177,8 @@
                 json.expires = HARBuilder.date(cookie.expirationDate(requestSentDate));
                 json.httpOnly = cookie.httpOnly;
                 json.secure = cookie.secure;
+                if (cookie.sameSite !== WI.Cookie.SameSiteType.None)
+                    json.sameSite = cookie.sameSite;
             }
 
             result.push(json);

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Cookie.js (232317 => 232318)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Cookie.js	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Cookie.js	2018-05-30 23:42:36 UTC (rev 232318)
@@ -25,7 +25,7 @@
 
 WI.Cookie = class Cookie
 {
-    constructor(type, name, value, raw, expires, maxAge, path, domain, secure, httpOnly)
+    constructor(type, name, value, raw, expires, maxAge, path, domain, secure, httpOnly, sameSite)
     {
         console.assert(Object.values(WI.Cookie.Type).includes(type));
         console.assert(typeof name === "string");
@@ -37,6 +37,7 @@
         console.assert(!domain || typeof domain === "string");
         console.assert(!secure || typeof secure === "boolean");
         console.assert(!httpOnly || typeof httpOnly === "boolean");
+        console.assert(!sameSite || Object.values(WI.Cookie.SameSiteType).includes(sameSite));
 
         this.type = type;
         this.name = name || "";
@@ -50,6 +51,7 @@
             this.domain = domain || null;
             this.secure = secure || false;
             this.httpOnly = httpOnly || false;
+            this.sameSite = sameSite || WI.Cookie.SameSiteType.None;
         }
     }
 
@@ -99,6 +101,35 @@
         return cookies;
     }
 
+    static displayNameForSameSiteType(sameSiteType)
+    {
+        switch (sameSiteType) {
+        case WI.Cookie.SameSiteType.None:
+            return WI.unlocalizedString("None");
+        case WI.Cookie.SameSiteType.Lax:
+            return WI.unlocalizedString("Lax");
+        case WI.Cookie.SameSiteType.Strict:
+            return WI.unlocalizedString("Strict");
+        default:
+            console.error("Invalid SameSite type", sameSiteType);
+            return sameSiteType;
+        }
+    }
+
+    // Derived from <https://tools.ietf.org/html/draft-west-first-party-cookies-06#section-3.2>.
+    static parseSameSiteAttributeValue(attributeValue)
+    {
+        if (!attributeValue)
+            return WI.Cookie.SameSiteType.Strict;
+        switch (attributeValue.toLowerCase()) {
+        case "lax":
+            return WI.Cookie.SameSiteType.Lax;
+        case "strict":
+        default:
+            return WI.Cookie.SameSiteType.Strict;
+        }
+    }
+
     static parseSetCookieResponseHeader(header)
     {
         if (!header)
@@ -122,6 +153,7 @@
         let domain = null;
         let secure = false;
         let httpOnly = false;
+        let sameSite = WI.Cookie.SameSiteType.None;
 
         // Parse Attributes
         let remaining = header.substr(nameValueMatch[0].length);
@@ -171,6 +203,9 @@
                 console.assert(!attributeValue);
                 httpOnly = true;
                 break;
+            case "samesite":
+                sameSite = WI.Cookie.parseSameSiteAttributeValue(attributeValue);
+                break;
             default:
                 console.warn("Unknown Cookie attribute:", attribute);
                 break;
@@ -177,7 +212,7 @@
             }
         }
 
-        return new WI.Cookie(WI.Cookie.Type.Response, name, value, header, expires, maxAge, path, domain, secure, httpOnly);
+        return new WI.Cookie(WI.Cookie.Type.Response, name, value, header, expires, maxAge, path, domain, secure, httpOnly, sameSite);
     }
 }
 
@@ -185,3 +220,10 @@
     Request: "request",
     Response: "response",
 };
+
+// Keep these in sync with the "CookieSameSitePolicy" enum defined by the "Page" domain.
+WI.Cookie.SameSiteType = {
+    None: "None",
+    Lax: "Lax",
+    Strict: "Strict",
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CookieStorageContentView.js (232317 => 232318)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CookieStorageContentView.js	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CookieStorageContentView.js	2018-05-30 23:42:36 UTC (rev 232318)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015, 2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -73,7 +73,7 @@
     {
         // FIXME <https://webkit.org/b/151400>: If there are no cookies, add placeholder explanatory text.
         if (!this._dataGrid) {
-            var columns = {name: {}, value: {}, domain: {}, path: {}, expires: {}, size: {}, http: {}, secure: {}};
+            var columns = {name: {}, value: {}, domain: {}, path: {}, expires: {}, size: {}, http: {}, secure: {}, sameSite: {} };
 
             columns.name.title = WI.UIString("Name");
             columns.name.sortable = true;
@@ -87,31 +87,35 @@
 
             columns.domain.title = WI.UIString("Domain");
             columns.domain.sortable = true;
-            columns.domain.width = "7%";
+            columns.domain.width = "6%";
 
             columns.path.title = WI.UIString("Path");
             columns.path.sortable = true;
-            columns.path.width = "7%";
+            columns.path.width = "6%";
 
             columns.expires.title = WI.UIString("Expires");
             columns.expires.sortable = true;
-            columns.expires.width = "7%";
+            columns.expires.width = "6%";
 
             columns.size.title = WI.UIString("Size");
             columns.size.aligned = "right";
             columns.size.sortable = true;
-            columns.size.width = "7%";
+            columns.size.width = "6%";
 
             columns.http.title = WI.UIString("HTTP");
             columns.http.aligned = "centered";
             columns.http.sortable = true;
-            columns.http.width = "7%";
+            columns.http.width = "6%";
 
             columns.secure.title = WI.UIString("Secure");
             columns.secure.aligned = "centered";
             columns.secure.sortable = true;
-            columns.secure.width = "7%";
+            columns.secure.width = "6%";
 
+            columns.sameSite.title = WI.UIString("Same-Site");
+            columns.sameSite.sortable = true;
+            columns.sameSite.width = "6%";
+
             this._dataGrid = new WI.DataGrid(columns, null, this._deleteCallback.bind(this));
             this._dataGrid.columnChooserEnabled = true;
             this._dataGrid.addEventListener(WI.DataGrid.Event.SortChanged, this._sortDataGrid, this);
@@ -125,7 +129,7 @@
         console.assert(this._dataGrid);
         this._dataGrid.removeChildren();
 
-        for (var cookie of this._cookies) {
+        for (let cookie of this._cookies) {
             const checkmark = "\u2713";
             var data = {
                 name: cookie.name,
@@ -136,6 +140,7 @@
                 size: Number.bytesToString(cookie.size),
                 http: cookie.httpOnly ? checkmark : "",
                 secure: cookie.secure ? checkmark : "",
+                sameSite: cookie.sameSite ? WI.Cookie.displayNameForSameSiteType(WI.Cookie.parseSameSiteAttributeValue(cookie.sameSite)) : "",
             };
 
             if (cookie.type !== WI.CookieType.Request)
@@ -203,6 +208,7 @@
             case "size": comparator = numberCompare.bind(this, "size"); break;
             case "http": comparator = localeCompare.bind(this, "http"); break;
             case "secure": comparator = localeCompare.bind(this, "secure"); break;
+            case "sameSite": comparator = localeCompare.bind(this, "sameSite"); break;
             case "name":
             default: comparator = localeCompare.bind(this, "name"); break;
         }

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js (232317 => 232318)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js	2018-05-30 23:34:12 UTC (rev 232317)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js	2018-05-30 23:42:36 UTC (rev 232318)
@@ -89,6 +89,9 @@
         case "httpOnly":
             cell.textContent = cookie.httpOnly ? checkmark : zeroWidthSpace;
             break;
+        case "sameSite":
+            cell.textContent = cookie.sameSite === WI.Cookie.SameSiteType.None ? emDash : WI.Cookie.displayNameForSameSiteType(cookie.sameSite);
+            break;
         }
 
         return cell;
@@ -146,6 +149,7 @@
         case "value":
         case "domain":
         case "path":
+        case "sameSite":
             // String.
             comparator = (a, b) => (a[sortColumnIdentifier] || "").extendedLocaleCompare(b[sortColumnIdentifier] || "");
             break;
@@ -248,6 +252,7 @@
             this._responseCookiesTable.addColumn(new WI.TableColumn("maxAge", WI.unlocalizedString("Max-Age"), {maxWidth: 90, align: "right"}));
             this._responseCookiesTable.addColumn(new WI.TableColumn("secure", WI.unlocalizedString("Secure"), {minWidth: 55, maxWidth: 65, align: "center"}));
             this._responseCookiesTable.addColumn(new WI.TableColumn("httpOnly", WI.unlocalizedString("HttpOnly"), {minWidth: 55, maxWidth: 65, align: "center"}));
+            this._responseCookiesTable.addColumn(new WI.TableColumn("sameSite", WI.unlocalizedString("SameSite"), {minWidth: 55, maxWidth: 65}));
             if (!this._responseCookiesTable.sortColumnIdentifier) {
                 this._responseCookiesTable.sortOrder = WI.Table.SortOrder.Ascending;
                 this._responseCookiesTable.sortColumnIdentifier = "name";
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to