aboutsummaryrefslogtreecommitdiff
path: root/src/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript')
-rw-r--r--src/javascript/jsc/base.zig74
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp15
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp11
-rw-r--r--src/javascript/jsc/bindings/bindings.zig11
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h2
-rw-r--r--src/javascript/jsc/bindings/headers.h4
-rw-r--r--src/javascript/jsc/bindings/headers.zig33
-rw-r--r--src/javascript/jsc/javascript.zig6
-rw-r--r--src/javascript/jsc/webcore/response.zig514
9 files changed, 515 insertions, 155 deletions
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index 58075dc38..3a0355503 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -726,11 +726,15 @@ pub fn NewClass(
var static_functions = brk: {
var funcs: [function_name_refs.len + 1]js.JSStaticFunction = undefined;
- std.mem.set(js.JSStaticFunction, &funcs, js.JSStaticFunction{
- .name = @intToPtr([*c]const u8, 0),
- .callAsFunction = null,
- .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
- },);
+ std.mem.set(
+ js.JSStaticFunction,
+ &funcs,
+ js.JSStaticFunction{
+ .name = @intToPtr([*c]const u8, 0),
+ .callAsFunction = null,
+ .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
+ },
+ );
break :brk funcs;
};
var instance_functions = std.mem.zeroes([function_names.len]js.JSObjectRef);
@@ -738,36 +742,40 @@ pub fn NewClass(
var property_name_refs = std.mem.zeroes([property_names.len]js.JSStringRef);
const property_name_literals = property_names;
var static_properties = brk: {
- var props: [property_names.len]js.JSStaticValue = undefined;
- std.mem.set(js.JSStaticValue, &props, js.JSStaticValue{
- .name = @intToPtr([*c]const u8, 0),
- .getProperty = null,
- .setProperty = null,
- .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
- },);
+ var props: [property_names.len]js.JSStaticValue = undefined;
+ std.mem.set(
+ js.JSStaticValue,
+ &props,
+ js.JSStaticValue{
+ .name = @intToPtr([*c]const u8, 0),
+ .getProperty = null,
+ .setProperty = null,
+ .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
+ },
+ );
break :brk props;
};
pub var ref: js.JSClassRef = null;
pub var loaded = false;
- pub var definition: js.JSClassDefinition =.{
- .version = 0,
- .attributes = js.JSClassAttributes.kJSClassAttributeNone,
- .className = name[0..:0].ptr,
- .parentClass = null,
- .staticValues = null,
- .staticFunctions = null,
- .initialize = null,
- .finalize = null,
- .hasProperty = null,
- .getProperty = null,
- .setProperty = null,
- .deleteProperty = null,
- .getPropertyNames = null,
- .callAsFunction = null,
- .callAsConstructor = null,
- .hasInstance = null,
- .convertToType = null,
+ pub var definition: js.JSClassDefinition = .{
+ .version = 0,
+ .attributes = js.JSClassAttributes.kJSClassAttributeNone,
+ .className = name[0.. :0].ptr,
+ .parentClass = null,
+ .staticValues = null,
+ .staticFunctions = null,
+ .initialize = null,
+ .finalize = null,
+ .hasProperty = null,
+ .getProperty = null,
+ .setProperty = null,
+ .deleteProperty = null,
+ .getPropertyNames = null,
+ .callAsFunction = null,
+ .callAsConstructor = null,
+ .hasInstance = null,
+ .convertToType = null,
};
const ConstructorWrapper = struct {
pub fn rfn(
@@ -1326,7 +1334,7 @@ pub fn NewClass(
.callAsConstructor = null,
.hasInstance = null,
.convertToType = null,
- };
+ };
if (static_functions.len > 0) {
std.mem.set(js.JSStaticFunction, &static_functions, std.mem.zeroes(js.JSStaticFunction));
@@ -1338,6 +1346,8 @@ pub fn NewClass(
def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor.rfn).rfn;
} else if (comptime strings.eqlComptime(function_names[i], "finalize")) {
def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize.rfn).rfn;
+ } else if (comptime strings.eqlComptime(function_names[i], "call")) {
+ def.callAsFunction = To.JS.Callback(ZigType, staticFunctions.call.rfn).rfn;
} else if (comptime strings.eqlComptime(function_names[i], "callAsFunction")) {
const ctxfn = @field(staticFunctions, function_names[i]).rfn;
const Func: std.builtin.TypeInfo.Fn = @typeInfo(@TypeOf(ctxfn)).Fn;
@@ -1379,6 +1389,8 @@ pub fn NewClass(
def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor).rfn;
} else if (comptime strings.eqlComptime(function_names[i], "finalize")) {
def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize).rfn;
+ } else if (comptime strings.eqlComptime(function_names[i], "call")) {
+ def.callAsFunction = To.JS.Callback(ZigType, staticFunctions.call).rfn;
} else {
var callback = To.JS.Callback(
ZigType,
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index ea7e89141..8caf09662 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -165,7 +165,7 @@ void GlobalObject::setConsole(void *console) {
// and any other objects available globally.
void GlobalObject::installAPIGlobals(JSClassRef *globals, int count) {
WTF::Vector<GlobalPropertyInfo> extraStaticGlobals;
- extraStaticGlobals.reserveCapacity((size_t)count + 1);
+ extraStaticGlobals.reserveCapacity((size_t)count + 2);
// This is not nearly a complete implementation. It's just enough to make some npm packages that
// were compiled with Webpack to run without crashing in this environment.
@@ -223,9 +223,7 @@ JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject *globalObject,
res.success = false;
ZigString keyZ = toZigString(key, globalObject);
ZigString referrerZ = referrer.isString() ? toZigString(referrer, globalObject) : ZigStringEmpty;
- Zig__GlobalObject__resolve(&res, globalObject, &keyZ,
- &referrerZ
- );
+ Zig__GlobalObject__resolve(&res, globalObject, &keyZ, &referrerZ);
if (res.success) {
return toIdentifier(res.result.value, globalObject);
@@ -250,11 +248,9 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderImportModule(JSGlobalObject *g
auto sourceURL = sourceOrigin.url();
ErrorableZigString resolved;
auto moduleNameZ = toZigString(moduleNameValue, globalObject);
- auto sourceOriginZ = sourceURL.isEmpty() ? ZigStringCwd
- : toZigString(sourceURL.fileSystemPath());
+ auto sourceOriginZ = sourceURL.isEmpty() ? ZigStringCwd : toZigString(sourceURL.fileSystemPath());
resolved.success = false;
- Zig__GlobalObject__resolve(&resolved, globalObject, &moduleNameZ, &sourceOriginZ
- );
+ Zig__GlobalObject__resolve(&resolved, globalObject, &moduleNameZ, &sourceOriginZ);
if (!resolved.success) {
throwException(scope, resolved.result.err, globalObject);
return promise->rejectWithCaughtException(globalObject, scope);
@@ -382,8 +378,7 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderFetch(JSGlobalObject *globalOb
res.result.err.code = 0;
res.result.err.ptr = nullptr;
- Zig__GlobalObject__fetch(&res, globalObject, &moduleKeyZig,
- &source );
+ Zig__GlobalObject__fetch(&res, globalObject, &moduleKeyZig, &source);
if (!res.success) {
throwException(scope, res.result.err, globalObject);
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 766de863b..d5c5e057d 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -1765,4 +1765,15 @@ void WTF__URL__setQuery(WTF__URL *arg0, bWTF__StringView arg1) {
void WTF__URL__setUser(WTF__URL *arg0, bWTF__StringView arg1) {
arg0->setUser(*Wrap<WTF::StringView, bWTF__StringView>::unwrap(&arg1));
};
+
+JSC__JSValue JSC__JSPromise__rejectedPromiseValue(JSC__JSGlobalObject *arg0,
+ JSC__JSValue JSValue1) {
+ return JSC::JSValue::encode(
+ JSC::JSPromise::rejectedPromise(arg0, JSC::JSValue::decode(JSValue1)));
+}
+JSC__JSValue JSC__JSPromise__resolvedPromiseValue(JSC__JSGlobalObject *arg0,
+ JSC__JSValue JSValue1) {
+ return JSC::JSValue::encode(
+ JSC::JSPromise::resolvedPromise(arg0, JSC::JSValue::decode(JSValue1)));
}
+} \ No newline at end of file
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index 3ff10a285..4f9d5595e 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -438,10 +438,19 @@ pub const JSPromise = extern struct {
pub fn resolvedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSPromise {
return cppFn("resolvedPromise", .{ globalThis, value });
}
+
+ pub fn resolvedPromiseValue(globalThis: *JSGlobalObject, value: JSValue) JSValue {
+ return cppFn("resolvedPromiseValue", .{ globalThis, value });
+ }
+
pub fn rejectedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSPromise {
return cppFn("rejectedPromise", .{ globalThis, value });
}
+ pub fn rejectedPromiseValue(globalThis: *JSGlobalObject, value: JSValue) JSValue {
+ return cppFn("rejectedPromiseValue", .{ globalThis, value });
+ }
+
pub fn resolve(this: *JSPromise, globalThis: *JSGlobalObject, value: JSValue) void {
cppFn("resolve", .{ this, globalThis, value });
}
@@ -470,6 +479,8 @@ pub const JSPromise = extern struct {
"rejectAsHandled",
// "rejectException",
"rejectAsHandledException",
+ "rejectedPromiseValue",
+ "resolvedPromiseValue",
};
};
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index 918138460..400697777 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1631085611
+//-- AUTOGENERATED FILE -- 1631179623
// clang-format off
#pragma once
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
index a26fecc2f..125937a59 100644
--- a/src/javascript/jsc/bindings/headers.h
+++ b/src/javascript/jsc/bindings/headers.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1631085611
+//-- AUTOGENERATED FILE -- 1631179623
// clang-format: off
#pragma once
@@ -285,9 +285,11 @@ CPP_DECL void JSC__JSPromise__reject(JSC__JSPromise* arg0, JSC__JSGlobalObject*
CPP_DECL void JSC__JSPromise__rejectAsHandled(JSC__JSPromise* arg0, JSC__JSGlobalObject* arg1, JSC__JSValue JSValue2);
CPP_DECL void JSC__JSPromise__rejectAsHandledException(JSC__JSPromise* arg0, JSC__JSGlobalObject* arg1, JSC__Exception* arg2);
CPP_DECL JSC__JSPromise* JSC__JSPromise__rejectedPromise(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
+CPP_DECL JSC__JSValue JSC__JSPromise__rejectedPromiseValue(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
CPP_DECL void JSC__JSPromise__rejectWithCaughtException(JSC__JSPromise* arg0, JSC__JSGlobalObject* arg1, bJSC__ThrowScope arg2);
CPP_DECL void JSC__JSPromise__resolve(JSC__JSPromise* arg0, JSC__JSGlobalObject* arg1, JSC__JSValue JSValue2);
CPP_DECL JSC__JSPromise* JSC__JSPromise__resolvedPromise(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
+CPP_DECL JSC__JSValue JSC__JSPromise__resolvedPromiseValue(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
CPP_DECL JSC__JSValue JSC__JSPromise__result(const JSC__JSPromise* arg0, JSC__VM* arg1);
CPP_DECL uint32_t JSC__JSPromise__status(const JSC__JSPromise* arg0, JSC__VM* arg1);
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index c1504a31f..f34816253 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -37,36 +37,7 @@ pub const __mbstate_t = extern union {
pub const __darwin_mbstate_t = __mbstate_t;
pub const __darwin_ptrdiff_t = c_long;
pub const __darwin_size_t = c_ulong;
-pub const __builtin_va_list = [*c]u8;
-pub const __darwin_va_list = __builtin_va_list;
-pub const __darwin_wchar_t = c_int;
-pub const __darwin_rune_t = __darwin_wchar_t;
-pub const __darwin_wint_t = c_int;
-pub const __darwin_clock_t = c_ulong;
-pub const __darwin_socklen_t = __uint32_t;
-pub const __darwin_ssize_t = c_long;
-pub const __darwin_time_t = c_long;
-pub const __darwin_blkcnt_t = __int64_t;
-pub const __darwin_blksize_t = __int32_t;
-pub const __darwin_dev_t = __int32_t;
-pub const __darwin_fsblkcnt_t = c_uint;
-pub const __darwin_fsfilcnt_t = c_uint;
-pub const __darwin_gid_t = __uint32_t;
-pub const __darwin_id_t = __uint32_t;
-pub const __darwin_ino64_t = __uint64_t;
-pub const __darwin_ino_t = __darwin_ino64_t;
-pub const __darwin_mach_port_name_t = __darwin_natural_t;
-pub const __darwin_mach_port_t = __darwin_mach_port_name_t;
-pub const __darwin_mode_t = __uint16_t;
-pub const __darwin_off_t = __int64_t;
-pub const __darwin_pid_t = __int32_t;
-pub const __darwin_sigset_t = __uint32_t;
-pub const __darwin_suseconds_t = __int32_t;
-pub const __darwin_uid_t = __uint32_t;
-pub const __darwin_useconds_t = __uint32_t;
-pub const __darwin_uuid_t = [16]u8;
-pub const __darwin_uuid_string_t = [37]u8;
-
+
pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype;
pub const JSC__GeneratorPrototype = struct_JSC__GeneratorPrototype;
@@ -162,9 +133,11 @@ pub extern fn JSC__JSPromise__reject(arg0: [*c]JSC__JSPromise, arg1: [*c]JSC__JS
pub extern fn JSC__JSPromise__rejectAsHandled(arg0: [*c]JSC__JSPromise, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue) void;
pub extern fn JSC__JSPromise__rejectAsHandledException(arg0: [*c]JSC__JSPromise, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__Exception) void;
pub extern fn JSC__JSPromise__rejectedPromise(arg0: [*c]JSC__JSGlobalObject, JSValue1: JSC__JSValue) [*c]JSC__JSPromise;
+pub extern fn JSC__JSPromise__rejectedPromiseValue(arg0: [*c]JSC__JSGlobalObject, JSValue1: JSC__JSValue) JSC__JSValue;
pub extern fn JSC__JSPromise__rejectWithCaughtException(arg0: [*c]JSC__JSPromise, arg1: [*c]JSC__JSGlobalObject, arg2: bJSC__ThrowScope) void;
pub extern fn JSC__JSPromise__resolve(arg0: [*c]JSC__JSPromise, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue) void;
pub extern fn JSC__JSPromise__resolvedPromise(arg0: [*c]JSC__JSGlobalObject, JSValue1: JSC__JSValue) [*c]JSC__JSPromise;
+pub extern fn JSC__JSPromise__resolvedPromiseValue(arg0: [*c]JSC__JSGlobalObject, JSValue1: JSC__JSValue) JSC__JSValue;
pub extern fn JSC__JSPromise__result(arg0: [*c]const JSC__JSPromise, arg1: [*c]JSC__VM) JSC__JSValue;
pub extern fn JSC__JSPromise__status(arg0: [*c]const JSC__JSPromise, arg1: [*c]JSC__VM) u32;
pub extern fn JSC__JSInternalPromise__create(arg0: [*c]JSC__JSGlobalObject) [*c]JSC__JSInternalPromise;
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 1d8616ff7..5349aaec1 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -33,6 +33,7 @@ pub const GlobalClasses = [_]type{
BuildError.Class,
ResolveError.Class,
Bun.Class,
+ Fetch.Class,
};
const Blob = @import("../../blob.zig");
@@ -276,6 +277,10 @@ pub const Bun = struct {
.rfn = Router.match,
.ts = Router.match_type_definition,
},
+ .fetch = .{
+ .rfn = Fetch.call,
+ .ts = d.ts{},
+ },
.getImportedStyles = .{
.rfn = Bun.getImportedStyles,
.ts = d.ts{
@@ -1348,7 +1353,6 @@ pub const EventListenerMixin = struct {
// Rely on JS finalizer
var fetch_event = try vm.allocator.create(FetchEvent);
-
fetch_event.* = FetchEvent{
.request_context = request_context,
.request = Request{ .request_context = request_context },
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index cd4dff8c8..680e8aa06 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -4,19 +4,34 @@ const Api = @import("../../../api/schema.zig").Api;
const http = @import("../../../http.zig");
usingnamespace @import("../javascript.zig");
usingnamespace @import("../bindings/bindings.zig");
-
+const ZigURL = @import("../../../query_string_map.zig").URL;
+const HTTPClient = @import("../../../http_client.zig");
+const picohttp = @import("picohttp");
pub const Response = struct {
pub const Class = NewClass(
Response,
.{ .name = "Response" },
.{
.@"constructor" = constructor,
+ .@"text" = .{
+ .rfn = getText,
+ .ts = d.ts{},
+ },
+ .@"json" = .{
+ .rfn = getJson,
+ .ts = d.ts{},
+ },
+ .@"arrayBuffer" = .{
+ .rfn = getArrayBuffer,
+ .ts = d.ts{},
+ },
},
.{
// .@"url" = .{
// .@"get" = getURL,
// .ro = true,
// },
+
.@"ok" = .{
.@"get" = getOK,
.ro = true,
@@ -30,6 +45,7 @@ pub const Response = struct {
allocator: *std.mem.Allocator,
body: Body,
+ status_text: string = "",
pub const Props = struct {};
@@ -41,7 +57,174 @@ pub const Response = struct {
exception: js.ExceptionRef,
) js.JSValueRef {
// https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
- return js.JSValueMakeBoolean(ctx, this.body.init.status_code >= 200 and this.body.init.status_code <= 299);
+ return js.JSValueMakeBoolean(ctx, this.body.init.status_code == 304 or (this.body.init.status_code >= 200 and this.body.init.status_code <= 299));
+ }
+
+ pub fn getText(
+ this: *Response,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ // https://developer.mozilla.org/en-US/docs/Web/API/Response/text
+ defer this.body.value = .Empty;
+ return JSPromise.resolvedPromiseValue(
+ VirtualMachine.vm.global,
+ (brk: {
+ switch (this.body.value) {
+ .Unconsumed => {
+ if (this.body.ptr) |_ptr| {
+ break :brk ZigString.init(_ptr[0..this.body.len]).toValue(VirtualMachine.vm.global);
+ }
+
+ break :brk ZigString.init("").toValue(VirtualMachine.vm.global);
+ },
+ .Empty => {
+ break :brk ZigString.init("").toValue(VirtualMachine.vm.global);
+ },
+ .String => |str| {
+ break :brk ZigString.init(str).toValue(VirtualMachine.vm.global);
+ },
+ .ArrayBuffer => |buffer| {
+ break :brk ZigString.init(buffer.ptr[buffer.offset..buffer.byte_len]).toValue(VirtualMachine.vm.global);
+ },
+ }
+ }),
+ ).asRef();
+ }
+
+ var temp_error_buffer: [4096]u8 = undefined;
+ var error_arg_list: [1]js.JSObjectRef = undefined;
+ pub fn getJson(
+ this: *Response,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ defer this.body.value = .Empty;
+ var zig_string = ZigString.init("");
+
+ var js_string = (js.JSValueCreateJSONString(
+ ctx,
+ brk: {
+ switch (this.body.value) {
+ .Unconsumed => {
+ if (this.body.ptr) |_ptr| {
+ zig_string = ZigString.init(_ptr[0..this.body.len]);
+ break :brk zig_string.toJSStringRef();
+ }
+
+ break :brk zig_string.toJSStringRef();
+ },
+ .Empty => {
+ break :brk zig_string.toJSStringRef();
+ },
+ .String => |str| {
+ zig_string = ZigString.init(str);
+ break :brk zig_string.toJSStringRef();
+ },
+ .ArrayBuffer => |buffer| {
+ zig_string = ZigString.init(buffer.ptr[buffer.offset..buffer.byte_len]);
+ break :brk zig_string.toJSStringRef();
+ },
+ }
+ },
+ 0,
+ exception,
+ ) orelse {
+ var out = std.fmt.bufPrint(&temp_error_buffer, "Invalid JSON\n\n \"{s}\"", .{zig_string.slice()[0..std.math.min(zig_string.len, 4000)]}) catch unreachable;
+ error_arg_list[0] = ZigString.init(out).toValueGC(VirtualMachine.vm.global).asRef();
+ return JSPromise.rejectedPromiseValue(
+ VirtualMachine.vm.global,
+ JSValue.fromRef(
+ js.JSObjectMakeError(
+ ctx,
+ 1,
+ &error_arg_list,
+ exception,
+ ),
+ ),
+ ).asRef();
+ });
+ defer js.JSStringRelease(js_string);
+
+ return JSPromise.resolvedPromiseValue(
+ VirtualMachine.vm.global,
+ JSValue.fromRef(
+ js.JSValueMakeString(
+ ctx,
+ js_string,
+ ),
+ ),
+ ).asRef();
+ }
+ pub fn getArrayBuffer(
+ this: *Response,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ defer this.body.value = .Empty;
+ return JSPromise.resolvedPromiseValue(
+ VirtualMachine.vm.global,
+ JSValue.fromRef(
+ (brk: {
+ switch (this.body.value) {
+ .Unconsumed => {
+ if (this.body.ptr) |_ptr| {
+ break :brk js.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ js.JSTypedArrayType.kJSTypedArrayTypeUint8Array,
+ _ptr,
+ this.body.len,
+ null,
+ null,
+ exception,
+ );
+ }
+
+ break :brk js.JSObjectMakeTypedArray(
+ ctx,
+ js.JSTypedArrayType.kJSTypedArrayTypeUint8Array,
+ 0,
+ exception,
+ );
+ },
+ .Empty => {
+ break :brk js.JSObjectMakeTypedArray(ctx, js.JSTypedArrayType.kJSTypedArrayTypeUint8Array, 0, exception);
+ },
+ .String => |str| {
+ break :brk js.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ js.JSTypedArrayType.kJSTypedArrayTypeUint8Array,
+ @intToPtr([*]u8, @ptrToInt(str.ptr)),
+ str.len,
+ null,
+ null,
+ exception,
+ );
+ },
+ .ArrayBuffer => |buffer| {
+ break :brk js.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ buffer.typed_array_type,
+ buffer.ptr,
+ buffer.byte_len,
+ null,
+ null,
+ exception,
+ );
+ },
+ }
+ }),
+ ),
+ ).asRef();
}
pub fn getStatus(
@@ -87,7 +270,7 @@ pub const Response = struct {
return http.MimeType.html.value;
},
- .ArrayBuffer => {
+ .Unconsumed, .ArrayBuffer => {
return "application/octet-stream";
},
}
@@ -134,6 +317,151 @@ pub const Response = struct {
}
};
+pub const Fetch = struct {
+ const headers_string = "headers";
+ const method_string = "method";
+
+ var fetch_body_string: MutableString = undefined;
+ var fetch_body_string_loaded = false;
+
+ pub const Class = NewClass(
+ void,
+ .{ .name = "fetch" },
+ .{
+ .@"call" = .{
+ .rfn = Fetch.call,
+ .ts = d.ts{},
+ },
+ },
+ .{},
+ );
+
+ pub fn call(
+ this: void,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ if (arguments.len == 0 or arguments.len > 2) return js.JSValueMakeNull(ctx);
+ var http_client = HTTPClient.init(getAllocator(ctx), .GET, ZigURL{}, .{}, "");
+ var headers: ?Headers = null;
+ var body: string = "";
+
+ if (!js.JSValueIsString(ctx, arguments[0])) {
+ return js.JSValueMakeNull(ctx);
+ }
+
+ var url_zig_str = ZigString.init("");
+ JSValue.fromRef(arguments[0]).toZigString(
+ &url_zig_str,
+ VirtualMachine.vm.global,
+ );
+ var url_str = url_zig_str.slice();
+ if (url_str.len == 0) return js.JSValueMakeNull(ctx);
+ http_client.url = ZigURL.parse(url_str);
+
+ if (arguments.len == 2 and js.JSValueIsObject(ctx, arguments[1])) {
+ var array = js.JSObjectCopyPropertyNames(ctx, arguments[1]);
+ defer js.JSPropertyNameArrayRelease(array);
+ const count = js.JSPropertyNameArrayGetCount(array);
+ var i: usize = 0;
+ while (i < count) : (i += 1) {
+ var property_name_ref = js.JSPropertyNameArrayGetNameAtIndex(array, i);
+ switch (js.JSStringGetLength(property_name_ref)) {
+ "headers".len => {
+ if (js.JSStringIsEqualToUTF8CString(property_name_ref, "headers")) {
+ if (js.JSObjectGetProperty(ctx, arguments[1], property_name_ref, null)) |value| {
+ if (GetJSPrivateData(Headers, value)) |headers_ptr| {
+ headers = headers_ptr.*;
+ } else if (Headers.JS.headersInit(ctx, value) catch null) |headers_| {
+ headers = headers_;
+ }
+ }
+ }
+ },
+ "body".len => {
+ if (js.JSStringIsEqualToUTF8CString(property_name_ref, "body")) {
+ if (js.JSObjectGetProperty(ctx, arguments[1], property_name_ref, null)) |value| {
+ var body_ = Body.extractBody(ctx, value, false, null, exception);
+ if (exception != null) return js.JSValueMakeNull(ctx);
+ switch (body_.value) {
+ .ArrayBuffer => |arraybuffer| {
+ body = arraybuffer.ptr[0..arraybuffer.byte_len];
+ },
+ .String => |str| {
+ body = str;
+ },
+ else => {},
+ }
+ }
+ }
+ },
+ "method".len => {
+ if (js.JSStringIsEqualToUTF8CString(property_name_ref, "method")) {
+ if (js.JSObjectGetProperty(ctx, arguments[1], property_name_ref, null)) |value| {
+ var string_ref = js.JSValueToStringCopy(ctx, value, exception);
+
+ if (exception != null) return js.JSValueMakeNull(ctx);
+ defer js.JSStringRelease(string_ref);
+ var method_name_buf: [16]u8 = undefined;
+ var method_name = method_name_buf[0..js.JSStringGetUTF8CString(string_ref, &method_name_buf, method_name_buf.len)];
+ http_client.method = http.Method.which(method_name) orelse http_client.method;
+ }
+ }
+ },
+ else => {},
+ }
+ }
+ }
+
+ if (headers) |head| {
+ http_client.header_entries = head.entries;
+ http_client.header_buf = head.buf.items;
+ }
+
+ if (fetch_body_string_loaded) {
+ fetch_body_string.reset();
+ } else {
+ fetch_body_string = MutableString.init(VirtualMachine.vm.allocator, 0) catch unreachable;
+ fetch_body_string_loaded = true;
+ }
+
+ var http_response = http_client.send(body, &fetch_body_string) catch |err| {
+ const fetch_error = std.fmt.allocPrint(getAllocator(ctx), "Fetch error: {s}", .{@errorName(err)}) catch unreachable;
+ return JSPromise.rejectedPromiseValue(VirtualMachine.vm.global, ZigString.init(fetch_error).toErrorInstance(VirtualMachine.vm.global)).asRef();
+ };
+
+ var response_headers = Headers.fromPicoHeaders(getAllocator(ctx), http_response.headers) catch unreachable;
+ response_headers.guard = .immutable;
+ var response = getAllocator(ctx).create(Response) catch unreachable;
+ var allocator = getAllocator(ctx);
+ var duped = allocator.dupeZ(u8, fetch_body_string.list.items) catch unreachable;
+ response.* = Response{
+ .allocator = allocator,
+ .status_text = allocator.dupe(u8, http_response.status) catch unreachable,
+ .body = .{
+ .init = .{
+ .headers = response_headers,
+ .status_code = @truncate(u16, http_response.status_code),
+ },
+ .value = .{
+ .Unconsumed = 0,
+ },
+ .ptr = duped.ptr,
+ .len = duped.len,
+ .ptr_allocator = allocator,
+ },
+ };
+
+ return JSPromise.resolvedPromiseValue(
+ VirtualMachine.vm.global,
+ JSValue.fromRef(Response.Class.make(ctx, response)),
+ ).asRef();
+ }
+};
+
// https://developer.mozilla.org/en-US/docs/Web/API/Headers
pub const Headers = struct {
pub const Kv = struct {
@@ -272,6 +600,77 @@ pub const Headers = struct {
return js.JSValueMakeNull(ctx);
}
+ pub fn headersInit(ctx: js.JSContextRef, header_prop: js.JSObjectRef) !?Headers {
+ const header_keys = js.JSObjectCopyPropertyNames(ctx, header_prop);
+ defer js.JSPropertyNameArrayRelease(header_keys);
+ const total_header_count = js.JSPropertyNameArrayGetCount(header_keys);
+ if (total_header_count == 0) return null;
+
+ // 2 passes through the headers
+
+ // Pass #1: find the "real" count.
+ // The number of things which are strings or numbers.
+ // Anything else should be ignored.
+ // We could throw a TypeError, but ignoring silently is more JavaScript-like imo
+ var real_header_count: usize = 0;
+ var estimated_buffer_len: usize = 0;
+ var j: usize = 0;
+ while (j < total_header_count) : (j += 1) {
+ var key_ref = js.JSPropertyNameArrayGetNameAtIndex(header_keys, j);
+ var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
+
+ switch (js.JSValueGetType(ctx, value_ref)) {
+ js.JSType.kJSTypeNumber => {
+ const key_len = js.JSStringGetLength(key_ref);
+ if (key_len > 0) {
+ real_header_count += 1;
+ estimated_buffer_len += key_len;
+ estimated_buffer_len += std.fmt.count("{d}", .{js.JSValueToNumber(ctx, value_ref, null)});
+ }
+ },
+ js.JSType.kJSTypeString => {
+ const key_len = js.JSStringGetLength(key_ref);
+ const value_len = js.JSStringGetLength(value_ref);
+ if (key_len > 0 and value_len > 0) {
+ real_header_count += 1;
+ estimated_buffer_len += key_len + value_len;
+ }
+ },
+ else => {},
+ }
+ }
+
+ if (real_header_count == 0 or estimated_buffer_len == 0) return null;
+
+ j = 0;
+ var allocator = getAllocator(ctx);
+ var headers = Headers{
+ .allocator = allocator,
+ .buf = try std.ArrayListUnmanaged(u8).initCapacity(allocator, estimated_buffer_len),
+ .entries = Headers.Entries{},
+ };
+ errdefer headers.deinit();
+ try headers.entries.ensureTotalCapacity(allocator, real_header_count);
+ headers.buf.expandToCapacity();
+ while (j < total_header_count) : (j += 1) {
+ var key_ref = js.JSPropertyNameArrayGetNameAtIndex(header_keys, j);
+ var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
+
+ switch (js.JSValueGetType(ctx, value_ref)) {
+ js.JSType.kJSTypeNumber => {
+ if (js.JSStringGetLength(key_ref) == 0) continue;
+ try headers.appendInit(ctx, key_ref, .kJSTypeNumber, value_ref);
+ },
+ js.JSType.kJSTypeString => {
+ if (js.JSStringGetLength(value_ref) == 0 or js.JSStringGetLength(key_ref) == 0) continue;
+ try headers.appendInit(ctx, key_ref, .kJSTypeString, value_ref);
+ },
+ else => {},
+ }
+ }
+ return headers;
+ }
+
// https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers
pub fn constructor(
ctx: js.JSContextRef,
@@ -283,6 +682,14 @@ pub const Headers = struct {
if (arguments.len > 0 and js.JSValueIsObjectOfClass(ctx, arguments[0], Headers.Class.get().*)) {
var other = castObj(arguments[0], Headers);
other.clone(headers) catch unreachable;
+ } else if (arguments.len == 1 and js.JSValueIsObject(ctx, arguments[0])) {
+ headers.* = (JS.headersInit(ctx, arguments[0]) catch unreachable) orelse Headers{
+ .entries = @TypeOf(headers.entries){},
+ .buf = @TypeOf(headers.buf){},
+ .used = 0,
+ .allocator = getAllocator(ctx),
+ .guard = Guard.none,
+ };
} else {
headers.* = Headers{
.entries = @TypeOf(headers.entries){},
@@ -356,26 +763,25 @@ pub const Headers = struct {
none,
};
- // TODO: is it worth making this lazy? instead of copying all the request headers, should we just do it on get/put/iterator?
- pub fn fromRequestCtx(allocator: *std.mem.Allocator, request: *http.RequestContext) !Headers {
+ pub fn fromPicoHeaders(allocator: *std.mem.Allocator, picohttp_headers: []const picohttp.Header) !Headers {
var total_len: usize = 0;
- for (request.request.headers) |header| {
+ for (picohttp_headers) |header| {
total_len += header.name.len;
total_len += header.value.len;
}
// for the null bytes
- total_len += request.request.headers.len * 2;
+ total_len += picohttp_headers.len * 2;
var headers = Headers{
.allocator = allocator,
.entries = Entries{},
.buf = std.ArrayListUnmanaged(u8){},
};
- try headers.entries.ensureTotalCapacity(allocator, request.request.headers.len);
+ try headers.entries.ensureTotalCapacity(allocator, picohttp_headers.len);
try headers.buf.ensureTotalCapacity(allocator, total_len);
headers.buf.expandToCapacity();
headers.guard = Guard.request;
- for (request.request.headers) |header| {
+ for (picohttp_headers) |header| {
headers.entries.appendAssumeCapacity(Kv{
.name = headers.appendString(
string,
@@ -394,11 +800,14 @@ pub const Headers = struct {
});
}
- headers.guard = Guard.immutable;
-
return headers;
}
+ // TODO: is it worth making this lazy? instead of copying all the request headers, should we just do it on get/put/iterator?
+ pub fn fromRequestCtx(allocator: *std.mem.Allocator, request: *http.RequestContext) !Headers {
+ return fromPicoHeaders(allocator, request.request.headers);
+ }
+
pub fn asStr(headers: *const Headers, ptr: Api.StringPointer) []u8 {
return headers.buf.items[ptr.offset..][0..ptr.length];
}
@@ -479,7 +888,7 @@ pub const Headers = struct {
),
.value = headers.appendString(
string,
- key,
+ value,
needs_lowercase,
needs_normalize,
append_null,
@@ -577,6 +986,9 @@ pub const Headers = struct {
pub const Body = struct {
init: Init,
value: Value,
+ ptr: ?[*]u8 = null,
+ len: usize = 0,
+ ptr_allocator: ?*std.mem.Allocator = null,
pub fn deinit(this: *Body, allocator: *std.mem.Allocator) void {
if (this.init.headers) |headers| {
@@ -602,7 +1014,7 @@ pub const Body = struct {
defer js.JSPropertyNameArrayRelease(array);
const count = js.JSPropertyNameArrayGetCount(array);
var i: usize = 0;
- upper: while (i < count) : (i += 1) {
+ while (i < count) : (i += 1) {
var property_name_ref = js.JSPropertyNameArrayGetNameAtIndex(array, i);
switch (js.JSStringGetLength(property_name_ref)) {
"headers".len => {
@@ -611,73 +1023,7 @@ pub const Body = struct {
if (js.JSObjectGetProperty(ctx, init_ref, property_name_ref, null)) |header_prop| {
switch (js.JSValueGetType(ctx, header_prop)) {
js.JSType.kJSTypeObject => {
- const header_keys = js.JSObjectCopyPropertyNames(ctx, header_prop);
- defer js.JSPropertyNameArrayRelease(header_keys);
- const total_header_count = js.JSPropertyNameArrayGetCount(array);
- if (total_header_count == 0) continue :upper;
-
- // 2 passes through the headers
-
- // Pass #1: find the "real" count.
- // The number of things which are strings or numbers.
- // Anything else should be ignored.
- // We could throw a TypeError, but ignoring silently is more JavaScript-like imo
- var real_header_count: usize = 0;
- var estimated_buffer_len: usize = 0;
- var j: usize = 0;
- while (j < total_header_count) : (j += 1) {
- var key_ref = js.JSPropertyNameArrayGetNameAtIndex(header_keys, j);
- var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
-
- switch (js.JSValueGetType(ctx, value_ref)) {
- js.JSType.kJSTypeNumber => {
- const key_len = js.JSStringGetLength(key_ref);
- if (key_len > 0) {
- real_header_count += 1;
- estimated_buffer_len += key_len;
- estimated_buffer_len += std.fmt.count("{d}", .{js.JSValueToNumber(ctx, value_ref, null)});
- }
- },
- js.JSType.kJSTypeString => {
- const key_len = js.JSStringGetLength(key_ref);
- const value_len = js.JSStringGetLength(value_ref);
- if (key_len > 0 and value_len > 0) {
- real_header_count += 1;
- estimated_buffer_len += key_len + value_len;
- }
- },
- else => {},
- }
- }
-
- if (real_header_count == 0 or estimated_buffer_len == 0) continue :upper;
-
- j = 0;
- var headers = Headers{
- .allocator = allocator,
- .buf = try std.ArrayListUnmanaged(u8).initCapacity(allocator, estimated_buffer_len),
- .entries = Headers.Entries{},
- };
- errdefer headers.deinit();
- try headers.entries.ensureTotalCapacity(allocator, real_header_count);
-
- while (j < total_header_count) : (j += 1) {
- var key_ref = js.JSPropertyNameArrayGetNameAtIndex(header_keys, j);
- var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
-
- switch (js.JSValueGetType(ctx, value_ref)) {
- js.JSType.kJSTypeNumber => {
- if (js.JSStringGetLength(key_ref) == 0) continue;
- try headers.appendInit(ctx, key_ref, .kJSTypeNumber, value_ref);
- },
- js.JSType.kJSTypeString => {
- if (js.JSStringGetLength(value_ref) == 0 or js.JSStringGetLength(key_ref) == 0) continue;
- try headers.appendInit(ctx, key_ref, .kJSTypeString, value_ref);
- },
- else => {},
- }
- }
- result.headers = headers;
+ result.headers = try Headers.JS.headersInit(ctx, header_prop);
},
else => {},
}
@@ -705,10 +1051,12 @@ pub const Body = struct {
ArrayBuffer: ArrayBuffer,
String: string,
Empty: u0,
+ Unconsumed: u0,
pub const Tag = enum {
ArrayBuffer,
String,
Empty,
+ Unconsumed,
};
pub fn length(value: *const Value) usize {
@@ -719,7 +1067,7 @@ pub const Body = struct {
.String => |str| {
return str.len;
},
- .Empty => {
+ else => {
return 0;
},
}
@@ -783,6 +1131,8 @@ pub const Body = struct {
}
body.value = Value{ .String = str.characters8()[0..len] };
+ body.ptr = @intToPtr([*]u8, @ptrToInt(body.value.String.ptr));
+ body.len = body.value.String.len;
return body;
},
.kJSTypeObject => {
@@ -807,6 +1157,8 @@ pub const Body = struct {
} else |err| {}
}
body.value = Value{ .ArrayBuffer = buffer };
+ body.ptr = buffer.ptr[buffer.offset..buffer.byte_len].ptr;
+ body.len = buffer.ptr[buffer.offset..buffer.byte_len].len;
return body;
},
}