Bug 177988 - Web Inspector: Network Tab - Cookies Detail View
Summary: Web Inspector: Network Tab - Cookies Detail View
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Inspector (show other bugs)
Version: WebKit Nightly Build
Hardware: All All
: P2 Normal
Assignee: Joseph Pecoraro
URL:
Keywords: InRadar
Depends on: 177896
Blocks:
  Show dependency treegraph
 
Reported: 2017-10-05 20:01 PDT by Joseph Pecoraro
Modified: 2017-10-09 12:33 PDT (History)
6 users (show)

See Also:


Attachments
[IMAGE] Cookies View (137.45 KB, image/png)
2017-10-05 20:12 PDT, Joseph Pecoraro
no flags Details
[IMAGE] Cookies - some empty (109.14 KB, image/png)
2017-10-05 20:12 PDT, Joseph Pecoraro
no flags Details
[IMAGE] Headers - Set-Cookie (before) (184.08 KB, image/png)
2017-10-05 20:12 PDT, Joseph Pecoraro
no flags Details
[IMAGE] Headers - Set-Cookie (after) (198.47 KB, image/png)
2017-10-05 20:13 PDT, Joseph Pecoraro
no flags Details
[PATCH] Proposed Fix (57.66 KB, patch)
2017-10-05 20:13 PDT, Joseph Pecoraro
no flags Details | Formatted Diff | Diff
[PATCH] Proposed Fix (58.64 KB, patch)
2017-10-08 14:41 PDT, Joseph Pecoraro
bburg: review+
bburg: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Joseph Pecoraro 2017-10-05 20:01:52 PDT
Web Inspector: Network Tab - Cookies Detail View

It can be useful to parse out the cookies from the difficult to read `Cookie` request and `Set-Cookie` response headers into tables. We do this already for cookies on a per-domain basis but this show more specifically what happened in an individual request.
Comment 1 Joseph Pecoraro 2017-10-05 20:02:17 PDT
<rdar://problem/34071927>
Comment 2 Joseph Pecoraro 2017-10-05 20:12:12 PDT
Created attachment 322974 [details]
[IMAGE] Cookies View
Comment 3 Joseph Pecoraro 2017-10-05 20:12:36 PDT
Created attachment 322975 [details]
[IMAGE] Cookies - some empty
Comment 4 Joseph Pecoraro 2017-10-05 20:12:58 PDT
Created attachment 322976 [details]
[IMAGE] Headers - Set-Cookie (before)
Comment 5 Joseph Pecoraro 2017-10-05 20:13:08 PDT
Created attachment 322977 [details]
[IMAGE] Headers - Set-Cookie (after)
Comment 6 Joseph Pecoraro 2017-10-05 20:13:23 PDT
Created attachment 322978 [details]
[PATCH] Proposed Fix
Comment 7 Joseph Pecoraro 2017-10-05 20:38:09 PDT
Cookie I need to test:

> name=value==;Domain=.example.com;Expires=Wed, 04-Apr-2018 03:34:02 GMT

I'm looking for '; ' but it appears some servers send cookies without the space?!
Comment 8 Devin Rousso 2017-10-06 00:19:31 PDT
Comment on attachment 322978 [details]
[PATCH] Proposed Fix

View in context: https://bugs.webkit.org/attachment.cgi?id=322978&action=review

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:28
> +    constructor(type, name, value, raw, expires, maxAge, path, domain, secure, httpOnly)

I'd like to move more WebInspector code to having "optional" parameters be inside of an `options` argument, as it makes future changes to widespread usage much simpler.  That being said, I'm not sure how much cookies will change, but it might be worth it regardless.

    constructor(type, name, value, {raw, expires, maxAge, path, domain, secure, httpOnly} = {})

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:30
> +        console.assert(type === WI.Cookie.Type.Request || type === WI.Cookie.Type.Response);

You could "simplify" this by using Object.values.  It isn't necessarily simpler, but it is a bit more future-proof.

    console.assert(Object.values(WI.Cookie.Type).includes(type));

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:43
> +        this.name = name || "";
> +        this.value = value || "";

Since you assert above, it it necessary to have a default value?

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:73
> +            let match = pair.match(/^(?<name>[^\s=]+)[ \t]*=[ \t]*(?<value>.*)$/);

