Skip to content

Commit a6b9764

Browse files
authored
fix: apply Respond Fields directly to Response
This will make it so that Respond Fields are directly applied onto the Response. This will help prevent a common issue where a stack-allocated slice was being returned in the `Respond`
2 parents efa34a3 + eb54ac5 commit a6b9764

File tree

15 files changed

+112
-152
lines changed

15 files changed

+112
-152
lines changed

examples/basic/main.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ const Context = http.Context;
1515
const Route = http.Route;
1616
const Respond = http.Respond;
1717

18-
fn base_handler(_: *const Context, _: void) !Respond {
19-
return Respond{ .standard = .{
18+
fn base_handler(ctx: *const Context, _: void) !Respond {
19+
return ctx.response.apply(.{
2020
.status = .OK,
2121
.mime = http.Mime.HTML,
2222
.body = "Hello, world!",
23-
} };
23+
});
2424
}
2525

2626
pub fn main() !void {

examples/cookies/main.zig

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@ fn base_handler(ctx: *const Context, _: void) !Respond {
2222
while (iter.next()) |kv| log.debug("cookie: k={s} v={s}", .{ kv.key_ptr.*, kv.value_ptr.* });
2323

2424
const cookie = Cookie.init("example_cookie", "abcdef123");
25-
26-
return Respond{ .standard = .{
25+
return ctx.response.apply(.{
2726
.status = .OK,
2827
.mime = http.Mime.HTML,
2928
.body = "Hello, world!",
3029
.headers = &.{
3130
.{ "Set-Cookie", try cookie.to_string_alloc(ctx.allocator) },
3231
},
33-
} };
32+
});
3433
}
3534

3635
pub fn main() !void {

examples/form/main.zig

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const Form = http.Form;
1717
const Query = http.Query;
1818
const Respond = http.Respond;
1919

20-
fn base_handler(_: *const Context, _: void) !Respond {
20+
fn base_handler(ctx: *const Context, _: void) !Respond {
2121
const body =
2222
\\<form>
2323
\\ <label for="fname">First name:</label>
@@ -33,11 +33,11 @@ fn base_handler(_: *const Context, _: void) !Respond {
3333
\\</form>
3434
;
3535

36-
return Respond{ .standard = .{
36+
return ctx.response.apply(.{
3737
.status = .OK,
3838
.mime = http.Mime.HTML,
3939
.body = body,
40-
} };
40+
});
4141
}
4242

4343
const UserInfo = struct {
@@ -69,11 +69,11 @@ fn generate_handler(ctx: *const Context, _: void) !Respond {
6969
},
7070
);
7171

72-
return Respond{ .standard = .{
72+
return ctx.response.apply(.{
7373
.status = .OK,
7474
.mime = http.Mime.TEXT,
7575
.body = body,
76-
} };
76+
});
7777
}
7878

7979
pub fn main() !void {

examples/fs/main.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const FsDir = http.FsDir;
1919

2020
const Compression = http.Middlewares.Compression;
2121

22-
fn base_handler(_: *const Context, _: void) !Respond {
22+
fn base_handler(ctx: *const Context, _: void) !Respond {
2323
const body =
2424
\\ <!DOCTYPE html>
2525
\\ <html>
@@ -29,11 +29,11 @@ fn base_handler(_: *const Context, _: void) !Respond {
2929
\\ </html>
3030
;
3131

32-
return Respond{ .standard = .{
32+
return try ctx.response.apply(.{
3333
.status = .OK,
3434
.mime = http.Mime.HTML,
3535
.body = body[0..],
36-
} };
36+
});
3737
}
3838

3939
pub fn main() !void {

examples/middleware/main.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ fn root_handler(ctx: *const Context, id: i8) !Respond {
3232
// This is the standard response and what you
3333
// will usually be using. This will send to the
3434
// client and then continue to await more requests.
35-
return Respond{ .standard = .{
35+
return ctx.response.apply(.{
3636
.status = .OK,
3737
.mime = http.Mime.HTML,
3838
.body = body[0..],
39-
} };
39+
});
4040
}
4141

4242
fn passing_middleware(next: *Next, _: void) !Respond {

examples/tls/main.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const Respond = http.Respond;
1717

1818
const Compression = http.Middlewares.Compression;
1919

20-
fn root_handler(_: *const Context, _: void) !Respond {
20+
fn root_handler(ctx: *const Context, _: void) !Respond {
2121
const body =
2222
\\ <!DOCTYPE html>
2323
\\ <html>
@@ -30,11 +30,11 @@ fn root_handler(_: *const Context, _: void) !Respond {
3030
\\ </html>
3131
;
3232

33-
return Respond{ .standard = .{
33+
return ctx.response.apply(.{
3434
.status = .OK,
3535
.mime = http.Mime.HTML,
3636
.body = body[0..],
37-
} };
37+
});
3838
}
3939

4040
pub fn main() !void {

examples/unix/main.zig

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,14 @@ const Route = http.Route;
1515
const Router = http.Router;
1616
const Respond = http.Respond;
1717

18-
pub const std_options = .{
19-
.log_level = .err,
20-
};
18+
pub const std_options = .{ .log_level = .err };
2119

22-
pub fn root_handler(_: *const Context, _: void) !Respond {
23-
return Respond{ .standard = .{
20+
pub fn root_handler(ctx: *const Context, _: void) !Respond {
21+
return ctx.response.apply(.{
2422
.status = .OK,
2523
.mime = http.Mime.HTML,
2624
.body = "This is an HTTP benchmark",
27-
} };
25+
});
2826
}
2927

3028
pub fn main() !void {

src/http/middlewares/compression.zig

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,25 @@ pub fn Compression(comptime compression: Kind) Layer {
1818
const func: TypedMiddlewareFn(void) = switch (compression) {
1919
.gzip => |inner| struct {
2020
fn gzip_mw(next: *Next, _: void) !Respond {
21-
var response = try next.run();
22-
switch (response) {
23-
.standard => |*respond| {
24-
var compressed = std.ArrayList(u8).init(next.context.allocator);
21+
const respond = try next.run();
22+
const response = next.context.response;
23+
if (response.body) |body| if (respond == .standard) {
24+
var compressed = try std.ArrayListUnmanaged(u8).initCapacity(next.context.allocator, body.len);
25+
errdefer compressed.deinit(next.context.allocator);
2526

26-
var body_stream = std.io.fixedBufferStream(respond.body);
27-
try std.compress.gzip.compress(body_stream.reader(), compressed.writer(), inner);
27+
var body_stream = std.io.fixedBufferStream(body);
28+
try std.compress.gzip.compress(
29+
body_stream.reader(),
30+
compressed.writer(next.context.allocator),
31+
inner,
32+
);
2833

29-
// TODO: consider having the headers be a part of the provision?
30-
// might be nice to reuse them as things go on??
31-
var header_list = std.ArrayList([2][]const u8).init(next.context.allocator);
32-
try header_list.appendSlice(respond.headers);
33-
try header_list.append(.{ "Content-Encoding", "gzip" });
34+
try response.headers.put("Content-Encoding", "gzip");
35+
response.body = try compressed.toOwnedSlice(next.context.allocator);
36+
return .standard;
37+
};
3438

35-
respond.body = try compressed.toOwnedSlice();
36-
respond.headers = try header_list.toOwnedSlice();
37-
return .{ .standard = respond.* };
38-
},
39-
else => return response,
40-
}
39+
return respond;
4140
}
4241
}.gzip_mw,
4342
};

src/http/middlewares/rate_limit.zig

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const std = @import("std");
22

33
const Mime = @import("../mime.zig").Mime;
44
const Respond = @import("../response.zig").Respond;
5+
const Response = @import("../response.zig").Response;
56
const Middleware = @import("../router/middleware.zig").Middleware;
67
const Next = @import("../router/middleware.zig").Next;
78
const Layer = @import("../router/middleware.zig").Layer;
@@ -43,7 +44,7 @@ pub const RateLimitConfig = struct {
4344
map: std.AutoHashMap(u128, Bucket),
4445
tokens_per_sec: u16,
4546
max_tokens: u16,
46-
response_on_limited: Respond,
47+
response_on_limited: Response.Fields,
4748
mutex: std.Thread.Mutex = .{},
4849

4950
pub fn init(
@@ -53,12 +54,10 @@ pub const RateLimitConfig = struct {
5354
response_on_limited: ?Respond,
5455
) RateLimitConfig {
5556
const map = std.AutoHashMap(u128, Bucket).init(allocator);
56-
const respond = response_on_limited orelse Respond{
57-
.standard = .{
58-
.status = .@"Too Many Requests",
59-
.mime = Mime.TEXT,
60-
.body = "",
61-
},
57+
const respond = response_on_limited orelse Response.Fields{
58+
.status = .@"Too Many Requests",
59+
.mime = Mime.TEXT,
60+
.body = "",
6261
};
6362

6463
return .{

src/http/response.zig

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,9 @@ const Date = @import("lib.zig").Date;
88

99
const Stream = @import("tardy").Stream;
1010

11-
pub const Respond = union(enum) {
12-
pub const Fields = struct {
13-
status: Status = .OK,
14-
mime: Mime = Mime.TEXT,
15-
body: []const u8 = "",
16-
headers: []const [2][]const u8 = &.{},
17-
};
18-
11+
pub const Respond = enum {
1912
// When we are returning a real HTTP request, we use this.
20-
standard: Fields,
13+
standard,
2114
// If we responded and we want to give control back to the HTTP engine.
2215
responded,
2316
// If we want the connection to close.
@@ -30,6 +23,13 @@ pub const Response = struct {
3023
body: ?[]const u8 = null,
3124
headers: AnyCaseStringMap,
3225

26+
pub const Fields = struct {
27+
status: Status,
28+
mime: Mime,
29+
body: []const u8 = "",
30+
headers: []const [2][]const u8 = &.{},
31+
};
32+
3333
pub fn init(allocator: std.mem.Allocator) Response {
3434
const headers = AnyCaseStringMap.init(allocator);
3535
return Response{ .headers = headers };
@@ -39,13 +39,12 @@ pub const Response = struct {
3939
self.headers.deinit();
4040
}
4141

42-
pub fn apply(self: *Response, into: Respond.Fields) !void {
42+
pub fn apply(self: *Response, into: Fields) !Respond {
4343
self.status = into.status;
4444
self.mime = into.mime;
4545
self.body = into.body;
46-
47-
self.headers.clearRetainingCapacity();
4846
for (into.headers) |pair| try self.headers.put(pair[0], pair[1]);
47+
return .standard;
4948
}
5049

5150
pub fn clear(self: *Response) void {

0 commit comments

Comments
 (0)