Changes
1 changed files (+69/-74)
-
-
@@ -44,8 +44,6 @@/// Service name described in metadata line. service: []const u8, context: HeaderParsingContext, const signature = "MOO/"; pub const ParseError = error{
-
@@ -56,7 +54,7 @@ InvalidService,NonUtf8ServiceName, }; pub fn parse(message: []const u8) ParseError!@This() { pub fn parse(message: []const u8) ParseError!struct { @This(), HeaderParsingContext } { var i: usize = 0; if (!std.mem.startsWith(u8, message, signature)) {
-
@@ -110,11 +108,13 @@ if (!std.unicode.utf8ValidateSlice(service)) {return ParseError.NonUtf8ServiceName; } return @This(){ .version = version, .verb = verb, .service = service, .context = HeaderParsingContext{ return .{ @This(){ .version = version, .verb = verb, .service = service, }, HeaderParsingContext{ .start_position = line_delimiter_position + 1, }, };
-
@@ -123,14 +123,14 @@ };test Metadata { { const metadata = try Metadata.parse("MOO/1 REQUEST foo/bar\n"); const metadata, _ = try Metadata.parse("MOO/1 REQUEST foo/bar\n"); try std.testing.expectEqual(1, metadata.version); try std.testing.expectEqualStrings("REQUEST", metadata.verb); try std.testing.expectEqualStrings("foo/bar", metadata.service); } { const metadata = try Metadata.parse("MOO/20 COMPLETE foo\n"); const metadata, _ = try Metadata.parse("MOO/20 COMPLETE foo\n"); try std.testing.expectEqual(20, metadata.version); try std.testing.expectEqualStrings("COMPLETE", metadata.verb); try std.testing.expectEqualStrings("foo", metadata.service);
-
@@ -487,8 +487,6 @@/// An ID unique to a connection, to associate corresponding request and response. request_id: i64, body_start_position: usize, pub const ParseError = error{ EmptyContentType, NonUintContentLength,
-
@@ -498,7 +496,7 @@ MissingContentLength,MissingRequestID, } || HeaderIterator.IterateError; pub fn parse(message: []const u8, context: HeaderParsingContext) ParseError!@This() { pub fn parse(message: []const u8, context: HeaderParsingContext) ParseError!struct { @This(), BodyParsingContext } { var iter = HeaderIterator{ .buffer = message[context.start_position..] }; var content_type: ?[]const u8 = null;
-
@@ -533,62 +531,59 @@ continue;} } return WellKnownHeaders{ .content_type = content_type orelse return ParseError.MissingContentType, .content_length = content_length orelse return ParseError.MissingContentLength, .request_id = request_id orelse return ParseError.MissingRequestID, // `i` does not include a final newline. .body_start_position = i + 1, }; } pub fn getContext(self: *const @This()) BodyParsingContext { return .{ .start_position = self.body_start_position, .content_type = self.content_type, .content_length = self.content_length, WellKnownHeaders{ .content_type = content_type orelse return ParseError.MissingContentType, .content_length = content_length orelse return ParseError.MissingContentLength, .request_id = request_id orelse return ParseError.MissingRequestID, }, BodyParsingContext{ // `i` does not include a final newline. .start_position = i + 1, .content_type = content_type.?, .content_length = content_length.?, }, }; } }; test "WellKnownHeaders.parse should parse well-known headers" { const message = "MOO/1 REQUEST foo\nContent-Type: application/json; charset=utf-8\nContent-Length: 876\nRequest-Id: 1\n\n"; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); _, const meta_ctx = try Metadata.parse(message); const header, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); try std.testing.expectEqualStrings("application/json; charset=utf-8", header.content_type); try std.testing.expectEqual(876, header.content_length); try std.testing.expectEqual(1, header.request_id); const ctx = header.getContext(); try std.testing.expectEqual(message.len, ctx.start_position); try std.testing.expectEqual(message.len, header_ctx.start_position); } test "WellKnownHeaders.parse should return error when required header is missing" { { const message = "MOO/1 REQUEST foo\nContent-Length: 876\nRequest-Id: 1\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.MissingContentType, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } { const message = "MOO/1 REQUEST foo\nContent-Type: application/json; charset=utf-8\nRequest-Id: 1\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.MissingContentLength, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } { const message = "MOO/1 REQUEST foo\nContent-Type: application/json; charset=utf-8\nContent-Length: 876\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.MissingRequestID, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } }
-
@@ -596,37 +591,37 @@test "WellKnownHeaders.parse should return error on an unexpected format" { { const message = "MOO/1 REQUEST foo\nContent-Type:\nContent-Length: 1\nRequest-Id: 1\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.EmptyContentType, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } { const message = "MOO/1 REQUEST foo\nContent-Type: text/plain\nContent-Length: 0x87\nRequest-Id: 1\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.NonUintContentLength, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } { const message = "MOO/1 REQUEST foo\nContent-Type: text/plain\nContent-Length: one\nRequest-Id: 1\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.NonUintContentLength, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } { const message = "MOO/1 REQUEST foo\nContent-Type: text/plain\nContent-Length: 1\nRequest-Id: 0D8C-F91C-22BB\n"; const meta = try Metadata.parse(message); _, const meta_ctx = try Metadata.parse(message); try std.testing.expectError( WellKnownHeaders.ParseError.NonIntRequestID, WellKnownHeaders.parse(message, meta.context), WellKnownHeaders.parse(message, meta_ctx), ); } }
-
@@ -638,8 +633,6 @@ /// Both key and value points to the source message bytes. Accessing those after/// free-ing the source message bytes is use-after-free. map: std.hash_map.StringHashMap([]const u8), context: BodyParsingContext, pub const ParseError = error{ MissingContentType, MissingContentLength,
-
@@ -647,7 +640,7 @@ EmptyContentType,NonUintContentLength, } || HeaderIterator.IterateError || std.mem.Allocator.Error; pub fn parse(allocator: std.mem.Allocator, message: []const u8, context: HeaderParsingContext) ParseError!@This() { pub fn parse(allocator: std.mem.Allocator, message: []const u8, context: HeaderParsingContext) ParseError!struct { @This(), BodyParsingContext } { var map = std.hash_map.StringHashMap([]const u8).init(allocator); var iter = HeaderIterator{ .buffer = message[context.start_position..] }; var i = context.start_position;
-
@@ -673,9 +666,11 @@try map.put(key, val); } return HashMapHeaders{ .map = map, .context = .{ return .{ HashMapHeaders{ .map = map, }, BodyParsingContext{ .content_type = content_type orelse return ParseError.MissingContentType, .content_length = content_length orelse return ParseError.MissingContentLength, // `i` does not include a final newline.
-
@@ -691,15 +686,15 @@ };test "HashMapHeaders.parse should save every headers" { const message = "MOO/1 REQUEST foo\nContent-Type: application/json; charset=utf-8\nContent-Length: 876\nRequest-Id: 1\nFoo: Bar\n\n"; const meta = try Metadata.parse(message); var header = try HashMapHeaders.parse(std.testing.allocator, message, meta.context); _, const meta_ctx = try Metadata.parse(message); var header, const header_ctx = try HashMapHeaders.parse(std.testing.allocator, message, meta_ctx); defer header.deinit(); try std.testing.expectEqualStrings(header.map.get("Content-Type").?, "application/json; charset=utf-8"); try std.testing.expectEqualStrings(header.map.get("Content-Length").?, "876"); try std.testing.expectEqualStrings(header.map.get("Request-Id").?, "1"); try std.testing.expectEqualStrings(header.map.get("Foo").?, "Bar"); try std.testing.expectEqual(message.len, header.context.start_position); try std.testing.expectEqual(message.len, header_ctx.start_position); } /// RawBody contains a bytes slice of body section in a MOO message.
-
@@ -726,9 +721,9 @@ };test "RawBody.parse should save rest of the bytes" { const message = "MOO/1 REQUEST foo\nContent-Type: text/plain\nContent-Length: 13\nRequest-Id: 1\n\nHello, World!"; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const body = try RawBody.parse(message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const body = try RawBody.parse(message, header_ctx); try std.testing.expectEqualStrings("Hello, World!", body.bytes); }
-
@@ -736,18 +731,18 @@test "RawBody.parse should reject mismatching Content-Length" { { const message = "MOO/1 REQUEST foo\nContent-Type: text/plain\nContent-Length: 12\nRequest-Id: 1\n\nHello, World!"; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const err = RawBody.parse(message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const err = RawBody.parse(message, header_ctx); try std.testing.expectError(RawBody.ParseError.ContentLengthMismatch, err); } { const message = "MOO/1 REQUEST foo\nContent-Type: text/plain\nContent-Length: 14\nRequest-Id: 1\n\nHello, World!"; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const err = RawBody.parse(message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const err = RawBody.parse(message, header_ctx); try std.testing.expectError(RawBody.ParseError.ContentLengthMismatch, err); }
-
@@ -815,9 +810,9 @@ const TestData = struct {foo: i32, }; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const body = try JsonBody(TestData).parse(std.testing.allocator, message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const body = try JsonBody(TestData).parse(std.testing.allocator, message, header_ctx); defer body.deinit(); try std.testing.expectEqual(body.value.foo, 8);
-
@@ -842,9 +837,9 @@ const TestData = struct {foo: i32, }; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const err = JsonBody(TestData).parse(std.testing.allocator, message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const err = JsonBody(TestData).parse(std.testing.allocator, message, header_ctx); try std.testing.expectError(JsonBody(TestData).ParseError.SyntaxError, err); }
-
@@ -868,9 +863,9 @@ const TestData = struct {foo: i32, }; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const err = JsonBody(TestData).parse(std.testing.allocator, message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const err = JsonBody(TestData).parse(std.testing.allocator, message, header_ctx); try std.testing.expectError(JsonBody(TestData).ParseError.ContentLengthMismatch, err); }
-
@@ -894,9 +889,9 @@ const TestData = struct {foo: i32, }; const meta = try Metadata.parse(message); const header = try WellKnownHeaders.parse(message, meta.context); const err = JsonBody(TestData).parse(std.testing.allocator, message, header.getContext()); _, const meta_ctx = try Metadata.parse(message); _, const header_ctx = try WellKnownHeaders.parse(message, meta_ctx); const err = JsonBody(TestData).parse(std.testing.allocator, message, header_ctx); try std.testing.expectError(JsonBody(TestData).ParseError.ContentTypeIsNotApplicationJson, err); }
-