Changeset 223058 in webkit


Ignore:
Timestamp:
Oct 9, 2017 12:32:28 PM (6 years ago)
Author:
Joseph Pecoraro
Message:

Web Inspector: Network Tab - Cookies Detail View
https://bugs.webkit.org/show_bug.cgi?id=177988
<rdar://problem/34071927>

Reviewed by Brian Burg.

Source/WebInspectorUI:

  • Localizations/en.lproj/localizedStrings.js:
  • UserInterface/Main.html:
  • UserInterface/Test.html:

New strings and resources.

  • UserInterface/Models/Cookie.js: Added.

(WI.Cookie):
(WI.Cookie.parseCookieRequestHeader):
(WI.Cookie.parseSetCookieResponseHeader):
Encapsulation for Cookie attributes.

  • UserInterface/Models/Resource.js:

(WI.Resource.prototype.get requestCookies):
(WI.Resource.prototype.get responseCookies):
(WI.Resource.prototype.updateForRedirectResponse):
(WI.Resource.prototype.updateForResponse):
(WI.Resource.prototype.updateWithMetrics):
New computed accessors for requestCookies and responseCookies.

  • UserInterface/Views/NetworkResourceDetailView.js:

(WI.NetworkResourceDetailView.prototype._showContentViewForNavigationItem):
Show the new Cookie View.

  • UserInterface/Views/NetworkTableContentView.css:

(.content-view.network .network-table .icon):
(.network-table li:not(.filler) .cell.name):
(.network-table .cache-type):
(.network-table .error):
(body[dir=ltr] .network-table .cell.name > .status):
(body[dir=rtl] .network-table .cell.name > .status):
(.network-table .cell.name > .status .indeterminate-progress-spinner):
(.showing-detail .network-table .cell:not(.name)):
(.showing-detail .network-table .resizer:not(:first-of-type)):
(.network-table :not(.header) .cell:first-of-type):
Rework these styles to be specific to the .network-table.

  • UserInterface/Views/Table.css:

(.table :not(.header) .cell:first-of-type): Deleted.
Move this to the network table styles, it shouldn't apply to all tables.

  • UserInterface/Views/ResourceCookiesContentView.css:

(.resource-cookies > section > .details.has-table):
(.resource-cookies .table):
(.resource-cookies .table > .header):
Styles for Cookies view and table.

  • UserInterface/Views/ResourceCookiesContentView.js: Added.

(WI.ResourceCookiesContentView):
(WI.ResourceCookiesContentView.prototype.tableNumberOfRows):
(WI.ResourceCookiesContentView.prototype.tableSortChanged):
(WI.ResourceCookiesContentView.prototype.tablePopulateCell):
(WI.ResourceCookiesContentView.prototype.initialLayout):
(WI.ResourceCookiesContentView.prototype._incompleteSectionWithMessage):
(WI.ResourceCookiesContentView.prototype._incompleteSectionWithLoadingIndicator):
(WI.ResourceCookiesContentView.prototype._dataSourceForTable):
(WI.ResourceCookiesContentView.prototype._generateSortComparator):
(WI.ResourceCookiesContentView.prototype._refreshRequestCookiesSection):
(WI.ResourceCookiesContentView.prototype._refreshResponseCookiesSection):
(WI.ResourceCookiesContentView.prototype._sizeForTable):
(WI.ResourceCookiesContentView.prototype._resourceRequestHeadersDidChange):
(WI.ResourceCookiesContentView.prototype._resourceResponseReceived):
Tables for Request and Response cookies. They are simliar with slightly different columns.
Handle simple display and sorting for the tables.

  • UserInterface/Views/ResourceHeadersContentView.js:

(WI.ResourceHeadersContentView.prototype._refreshResponseHeadersSection):
Break out Set-Cookie headers as multiple headers. THey should never be combined.

  • UserInterface/Views/Table.js:

(WI.Table.prototype.showColumn):
(WI.Table.prototype.hideColumn):
(WI.Table.prototype._handleHeaderContextMenu):

  • UserInterface/Views/TableColumn.js:

