aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/api/html_rewriter.zig
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/bun.js/api/html_rewriter.zig169
1 files changed, 88 insertions, 81 deletions
diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig
index bfbdb9a37..b309e07d7 100644
--- a/src/bun.js/api/html_rewriter.zig
+++ b/src/bun.js/api/html_rewriter.zig
@@ -106,7 +106,7 @@ pub const HTMLRewriter = struct {
var selector = LOLHTML.HTMLSelector.parse(selector_slice) catch
return throwLOLHTMLError(global);
- var handler_ = ElementHandler.init(global, listener, exception);
+ var handler_ = ElementHandler.init(global, listener, exception) catch return .zero;
if (exception.* != null) {
selector.deinit();
return JSValue.fromRef(exception.*);
@@ -154,7 +154,7 @@ pub const HTMLRewriter = struct {
thisObject: JSC.C.JSObjectRef,
exception: JSC.C.ExceptionRef,
) JSValue {
- var handler_ = DocumentHandler.init(global, listener, exception);
+ var handler_ = DocumentHandler.init(global, listener, exception) catch return .zero;
if (exception.* != null) {
return JSValue.fromRef(exception.*);
}
@@ -446,10 +446,14 @@ pub const HTMLRewriter = struct {
},
};
- 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;
+ // https://github.com/oven-sh/bun/issues/3334
+ if (original.body.init.headers) |headers| {
+ result.body.init.headers = headers.cloneThis(global);
+ }
+
result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable;
result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable;
@@ -472,13 +476,13 @@ pub const HTMLRewriter = struct {
pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
switch (bytes) {
.err => |err| {
- if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
+ if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
sink.response.body.value.Locked.promise == null)
{
sink.response.body.value = .{ .Empty = {} };
// is there a pending promise?
// we will need to reject it
- } else if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
+ } else if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
sink.response.body.value.Locked.promise != null)
{
sink.response.body.value.Locked.onReceiveValue = null;
@@ -723,29 +727,44 @@ const DocumentHandler = struct {
"onEndCallback",
);
- pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) DocumentHandler {
+ pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) !DocumentHandler {
var handler = DocumentHandler{
.thisObject = thisObject,
.global = global,
};
- switch (thisObject.jsType()) {
- .Object, .ProxyObject, .Cell, .FinalObject => {},
- else => |kind| {
- JSC.throwInvalidArguments(
- "Expected object but received {s}",
- .{@as(string, @tagName(kind))},
- global,
- exception,
- );
- return undefined;
- },
+ if (!thisObject.isObject()) {
+ JSC.throwInvalidArguments(
+ "Expected object",
+ .{},
+ global,
+ exception,
+ );
+ return error.InvalidArguments;
+ }
+
+ errdefer {
+ if (handler.onDocTypeCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onCommentCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onTextCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onEndCallback) |cb| {
+ cb.unprotect();
+ }
}
if (thisObject.get(global, "doctype")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("doctype must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onDocTypeCallback = val;
@@ -754,7 +773,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "comments")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("comments must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onCommentCallback = val;
@@ -763,7 +782,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "text")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("text must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onTextCallback = val;
@@ -772,7 +791,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "end")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("end must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onEndCallback = val;
@@ -863,29 +882,39 @@ const ElementHandler = struct {
global: *JSGlobalObject,
ctx: ?*HTMLRewriter.BufferOutputSink = null,
- pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) ElementHandler {
+ pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) !ElementHandler {
var handler = ElementHandler{
.thisObject = thisObject,
.global = global,
};
+ errdefer {
+ if (handler.onCommentCallback) |cb| {
+ cb.unprotect();
+ }
- switch (thisObject.jsType()) {
- .Object, .ProxyObject, .Cell, .FinalObject => {},
- else => |kind| {
- JSC.throwInvalidArguments(
- "Expected object but received {s}",
- .{@as(string, @tagName(kind))},
- global,
- exception,
- );
- return undefined;
- },
+ if (handler.onElementCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onTextCallback) |cb| {
+ cb.unprotect();
+ }
+ }
+
+ if (!thisObject.isObject()) {
+ JSC.throwInvalidArguments(
+ "Expected object",
+ .{},
+ global,
+ exception,
+ );
+ return error.InvalidArguments;
}
if (thisObject.get(global, "element")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("element must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onElementCallback = val;
@@ -894,7 +923,7 @@ const ElementHandler = struct {
if (thisObject.get(global, "comments")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("comments must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onCommentCallback = val;
@@ -903,7 +932,7 @@ const ElementHandler = struct {
if (thisObject.get(global, "text")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("text must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onTextCallback = val;
@@ -967,26 +996,14 @@ const getterWrap = JSC.getterWrap;
const setterWrap = JSC.setterWrap;
const wrap = JSC.wrapSync;
-pub fn free_html_writer_string(_: ?*anyopaque, ptr: ?*anyopaque, len: usize) callconv(.C) void {
- var str = LOLHTML.HTMLString{ .ptr = bun.cast([*]const u8, ptr.?), .len = len };
- str.deinit();
-}
-
fn throwLOLHTMLError(global: *JSGlobalObject) JSValue {
- var err = LOLHTML.HTMLString.lastError();
- return ZigString.init(err.slice()).toErrorInstance(global);
+ const err = LOLHTML.HTMLString.lastError();
+ defer err.deinit();
+ return ZigString.fromUTF8(err.slice()).toErrorInstance(global);
}
fn htmlStringValue(input: LOLHTML.HTMLString, globalObject: *JSGlobalObject) JSValue {
- var str = ZigString.init(
- input.slice(),
- );
- str.detectEncoding();
-
- return str.toExternalValueWithCallback(
- globalObject,
- free_html_writer_string,
- );
+ return input.toJS(globalObject);
}
pub const TextChunk = struct {
@@ -1016,6 +1033,9 @@ pub const TextChunk = struct {
.removed = .{
.get = getterWrap(TextChunk, "removed"),
},
+ .lastInTextNode = .{
+ .get = getterWrap(TextChunk, "lastInTextNode"),
+ },
.text = .{
.get = getterWrap(TextChunk, "getText"),
},
@@ -1084,6 +1104,10 @@ pub const TextChunk = struct {
return JSC.JSValue.jsBoolean(this.text_chunk.?.isRemoved());
}
+ pub fn lastInTextNode(this: *TextChunk, _: *JSGlobalObject) JSValue {
+ return JSC.JSValue.jsBoolean(this.text_chunk.?.isLastInTextNode());
+ }
+
pub fn finalize(this: *TextChunk) void {
this.text_chunk = null;
bun.default_allocator.destroy(this);
@@ -1292,7 +1316,7 @@ pub const Comment = struct {
pub fn getText(this: *Comment, global: *JSGlobalObject) JSValue {
if (this.comment == null)
return JSValue.jsNull();
- return ZigString.init(this.comment.?.getText().slice()).withEncoding().toValueGC(global);
+ return this.comment.?.getText().toJS(global);
}
pub fn setText(
@@ -1422,7 +1446,7 @@ pub const EndTag = struct {
if (this.end_tag == null)
return JSC.JSValue.jsUndefined();
- return ZigString.init(this.end_tag.?.getName().slice()).withEncoding().toValueGC(global);
+ return this.end_tag.?.getName().toJS(global);
}
pub fn setName(
@@ -1534,27 +1558,16 @@ pub const AttributeIterator = struct {
return JSC.JSValue.jsNull();
};
- // TODO: don't clone here
const value = attribute.value();
const name = attribute.name();
- defer name.deinit();
- defer value.deinit();
- var strs = [2]ZigString{
- ZigString.init(name.slice()),
- ZigString.init(value.slice()),
- };
-
- var valid_strs: []ZigString = strs[0..2];
-
- var array = JSC.JSValue.createStringArray(
+ return bun.String.toJSArray(
globalObject,
- valid_strs.ptr,
- valid_strs.len,
- true,
+ &[_]bun.String{
+ name.toString(),
+ value.toString(),
+ },
);
-
- return array;
}
};
pub const Element = struct {
@@ -1660,19 +1673,12 @@ pub const Element = struct {
var slice = name.toSlice(bun.default_allocator);
defer slice.deinit();
- var attr = this.element.?.getAttribute(slice.slice()).slice();
+ var attr = this.element.?.getAttribute(slice.slice());
if (attr.len == 0)
return JSC.JSValue.jsNull();
- var str = ZigString.init(
- attr,
- );
-
- return str.toExternalValueWithCallback(
- globalObject,
- free_html_writer_string,
- );
+ return attr.toJS(globalObject);
}
/// Returns a boolean indicating whether an attribute exists on the element.
@@ -1847,8 +1853,9 @@ pub const Element = struct {
pub fn getNamespaceURI(this: *Element, globalObject: *JSGlobalObject) JSValue {
if (this.element == null)
return JSValue.jsUndefined();
-
- return ZigString.init(std.mem.span(this.element.?.namespaceURI())).toValueGC(globalObject);
+ var str = bun.String.create(std.mem.span(this.element.?.namespaceURI()));
+ defer str.deref();
+ return str.toJS(globalObject);
}
pub fn getAttributes(this: *Element, globalObject: *JSGlobalObject) JSValue {