From 059fb85e22dd516dc56cf5319c11096600335b9a Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sat, 28 Feb 2026 14:42:43 +0800 Subject: [PATCH] Escape XHR URL, Lax MIME parameter parsing Follow up to https://github.com/lightpanda-io/browser/pull/1646 applies the same change to XHR URLs. Following specs, ignores unknown/invalid parameters of the Content-Type when parsing the MIME (rather than rejecting the entire header). --- src/browser/Mime.zig | 27 ++++++++++++++++++----- src/browser/webapi/element/Html.zig | 2 +- src/browser/webapi/net/XMLHttpRequest.zig | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/browser/Mime.zig b/src/browser/Mime.zig index 6c51d75f..43ca3632 100644 --- a/src/browser/Mime.zig +++ b/src/browser/Mime.zig @@ -133,12 +133,12 @@ pub fn parse(input: []u8) !Mime { var it = std.mem.splitScalar(u8, params, ';'); while (it.next()) |attr| { - const i = std.mem.indexOfScalarPos(u8, attr, 0, '=') orelse return error.Invalid; + const i = std.mem.indexOfScalarPos(u8, attr, 0, '=') orelse continue; const name = trimLeft(attr[0..i]); const value = trimRight(attr[i + 1 ..]); if (value.len == 0) { - return error.Invalid; + continue; } const attribute_name = std.meta.stringToEnum(enum { @@ -151,7 +151,7 @@ pub fn parse(input: []u8) !Mime { break; } - const attribute_value = try parseCharset(value); + const attribute_value = parseCharset(value) catch continue; @memcpy(charset[0..attribute_value.len], attribute_value); // Null-terminate right after attribute value. charset[attribute_value.len] = 0; @@ -335,6 +335,19 @@ test "Mime: invalid" { "text/ html", "text / html", "text/html other", + }; + + for (invalids) |invalid| { + const mutable_input = try testing.arena_allocator.dupe(u8, invalid); + try testing.expectError(error.Invalid, Mime.parse(mutable_input)); + } +} + +test "Mime: malformed parameters are ignored" { + defer testing.reset(); + + // These should all parse successfully as text/html with malformed params ignored + const valid_with_malformed_params = [_][]const u8{ "text/html; x", "text/html; x=", "text/html; x= ", @@ -343,11 +356,13 @@ test "Mime: invalid" { "text/html; charset=\"\"", "text/html; charset=\"", "text/html; charset=\"\\", + "text/html;\"", }; - for (invalids) |invalid| { - const mutable_input = try testing.arena_allocator.dupe(u8, invalid); - try testing.expectError(error.Invalid, Mime.parse(mutable_input)); + for (valid_with_malformed_params) |input| { + const mutable_input = try testing.arena_allocator.dupe(u8, input); + const mime = try Mime.parse(mutable_input); + try testing.expectEqual(.text_html, std.meta.activeTag(mime.content_type)); } } diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig index d6201010..07187384 100644 --- a/src/browser/webapi/element/Html.zig +++ b/src/browser/webapi/element/Html.zig @@ -415,7 +415,7 @@ fn setAttributeListener( ) !void { if (comptime IS_DEBUG) { log.debug(.event, "Html.setAttributeListener", .{ - .type = self._type, + .type = std.meta.activeTag(self._type), .listener_type = listener_type, }); } diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index fa37ff42..8e839ff6 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -183,7 +183,7 @@ pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8) !void const page = self._page; self._method = try parseMethod(method_); - self._url = try URL.resolve(self._arena, page.base(), url, .{ .always_dupe = true }); + self._url = try URL.resolve(self._arena, page.base(), url, .{ .always_dupe = true, .encode = true }); try self.stateChanged(.opened, page.js.local.?, page); }