mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
Merge pull request #78 from jetzig-framework/middleware-request-resolution
Middleware request resolution
This commit is contained in:
commit
3cad3fddc0
@ -33,6 +33,12 @@ pub fn init(request: *jetzig.http.Request) !*DemoMiddleware {
|
||||
/// Any calls to `request.render` or `request.redirect` will prevent further processing of the
|
||||
/// request, including any other middleware in the chain.
|
||||
pub fn afterRequest(self: *DemoMiddleware, request: *jetzig.http.Request) !void {
|
||||
// Middleware can invoke `request.redirect` or `request.render`. All request processing stops
|
||||
// and the response is immediately returned if either of these two functions are called
|
||||
// during middleware processing.
|
||||
// _ = request.redirect("/foobar", .moved_permanently);
|
||||
// _ = request.render(.unauthorized);
|
||||
|
||||
try request.server.logger.DEBUG(
|
||||
"[DemoMiddleware:afterRequest] my_custom_value: {s}",
|
||||
.{self.my_custom_value},
|
||||
|
1
demo/src/app/views/301.zmpl
Normal file
1
demo/src/app/views/301.zmpl
Normal file
@ -0,0 +1 @@
|
||||
Redirecting to <a href="{{.location}}">{{.location}}</a>
|
@ -16,39 +16,55 @@ pub const jetzig_options = struct {
|
||||
jetzig.middleware.HtmxMiddleware,
|
||||
// Demo middleware included with new projects. Remove once you are familiar with Jetzig's
|
||||
// middleware system.
|
||||
// @import("app/middleware/DemoMiddleware.zig"),
|
||||
@import("app/middleware/DemoMiddleware.zig"),
|
||||
};
|
||||
|
||||
// Maximum bytes to allow in request body.
|
||||
// pub const max_bytes_request_body: usize = std.math.pow(usize, 2, 16);
|
||||
pub const max_bytes_request_body: usize = std.math.pow(usize, 2, 16);
|
||||
|
||||
// Maximum filesize for `public/` content.
|
||||
// pub const max_bytes_public_content: usize = std.math.pow(usize, 2, 20);
|
||||
pub const max_bytes_public_content: usize = std.math.pow(usize, 2, 20);
|
||||
|
||||
// Maximum filesize for `static/` content (applies only to apps using `jetzig.http.StaticRequest`).
|
||||
// pub const max_bytes_static_content: usize = std.math.pow(usize, 2, 18);
|
||||
pub const max_bytes_static_content: usize = std.math.pow(usize, 2, 18);
|
||||
|
||||
// Maximum length of a header name. There is no limit imposed by the HTTP specification but
|
||||
// AWS load balancers reference 40 as a limit so we use that as a baseline:
|
||||
// https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_HttpHeaderConditionConfig.html
|
||||
// This can be increased if needed.
|
||||
// pub const max_bytes_header_name: u16 = 40;
|
||||
pub const max_bytes_header_name: u16 = 40;
|
||||
|
||||
// Log message buffer size. Log messages exceeding this size spill to heap with degraded
|
||||
// performance. Log messages should aim to fit in the message buffer.
|
||||
// pub const log_message_buffer_len: usize = 4096;
|
||||
pub const log_message_buffer_len: usize = 4096;
|
||||
|
||||
// Maximum log pool size. When a log buffer is no longer required it is returned to a pool
|
||||
// for recycling. When logging i/o is slow, a high volume of requests will result in this
|
||||
// pool growing. When the pool size reaches the maximum value defined here, log events are
|
||||
// freed instead of recycled.
|
||||
// pub const max_log_pool_len: usize = 256;
|
||||
pub const max_log_pool_len: usize = 256;
|
||||
|
||||
// Number of request threads. Defaults to number of detected CPUs.
|
||||
pub const thread_count: ?u16 = null;
|
||||
|
||||
// Number of response worker threads.
|
||||
pub const worker_count: u16 = 4;
|
||||
|
||||
// Total number of connections managed by worker threads.
|
||||
pub const max_connections: u16 = 512;
|
||||
|
||||
// Per-thread stack memory to use before spilling into request arena (possibly with allocations).
|
||||
pub const buffer_size: usize = 64 * 1024;
|
||||
|
||||
// The size of each item in the available memory pool used by requests for rendering.
|
||||
// Total retained allocation: `worker_count * max_connections`.
|
||||
pub const arena_size: usize = 1024 * 1024;
|
||||
|
||||
// Path relative to cwd() to serve public content from. Symlinks are not followed.
|
||||
// pub const public_content_path = "public";
|
||||
pub const public_content_path = "public";
|
||||
|
||||
// HTTP buffer. Must be large enough to store all headers. This should typically not be modified.
|
||||
// pub const http_buffer_size: usize = std.math.pow(usize, 2, 16);
|
||||
pub const http_buffer_size: usize = std.math.pow(usize, 2, 16);
|
||||
|
||||
// The number of worker threads to spawn on startup for processing Jobs (NOT the number of
|
||||
// HTTP server worker threads).
|
||||
@ -56,7 +72,7 @@ pub const jetzig_options = struct {
|
||||
|
||||
// Duration before looking for more Jobs when the queue is found to be empty, in
|
||||
// milliseconds.
|
||||
// pub const job_worker_sleep_interval_ms: usize = 10;
|
||||
pub const job_worker_sleep_interval_ms: usize = 10;
|
||||
|
||||
/// Key-value store options. Set backend to `.file` to use a file-based store.
|
||||
/// When using `.file` backend, you must also set `.file_options`.
|
||||
@ -108,7 +124,7 @@ pub const jetzig_options = struct {
|
||||
// };
|
||||
|
||||
/// Force email delivery in development mode (instead of printing email body to logger).
|
||||
// pub const force_development_email_delivery = false;
|
||||
pub const force_development_email_delivery = false;
|
||||
|
||||
// Set custom fragments for rendering markdown templates. Any values will fall back to
|
||||
// defaults provided by Zmd (https://github.com/jetzig-framework/zmd/blob/main/src/zmd/html.zig).
|
||||
|
@ -101,16 +101,21 @@ pub const config = struct {
|
||||
/// Number of request threads. Defaults to number of detected CPUs.
|
||||
pub const thread_count: ?u16 = null;
|
||||
|
||||
/// Per-thread stack memory to use before spilling into request arena (possibly with allocations).
|
||||
pub const buffer_size: usize = 64 * 1024;
|
||||
|
||||
/// The pre-heated size of each item in the available memory pool used by requests for
|
||||
/// rendering. Total retained allocation: `worker_count * max_connections`. Requests
|
||||
/// requiring more memory will allocate per-request, leaving `arena_size` bytes pre-allocated
|
||||
/// for the next request.
|
||||
pub const arena_size: usize = 1024 * 1024;
|
||||
|
||||
/// Number of response worker threads.
|
||||
pub const worker_count: u16 = 4;
|
||||
|
||||
/// Total number of connections managed by worker threads.
|
||||
pub const max_connections: u16 = 512;
|
||||
|
||||
/// The size of each item in the available memory pool used by requests for rendering.
|
||||
/// Total retained allocation: `worker_count * max_connections`.
|
||||
pub const arena_size: usize = 1024 * 1024;
|
||||
|
||||
/// Path relative to cwd() to serve public content from. Symlinks are not followed.
|
||||
pub const public_content_path = "public";
|
||||
|
||||
|
@ -5,7 +5,7 @@ const builtin = @import("builtin");
|
||||
const types = @import("types.zig");
|
||||
|
||||
// Must be consistent with `std.io.tty.Color` for Windows compatibility.
|
||||
const codes = .{
|
||||
pub const codes = .{
|
||||
.escape = "\x1b[",
|
||||
.black = "30m",
|
||||
.red = "31m",
|
||||
|
@ -14,3 +14,7 @@ pub const status_codes = @import("http/status_codes.zig");
|
||||
pub const StatusCode = status_codes.StatusCode;
|
||||
pub const middleware = @import("http/middleware.zig");
|
||||
pub const mime = @import("http/mime.zig");
|
||||
|
||||
pub const SimplifiedRequest = struct {
|
||||
location: ?[]const u8,
|
||||
};
|
||||
|
@ -26,12 +26,16 @@ query_body: ?*jetzig.http.Query = null,
|
||||
_cookies: ?*jetzig.http.Cookies = null,
|
||||
_session: ?*jetzig.http.Session = null,
|
||||
body: []const u8 = undefined,
|
||||
processed: bool = false,
|
||||
state: enum { initial, processed } = .initial,
|
||||
response_started: bool = false,
|
||||
dynamic_assigned_template: ?[]const u8 = null,
|
||||
layout: ?[]const u8 = null,
|
||||
layout_disabled: bool = false,
|
||||
rendered: bool = false,
|
||||
redirected: bool = false,
|
||||
redirect_state: ?RedirectState = null,
|
||||
middleware_rendered: ?struct { name: []const u8, action: []const u8 } = null,
|
||||
middleware_rendered_during_response: bool = false,
|
||||
rendered_multiple: bool = false,
|
||||
rendered_view: ?jetzig.views.View = null,
|
||||
start_time: i128,
|
||||
@ -132,18 +136,18 @@ pub fn deinit(self: *Request) void {
|
||||
self.cookies.deinit();
|
||||
self.allocator.destroy(self.cookies);
|
||||
self.allocator.destroy(self.session);
|
||||
if (self.processed) self.allocator.free(self.body);
|
||||
if (self.state != .initial) self.allocator.free(self.body);
|
||||
}
|
||||
|
||||
/// Process request, read body if present.
|
||||
pub fn process(self: *Request) !void {
|
||||
self.body = self.httpz_request.body() orelse "";
|
||||
self.processed = true;
|
||||
self.state = .processed;
|
||||
}
|
||||
|
||||
/// Set response headers, write response payload, and finalize the response.
|
||||
pub fn respond(self: *Request) !void {
|
||||
if (!self.processed) unreachable;
|
||||
if (self.state == .initial) unreachable;
|
||||
|
||||
try self.setCookieHeaders();
|
||||
|
||||
@ -158,6 +162,7 @@ pub fn render(self: *Request, status_code: jetzig.http.status_codes.StatusCode)
|
||||
if (self.rendered) self.rendered_multiple = true;
|
||||
|
||||
self.rendered = true;
|
||||
if (self.response_started) self.middleware_rendered_during_response = true;
|
||||
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
||||
return self.rendered_view.?;
|
||||
}
|
||||
@ -179,15 +184,23 @@ pub fn redirect(
|
||||
|
||||
self.rendered = true;
|
||||
self.redirected = true;
|
||||
if (self.response_started) self.middleware_rendered_during_response = true;
|
||||
|
||||
const status_code = switch (redirect_status) {
|
||||
.moved_permanently => jetzig.http.status_codes.StatusCode.moved_permanently,
|
||||
.found => jetzig.http.status_codes.StatusCode.found,
|
||||
};
|
||||
|
||||
self.redirect_state = .{ .location = location, .status_code = status_code };
|
||||
return .{ .data = self.response_data, .status_code = status_code };
|
||||
}
|
||||
|
||||
const RedirectState = struct { location: []const u8, status_code: jetzig.http.status_codes.StatusCode };
|
||||
|
||||
pub fn renderRedirect(self: *Request, state: RedirectState) !void {
|
||||
self.response_data.reset();
|
||||
|
||||
self.response.headers.append("Location", location) catch |err| {
|
||||
self.response.headers.append("Location", state.location) catch |err| {
|
||||
switch (err) {
|
||||
error.JetzigTooManyHeaders => std.debug.print(
|
||||
"Header limit reached. Unable to add redirect header.\n",
|
||||
@ -197,8 +210,32 @@ pub fn redirect(
|
||||
}
|
||||
};
|
||||
|
||||
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
||||
return self.rendered_view.?;
|
||||
const view = .{ .data = self.response_data, .status_code = state.status_code };
|
||||
const status = jetzig.http.status_codes.get(state.status_code);
|
||||
const maybe_template = jetzig.zmpl.findPrefixed("views", status.getCode());
|
||||
self.rendered_view = view;
|
||||
|
||||
var root = try self.response_data.root(.object);
|
||||
try root.put("location", self.response_data.string(state.location));
|
||||
const content = switch (self.requestFormat()) {
|
||||
.HTML, .UNKNOWN => if (maybe_template) |template| blk: {
|
||||
try view.data.addConst("jetzig_view", view.data.string("internal"));
|
||||
try view.data.addConst("jetzig_action", view.data.string(@tagName(state.status_code)));
|
||||
break :blk try template.render(self.response_data);
|
||||
} else try std.fmt.allocPrint(self.allocator, "Redirecting to {s}", .{state.location}),
|
||||
.JSON => blk: {
|
||||
break :blk try std.json.stringifyAlloc(
|
||||
self.allocator,
|
||||
.{ .location = state.location, .status = .{
|
||||
.message = status.getMessage(),
|
||||
.code = status.getCode(),
|
||||
} },
|
||||
.{},
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
self.setResponse(.{ .view = view, .content = content }, .{});
|
||||
}
|
||||
|
||||
/// Infer the current format (JSON or HTML) from the request in this order:
|
||||
@ -246,7 +283,7 @@ pub fn getHeader(self: *const Request, key: []const u8) ?[]const u8 {
|
||||
/// otherwise the parsed JSON request body will take precedence and query parameters will be
|
||||
/// ignored.
|
||||
pub fn params(self: *Request) !*jetzig.data.Value {
|
||||
if (!self.processed) unreachable;
|
||||
if (self.state == .initial) unreachable;
|
||||
|
||||
switch (self.requestFormat()) {
|
||||
.JSON => {
|
||||
@ -489,7 +526,7 @@ pub fn formatStatus(self: *const Request, status_code: jetzig.http.StatusCode) !
|
||||
|
||||
return switch (self.requestFormat()) {
|
||||
.JSON => try std.json.stringifyAlloc(self.allocator, .{
|
||||
.@"error" = .{
|
||||
.status = .{
|
||||
.message = status.getMessage(),
|
||||
.code = status.getCode(),
|
||||
},
|
||||
|
@ -70,7 +70,7 @@ const Dispatcher = struct {
|
||||
|
||||
pub fn handle(self: Dispatcher, request: *httpz.Request, response: *httpz.Response) void {
|
||||
self.server.processNextRequest(request, response) catch |err| {
|
||||
self.server.errorHandlerFn(request, response, err);
|
||||
self.server.errorHandlerFn(request, response, err) catch {};
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -83,6 +83,7 @@ pub fn listen(self: *Server) !void {
|
||||
.address = self.options.bind,
|
||||
.thread_pool = .{
|
||||
.count = jetzig.config.get(?u16, "thread_count") orelse @intCast(try std.Thread.getCpuCount()),
|
||||
.buffer_size = jetzig.config.get(usize, "buffer_size"),
|
||||
},
|
||||
.workers = .{
|
||||
.count = jetzig.config.get(u16, "worker_count"),
|
||||
@ -105,10 +106,13 @@ pub fn listen(self: *Server) !void {
|
||||
return try httpz_server.listen();
|
||||
}
|
||||
|
||||
pub fn errorHandlerFn(self: *Server, request: *httpz.Request, response: *httpz.Response, err: anyerror) void {
|
||||
pub fn errorHandlerFn(self: *Server, request: *httpz.Request, response: *httpz.Response, err: anyerror) !void {
|
||||
if (isBadHttpError(err)) return;
|
||||
|
||||
self.logger.ERROR("Encountered error: {s} {s}", .{ @errorName(err), request.url.raw }) catch {};
|
||||
const stack = @errorReturnTrace();
|
||||
if (stack) |capture| self.logStackTrace(capture, .{ .httpz = request }) catch {};
|
||||
|
||||
response.body = "500 Internal Server Error";
|
||||
}
|
||||
|
||||
@ -119,11 +123,9 @@ fn processNextRequest(
|
||||
) !void {
|
||||
const start_time = std.time.nanoTimestamp();
|
||||
|
||||
const allocator = httpz_request.arena;
|
||||
|
||||
var response = try jetzig.http.Response.init(allocator, httpz_response);
|
||||
var response = try jetzig.http.Response.init(httpz_response.arena, httpz_response);
|
||||
var request = try jetzig.http.Request.init(
|
||||
allocator,
|
||||
httpz_request.arena,
|
||||
self,
|
||||
start_time,
|
||||
httpz_request,
|
||||
@ -135,15 +137,24 @@ fn processNextRequest(
|
||||
|
||||
var middleware_data = try jetzig.http.middleware.afterRequest(&request);
|
||||
|
||||
try self.renderResponse(&request);
|
||||
try request.response.headers.append("Content-Type", response.content_type);
|
||||
if (request.middleware_rendered) |_| { // Request processing ends when a middleware renders or redirects.
|
||||
if (request.redirect_state) |state| {
|
||||
try request.renderRedirect(state);
|
||||
} else if (request.rendered_view) |rendered| {
|
||||
// TODO: Allow middleware to set content
|
||||
request.setResponse(.{ .view = rendered, .content = "" }, .{});
|
||||
}
|
||||
try request.response.headers.append("Content-Type", response.content_type);
|
||||
try request.respond();
|
||||
} else {
|
||||
try self.renderResponse(&request);
|
||||
try request.response.headers.append("Content-Type", response.content_type);
|
||||
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
||||
jetzig.http.middleware.deinit(&middleware_data, &request);
|
||||
|
||||
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
||||
|
||||
try request.respond();
|
||||
|
||||
try jetzig.http.middleware.afterResponse(&middleware_data, &request);
|
||||
jetzig.http.middleware.deinit(&middleware_data, &request);
|
||||
try jetzig.http.middleware.afterResponse(&middleware_data, &request);
|
||||
try request.respond();
|
||||
}
|
||||
|
||||
try self.logger.logRequest(&request);
|
||||
}
|
||||
@ -180,6 +191,8 @@ fn renderResponse(self: *Server, request: *jetzig.http.Request) !void {
|
||||
.JSON => try self.renderJSON(request, route),
|
||||
.UNKNOWN => try self.renderHTML(request, route),
|
||||
}
|
||||
|
||||
if (request.redirect_state) |state| return try request.renderRedirect(state);
|
||||
}
|
||||
|
||||
fn renderStatic(resource: StaticResource, request: *jetzig.http.Request) !void {
|
||||
@ -388,7 +401,7 @@ fn renderInternalServerError(self: *Server, request: *jetzig.http.Request, err:
|
||||
try self.logger.ERROR("Encountered Error: {s}", .{@errorName(err)});
|
||||
|
||||
const stack = @errorReturnTrace();
|
||||
if (stack) |capture| try self.logStackTrace(capture, request);
|
||||
if (stack) |capture| try self.logStackTrace(capture, .{ .jetzig = request });
|
||||
|
||||
const status = .internal_server_error;
|
||||
return try self.renderError(request, status);
|
||||
@ -436,7 +449,7 @@ fn renderErrorView(
|
||||
.{@errorName(err)},
|
||||
);
|
||||
const stack = @errorReturnTrace();
|
||||
if (stack) |capture| try self.logStackTrace(capture, request);
|
||||
if (stack) |capture| try self.logStackTrace(capture, .{ .jetzig = request });
|
||||
return try renderDefaultError(request, status_code);
|
||||
};
|
||||
|
||||
@ -503,14 +516,18 @@ fn renderDefaultError(
|
||||
fn logStackTrace(
|
||||
self: Server,
|
||||
stack: *std.builtin.StackTrace,
|
||||
request: *jetzig.http.Request,
|
||||
request: union(enum) { jetzig: *const jetzig.http.Request, httpz: *const httpz.Request },
|
||||
) !void {
|
||||
try self.logger.ERROR("\nStack Trace:\n{}", .{stack});
|
||||
var buf = std.ArrayList(u8).init(request.allocator);
|
||||
const allocator = switch (request) {
|
||||
.jetzig => |capture| capture.allocator,
|
||||
.httpz => |capture| capture.arena,
|
||||
};
|
||||
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
defer buf.deinit();
|
||||
const writer = buf.writer();
|
||||
try stack.format("", .{}, writer);
|
||||
try self.logger.ERROR("{s}\n", .{buf.items});
|
||||
if (buf.items.len > 0) try self.logger.ERROR("{s}\n", .{buf.items});
|
||||
}
|
||||
|
||||
fn matchCustomRoute(self: Server, request: *const jetzig.http.Request) ?jetzig.views.Route {
|
||||
|
@ -3,22 +3,24 @@ const jetzig = @import("../../jetzig.zig");
|
||||
|
||||
const middlewares: []const type = jetzig.config.get([]const type, "middleware");
|
||||
|
||||
const MiddlewareData = std.BoundedArray(*anyopaque, middlewares.len);
|
||||
const MiddlewareData = std.BoundedArray(?*anyopaque, middlewares.len);
|
||||
|
||||
pub fn afterRequest(request: *jetzig.http.Request) !MiddlewareData {
|
||||
var middleware_data = MiddlewareData.init(0) catch unreachable;
|
||||
|
||||
inline for (middlewares, 0..) |middleware, index| {
|
||||
if (comptime !@hasDecl(middleware, "init")) continue;
|
||||
const data = try @call(.always_inline, middleware.init, .{request});
|
||||
// We cannot overflow here because we know the length of the array
|
||||
middleware_data.insert(index, data) catch unreachable;
|
||||
if (comptime !@hasDecl(middleware, "init")) {
|
||||
try middleware_data.insert(index, null);
|
||||
} else {
|
||||
const data = try @call(.always_inline, middleware.init, .{request});
|
||||
try middleware_data.insert(index, data);
|
||||
}
|
||||
}
|
||||
|
||||
inline for (middlewares, 0..) |middleware, index| {
|
||||
if (comptime !@hasDecl(middleware, "afterRequest")) continue;
|
||||
if (comptime @hasDecl(middleware, "init")) {
|
||||
const data = middleware_data.get(index);
|
||||
const data = middleware_data.get(index).?;
|
||||
try @call(
|
||||
.always_inline,
|
||||
middleware.afterRequest,
|
||||
@ -27,6 +29,10 @@ pub fn afterRequest(request: *jetzig.http.Request) !MiddlewareData {
|
||||
} else {
|
||||
try @call(.always_inline, middleware.afterRequest, .{request});
|
||||
}
|
||||
if (request.rendered or request.redirected) {
|
||||
request.middleware_rendered = .{ .name = @typeName(middleware), .action = "afterRequest" };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return middleware_data;
|
||||
@ -36,17 +42,25 @@ pub fn beforeResponse(
|
||||
middleware_data: *MiddlewareData,
|
||||
request: *jetzig.http.Request,
|
||||
) !void {
|
||||
request.response_started = true;
|
||||
|
||||
inline for (middlewares, 0..) |middleware, index| {
|
||||
if (comptime !@hasDecl(middleware, "beforeResponse")) continue;
|
||||
if (comptime @hasDecl(middleware, "init")) {
|
||||
const data = middleware_data.get(index);
|
||||
try @call(
|
||||
.always_inline,
|
||||
middleware.beforeResponse,
|
||||
.{ @as(*middleware, @ptrCast(@alignCast(data))), request, request.response },
|
||||
);
|
||||
} else {
|
||||
try @call(.always_inline, middleware.beforeResponse, .{ request, request.response });
|
||||
if (!request.middleware_rendered_during_response) {
|
||||
if (comptime @hasDecl(middleware, "init")) {
|
||||
const data = middleware_data.get(index).?;
|
||||
try @call(
|
||||
.always_inline,
|
||||
middleware.beforeResponse,
|
||||
.{ @as(*middleware, @ptrCast(@alignCast(data))), request, request.response },
|
||||
);
|
||||
} else {
|
||||
try @call(.always_inline, middleware.beforeResponse, .{ request, request.response });
|
||||
}
|
||||
}
|
||||
if (request.middleware_rendered_during_response) {
|
||||
request.middleware_rendered = .{ .name = @typeName(middleware), .action = "beforeResponse" };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,7 +72,7 @@ pub fn afterResponse(
|
||||
inline for (middlewares, 0..) |middleware, index| {
|
||||
if (comptime !@hasDecl(middleware, "afterResponse")) continue;
|
||||
if (comptime @hasDecl(middleware, "init")) {
|
||||
const data = middleware_data.get(index);
|
||||
const data = middleware_data.get(index).?;
|
||||
try @call(
|
||||
.always_inline,
|
||||
middleware.afterResponse,
|
||||
|
@ -84,12 +84,22 @@ pub fn logRequest(self: DevelopmentLogger, request: *const jetzig.http.Request)
|
||||
|
||||
const formatted_level = if (self.stdout_colorized) colorizedLogLevel(.INFO) else @tagName(.INFO);
|
||||
|
||||
try self.log_queue.print("{s: >5} [{s}] [{s}/{s}/{s}] {s}\n", .{
|
||||
try self.log_queue.print("{s: >5} [{s}] [{s}/{s}/{s}]{s}{s}{s}{s}{s}{s}{s}{s}{s}{s} {s}\n", .{
|
||||
formatted_level,
|
||||
iso8601,
|
||||
formatted_duration,
|
||||
request.fmtMethod(self.stdout_colorized),
|
||||
formatted_status,
|
||||
if (request.middleware_rendered) |_| " [" ++ jetzig.colors.codes.escape ++ jetzig.colors.codes.magenta else "",
|
||||
if (request.middleware_rendered) |middleware| middleware.name else "",
|
||||
if (request.middleware_rendered) |_| jetzig.colors.codes.escape ++ jetzig.colors.codes.white ++ ":" else "",
|
||||
if (request.middleware_rendered) |_| jetzig.colors.codes.escape ++ jetzig.colors.codes.blue else "",
|
||||
if (request.middleware_rendered) |middleware| middleware.action else "",
|
||||
if (request.middleware_rendered) |_| jetzig.colors.codes.escape ++ jetzig.colors.codes.white ++ ":" else "",
|
||||
if (request.middleware_rendered) |_| jetzig.colors.codes.escape ++ jetzig.colors.codes.bright_cyan else "",
|
||||
if (request.middleware_rendered) |_| if (request.redirected) "redirect" else "render" else "",
|
||||
if (request.middleware_rendered) |_| jetzig.colors.codes.escape ++ jetzig.colors.codes.reset else "",
|
||||
if (request.middleware_rendered) |_| "]" else "",
|
||||
request.path.path,
|
||||
}, .stdout);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub fn afterRequest(request: *jetzig.http.Request) !void {
|
||||
|
||||
/// If a redirect was issued during request processing, reset any response data, set response
|
||||
/// status to `200 OK` and replace the `Location` header with a `HX-Redirect` header.
|
||||
pub fn beforeResponse(request: *const jetzig.http.Request, response: *jetzig.http.Response) !void {
|
||||
pub fn beforeResponse(request: *jetzig.http.Request, response: *jetzig.http.Response) !void {
|
||||
if (response.status_code != .moved_permanently and response.status_code != .found) return;
|
||||
if (request.headers.get("HX-Request") == null) return;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user