Skip to content

Commit 8ccf8e7

Browse files
committed
expand Request/Response interfaces
1 parent 152d7d4 commit 8ccf8e7

File tree

5 files changed

+143
-29
lines changed

5 files changed

+143
-29
lines changed

src/browser/fetch/Request.zig

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ const URL = @import("../../url.zig").URL;
2323
const Page = @import("../page.zig").Page;
2424

2525
const Response = @import("./Response.zig");
26-
2726
const Http = @import("../../http/Http.zig");
27+
const ReadableStream = @import("../streams/ReadableStream.zig");
2828

2929
const v8 = @import("v8");
3030
const Env = @import("../env.zig").Env;
@@ -37,19 +37,58 @@ pub const RequestInput = union(enum) {
3737
request: *Request,
3838
};
3939

40+
pub const RequestCache = enum {
41+
default,
42+
@"no-store",
43+
reload,
44+
@"no-cache",
45+
@"force-cache",
46+
@"only-if-cached",
47+
48+
pub fn fromString(str: []const u8) ?RequestCache {
49+
for (std.enums.values(RequestCache)) |cache| {
50+
if (std.ascii.eqlIgnoreCase(str, @tagName(cache))) {
51+
return cache;
52+
}
53+
} else {
54+
return null;
55+
}
56+
}
57+
};
58+
59+
pub const RequestCredentials = enum {
60+
omit,
61+
@"same-origin",
62+
include,
63+
64+
pub fn fromString(str: []const u8) ?RequestCredentials {
65+
for (std.enums.values(RequestCredentials)) |cache| {
66+
if (std.ascii.eqlIgnoreCase(str, @tagName(cache))) {
67+
return cache;
68+
}
69+
} else {
70+
return null;
71+
}
72+
}
73+
};
74+
4075
// https://developer.mozilla.org/en-US/docs/Web/API/RequestInit
4176
pub const RequestInit = struct {
42-
method: ?[]const u8 = null,
4377
body: ?[]const u8 = null,
44-
integrity: ?[]const u8 = null,
78+
cache: ?[]const u8 = null,
79+
credentials: ?[]const u8 = null,
4580
headers: ?HeadersInit = null,
81+
integrity: ?[]const u8 = null,
82+
method: ?[]const u8 = null,
4683
};
4784

4885
// https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
4986
const Request = @This();
5087

5188
method: Http.Method,
5289
url: [:0]const u8,
90+
cache: RequestCache,
91+
credentials: RequestCredentials,
5392
headers: Headers,
5493
body: ?[]const u8,
5594
body_used: bool = false,
@@ -68,6 +107,12 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re
68107
},
69108
};
70109

110+
const body = if (options.body) |body| try arena.dupe(u8, body) else null;
111+
const cache = (if (options.cache) |cache| RequestCache.fromString(cache) else null) orelse RequestCache.default;
112+
const credentials = (if (options.credentials) |creds| RequestCredentials.fromString(creds) else null) orelse RequestCredentials.@"same-origin";
113+
const integrity = if (options.integrity) |integ| try arena.dupe(u8, integ) else "";
114+
const headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else Headers{};
115+
71116
const method: Http.Method = blk: {
72117
if (options.method) |given_method| {
73118
for (std.enums.values(Http.Method)) |method| {
@@ -82,27 +127,33 @@ pub fn constructor(input: RequestInput, _options: ?RequestInit, page: *Page) !Re
82127
}
83128
};
84129

85-
const body = if (options.body) |body| try arena.dupe(u8, body) else null;
86-
const integrity = if (options.integrity) |integ| try arena.dupe(u8, integ) else "";
87-
const headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else Headers{};
88-
89130
return .{
90131
.method = method,
91132
.url = url,
133+
.cache = cache,
134+
.credentials = credentials,
92135
.headers = headers,
93136
.body = body,
94137
.integrity = integrity,
95138
};
96139
}
97140

98-
// pub fn get_body(self: *const Request) ?[]const u8 {
99-
// return self.body;
100-
// }
141+
pub fn get_body(self: *const Request, page: *Page) !?*ReadableStream {
142+
if (self.body) |body| {
143+
const stream = try ReadableStream.constructor(null, null, page);
144+
try stream.queue.append(page.arena, body);
145+
return stream;
146+
} else return null;
147+
}
101148