(WI.TableColumn.prototype.get hideable):
(WI.TableColumn.prototype.set hidden):
(WI.TableColumn):
(WI.TableColumn.prototype.setHidden): Deleted.
Make it so some columns can not be hidden. For example the "value" column
in the Cookie tables.

LayoutTests:

  • inspector/unit-tests/cookie-expected.txt: Added.
  • inspector/unit-tests/cookie.html: Added.
Location:
trunk
Files:
4 added
12 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r223055 r223058  
     12017-10-09  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Network Tab - Cookies Detail View
     4        https://bugs.webkit.org/show_bug.cgi?id=177988
     5        <rdar://problem/34071927>
     6
     7        Reviewed by Brian Burg.
     8
     9        * inspector/unit-tests/cookie-expected.txt: Added.
     10        * inspector/unit-tests/cookie.html: Added.
     11
    1122017-10-09  Matt Lewis  <jlewis3@apple.com>
    213
  • trunk/Source/WebInspectorUI/ChangeLog

    r223057 r223058  
     12017-10-09  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Network Tab - Cookies Detail View
     4        https://bugs.webkit.org/show_bug.cgi?id=177988
     5        <rdar://problem/34071927>
     6
     7        Reviewed by Brian Burg.
     8
     9        * Localizations/en.lproj/localizedStrings.js:
     10        * UserInterface/Main.html:
     11        * UserInterface/Test.html:
     12        New strings and resources.
     13
     14        * UserInterface/Models/Cookie.js: Added.
     15        (WI.Cookie):
     16        (WI.Cookie.parseCookieRequestHeader):
     17        (WI.Cookie.parseSetCookieResponseHeader):
     18        Encapsulation for Cookie attributes.
     19
     20        * UserInterface/Models/Resource.js:
     21        (WI.Resource.prototype.get requestCookies):
     22        (WI.Resource.prototype.get responseCookies):
     23        (WI.Resource.prototype.updateForRedirectResponse):
     24        (WI.Resource.prototype.updateForResponse):
     25        (WI.Resource.prototype.updateWithMetrics):
     26        New computed accessors for requestCookies and responseCookies.
     27
     28        * UserInterface/Views/NetworkResourceDetailView.js:
     29        (WI.NetworkResourceDetailView.prototype._showContentViewForNavigationItem):
     30        Show the new Cookie View.
     31
     32        * UserInterface/Views/NetworkTableContentView.css:
     33        (.content-view.network .network-table .icon):
     34        (.network-table li:not(.filler) .cell.name):
     35        (.network-table .cache-type):
     36        (.network-table .error):
     37        (body[dir=ltr] .network-table .cell.name > .status):
     38        (body[dir=rtl] .network-table .cell.name > .status):
     39        (.network-table .cell.name > .status .indeterminate-progress-spinner):
     40        (.showing-detail .network-table .cell:not(.name)):
     41        (.showing-detail .network-table .resizer:not(:first-of-type)):
     42        (.network-table :not(.header) .cell:first-of-type):
     43        Rework these styles to be specific to the .network-table.
     44
     45        * UserInterface/Views/Table.css:
     46        (.table :not(.header) .cell:first-of-type): Deleted.
     47        Move this to the network table styles, it shouldn't apply to all tables.
     48
     49        * UserInterface/Views/ResourceCookiesContentView.css:
     50        (.resource-cookies > section > .details.has-table):
     51        (.resource-cookies .table):
     52        (.resource-cookies .table > .header):
     53        Styles for Cookies view and table.
     54
     55        * UserInterface/Views/ResourceCookiesContentView.js: Added.
     56        (WI.ResourceCookiesContentView):
     57        (WI.ResourceCookiesContentView.prototype.tableNumberOfRows):
     58        (WI.ResourceCookiesContentView.prototype.tableSortChanged):
     59        (WI.ResourceCookiesContentView.prototype.tablePopulateCell):
     60        (WI.ResourceCookiesContentView.prototype.initialLayout):
     61        (WI.ResourceCookiesContentView.prototype._incompleteSectionWithMessage):
     62        (WI.ResourceCookiesContentView.prototype._incompleteSectionWithLoadingIndicator):
     63        (WI.ResourceCookiesContentView.prototype._dataSourceForTable):
     64        (WI.ResourceCookiesContentView.prototype._generateSortComparator):
     65        (WI.ResourceCookiesContentView.prototype._refreshRequestCookiesSection):
     66        (WI.ResourceCookiesContentView.prototype._refreshResponseCookiesSection):
     67        (WI.ResourceCookiesContentView.prototype._sizeForTable):
     68        (WI.ResourceCookiesContentView.prototype._resourceRequestHeadersDidChange):
     69        (WI.ResourceCookiesContentView.prototype._resourceResponseReceived):
     70        Tables for Request and Response cookies. They are simliar with slightly different columns.
     71        Handle simple display and sorting for the tables.
     72
     73        * UserInterface/Views/ResourceHeadersContentView.js:
     74        (WI.ResourceHeadersContentView.prototype._refreshResponseHeadersSection):
     75        Break out Set-Cookie headers as multiple headers. THey should never be combined.
     76
     77        * UserInterface/Views/Table.js:
     78        (WI.Table.prototype.showColumn):
     79        (WI.Table.prototype.hideColumn):
     80        (WI.Table.prototype._handleHeaderContextMenu):
     81        * UserInterface/Views/TableColumn.js:
     82        (WI.TableColumn.prototype.get hideable):
     83        (WI.TableColumn.prototype.set hidden):
     84        (WI.TableColumn):
     85        (WI.TableColumn.prototype.setHidden): Deleted.
     86        Make it so some columns can not be hidden. For example the "value" column
     87        in the Cookie tables.
     88
    1892017-10-09  Joseph Pecoraro  <pecoraro@apple.com>
    290
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r223011 r223058  
    610610localizedStrings["No matching ARIA role"] = "No matching ARIA role";
    611611localizedStrings["No preview available"] = "No preview available";
     612localizedStrings["No request cookies."] = "No request cookies.";
    612613localizedStrings["No request headers"] = "No request headers";
    613614localizedStrings["No request, served from the disk cache."] = "No request, served from the disk cache.";
    614615localizedStrings["No request, served from the memory cache."] = "No request, served from the memory cache.";
     616localizedStrings["No response cookies."] = "No response cookies.";
    615617localizedStrings["No response headers"] = "No response headers";
    616618localizedStrings["Node"] = "Node";
     
    725727localizedStrings["Request"] = "Request";
    726728localizedStrings["Request & Response"] = "Request & Response";
     729localizedStrings["Request Cookies"] = "Request Cookies";
    727730localizedStrings["Request Data"] = "Request Data";
    728731localizedStrings["Request Headers"] = "Request Headers";
     
    739742localizedStrings["Resources"] = "Resources";
    740743localizedStrings["Response"] = "Response";
     744localizedStrings["Response Cookies"] = "Response Cookies";
    741745localizedStrings["Response Headers"] = "Response Headers";
    742746localizedStrings["Restart (%s)"] = "Restart (%s)";
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r223011 r223058  
    154154    <link rel="stylesheet" href="Views/RenderingFrameTimelineView.css">
    155155    <link rel="stylesheet" href="Views/Resizer.css">
     156    <link rel="stylesheet" href="Views/ResourceCookiesContentView.css">
    156157    <link rel="stylesheet" href="Views/ResourceDetailsSection.css">
    157158    <link rel="stylesheet" href="Views/ResourceDetailsSidebarPanel.css">
     
    353354    <script src="Models/Color.js"></script>
    354355    <script src="Models/ConsoleCommandResultMessage.js"></script>
     356    <script src="Models/Cookie.js"></script>
    355357    <script src="Models/CookieStorageObject.js"></script>
    356358    <script src="Models/DOMBreakpoint.js"></script>
     
    697699    <script src="Views/ResourceDetailsSidebarPanel.js"></script>
    698700    <script src="Views/ResourceHeadersContentView.js"></script>
     701    <script src="Views/ResourceCookiesContentView.js"></script>
    699702    <script src="Views/ResourceSidebarPanel.js"></script>
    700703    <script src="Views/ResourceTimelineDataGridNode.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js

    r223006 r223058  
    4747        this._requestHeaders = requestHeaders || {};
    4848        this._responseHeaders = {};
     49        this._requestCookies = null;
     50        this._responseCookies = null;
    4951        this._parentFrame = null;
    5052        this._initiatorSourceCodeLocation = initiatorSourceCodeLocation || null;
     
    424426    }
    425427
     428    get requestCookies()
     429    {
     430        if (!this._requestCookies)
     431            this._requestCookies = WI.Cookie.parseCookieRequestHeader(this._requestHeaders.valueForCaseInsensitiveKey("Cookie"));
     432
     433        return this._requestCookies;
     434    }
     435
     436    get responseCookies()
     437    {
     438        if (!this._responseCookies) {
     439            // FIXME: The backend sends multiple "Set-Cookie" headers in one "Set-Cookie" with multiple values
     440            // separated by ", ". This doesn't allow us to safely distinguish between a ", " that separates
     441            // multiple headers or one that may be valid part of a Cookie's value or attribute, such as the
     442            // ", " in the the date format "Expires=Tue, 03-Oct-2017 04:39:21 GMT". To improve heuristics
     443            // we do a negative lookahead for numbers, but we can still fail on cookie values containing ", ".
     444            let rawCombinedHeader = this._responseHeaders.valueForCaseInsensitiveKey("Set-Cookie") || "";
     445            let setCookieHeaders = rawCombinedHeader.split(/, (?![0-9])/);
     446            let cookies = [];
     447            for (let header of setCookieHeaders) {
     448                let cookie = WI.Cookie.parseSetCookieResponseHeader(header);
     449                if (cookie)
     450                    cookies.push(cookie);
     451            }
     452            this._responseCookies = cookies;
     453        }
     454
     455        return this._responseCookies;
     456    }
     457
    426458    get requestSentTimestamp()
    427459    {
     
    606638        this._url = url;
    607639        this._requestHeaders = requestHeaders || {};
     640        this._requestCookies = null;
    608641        this._lastRedirectReceivedTimestamp = elapsedTime || NaN;
    609642
     
    643676        this._statusText = statusText;
    644677        this._responseHeaders = responseHeaders || {};
     678        this._responseCookies = null;
    645679        this._responseReceivedTimestamp = elapsedTime || NaN;
    646680        this._timingData = WI.ResourceTimingData.fromPayload(timingData, this);
     
    703737        if (metrics.requestHeaders) {
    704738            this._requestHeaders = metrics.requestHeaders;
     739            this._requestCookies = null;
    705740            this.dispatchEventToListeners(WI.Resource.Event.RequestHeadersDidChange);
    706741        }
  • trunk/Source/WebInspectorUI/UserInterface/Test.html

    r222782 r223058  
    117117    <script src="Models/Color.js"></script>
    118118    <script src="Models/ConsoleCommandResultMessage.js"></script>
     119    <script src="Models/Cookie.js"></script>
    119120    <script src="Models/CookieStorageObject.js"></script>
    120121    <script src="Models/DOMBreakpoint.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js

    r223006 r223058  
    162162            break;
    163163        case "cookies":
    164             // FIXME: Provide a Resource Cookies View.
    165164            if (!this._cookiesContentView)
    166                 this._cookiesContentView = new WI.DebugContentView("Cookies");
     165                this._cookiesContentView = new WI.ResourceCookiesContentView(this._resource);
    167166            this._contentBrowser.showContentView(this._cookiesContentView);
    168167            break;
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css

    r222868 r223058  
    2424 */
    2525
    26 .content-view.network .table .icon {
     26.content-view.network .network-table .icon {
    2727    position: relative;
    2828    width: 16px;
     
    3333}
    3434
    35 .content-view.network .table li:not(.filler) .cell.name {
     35.network-table li:not(.filler) .cell.name {
    3636    cursor: pointer;
    3737}
    3838
    39 .content-view.network .table .cache-type {
     39.network-table .cache-type {
    4040    color: var(--text-color-gray-medium);
    4141}
    4242
    43 .content-view.network .table .error {
     43.network-table .error {
    4444    color: var(--error-text-color);
    4545}
    4646
    47 body[dir=ltr] .content-view.network .table .cell.name > .status {
     47body[dir=ltr] .network-table .cell.name > .status {
    4848    float: right;
    4949    margin-left: 4px;
    5050}
    5151
    52 body[dir=rtl] .content-view.network .table .cell.name > .status {
     52body[dir=rtl] .network-table .cell.name > .status {
    5353    float: left;
    5454    margin-right: 4px;
    5555}
    5656
    57 .content-view.network .table .cell.name > .status .indeterminate-progress-spinner {
     57.network-table .cell.name > .status .indeterminate-progress-spinner {
    5858    margin-top: 3px;
    5959    width: 14px;
     
    6161}
    6262
    63 .showing-detail .table .cell:not(.name) {
     63.showing-detail .network-table .cell:not(.name) {
    6464    display: none;
    6565}
    6666
    67 .showing-detail .table .resizer:not(:first-of-type) {
     67.showing-detail .network-table .resizer:not(:first-of-type) {
    6868    display: none;
    6969}
     70
     71.network-table :not(.header) .cell:first-of-type {
     72    background: rgba(0, 0, 0, 0.07);
     73}
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceCookiesContentView.css

    r223057 r223058  
    2424 */
    2525
    26 .content-view.network .table .icon {
    27     position: relative;
    28     width: 16px;
    29     height: 16px;
    30     bottom: 1px;
    31     vertical-align: middle;
    32     -webkit-margin-end: 4px;
     26.resource-cookies.resource-details > section > .details.has-table {
     27    border-left: none;
    3328}
    3429
    35 .content-view.network .table li:not(.filler) .cell.name {
    36     cursor: pointer;
     30.resource-cookies .table {
     31    border: 1px solid var(--border-color);
    3732}
    3833
    39 .content-view.network .table .cache-type {
    40     color: var(--text-color-gray-medium);
     34.resource-cookies .table > .header {
     35    -webkit-user-select: none;
    4136}
    42 
    43 .content-view.network .table .error {
    44     color: var(--error-text-color);
    45 }
    46 
    47 body[dir=ltr] .content-view.network .table .cell.name > .status {
    48     float: right;
    49     margin-left: 4px;
    50 }
    51 
    52 body[dir=rtl] .content-view.network .table .cell.name > .status {
    53     float: left;
    54     margin-right: 4px;
    55 }
    56 
    57 .content-view.network .table .cell.name > .status .indeterminate-progress-spinner {
    58     margin-top: 3px;
    59     width: 14px;
    60     height: 14px;
    61 }
    62 
    63 .showing-detail .table .cell:not(.name) {
    64     display: none;
    65 }
    66 
    67 .showing-detail .table .resizer:not(:first-of-type) {
    68     display: none;
    69 }
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.js

    r223057 r223058  
    202202    // Private
    203203
    204     _incompleteSectionWithMessage(section, message)
     204    _markIncompleteSectionWithMessage(section, message)
    205205    {
    206206        section.toggleIncomplete(true);
     
    210210    }
    211211
    212     _incompleteSectionWithLoadingIndicator(section)
     212    _markIncompleteSectionWithLoadingIndicator(section)
    213213    {
    214214        section.toggleIncomplete(true);
     
    283283        if (this._resource.statusCode !== 304) {
    284284            if (this._resource.responseSource === WI.Resource.ResponseSource.MemoryCache) {
    285                 this._incompleteSectionWithMessage(this._requestHeadersSection, WI.UIString("No request, served from the memory cache."));
     285                this._markIncompleteSectionWithMessage(this._requestHeadersSection, WI.UIString("No request, served from the memory cache."));
    286286                return;
    287287            }
    288288            if (this._resource.responseSource === WI.Resource.ResponseSource.DiskCache) {
    289                 this._incompleteSectionWithMessage(this._requestHeadersSection, WI.UIString("No request, served from the disk cache."));
     289                this._markIncompleteSectionWithMessage(this._requestHeadersSection, WI.UIString("No request, served from the disk cache."));
    290290                return;
    291291            }
     
    313313
    314314        if (!detailsElement.firstChild)
    315             this._incompleteSectionWithMessage(this._requestHeadersSection, WI.UIString("No request headers"));
     315            this._markIncompleteSectionWithMessage(this._requestHeadersSection, WI.UIString("No request headers"));
    316316    }
    317317
     
    322322
    323323        if (!this._resource.hasResponse()) {
    324             this._incompleteSectionWithLoadingIndicator(this._responseHeadersSection);
     324            this._markIncompleteSectionWithLoadingIndicator(this._responseHeadersSection);
    325325            return;
    326326        }
     
    341341
    342342        let responseHeaders = this._resource.responseHeaders;
    343         for (let key in responseHeaders)
     343        for (let key in responseHeaders) {
     344            // Split multiple Set-Cookie response headers out into their multiple headers instead of as a combined value.
     345            if (key.toLowerCase() === "set-cookie") {
     346                let responseCookies = this._resource.responseCookies;
     347                console.assert(responseCookies.length > 0);
     348                for (let cookie of responseCookies)
     349                    this._appendKeyValuePair(detailsElement, key, cookie.rawHeader, "header");
     350                continue;
     351            }
     352
    344353            this._appendKeyValuePair(detailsElement, key, responseHeaders[key], "header");
     354        }
    345355
    346356        if (!detailsElement.firstChild)
    347             this._incompleteSectionWithMessage(this._responseHeadersSection, WI.UIString("No response headers"));
     357            this._markIncompleteSectionWithMessage(this._responseHeadersSection, WI.UIString("No response headers"));
    348358    }
    349359
  • trunk/Source/WebInspectorUI/UserInterface/Views/Table.css

    r223006 r223058  
    161161}
    162162
    163 .table :not(.header) .cell:first-of-type {
    164     background: rgba(0, 0, 0, 0.07);
    165 }
    166 
    167163.table .cell.align-right {
    168164    text-align: right;
  • trunk/Source/WebInspectorUI/UserInterface/Views/Table.js

    r222988 r223058  
    4545        // respect different vertical / horizontal scroll containers.
    4646
    47         this.element.classList.add("table");
     47        this.element.classList.add("table", identifier);
    4848        this.element.tabIndex = 0;
    4949        this.element.addEventListener("keydown", this._handleKeyDown.bind(this));
     
    335335            return;
    336336
    337         column.setHidden(false);
     337        column.hidden = false;
    338338
    339339        let columnIndex = this._hiddenColumns.indexOf(column);
     
    389389            return;
    390390
     391        console.assert(column.hideable, "Column is not hideable so should always be shown.");
     392        if (!column.hideable)
     393            return;
     394
    391395        if (column.hidden)
    392396            return;
    393397
    394         column.setHidden(true);
     398        column.hidden = true;
    395399
    396400        this._hiddenColumns.push(column);
     
    11751179            if (column.locked)
    11761180                continue;
     1181            if (!column.hideable)
     1182                continue;
    11771183
    11781184            let checked = !column.hidden;
  • trunk/Source/WebInspectorUI/UserInterface/Views/TableColumn.js

    r222470 r223058  
    2626WI.TableColumn = class TableColumn extends WI.Object
    2727{
    28     constructor(identifier, name, {initialWidth, minWidth, maxWidth, hidden, sortable, align, resizeType} = {})
     28    constructor(identifier, name, {initialWidth, minWidth, maxWidth, hidden, sortable, hideable, align, resizeType} = {})
    2929    {
    3030        super();
     
    4545        this._defaultHidden = hidden || false;
    4646        this._sortable = typeof sortable === "boolean" ? sortable : true;
     47        this._hideable = typeof hideable === "boolean" ? hideable : true;
    4748        this._align = align || null;
    4849        this._resizeType = resizeType || TableColumn.ResizeType.Auto;
     
    6162    get defaultHidden() { return this._defaultHidden; }
    6263    get sortable() { return this._sortable; }
     64    get hideable() { return this._hideable; }
    6365    get align() { return this._align; }
    6466
     
    9193    }
    9294
    93     setHidden(x)
     95    set hidden(x)
    9496    {
     97        console.assert(!this.locked && this._hideable, "Should not be able to hide a non-hideable column.");
    9598        this._hidden = x;
    9699    }
Note: See TracChangeset for help on using the changeset viewer.