In this regex (and the others below) you check for `[^\s]`, but then use `[ \t]` later on.  Is there a reason for this difference?  I would think that they would match.

    let match = pair.match(/^(?<name>[^ \t=]+)[ \t]*=[ \t]*(?<value>.*)$/);

OR

    let match = pair.match(/^(?<name>[^\s=]+)\s*=\s*(?<value>.*)$/);

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:117
> +            let match = attribute.match(/^(?<name>[^\s=]+)(?:=(?<value>.*))?$/);

Are attributes not allowed to have spaces around the "=" (assuming it exists)?

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:30
> +        super(null);

NIT: use a const variable.

    const representedObject = null;
    super(representedObject);

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:99
> +    initialLayout()

Add `super.initialLayout()` call, or a comment as to why it isn't needed/wanted.

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:138
> +            return;

Style: since this function returns a value, this should be `return null;`.  I think ESLint should show a warning for this.

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:179
> +                return a > b ? 1 : -1;

What about if the dates are equal?  Does that case matter much for ordering?

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:185
> +            return;

Ditto (138).

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:272
> +        const rowsHeight = this._dataSourceForTable(table).length * table.rowHeight;

Style: I think this should be a `let` instead of a `const`.

> Source/WebInspectorUI/UserInterface/Views/TableColumn.js:28
> +    constructor(identifier, name, {initialWidth, minWidth, maxWidth, hidden, sortable, hideable, align, resizeType} = {})

This is why I like `options` objects in constructors :)
Comment 9 Joseph Pecoraro 2017-10-06 11:45:05 PDT
Comment on attachment 322978 [details]
[PATCH] Proposed Fix

View in context: https://bugs.webkit.org/attachment.cgi?id=322978&action=review

>> Source/WebInspectorUI/UserInterface/Models/Cookie.js:43
>> +        this.value = value || "";
> 
> Since you assert above, it it necessary to have a default value?

Asserts are what we expect. This protects us against something going wrong in the wild.

>> Source/WebInspectorUI/UserInterface/Models/Cookie.js:73
>> +            let match = pair.match(/^(?<name>[^\s=]+)[ \t]*=[ \t]*(?<value>.*)$/);
> 
> In this regex (and the others below) you check for `[^\s]`, but then use `[ \t]` later on.  Is there a reason for this difference?  I would think that they would match.
> 
>     let match = pair.match(/^(?<name>[^ \t=]+)[ \t]*=[ \t]*(?<value>.*)$/);
> 
> OR
> 
>     let match = pair.match(/^(?<name>[^\s=]+)\s*=\s*(?<value>.*)$/);

So the syntax here from RFC 6265 is:
https://www.ietf.org/rfc/rfc6265.txt

   cookie-header = "Cookie:" OWS cookie-string OWS
   cookie-string = cookie-pair *( ";" SP cookie-pair )
   cookie-pair   = cookie-name "=" cookie-value

OWS is:

   OWS            = *( [ obs-fold ] WSP )
                    ; "optional" whitespace
   obs-fold       = CRLF

And RFC 5234 defines WSP as:
https://tools.ietf.org/html/rfc5234

    SP    =  %x20
    HTAB  =  %x09
          ; horizontal tab
    WSP   =  SP / HTAB
          ; white space

I was also expecting that newlines might terminate the header and might not be allowed.

In any case most of this doesn't matter so we can probably simplify.

For reference this is what Blink does, which is somewhat close to this, but less strict:
https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js#128

>> Source/WebInspectorUI/UserInterface/Models/Cookie.js:117
>> +            let match = attribute.match(/^(?<name>[^\s=]+)(?:=(?<value>.*))?$/);
> 
> Are attributes not allowed to have spaces around the "=" (assuming it exists)?

My reading of the spec is that spaces not allowed. In practice servers might send badly formatted data, and browsers might accept it, so we might want to loosen this.

>> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:138
>> +            return;
> 
> Style: since this function returns a value, this should be `return null;`.  I think ESLint should show a warning for this.

Oops, yes. Good catch.

>> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:179
>> +                return a > b ? 1 : -1;
> 
> What about if the dates are equal?  Does that case matter much for ordering?

