srctree

Gregory Mullen parent c29e11e9 42d48d8f
add iovec shim & extend frame.sendPage with stackalloc

inlinesplit
src/cookies.zig added: 61, removed: 51, total 10
@@ -18,7 +18,7 @@ pub const Attributes = struct {
};
 
/// vec must be large enough for the largest cookie (10)
pub fn writeVec(a: Attributes, vec: []std.posix.iovec_const) !usize {
pub fn writeVec(a: Attributes, vec: []IOVec) !usize {
var used: usize = 0;
if (a.domain) |d| {
vec[used] = .{ .base = "; Domain=", .len = 9 };
@@ -96,7 +96,7 @@ pub const Cookie = struct {
}
 
/// vec must be large enough for the largest cookie (4 + attributes)
pub fn writeVec(c: Cookie, vec: []std.posix.iovec_const) !usize {
pub fn writeVec(c: Cookie, vec: []IOVec) !usize {
if (vec.len < 12) return error.NoSpaceLeft;
var used: usize = 0;
vec[used] = .{ .base = "Set-Cookie: ".ptr, .len = 12 };
@@ -143,14 +143,14 @@ test Cookie {
try std.testing.expectEqualStrings(expect, res);
}
 
const v_expct = [4]std.posix.iovec_const{
const v_expct = [4]IOVec{
.{ .base = "Set-Cookie: ", .len = 12 },
.{ .base = "name", .len = 4 },
.{ .base = "=", .len = 1 },
.{ .base = "value", .len = 5 },
};
 
var v_buf: [14]std.posix.iovec_const = undefined;
var v_buf: [14]IOVec = undefined;
const used = try cookies[0].writeVec(v_buf[0..]);
try std.testing.expectEqual(4, used);
try std.testing.expectEqualDeep(v_expct[0..4], v_buf[0..4]);
@@ -266,3 +266,5 @@ const indexOf = std.mem.indexOf;
const indexOfScalar = std.mem.indexOfScalar;
const splitSequence = std.mem.splitSequence;
const ArrayListUnmanaged = std.ArrayListUnmanaged;
 
const IOVec = @import("iovec.zig").IOVec;
 
src/frame.zig added: 61, removed: 51, total 10
@@ -60,25 +60,27 @@ pub const Downstream = union(enum) {
 
/// sendPage is the default way to respond in verse using the Template system.
/// sendPage will flush headers to the client before sending Page data
pub fn sendPage(vrs: *Frame, page: anytype) NetworkError!void {
vrs.status = .ok;
pub fn sendPage(frame: *Frame, page: anytype) NetworkError!void {
frame.status = .ok;
 
vrs.sendHeaders() catch |err| switch (err) {
frame.sendHeaders() catch |err| switch (err) {
error.BrokenPipe => |e| return e,
else => return error.IOWriteFailure,
};
 
try vrs.sendRawSlice("\r\n");
try frame.sendRawSlice("\r\n");
 
switch (vrs.downstream) {
switch (frame.downstream) {
.http, .zwsgi => |stream| {
var vec_s = [_]std.posix.iovec_const{undefined} ** 2048;
var vecs: []std.posix.iovec_const = vec_s[0..];
var vec_s: [2048]IOVec = @splat(undefined);
var vecs: []IOVec = vec_s[0..];
const required = page.iovecCountAll();
if (required > 2048) {
vecs = vrs.alloc.alloc(std.posix.iovec_const, required) catch @panic("OOM");
if (required > vec_s.len) {
vecs = frame.alloc.alloc(IOVec, required) catch @panic("OOM");
}
const vec = page.ioVec(vecs, vrs.alloc) catch |iovec_err| {
var stkfb = std.heap.stackFallback(0xffff, frame.alloc);
const stkalloc = stkfb.get();
const vec = page.ioVec(vecs, stkalloc) catch |iovec_err| {
log.err("Error building iovec ({}) fallback to writer", .{iovec_err});
const w = stream.writer();
page.format("{}", .{}, w) catch |err| switch (err) {
@@ -86,10 +88,10 @@ pub fn sendPage(vrs: *Frame, page: anytype) NetworkError!void {
};
return;
};
stream.writevAll(vec) catch |err| switch (err) {
stream.writevAll(@ptrCast(vec)) catch |err| switch (err) {
else => log.err("iovec write error Error {} len {}", .{ err, vec.len }),
};
if (required > 2048) vrs.alloc.free(vecs);
if (required > 2048) frame.alloc.free(vecs);
},
.buffer => @panic("not implemented"),
}
@@ -174,10 +176,10 @@ pub fn redirect(vrs: *Frame, loc: []const u8, comptime scode: std.http.Status) N
else => return error.IOWriteFailure,
};
 
var vect = [3]iovec_c{
.{ .base = "Location: ".ptr, .len = 10 },
.{ .base = loc.ptr, .len = loc.len },
.{ .base = "\r\n\r\n".ptr, .len = 4 },
var vect = [3]IOVec{
.fromSlice("Location: "),
.fromSlice(loc),
.fromSlice("\r\n\r\n"),
};
vrs.writevAll(vect[0..]) catch |err| switch (err) {
error.BrokenPipe => return error.BrokenPipe,
@@ -209,7 +211,7 @@ pub fn init(a: Allocator, req: *const Request, auth: Auth.Provider) !Frame {
fn VecList(comptime SIZE: usize) type {
return struct {
pub const capacity = SIZE;
vect: [SIZE]iovec_c = undefined,
vect: [SIZE]IOVec = undefined,
length: usize = 0,
 
pub fn init() @This() {
@@ -218,10 +220,7 @@ fn VecList(comptime SIZE: usize) type {
 
pub fn append(self: *@This(), str: []const u8) !void {
if (self.length >= capacity) return error.NoSpaceLeft;
self.vect[self.length] = .{
.base = str.ptr,
.len = str.len,
};
self.vect[self.length] = .fromSlice(str);
self.length += 1;
}
};
@@ -276,7 +275,7 @@ pub fn sendHeaders(vrs: *Frame) SendError!void {
try vect.append("\r\n");
}
 
stream.writevAll(vect.vect[0..vect.length]) catch return error.IOWriteFailure;
stream.writevAll(@ptrCast(vect.vect[0..vect.length])) catch return error.IOWriteFailure;
},
.buffer => @panic("not implemented"),
}
@@ -312,9 +311,9 @@ fn writeAll(vrs: Frame, data: []const u8) !void {
}
}
 
fn writevAll(vrs: Frame, vect: []iovec_c) !void {
fn writevAll(vrs: Frame, vect: []IOVec) !void {
switch (vrs.downstream) {
.zwsgi, .http => |stream| try stream.writevAll(vect),
.zwsgi, .http => |stream| try stream.writevAll(@ptrCast(vect)),
.buffer => @panic("not implemented"),
}
}
@@ -404,8 +403,8 @@ const bufPrint = std.fmt.bufPrint;
const allocPrint = std.fmt.allocPrint;
const splitScalar = std.mem.splitScalar;
const log = std.log.scoped(.Verse);
const iovec = std.posix.iovec;
const iovec_c = std.posix.iovec_const;
 
const IOVec = @import("iovec.zig").IOVec;
 
const Server = @import("server.zig");
const Request = @import("request.zig");
 
filename was Deleted added: 61, removed: 51, total 10
@@ -0,0 +1,10 @@
pub const IOVec = extern struct {
base: [*]const u8,
len: usize,
 
pub const empty: IOVec = .{ .base = "".ptr, .len = 0 };
 
pub fn fromSlice(s: []const u8) IOVec {
return .{ .base = s.ptr, .len = s.len };
}
};
 
src/template.zig added: 61, removed: 51, total 10
@@ -4,9 +4,9 @@ pub const Template = @import("template/Template.zig");
 
pub const html = @import("template/html.zig");
 
const Pages = @import("template/page.zig");
pub const Page = Pages.Page;
pub const PageRuntime = Pages.PageRuntime;
const pages = @import("template/page.zig");
pub const Page = pages.Page;
pub const PageRuntime = pages.PageRuntime;
 
const MAX_BYTES = 2 <<| 15;
 
 
src/template/page.zig added: 61, removed: 51, total 10
@@ -226,23 +226,23 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
fn ioVecDirective(T: type, data: T, drct: Directive, vec: []IOVec, a: Allocator) !usize {
std.debug.assert(drct.verb == .variable);
switch (T) {
[]const u8 => vec[0] = .{ .base = data.ptr, .len = data.len },
[]const u8 => vec[0] = .fromSlice(data),
?[]const u8 => if (data) |d| {
vec[0] = .{ .base = d.ptr, .len = d.len };
vec[0] = .fromSlice(d);
} else if (drct.otherwise == .default) {
vec[0] = .{ .base = drct.otherwise.default.ptr, .len = drct.otherwise.default.len };
vec[0] = .fromSlice(drct.otherwise.default);
} else {
vec[0] = .{ .base = "".ptr, .len = 0 };
vec[0] = .empty;
return 0;
},
usize, isize => {
const int = try allocPrint(a, "{}", .{data});
vec[0] = .{ .base = int.ptr, .len = int.len };
vec[0] = .fromSlice(int);
},
?usize => {
if (data) |us| {
const int = try allocPrint(a, "{}", .{us});
vec[0] = .{ .base = int.ptr, .len = int.len };
vec[0] = .fromSlice(int);
}
},
else => {
@@ -259,12 +259,12 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
[]const u8, u8 => comptime unreachable,
[]const []const u8 => {
for (data) |each| {
vec[idx] = .{ .base = each.ptr, .len = each.len };
vec[idx] = .fromSlice(each);
idx += 1;
// I should find a better way to write this hack
if (ofs.len == 2) {
if (ofs[1].kind == .slice and ofs[1].kind.slice.len > 0) {
vec[idx] = .{ .base = ofs[1].kind.slice.ptr, .len = ofs[1].kind.slice.len };
vec[idx] = .fromSlice(ofs[1].kind.slice);
idx += 1;
}
}
@@ -305,10 +305,7 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
skip -|= 1;
} else switch (os.kind) {
.slice => |slice| {
vec[vec_idx] = .{
.base = slice.ptr,
.len = slice.len,
};
vec[vec_idx] = .fromSlice(slice);
vec_idx += 1;
},
.component => |comp| {
@@ -405,7 +402,9 @@ const std = @import("std");
const is_test = @import("builtin").is_test;
const log = std.log.scoped(.Verse);
const Allocator = std.mem.Allocator;
const IOVec = std.posix.iovec_const;
 
pub const IOVec = @import("../iovec.zig").IOVec;
 
const indexOfScalar = std.mem.indexOfScalar;
const indexOfPosLinear = std.mem.indexOfPosLinear;
const allocPrint = std.fmt.allocPrint;