mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 22:16:08 +00:00
Fix middleware render detection
This commit is contained in:
parent
1565ae3b73
commit
9684181c64
@ -11,6 +11,16 @@ pub const Method = enum { DELETE, GET, PATCH, POST, HEAD, PUT, CONNECT, OPTIONS,
|
|||||||
pub const Modifier = enum { edit, new };
|
pub const Modifier = enum { edit, new };
|
||||||
pub const Format = enum { HTML, JSON, UNKNOWN };
|
pub const Format = enum { HTML, JSON, UNKNOWN };
|
||||||
pub const Protocol = enum { http, https };
|
pub const Protocol = enum { http, https };
|
||||||
|
pub const RequestState = enum {
|
||||||
|
initial, // No processing has taken place
|
||||||
|
processed, // Request headers have been processed
|
||||||
|
after_request, // Initial middleware processing
|
||||||
|
rendered, // Rendered by middleware or view
|
||||||
|
redirected, // Redirected by middleware or view
|
||||||
|
failed, // Failed by middleware or view
|
||||||
|
before_response, // Post middleware processing
|
||||||
|
finalized, // Response generated
|
||||||
|
};
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
path: jetzig.http.Path,
|
path: jetzig.http.Path,
|
||||||
@ -30,14 +40,12 @@ parsed_multipart: ?*jetzig.data.Data = null,
|
|||||||
_cookies: ?*jetzig.http.Cookies = null,
|
_cookies: ?*jetzig.http.Cookies = null,
|
||||||
_session: ?*jetzig.http.Session = null,
|
_session: ?*jetzig.http.Session = null,
|
||||||
body: []const u8 = undefined,
|
body: []const u8 = undefined,
|
||||||
state: enum { initial, rendered, redirected, failed, processed } = .initial,
|
state: RequestState = .initial,
|
||||||
response_started: bool = false,
|
|
||||||
dynamic_assigned_template: ?[]const u8 = null,
|
dynamic_assigned_template: ?[]const u8 = null,
|
||||||
layout: ?[]const u8 = null,
|
layout: ?[]const u8 = null,
|
||||||
layout_disabled: bool = false,
|
layout_disabled: bool = false,
|
||||||
redirect_state: ?RedirectState = null,
|
redirect_state: ?RedirectState = null,
|
||||||
middleware_rendered: ?struct { name: []const u8, action: []const u8 } = null,
|
middleware_rendered: ?struct { name: []const u8, action: []const u8 } = null,
|
||||||
middleware_rendered_during_response: bool = false,
|
|
||||||
middleware_data: jetzig.http.middleware.MiddlewareData = undefined,
|
middleware_data: jetzig.http.middleware.MiddlewareData = undefined,
|
||||||
rendered_multiple: bool = false,
|
rendered_multiple: bool = false,
|
||||||
rendered_view: ?jetzig.views.View = null,
|
rendered_view: ?jetzig.views.View = null,
|
||||||
@ -172,6 +180,7 @@ pub fn respond(self: *Request) !void {
|
|||||||
const status = jetzig.http.status_codes.get(self.response.status_code);
|
const status = jetzig.http.status_codes.get(self.response.status_code);
|
||||||
self.httpz_response.status = try status.getCodeInt();
|
self.httpz_response.status = try status.getCodeInt();
|
||||||
self.httpz_response.body = self.response.content;
|
self.httpz_response.body = self.response.content;
|
||||||
|
self.state = .finalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the root value for response data.
|
/// Set the root value for response data.
|
||||||
@ -186,10 +195,9 @@ pub fn data(self: Request, comptime root: @TypeOf(.enum_literal)) !*jetzig.Data.
|
|||||||
/// Render a response. This function can only be called once per request (repeat calls will
|
/// Render a response. This function can only be called once per request (repeat calls will
|
||||||
/// trigger an error).
|
/// trigger an error).
|
||||||
pub fn render(self: *Request, status_code: jetzig.http.status_codes.StatusCode) jetzig.views.View {
|
pub fn render(self: *Request, status_code: jetzig.http.status_codes.StatusCode) jetzig.views.View {
|
||||||
if (self.state != .processed) self.rendered_multiple = true;
|
if (self.isRendered()) self.rendered_multiple = true;
|
||||||
|
|
||||||
self.state = .rendered;
|
self.state = .rendered;
|
||||||
if (self.response_started) self.middleware_rendered_during_response = true;
|
|
||||||
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
||||||
return self.rendered_view.?;
|
return self.rendered_view.?;
|
||||||
}
|
}
|
||||||
@ -197,14 +205,20 @@ pub fn render(self: *Request, status_code: jetzig.http.status_codes.StatusCode)
|
|||||||
/// Render an error. This function can only be called once per request (repeat calls will
|
/// Render an error. This function can only be called once per request (repeat calls will
|
||||||
/// trigger an error).
|
/// trigger an error).
|
||||||
pub fn fail(self: *Request, status_code: jetzig.http.status_codes.StatusCode) jetzig.views.View {
|
pub fn fail(self: *Request, status_code: jetzig.http.status_codes.StatusCode) jetzig.views.View {
|
||||||
if (self.state != .processed) self.rendered_multiple = true;
|
if (self.isRendered()) self.rendered_multiple = true;
|
||||||
|
|
||||||
self.state = .failed;
|
self.state = .failed;
|
||||||
if (self.response_started) self.middleware_rendered_during_response = true;
|
|
||||||
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
||||||
return self.rendered_view.?;
|
return self.rendered_view.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn isRendered(self: *const Request) bool {
|
||||||
|
return switch (self.state) {
|
||||||
|
.initial, .processed, .after_request, .before_response => false,
|
||||||
|
.rendered, .redirected, .failed, .finalized => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Issue a redirect to a new location.
|
/// Issue a redirect to a new location.
|
||||||
/// ```zig
|
/// ```zig
|
||||||
/// return request.redirect("https://www.example.com/", .moved_permanently);
|
/// return request.redirect("https://www.example.com/", .moved_permanently);
|
||||||
@ -218,10 +232,9 @@ pub fn redirect(
|
|||||||
location: []const u8,
|
location: []const u8,
|
||||||
redirect_status: enum { moved_permanently, found },
|
redirect_status: enum { moved_permanently, found },
|
||||||
) jetzig.views.View {
|
) jetzig.views.View {
|
||||||
if (self.state != .processed) self.rendered_multiple = true;
|
if (self.isRendered()) self.rendered_multiple = true;
|
||||||
|
|
||||||
self.state = .redirected;
|
self.state = .redirected;
|
||||||
if (self.response_started) self.middleware_rendered_during_response = true;
|
|
||||||
|
|
||||||
const status_code = switch (redirect_status) {
|
const status_code = switch (redirect_status) {
|
||||||
.moved_permanently => jetzig.http.status_codes.StatusCode.moved_permanently,
|
.moved_permanently => jetzig.http.status_codes.StatusCode.moved_permanently,
|
||||||
|
@ -138,7 +138,8 @@ pub fn processNextRequest(
|
|||||||
|
|
||||||
var middleware_data = try jetzig.http.middleware.afterRequest(&request);
|
var middleware_data = try jetzig.http.middleware.afterRequest(&request);
|
||||||
|
|
||||||
if (request.middleware_rendered) |_| { // Request processing ends when a middleware renders or redirects.
|
if (request.middleware_rendered) |_| {
|
||||||
|
// Request processing ends when a middleware renders or redirects.
|
||||||
if (request.redirect_state) |state| {
|
if (request.redirect_state) |state| {
|
||||||
try request.renderRedirect(state);
|
try request.renderRedirect(state);
|
||||||
} else if (request.rendered_view) |rendered| {
|
} else if (request.rendered_view) |rendered| {
|
||||||
@ -150,8 +151,8 @@ pub fn processNextRequest(
|
|||||||
} else {
|
} else {
|
||||||
try self.renderResponse(&request);
|
try self.renderResponse(&request);
|
||||||
try request.response.headers.append("Content-Type", response.content_type);
|
try request.response.headers.append("Content-Type", response.content_type);
|
||||||
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
|
||||||
|
|
||||||
|
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
||||||
try request.respond();
|
try request.respond();
|
||||||
try jetzig.http.middleware.afterResponse(&middleware_data, &request);
|
try jetzig.http.middleware.afterResponse(&middleware_data, &request);
|
||||||
jetzig.http.middleware.deinit(&middleware_data, &request);
|
jetzig.http.middleware.deinit(&middleware_data, &request);
|
||||||
@ -371,7 +372,7 @@ fn renderView(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (request.state != .redirected) {
|
if (request.state == .processed) {
|
||||||
try self.logger.WARN("`request.render` was not invoked. Rendering empty content.", .{});
|
try self.logger.WARN("`request.render` was not invoked. Rendering empty content.", .{});
|
||||||
}
|
}
|
||||||
request.response_data.reset();
|
request.response_data.reset();
|
||||||
@ -475,8 +476,6 @@ fn renderInternalServerError(
|
|||||||
stack_trace: ?*std.builtin.StackTrace,
|
stack_trace: ?*std.builtin.StackTrace,
|
||||||
err: anyerror,
|
err: anyerror,
|
||||||
) !RenderedView {
|
) !RenderedView {
|
||||||
// request.response_data.reset();
|
|
||||||
|
|
||||||
try self.logger.logError(stack_trace, err);
|
try self.logger.logError(stack_trace, err);
|
||||||
|
|
||||||
const status = jetzig.http.StatusCode.internal_server_error;
|
const status = jetzig.http.StatusCode.internal_server_error;
|
||||||
|
@ -60,8 +60,11 @@ pub fn afterRequest(request: *jetzig.http.Request) !MiddlewareData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.state = .after_request;
|
||||||
|
|
||||||
inline for (middlewares, 0..) |middleware, index| {
|
inline for (middlewares, 0..) |middleware, index| {
|
||||||
if (comptime !@hasDecl(middleware, "afterRequest")) continue;
|
if (comptime !@hasDecl(middleware, "afterRequest")) continue;
|
||||||
|
|
||||||
if (comptime @hasDecl(middleware, "init")) {
|
if (comptime @hasDecl(middleware, "init")) {
|
||||||
const data = middleware_data.get(index).?;
|
const data = middleware_data.get(index).?;
|
||||||
try @call(
|
try @call(
|
||||||
@ -72,7 +75,8 @@ pub fn afterRequest(request: *jetzig.http.Request) !MiddlewareData {
|
|||||||
} else {
|
} else {
|
||||||
try @call(.always_inline, middleware.afterRequest, .{request});
|
try @call(.always_inline, middleware.afterRequest, .{request});
|
||||||
}
|
}
|
||||||
if (request.state != .initial) {
|
|
||||||
|
if (request.state != .after_request) {
|
||||||
request.middleware_rendered = .{ .name = @typeName(middleware), .action = "afterRequest" };
|
request.middleware_rendered = .{ .name = @typeName(middleware), .action = "afterRequest" };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -86,11 +90,11 @@ pub fn beforeResponse(
|
|||||||
middleware_data: *MiddlewareData,
|
middleware_data: *MiddlewareData,
|
||||||
request: *jetzig.http.Request,
|
request: *jetzig.http.Request,
|
||||||
) !void {
|
) !void {
|
||||||
request.response_started = true;
|
request.state = .before_response;
|
||||||
|
|
||||||
inline for (middlewares, 0..) |middleware, index| {
|
inline for (middlewares, 0..) |middleware, index| {
|
||||||
if (comptime !@hasDecl(middleware, "beforeResponse")) continue;
|
if (comptime !@hasDecl(middleware, "beforeResponse")) continue;
|
||||||
if (!request.middleware_rendered_during_response) {
|
if (request.state == .before_response) {
|
||||||
if (comptime @hasDecl(middleware, "init")) {
|
if (comptime @hasDecl(middleware, "init")) {
|
||||||
const data = middleware_data.get(index).?;
|
const data = middleware_data.get(index).?;
|
||||||
try @call(
|
try @call(
|
||||||
@ -99,10 +103,15 @@ pub fn beforeResponse(
|
|||||||
.{ @as(*middleware, @ptrCast(@alignCast(data))), request, request.response },
|
.{ @as(*middleware, @ptrCast(@alignCast(data))), request, request.response },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
try @call(.always_inline, middleware.beforeResponse, .{ request, request.response });
|
try @call(
|
||||||
|
.always_inline,
|
||||||
|
middleware.beforeResponse,
|
||||||
|
.{ request, request.response },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (request.middleware_rendered_during_response) {
|
|
||||||
|
if (request.state != .before_response) {
|
||||||
request.middleware_rendered = .{
|
request.middleware_rendered = .{
|
||||||
.name = @typeName(middleware),
|
.name = @typeName(middleware),
|
||||||
.action = "beforeResponse",
|
.action = "beforeResponse",
|
||||||
|
@ -20,7 +20,11 @@ pub fn afterRequest(request: *jetzig.http.Request) !void {
|
|||||||
/// If a redirect was issued during request processing, reset any response data, set response
|
/// 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.
|
/// status to `200 OK` and replace the `Location` header with a `HX-Redirect` header.
|
||||||
pub fn beforeResponse(request: *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;
|
switch (response.status_code) {
|
||||||
|
.moved_permanently, .found => {},
|
||||||
|
else => return,
|
||||||
|
}
|
||||||
|
|
||||||
if (request.headers.get("HX-Request") == null) return;
|
if (request.headers.get("HX-Request") == null) return;
|
||||||
|
|
||||||
if (response.headers.get("Location")) |location| {
|
if (response.headers.get("Location")) |location| {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user