mirror of
https://github.com/zigzap/zap.git
synced 2025-10-21 07:34:08 +00:00
fix: simplify accept header api somewhat
This commit is contained in:
parent
6d646b62d6
commit
4988feb314
3 changed files with 102 additions and 74 deletions
72
examples/accept/accept.zig
Normal file
72
examples/accept/accept.zig
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const zap = @import("zap");
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
||||||
|
.thread_safe = true,
|
||||||
|
}){};
|
||||||
|
|
||||||
|
fn on_request_verbose(r: zap.Request) void {
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
const content_type: zap.ContentType = content_type: {
|
||||||
|
var accept_list = std.ArrayList(zap.Request.AcceptItem).init(allocator);
|
||||||
|
defer accept_list.deinit();
|
||||||
|
r.parseAccept(&accept_list) catch break :content_type .HTML;
|
||||||
|
for (accept_list.items) |accept| {
|
||||||
|
break :content_type accept.toContentType() orelse continue;
|
||||||
|
}
|
||||||
|
break :content_type .HTML;
|
||||||
|
};
|
||||||
|
|
||||||
|
r.setContentType(content_type) catch return;
|
||||||
|
switch (content_type) {
|
||||||
|
.TEXT => {
|
||||||
|
r.sendBody("Hello from ZAP!!!") catch return;
|
||||||
|
},
|
||||||
|
.HTML => {
|
||||||
|
r.sendBody("<html><body><h1>Hello from ZAP!!!</h1></body></html>") catch return;
|
||||||
|
},
|
||||||
|
.XML => {
|
||||||
|
r.sendBody(
|
||||||
|
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
\\<message>
|
||||||
|
\\ <warning>
|
||||||
|
\\ Hello from ZAP!!!
|
||||||
|
\\ </warning>
|
||||||
|
\\</message>
|
||||||
|
) catch return;
|
||||||
|
},
|
||||||
|
.JSON => {
|
||||||
|
var buffer: [128]u8 = undefined;
|
||||||
|
const json = zap.stringifyBuf(&buffer, .{ .message = "Hello from ZAP!!!" }, .{}) orelse return;
|
||||||
|
r.sendJson(json) catch return;
|
||||||
|
},
|
||||||
|
.XHTML => {
|
||||||
|
r.sendBody(
|
||||||
|
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
\\<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
|
||||||
|
\\ <body>
|
||||||
|
\\ <h1>Hello from ZAP!!!</h1>
|
||||||
|
\\ </body>
|
||||||
|
\\</html>
|
||||||
|
) catch return;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var listener = zap.HttpListener.init(.{
|
||||||
|
.port = 3000,
|
||||||
|
.on_request = on_request_verbose,
|
||||||
|
.log = true,
|
||||||
|
.max_clients = 100000,
|
||||||
|
});
|
||||||
|
try listener.listen();
|
||||||
|
|
||||||
|
std.debug.print("Listening on 0.0.0.0:3000\n", .{});
|
||||||
|
|
||||||
|
// start worker threads
|
||||||
|
zap.start(.{
|
||||||
|
.threads = 2,
|
||||||
|
.workers = 2,
|
||||||
|
});
|
||||||
|
}
|
|
@ -577,76 +577,30 @@ pub fn parseCookies(self: *const Self, url_encoded: bool) void {
|
||||||
fio.http_parse_cookies(self.h, if (url_encoded) 1 else 0);
|
fio.http_parse_cookies(self.h, if (url_encoded) 1 else 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const MIMEType = struct {
|
pub const AcceptItem = struct {
|
||||||
|
raw: []const u8,
|
||||||
type: Fragment,
|
type: Fragment,
|
||||||
subtype: Fragment,
|
subtype: Fragment,
|
||||||
|
q: f64,
|
||||||
|
|
||||||
const Fragment = union(enum) {
|
const Fragment = union(enum) {
|
||||||
glob,
|
glob,
|
||||||
value: []const u8,
|
value: []const u8,
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
pub const AcceptItem = struct {
|
|
||||||
mimetype: MIMEType,
|
|
||||||
q: f64,
|
|
||||||
|
|
||||||
pub fn lessThan(_: void, lhs: AcceptItem, rhs: AcceptItem) bool {
|
pub fn lessThan(_: void, lhs: AcceptItem, rhs: AcceptItem) bool {
|
||||||
return lhs.q < rhs.q;
|
return lhs.q < rhs.q;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asCommon(item: AcceptItem) ?Common {
|
pub fn toContentType(item: AcceptItem) ?ContentType {
|
||||||
if (item.mimetype.type == .glob) {
|
if (ContentType.string_map.get(item.raw)) |common| {
|
||||||
if (item.mimetype.subtype == .glob) return .@"*/*";
|
return common;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (std.mem.eql(u8, "text", item.mimetype.type.value)) {
|
|
||||||
if (item.mimetype.subtype == .glob) {
|
|
||||||
return .@"text/*";
|
|
||||||
} else if (std.mem.eql(u8, "html", item.mimetype.subtype.value)) {
|
|
||||||
return .@"text/html";
|
|
||||||
} else if (std.mem.eql(u8, "plain", item.mimetype.subtype.value)) {
|
|
||||||
return .@"text/plain";
|
|
||||||
}
|
|
||||||
} else if (std.mem.eql(u8, "application", item.mimetype.type.value)) {
|
|
||||||
if (item.mimetype.subtype == .glob) {
|
|
||||||
return .@"application/*";
|
|
||||||
} else if (std.mem.eql(u8, "xml", item.mimetype.subtype.value)) {
|
|
||||||
return .@"application/xml";
|
|
||||||
} else if (std.mem.eql(u8, "json", item.mimetype.subtype.value)) {
|
|
||||||
return .@"application/json";
|
|
||||||
} else if (std.mem.eql(u8, "xhtml+xml", item.mimetype.subtype.value)) {
|
|
||||||
return .@"application/xhtml+xml";
|
|
||||||
}
|
|
||||||
} else if (std.mem.eql(u8, "image", item.mimetype.type.value)) {
|
|
||||||
if (item.mimetype.subtype == .glob) {
|
|
||||||
return .@"image/*";
|
|
||||||
} else if (std.mem.eql(u8, "avif", item.mimetype.subtype.value)) {
|
|
||||||
return .@"image/avif";
|
|
||||||
} else if (std.mem.eql(u8, "webp", item.mimetype.subtype.value)) {
|
|
||||||
return .@"image/webp";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Common = enum {
|
|
||||||
@"*/*",
|
|
||||||
@"text/*",
|
|
||||||
@"text/html",
|
|
||||||
@"text/plain",
|
|
||||||
@"application/*",
|
|
||||||
@"application/xhtml+xml",
|
|
||||||
@"application/xml",
|
|
||||||
@"application/json",
|
|
||||||
@"image/*",
|
|
||||||
@"image/avif",
|
|
||||||
@"image/webp",
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses `Accept:` http header into `list`.
|
/// Parses `Accept:` http header into `list`, ordered from highest q factor to lowest
|
||||||
pub fn parseAccept(self: *const Self, list: *std.ArrayList(AcceptItem)) !void {
|
pub fn parseAccept(self: *const Self, list: *std.ArrayList(AcceptItem)) !void {
|
||||||
const accept_str = self.getHeaderCommon(.accept) orelse return error.NoAccept;
|
const accept_str = self.getHeaderCommon(.accept) orelse return error.NoAccept;
|
||||||
|
|
||||||
|
@ -669,29 +623,21 @@ pub fn parseAccept(self: *const Self, list: *std.ArrayList(AcceptItem)) !void {
|
||||||
const mimetype_type_str = type_split_iter.next() orelse continue;
|
const mimetype_type_str = type_split_iter.next() orelse continue;
|
||||||
const mimetype_subtype_str = type_split_iter.next() orelse continue;
|
const mimetype_subtype_str = type_split_iter.next() orelse continue;
|
||||||
|
|
||||||
const mimetype_type: MIMEType.Fragment = if (std.mem.eql(u8, "*", mimetype_type_str))
|
const new_item: AcceptItem = .{
|
||||||
.glob
|
.raw = mimetype_str,
|
||||||
else
|
.type = if (std.mem.eql(u8, "*", mimetype_type_str)) .glob else .{ .value = mimetype_type_str },
|
||||||
.{ .value = mimetype_type_str };
|
.subtype = if (std.mem.eql(u8, "*", mimetype_subtype_str)) .glob else .{ .value = mimetype_subtype_str },
|
||||||
|
|
||||||
const mimetype_subtype: MIMEType.Fragment = if (std.mem.eql(u8, "*", mimetype_subtype_str))
|
|
||||||
.glob
|
|
||||||
else
|
|
||||||
.{ .value = mimetype_subtype_str };
|
|
||||||
|
|
||||||
try list.append(.{
|
|
||||||
.mimetype = .{
|
|
||||||
.type = mimetype_type,
|
|
||||||
.subtype = mimetype_subtype,
|
|
||||||
},
|
|
||||||
.q = q_factor,
|
.q = q_factor,
|
||||||
});
|
};
|
||||||
|
for (list.items, 1..) |item, i| {
|
||||||
|
if (AcceptItem.lessThan({}, new_item, item)) {
|
||||||
|
try list.insert(i, new_item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try list.append(new_item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Sorts list from `parseAccept`
|
|
||||||
pub fn sortAccept(accept_list: []AcceptItem) void {
|
|
||||||
std.sort.insertion(AcceptItem, accept_list, {}, AcceptItem.lessThan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a response cookie
|
/// Set a response cookie
|
||||||
|
|
10
src/zap.zig
10
src/zap.zig
|
@ -159,8 +159,18 @@ pub const HttpError = error{
|
||||||
pub const ContentType = enum {
|
pub const ContentType = enum {
|
||||||
TEXT,
|
TEXT,
|
||||||
HTML,
|
HTML,
|
||||||
|
XML,
|
||||||
JSON,
|
JSON,
|
||||||
|
XHTML,
|
||||||
// TODO: more content types
|
// TODO: more content types
|
||||||
|
|
||||||
|
pub const string_map = std.ComptimeStringMap(ContentType, .{
|
||||||
|
.{ "text/plain", .TEXT },
|
||||||
|
.{ "text/html", .HTML },
|
||||||
|
.{ "application/xml", .XML },
|
||||||
|
.{ "application/json", .JSON },
|
||||||
|
.{ "application/xhtml+xml", .XHTML },
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Used internally: facilio Http request callback function type
|
/// Used internally: facilio Http request callback function type
|
||||||
|
|
Loading…
Add table
Reference in a new issue