aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--.scripts/write-versions.sh10
-rw-r--r--src/deps/_libusockets.h9
-rw-r--r--src/deps/libuwsockets.cpp30
-rw-r--r--src/deps/uws.zig36
-rw-r--r--src/javascript/jsc/api/html_rewriter.zig6
-rw-r--r--src/javascript/jsc/api/server.zig23
-rw-r--r--src/javascript/jsc/javascript.zig2
-rw-r--r--src/javascript/jsc/webcore/response.zig59
9 files changed, 154 insertions, 24 deletions
diff --git a/.gitmodules b/.gitmodules
index 3df35adb2..f105a2a6d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -35,4 +35,5 @@
ignore = dirty
[submodule "src/deps/uws"]
path = src/deps/uws
- url = https://github.com/uNetworking/uWebSockets
+ url = https://github.com/Jarred-Sumner/uWebSockets
+ ignore = dirty
diff --git a/.scripts/write-versions.sh b/.scripts/write-versions.sh
index af020f3f0..5fed3ee18 100644
--- a/.scripts/write-versions.sh
+++ b/.scripts/write-versions.sh
@@ -7,17 +7,19 @@ LIBARCHIVE_VERSION=$(git rev-parse HEAD:./src/deps/libarchive)
PICOHTTPPARSER_VERSION=$(git rev-parse HEAD:./src/deps/picohttpparser)
BORINGSSL_VERSION=$(git rev-parse HEAD:./src/deps/boringssl)
ZLIB_VERSION=$(git rev-parse HEAD:./src/deps/zlib)
+UWS_VERSION=$(git rev-parse HEAD:./src/deps/uws)
rm -rf src/generated_versions_list.zig
echo "// AUTO-GENERATED FILE. Created via .scripts/write-versions.sh" >src/generated_versions_list.zig
echo "" >>src/generated_versions_list.zig
-echo "pub const webkit = \"$WEBKIT_VERSION\";" >>src/generated_versions_list.zig
-echo "pub const mimalloc = \"$MIMALLOC_VERSION\";" >>src/generated_versions_list.zig
+echo "pub const boringssl = \"$BORINGSSL_VERSION\";" >>src/generated_versions_list.zig
echo "pub const libarchive = \"$LIBARCHIVE_VERSION\";" >>src/generated_versions_list.zig
+echo "pub const mimalloc = \"$MIMALLOC_VERSION\";" >>src/generated_versions_list.zig
echo "pub const picohttpparser = \"$PICOHTTPPARSER_VERSION\";" >>src/generated_versions_list.zig
-echo "pub const boringssl = \"$BORINGSSL_VERSION\";" >>src/generated_versions_list.zig
-echo "pub const zlib = \"$ZLIB_VERSION\";" >>src/generated_versions_list.zig
+echo "pub const uws = \"$UWS_VERSION\";" >>src/generated_versions_list.zig
+echo "pub const webkit = \"$WEBKIT_VERSION\";" >>src/generated_versions_list.zig
echo "pub const zig = @import(\"std\").fmt.comptimePrint(\"{}\", .{@import(\"builtin\").zig_version});" >>src/generated_versions_list.zig
+echo "pub const zlib = \"$ZLIB_VERSION\";" >>src/generated_versions_list.zig
echo "" >>src/generated_versions_list.zig
zig fmt src/generated_versions_list.zig
diff --git a/src/deps/_libusockets.h b/src/deps/_libusockets.h
index 5456ff921..7042d3d14 100644
--- a/src/deps/_libusockets.h
+++ b/src/deps/_libusockets.h
@@ -282,6 +282,15 @@ void uws_loop_addPreHandler(us_loop_t *loop, void *key,
void uws_loop_removePreHandler(us_loop_t *loop, void *ctx_);
void uws_loop_defer(us_loop_t *loop, void *ctx, void (*cb)(void *ctx));
+typedef struct StringPointer {
+ uint32_t off;
+ uint32_t len;
+} StringPointer;
+
+void uws_res_write_headers(int ssl, uws_res_t *res, const StringPointer *names,
+ const StringPointer *values, size_t count,
+ const char *buf);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/deps/libuwsockets.cpp b/src/deps/libuwsockets.cpp
index ec082db43..132a22be8 100644
--- a/src/deps/libuwsockets.cpp
+++ b/src/deps/libuwsockets.cpp
@@ -981,4 +981,34 @@ void uws_loop_defer(us_loop_t *loop, void *ctx, void (*cb)(void *ctx)) {
uWS::Loop *uwsLoop = (uWS::Loop *)loop;
uwsLoop->defer([ctx, cb]() { cb(ctx); });
}
+
+void uws_res_write_headers(int ssl, uws_res_t *res, const StringPointer *names,
+ const StringPointer *values, size_t count,
+ const char *buf) {
+ if (ssl) {
+ uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
+ for (size_t i = 0; i < count; i++) {
+ uwsRes->writeHeader(std::string_view(&buf[names[i].off], names[i].len),
+ std::string_view(&buf[values[i].off], values[i].len));
+ }
+
+ } else {
+ uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
+ for (size_t i = 0; i < count; i++) {
+ uwsRes->writeHeader(std::string_view(&buf[names[i].off], names[i].len),
+ std::string_view(&buf[values[i].off], values[i].len));
+ }
+ }
+}
+
+void uws_res_cork(int ssl, uws_res_t *res, void *ctx,
+ void (*corker)(void *ctx)) {
+ if (ssl) {
+ uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
+ uwsRes->cork([ctx, corker]() { corker(ctx); });
+ } else {
+ uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
+ uwsRes->cork([ctx, corker]() { corker(ctx); });
+ }
+}
} \ No newline at end of file
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index fc7a32865..30e23b39a 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -1,3 +1,4 @@
+const Api = @import("../api/schema.zig").Api;
pub const u_int8_t = u8;
pub const u_int16_t = c_ushort;
pub const u_int32_t = c_uint;
@@ -497,6 +498,38 @@ pub fn NewApp(comptime ssl: bool) type {
uws_res_on_data(ssl_flag, res.downcast(), Wrapper.handle, opcional_data);
}
+
+ pub fn runCorked(
+ res: *Response,
+ comptime UserDataType: type,
+ comptime handler: fn (UserDataType) void,
+ opcional_data: UserDataType,
+ ) void {
+ const Wrapper = struct {
+ pub fn handle(user_data: ?*anyopaque) callconv(.C) void {
+ if (comptime UserDataType == void) {
+ @call(.{ .modifier = .always_inline }, handler, .{
+ void{},
+ });
+ } else {
+ @call(.{ .modifier = .always_inline }, handler, .{
+ @ptrCast(UserDataType, @alignCast(@alignOf(UserDataType), user_data.?)),
+ });
+ }
+ }
+ };
+
+ uws_res_cork(ssl_flag, res.downcast(), opcional_data, Wrapper.handle);
+ }
+
+ pub fn writeHeaders(
+ res: *Response,
+ names: []const Api.StringPointer,
+ values: []const Api.StringPointer,
+ buf: []const u8,
+ ) void {
+ uws_res_write_headers(ssl_flag, res.downcast(), names.ptr, values.ptr, values.len, buf.ptr);
+ }
};
};
}
@@ -578,7 +611,8 @@ extern fn uws_res_upgrade(
sec_web_socket_extensions_length: usize,
ws: ?*uws_socket_context_t,
) void;
-
+extern fn uws_res_cork(c_int, res: *uws_res, ctx: *anyopaque, corker: fn (?*anyopaque) callconv(.C) void) void;
+extern fn uws_res_write_headers(c_int, res: *uws_res, names: [*]const Api.StringPointer, values: [*]const Api.StringPointer, count: usize, buf: [*]const u8) void;
pub const LIBUS_RECV_BUFFER_LENGTH = @import("std").zig.c_translation.promoteIntLiteral(c_int, 524288, .decimal);
pub const LIBUS_TIMEOUT_GRANULARITY = @as(c_int, 4);
pub const LIBUS_RECV_BUFFER_PADDING = @as(c_int, 32);
diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig
index c62a6503f..e314fc18d 100644
--- a/src/javascript/jsc/api/html_rewriter.zig
+++ b/src/javascript/jsc/api/html_rewriter.zig
@@ -216,7 +216,7 @@ pub const HTMLRewriter = struct {
response.cloneInto(result, getAllocator(global.ref()));
this.finalizeWithoutDestroy();
- return JSValue.fromRef(Response.Class.make(global.ref(), result));
+ return JSValue.fromRef(Response.makeMaybePooled(global.ref(), result));
}
var new_context = this.context;
@@ -311,7 +311,7 @@ pub const HTMLRewriter = struct {
};
return JSC.JSValue.fromRef(
- Response.Class.make(sink.global.ref(), sink.response),
+ Response.makeMaybePooled(sink.global.ref(), sink.response),
);
}
@@ -327,7 +327,7 @@ pub const HTMLRewriter = struct {
if (prev_value.Locked.promise) |promise| {
prev_value.Locked.promise = null;
promise.asInternalPromise().?.resolve(this.global, JSC.JSValue.fromRef(
- Response.Class.make(
+ Response.makeMaybePooled(
this.global.ref(),
this.response,
),
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig
index 4b7805adb..8c64c112a 100644
--- a/src/javascript/jsc/api/server.zig
+++ b/src/javascript/jsc/api/server.zig
@@ -92,6 +92,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
app: *App = undefined,
globalThis: *JSGlobalObject,
default_server: URL = URL{ .host = "localhost", .port = "3000" },
+ response_objects_pool: JSC.WebCore.Response.Pool = JSC.WebCore.Response.Pool{},
request_pool_allocator: std.mem.Allocator = undefined,
@@ -116,6 +117,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
this.listener = socket;
VirtualMachine.vm.uws_event_loop = uws.Loop.get();
+ VirtualMachine.vm.response_objects_pool = &this.response_objects_pool;
this.app.run();
}
@@ -127,6 +129,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
method: HTTP.Method,
aborted: bool = false,
response_jsvalue: JSC.JSValue = JSC.JSValue.zero,
+ response_ptr: ?*JSC.WebCore.Response = null,
blob: JSC.WebCore.Blob = JSC.WebCore.Blob{},
promise: ?*JSC.JSValue = null,
response_headers: ?*JSC.WebCore.Headers.RefCountedHeaders = null,
@@ -181,14 +184,13 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
.method = HTTP.Method.which(req.method()) orelse .GET,
.server = server,
};
- resp.onAborted(*RequestContext, onAbort, this);
}
pub fn onAbort(this: *RequestContext, _: *App.Response) void {
this.aborted = true;
this.req = undefined;
if (!this.response_jsvalue.isEmpty()) {
- JSC.C.JSValueUnprotect(this.server.globalThis.ref(), this.response_jsvalue.asObjectRef());
+ this.server.response_objects_pool.push(this.server.globalThis, this.response_jsvalue);
this.response_jsvalue = JSC.JSValue.zero;
}
}
@@ -196,7 +198,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
pub fn finalize(this: *RequestContext) void {
this.blob.detach();
if (!this.response_jsvalue.isEmpty()) {
- JSC.C.JSValueUnprotect(this.server.globalThis.ref(), this.response_jsvalue.asObjectRef());
+ this.server.response_objects_pool.push(this.server.globalThis, this.response_jsvalue);
this.response_jsvalue = JSC.JSValue.zero;
}
@@ -213,11 +215,11 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
this.server.request_pool_allocator.destroy(this);
}
- pub fn render(this: *RequestContext, response: *JSC.WebCore.Response) void {
+ pub fn doRender(this: *RequestContext) void {
if (this.aborted) {
return;
}
-
+ var response = this.response_ptr.?;
this.blob = response.body.use();
const status = response.statusCode();
@@ -236,9 +238,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
this.resp.writeStatus(std.fmt.bufPrint(&status_text_buf, "{d} HM", .{response.body.init.status_code}) catch unreachable);
}
- for (names) |name, i| {
- this.resp.writeHeader(headers.asStr(name), headers.asStr(values[i]));
- }
+ this.resp.writeHeaders(names, values, headers.buf.items);
}
if (status == 302 or status == 202 or this.blob.size == 0) {
@@ -250,6 +250,12 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
this.resp.end(this.blob.sharedView(), false);
this.finalize();
}
+
+ pub fn render(this: *RequestContext, response: *JSC.WebCore.Response) void {
+ this.response_ptr = response;
+ this.resp.runCorked(*RequestContext, doRender, this);
+ this.response_ptr = null;
+ }
};
pub fn onRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void {
@@ -286,6 +292,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
}
if (ctx.response_jsvalue.jsTypeLoose() == .JSPromise) {
+ resp.onAborted(*RequestContext, RequestContext.onAbort, ctx);
JSC.VirtualMachine.vm.tick();
ctx.response_jsvalue.then(
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 4a8fefd3c..d0dcb9ddc 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -480,7 +480,7 @@ pub const VirtualMachine = struct {
ref_strings: JSC.RefString.Map = undefined,
source_mappings: SavedSourceMap = undefined,
-
+ response_objects_pool: ?*Response.Pool = null,
pub inline fn eventLoop(this: *VirtualMachine) *EventLoop {
return this.event_loop;
}
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index 778b22171..6e9859352 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -42,6 +42,42 @@ const JSPrinter = @import("../../../js_printer.zig");
const picohttp = @import("picohttp");
const StringJoiner = @import("../../../string_joiner.zig");
pub const Response = struct {
+ pub const Pool = struct {
+ response_objects_pool: [127]JSC.C.JSObjectRef = undefined,
+ response_objects_used: u8 = 0,
+
+ pub fn get(this: *Pool, ptr: *Response) ?JSC.C.JSObjectRef {
+ if (this.response_objects_used > 0) {
+ var result = this.response_objects_pool[this.response_objects_used - 1];
+ this.response_objects_used -= 1;
+ if (JSC.C.JSObjectSetPrivate(result, JSPrivateDataPtr.init(ptr).ptr())) {
+ return result;
+ } else {
+ JSC.C.JSValueUnprotect(VirtualMachine.vm.global.ref(), result);
+ }
+ }
+
+ return null;
+ }
+
+ pub fn push(this: *Pool, globalThis: *JSC.JSGlobalObject, object: JSC.JSValue) void {
+ var remaining = this.response_objects_pool[@minimum(this.response_objects_used, this.response_objects_pool.len)..];
+ if (remaining.len == 0) {
+ JSC.C.JSValueUnprotect(globalThis.ref(), object.asObjectRef());
+ return;
+ }
+
+ if (object.as(Response)) |resp| {
+ _ = JSC.C.JSObjectSetPrivate(object.asObjectRef(), null);
+
+ _ = resp.body.use();
+ resp.finalize();
+ remaining[0] = object.asObjectRef();
+ this.response_objects_used += 1;
+ }
+ }
+ };
+
pub const Constructor = JSC.NewConstructor(
Response,
.{
@@ -262,7 +298,18 @@ pub const Response = struct {
_: js.ExceptionRef,
) js.JSValueRef {
var cloned = this.clone(getAllocator(ctx));
- return Response.Class.make(ctx, cloned);
+ return Response.makeMaybePooled(ctx, cloned);
+ }
+
+ pub fn makeMaybePooled(ctx: js.JSContextRef, ptr: *Response) JSC.C.JSObjectRef {
+ if (JSC.VirtualMachine.vm.response_objects_pool) |pool| {
+ if (pool.get(ptr)) |object| {
+ JSC.C.JSValueUnprotect(ctx, object);
+ return object;
+ }
+ }
+
+ return Response.Class.make(ctx, ptr);
}
pub fn cloneInto(this: *const Response, new_response: *Response, allocator: std.mem.Allocator) void {
@@ -410,7 +457,7 @@ pub const Response = struct {
var ptr = response.allocator.create(Response) catch unreachable;
ptr.* = response;
- return Response.Class.make(ctx, ptr);
+ return Response.makeMaybePooled(ctx, ptr);
}
pub fn constructRedirect(
_: void,
@@ -462,7 +509,7 @@ pub const Response = struct {
var ptr = response.allocator.create(Response) catch unreachable;
ptr.* = response;
- return Response.Class.make(ctx, ptr);
+ return Response.makeMaybePooled(ctx, ptr);
}
pub fn constructError(
_: void,
@@ -485,7 +532,7 @@ pub const Response = struct {
.url = "",
};
- return Response.Class.make(
+ return Response.makeMaybePooled(
ctx,
response,
);
@@ -522,7 +569,7 @@ pub const Response = struct {
.allocator = getAllocator(ctx),
.url = "",
};
- return Response.Class.make(
+ return Response.makeMaybePooled(
ctx,
response,
);
@@ -753,7 +800,7 @@ pub const Fetch = struct {
},
},
};
- return JSValue.fromRef(Response.Class.make(@ptrCast(js.JSContextRef, this.global_this), response));
+ return JSValue.fromRef(Response.makeMaybePooled(@ptrCast(js.JSContextRef, this.global_this), response));
}
pub fn get(