ex_aws icon indicating copy to clipboard operation
ex_aws copied to clipboard

ExAws.Request.Url.normalize_path/1 breaks operations on S3 objects with slashes at start of key name

Open MisterToolbox opened this issue 6 years ago • 0 comments

The function that normalizes paths for AWS operations will cause operations on S3 objects with a / as their first character to fail.

Environment

  • Elixir & Erlang versions (elixir --version):
Erlang/OTP 20 [erts-9.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.6.1 (compiled with OTP 20)
  • ExAws version:
mix deps | grep ex_aws
* ex_aws 2.0.2 (Hex package) (mix)
  locked at 2.0.2 (ex_aws) 8df2f96f
* ex_aws_s3 2.0.0 (Hex package) (mix)
  locked at 2.0.0 (ex_aws_s3) 404e7951
  • HTTP client version:
mix deps | grep hackney
* hackney 1.11.0 (Hex package) (rebar3)
  locked at 1.11.0 (hackney) 4951ee01

Current behavior

I've got a bucket that a third-party technology populated with objects whose keys begin with a /:

(I've added two debug logs to the normalize_path/1 function to see the URL before and after it transforms it)

object = ExAws.S3.list_objects(bucket_name)
    |> ExAws.stream!(connection_list)
    |> Enum.take(2) 
    |> List.first

10:00:36.915 [debug] url before normalization: /mybucket//

10:00:36.915 [debug] url after normalization: /mybucket/

10:00:36.947 [debug] Request URL: "https://myendpoint/mybucket/"
...
%{
  e_tag: "\"b0c2828fe6695df01c30df818c443cc8\"",
  key: "/example/container/1234/12345",
  last_modified: "2018-01-26T17:08:27.064Z",
  owner: %{display_name: "example", id: "9ef748b4-b30e-7472-1190-5352fc03bf50"},
  size: "104448",
  storage_class: "STANDARD"
}

If I attempt to head one of these objects, it returns a 404 because the extra slash at the beginning of the object key is stripped off by normalize_path/1

ExAws.S3.head_object(bucket_name, object)
    |> ExAws.request(connection_list)

10:00:41.666 [debug] url before normalization: /mybucket//example/container/1234/12345

10:00:41.666 [debug] url after normalization: /mybucket/example/container/1234/12345

10:00:41.666 [debug] Request URL: "https://myendpoint/mybucket/example/container/1234/12345"
...
10:00:41.666 [debug] Request BODY: ""
{:error,
 {:http_error, 404,
  %{
    headers: [...],
    status_code: 404
  }}}

Workaround

Changing the normalize_path/1 function defp to:

  defp normalize_path(url) do
    url |> Map.update(:path, "", &String.replace(&1, ~r/\/{2,}$/, "/"))
  end

This allows bucket listing (which needs the trailing / stripped) to continue to work and also allows objects with and without the prepended / on the key to be operated on.

Note

I'm near certain that I'm blind to a use case that requires stripping a number of slashes out of it, else this would have been a PR. Thought I'd kick off a dialog and see what shakes out.

Thanks for all the work you've done on ex_aws!

MisterToolbox avatar Mar 23 '18 15:03 MisterToolbox