diff --git a/lib/aws_codegen.ex b/lib/aws_codegen.ex index 8fc0483..91b66bc 100644 --- a/lib/aws_codegen.ex +++ b/lib/aws_codegen.ex @@ -26,6 +26,11 @@ defmodule AWS.CodeGen do decode: nil, encode: nil, endpoint_prefix: nil, + # Name of the AWS-canonical service-specific endpoint env var + # (e.g. "AWS_ENDPOINT_URL_DYNAMODB"). Derived from `service_id` + # per the AWS CLI/SDK convention: spaces -> "_", uppercased. + # See https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-endpoints.html + endpoint_url_env_var: nil, is_global: false, hostname: nil, json_version: nil, diff --git a/lib/aws_codegen/post_service.ex b/lib/aws_codegen/post_service.ex index 9a4fb4f..55edf02 100644 --- a/lib/aws_codegen/post_service.ex +++ b/lib/aws_codegen/post_service.ex @@ -111,6 +111,7 @@ defmodule AWS.CodeGen.PostService do signing_name: signing_name, signature_version: AWS.CodeGen.Util.get_signature_version(service), service_id: AWS.CodeGen.Util.get_service_id(service), + endpoint_url_env_var: "AWS_ENDPOINT_URL_" <> spec.module_name |> String.upcase(), target_prefix: target_prefix(spec.api) } end diff --git a/lib/aws_codegen/rest_service.ex b/lib/aws_codegen/rest_service.ex index c9f3795..500a237 100644 --- a/lib/aws_codegen/rest_service.ex +++ b/lib/aws_codegen/rest_service.ex @@ -157,6 +157,7 @@ defmodule AWS.CodeGen.RestService do signing_name: signing_name, signature_version: AWS.CodeGen.Util.get_signature_version(service), service_id: AWS.CodeGen.Util.get_service_id(service), + endpoint_url_env_var: "AWS_ENDPOINT_URL_" <> spec.module_name |> String.upcase(), ## TODO: metadata["targetPrefix"], target_prefix: nil, shapes: Shapes.collect_shapes(language, spec.api) diff --git a/priv/post.erl.eex b/priv/post.erl.eex index 6a42686..544ce52 100644 --- a/priv/post.erl.eex +++ b/priv/post.erl.eex @@ -75,8 +75,8 @@ request(Client, Action, Input, Options) -> <% else %>do_request(Client, Action, Input0, Options) -> <% end %> Client1 = Client#{service => <<"<%= context.signing_name %>">><%= if context.is_global do %>, region => <<"<%= context.credential_scope %>">><% end %>}, - Host = build_host(<<"<%= context.endpoint_prefix %>">>, Client1), - URL = build_url(Host, Client1), + DefaultHost = build_host(<<"<%= context.endpoint_prefix %>">>, Client1), + {URL, Host} = aws_util:apply_endpoint_url_override(build_url(DefaultHost, Client1), DefaultHost, <<"/">>, <<"<%= context.endpoint_url_env_var %>">>), Headers = [ {<<"Host">>, Host}, {<<"Content-Type">>, <<"<%= context.content_type %>">>}<%= if context.protocol == "json" do %>, diff --git a/priv/rest.erl.eex b/priv/rest.erl.eex index 251f320..1b4664a 100644 --- a/priv/rest.erl.eex +++ b/priv/rest.erl.eex @@ -209,9 +209,11 @@ do_request(Client, Method, Path, Query, Headers0, Input, Options, SuccessStatusC Client1 = Client#{service => <<"<%= context.signing_name %>">><%= if context.is_global do %>, region => <<"<%= context.credential_scope %>">><% end %>}, <%= if context.endpoint_prefix == "s3-control" do %>AccountId = proplists:get_value(<<"x-amz-account-id">>, Headers0), - Host = build_host(AccountId, <<"<%= context.endpoint_prefix %>">>, Client1),<% else %><%= if AWS.CodeGen.RestService.Context.s3_context?(context) do %>Host = build_host(<<"<%= context.endpoint_prefix %>">>, Client1, Bucket),<%else %>Host = build_host(<<"<%= context.endpoint_prefix %>">>, Client1),<% end %><% end %> - URL0 = build_url(Host, Path, Client1<%= if AWS.CodeGen.RestService.Context.s3_context?(context) do %>, Bucket<% end %>), - URL = aws_request:add_query(URL0, Query), + DefaultHost = build_host(AccountId, <<"<%= context.endpoint_prefix %>">>, Client1),<% else %><%= if AWS.CodeGen.RestService.Context.s3_context?(context) do %>DefaultHost = build_host(<<"<%= context.endpoint_prefix %>">>, Client1, Bucket),<%else %>DefaultHost = build_host(<<"<%= context.endpoint_prefix %>">>, Client1),<% end %><% end %> + URL0 = build_url(DefaultHost, Path, Client1<%= if AWS.CodeGen.RestService.Context.s3_context?(context) do %>, Bucket<% end %>), + PathBin = erlang:iolist_to_binary(Path), + {URL1, Host} = aws_util:apply_endpoint_url_override(URL0, DefaultHost, PathBin, <<"<%= context.endpoint_url_env_var %>">>), + URL = aws_request:add_query(URL1, Query), AdditionalHeaders1 = [ {<<"Host">>, Host} , {<<"Content-Type">>, <<"<%= context.content_type %>">>} ], @@ -332,7 +334,6 @@ build_host(EndpointPrefix, #{endpoint := Endpoint}) -> aws_util:binary_join([EndpointPrefix, Endpoint], <<".">>).<% else %> build_host(EndpointPrefix, #{region := Region, endpoint := Endpoint}) -> aws_util:binary_join([EndpointPrefix, Region, Endpoint], <<".">>).<% end %><% end %><% end %><% end %> - <%= if AWS.CodeGen.RestService.Context.s3_context?(context) do %>build_url(Host0, Path0, Client, Bucket) -> Proto = aws_client:proto(Client), %% Mocks are notoriously bad with host-style requests, just skip it and use path-style for anything local diff --git a/test/aws_codegen/rest_service_test.exs b/test/aws_codegen/rest_service_test.exs index cd45c61..e38a160 100644 --- a/test/aws_codegen/rest_service_test.exs +++ b/test/aws_codegen/rest_service_test.exs @@ -51,6 +51,7 @@ defmodule AWS.CodeGen.RestServiceTest do module_name: "AWS.CloudTrailData", protocol: "rest-json", service_id: "CloudTrail Data", + endpoint_url_env_var: "AWS_ENDPOINT_URL_CLOUDTRAIL_DATA", signature_version: "v4", signing_name: "cloudtrail-data", target_prefix: nil