2023-05-13 19:56:47 +00:00
|
|
|
const std = @import("std");
|
|
|
|
|
2023-05-30 23:03:40 +00:00
|
|
|
// C interfaces between main and libraries
|
2023-05-13 19:56:47 +00:00
|
|
|
pub const Header = extern struct {
|
|
|
|
name_ptr: [*]u8,
|
|
|
|
name_len: usize,
|
|
|
|
|
|
|
|
value_ptr: [*]u8,
|
|
|
|
value_len: usize,
|
|
|
|
};
|
|
|
|
pub const Response = extern struct {
|
|
|
|
ptr: [*]u8,
|
|
|
|
len: usize,
|
|
|
|
|
|
|
|
headers: [*]Header,
|
|
|
|
headers_len: usize,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Request = extern struct {
|
2023-05-18 00:43:17 +00:00
|
|
|
method: [*:0]u8,
|
2023-05-13 19:56:47 +00:00
|
|
|
method_len: usize,
|
|
|
|
|
|
|
|
content: [*]u8,
|
|
|
|
content_len: usize,
|
|
|
|
|
|
|
|
headers: [*]Header,
|
|
|
|
headers_len: usize,
|
|
|
|
};
|
|
|
|
|
2023-05-30 23:03:40 +00:00
|
|
|
// If the library is Zig, we can use these helpers
|
|
|
|
pub const ZigRequest = struct {
|
|
|
|
method: [:0]u8,
|
|
|
|
content: []u8,
|
|
|
|
headers: []Header,
|
|
|
|
};
|
|
|
|
|
2023-05-30 19:46:23 +00:00
|
|
|
pub fn toHeaders(alloc: std.mem.Allocator, headers: std.StringHashMap([]const u8)) ![*]Header {
|
|
|
|
var header_array = try std.ArrayList(Header).initCapacity(alloc, headers.count());
|
2023-05-13 19:56:47 +00:00
|
|
|
var iterator = headers.iterator();
|
|
|
|
while (iterator.next()) |kv| {
|
|
|
|
header_array.appendAssumeCapacity(.{
|
|
|
|
.name_ptr = @constCast(kv.key_ptr.*).ptr,
|
|
|
|
.name_len = kv.key_ptr.*.len,
|
|
|
|
|
|
|
|
.value_ptr = @constCast(kv.value_ptr.*).ptr,
|
|
|
|
.value_len = kv.value_ptr.*.len,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return header_array.items.ptr;
|
|
|
|
}
|
2023-05-30 19:46:23 +00:00
|
|
|
|
|
|
|
var allocator: ?*std.mem.Allocator = null;
|
|
|
|
|
|
|
|
pub const ZigResponse = struct {
|
|
|
|
body: *std.ArrayList(u8),
|
|
|
|
headers: *std.StringHashMap([]const u8),
|
|
|
|
};
|
|
|
|
|
|
|
|
/// This function is optional and can be exported by zig libraries for
|
|
|
|
/// initialization. If exported, it will be called once in the beginning of
|
|
|
|
/// a request and will be provided a pointer to std.mem.Allocator, which is
|
|
|
|
/// useful for reusing the parent allocator
|
|
|
|
pub fn zigInit(parent_allocator: *anyopaque) callconv(.C) void {
|
|
|
|
allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), parent_allocator));
|
|
|
|
}
|
|
|
|
|
2023-05-30 23:03:40 +00:00
|
|
|
pub const ZigRequestHandler = *const fn (std.mem.Allocator, ZigRequest, ZigResponse) anyerror!void;
|
2023-05-30 19:46:23 +00:00
|
|
|
|
|
|
|
const log = std.log.scoped(.interface);
|
|
|
|
pub fn handleRequest(request: *Request, zigRequestHandler: ZigRequestHandler) ?*Response {
|
|
|
|
// TODO: implement another library in C or Rust or something to show
|
|
|
|
// that anything using a C ABI can be successful
|
|
|
|
var alloc = if (allocator) |a| a.* else @panic("zigInit not called prior to handle_request. This is a coding error");
|
|
|
|
|
|
|
|
// setup response body
|
|
|
|
var response = std.ArrayList(u8).init(alloc);
|
|
|
|
|
|
|
|
// setup headers
|
|
|
|
var headers = std.StringHashMap([]const u8).init(alloc);
|
2023-05-30 23:03:40 +00:00
|
|
|
zigRequestHandler(
|
|
|
|
alloc,
|
|
|
|
.{
|
|
|
|
.method = request.method[0..request.method_len :0],
|
|
|
|
.content = request.content[0..request.content_len],
|
|
|
|
.headers = request.headers[0..request.headers_len],
|
|
|
|
},
|
|
|
|
.{
|
|
|
|
.body = &response,
|
|
|
|
.headers = &headers,
|
|
|
|
},
|
|
|
|
) catch |e| {
|
2023-05-30 19:46:23 +00:00
|
|
|
log.err("Unexpected error processing request: {any}", .{e});
|
|
|
|
if (@errorReturnTrace()) |trace| {
|
|
|
|
std.debug.dumpStackTrace(trace.*);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
log.debug("response ptr: {*}", .{response.items.ptr});
|
|
|
|
// Marshall data back for handling by server
|
|
|
|
|
|
|
|
var rc = alloc.create(Response) catch @panic("OOM");
|
|
|
|
rc.ptr = response.items.ptr;
|
|
|
|
rc.len = response.items.len;
|
|
|
|
rc.headers = toHeaders(alloc, headers) catch |e| {
|
|
|
|
log.err("Unexpected error processing request: {any}", .{e});
|
|
|
|
if (@errorReturnTrace()) |trace| {
|
|
|
|
std.debug.dumpStackTrace(trace.*);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
rc.headers_len = headers.count();
|
|
|
|
return rc;
|
|
|
|
}
|