2020-05-17 15:50:13 +01:00
|
|
|
const std = @import("std");
|
|
|
|
const mem = std.mem;
|
|
|
|
|
|
|
|
const RequestHeader = struct {
|
|
|
|
content_length: usize,
|
|
|
|
|
|
|
|
/// null implies "application/vscode-jsonrpc; charset=utf-8"
|
|
|
|
content_type: ?[]const u8,
|
|
|
|
|
|
|
|
pub fn deinit(self: @This(), allocator: *mem.Allocator) void {
|
|
|
|
if (self.content_type) |ct| allocator.free(ct);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-12 20:12:09 +01:00
|
|
|
pub fn readRequestHeader(allocator: *mem.Allocator, instream: anytype) !RequestHeader {
|
2020-05-17 15:50:13 +01:00
|
|
|
var r = RequestHeader{
|
|
|
|
.content_length = undefined,
|
|
|
|
.content_type = null,
|
|
|
|
};
|
|
|
|
errdefer r.deinit(allocator);
|
|
|
|
|
|
|
|
var has_content_length = false;
|
|
|
|
while (true) {
|
|
|
|
const header = try instream.readUntilDelimiterAlloc(allocator, '\n', 0x100);
|
|
|
|
defer allocator.free(header);
|
|
|
|
if (header.len == 0 or header[header.len - 1] != '\r') return error.MissingCarriageReturn;
|
|
|
|
if (header.len == 1) break;
|
|
|
|
|
2020-07-12 20:12:09 +01:00
|
|
|
const header_name = header[0 .. mem.indexOf(u8, header, ": ") orelse return error.MissingColon];
|
|
|
|
const header_value = header[header_name.len + 2 .. header.len - 1];
|
2020-05-17 15:50:13 +01:00
|
|
|
if (mem.eql(u8, header_name, "Content-Length")) {
|
|
|
|
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;
|
|
|
|
} else if (mem.eql(u8, header_name, "Content-Type")) {
|
|
|
|
r.content_type = try mem.dupe(allocator, u8, header_value);
|
|
|
|
} else {
|
|
|
|
return error.UnknownHeader;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_content_length) return error.MissingContentLength;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|