LibWebView: Add a storage tab to the Inspector to manage cookies

This adds a storage tab which contains just a cookie viewer for now. In
the future, storage like Local Storage and Indexed DB can be added here
as well.

In this patch, the cookie table is read-only.
This commit is contained in:
Timothy Flynn 2024-09-06 12:08:50 -04:00 committed by Andreas Kling
parent 693af180dd
commit 3c5650f846
Notes: github-actions[bot] 2024-09-07 09:11:43 +00:00
5 changed files with 97 additions and 0 deletions

View file

@ -276,6 +276,9 @@ details > :not(:first-child) {
.property-table td {
padding: 4px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
#fonts {

View file

@ -16,6 +16,7 @@
<div class="tab-controls">
<button id="dom-tree-button" onclick="selectTopTab(this, 'dom-tree')">DOM Tree</button>
<button id="accessibility-tree-button" onclick="selectTopTab(this, 'accessibility-tree')">Accessibility Tree</button>
<button id="storage-button" onclick="selectTopTab(this, 'storage')">Storage</button>
<button id="style-sheets-button" onclick="selectTopTab(this, 'style-sheets')">Style Sheets</button>
</div>
@ -27,6 +28,32 @@
<div id="dom-tree" class="tab-content html"></div>
<div id="accessibility-tree" class="tab-content"></div>
<div id="storage" class="tab-content" style="padding: 0">
<div class="tab-header">
<select id="storage-picker">
<option value="cookies" selected>Cookies</option>
</select>
</div>
<div id="cookie-storage">
<table class="property-table">
<thead>
<tr>
<th style="width: 10%">Name</th>
<th style="width: 15%">Value</th>
<th style="width: 10%">Domain</th>
<th style="width: 5%">Path</th>
<th style="width: 20%">Created</th>
<th style="width: 20%">Last Accessed</th>
<th style="width: 20%">Expires</th>
</tr>
</thead>
<tbody id="cookie-table">
</tbody>
</table>
</div>
</div>
<div id="style-sheets" class="tab-content" style="padding: 0">
<div class="tab-header">
<select id="style-sheet-picker" disabled onchange="loadStyleSheet()">

View file

@ -103,6 +103,9 @@ inspector.reset = () => {
let accessibilityTree = document.getElementById("accessibility-tree");
accessibilityTree.innerHTML = "";
let cookieTable = document.getElementById("cookie-table");
cookieTable.innerHTML = "";
let styleSheetPicker = document.getElementById("style-sheet-picker");
styleSheetPicker.replaceChildren();
@ -208,6 +211,35 @@ inspector.addAttributeToDOMNodeID = nodeID => {
pendingEditDOMNode = null;
};
inspector.setCookies = cookies => {
let oldTable = document.getElementById("cookie-table");
let newTable = document.createElement("tbody");
newTable.setAttribute("id", oldTable.id);
const addColumn = (row, value) => {
let column = row.insertCell();
column.innerText = value;
column.title = value;
};
cookies
.sort((lhs, rhs) => lhs.name.localeCompare(rhs.name))
.forEach(cookie => {
let row = newTable.insertRow();
addColumn(row, cookie.name);
addColumn(row, cookie.value);
addColumn(row, cookie.domain);
addColumn(row, cookie.path);
addColumn(row, new Date(cookie.creationTime).toLocaleString());
addColumn(row, new Date(cookie.lastAccessTime).toLocaleString());
addColumn(row, new Date(cookie.expiryTime).toLocaleString());
});
oldTable.parentNode.replaceChild(newTable, oldTable);
};
inspector.setStyleSheets = styleSheets => {
const styleSheetPicker = document.getElementById("style-sheet-picker");
const styleSheetSource = document.getElementById("style-sheet-source");

View file

@ -5,6 +5,7 @@
*/
#include <AK/Base64.h>
#include <AK/Enumerate.h>
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/LexicalPath.h>
@ -16,6 +17,7 @@
#include <LibJS/MarkupGenerator.h>
#include <LibWeb/Infra/Strings.h>
#include <LibWebView/Application.h>
#include <LibWebView/CookieJar.h>
#include <LibWebView/InspectorClient.h>
#include <LibWebView/SourceHighlighter.h>
@ -294,6 +296,7 @@ void InspectorClient::inspect()
m_content_web_view.inspect_dom_tree();
m_content_web_view.inspect_accessibility_tree();
m_content_web_view.list_style_sheets();
load_cookies();
}
void InspectorClient::reset()
@ -342,6 +345,34 @@ void InspectorClient::select_node(i32 node_id)
m_inspector_web_view.run_javascript(script);
}
void InspectorClient::load_cookies()
{
m_cookies = Application::cookie_jar().get_all_cookies(m_content_web_view.url());
JsonArray json_cookies;
for (auto const& [index, cookie] : enumerate(m_cookies)) {
JsonObject json_cookie;
json_cookie.set("index"sv, JsonValue { index });
json_cookie.set("name"sv, JsonValue { cookie.name });
json_cookie.set("value"sv, JsonValue { cookie.value });
json_cookie.set("domain"sv, JsonValue { cookie.domain });
json_cookie.set("path"sv, JsonValue { cookie.path });
json_cookie.set("creationTime"sv, JsonValue { cookie.creation_time.milliseconds_since_epoch() });
json_cookie.set("lastAccessTime"sv, JsonValue { cookie.last_access_time.milliseconds_since_epoch() });
json_cookie.set("expiryTime"sv, JsonValue { cookie.expiry_time.milliseconds_since_epoch() });
MUST(json_cookies.append(move(json_cookie)));
}
StringBuilder builder;
builder.append("inspector.setCookies("sv);
json_cookies.serialize(builder);
builder.append(");"sv);
m_inspector_web_view.run_javascript(builder.string_view());
}
void InspectorClient::context_menu_edit_dom_node()
{
VERIFY(m_context_menu_data.has_value());

View file

@ -51,6 +51,8 @@ private:
String generate_accessibility_tree(JsonObject const&);
void select_node(i32 node_id);
void load_cookies();
void request_console_messages();
void handle_console_message(i32 message_index);
void handle_console_messages(i32 start_index, ReadonlySpan<ByteString> message_types, ReadonlySpan<ByteString> messages);
@ -82,6 +84,8 @@ private:
HashMap<int, Vector<Attribute>> m_dom_node_attributes;
Vector<Web::Cookie::Cookie> m_cookies;
i32 m_highest_notified_message_index { -1 };
i32 m_highest_received_message_index { -1 };
bool m_waiting_for_messages { false };