fix most test compilation errors

This commit is contained in:
Emil Lerch 2025-08-23 08:48:32 -07:00
parent 8d399cb8a6
commit 1170ba99fc
Signed by: lobo
GPG key ID: A7B62D657EF764F8
3 changed files with 142 additions and 129 deletions

View file

@ -1412,14 +1412,14 @@ fn typeForField(comptime T: type, comptime field_name: []const u8) !type {
test "custom serialization for map objects" { test "custom serialization for map objects" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var buffer = std.ArrayList(u8).init(allocator); var buffer = std.Io.Writer.Allocating.init(allocator);
defer buffer.deinit(); defer buffer.deinit();
var tags = try std.ArrayList(@typeInfo(try typeForField(services.lambda.tag_resource.Request, "tags")).pointer.child).initCapacity(allocator, 2); var tags = try std.ArrayList(@typeInfo(try typeForField(services.lambda.tag_resource.Request, "tags")).pointer.child).initCapacity(allocator, 2);
defer tags.deinit(); defer tags.deinit(allocator);
tags.appendAssumeCapacity(.{ .key = "Foo", .value = "Bar" }); tags.appendAssumeCapacity(.{ .key = "Foo", .value = "Bar" });
tags.appendAssumeCapacity(.{ .key = "Baz", .value = "Qux" }); tags.appendAssumeCapacity(.{ .key = "Baz", .value = "Qux" });
const req = services.lambda.TagResourceRequest{ .resource = "hello", .tags = tags.items }; const req = services.lambda.TagResourceRequest{ .resource = "hello", .tags = tags.items };
try std.json.stringify(req, .{ .whitespace = .indent_4 }, buffer.writer()); try buffer.writer.print("{f}", .{std.json.fmt(req, .{ .whitespace = .indent_4 })});
const parsed_body = try std.json.parseFromSlice(struct { const parsed_body = try std.json.parseFromSlice(struct {
Resource: []const u8, Resource: []const u8,
@ -1427,7 +1427,7 @@ test "custom serialization for map objects" {
Foo: []const u8, Foo: []const u8,
Baz: []const u8, Baz: []const u8,
}, },
}, testing.allocator, buffer.items, .{}); }, testing.allocator, buffer.written(), .{});
defer parsed_body.deinit(); defer parsed_body.deinit();
try testing.expectEqualStrings("hello", parsed_body.value.Resource); try testing.expectEqualStrings("hello", parsed_body.value.Resource);
@ -1439,7 +1439,7 @@ test "proper serialization for kms" {
// Github issue #8 // Github issue #8
// https://github.com/elerch/aws-sdk-for-zig/issues/8 // https://github.com/elerch/aws-sdk-for-zig/issues/8
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var buffer = std.ArrayList(u8).init(allocator); var buffer = std.Io.Writer.Allocating.init(allocator);
defer buffer.deinit(); defer buffer.deinit();
const req = services.kms.encrypt.Request{ const req = services.kms.encrypt.Request{
.encryption_algorithm = "SYMMETRIC_DEFAULT", .encryption_algorithm = "SYMMETRIC_DEFAULT",
@ -1451,7 +1451,7 @@ test "proper serialization for kms" {
.dry_run = false, .dry_run = false,
.grant_tokens = &[_][]const u8{}, .grant_tokens = &[_][]const u8{},
}; };
try std.json.stringify(req, .{ .whitespace = .indent_4 }, buffer.writer()); try buffer.writer.print("{f}", .{std.json.fmt(req, .{ .whitespace = .indent_4 })});
{ {
const parsed_body = try std.json.parseFromSlice(struct { const parsed_body = try std.json.parseFromSlice(struct {
@ -1461,7 +1461,7 @@ test "proper serialization for kms" {
GrantTokens: [][]const u8, GrantTokens: [][]const u8,
EncryptionAlgorithm: []const u8, EncryptionAlgorithm: []const u8,
DryRun: bool, DryRun: bool,
}, testing.allocator, buffer.items, .{}); }, testing.allocator, buffer.written(), .{});
defer parsed_body.deinit(); defer parsed_body.deinit();
try testing.expectEqualStrings("42", parsed_body.value.KeyId); try testing.expectEqualStrings("42", parsed_body.value.KeyId);
@ -1471,7 +1471,7 @@ test "proper serialization for kms" {
try testing.expectEqual(false, parsed_body.value.DryRun); try testing.expectEqual(false, parsed_body.value.DryRun);
} }
var buffer_null = std.ArrayList(u8).init(allocator); var buffer_null = std.Io.Writer.Allocating.init(allocator);
defer buffer_null.deinit(); defer buffer_null.deinit();
const req_null = services.kms.encrypt.Request{ const req_null = services.kms.encrypt.Request{
.encryption_algorithm = "SYMMETRIC_DEFAULT", .encryption_algorithm = "SYMMETRIC_DEFAULT",
@ -1483,7 +1483,7 @@ test "proper serialization for kms" {
.grant_tokens = &[_][]const u8{}, .grant_tokens = &[_][]const u8{},
}; };
try std.json.stringify(req_null, .{ .whitespace = .indent_4 }, buffer_null.writer()); try buffer_null.writer.print("{f}", .{std.json.fmt(req_null, .{ .whitespace = .indent_4 })});
{ {
const parsed_body = try std.json.parseFromSlice(struct { const parsed_body = try std.json.parseFromSlice(struct {
@ -1493,7 +1493,7 @@ test "proper serialization for kms" {
GrantTokens: [][]const u8, GrantTokens: [][]const u8,
EncryptionAlgorithm: []const u8, EncryptionAlgorithm: []const u8,
DryRun: bool, DryRun: bool,
}, testing.allocator, buffer_null.items, .{}); }, testing.allocator, buffer_null.written(), .{});
defer parsed_body.deinit(); defer parsed_body.deinit();
try testing.expectEqualStrings("42", parsed_body.value.KeyId); try testing.expectEqualStrings("42", parsed_body.value.KeyId);
@ -1541,8 +1541,8 @@ test "REST Json v1 serializes lists in queries" {
} }
test "REST Json v1 buildpath substitutes" { test "REST Json v1 buildpath substitutes" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var al = std.ArrayList([]const u8).init(allocator); var al = std.ArrayList([]const u8){};
defer al.deinit(); defer al.deinit(allocator);
const svs = Services(.{.lambda}){}; const svs = Services(.{.lambda}){};
const request = svs.lambda.list_functions.Request{ const request = svs.lambda.list_functions.Request{
.max_items = 1, .max_items = 1,
@ -1554,8 +1554,8 @@ test "REST Json v1 buildpath substitutes" {
} }
test "REST Json v1 buildpath handles restricted characters" { test "REST Json v1 buildpath handles restricted characters" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var al = std.ArrayList([]const u8).init(allocator); var al = std.ArrayList([]const u8){};
defer al.deinit(); defer al.deinit(allocator);
const svs = Services(.{.lambda}){}; const svs = Services(.{.lambda}){};
const request = svs.lambda.list_functions.Request{ const request = svs.lambda.list_functions.Request{
.marker = ":", .marker = ":",
@ -1571,7 +1571,7 @@ test "basic json request serialization" {
const request = svs.dynamo_db.list_tables.Request{ const request = svs.dynamo_db.list_tables.Request{
.limit = 1, .limit = 1,
}; };
var buffer = std.ArrayList(u8).init(allocator); var buffer = std.Io.Writer.Allocating.init(allocator);
defer buffer.deinit(); defer buffer.deinit();
// The transformer needs to allocate stuff out of band, but we // The transformer needs to allocate stuff out of band, but we
@ -1583,13 +1583,13 @@ test "basic json request serialization" {
// for a boxed member with no observable difference." But we're // for a boxed member with no observable difference." But we're
// seeing a lot of differences here between spec and reality // seeing a lot of differences here between spec and reality
// //
try std.json.stringify(request, .{ .whitespace = .indent_4 }, buffer.writer()); try buffer.writer.print("{f}", .{std.json.fmt(request, .{ .whitespace = .indent_4 })});
try std.testing.expectEqualStrings( try std.testing.expectEqualStrings(
\\{ \\{
\\ "ExclusiveStartTableName": null, \\ "ExclusiveStartTableName": null,
\\ "Limit": 1 \\ "Limit": 1
\\} \\}
, buffer.items); , buffer.written());
} }
test "layer object only" { test "layer object only" {
const TestResponse = struct { const TestResponse = struct {
@ -2291,7 +2291,7 @@ test "rest_json_1_work_with_lambda: lambda tagResource (only), to excercise zig
const options = try test_harness.start(); const options = try test_harness.start();
const lambda = (Services(.{.lambda}){}).lambda; const lambda = (Services(.{.lambda}){}).lambda;
var tags = try std.ArrayList(@typeInfo(try typeForField(lambda.tag_resource.Request, "tags")).pointer.child).initCapacity(allocator, 1); var tags = try std.ArrayList(@typeInfo(try typeForField(lambda.tag_resource.Request, "tags")).pointer.child).initCapacity(allocator, 1);
defer tags.deinit(); defer tags.deinit(allocator);
tags.appendAssumeCapacity(.{ .key = "Foo", .value = "Bar" }); tags.appendAssumeCapacity(.{ .key = "Foo", .value = "Bar" });
const req = services.lambda.tag_resource.Request{ .resource = "arn:aws:lambda:us-west-2:550620852718:function:awsome-lambda-LambdaStackawsomeLambda", .tags = tags.items }; const req = services.lambda.tag_resource.Request{ .resource = "arn:aws:lambda:us-west-2:550620852718:function:awsome-lambda-LambdaStackawsomeLambda", .tags = tags.items };
const call = try Request(lambda.tag_resource).call(req, options); const call = try Request(lambda.tag_resource).call(req, options);
@ -2674,7 +2674,7 @@ test "jsonStringify: structure + enums" {
var arena = std.heap.ArenaAllocator.init(testing.allocator); var arena = std.heap.ArenaAllocator.init(testing.allocator);
defer arena.deinit(); defer arena.deinit();
const request_json = try std.json.stringifyAlloc(std.testing.allocator, request, .{}); const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
defer std.testing.allocator.free(request_json); defer std.testing.allocator.free(request_json);
const parsed = try std.json.parseFromSlice(struct { const parsed = try std.json.parseFromSlice(struct {
@ -2699,7 +2699,7 @@ test "jsonStringify: strings" {
var arena = std.heap.ArenaAllocator.init(testing.allocator); var arena = std.heap.ArenaAllocator.init(testing.allocator);
defer arena.deinit(); defer arena.deinit();
const request_json = try std.json.stringifyAlloc(std.testing.allocator, request, .{}); const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
defer std.testing.allocator.free(request_json); defer std.testing.allocator.free(request_json);
try testing.expectEqualStrings("{\"arn\":\"1234\"}", request_json); try testing.expectEqualStrings("{\"arn\":\"1234\"}", request_json);
@ -2721,7 +2721,7 @@ test "jsonStringify" {
var arena = std.heap.ArenaAllocator.init(testing.allocator); var arena = std.heap.ArenaAllocator.init(testing.allocator);
defer arena.deinit(); defer arena.deinit();
const request_json = try std.json.stringifyAlloc(std.testing.allocator, request, .{}); const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
defer std.testing.allocator.free(request_json); defer std.testing.allocator.free(request_json);
const json_parsed = try std.json.parseFromSlice(struct { const json_parsed = try std.json.parseFromSlice(struct {
@ -2748,7 +2748,7 @@ test "jsonStringify nullable object" {
}, },
}; };
const request_json = try std.json.stringifyAlloc(std.testing.allocator, request, .{}); const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
defer std.testing.allocator.free(request_json); defer std.testing.allocator.free(request_json);
const json_parsed = try std.json.parseFromSlice(struct { const json_parsed = try std.json.parseFromSlice(struct {
@ -2774,7 +2774,7 @@ test "jsonStringify nullable object" {
.ciphertext_blob = "bar", .ciphertext_blob = "bar",
}; };
const request_json = try std.json.stringifyAlloc(std.testing.allocator, request, .{}); const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
defer std.testing.allocator.free(request_json); defer std.testing.allocator.free(request_json);
const json_parsed = try std.json.parseFromSlice(struct { const json_parsed = try std.json.parseFromSlice(struct {

View file

@ -348,10 +348,10 @@ pub fn freeSignedRequest(allocator: std.mem.Allocator, request: *base.Request, c
pub const credentialsFn = *const fn ([]const u8) ?Credentials; pub const credentialsFn = *const fn ([]const u8) ?Credentials;
pub fn verifyServerRequest(allocator: std.mem.Allocator, request: *std.http.Server.Request, request_body_reader: anytype, credentials_fn: credentialsFn) !bool { pub fn verifyServerRequest(allocator: std.mem.Allocator, request: *std.http.Server.Request, credentials_fn: credentialsFn) !bool {
var unverified_request = try UnverifiedRequest.init(allocator, request); var unverified_request = try UnverifiedRequest.init(allocator, request);
defer unverified_request.deinit(); defer unverified_request.deinit();
return verify(allocator, unverified_request, request_body_reader, credentials_fn); return verify(allocator, unverified_request, credentials_fn);
} }
pub const UnverifiedRequest = struct { pub const UnverifiedRequest = struct {
@ -359,17 +359,19 @@ pub const UnverifiedRequest = struct {
target: []const u8, target: []const u8,
method: std.http.Method, method: std.http.Method,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
raw: *std.http.Server.Request,
pub fn init(allocator: std.mem.Allocator, request: *std.http.Server.Request) !UnverifiedRequest { pub fn init(allocator: std.mem.Allocator, request: *std.http.Server.Request) !UnverifiedRequest {
var al = std.ArrayList(std.http.Header).init(allocator); var al = std.ArrayList(std.http.Header){};
defer al.deinit(); defer al.deinit(allocator);
var it = request.iterateHeaders(); var it = request.iterateHeaders();
while (it.next()) |h| try al.append(h); while (it.next()) |h| try al.append(allocator, h);
return .{ return .{
.target = request.head.target, .target = request.head.target,
.method = request.head.method, .method = request.head.method,
.headers = try al.toOwnedSlice(), .headers = try al.toOwnedSlice(allocator),
.allocator = allocator, .allocator = allocator,
.raw = request,
}; };
} }
@ -387,7 +389,7 @@ pub const UnverifiedRequest = struct {
} }
}; };
pub fn verify(allocator: std.mem.Allocator, request: UnverifiedRequest, request_body_reader: anytype, credentials_fn: credentialsFn) !bool { pub fn verify(allocator: std.mem.Allocator, request: UnverifiedRequest, credentials_fn: credentialsFn) !bool {
var arena = std.heap.ArenaAllocator.init(allocator); var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit(); defer arena.deinit();
const aa = arena.allocator(); const aa = arena.allocator();
@ -420,7 +422,6 @@ pub fn verify(allocator: std.mem.Allocator, request: UnverifiedRequest, request_
return verifyParsedAuthorization( return verifyParsedAuthorization(
aa, aa,
request, request,
request_body_reader,
credential.?, credential.?,
signed_headers.?, signed_headers.?,
signature.?, signature.?,
@ -431,7 +432,6 @@ pub fn verify(allocator: std.mem.Allocator, request: UnverifiedRequest, request_
fn verifyParsedAuthorization( fn verifyParsedAuthorization(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
request: UnverifiedRequest, request: UnverifiedRequest,
request_body_reader: anytype,
credential: []const u8, credential: []const u8,
signed_headers: []const u8, signed_headers: []const u8,
signature: []const u8, signature: []const u8,
@ -494,7 +494,8 @@ fn verifyParsedAuthorization(
.content_type = request.getFirstHeaderValue("content-type").?, .content_type = request.getFirstHeaderValue("content-type").?,
}; };
signed_request.query = request.target[signed_request.path.len..]; // TODO: should this be +1? query here would include '?' signed_request.query = request.target[signed_request.path.len..]; // TODO: should this be +1? query here would include '?'
signed_request.body = try request_body_reader.readAllAlloc(allocator, std.math.maxInt(usize)); // TODO: This is almost certainly not what we want here long term, but will get tests working
signed_request.body = try request.raw.server.reader.in.allocRemaining(allocator, .unlimited);
defer allocator.free(signed_request.body); defer allocator.free(signed_request.body);
signed_request = try signRequest(allocator, signed_request, config); signed_request = try signRequest(allocator, signed_request, config);
defer freeSignedRequest(allocator, &signed_request, config); defer freeSignedRequest(allocator, &signed_request, config);
@ -1010,13 +1011,13 @@ test "canonical query" {
test "canonical headers" { test "canonical headers" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5); var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5);
defer headers.deinit(); defer headers.deinit(allocator);
try headers.append(.{ .name = "Host", .value = "iam.amazonaws.com" }); try headers.append(allocator, .{ .name = "Host", .value = "iam.amazonaws.com" });
try headers.append(.{ .name = "Content-Type", .value = "application/x-www-form-urlencoded; charset=utf-8" }); try headers.append(allocator, .{ .name = "Content-Type", .value = "application/x-www-form-urlencoded; charset=utf-8" });
try headers.append(.{ .name = "User-Agent", .value = "This header should be skipped" }); try headers.append(allocator, .{ .name = "User-Agent", .value = "This header should be skipped" });
try headers.append(.{ .name = "My-header1", .value = " a b c " }); try headers.append(allocator, .{ .name = "My-header1", .value = " a b c " });
try headers.append(.{ .name = "X-Amz-Date", .value = "20150830T123600Z" }); try headers.append(allocator, .{ .name = "X-Amz-Date", .value = "20150830T123600Z" });
try headers.append(.{ .name = "My-header2", .value = " \"a b c\" " }); try headers.append(allocator, .{ .name = "My-header2", .value = " \"a b c\" " });
const expected = const expected =
\\content-type:application/x-www-form-urlencoded; charset=utf-8 \\content-type:application/x-www-form-urlencoded; charset=utf-8
\\host:iam.amazonaws.com \\host:iam.amazonaws.com
@ -1035,12 +1036,12 @@ test "canonical headers" {
test "canonical request" { test "canonical request" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5); var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5);
defer headers.deinit(); defer headers.deinit(allocator);
try headers.append(.{ .name = "User-agent", .value = "c sdk v1.0" }); try headers.append(allocator, .{ .name = "User-agent", .value = "c sdk v1.0" });
// In contrast to AWS CRT (aws-c-auth), we add the date as part of the // In contrast to AWS CRT (aws-c-auth), we add the date as part of the
// signing operation. They add it as part of the canonicalization // signing operation. They add it as part of the canonicalization
try headers.append(.{ .name = "X-Amz-Date", .value = "20150830T123600Z" }); try headers.append(allocator, .{ .name = "X-Amz-Date", .value = "20150830T123600Z" });
try headers.append(.{ .name = "Host", .value = "example.amazonaws.com" }); try headers.append(allocator, .{ .name = "Host", .value = "example.amazonaws.com" });
const req = base.Request{ const req = base.Request{
.path = "/", .path = "/",
.method = "GET", .method = "GET",
@ -1095,10 +1096,10 @@ test "can sign" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5); var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5);
defer headers.deinit(); defer headers.deinit(allocator);
try headers.append(.{ .name = "Content-Type", .value = "application/x-www-form-urlencoded; charset=utf-8" }); try headers.append(allocator, .{ .name = "Content-Type", .value = "application/x-www-form-urlencoded; charset=utf-8" });
try headers.append(.{ .name = "Content-Length", .value = "13" }); try headers.append(allocator, .{ .name = "Content-Length", .value = "13" });
try headers.append(.{ .name = "Host", .value = "example.amazonaws.com" }); try headers.append(allocator, .{ .name = "Host", .value = "example.amazonaws.com" });
const req = base.Request{ const req = base.Request{
.path = "/", .path = "/",
.query = "", .query = "",
@ -1165,25 +1166,25 @@ test "can verify server request" {
"X-Amz-Date: 20230908T170252Z\r\n" ++ "X-Amz-Date: 20230908T170252Z\r\n" ++
"x-amz-content-sha256: fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9\r\n" ++ "x-amz-content-sha256: fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9\r\n" ++
"Authorization: AWS4-HMAC-SHA256 Credential=ACCESS/20230908/us-west-2/s3/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=fcc43ce73a34c9bd1ddf17e8a435f46a859812822f944f9eeb2aabcd64b03523\r\n\r\nbar"; "Authorization: AWS4-HMAC-SHA256 Credential=ACCESS/20230908/us-west-2/s3/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=fcc43ce73a34c9bd1ddf17e8a435f46a859812822f944f9eeb2aabcd64b03523\r\n\r\nbar";
var read_buffer: [1024]u8 = undefined; var reader = std.Io.Reader.fixed(req);
@memcpy(read_buffer[0..req.len], req);
var server: std.http.Server = .{ var server: std.http.Server = .{
.connection = undefined, .out = undefined, // We're not sending a response here
.state = .ready, .reader = .{
.read_buffer = &read_buffer, .in = &reader,
.read_buffer_len = req.len, .interface = undefined,
.next_request_start = 0, .state = .ready,
.max_head_len = req.len,
},
}; };
var request: std.http.Server.Request = .{ var request: std.http.Server.Request = .{
.server = &server, .server = &server,
.head_end = req.len - 3, .head = undefined,
.head = try std.http.Server.Request.Head.parse(read_buffer[0 .. req.len - 3]), .head_buffer = &.{},
.reader_state = undefined,
}; };
// I think we need a request.receiveHead() call here
// std.testing.log_level = .debug; // std.testing.log_level = .debug;
var fbs = std.io.fixedBufferStream("bar"); try std.testing.expect(try verifyServerRequest(allocator, &request, struct {
try std.testing.expect(try verifyServerRequest(allocator, &request, fbs.reader(), struct {
cred: Credentials, cred: Credentials,
const Self = @This(); const Self = @This();
@ -1221,22 +1222,24 @@ test "can verify server request without x-amz-content-sha256" {
const req_data = head ++ body; const req_data = head ++ body;
var read_buffer: [2048]u8 = undefined; var read_buffer: [2048]u8 = undefined;
@memcpy(read_buffer[0..req_data.len], req_data); @memcpy(read_buffer[0..req_data.len], req_data);
var reader = std.Io.Reader.fixed(&read_buffer);
var server: std.http.Server = .{ var server: std.http.Server = .{
.connection = undefined, .out = undefined, // We're not sending a response here
.state = .ready, .reader = .{
.read_buffer = &read_buffer, .interface = undefined,
.read_buffer_len = req_data.len, .in = &reader,
.next_request_start = 0, .state = .ready,
.max_head_len = 1024,
},
}; };
var request: std.http.Server.Request = .{ var request: std.http.Server.Request = .{
.server = &server, .server = &server,
.head_end = head.len, .head = undefined,
.head = try std.http.Server.Request.Head.parse(read_buffer[0..head.len]), .head_buffer = &.{},
.reader_state = undefined,
}; };
{ {
var h = std.ArrayList(std.http.Header).init(allocator); var h = try std.ArrayList(std.http.Header).initCapacity(allocator, 4);
defer h.deinit(); defer h.deinit(allocator);
const signed_headers = &[_][]const u8{ "content-type", "host", "x-amz-date", "x-amz-target" }; const signed_headers = &[_][]const u8{ "content-type", "host", "x-amz-date", "x-amz-target" };
var it = request.iterateHeaders(); var it = request.iterateHeaders();
while (it.next()) |source| { while (it.next()) |source| {
@ -1245,7 +1248,7 @@ test "can verify server request without x-amz-content-sha256" {
match = std.ascii.eqlIgnoreCase(s, source.name); match = std.ascii.eqlIgnoreCase(s, source.name);
if (match) break; if (match) break;
} }
if (match) try h.append(.{ .name = source.name, .value = source.value }); if (match) try h.append(allocator, .{ .name = source.name, .value = source.value });
} }
const req = base.Request{ const req = base.Request{
.path = "/", .path = "/",
@ -1282,9 +1285,7 @@ test "can verify server request without x-amz-content-sha256" {
} }
{ // verification { // verification
var fis = std.io.fixedBufferStream(body[0..]); try std.testing.expect(try verifyServerRequest(allocator, &request, struct {
try std.testing.expect(try verifyServerRequest(allocator, &request, fis.reader(), struct {
cred: Credentials, cred: Credentials,
const Self = @This(); const Self = @This();

View file

@ -103,60 +103,72 @@ pub fn encodeInternal(
return rc; return rc;
} }
fn testencode(allocator: std.mem.Allocator, expected: []const u8, value: anytype, comptime options: EncodingOptions) !void { const ValidationWriter = struct {
const ValidationWriter = struct { const Self = @This();
const Self = @This(); pub const Writer = std.io.Writer(*Self, Error, write);
pub const Writer = std.io.Writer(*Self, Error, write); pub const Error = error{
pub const Error = error{ TooMuchData,
TooMuchData, DifferentData,
DifferentData,
};
expected_remaining: []const u8,
fn init(exp: []const u8) Self {
return .{ .expected_remaining = exp };
}
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
fn write(self: *Self, bytes: []const u8) Error!usize {
// std.debug.print("{s}\n", .{bytes});
if (self.expected_remaining.len < bytes.len) {
std.log.warn(
\\====== expected this output: =========
\\{s}
\\======== instead found this: =========
\\{s}
\\======================================
, .{
self.expected_remaining,
bytes,
});
return error.TooMuchData;
}
if (!std.mem.eql(u8, self.expected_remaining[0..bytes.len], bytes)) {
std.log.warn(
\\====== expected this output: =========
\\{s}
\\======== instead found this: =========
\\{s}
\\======================================
, .{
self.expected_remaining[0..bytes.len],
bytes,
});
return error.DifferentData;
}
self.expected_remaining = self.expected_remaining[bytes.len..];
return bytes.len;
}
}; };
expected_remaining: []const u8,
writer: std.Io.Writer,
fn init(exp: []const u8) Self {
return .{
.expected_remaining = exp,
.writer = .{
.buffer = &.{},
.vtable = &.{
.drain = drain,
},
},
};
}
fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
if (splat > 0) @panic("No splat");
const self: *ValidationWriter = @fieldParentPtr("writer", w);
var bytes: usize = 0;
for (data) |d| bytes += try self.write(d);
return bytes;
}
fn write(self: *Self, bytes: []const u8) std.Io.Writer.Error!usize {
if (self.expected_remaining.len < bytes.len) {
std.log.warn(
\\====== expected this output: =========
\\{s}
\\======== instead found this: =========
\\{s}
\\======================================
, .{
self.expected_remaining,
bytes,
});
return error.WriteFailed;
}
if (!std.mem.eql(u8, self.expected_remaining[0..bytes.len], bytes)) {
std.log.warn(
\\====== expected this output: =========
\\{s}
\\======== instead found this: =========
\\{s}
\\======================================
, .{
self.expected_remaining[0..bytes.len],
bytes,
});
return error.WriteFailed;
}
self.expected_remaining = self.expected_remaining[bytes.len..];
return bytes.len;
}
};
fn testencode(allocator: std.mem.Allocator, expected: []const u8, value: anytype, comptime options: EncodingOptions) !void {
var vos = ValidationWriter.init(expected); var vos = ValidationWriter.init(expected);
try encode(allocator, value, vos.writer(), options); try encode(allocator, value, &vos.writer, options);
if (vos.expected_remaining.len > 0) return error.NotEnoughData; if (vos.expected_remaining.len > 0) return error.NotEnoughData;
} }
@ -238,17 +250,17 @@ test "can urlencode an EC2 Filter" {
}, },
.{}, .{},
) catch |err| { ) catch |err| {
var al = std.ArrayList(u8).init(std.testing.allocator); var aw = std.Io.Writer.Allocating.init(std.testing.allocator);
defer al.deinit(); defer aw.deinit();
try encode( try encode(
std.testing.allocator, std.testing.allocator,
Request{ Request{
.filters = @constCast(&[_]Filter{.{ .name = "foo", .values = @constCast(&[_][]const u8{"bar"}) }}), .filters = @constCast(&[_]Filter{.{ .name = "foo", .values = @constCast(&[_][]const u8{"bar"}) }}),
}, },
al.writer(), &aw.writer,
.{}, .{},
); );
std.log.warn("Error found. Full encoding is '{s}'", .{al.items}); std.log.warn("Error found. Full encoding is '{s}'", .{aw.written()});
return err; return err;
}; };
} }