Conversation
|
@mookums the PR is in draft, is it ready for review? |
|
Was mostly finished but needed some updating on some tests. |
3b214ff to
8b7b46b
Compare
|
@mookums are you still working on this one? |
b2b13e0 to
5ab8c12
Compare
|
Yeah, done now. It supports taking in a ReadableStream for the Request body, consuming it before use and throwing an error if it isn't ready. It prevents the error on #3163 that is present on main. |
krichprollsch
left a comment
There was a problem hiding this comment.
One suggestion to resolve the sharing stream issue could be:
// Resolve a stream body to bytes on first need, so every copy (clone(), or
// `new Request(other)`) owns its own bytes. Null means no body.
fn resolveBody(self: *Request) !?[]const u8 {
switch (self._body) {
.none => return null,
.bytes => |b| return b,
.stream => |s| {
const collected = s.collectBodyBytes(self._arena.allocator()) catch return error.TypeError;
self._body = .{ .bytes = collected };
return collected;
},
}
}Then:
pub fn clone(self: *Request, exec: *const Execution) !*Request {
// Fetch: clone() throws if the body is already disturbed.
if (self._body_used) return error.TypeError;
const body = try self.resolveBody();
const arena = try exec.getPinnedArena(if (body) |b| b.len else 512, "Request.clone");
errdefer arena.release();
...
._body = if (body) |b| .{ .bytes = try arena.dupe(u8, b) } else .none,and
.request => |r| blk: {
if (r._body_used) return error.TypeError;
break :blk if (try r.resolveBody()) |b| .{ .bytes = try arena.dupe(u8, b) } else .none;
},
Or we need Tee for request clone
| fn consume(self: *Request, local: *const js.Local) ?js.Promise { | ||
| if (self._body == null) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Shouldn't we keep this early return by testing the case of body == .none?
|
|
||
| pub fn clone(self: *const Request, exec: *const Execution) !*Request { | ||
| const arena = try exec.getPinnedArena(if (self._body) |b| b.len else 512, "Request.clone"); | ||
| const arena = try exec.getPinnedArena(512, "Request.clone"); |
There was a problem hiding this comment.
Keep the hint when body is bytes.
const arena = try exec.getPinnedArena(switch (self._body) {
.bytes => |b| b.len,
.none, .stream => 512,
}, "Request.clone");
| } | ||
|
|
||
| const body_bytes: []const u8 = switch (request._body) { | ||
| .stream => |stream| stream.collectBodyBytes(request._arena.allocator()) catch { |
There was a problem hiding this comment.
You drain the stream, but you let the request in an invalid state.
you should replace the request's body with the collected bytes.
as you do in Request.consume
| switch (self) { | ||
| .none => return .none, | ||
| .bytes => |b| return .{ .bytes = try allocator.dupe(u8, b) }, | ||
| .stream => |s| return .{ .stream = s }, |
There was a problem hiding this comment.
Not sure it's safe to share the stream. If one collect it, the other won't be updated 🤔
| .none => .none, | ||
| .bytes => |b| .{ .bytes = try arena.dupe(u8, b) }, | ||
| .stream => |s| blk: { | ||
| break :blk .{ .stream = s }; |
There was a problem hiding this comment.
same about sharing the stream
This adds support for
Requesttaking aReadableStream.https://developer.mozilla.org/en-US/docs/Web/API/Request/duplex