mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
Merge pull request #198 from jetzig-framework/render-text
Implement `request.renderText()`
This commit is contained in:
commit
fe49185c32
17
demo/src/app/views/render_text.zig
Normal file
17
demo/src/app/views/render_text.zig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const jetzig = @import("jetzig");
|
||||||
|
|
||||||
|
pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||||
|
request.response.content_type = "text/xml";
|
||||||
|
return request.renderText("<foo><bar>baz</bar></foo>", .ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "index" {
|
||||||
|
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||||
|
defer app.deinit();
|
||||||
|
|
||||||
|
const response = try app.request(.GET, "/render_text", .{});
|
||||||
|
try response.expectStatus(.ok);
|
||||||
|
try response.expectBodyContains("<foo><bar>baz</bar></foo>");
|
||||||
|
try response.expectHeader("content-type", "text/xml");
|
||||||
|
}
|
3
demo/src/app/views/render_text/index.zmpl
Normal file
3
demo/src/app/views/render_text/index.zmpl
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<span>Content goes here</span>
|
||||||
|
</div>
|
@ -26,3 +26,5 @@ pub const params = @import("http/params.zig");
|
|||||||
pub const SimplifiedRequest = struct {
|
pub const SimplifiedRequest = struct {
|
||||||
location: ?[]const u8,
|
location: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const default_content_type = "application/octet-stream";
|
||||||
|
@ -16,6 +16,7 @@ pub const RequestState = enum {
|
|||||||
processed, // Request headers have been processed
|
processed, // Request headers have been processed
|
||||||
after_request, // Initial middleware processing
|
after_request, // Initial middleware processing
|
||||||
rendered, // Rendered by middleware or view
|
rendered, // Rendered by middleware or view
|
||||||
|
rendered_text, // Rendered text by middleware or view
|
||||||
redirected, // Redirected by middleware or view
|
redirected, // Redirected by middleware or view
|
||||||
failed, // Failed by middleware or view
|
failed, // Failed by middleware or view
|
||||||
before_response, // Post middleware processing
|
before_response, // Post middleware processing
|
||||||
@ -230,7 +231,7 @@ pub fn fail(self: *Request, status_code: jetzig.http.status_codes.StatusCode) je
|
|||||||
pub inline fn isRendered(self: *const Request) bool {
|
pub inline fn isRendered(self: *const Request) bool {
|
||||||
return switch (self.state) {
|
return switch (self.state) {
|
||||||
.initial, .processed, .after_request, .before_response => false,
|
.initial, .processed, .after_request, .before_response => false,
|
||||||
.rendered, .redirected, .failed, .finalized => true,
|
.rendered, .rendered_text, .redirected, .failed, .finalized => true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,6 +737,18 @@ pub fn joinPath(self: *const Request, args: anytype) ![]const u8 {
|
|||||||
return try std.mem.join(self.allocator, "/", buf[0..]);
|
return try std.mem.join(self.allocator, "/", buf[0..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn renderText(
|
||||||
|
self: *Request,
|
||||||
|
text: []const u8,
|
||||||
|
status_code: jetzig.http.StatusCode,
|
||||||
|
) jetzig.views.View {
|
||||||
|
self.state = .rendered_text;
|
||||||
|
self.rendered_view = .{ .data = self.response_data, .status_code = status_code };
|
||||||
|
self.setResponse(.{ .view = self.rendered_view.?, .content = text }, .{});
|
||||||
|
|
||||||
|
return self.rendered_view.?;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn joinPaths(self: *const Request, paths: []const []const []const u8) ![]const u8 {
|
pub fn joinPaths(self: *const Request, paths: []const []const []const u8) ![]const u8 {
|
||||||
var buf = std.ArrayList([]const u8).init(self.allocator);
|
var buf = std.ArrayList([]const u8).init(self.allocator);
|
||||||
defer buf.deinit();
|
defer buf.deinit();
|
||||||
@ -753,10 +766,12 @@ pub fn setResponse(
|
|||||||
) void {
|
) void {
|
||||||
self.response.content = rendered_view.content;
|
self.response.content = rendered_view.content;
|
||||||
self.response.status_code = rendered_view.view.status_code;
|
self.response.status_code = rendered_view.view.status_code;
|
||||||
|
if (self.response.content_type == null) {
|
||||||
self.response.content_type = options.content_type orelse switch (self.requestFormat()) {
|
self.response.content_type = options.content_type orelse switch (self.requestFormat()) {
|
||||||
.HTML, .UNKNOWN => "text/html",
|
.HTML, .UNKNOWN => "text/html",
|
||||||
.JSON => "application/json",
|
.JSON => "application/json",
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setCookieHeaders(self: *Request) !void {
|
fn setCookieHeaders(self: *Request) !void {
|
||||||
|
@ -11,7 +11,7 @@ allocator: std.mem.Allocator,
|
|||||||
headers: jetzig.http.Headers,
|
headers: jetzig.http.Headers,
|
||||||
content: []const u8,
|
content: []const u8,
|
||||||
status_code: http.status_codes.StatusCode,
|
status_code: http.status_codes.StatusCode,
|
||||||
content_type: []const u8,
|
content_type: ?[]const u8 = null,
|
||||||
httpz_response: *httpz.Response,
|
httpz_response: *httpz.Response,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
@ -22,8 +22,11 @@ pub fn init(
|
|||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.httpz_response = httpz_response,
|
.httpz_response = httpz_response,
|
||||||
.status_code = .no_content,
|
.status_code = .no_content,
|
||||||
.content_type = "application/octet-stream",
|
|
||||||
.content = "",
|
.content = "",
|
||||||
.headers = jetzig.http.Headers.init(allocator, &httpz_response.headers),
|
.headers = jetzig.http.Headers.init(allocator, &httpz_response.headers),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn contentType(self: *const jetzig.http.Response) []const u8 {
|
||||||
|
return self.content_type orelse jetzig.http.default_content_type;
|
||||||
|
}
|
||||||
|
@ -159,7 +159,7 @@ pub fn processNextRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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.contentType());
|
||||||
|
|
||||||
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
try jetzig.http.middleware.beforeResponse(&middleware_data, &request);
|
||||||
try request.respond();
|
try request.respond();
|
||||||
@ -178,7 +178,7 @@ fn maybeMiddlewareRender(request: *jetzig.http.Request, response: *const jetzig.
|
|||||||
// TODO: Allow middleware to set content
|
// TODO: Allow middleware to set content
|
||||||
request.setResponse(.{ .view = rendered, .content = "" }, .{});
|
request.setResponse(.{ .view = rendered, .content = "" }, .{});
|
||||||
}
|
}
|
||||||
try request.response.headers.append("Content-Type", response.content_type);
|
try request.response.headers.append("Content-Type", response.contentType());
|
||||||
try request.respond();
|
try request.respond();
|
||||||
return true;
|
return true;
|
||||||
} else return false;
|
} else return false;
|
||||||
@ -356,12 +356,16 @@ fn renderView(
|
|||||||
return try self.renderInternalServerError(request, @errorReturnTrace(), err);
|
return try self.renderInternalServerError(request, @errorReturnTrace(), err);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (request.state == .failed) {
|
switch (request.state) {
|
||||||
const view: jetzig.views.View = request.rendered_view orelse .{
|
.failed => {
|
||||||
.data = request.response_data,
|
const status_code = request.rendered_view.?.status_code;
|
||||||
.status_code = .internal_server_error,
|
return try self.renderError(request, status_code, .{});
|
||||||
};
|
},
|
||||||
return try self.renderError(request, view.status_code, .{});
|
.rendered_text => {
|
||||||
|
const view = request.rendered_view.?; // a panic here is a bug.
|
||||||
|
return .{ .view = view, .content = request.response.content };
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
const template: ?zmpl.Template = if (request.dynamic_assigned_template) |request_template|
|
const template: ?zmpl.Template = if (request.dynamic_assigned_template) |request_template|
|
||||||
@ -721,7 +725,7 @@ fn matchRoute(self: *Server, request: *jetzig.http.Request, static: bool) !?jetz
|
|||||||
|
|
||||||
const StaticResource = struct {
|
const StaticResource = struct {
|
||||||
content: []const u8,
|
content: []const u8,
|
||||||
mime_type: []const u8 = "application/octet-stream",
|
mime_type: []const u8 = jetzig.http.default_content_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn matchStaticResource(self: *Server, request: *jetzig.http.Request) !?StaticResource {
|
fn matchStaticResource(self: *Server, request: *jetzig.http.Request) !?StaticResource {
|
||||||
@ -780,7 +784,7 @@ fn matchPublicContent(self: *Server, request: *jetzig.http.Request) !?StaticReso
|
|||||||
jetzig.config.get(usize, "max_bytes_public_content"),
|
jetzig.config.get(usize, "max_bytes_public_content"),
|
||||||
);
|
);
|
||||||
const extension = std.fs.path.extension(file_path);
|
const extension = std.fs.path.extension(file_path);
|
||||||
const mime_type = if (self.mime_map.get(extension)) |mime| mime else "application/octet-stream";
|
const mime_type = if (self.mime_map.get(extension)) |mime| mime else jetzig.http.default_content_type;
|
||||||
return .{
|
return .{
|
||||||
.content = content,
|
.content = content,
|
||||||
.mime_type = mime_type,
|
.mime_type = mime_type,
|
||||||
|
@ -120,14 +120,31 @@ pub fn expectBodyContains(expected: []const u8, response: TestResponse) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn expectHeader(expected_name: []const u8, expected_value: ?[]const u8, response: TestResponse) !void {
|
pub fn expectHeader(expected_name: []const u8, expected_value: ?[]const u8, response: TestResponse) !void {
|
||||||
|
var mismatches = std.ArrayList([]const u8).init(response.allocator);
|
||||||
|
defer mismatches.deinit();
|
||||||
|
|
||||||
for (response.headers) |header| {
|
for (response.headers) |header| {
|
||||||
if (!std.ascii.eqlIgnoreCase(header.name, expected_name)) continue;
|
if (!std.ascii.eqlIgnoreCase(header.name, expected_name)) continue;
|
||||||
if (expected_value) |value| {
|
if (expected_value) |value| {
|
||||||
if (std.mem.eql(u8, header.value, value)) return;
|
if (std.mem.eql(u8, header.value, value)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
try mismatches.append(header.value);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFailure(
|
||||||
|
"Expected header " ++
|
||||||
|
jetzig.colors.cyan("{s}") ++
|
||||||
|
": " ++
|
||||||
|
jetzig.colors.green("{?s}") ++
|
||||||
|
", found: " ++
|
||||||
|
jetzig.colors.red("{s}"),
|
||||||
|
.{ expected_name, expected_value, mismatches.items },
|
||||||
|
);
|
||||||
return error.JetzigExpectHeaderError;
|
return error.JetzigExpectHeaderError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user