Packages
ex_aws
2.5.0
2.7.0
2.6.1
2.6.0
2.5.11
2.5.10
2.5.9
2.5.8
2.5.7
2.5.6
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.9
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.2
2.0.1
2.0.0
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.1
1.0.0-beta3
1.0.0-beta2
1.0.0-beta1
1.0.0-beta0
0.5.0
0.4.19
0.4.18
0.4.17
0.4.15
0.4.14
0.4.13
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.1
0.3.0
0.2.0
0.1.2
0.1.1
0.1.0
0.0.5
0.0.4
0.0.3
AWS client for Elixir. Currently supports Dynamo, DynamoStreams, EC2, Firehose, Kinesis, KMS, Lambda, RRDS, Route53, S3, SES, SNS, SQS, STS and others.
Current section
Files
Jump to
Current section
Files
lib/ex_aws/operation/s3.ex
defmodule ExAws.Operation.S3 do
@moduledoc """
Holds data necessary for an operation on the S3 service.
"""
defstruct stream_builder: nil,
parser: &Function.identity/1,
bucket: "",
path: "/",
http_method: nil,
body: "",
resource: "",
params: %{},
headers: %{},
service: :s3
@type t :: %__MODULE__{}
defimpl ExAws.Operation do
def perform(operation, config) do
body = operation.body
headers = operation.headers
http_method = operation.http_method
{operation, config} = add_bucket_to_path(operation, config)
url =
operation
|> add_resource_to_params()
|> ExAws.Request.Url.build(config)
hashed_payload = ExAws.Auth.Utils.hash_sha256(body)
headers =
headers
|> Map.put("x-amz-content-sha256", hashed_payload)
|> put_content_length_header(body, http_method)
|> Map.to_list()
ExAws.Request.request(http_method, url, body, headers, config, operation.service)
|> ExAws.Request.default_aws_error()
|> operation.parser.()
end
def stream!(%{stream_builder: fun}, config), do: fun.(config)
defp put_content_length_header(headers, "", :get), do: headers
defp put_content_length_header(headers, body, _) do
Map.put(headers, "content-length", byte_size(body) |> Integer.to_string())
end
@spec add_bucket_to_path(operation :: ExAws.Operation.S3.t(), config :: map) ::
{operation :: ExAws.Operation.S3.t(), config :: map}
def add_bucket_to_path(operation, config \\ %{})
def add_bucket_to_path(%{bucket: nil}, _config) do
raise "#{__MODULE__}.perform/2 cannot perform operation on `nil` bucket"
end
def add_bucket_to_path(operation, %{virtual_host: true, host: base_host} = config) do
vhost_domain = "#{operation.bucket}.#{base_host}"
{put_in(operation.path, ensure_absolute(operation.path)),
Map.put(config, :host, vhost_domain)}
end
def add_bucket_to_path(operation, config) do
path = "/#{operation.bucket}#{ensure_absolute(operation.path)}" |> expand_dot()
{operation |> Map.put(:path, path), config}
end
@spec add_resource_to_params(operation :: ExAws.Operation.S3.t()) :: ExAws.Operation.S3.t()
def add_resource_to_params(operation) do
params = operation.params |> Map.new() |> Map.put(operation.resource, 1)
operation |> Map.put(:params, params)
end
defp ensure_absolute(<<"/", _rest::binary>> = path), do: path
defp ensure_absolute(path), do: "/#{path}"
# A subset of Elixir's built-in Path.expand/1 - because it's OS-specific
# we can't use it to normalise paths with "." or ".." in them (otherwise
# it breaks on Windows because the /'s become \'s).
defp expand_dot(<<"/", rest::binary>>), do: "/" <> do_expand_dot(rest)
defp expand_dot(path), do: do_expand_dot(path)
defp do_expand_dot(path), do: do_expand_dot(:binary.split(path, "/", [:global]), [])
defp do_expand_dot([".." | t], [_, _ | acc]), do: do_expand_dot(t, acc)
defp do_expand_dot([".." | t], []), do: do_expand_dot(t, [])
defp do_expand_dot(["." | t], acc), do: do_expand_dot(t, acc)
defp do_expand_dot([h | t], acc), do: do_expand_dot(t, ["/", h | acc])
defp do_expand_dot([], []), do: ""
defp do_expand_dot([], ["/" | acc]), do: IO.iodata_to_binary(:lists.reverse(acc))
end
end