const SendHttpResponseError = os.SendError || HttpHeadersIterator.NextError || error{
Overflow,
NoStartLine,
BadStartLine,
};
fn sendHttpResponse(
comptime BUFFER_SIZE: usize,
sockfd: os.socket_t,
request: []const u8,
) SendHttpResponseError!void {
const start_line = request[0 .. std.mem.indexOf(u8, request, "\r\n") orelse request.len];
if (request.len == 0) return SendHttpResponseError.NoStartLine;
// TODO don't assume start line is OK!
// Make the writer object.
var send_writer = OsSendWriter{ .sockfd = sockfd };
var buf_send_writer = std.io.BufferedWriter(
BUFFER_SIZE,
OsSendWriter.Writer,
){ .unbuffered_writer = send_writer.writer() };
var writer = buf_send_writer.writer();
var json_writer = std.json.writeStream(writer, 3);
_ = try writer.write("HTTP/1.1 200 OK\r\n\r\n");
var headers_iter = HttpHeadersIterator.init(request[start_line.len + 2 ..]);
// Build the JSON blob.
try json_writer.beginObject();
while (try headers_iter.next()) |header| {
try json_writer.objectField(header[0]);
try json_writer.emitString(header[1]);
}
try json_writer.endObject();
// Flush the buffer.
try buf_send_writer.flush();
}
const OsSendWriter = struct {
sockfd: os.socket_t,
const Self = @This();
const WriteError = os.SendError;
pub fn write(self: *Self, str: []const u8) WriteError!usize {
return os.send(self.sockfd, str, 0);
}
pub const Writer = std.io.Writer(*Self, WriteError, write);
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
};
const HttpHeadersIterator = struct {
lines_iter: std.mem.SplitIterator(u8),
const Self = @This();
pub fn init(request: []const u8) Self {
return .{ .lines_iter = .{ .buffer = request, .delimiter = "\r\n", .index = 0 } };
}
const NextError = error{NoDivider};
pub fn next(self: *Self) !?struct { []const u8, []const u8 } {
const DIVIDER: []const u8 = ": ";
const line = self.lines_iter.next() orelse return null;
if (line.len == 0) return null;
const div_pos = std.mem.indexOf(u8, line, DIVIDER) orelse return NextError.NoDivider;
const result = .{
line[0..div_pos],
line[div_pos + DIVIDER.len ..],
};
return result;
}
};