aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/api/html_rewriter.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc/api/html_rewriter.zig')
-rw-r--r--src/javascript/jsc/api/html_rewriter.zig107
1 files changed, 79 insertions, 28 deletions
diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig
index e314fc18d..3ea438556 100644
--- a/src/javascript/jsc/api/html_rewriter.zig
+++ b/src/javascript/jsc/api/html_rewriter.zig
@@ -208,20 +208,28 @@ pub const HTMLRewriter = struct {
this.context.deinit(bun.default_allocator);
}
+ pub fn beginTransform(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
+ const new_context = this.context;
+ this.context = .{};
+ return BufferOutputSink.init(new_context, global, response, this.builder);
+ }
+
+ pub fn returnEmptyResponse(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
+ var result = bun.default_allocator.create(Response) catch unreachable;
+
+ response.cloneInto(result, getAllocator(global.ref()));
+ this.finalizeWithoutDestroy();
+ return JSValue.fromRef(Response.makeMaybePooled(global.ref(), result));
+ }
+
pub fn transform(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
var input = response.body.slice();
- if (input.len == 0) {
- var result = bun.default_allocator.create(Response) catch unreachable;
-
- response.cloneInto(result, getAllocator(global.ref()));
- this.finalizeWithoutDestroy();
- return JSValue.fromRef(Response.makeMaybePooled(global.ref(), result));
+ if (input.len == 0 and !(response.body.value == .Blob and response.body.value.Blob.needsToReadFile())) {
+ return this.returnEmptyResponse(global, response);
}
- var new_context = this.context;
- this.context = .{};
- return BufferOutputSink.init(new_context, global, response, this.builder);
+ return this.beginTransform(global, response);
}
pub const BufferOutputSink = struct {
@@ -230,7 +238,7 @@ pub const HTMLRewriter = struct {
rewriter: *LOLHTML.HTMLRewriter,
context: LOLHTMLContext,
response: *Response,
-
+ input: JSC.WebCore.Blob = undefined,
pub fn init(context: LOLHTMLContext, global: *JSGlobalObject, original: *Response, builder: *LOLHTML.HTMLRewriter.Builder) JSValue {
var result = bun.default_allocator.create(Response) catch unreachable;
var sink = bun.default_allocator.create(BufferOutputSink) catch unreachable;
@@ -252,7 +260,7 @@ pub const HTMLRewriter = struct {
sink.rewriter = builder.build(
.UTF8,
.{
- .preallocated_parsing_buffer_size = original.body.len(),
+ .preallocated_parsing_buffer_size = @maximum(original.body.len(), 1024),
.max_allowed_memory_usage = std.math.maxInt(u32),
},
false,
@@ -282,19 +290,7 @@ pub const HTMLRewriter = struct {
},
},
};
- {
- var input = original.body.value.use();
- sink.bytes.growBy(input.sharedView().len) catch unreachable;
- defer input.detach();
- sink.rewriter.write(input.sharedView()) catch {
- sink.deinit();
- bun.default_allocator.destroy(result);
-
- return throwLOLHTMLError(global);
- };
- }
- // Hold off on cloning until we're actually done.
result.body.init.headers = original.body.init.headers;
result.body.init.method = original.body.init.method;
result.body.init.status_code = original.body.init.status_code;
@@ -302,17 +298,72 @@ pub const HTMLRewriter = struct {
result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable;
result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable;
+ var input: JSC.WebCore.Blob = original.body.value.use();
+
+ const is_pending = input.needsToReadFile();
+ defer if (!is_pending) input.detach();
+
+ if (input.needsToReadFile()) {
+ input.doReadFileInternal(*BufferOutputSink, sink, onFinishedLoading, global);
+ } else if (sink.runOutputSink(input.sharedView())) |error_value| {
+ return error_value;
+ }
+
+ // Hold off on cloning until we're actually done.
+
+ return JSC.JSValue.fromRef(
+ Response.makeMaybePooled(sink.global.ref(), sink.response),
+ );
+ }
+
+ pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: anyerror![]u8) void {
+ var input = sink.input;
+ defer input.detach();
+ const data = bytes catch |err| {
+ if (sink.response.body.value == .Locked and sink.response.body.value.Locked.task == sink) {
+ sink.response.body.value = .{ .Empty = .{} };
+ }
+
+ sink.response.body.value.toError(err, sink.global);
+ sink.rewriter.end() catch {};
+ sink.deinit();
+ return;
+ };
+
+ _ = sink.runOutputSink(data, true);
+ }
+
+ pub fn runOutputSink(sink: *BufferOutputSink, bytes: []const u8, is_async: bool) ?JSValue {
+ sink.bytes.growBy(bytes) catch unreachable;
+ var global = sink.global;
+ var response = sink.response;
+ sink.rewriter.write(bytes) catch {
+ sink.deinit();
+ bun.default_allocator.destroy(sink);
+
+ if (is_async) {
+ response.body.value.toErrorInstance(throwLOLHTMLError(global), global);
+
+ return null;
+ } else {
+ return throwLOLHTMLError(global);
+ }
+ };
+
sink.rewriter.end() catch {
- result.finalize();
+ if (!is_async) response.finalize();
sink.response = undefined;
sink.deinit();
- return throwLOLHTMLError(global);
+ if (is_async) {
+ response.body.value.toErrorInstance(throwLOLHTMLError(global), global);
+ return null;
+ } else {
+ return throwLOLHTMLError(global);
+ }
};
- return JSC.JSValue.fromRef(
- Response.makeMaybePooled(sink.global.ref(), sink.response),
- );
+ return null;
}
pub const Sync = enum { suspended, pending, done };