blob: 79e77efd51a7affb418907a71501a24cbc1edf0b [file] [log] [blame]
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WI.ResourceCookiesContentView = class ResourceCookiesContentView extends WI.ContentView
{
constructor(resource)
{
super(null);
console.assert(resource instanceof WI.Resource);
this._resource = resource;
this._resource.addEventListener(WI.Resource.Event.RequestHeadersDidChange, this._resourceRequestHeadersDidChange, this);
this._resource.addEventListener(WI.Resource.Event.ResponseReceived, this._resourceResponseReceived, this);
this.element.classList.add("resource-details", "resource-cookies");
}
// Table dataSource
tableNumberOfRows(table)
{
return this._dataSourceForTable(table).length;
}
tableSortChanged(table)
{
let sortComparator = this._generateSortComparator(table);
if (!sortComparator)
return;
let dataSource = this._dataSourceForTable(table);
dataSource.sort(sortComparator);
table.reloadData();
}
tableIndexForRepresentedObject(table, object)
{
let cookies = this._dataSourceForTable(table);
let index = cookies.indexOf(object);
console.assert(index >= 0);
return index;
}
tableRepresentedObjectForIndex(table, index)
{
let cookies = this._dataSourceForTable(table);
console.assert(index >= 0 && index < cookies.length);
return cookies[index];
}
// Table delegate
tableShouldSelectRow(table, cell, column, rowIndex)
{
return false;
}
tablePopulateCell(table, cell, column, rowIndex)
{
let cookie = this._dataSourceForTable(table)[rowIndex];
const checkmark = "\u2713";
switch (column.identifier) {
case "name":
cell.textContent = cookie.name;
break;
case "value":
cell.textContent = cookie.value;
break;
case "domain":
cell.textContent = cookie.domain || emDash;
break;
case "path":
cell.textContent = cookie.path || emDash;
break;
case "expires":
cell.textContent = cookie.expires ? cookie.expires.toLocaleString() : WI.UIString("Session");
break;
case "maxAge":
cell.textContent = cookie.maxAge || emDash;
break;
case "secure":
cell.textContent = cookie.secure ? checkmark : zeroWidthSpace;
break;
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;
}
// Protected
initialLayout()
{
super.initialLayout();
this._requestCookiesSection = new WI.ResourceDetailsSection(WI.UIString("Request Cookies"));
this.element.appendChild(this._requestCookiesSection.element);
this._refreshRequestCookiesSection();
this._responseCookiesSection = new WI.ResourceDetailsSection(WI.UIString("Response Cookies"));
this.element.appendChild(this._responseCookiesSection.element);
this._refreshResponseCookiesSection();
}
// Private
_dataSourceForTable(table)
{
return table === this._requestCookiesTable ? this._requestCookiesDataSource : this._responseCookiesDataSource;
}
_generateSortComparator(table)
{
let sortColumnIdentifier = table.sortColumnIdentifier;
if (!sortColumnIdentifier)
return null;
let comparator;
switch (sortColumnIdentifier) {
case "name":
case "value":
case "domain":
case "path":
case "sameSite":
// String.
comparator = (a, b) => (a[sortColumnIdentifier] || "").extendedLocaleCompare(b[sortColumnIdentifier] || "");
break;
case "maxAge":
// Number.
comparator = (a, b) => {
let aValue = a[sortColumnIdentifier];
if (isNaN(aValue))
return 1;
let bValue = b[sortColumnIdentifier];
if (isNaN(bValue))
return -1;
return aValue - bValue;
};
break;
case "httpOnly":
case "secure":
// Boolean.
comparator = (a, b) => a[sortColumnIdentifier] - b[sortColumnIdentifier];
break;
case "expires":
// Date.
comparator = (a, b) => {
let aExpires = a.expires;
if (!aExpires)
return 1;
let bExpires = b.expires;
if (!bExpires)
return -1;
return aExpires.getTime() - bExpires.getTime();
};
break;
default:
console.assert("Unexpected sort column", sortColumnIdentifier);
return null;
}
let reverseFactor = table.sortOrder === WI.Table.SortOrder.Ascending ? 1 : -1;
return (a, b) => reverseFactor * comparator(a, b);
}
_refreshRequestCookiesSection()
{
let detailsElement = this._requestCookiesSection.detailsElement;
detailsElement.removeChildren();
if (this._resource.responseSource === WI.Resource.ResponseSource.MemoryCache) {
this._requestCookiesSection.markIncompleteSectionWithMessage(WI.UIString("No request, served from the memory cache."));
return;
}
this._requestCookiesDataSource = this._resource.requestCookies;
if (!this._requestCookiesTable) {
this._requestCookiesTable = new WI.Table("request-cookies", this, this, 20);
this._requestCookiesTable.addColumn(new WI.TableColumn("name", WI.UIString("Name"), {minWidth: 150, maxWidth: 300, initialWidth: 200, resizeType: WI.TableColumn.ResizeType.Locked}));
this._requestCookiesTable.addColumn(new WI.TableColumn("value", WI.UIString("Value"), {minWidth: 150, hideable: false}));
if (!this._requestCookiesTable.sortColumnIdentifier) {
this._requestCookiesTable.sortOrder = WI.Table.SortOrder.Ascending;
this._requestCookiesTable.sortColumnIdentifier = "name";
}
}
if (!this._requestCookiesDataSource.length) {
if (this._requestCookiesTable.isAttached)
this.removeSubview(this._requestCookiesTable);
this._requestCookiesSection.markIncompleteSectionWithMessage(WI.UIString("No request cookies."));
} else {
this._requestCookiesSection.toggleIncomplete(false);
this._requestCookiesTable.element.style.height = this._sizeForTable(this._requestCookiesTable) + "px";
this.addSubview(this._requestCookiesTable);
detailsElement.classList.add("has-table");
detailsElement.appendChild(this._requestCookiesTable.element);
}
}
_refreshResponseCookiesSection()
{
let detailsElement = this._responseCookiesSection.detailsElement;
detailsElement.removeChildren();
if (!this._resource.hasResponse()) {
this._responseCookiesSection.markIncompleteSectionWithLoadingIndicator();
return;
}
this._responseCookiesDataSource = this._resource.responseCookies;
if (!this._responseCookiesTable) {
this._responseCookiesTable = new WI.Table("request-cookies", this, this, 20);
this._responseCookiesTable.addColumn(new WI.TableColumn("name", WI.UIString("Name"), {minWidth: 150, maxWidth: 300, initialWidth: 200, resizeType: WI.TableColumn.ResizeType.Locked}));
this._responseCookiesTable.addColumn(new WI.TableColumn("value", WI.UIString("Value"), {minWidth: 150, hideable: false}));
this._responseCookiesTable.addColumn(new WI.TableColumn("domain", WI.unlocalizedString("Domain"), {}));
this._responseCookiesTable.addColumn(new WI.TableColumn("path", WI.unlocalizedString("Path"), {}));
this._responseCookiesTable.addColumn(new WI.TableColumn("expires", WI.unlocalizedString("Expires"), {maxWidth: 150}));
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";
}
}
if (!this._responseCookiesDataSource.length) {
if (this._responseCookiesTable.isAttached)
this.removeSubview(this._responseCookiesTable);
this._responseCookiesSection.markIncompleteSectionWithMessage(WI.UIString("No response cookies."));
} else {
this._responseCookiesSection.toggleIncomplete(false);
this._responseCookiesTable.element.style.height = this._sizeForTable(this._responseCookiesTable) + "px";
this.addSubview(this._responseCookiesTable);
detailsElement.classList.add("has-table");
detailsElement.appendChild(this._responseCookiesTable.element);
}
}
_sizeForTable(table)
{
const headerHeight = 28;
const borderHeight = 3;
let rowsHeight = this._dataSourceForTable(table).length * table.rowHeight;
return rowsHeight + headerHeight + borderHeight;
}
_resourceRequestHeadersDidChange(event)
{
this._refreshRequestCookiesSection();
}
_resourceResponseReceived(event)
{
this._refreshResponseCookiesSection();
}
};