I don't think 0 or 1 matters. I can probably just do a.getTime() - b.getTime() though.
Comment 10 Joseph Pecoraro 2017-10-06 11:46:45 PDT
> So the syntax here from RFC 6265 is:
> https://www.ietf.org/rfc/rfc6265.txt
> 
>    cookie-header = "Cookie:" OWS cookie-string OWS
>    cookie-string = cookie-pair *( ";" SP cookie-pair )
>    cookie-pair   = cookie-name "=" cookie-value
> 

I forgot got copy my comments over from outside the comment field:

So the syntax here from RFC 6265 is:
https://www.ietf.org/rfc/rfc6265.txt

   cookie-header = "Cookie:" OWS cookie-string OWS
   cookie-string = cookie-pair *( ";" SP cookie-pair )
   cookie-pair   = cookie-name "=" cookie-value
   cookie-name   = token
   cookie-value  = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
   cookie-octet  = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                 ; US-ASCII characters excluding CTLs,
                 ; whitespace DQUOTE, comma, semicolon,
                 ; and backslash

The interesting part being whitespace isn't allowed in the octet.
Comment 11 Joseph Pecoraro 2017-10-08 14:41:58 PDT
Created attachment 323143 [details]
[PATCH] Proposed Fix
Comment 12 Sam Weinig 2017-10-08 14:50:37 PDT
Do you have a screenshot with a redirect?
Comment 13 Joseph Pecoraro 2017-10-08 15:19:37 PDT
(In reply to Sam Weinig from comment #12)
> Do you have a screenshot with a redirect?

Since Web Inspector doesn't maintain redirect data yet, it'll just show the last redirect / request's cookies in the Request section.
Comment 14 BJ Burg 2017-10-09 10:31:25 PDT
(In reply to Joseph Pecoraro from comment #13)
> (In reply to Sam Weinig from comment #12)
> > Do you have a screenshot with a redirect?
> 
> Since Web Inspector doesn't maintain redirect data yet, it'll just show the
> last redirect / request's cookies in the Request section.

Tracked internally in <rdar://problem/5378164>
Comment 15 BJ Burg 2017-10-09 10:49:08 PDT
Comment on attachment 323143 [details]
[PATCH] Proposed Fix

View in context: https://bugs.webkit.org/attachment.cgi?id=323143&action=review

r=me, this table code is super easy to follow now! (Well, at least it fits in just one file..)

> Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js:560
> +localizedStrings["Max-Age"] = "Max-Age";

This is a header literal, yes? In that case it shouldn't be localized.

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:29
> +    {

I tend to agree with Devin's comment about moving optional stuff into options={}.

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:58
> +    // RFC 6265 Defines the HTTP Cookie and Set-Cookie header fields:

nit: defines

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:79
> +                console.error("Failed to parse Cookie pair", pair);

Please use WI.reportInternalError("Failed to parse Cookie", {header, pair}) so that engineers will report cookies that this code doesn't know how to parse.

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:102
> +            console.error("Failed to parse Set-Cookie header", header);

Ditto.

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:123
> +                console.error("Failed to parse Set-Cookie attribute:", attribute);

Ditto.

> Source/WebInspectorUI/UserInterface/Models/Cookie.js:142
> +                    console.warn("Invalid MaxAge value:", attributeValue);

Is this something we ever care about seeing in Inspector^2?

> Source/WebInspectorUI/UserInterface/Models/Resource.js:439
> +            // FIXME: The backend sends multiple "Set-Cookie" headers in one "Set-Cookie" with multiple values

Is this something that we can fix without worrying about breakage, or is it performed outside of Inspector code?

> Source/WebInspectorUI/UserInterface/Models/Resource.js:442
> +            // ", " in the the date format "Expires=Tue, 03-Oct-2017 04:39:21 GMT". To improve hueristics

Nit: heuristics

> Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.js:114
> +    _incompleteSectionWithMessage(section, message)

Nit: there's no verb here but it's doing stuff. Perhaps  _markSectionIncompleteWithMessage, _markSectionIncompleteWithLoadingIndicator?
Comment 16 Joseph Pecoraro 2017-10-09 12:33:04 PDT
<https://trac.webkit.org/r223058>