mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-15 15:58:57 +00:00
Header case insensitive
This commit is contained in:
@@ -143,7 +143,6 @@
|
||||
// innerText does NOT parse HTML (unlike innerHTML)
|
||||
d1.innerText = 'hello <div>world</div><b>!!</b>';
|
||||
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerText);
|
||||
console.warn(d1.innerHTML);
|
||||
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerHTML);
|
||||
|
||||
// Setting empty string clears children
|
||||
|
||||
@@ -17,15 +17,145 @@
|
||||
testing.expectEqual(null, headers.get('Content-Type'));
|
||||
testing.expectEqual(false, headers.has('Content-Type'));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=case-insensitive>
|
||||
// Headers should be case-insensitive per HTTP spec
|
||||
{
|
||||
const headers = new Headers();
|
||||
|
||||
// Set with one case, get with another
|
||||
headers.set('Content-Type', 'application/json');
|
||||
testing.expectEqual('application/json', headers.get('content-type'));
|
||||
testing.expectEqual('application/json', headers.get('CONTENT-TYPE'));
|
||||
testing.expectEqual('application/json', headers.get('Content-Type'));
|
||||
|
||||
// has should be case-insensitive
|
||||
testing.expectEqual(true, headers.has('content-type'));
|
||||
testing.expectEqual(true, headers.has('CONTENT-TYPE'));
|
||||
testing.expectEqual(true, headers.has('Content-Type'));
|
||||
|
||||
// delete should be case-insensitive
|
||||
headers.delete('CONTENT-TYPE');
|
||||
testing.expectEqual(false, headers.has('content-type'));
|
||||
testing.expectEqual(false, headers.has('Content-Type'));
|
||||
}
|
||||
|
||||
{
|
||||
const headers = new Headers();
|
||||
|
||||
// Append with different cases - should all be treated as same header
|
||||
headers.append('Accept', 'application/json');
|
||||
headers.append('ACCEPT', 'text/html');
|
||||
headers.append('accept', 'text/plain');
|
||||
|
||||
// Verify all values are present using iteration
|
||||
const values = Array.from(headers.values());
|
||||
testing.expectEqual(3, values.length);
|
||||
testing.expectEqual('application/json', values[0]);
|
||||
testing.expectEqual('text/html', values[1]);
|
||||
testing.expectEqual('text/plain', values[2]);
|
||||
}
|
||||
|
||||
{
|
||||
const headers = new Headers();
|
||||
|
||||
// Set should replace regardless of case
|
||||
headers.set('Authorization', 'Bearer token1');
|
||||
headers.set('AUTHORIZATION', 'Bearer token2');
|
||||
|
||||
testing.expectEqual('Bearer token2', headers.get('authorization'));
|
||||
|
||||
// Should only have one entry after set replaces
|
||||
const entries = Array.from(headers.entries());
|
||||
testing.expectEqual(1, entries.length);
|
||||
testing.expectEqual('authorization', entries[0][0]);
|
||||
testing.expectEqual('Bearer token2', entries[0][1]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=iterators>
|
||||
// Test keys(), values(), entries() iterators
|
||||
{
|
||||
const headers = new Headers();
|
||||
headers.set('Content-Type', 'application/json');
|
||||
headers.set('Authorization', 'Bearer token123');
|
||||
headers.set('X-Custom', 'test-value');
|
||||
|
||||
// Test keys()
|
||||
const keys = Array.from(headers.keys());
|
||||
testing.expectEqual(3, keys.length);
|
||||
testing.expectEqual('content-type', keys[0]);
|
||||
testing.expectEqual('authorization', keys[1]);
|
||||
testing.expectEqual('x-custom', keys[2]);
|
||||
|
||||
// Test values()
|
||||
const values = Array.from(headers.values());
|
||||
testing.expectEqual(3, values.length);
|
||||
testing.expectEqual('application/json', values[0]);
|
||||
testing.expectEqual('Bearer token123', values[1]);
|
||||
testing.expectEqual('test-value', values[2]);
|
||||
|
||||
// Test entries()
|
||||
const entries = Array.from(headers.entries());
|
||||
testing.expectEqual(3, entries.length);
|
||||
testing.expectEqual('content-type', entries[0][0]);
|
||||
testing.expectEqual('application/json', entries[0][1]);
|
||||
testing.expectEqual('authorization', entries[1][0]);
|
||||
testing.expectEqual('Bearer token123', entries[1][1]);
|
||||
testing.expectEqual('x-custom', entries[2][0]);
|
||||
testing.expectEqual('test-value', entries[2][1]);
|
||||
}
|
||||
|
||||
// Test forEach()
|
||||
{
|
||||
const headers = new Headers();
|
||||
headers.set('Content-Type', 'application/json');
|
||||
headers.set('Authorization', 'Bearer token123');
|
||||
|
||||
const collected = [];
|
||||
headers.forEach(function(value, name, headersObj) {
|
||||
collected.push([name, value]);
|
||||
testing.expectEqual(headers, headersObj);
|
||||
});
|
||||
|
||||
testing.expectEqual(2, collected.length);
|
||||
testing.expectEqual('content-type', collected[0][0]);
|
||||
testing.expectEqual('application/json', collected[0][1]);
|
||||
testing.expectEqual('authorization', collected[1][0]);
|
||||
testing.expectEqual('Bearer token123', collected[1][1]);
|
||||
}
|
||||
|
||||
// Test forEach with thisArg
|
||||
{
|
||||
const headers = new Headers();
|
||||
headers.set('X-Test', 'value');
|
||||
|
||||
const context = { count: 0 };
|
||||
headers.forEach(function() {
|
||||
this.count++;
|
||||
}, context);
|
||||
|
||||
testing.expectEqual(1, context.count);
|
||||
}
|
||||
|
||||
// Test multiple values for same header using append
|
||||
{
|
||||
const headers = new Headers();
|
||||
headers.append('Accept', 'application/json');
|
||||
headers.append('Accept', 'text/html');
|
||||
headers.append('Accept', 'text/plain');
|
||||
|
||||
const all = headers.getAll('Accept');
|
||||
testing.expectEqual(2, all.length);
|
||||
testing.expectEqual('application/json', all[0]);
|
||||
testing.expectEqual('text/html', all[1]);
|
||||
const values = [];
|
||||
headers.forEach((value, name) => {
|
||||
if (name === 'accept') {
|
||||
values.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
testing.expectEqual(3, values.length);
|
||||
testing.expectEqual('application/json', values[0]);
|
||||
testing.expectEqual('text/html', values[1]);
|
||||
testing.expectEqual('text/plain', values[2]);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -75,7 +75,7 @@ pub fn forEach(self: *NodeList, cb: js.Function, page: *Page) !void {
|
||||
|
||||
var result: js.Function.Result = undefined;
|
||||
cb.tryCall(void, .{ next.value, i, self }, &result) catch {
|
||||
log.debug(.js, "forEach callback", .{ .err = result.exception, .stack = result.stack });
|
||||
log.debug(.js, "forEach callback", .{ .err = result.exception, .stack = result.stack, .source = "nodelist" });
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
const js = @import("../../js/js.zig");
|
||||
const log = @import("../../../log.zig");
|
||||
|
||||
const Page = @import("../../Page.zig");
|
||||
const KeyValueList = @import("../KeyValueList.zig");
|
||||
@@ -15,27 +16,58 @@ pub fn init(page: *Page) !*Headers {
|
||||
}
|
||||
|
||||
pub fn append(self: *Headers, name: []const u8, value: []const u8, page: *Page) !void {
|
||||
try self._list.append(page.arena, name, value);
|
||||
const normalized_name = normalizeHeaderName(name, page);
|
||||
try self._list.append(page.arena, normalized_name, value);
|
||||
}
|
||||
|
||||
pub fn delete(self: *Headers, name: []const u8) void {
|
||||
self._list.delete(name, null);
|
||||
pub fn delete(self: *Headers, name: []const u8, page: *Page) void {
|
||||
const normalized_name = normalizeHeaderName(name, page);
|
||||
self._list.delete(normalized_name, null);
|
||||
}
|
||||
|
||||
pub fn get(self: *const Headers, name: []const u8) ?[]const u8 {
|
||||
return self._list.get(name);
|
||||
pub fn get(self: *const Headers, name: []const u8, page: *Page) ?[]const u8 {
|
||||
const normalized_name = normalizeHeaderName(name, page);
|
||||
return self._list.get(normalized_name);
|
||||
}
|
||||
|
||||
pub fn getAll(self: *const Headers, name: []const u8, page: *Page) ![]const []const u8 {
|
||||
return self._list.getAll(name, page);
|
||||
}
|
||||
|
||||
pub fn has(self: *const Headers, name: []const u8) bool {
|
||||
return self._list.has(name);
|
||||
pub fn has(self: *const Headers, name: []const u8, page: *Page) bool {
|
||||
const normalized_name = normalizeHeaderName(name, page);
|
||||
return self._list.has(normalized_name);
|
||||
}
|
||||
|
||||
pub fn set(self: *Headers, name: []const u8, value: []const u8, page: *Page) !void {
|
||||
try self._list.set(page.arena, name, value);
|
||||
const normalized_name = normalizeHeaderName(name, page);
|
||||
try self._list.set(page.arena, normalized_name, value);
|
||||
}
|
||||
|
||||
pub fn keys(self: *Headers, page: *Page) !*KeyValueList.KeyIterator {
|
||||
return KeyValueList.KeyIterator.init(.{ .list = self, .kv = &self._list }, page);
|
||||
}
|
||||
|
||||
pub fn values(self: *Headers, page: *Page) !*KeyValueList.ValueIterator {
|
||||
return KeyValueList.ValueIterator.init(.{ .list = self, .kv = &self._list }, page);
|
||||
}
|
||||
|
||||
pub fn entries(self: *Headers, page: *Page) !*KeyValueList.EntryIterator {
|
||||
return KeyValueList.EntryIterator.init(.{ .list = self, .kv = &self._list }, page);
|
||||
}
|
||||
|
||||
pub fn forEach(self: *Headers, cb_: js.Function, js_this_: ?js.Object) !void {
|
||||
const cb = if (js_this_) |js_this| try cb_.withThis(js_this) else cb_;
|
||||
|
||||
for (self._list._entries.items) |entry| {
|
||||
var result: js.Function.Result = undefined;
|
||||
cb.tryCall(void, .{ entry.value.str(), entry.name.str(), self }, &result) catch {
|
||||
log.debug(.js, "forEach callback", .{ .err = result.exception, .stack = result.stack, .source = "headers" });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn normalizeHeaderName(name: []const u8, page: *Page) []const u8 {
|
||||
if (name.len > page.buf.len) {
|
||||
return name;
|
||||
}
|
||||
return std.ascii.lowerString(&page.buf, name);
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
@@ -51,9 +83,12 @@ pub const JsApi = struct {
|
||||
pub const append = bridge.function(Headers.append, .{});
|
||||
pub const delete = bridge.function(Headers.delete, .{});
|
||||
pub const get = bridge.function(Headers.get, .{});
|
||||
pub const getAll = bridge.function(Headers.getAll, .{});
|
||||
pub const has = bridge.function(Headers.has, .{});
|
||||
pub const set = bridge.function(Headers.set, .{});
|
||||
pub const keys = bridge.function(Headers.keys, .{});
|
||||
pub const values = bridge.function(Headers.values, .{});
|
||||
pub const entries = bridge.function(Headers.entries, .{});
|
||||
pub const forEach = bridge.function(Headers.forEach, .{});
|
||||
};
|
||||
|
||||
const testing = @import("../../../testing.zig");
|
||||
|
||||
Reference in New Issue
Block a user