102149
pub fn get_bodyUsed(self: *const Request) bool {
103150
return self.body_used;
104151
}
105152

153+
pub fn get_cache(self: *const Request) RequestCache {
154+
return self.cache;
155+
}
156+
106157
pub fn get_headers(self: *Request) *Headers {
107158
return &self.headers;
108159
}
@@ -133,6 +184,8 @@ pub fn _clone(self: *Request, page: *Page) !Request {
133184
return Request{
134185
.body = if (self.body) |body| try arena.dupe(u8, body) else null,
135186
.body_used = self.body_used,
187+
.cache = self.cache,
188+
.credentials = self.credentials,
136189
.headers = try self.headers.clone(arena),
137190
.method = self.method,
138191
.integrity = try arena.dupe(u8, self.integrity),

src/browser/fetch/Response.zig

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ const v8 = @import("v8");
2424
const HttpClient = @import("../../http/Client.zig");
2525
const Http = @import("../../http/Http.zig");
2626
const URL = @import("../../url.zig").URL;
27+
28+
const ReadableStream = @import("../streams/ReadableStream.zig");
29+
const Headers = @import("Headers.zig");
30+
const HeadersInit = @import("Headers.zig").HeadersInit;
31+
2732
const Env = @import("../env.zig").Env;
2833
const Mime = @import("../mime.zig").Mime;
2934
const Page = @import("../page.zig").Page;
@@ -32,26 +37,28 @@ const Page = @import("../page.zig").Page;
3237
const Response = @This();
3338

3439
status: u16 = 0,
35-
headers: []const []const u8,
40+
headers: Headers = .{},
3641
mime: ?Mime = null,
37-
body: []const u8,
42+
url: []const u8 = "",
43+
body: []const u8 = "",
3844
body_used: bool = false,
3945
redirected: bool = false,
4046

41-
const ResponseInput = union(enum) {
47+
const ResponseBody = union(enum) {
4248
string: []const u8,
4349
};
4450

4551
const ResponseOptions = struct {
4652
status: u16 = 200,
4753
statusText: []const u8 = "",
48-
// List of header pairs.
49-
headers: []const []const u8 = &[][].{},
54+
headers: ?HeadersInit = null,
5055
};
5156

52-
pub fn constructor(_input: ?ResponseInput, page: *Page) !Response {
57+
pub fn constructor(_input: ?ResponseBody, _options: ?ResponseOptions, page: *Page) !Response {
5358
const arena = page.arena;
5459

60+
const options: ResponseOptions = _options orelse .{};
61+
5562
const body = blk: {
5663
if (_input) |input| {
5764
switch (input) {
@@ -64,20 +71,32 @@ pub fn constructor(_input: ?ResponseInput, page: *Page) !Response {
6471
}
6572
};
6673

74+
const headers: Headers = if (options.headers) |hdrs| try Headers.constructor(hdrs, page) else .{};
75+
6776
return .{
6877
.body = body,
69-
.headers = &[_][]const u8{},
78+
.headers = headers,
7079
};
7180
}
7281

73-
pub fn get_ok(self: *const Response) bool {
74-
return self.status >= 200 and self.status <= 299;
82+
pub fn get_body(self: *const Response, page: *Page) !*ReadableStream {
83+
const stream = try ReadableStream.constructor(null, null, page);
84+
try stream.queue.append(page.arena, self.body);
85+
return stream;
7586
}
7687

7788
pub fn get_bodyUsed(self: *const Response) bool {
7889
return self.body_used;
7990
}
8091

92+
pub fn get_headers(self: *Response) *Headers {
93+
return &self.headers;
94+
}
95+
96+
pub fn get_ok(self: *const Response) bool {
97+
return self.status >= 200 and self.status <= 299;
98+
}
99+
81100
pub fn get_redirected(self: *const Response) bool {
82101
return self.redirected;
83102
}
@@ -86,6 +105,28 @@ pub fn get_status(self: *const Response) u16 {
86105
return self.status;
87106
}
88107

108+
pub fn get_url(self: *const Response) []const u8 {
109+
return self.url;
110+
}
111+
112+
pub fn _clone(self: *const Response, page: *Page) !Response {
113+
if (self.body_used) {
114+
return error.TypeError;
115+
}
116+
117+
const arena = page.arena;
118+
119+
return Response{
120+
.body = try arena.dupe(u8, self.body),
121+
.body_used = self.body_used,
122+
.mime = if (self.mime) |mime| try mime.clone(arena) else null,
123+
.headers = try self.headers.clone(arena),
124+
.redirected = self.redirected,
125+
.status = self.status,
126+
.url = try arena.dupe(u8, self.url),
127+
};
128+
}
129+
89130
pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
90131
if (self.body_used) {
91132
return error.TypeError;

src/browser/mime.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,22 @@ pub const Mime = struct {
281281
fn trimRight(s: []const u8) []const u8 {
282282
return std.mem.trimRight(u8, s, &std.ascii.whitespace);
283283
}
284+
285+
pub fn clone(self: *const Mime, allocator: Allocator) !Mime {
286+
return Mime{
287+
.content_type = blk: {
288+
switch (self.content_type) {
289+
.other => |data| break :blk ContentType{ .other = .{
290+
.type = try allocator.dupe(u8, data.type),
291+
.sub_type = try allocator.dupe(u8, data.sub_type),
292+
} },
293+
else => break :blk self.content_type,
294+
}
295+
},
296+
.params = try allocator.dupe(u8, self.params),
297+
.charset = if (self.charset) |charset| try allocator.dupeZ(u8, charset) else null,
298+
};
299+
}
284300
};
285301

286302
const testing = @import("../testing.zig");

src/browser/streams/ReadableStream.zig

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ const State = union(enum) {
3434
};
3535

3636
// This promise resolves when a stream is canceled.
37-
cancel_resolver: Env.PromiseResolver,
37+
cancel_resolver: v8.Persistent(v8.PromiseResolver),
3838
locked: bool = false,
3939
state: State = .readable,
4040

41-
// A queue would be ideal here but I don't want to pay the cost of the priority operation.
4241
queue: std.ArrayListUnmanaged([]const u8) = .empty,
4342

4443
const UnderlyingSource = struct {
@@ -56,10 +55,10 @@ const QueueingStrategy = struct {
5655
pub fn constructor(underlying: ?UnderlyingSource, strategy: ?QueueingStrategy, page: *Page) !*ReadableStream {
5756
_ = strategy;
5857

59-
const cancel_resolver = Env.PromiseResolver{
60-
.js_context = page.main_context,
61-
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
62-
};
58+
const cancel_resolver = v8.Persistent(v8.PromiseResolver).init(
59+
page.main_context.isolate,
60+
v8.PromiseResolver.init(page.main_context.v8_context),
61+
);
6362

6463
const stream = try page.arena.create(ReadableStream);
6564
stream.* = ReadableStream{ .cancel_resolver = cancel_resolver };
@@ -76,8 +75,13 @@ pub fn constructor(underlying: ?UnderlyingSource, strategy: ?QueueingStrategy, p
7675
return stream;
7776
}
7877

79-
pub fn _cancel(self: *const ReadableStream) Env.Promise {
80-
return self.cancel_resolver.promise();
78+
pub fn _cancel(self: *const ReadableStream, page: *Page) Env.Promise {
79+
const resolver = Env.PromiseResolver{
80+
.js_context = page.main_context,
81+
.resolver = self.cancel_resolver.castToPromiseResolver(),
82+
};
83+
84+
return resolver.promise();
8185
}
8286

8387
pub fn get_locked(self: *const ReadableStream) bool {

src/browser/streams/ReadableStreamDefaultReader.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ pub fn get_closed(self: *const ReadableStreamDefaultReader) Env.Promise {
4747
return self.closed_resolver.promise();
4848
}
4949

50-
pub fn _cancel(self: *ReadableStreamDefaultReader) Env.Promise {
51-
return self.stream._cancel();
50+
pub fn _cancel(self: *ReadableStreamDefaultReader, page: *Page) Env.Promise {
51+
return self.stream._cancel(page);
5252
}
5353

5454
pub const ReadableStreamReadResult = struct {

0 commit comments

Comments
 (0)