srctree

Gregory Mullen parent 9ebcd360 366f2794
refactor and improve request data api

inlinesplit
src/context.zig added: 101, removed: 88, total 13
@@ -9,7 +9,7 @@ const zWSGIRequest = zWSGI.zWSGIRequest;
 
pub const Request = @import("request.zig");
pub const Response = @import("response.zig");
pub const RequestData = @import("request_data.zig").RequestData;
pub const RequestData = @import("request_data.zig");
pub const Template = @import("template.zig");
pub const Routes = @import("routes.zig");
pub const UriIter = Routes.UriIter;
@@ -22,7 +22,7 @@ pub const Context = @This();
alloc: Allocator,
request: Request,
response: Response,
req_data: RequestData,
reqdata: RequestData,
uri: UriIter,
cfg: ?Config,
 
@@ -36,14 +36,14 @@ const VarPair = struct {
[]const u8,
};
 
pub fn init(a: Allocator, cfg: ?Config, req: Request, res: Response, req_data: RequestData) !Context {
pub fn init(a: Allocator, cfg: ?Config, req: Request, res: Response, reqdata: RequestData) !Context {
std.debug.assert(req.uri[0] == '/');
//const reqheader = req.headers
return Context{
.alloc = a,
.request = req,
.response = res,
.req_data = req_data,
.reqdata = reqdata,
.uri = std.mem.split(u8, req.uri[1..], "/"),
.cfg = cfg,
.auth = Auth.init(req.headers),
 
src/endpoints/admin.zig added: 101, removed: 88, total 13
@@ -4,7 +4,6 @@ const Allocator = std.mem.Allocator;
 
const Context = @import("../context.zig");
const Route = @import("../routes.zig");
const UserData = @import("../request_data.zig").UserData;
const HTML = @import("../html.zig");
const DOM = @import("../dom.zig");
const Template = @import("../template.zig");
@@ -85,7 +84,7 @@ const CloneUpstreamReq = struct {
fn postCloneUpstream(ctx: *Context) Error!void {
try ctx.request.auth.validOrError();
 
const udata = UserData(CloneUpstreamReq).init(ctx.req_data.post_data.?) catch return error.BadData;
const udata = ctx.reqdata.post.?.validate(CloneUpstreamReq) catch return error.BadData;
std.debug.print("repo uri {s}\n", .{udata.repo_uri});
var nameitr = std.mem.splitBackwards(u8, udata.repo_uri, "/");
const name = nameitr.first();
@@ -121,7 +120,7 @@ fn postCloneUpstream(ctx: *Context) Error!void {
fn postNewRepo(ctx: *Context) Error!void {
try ctx.request.auth.validOrError();
// TODO ini repo dir
var valid = if (ctx.req_data.post_data) |p|
var valid = if (ctx.reqdata.post) |p|
p.validator()
else
return error.Unknown;
@@ -185,7 +184,7 @@ fn newRepo(ctx: *Context) Error!void {
 
fn view(ctx: *Context) Error!void {
try ctx.request.auth.validOrError();
if (ctx.req_data.post_data) |pd| {
if (ctx.reqdata.post) |pd| {
std.debug.print("{any}\n", .{pd.items});
return newRepo(ctx);
}
 
src/endpoints/commit-flex.zig added: 101, removed: 88, total 13
@@ -205,7 +205,7 @@ pub fn commitFlex(ctx: *Context) Error!void {
var nowish = DateTime.now();
var email: []const u8 = undefined;
var tz_offset: ?i32 = null;
var query = ctx.req_data.query_data.validator();
var query = ctx.reqdata.query.validator();
const user = query.optional("user");
 
if (user) |u| {
 
src/endpoints/gist.zig added: 101, removed: 88, total 13
@@ -3,7 +3,7 @@ const allocPrint = std.fmt.allocPrint;
 
const Context = @import("../context.zig");
const Template = @import("../template.zig");
const UserData = @import("../request_data.zig").UserData;
const RequestData = @import("../request_data.zig").RequestData;
const Bleach = @import("../bleach.zig");
const Allocator = std.mem.Allocator;
 
@@ -53,8 +53,7 @@ const GistPost = struct {
fn post(ctx: *Context) Error!void {
try ctx.request.auth.validOrError();
 
const postd = ctx.req_data.post_data orelse return error.BadData;
const udata = UserData(GistPost).initMap(ctx.alloc, postd) catch return error.BadData;
const udata = RequestData(GistPost).initMap(ctx.alloc, ctx.reqdata) catch return error.BadData;
 
if (udata.file_name.len != udata.file_blob.len) return error.BadData;
const username = if (ctx.auth.valid())
 
src/endpoints/repos.zig added: 101, removed: 88, total 13
@@ -18,7 +18,7 @@ const UriIter = Route.UriIter;
const ROUTE = Route.ROUTE;
const POST = Route.POST;
const GET = Route.GET;
const UserData = @import("../request_data.zig").UserData;
const RequestData = @import("../request_data.zig").RequestData;
 
const Bleach = @import("../bleach.zig");
const Humanize = @import("../humanize.zig");
@@ -270,7 +270,7 @@ const RepoSortReq = struct {
fn list(ctx: *Context) Error!void {
var cwd = std.fs.cwd();
 
const udata = UserData(RepoSortReq).init(ctx.req_data.query_data) catch return error.BadData;
const udata = ctx.reqdata.query.validate(RepoSortReq) catch return error.BadData;
const tag_sort: bool = if (udata.sort) |srt| if (eql(u8, srt, "tag")) true else false else false;
 
if (cwd.openDir("./repos", .{ .iterate = true })) |idir| {
 
src/endpoints/repos/commits.zig added: 101, removed: 88, total 13
@@ -17,7 +17,7 @@ const Response = @import("../../response.zig");
const Route = @import("../../routes.zig");
const Template = @import("../../template.zig");
const Types = @import("../../types.zig");
const UserData = @import("../../request_data.zig").UserData;
const RequestData = @import("../../request_data.zig").RequestData;
 
const Comment = Types.Comment;
const CommitMap = Types.CommitMap;
@@ -46,8 +46,8 @@ pub fn router(ctx: *Context) Error!Route.Callable {
}
 
fn newComment(ctx: *Context) Error!void {
if (ctx.req_data.post_data) |post| {
_ = UserData(AddComment).init(post) catch return error.BadData;
if (ctx.reqdata.post) |post| {
_ = post.validate(AddComment) catch return error.BadData;
}
return error.BadData;
}
@@ -143,7 +143,7 @@ fn commitHtml(ctx: *Context, sha: []const u8, repo_name: []const u8, repo: Git.R
}
}
 
const udata = UserData(Diffs.PatchView).init(ctx.req_data.query_data) catch return error.BadData;
const udata = ctx.reqdata.query.validate(Diffs.PatchView) catch return error.BadData;
const inline_html = udata.@"inline" orelse true;
 
var page = CommitPage.init(.{
 
src/endpoints/repos/diffs.zig added: 101, removed: 88, total 13
@@ -17,7 +17,6 @@ const Response = @import("../../response.zig");
const Route = @import("../../routes.zig");
const Template = @import("../../template.zig");
const Types = @import("../../types.zig");
const UserData = @import("../../request_data.zig").UserData;
 
const Comment = Types.Comment;
const Delta = Types.Delta;
@@ -78,8 +77,8 @@ const IssueCreateReq = struct {
 
fn newPost(ctx: *Context) Error!void {
const rd = Repo.RouteData.make(&ctx.uri) orelse return error.Unrouteable;
if (ctx.req_data.post_data) |post| {
const udata = UserData(IssueCreateReq).init(post) catch return error.BadData;
if (ctx.reqdata.post) |post| {
const udata = post.validate(IssueCreateReq) catch return error.BadData;
 
var delta = Delta.new(rd.name) catch unreachable;
//delta.src = src;
@@ -117,7 +116,7 @@ fn newPost(ctx: *Context) Error!void {
fn newComment(ctx: *Context) Error!void {
const rd = Repo.RouteData.make(&ctx.uri) orelse return error.Unrouteable;
var buf: [2048]u8 = undefined;
if (ctx.req_data.post_data) |post| {
if (ctx.reqdata.post) |post| {
var valid = post.validator();
const delta_id = try valid.require("did");
const delta_index = isHex(delta_id.value) orelse return error.Unrouteable;
@@ -285,7 +284,7 @@ fn view(ctx: *Context) Error!void {
 
try ctx.putContext("Delta_id", .{ .slice = delta_id });
 
const udata = UserData(PatchView).init(ctx.req_data.query_data) catch return error.BadData;
const udata = ctx.reqdata.query.validate(PatchView) catch return error.BadData;
const inline_html = udata.@"inline" orelse true;
 
var patch_formatted: ?Template.Structs.PatchHtml = null;
 
src/endpoints/repos/issues.zig added: 101, removed: 88, total 13
@@ -54,7 +54,7 @@ fn new(ctx: *Context) Error!void {
fn newPost(ctx: *Context) Error!void {
const rd = Repo.RouteData.make(&ctx.uri) orelse return error.Unrouteable;
var buf: [2048]u8 = undefined;
if (ctx.req_data.post_data) |post| {
if (ctx.reqdata.post) |post| {
var valid = post.validator();
const title = try valid.require("title");
const msg = try valid.require("desc");
@@ -74,7 +74,7 @@ fn newPost(ctx: *Context) Error!void {
 
fn newComment(ctx: *Context) Error!void {
const rd = Repo.RouteData.make(&ctx.uri) orelse return error.Unrouteable;
if (ctx.req_data.post_data) |post| {
if (ctx.reqdata.post) |post| {
var valid = post.validator();
const delta_id = try valid.require("did");
const msg = try valid.require("comment");
 
src/endpoints/search.zig added: 101, removed: 88, total 13
@@ -8,7 +8,6 @@ const Route = @import("../routes.zig");
const Error = Route.Error;
const ROUTE = Route.ROUTE;
 
const UserData = @import("../request_data.zig").UserData;
const Bleach = @import("../bleach.zig");
 
pub const routes = [_]Route.Match{
@@ -30,7 +29,7 @@ fn inbox(ctx: *Context) Error!void {
}
 
fn search(ctx: *Context) Error!void {
const udata = UserData(SearchReq).init(ctx.req_data.query_data) catch return error.BadData;
const udata = ctx.reqdata.query.validate(SearchReq) catch return error.BadData;
 
const query_str = udata.q orelse "null";
std.debug.print("query {s}\n", .{query_str});
 
src/endpoints/settings.zig added: 101, removed: 88, total 13
@@ -2,7 +2,7 @@ const std = @import("std");
pub const Template = @import("../template.zig");
const Context = @import("../context.zig");
const Route = @import("../routes.zig");
const UserData = @import("../request_data.zig").UserData;
const RequestData = @import("../request_data.zig").RequestData;
 
pub const endpoints = [_]Route.Match{
Route.GET("", default),
@@ -40,7 +40,7 @@ const SettingsReq = struct {
fn post(ctx: *Context) Route.Error!void {
try ctx.request.auth.validOrError();
 
const udata = UserData(SettingsReq).initMap(ctx.alloc, ctx.req_data.post_data.?) catch return error.BadData;
const udata = RequestData(SettingsReq).initMap(ctx.alloc, ctx.reqdata) catch return error.BadData;
 
for (udata.block_name, udata.block_text) |name, text| {
std.debug.print("block data:\nname '{s}'\ntext '''{s}'''\n", .{ name, text });
 
src/gitweb.zig added: 101, removed: 88, total 13
@@ -53,7 +53,7 @@ fn gitUploadPack(ctx: *Context) Error!void {
defer map.deinit();
 
//(if GIT_PROJECT_ROOT is set, otherwise PATH_TRANSLATED)
if (ctx.req_data.post_data == null) {
if (ctx.reqdata.post == null) {
try map.put("PATH_TRANSLATED", path_tr);
try map.put("QUERY_STRING", "service=git-upload-pack");
try map.put("REQUEST_METHOD", "GET");
@@ -87,7 +87,7 @@ fn gitUploadPack(ctx: *Context) Error!void {
.revents = undefined,
},
};
if (ctx.req_data.post_data) |pd| {
if (ctx.reqdata.post) |pd| {
_ = std.posix.write(child.stdin.?.handle, pd.rawpost) catch unreachable;
std.posix.close(child.stdin.?.handle);
child.stdin = null;
 
src/request_data.zig added: 101, removed: 88, total 13
@@ -3,6 +3,15 @@ const Type = @import("builtin").Type;
const Allocator = std.mem.Allocator;
const eql = std.mem.eql;
 
const Data = @This();
 
post: ?PostData,
query: QueryData,
 
pub fn Validate(data: Data, comptime T: type) !T {
return RequestData(T).init(data);
}
 
/// This is the preferred api to use... once it actually exists :D
pub fn Validator(comptime T: type) type {
return struct {
@@ -87,6 +96,10 @@ pub const PostData = struct {
rawpost: []u8,
items: []DataItem,
 
pub fn validate(pdata: PostData, comptime T: type) !T {
return RequestData(T).initPost(pdata);
}
 
pub fn validator(self: PostData) Validator(PostData) {
return Validator(PostData).init(self);
}
@@ -97,6 +110,26 @@ pub const QueryData = struct {
rawquery: []const u8,
items: []DataItem,
 
/// TODO leaks on error
pub fn init(a: Allocator, query: []const u8) !QueryData {
var itr = std.mem.split(u8, query, "&");
const count = std.mem.count(u8, query, "&") + 1;
const items = try a.alloc(DataItem, count);
for (items) |*item| {
item.* = try parseSegment(a, itr.next().?);
}
 
return QueryData{
.alloc = a,
.rawquery = query,
.items = items,
};
}
 
pub fn validate(qdata: QueryData, comptime T: type) !T {
return RequestData(T).initQuery(qdata);
}
 
/// segments name=value&name2=otherval
/// segment in name=%22dquote%22
/// segment out name="dquote"
@@ -123,32 +156,11 @@ pub const QueryData = struct {
}
}
 
/// TODO leaks on error
pub fn init(a: Allocator, query: []const u8) !QueryData {
var itr = std.mem.split(u8, query, "&");
const count = std.mem.count(u8, query, "&") + 1;
const items = try a.alloc(DataItem, count);
for (items) |*item| {
item.* = try parseSegment(a, itr.next().?);
}
 
return QueryData{
.alloc = a,
.rawquery = query,
.items = items,
};
}
 
pub fn validator(self: QueryData) Validator(QueryData) {
return Validator(QueryData).init(self);
}
};
 
pub const RequestData = struct {
post_data: ?PostData,
query_data: QueryData,
};
 
pub const ContentType = union(enum) {
const Application = enum {
@"x-www-form-urlencoded",
@@ -188,31 +200,36 @@ pub const ContentType = union(enum) {
}
};
 
pub fn UserData(comptime T: type) type {
pub fn RequestData(comptime T: type) type {
return struct {
req: T,
 
const Self = @This();
 
pub fn init(data: anytype) !T {
pub fn init(data: Data) !T {
return switch (@TypeOf(data)) {
QueryData => initQuery(data),
PostData => initPost(data),
else => comptime unreachable,
};
//const info = @typeInfo(T).@"struct".info.fields;
//if (info.len == 2) {
// for (std.meta.fields(T)) |field| {
// if (!eql(u8, field.name, "post") or !eql(u8, field.name, "query")) {
// }
// }
//} else @compileLog("not implemented");
}
 
pub fn initMap(a: Allocator, data: anytype) !T {
return switch (@TypeOf(data)) {
QueryData => comptime unreachable, // Not implemented
PostData => initPostMap(a, data),
else => comptime unreachable,
};
pub fn initMap(a: Allocator, data: Data) !T {
if (data.post) |post| return initPostMap(a, post);
 
// Only post is implemented
return error.NotImplemented;
}
 
fn initQuery(data: QueryData) !T {
var valid = data.validator();
 
fn initQuery(query: QueryData) !T {
var valid = query.validator();
var req: T = undefined;
inline for (std.meta.fields(T)) |field| {
@field(req, field.name) = switch (@typeInfo(field.type)) {
 
src/routes.zig added: 101, removed: 88, total 13
@@ -122,7 +122,7 @@ pub fn defaultResponse(comptime code: std.http.Status) Callable {
fn notFound(ctx: *Context) Error!void {
ctx.response.status = .not_found;
var tmpl = Template.find("4XX.html");
ctx.sendTemplate(&tmpl) catch unreachable;
try ctx.sendTemplate(&tmpl);
}
 
fn internalServerError(ctx: *Context) Error!void {
@@ -133,7 +133,7 @@ fn internalServerError(ctx: *Context) Error!void {
 
fn default(ctx: *Context) Error!void {
var tmpl = Template.find("index.html");
ctx.sendTemplate(&tmpl) catch unreachable;
ctx.sendTemplate(&tmpl);
}
 
pub fn router(ctx: *Context, comptime routes: []const Match) Callable {
 
src/zwsgi.zig added: 101, removed: 88, total 13
@@ -125,7 +125,7 @@ fn serveUnix(zwsgi: *ZWSGI) !void {
for (ctx.request.raw_request.zwsgi.vars) |vars| {
std.debug.print("Abusive var '{s}' => '''{s}'''\n", .{ vars.key, vars.val });
}
if (ctx.req_data.post_data) |post_data| {
if (ctx.reqdata.post) |post_data| {
std.debug.print("post data => '''{s}'''\n", .{post_data.rawpost});
}
},
@@ -266,7 +266,7 @@ fn buildContext(z: ZWSGI, a: Allocator, request: *Request) !Context {
const response = try Response.init(a, request);
 
var post_data: ?RequestData.PostData = null;
var req_data: RequestData.RequestData = undefined;
var reqdata: RequestData = undefined;
switch (request.raw_request) {
.zwsgi => |zreq| {
if (find(zreq.vars, "HTTP_CONTENT_LENGTH")) |h_len| {
@@ -291,9 +291,9 @@ fn buildContext(z: ZWSGI, a: Allocator, request: *Request) !Context {
if (find(zreq.vars, "QUERY_STRING")) |qs| {
query = try RequestData.readQuery(a, qs);
}
req_data = RequestData.RequestData{
.post_data = post_data,
.query_data = query,
reqdata = RequestData{
.post = post_data,
.query = query,
};
},
.http => |*hreq| {
@@ -317,14 +317,14 @@ fn buildContext(z: ZWSGI, a: Allocator, request: *Request) !Context {
if (std.mem.indexOf(u8, hreq.head.target, "/")) |i| {
query_data = try RequestData.readQuery(a, hreq.head.target[i..]);
}
req_data = RequestData.RequestData{
.post_data = post_data,
.query_data = query_data,
reqdata = RequestData{
.post = post_data,
.query = query_data,
};
},
}
 
return Context.init(a, z.config, request.*, response, req_data);
return Context.init(a, z.config, request.*, response, reqdata);
}
 
fn readHttpHeaders(a: Allocator, req: *std.http.Server.Request) !Request {