zls/src/Header.zig

60 lines
2.0 KiB
Zig
Raw Normal View History

2020-05-17 15:50:13 +01:00
const std = @import("std");
const Header = @This();
2020-05-17 15:50:13 +01:00
content_length: usize,
2020-05-17 15:50:13 +01:00
/// null implies "application/vscode-jsonrpc; charset=utf-8"
content_type: ?[]const u8 = null,
pub fn deinit(self: @This(), allocator: std.mem.Allocator) void {
if (self.content_type) |ct| allocator.free(ct);
}
2020-05-17 15:50:13 +01:00
// Caller owns returned memory.
pub fn parse(allocator: std.mem.Allocator, reader: anytype) !Header {
var r = Header{
2020-05-17 15:50:13 +01:00
.content_length = undefined,
.content_type = null,
};
errdefer r.deinit(allocator);
var has_content_length = false;
while (true) {
const header = try reader.readUntilDelimiterAlloc(allocator, '\n', 0x100);
2020-05-17 15:50:13 +01:00
defer allocator.free(header);
if (header.len == 0 or header[header.len - 1] != '\r') return error.MissingCarriageReturn;
if (header.len == 1) break;
2021-10-01 02:47:19 +01:00
const header_name = header[0 .. std.mem.indexOf(u8, header, ": ") orelse return error.MissingColon];
2020-07-12 20:12:09 +01:00
const header_value = header[header_name.len + 2 .. header.len - 1];
2021-10-01 02:47:19 +01:00
if (std.mem.eql(u8, header_name, "Content-Length")) {
2020-05-17 15:50:13 +01:00
if (header_value.len == 0) return error.MissingHeaderValue;
r.content_length = std.fmt.parseInt(usize, header_value, 10) catch return error.InvalidContentLength;
has_content_length = true;
2021-10-01 02:47:19 +01:00
} else if (std.mem.eql(u8, header_name, "Content-Type")) {
r.content_type = try allocator.dupe(u8, header_value);
2020-05-17 15:50:13 +01:00
} else {
return error.UnknownHeader;
}
}
if (!has_content_length) return error.MissingContentLength;
return r;
}
pub fn format(
header: Header,
comptime unused_fmt_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
_ = options;
std.debug.assert(unused_fmt_string.len == 0);
try writer.print("Content-Length: {}\r\n", .{header.content_length});
if (header.content_type) |content_type| {
try writer.print("Content-Type: {s}\r\n", .{content_type});
}
try writer.writeAll("\r\n");
}