Packages
ex_aws
2.4.3
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/request/url.ex
defmodule ExAws.Request.Url do
@moduledoc false
@doc """
Builds URL for an operation and a config"
"""
def build(operation, config) do
config
|> Map.take([:scheme, :host, :port])
|> Map.put(:query, query(operation))
|> Map.put(:path, operation.path)
|> normalize_scheme
|> normalize_path(config.normalize_path)
|> convert_port_to_integer
|> (&struct(URI, &1)).()
|> URI.to_string()
|> String.trim_trailing("?")
end
defp query(operation) do
operation
|> Map.get(:params, %{})
|> normalize_params
|> URI.encode_query()
end
defp normalize_scheme(url) do
url |> Map.update(:scheme, "", &String.replace(&1, "://", ""))
end
defp normalize_path(url, false), do: url
defp normalize_path(url, _normalize) do
url |> Map.update(:path, "", &String.replace(&1, ~r/\/{2,}/, "/"))
end
defp convert_port_to_integer(url = %{port: port}) when is_binary(port) do
{port, _} = Integer.parse(port)
put_in(url[:port], port)
end
defp convert_port_to_integer(url), do: url
defp normalize_params(params) when is_map(params) do
params |> Map.delete("") |> Map.delete(nil)
end
defp normalize_params(params), do: params
def sanitize(url, service) when service in ["s3", :s3] do
new_path =
url
|> get_path(service)
|> String.replace_prefix("/", "")
|> uri_encode()
query =
case String.split(url, "?", parts: 2) do
[_] -> nil
[_, ""] -> nil
[_, q] -> q
end
url
|> URI.parse()
|> Map.put(:fragment, nil)
|> Map.put(:path, "/" <> new_path)
|> Map.put(:query, query)
|> URI.to_string()
|> String.replace("+", "%20")
end
def sanitize(url, _), do: String.replace(url, "+", "%20")
def get_path(url, service \\ nil)
# Elixir's URI.parse will treat everything after the # sign
# as a fragment. This is correct, but S3 treats it as part
# of the path of the object.
#
# This will split the URL at the base with the right side
# being the path, except for the query params.
#
# for example:
# `"https://bucket.aws.com/my/path/here+ #3.txt?t=21"`
# https://bucket.aws.com | /my/path/here+ #3.txt?t=21
# ________base__________ | /my/path/here+ #3.txt | t=21
# ________base__________ | /my/path/here+ #3.txt | _params_
#
# After using `uri_encode` it will be `/my/path/here%2B%20%233.txt`
#
def get_path(url, service) when service in ["s3", :s3] do
base =
url
|> URI.parse()
|> Map.put(:path, nil)
|> Map.put(:query, nil)
|> Map.put(:fragment, nil)
|> URI.to_string()
[_base, path_with_params] = String.split(url, base, parts: 2)
[path | _query_params] = String.split(path_with_params, "?", parts: 2)
path
end
def get_path(url, _), do: URI.parse(url).path || "/"
def uri_encode(url), do: URI.encode(url, &valid_path_char?/1)
# Space character
defp valid_path_char?(?\s), do: false
defp valid_path_char?(?/), do: true
defp valid_path_char?(c) do
URI.char_unescaped?(c) && !URI.char_reserved?(c)
end
end