From 33ef964582c62b2cb135ac84c37b525008ff7fb2 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Thu, 28 Dec 2023 10:20:22 +0100 Subject: [PATCH 1/4] fix(s3): handle extra configured headers correctly * Header names in config become atoms. (Probably because of blanket `unsafe_atom_key_map/1` in `emqx_config`) * Header names should be normalized to lowercase. (Otherwise signature will be incorrect) --- apps/emqx_s3/src/emqx_s3_client.erl | 4 +- apps/emqx_s3/test/emqx_s3_client_SUITE.erl | 43 ++++++++++++++++------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/apps/emqx_s3/src/emqx_s3_client.erl b/apps/emqx_s3/src/emqx_s3_client.erl index 73cf667a1..fe0058433 100644 --- a/apps/emqx_s3/src/emqx_s3_client.erl +++ b/apps/emqx_s3/src/emqx_s3_client.erl @@ -388,7 +388,7 @@ with_path_and_query_only(Url, Fun) -> %% Users provide headers as a map, but erlcloud expects a list of tuples with string keys and values. headers_user_to_erlcloud_request(UserHeaders) -> - [{to_list_string(K), V} || {K, V} <- maps:to_list(UserHeaders)]. + [{string:to_lower(to_list_string(K)), V} || {K, V} <- maps:to_list(UserHeaders)]. %% Ehttpc returns operates on headers as a list of tuples with binary keys. %% Erlcloud expects a list of tuples with string values and lowcase string keys @@ -409,6 +409,8 @@ to_binary(Val) when is_binary(Val) -> Val. to_list_string(Val) when is_binary(Val) -> binary_to_list(Val); +to_list_string(Val) when is_atom(Val) -> + atom_to_list(Val); to_list_string(Val) when is_list(Val) -> Val. diff --git a/apps/emqx_s3/test/emqx_s3_client_SUITE.erl b/apps/emqx_s3/test/emqx_s3_client_SUITE.erl index 434510867..2522af9b7 100644 --- a/apps/emqx_s3/test/emqx_s3_client_SUITE.erl +++ b/apps/emqx_s3/test/emqx_s3_client_SUITE.erl @@ -142,6 +142,22 @@ t_no_acl(Config) -> ok = emqx_s3_client:put_object(Client, Key, <<"data">>). +t_extra_headers(Config0) -> + Config = [{extra_headers, #{'Content-Type' => <<"application/json">>}} | Config0], + Key = ?config(key, Config), + + Client = client(Config), + Data = #{foo => bar}, + ok = emqx_s3_client:put_object(Client, Key, emqx_utils_json:encode(Data)), + + Url = emqx_s3_client:uri(Client, Key), + + {ok, {{_StatusLine, 200, "OK"}, _Headers, Content}} = httpc:request(Url), + ?_assertEqual( + Data, + emqx_utils_json:decode(Content) + ). + %%-------------------------------------------------------------------- %% Helpers %%-------------------------------------------------------------------- @@ -154,17 +170,22 @@ client(Config) -> profile_config(Config) -> ProfileConfig0 = emqx_s3_test_helpers:base_config(?config(conn_type, Config)), - ProfileConfig1 = maps:put( - bucket, - ?config(bucket, Config), - ProfileConfig0 - ), - ProfileConfig2 = emqx_utils_maps:deep_put( - [transport_options, pool_type], - ProfileConfig1, - ?config(pool_type, Config) - ), - ProfileConfig2. + maps:fold( + fun inject_config/3, + ProfileConfig0, + #{ + bucket => ?config(bucket, Config), + [transport_options, pool_type] => ?config(pool_type, Config), + [transport_options, headers] => ?config(extra_headers, Config) + } + ). + +inject_config(_Key, undefined, ProfileConfig) -> + ProfileConfig; +inject_config(KeyPath, Value, ProfileConfig) when is_list(KeyPath) -> + emqx_utils_maps:deep_put(KeyPath, ProfileConfig, Value); +inject_config(Key, Value, ProfileConfig) -> + maps:put(Key, Value, ProfileConfig). data(Size) -> iolist_to_binary([$a || _ <- lists:seq(1, Size)]). From 1d9374125c8d2df24772b786957dffb5dcdc37cb Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Thu, 28 Dec 2023 14:12:33 +0100 Subject: [PATCH 2/4] chore: bump `emqx_s3` to 5.0.13 --- apps/emqx_s3/src/emqx_s3.app.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/emqx_s3/src/emqx_s3.app.src b/apps/emqx_s3/src/emqx_s3.app.src index 2658dfe69..3da9ea7ca 100644 --- a/apps/emqx_s3/src/emqx_s3.app.src +++ b/apps/emqx_s3/src/emqx_s3.app.src @@ -1,6 +1,6 @@ {application, emqx_s3, [ {description, "EMQX S3"}, - {vsn, "5.0.12"}, + {vsn, "5.0.13"}, {modules, []}, {registered, [emqx_s3_sup]}, {applications, [ From 18dc9b251652d496859c8f40a835e00de4b681d2 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Thu, 28 Dec 2023 14:13:22 +0100 Subject: [PATCH 3/4] fix(s3): remove `emqx_bridge_http` from runtime dependencies Otherwise it's impossible to test `emqx_s3` in isolation. --- apps/emqx_s3/src/emqx_s3.app.src | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/emqx_s3/src/emqx_s3.app.src b/apps/emqx_s3/src/emqx_s3.app.src index 3da9ea7ca..ef59859ce 100644 --- a/apps/emqx_s3/src/emqx_s3.app.src +++ b/apps/emqx_s3/src/emqx_s3.app.src @@ -8,8 +8,7 @@ stdlib, gproc, erlcloud, - ehttpc, - emqx_bridge_http + ehttpc ]}, {mod, {emqx_s3_app, []}} ]}. From 72677f69d40dcad1d6af565e8d21b736c90219cc Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Thu, 28 Dec 2023 14:49:05 +0100 Subject: [PATCH 4/4] chore: add changelog entry --- changes/ee/fix-12241.en.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/ee/fix-12241.en.md diff --git a/changes/ee/fix-12241.en.md b/changes/ee/fix-12241.en.md new file mode 100644 index 000000000..e9f5be6aa --- /dev/null +++ b/changes/ee/fix-12241.en.md @@ -0,0 +1 @@ +Fix an issue where setting up extra HTTP headers for communication with S3 API would break File Transfers using S3 storage backend.