lib/http/src/writer.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const Connection = @import("connection.zig").Connection;
 3 
 4 pub const ChunkedWriter = struct {
 5     conn: *Connection,
 6     allocator: std.mem.Allocator,
 7     headers_sent: bool,
 8 
 9     pub fn init(conn: *Connection, allocator: std.mem.Allocator) ChunkedWriter {
10         return .{
11             .conn = conn,
12             .allocator = allocator,
13             .headers_sent = false,
14         };
15     }
16 
17     pub fn writeHeader(
18         self: *ChunkedWriter,
19         status: u16,
20         status_text: []const u8,
21         headers: []const struct { name: []const u8, value: []const u8 },
22     ) !void {
23         if (self.headers_sent) return;
24 
25         var buf: std.ArrayListUnmanaged(u8) = .empty;
26         defer buf.deinit(self.allocator);
27 
28         try buf.writer(self.allocator).print("HTTP/1.1 {d} {s}\r\n", .{ status, status_text });
29 
30         for (headers) |header| {
31             try buf.writer(self.allocator).print("{s}: {s}\r\n", .{ header.name, header.value });
32         }
33 
34         try buf.appendSlice(self.allocator, "Transfer-Encoding: chunked\r\n");
35         try buf.appendSlice(self.allocator, "\r\n");
36 
37         try self.conn.write(buf.items);
38         self.headers_sent = true;
39     }
40 
41     pub fn chunk(self: *ChunkedWriter, data: []const u8) !void {
42         if (data.len == 0) return;
43 
44         var header_buf: [32]u8 = undefined;
45         const header = std.fmt.bufPrint(&header_buf, "{x}\r\n", .{data.len}) catch unreachable;
46 
47         try self.conn.write(header);
48         try self.conn.write(data);
49         try self.conn.write("\r\n");
50     }
51 
52     pub fn finish(self: *ChunkedWriter) !void {
53         try self.conn.write("0\r\n\r\n");
54     }
55 };
56 
57 test "ChunkedWriter chunk format" {
58     var buf: [32]u8 = undefined;
59     const header = std.fmt.bufPrint(&buf, "{x}\r\n", .{@as(usize, 256)}) catch unreachable;
60     try std.testing.expectEqualStrings("100\r\n", header);
61 
62     const header2 = std.fmt.bufPrint(&buf, "{x}\r\n", .{@as(usize, 5)}) catch unreachable;
63     try std.testing.expectEqualStrings("5\r\n", header2);
64 }