mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 16:28:58 +00:00
Header case insensitive
This commit is contained in:
@@ -143,7 +143,6 @@
|
|||||||
// innerText does NOT parse HTML (unlike innerHTML)
|
// innerText does NOT parse HTML (unlike innerHTML)
|
||||||
d1.innerText = 'hello <div>world</div><b>!!</b>';
|
d1.innerText = 'hello <div>world</div><b>!!</b>';
|
||||||
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerText);
|
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerText);
|
||||||
console.warn(d1.innerHTML);
|
|
||||||
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerHTML);
|
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerHTML);
|
||||||
|
|
||||||
// Setting empty string clears children
|
// Setting empty string clears children
|
||||||
|
|||||||
@@ -17,15 +17,145 @@
|
|||||||
testing.expectEqual(null, headers.get('Content-Type'));
|
testing.expectEqual(null, headers.get('Content-Type'));
|
||||||
testing.expectEqual(false, headers.has('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();
|
const headers = new Headers();
|
||||||
headers.append('Accept', 'application/json');
|
headers.append('Accept', 'application/json');
|
||||||
headers.append('Accept', 'text/html');
|
headers.append('Accept', 'text/html');
|
||||||
|
headers.append('Accept', 'text/plain');
|
||||||
|
|
||||||
const all = headers.getAll('Accept');
|
const values = [];
|
||||||
testing.expectEqual(2, all.length);
|
headers.forEach((value, name) => {
|
||||||
testing.expectEqual('application/json', all[0]);
|
if (name === 'accept') {
|
||||||
testing.expectEqual('text/html', all[1]);
|
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>
|
</script>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ pub fn forEach(self: *NodeList, cb: js.Function, page: *Page) !void {
|
|||||||
|
|
||||||
var result: js.Function.Result = undefined;
|
var result: js.Function.Result = undefined;
|
||||||
cb.tryCall(void, .{ next.value, i, self }, &result) catch {
|
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;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const js = @import("../../js/js.zig");
|
const js = @import("../../js/js.zig");
|
||||||
|
const log = @import("../../../log.zig");
|
||||||
|
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
const KeyValueList = @import("../KeyValueList.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 {
|
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 {
|
pub fn delete(self: *Headers, name: []const u8, page: *Page) void {
|
||||||
self._list.delete(name, null);
|
const normalized_name = normalizeHeaderName(name, page);
|
||||||
|
self._list.delete(normalized_name, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: *const Headers, name: []const u8) ?[]const u8 {
|
pub fn get(self: *const Headers, name: []const u8, page: *Page) ?[]const u8 {
|
||||||
return self._list.get(name);
|
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 {
|
pub fn has(self: *const Headers, name: []const u8, page: *Page) bool {
|
||||||
return self._list.getAll(name, page);
|
const normalized_name = normalizeHeaderName(name, page);
|
||||||
}
|
return self._list.has(normalized_name);
|
||||||
|
|
||||||
pub fn has(self: *const Headers, name: []const u8) bool {
|
|
||||||
return self._list.has(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(self: *Headers, name: []const u8, value: []const u8, page: *Page) !void {
|
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 {
|
pub const JsApi = struct {
|
||||||
@@ -51,9 +83,12 @@ pub const JsApi = struct {
|
|||||||
pub const append = bridge.function(Headers.append, .{});
|
pub const append = bridge.function(Headers.append, .{});
|
||||||
pub const delete = bridge.function(Headers.delete, .{});
|
pub const delete = bridge.function(Headers.delete, .{});
|
||||||
pub const get = bridge.function(Headers.get, .{});
|
pub const get = bridge.function(Headers.get, .{});
|
||||||
pub const getAll = bridge.function(Headers.getAll, .{});
|
|
||||||
pub const has = bridge.function(Headers.has, .{});
|
pub const has = bridge.function(Headers.has, .{});
|
||||||
pub const set = bridge.function(Headers.set, .{});
|
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");
|
const testing = @import("../../../testing.zig");
|
||||||
|
|||||||
Reference in New Issue
Block a user