diff --git a/src/browser/fetch/Headers.zig b/src/browser/fetch/Headers.zig index 74157263..e6acd935 100644 --- a/src/browser/fetch/Headers.zig +++ b/src/browser/fetch/Headers.zig @@ -79,8 +79,8 @@ pub fn constructor(_init: ?HeadersInit, page: *Page) !Headers { return error.TypeError; } - const key = try page.arena.dupe(u8, pair[0]); - const value = try page.arena.dupe(u8, pair[1]); + const key = try arena.dupe(u8, pair[0]); + const value = try arena.dupe(u8, pair[1]); try headers.put(arena, key, value); } @@ -88,8 +88,8 @@ pub fn constructor(_init: ?HeadersInit, page: *Page) !Headers { .headers => |hdrs| { var iter = hdrs.headers.iterator(); while (iter.next()) |entry| { - const key = try page.arena.dupe(u8, entry.key_ptr.*); - const value = try page.arena.dupe(u8, entry.value_ptr.*); + const key = try arena.dupe(u8, entry.key_ptr.*); + const value = try arena.dupe(u8, entry.value_ptr.*); try headers.put(arena, key, value); } }, @@ -129,10 +129,29 @@ pub fn _delete(self: *Headers, name: []const u8) void { _ = self.headers.remove(name); } -// TODO: entries iterator -// They should be: -// 1. Sorted in lexicographical order. -// 2. Duplicate header names should be combined. +pub const HeaderEntryIterator = struct { + slot: [][]const u8, + iter: *HeaderHashMap.Iterator, + + // TODO: these SHOULD be in lexigraphical order but I'm not sure how actually + // important that is. + pub fn _next(self: *HeaderEntryIterator) !?[]const []const u8 { + if (self.iter.next()) |entry| { + self.slot[0] = entry.key_ptr.*; + self.slot[1] = entry.value_ptr.*; + return self.slot; + } else { + return null; + } + } +}; + +pub fn _entries(self: *const Headers, page: *Page) !HeaderEntryIterator { + const iter = try page.arena.create(HeaderHashMap.Iterator); + iter.* = self.headers.iterator(); + + return .{ .slot = try page.arena.alloc([]const u8, 2), .iter = iter }; +} pub fn _forEach(self: *Headers, callback_fn: Env.Function, this_arg: ?Env.JsObject) !void { var iter = self.headers.iterator(); @@ -163,7 +182,24 @@ pub fn _has(self: *const Headers, name: []const u8) bool { return self.headers.contains(name); } -// TODO: keys iterator +pub const HeaderKeyIterator = struct { + iter: *HeaderHashMap.KeyIterator, + + pub fn _next(self: *HeaderKeyIterator) !?[]const u8 { + if (self.iter.next()) |key| { + return key.*; + } else { + return null; + } + } +}; + +pub fn _keys(self: *const Headers, page: *Page) !HeaderKeyIterator { + const iter = try page.arena.create(HeaderHashMap.KeyIterator); + iter.* = self.headers.keyIterator(); + + return .{ .iter = iter }; +} pub fn _set(self: *Headers, name: []const u8, value: []const u8, page: *Page) !void { const arena = page.arena; @@ -172,7 +208,23 @@ pub fn _set(self: *Headers, name: []const u8, value: []const u8, page: *Page) !v gop.value_ptr.* = try arena.dupe(u8, value); } -// TODO: values iterator +pub const HeaderValueIterator = struct { + iter: *HeaderHashMap.ValueIterator, + + pub fn _next(self: *HeaderValueIterator) !?[]const u8 { + if (self.iter.next()) |value| { + return value.*; + } else { + return null; + } + } +}; + +pub fn _values(self: *const Headers, page: *Page) !HeaderValueIterator { + const iter = try page.arena.create(HeaderHashMap.ValueIterator); + iter.* = self.headers.valueIterator(); + return .{ .iter = iter }; +} const testing = @import("../../testing.zig"); test "fetch: headers" { diff --git a/src/browser/fetch/Request.zig b/src/browser/fetch/Request.zig index 6f4e3751..cf59c32e 100644 --- a/src/browser/fetch/Request.zig +++ b/src/browser/fetch/Request.zig @@ -98,7 +98,7 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re const arena = page.arena; const options: RequestInit = _options orelse .{}; - const url = blk: switch (input) { + const url: [:0]const u8 = blk: switch (input) { .string => |str| { break :blk try URL.stitch(arena, str, page.url.raw, .{ .null_terminated = true }); }, @@ -111,7 +111,7 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re const cache = (if (options.cache) |cache| RequestCache.fromString(cache) else null) orelse RequestCache.default; const credentials = (if (options.credentials) |creds| RequestCredentials.fromString(creds) else null) orelse RequestCredentials.@"same-origin"; const integrity = if (options.integrity) |integ| try arena.dupe(u8, integ) else ""; - const headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else Headers{}; + const headers: Headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else .{}; const method: Http.Method = blk: { if (options.method) |given_method| { diff --git a/src/browser/fetch/Response.zig b/src/browser/fetch/Response.zig index 21a950de..858e8487 100644 --- a/src/browser/fetch/Response.zig +++ b/src/browser/fetch/Response.zig @@ -37,7 +37,7 @@ const Page = @import("../page.zig").Page; const Response = @This(); status: u16 = 0, -headers: Headers = .{}, +headers: Headers, mime: ?Mime = null, url: []const u8 = "", body: []const u8 = "", diff --git a/src/browser/fetch/fetch.zig b/src/browser/fetch/fetch.zig index fc8e9b78..a9e47ea8 100644 --- a/src/browser/fetch/fetch.zig +++ b/src/browser/fetch/fetch.zig @@ -26,6 +26,7 @@ const Page = @import("../page.zig").Page; const Http = @import("../../http/Http.zig"); const HttpClient = @import("../../http/Client.zig"); const Mime = @import("../mime.zig").Mime; + const Headers = @import("Headers.zig"); const RequestInput = @import("Request.zig").RequestInput; @@ -35,6 +36,9 @@ const Response = @import("Response.zig"); pub const Interfaces = .{ @import("Headers.zig"), + @import("Headers.zig").HeaderEntryIterator, + @import("Headers.zig").HeaderKeyIterator, + @import("Headers.zig").HeaderValueIterator, @import("Request.zig"), @import("Response.zig"), }; @@ -157,6 +161,7 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi .done_callback = struct { fn doneCallback(ctx: *anyopaque) !void { const self: *FetchContext = @ptrCast(@alignCast(ctx)); + self.transfer = null; log.info(.http, "request complete", .{ .source = "fetch", @@ -177,8 +182,8 @@ pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promi .error_callback = struct { fn errorCallback(ctx: *anyopaque, err: anyerror) void { const self: *FetchContext = @ptrCast(@alignCast(ctx)); - self.transfer = null; + const promise_resolver: Env.PromiseResolver = .{ .js_context = self.js_ctx, .resolver = self.promise_resolver.castToPromiseResolver(),