Compare commits
No commits in common. "f4c306a2dfc1d54904466659cae50bbf04bfe5b2" and "28698e8ec42ba4b5d8c5ba91e2148ce44cc6a66d" have entirely different histories.
f4c306a2df
...
28698e8ec4
2 changed files with 10 additions and 222 deletions
84
src/aws.zig
84
src/aws.zig
|
@ -236,8 +236,6 @@ pub fn Request(comptime request_action: anytype) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aws_request.body = buffer.items;
|
aws_request.body = buffer.items;
|
||||||
var rest_xml_body: ?[]const u8 = null;
|
|
||||||
defer if (rest_xml_body) |b| options.client.allocator.free(b);
|
|
||||||
if (Self.service_meta.aws_protocol == .rest_xml) {
|
if (Self.service_meta.aws_protocol == .rest_xml) {
|
||||||
if (std.mem.eql(u8, "PUT", aws_request.method) or std.mem.eql(u8, "POST", aws_request.method)) {
|
if (std.mem.eql(u8, "PUT", aws_request.method) or std.mem.eql(u8, "POST", aws_request.method)) {
|
||||||
if (@hasDecl(ActionRequest, "http_payload")) {
|
if (@hasDecl(ActionRequest, "http_payload")) {
|
||||||
|
@ -245,49 +243,7 @@ pub fn Request(comptime request_action: anytype) type {
|
||||||
// the http_payload declaration on the request type.
|
// the http_payload declaration on the request type.
|
||||||
// Hopefully these will always be ?[]const u8, otherwise
|
// Hopefully these will always be ?[]const u8, otherwise
|
||||||
// we should see a compile error on this line
|
// we should see a compile error on this line
|
||||||
const payload = @field(request, ActionRequest.http_payload);
|
aws_request.body = @field(request, ActionRequest.http_payload).?;
|
||||||
const T = @TypeOf(payload);
|
|
||||||
var body_assigned = false;
|
|
||||||
if (T == ?[]const u8) {
|
|
||||||
aws_request.body = payload.?;
|
|
||||||
body_assigned = true;
|
|
||||||
}
|
|
||||||
if (T == []const u8) {
|
|
||||||
aws_request.body = payload;
|
|
||||||
body_assigned = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!body_assigned) {
|
|
||||||
const sm = ActionRequest.metaInfo().service_metadata;
|
|
||||||
if (!std.mem.eql(u8, sm.endpoint_prefix, "s3"))
|
|
||||||
// Because the attributes below are most likely only
|
|
||||||
// applicable to s3, we are better off to fail
|
|
||||||
// early. This portion of the code base should
|
|
||||||
// only be executed for s3 as no other known
|
|
||||||
// service uses this protocol
|
|
||||||
return error.NotImplemented;
|
|
||||||
|
|
||||||
const attrs = try std.fmt.allocPrint(
|
|
||||||
options.client.allocator,
|
|
||||||
"xmlns=\"http://{s}.amazonaws.com/doc/{s}/\"",
|
|
||||||
.{ sm.endpoint_prefix, sm.version },
|
|
||||||
);
|
|
||||||
defer options.client.allocator.free(attrs); // once serialized, the value should be copied over
|
|
||||||
|
|
||||||
// Need to serialize this
|
|
||||||
rest_xml_body = try xml_serializer.stringifyAlloc(
|
|
||||||
options.client.allocator,
|
|
||||||
payload,
|
|
||||||
.{
|
|
||||||
.whitespace = .indent_2,
|
|
||||||
.root_name = request.fieldNameFor(ActionRequest.http_payload),
|
|
||||||
.root_attributes = attrs,
|
|
||||||
.emit_null_optional_fields = false,
|
|
||||||
.include_declaration = false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
aws_request.body = rest_xml_body.?;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return error.NotImplemented;
|
return error.NotImplemented;
|
||||||
}
|
}
|
||||||
|
@ -2303,44 +2259,6 @@ test "ec2_query_with_input: EC2 describe instances" {
|
||||||
try std.testing.expectEqualStrings("i-0212d7d1f62b96676", call.response.reservations.?[1].instances.?[0].instance_id.?);
|
try std.testing.expectEqualStrings("i-0212d7d1f62b96676", call.response.reservations.?[1].instances.?[0].instance_id.?);
|
||||||
try std.testing.expectEqualStrings("123456789012:found-me", call.response.reservations.?[1].instances.?[0].tags.?[0].value.?);
|
try std.testing.expectEqualStrings("123456789012:found-me", call.response.reservations.?[1].instances.?[0].tags.?[0].value.?);
|
||||||
}
|
}
|
||||||
test "rest_xml_with_input_s3: S3 create bucket" {
|
|
||||||
const allocator = std.testing.allocator;
|
|
||||||
var test_harness = TestSetup.init(.{
|
|
||||||
.allocator = allocator,
|
|
||||||
.server_response =
|
|
||||||
\\
|
|
||||||
,
|
|
||||||
.server_response_headers = &.{ // I don't see content type coming back in actual S3 requests
|
|
||||||
.{ .name = "x-amzn-RequestId", .value = "9PEYBAZ9J7TPRX43" },
|
|
||||||
.{ .name = "x-amz-id-2", .value = "u7lzgW0tIyRP15vSUsVOXxJ37OfVCO8lZmLIVuqeq5EE4tNp9qebb5fy+/kendlZpR4YQE+y4Xg=" },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
defer test_harness.deinit();
|
|
||||||
errdefer test_harness.creds.deinit();
|
|
||||||
const options = try test_harness.start();
|
|
||||||
const s3 = (Services(.{.s3}){}).s3;
|
|
||||||
const call = try test_harness.client.call(s3.create_bucket.Request{
|
|
||||||
.bucket = "",
|
|
||||||
.create_bucket_configuration = .{
|
|
||||||
.location_constraint = "us-west-2",
|
|
||||||
},
|
|
||||||
}, options);
|
|
||||||
defer call.deinit();
|
|
||||||
test_harness.stop();
|
|
||||||
// Request expectations
|
|
||||||
try std.testing.expectEqual(std.http.Method.PUT, test_harness.request_options.request_method);
|
|
||||||
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
||||||
try std.testing.expectEqualStrings(
|
|
||||||
\\<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
||||||
\\ <LocationConstraint>us-west-2</LocationConstraint>
|
|
||||||
\\</CreateBucketConfiguration>
|
|
||||||
, test_harness.request_options.request_body);
|
|
||||||
// Response expectations
|
|
||||||
try std.testing.expectEqualStrings(
|
|
||||||
"9PEYBAZ9J7TPRX43, host_id: u7lzgW0tIyRP15vSUsVOXxJ37OfVCO8lZmLIVuqeq5EE4tNp9qebb5fy+/kendlZpR4YQE+y4Xg=",
|
|
||||||
call.response_metadata.request_id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
test "rest_xml_no_input: S3 list buckets" {
|
test "rest_xml_no_input: S3 list buckets" {
|
||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
var test_harness = TestSetup.init(.{
|
var test_harness = TestSetup.init(.{
|
||||||
|
|
|
@ -20,9 +20,6 @@ pub const StringifyOptions = struct {
|
||||||
/// Root element name to use when serializing a value that doesn't have a natural name
|
/// Root element name to use when serializing a value that doesn't have a natural name
|
||||||
root_name: ?[]const u8 = "root",
|
root_name: ?[]const u8 = "root",
|
||||||
|
|
||||||
/// Root attributes (e.g. xmlns="...") that will be added to the root element node only
|
|
||||||
root_attributes: []const u8 = "",
|
|
||||||
|
|
||||||
/// Function to determine the element name for an array item based on the element
|
/// Function to determine the element name for an array item based on the element
|
||||||
/// name of the array containing the elements. See arrayElementPluralToSingluarTransformation
|
/// name of the array containing the elements. See arrayElementPluralToSingluarTransformation
|
||||||
/// and arrayElementNoopTransformation functions for examples
|
/// and arrayElementNoopTransformation functions for examples
|
||||||
|
@ -61,10 +58,7 @@ pub fn stringify(
|
||||||
|
|
||||||
// Start serialization with the root element
|
// Start serialization with the root element
|
||||||
const root_name = options.root_name;
|
const root_name = options.root_name;
|
||||||
if (@typeInfo(@TypeOf(value)) != .optional or value == null)
|
try serializeValue(value, root_name, options, writer.any(), 0);
|
||||||
try serializeValue(value, root_name, options, writer.any(), 0)
|
|
||||||
else
|
|
||||||
try serializeValue(value.?, root_name, options, writer.any(), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes a value to XML and returns an allocated string
|
/// Serializes a value to XML and returns an allocated string
|
||||||
|
@ -90,21 +84,18 @@ fn serializeValue(
|
||||||
) !void {
|
) !void {
|
||||||
const T = @TypeOf(value);
|
const T = @TypeOf(value);
|
||||||
|
|
||||||
// const output_indent = !(!options.emit_null_optional_fields and @typeInfo(@TypeOf(value)) == .optional and value == null);
|
|
||||||
const output_indent = options.emit_null_optional_fields or @typeInfo(@TypeOf(value)) != .optional or value != null;
|
|
||||||
|
|
||||||
if (output_indent and element_name != null)
|
|
||||||
try writeIndent(writer, depth, options.whitespace);
|
try writeIndent(writer, depth, options.whitespace);
|
||||||
|
|
||||||
|
// const write_outer_element =
|
||||||
|
// @typeInfo(T) != .optional or
|
||||||
|
// options.emit_strings_as_arrays == false or
|
||||||
|
// (@typeInfo(T) == .optional and element_name != null) or
|
||||||
|
// (options.emit_strings_as_arrays and (@typeInfo(T) != .array or @typeInfo(T).array.child != u8));
|
||||||
// Start element tag
|
// Start element tag
|
||||||
if (@typeInfo(T) != .optional and @typeInfo(T) != .array) {
|
if (@typeInfo(T) != .optional and @typeInfo(T) != .array) {
|
||||||
if (element_name) |n| {
|
if (element_name) |n| {
|
||||||
try writer.writeAll("<");
|
try writer.writeAll("<");
|
||||||
try writer.writeAll(n);
|
try writer.writeAll(n);
|
||||||
if (depth == 0 and options.root_attributes.len > 0) {
|
|
||||||
try writer.writeByte(' ');
|
|
||||||
try writer.writeAll(options.root_attributes);
|
|
||||||
}
|
|
||||||
try writer.writeAll(">");
|
try writer.writeAll(">");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,9 +197,8 @@ fn serializeValue(
|
||||||
else
|
else
|
||||||
field.name; // TODO: field mapping
|
field.name; // TODO: field mapping
|
||||||
|
|
||||||
const field_value = @field(value, field.name);
|
|
||||||
try serializeValue(
|
try serializeValue(
|
||||||
field_value,
|
@field(value, field.name),
|
||||||
field_name,
|
field_name,
|
||||||
options,
|
options,
|
||||||
writer,
|
writer,
|
||||||
|
@ -216,13 +206,9 @@ fn serializeValue(
|
||||||
);
|
);
|
||||||
|
|
||||||
if (options.whitespace != .minified) {
|
if (options.whitespace != .minified) {
|
||||||
if (!options.emit_null_optional_fields and @typeInfo(@TypeOf(field_value)) == .optional and field_value == null) {
|
|
||||||
// Skip writing anything
|
|
||||||
} else {
|
|
||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try writeIndent(writer, depth, options.whitespace);
|
try writeIndent(writer, depth, options.whitespace);
|
||||||
},
|
},
|
||||||
|
@ -675,119 +661,3 @@ test "structs with custom field names" {
|
||||||
, result);
|
, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "structs with optional values" {
|
|
||||||
const testing = std.testing;
|
|
||||||
const allocator = testing.allocator;
|
|
||||||
|
|
||||||
const Person = struct {
|
|
||||||
first_name: []const u8,
|
|
||||||
middle_name: ?[]const u8 = null,
|
|
||||||
last_name: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const person = Person{
|
|
||||||
.first_name = "John",
|
|
||||||
.last_name = "Doe",
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
const result = try stringifyAlloc(
|
|
||||||
allocator,
|
|
||||||
person,
|
|
||||||
.{
|
|
||||||
.whitespace = .indent_2,
|
|
||||||
.emit_null_optional_fields = false,
|
|
||||||
.root_attributes = "xmlns=\"http://example.com/blah/xxxx/\"",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
defer allocator.free(result);
|
|
||||||
try testing.expectEqualStrings(
|
|
||||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
\\<root xmlns="http://example.com/blah/xxxx/">
|
|
||||||
\\ <first_name>John</first_name>
|
|
||||||
\\ <last_name>Doe</last_name>
|
|
||||||
\\</root>
|
|
||||||
, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "optional structs with value" {
|
|
||||||
const testing = std.testing;
|
|
||||||
const allocator = testing.allocator;
|
|
||||||
|
|
||||||
const Person = struct {
|
|
||||||
first_name: []const u8,
|
|
||||||
middle_name: ?[]const u8 = null,
|
|
||||||
last_name: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const person: ?Person = Person{
|
|
||||||
.first_name = "John",
|
|
||||||
.last_name = "Doe",
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
const result = try stringifyAlloc(
|
|
||||||
allocator,
|
|
||||||
person,
|
|
||||||
.{
|
|
||||||
.whitespace = .indent_2,
|
|
||||||
.emit_null_optional_fields = false,
|
|
||||||
.root_attributes = "xmlns=\"http://example.com/blah/xxxx/\"",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
defer allocator.free(result);
|
|
||||||
try testing.expectEqualStrings(
|
|
||||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
\\<root xmlns="http://example.com/blah/xxxx/">
|
|
||||||
\\ <first_name>John</first_name>
|
|
||||||
\\ <last_name>Doe</last_name>
|
|
||||||
\\</root>
|
|
||||||
, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "nested optional structs with value" {
|
|
||||||
const testing = std.testing;
|
|
||||||
const allocator = testing.allocator;
|
|
||||||
|
|
||||||
const Name = struct {
|
|
||||||
first_name: []const u8,
|
|
||||||
middle_name: ?[]const u8 = null,
|
|
||||||
last_name: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Person = struct {
|
|
||||||
name: ?Name,
|
|
||||||
};
|
|
||||||
|
|
||||||
const person: ?Person = Person{
|
|
||||||
.name = .{
|
|
||||||
.first_name = "John",
|
|
||||||
.last_name = "Doe",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
const result = try stringifyAlloc(
|
|
||||||
allocator,
|
|
||||||
person,
|
|
||||||
.{
|
|
||||||
.whitespace = .indent_2,
|
|
||||||
.emit_null_optional_fields = false,
|
|
||||||
.root_attributes = "xmlns=\"http://example.com/blah/xxxx/\"",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
defer allocator.free(result);
|
|
||||||
try testing.expectEqualStrings(
|
|
||||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
\\<root xmlns="http://example.com/blah/xxxx/">
|
|
||||||
\\ <name>
|
|
||||||
\\ <first_name>John</first_name>
|
|
||||||
\\ <last_name>Doe</last_name>
|
|
||||||
\\ </name>
|
|
||||||
\\</root>
|
|
||||||
, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue