mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
[bun.js] Add baseURI support to HTTP server
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"typeRoots": ["~/.bun/types"]
|
||||
"typeRoots": ["../types"]
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -8,9 +8,7 @@
|
||||
"build": "esbuild --define:process.env.NODE_ENV=\"'production'\" --minify index.tsx bun-error.css --bundle --outdir=dist --platform=browser --format=esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"esbuild": "^0.14.10",
|
||||
"preact": "^10.5.14",
|
||||
"preact-compat": "^3.19.0",
|
||||
"esbuild": "latest",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bun-framework-next",
|
||||
"version": "12.1.0",
|
||||
"version": "12.1.1",
|
||||
"main": "empty.js",
|
||||
"module": "empty.js",
|
||||
"description": "bun compatibility layer for Next.js v12.x.x",
|
||||
@@ -16,12 +16,12 @@
|
||||
"next": "^12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.34",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"next": "^12.1.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"typescript": "^4.4.4"
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"typescript": "^4"
|
||||
},
|
||||
"framework": {
|
||||
"displayName": "Next.js",
|
||||
|
||||
@@ -95,6 +95,11 @@ const linux = std.os.linux;
|
||||
pub const ServerConfig = struct {
|
||||
port: u16 = 0,
|
||||
hostname: [*:0]const u8 = "0.0.0.0",
|
||||
|
||||
// TODO: use webkit URL parser instead of bun's
|
||||
base_url: URL = URL{},
|
||||
base_uri: string = "",
|
||||
|
||||
ssl_config: ?SSLConfig = null,
|
||||
max_request_body_size: usize = 1024 * 1024 * 128,
|
||||
development: bool = false,
|
||||
@@ -238,7 +243,7 @@ pub const ServerConfig = struct {
|
||||
.hostname = "0.0.0.0",
|
||||
.development = true,
|
||||
};
|
||||
|
||||
var has_hostname = false;
|
||||
if (strings.eqlComptime(env.get("NODE_ENV") orelse "", "production")) {
|
||||
args.development = false;
|
||||
}
|
||||
@@ -261,6 +266,10 @@ pub const ServerConfig = struct {
|
||||
args.port = port;
|
||||
}
|
||||
|
||||
if (VirtualMachine.vm.bundler.options.transform_options.origin) |origin| {
|
||||
args.base_uri = origin;
|
||||
}
|
||||
|
||||
if (arguments.next()) |arg| {
|
||||
if (arg.isUndefinedOrNull() or !arg.isObject()) {
|
||||
JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global.ref(), exception);
|
||||
@@ -271,6 +280,15 @@ pub const ServerConfig = struct {
|
||||
args.port = @intCast(u16, @minimum(@maximum(0, port_.toInt32()), std.math.maxInt(u16)));
|
||||
}
|
||||
|
||||
if (arg.getTruthy(global, "baseURI")) |baseURI| {
|
||||
var sliced = baseURI.toSlice(global, bun.default_allocator);
|
||||
|
||||
if (sliced.len > 0) {
|
||||
defer sliced.deinit();
|
||||
args.base_uri = bun.default_allocator.dupe(u8, sliced.slice()) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.getTruthy(global, "hostname") orelse arg.getTruthy(global, "host")) |host| {
|
||||
const host_str = host.toSlice(
|
||||
global,
|
||||
@@ -278,6 +296,7 @@ pub const ServerConfig = struct {
|
||||
);
|
||||
if (host_str.len > 0) {
|
||||
args.hostname = bun.default_allocator.dupeZ(u8, host_str.slice()) catch unreachable;
|
||||
has_hostname = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,6 +348,80 @@ pub const ServerConfig = struct {
|
||||
JSC.throwInvalidArguments("Invalid port: must be > 0", .{}, global.ref(), exception);
|
||||
}
|
||||
|
||||
if (args.base_uri.len > 0) {
|
||||
args.base_url = URL.parse(args.base_uri);
|
||||
if (args.base_url.hostname.len == 0) {
|
||||
JSC.throwInvalidArguments("baseURI must have a hostname", .{}, global.ref(), exception);
|
||||
bun.default_allocator.free(bun.constStrToU8(args.base_uri));
|
||||
args.base_uri = "";
|
||||
return args;
|
||||
}
|
||||
|
||||
if (!strings.isAllASCII(args.base_uri)) {
|
||||
JSC.throwInvalidArguments("Unicode baseURI must already be encoded for now.\nnew URL(baseuRI).toString() should do the trick.", .{}, global.ref(), exception);
|
||||
bun.default_allocator.free(bun.constStrToU8(args.base_uri));
|
||||
args.base_uri = "";
|
||||
return args;
|
||||
}
|
||||
|
||||
if (args.base_url.protocol.len == 0) {
|
||||
const protocol: string = if (args.ssl_config != null) "https" else "http";
|
||||
|
||||
args.base_uri = (if ((args.port == 80 and args.ssl_config == null) or (args.port == 443 and args.ssl_config != null))
|
||||
std.fmt.allocPrint(bun.default_allocator, "{s}://{s}/{s}", .{
|
||||
protocol,
|
||||
args.base_url.hostname,
|
||||
strings.trimLeadingChar(args.base_url.pathname, '/'),
|
||||
})
|
||||
else
|
||||
std.fmt.allocPrint(bun.default_allocator, "{s}://{s}:{d}/{s}", .{
|
||||
protocol,
|
||||
args.base_url.hostname,
|
||||
args.port,
|
||||
strings.trimLeadingChar(args.base_url.pathname, '/'),
|
||||
})) catch unreachable;
|
||||
|
||||
args.base_url = URL.parse(args.base_uri);
|
||||
}
|
||||
} else {
|
||||
const hostname: string =
|
||||
if (has_hostname and std.mem.span(args.hostname).len > 0) std.mem.span(args.hostname) else "localhost";
|
||||
const protocol: string = if (args.ssl_config != null) "https" else "http";
|
||||
|
||||
args.base_uri = (if ((args.port == 80 and args.ssl_config == null) or (args.port == 443 and args.ssl_config != null))
|
||||
std.fmt.allocPrint(bun.default_allocator, "{s}://{s}/", .{
|
||||
protocol,
|
||||
hostname,
|
||||
})
|
||||
else
|
||||
std.fmt.allocPrint(bun.default_allocator, "{s}://{s}:{d}/", .{ protocol, hostname, args.port })) catch unreachable;
|
||||
|
||||
if (!strings.isAllASCII(hostname)) {
|
||||
JSC.throwInvalidArguments("Unicode hostnames must already be encoded for now.\nnew URL(input).hostname should do the trick.", .{}, global.ref(), exception);
|
||||
bun.default_allocator.free(bun.constStrToU8(args.base_uri));
|
||||
args.base_uri = "";
|
||||
return args;
|
||||
}
|
||||
|
||||
args.base_url = URL.parse(args.base_uri);
|
||||
}
|
||||
|
||||
// I don't think there's a case where this can happen
|
||||
// but let's check anyway, just in case
|
||||
if (args.base_url.hostname.len == 0) {
|
||||
JSC.throwInvalidArguments("baseURI must have a hostname", .{}, global.ref(), exception);
|
||||
bun.default_allocator.free(bun.constStrToU8(args.base_uri));
|
||||
args.base_uri = "";
|
||||
return args;
|
||||
}
|
||||
|
||||
if (args.base_url.username.len > 0 or args.base_url.password.len > 0) {
|
||||
JSC.throwInvalidArguments("baseURI can't have a username or password", .{}, global.ref(), exception);
|
||||
bun.default_allocator.free(bun.constStrToU8(args.base_uri));
|
||||
args.base_uri = "";
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
};
|
||||
@@ -499,7 +592,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
|
||||
this.* = .{
|
||||
.resp = resp,
|
||||
.req = req,
|
||||
.url = req.url(),
|
||||
// this memory is owned by the Request object
|
||||
.url = strings.append(bun.default_allocator, server.base_url_string_for_joining, req.url()) catch
|
||||
@panic("Out of memory while joining the URL path?"),
|
||||
.method = HTTP.Method.which(req.method()) orelse .GET,
|
||||
.server = server,
|
||||
};
|
||||
@@ -1030,7 +1125,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
|
||||
app: *App = undefined,
|
||||
globalThis: *JSGlobalObject,
|
||||
|
||||
base_url_string_for_joining: string = "",
|
||||
response_objects_pool: JSC.WebCore.Response.Pool = JSC.WebCore.Response.Pool{},
|
||||
config: ServerConfig = ServerConfig{},
|
||||
request_pool_allocator: std.mem.Allocator = undefined,
|
||||
@@ -1040,6 +1135,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
server.* = .{
|
||||
.globalThis = globalThis,
|
||||
.config = config,
|
||||
.base_url_string_for_joining = strings.trim(config.base_url.href, "/"),
|
||||
};
|
||||
RequestContext.pool = bun.default_allocator.create(RequestContext.RequestContextStackAllocator) catch @panic("Out of memory!");
|
||||
server.request_pool_allocator = RequestContext.pool.get();
|
||||
@@ -1190,6 +1286,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
|
||||
},
|
||||
},
|
||||
};
|
||||
request_object.url.mark();
|
||||
// We keep the Request object alive for the duration of the request so that we can remove the pointer to the UWS request object.
|
||||
var args = [_]JSC.C.JSValueRef{JSC.WebCore.Request.Class.make(this.globalThis.ref(), request_object)};
|
||||
ctx.request_js_object = args[0];
|
||||
|
||||
@@ -1085,7 +1085,7 @@ JSC::JSObject* GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObje
|
||||
|
||||
metaProperties->putDirect(vm, clientData->builtinNames().resolvePublicName(),
|
||||
JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject), 0,
|
||||
WTF::String("resolve"), functionImportMeta__resolve),
|
||||
WTF::String("resolve"_s), functionImportMeta__resolve),
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
@@ -2780,6 +2780,10 @@ pub const JSValue = enum(u64) {
|
||||
return @intToPtr(C_API.JSValueRef, @intCast(usize, @enumToInt(this)));
|
||||
}
|
||||
|
||||
pub inline fn c(this: C_API.JSValueRef) JSValue {
|
||||
return @intToEnum(JSValue, @ptrToInt(this));
|
||||
}
|
||||
|
||||
pub inline fn fromRef(this: C_API.JSValueRef) JSValue {
|
||||
return @intToEnum(JSValue, @ptrToInt(this));
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ pub const Response = struct {
|
||||
_: js.ExceptionRef,
|
||||
) js.JSValueRef {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Response/url
|
||||
return ZigString.init(this.url).withEncoding().toValueGC(ctx.ptr()).asObjectRef();
|
||||
return ZigString.init(this.url).toValueGC(ctx.ptr()).asObjectRef();
|
||||
}
|
||||
|
||||
pub fn getResponseType(
|
||||
@@ -4352,6 +4352,10 @@ pub const Request = struct {
|
||||
this.headers = null;
|
||||
}
|
||||
|
||||
if (this.url.isGloballyAllocated()) {
|
||||
bun.default_allocator.free(bun.constStrToU8(this.url.slice()));
|
||||
}
|
||||
|
||||
bun.default_allocator.destroy(this);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user