defmodule ExAws.S3.Impl do import ExAws.S3.Utils alias ExAws.S3.Parsers @moduledoc false # Implementation of the AWS S3 API. # # See ExAws.S3.Client for usage. ## Buckets ############# defdelegate stream_objects!(client, bucket), to: ExAws.S3.Lazy defdelegate stream_objects!(client, bucket, opts), to: ExAws.S3.Lazy def list_buckets(client, opts \\ []) do request(client, :get, "", "/", params: opts) end def delete_bucket(client, bucket) do request(client, :delete, bucket, "/") end def delete_bucket_cors(client, bucket) do request(client, :delete, bucket, "/", resource: "cors") end def delete_bucket_lifecycle(client, bucket) do request(client, :delete, bucket, "/", resource: "lifecycle") end def delete_bucket_policy(client, bucket) do request(client, :delete, bucket, "/", resource: "policy") end def delete_bucket_replication(client, bucket) do request(client, :delete, bucket, "/", resource: "replication") end def delete_bucket_tagging(client, bucket) do request(client, :delete, bucket, "/", resource: "tagging") end def delete_bucket_website(client, bucket) do request(client, :delete, bucket, "/", resource: "website") end @params [:delimiter, :marker, :prefix, :encoding_type, :max_keys] def list_objects(client, bucket, opts \\ []) do params = opts |> format_and_take(@params) request(client, :get, bucket, "/", params: params) |> Parsers.parse_list_objects end def list_objects!(client, bucket, opts \\ []) do {:ok, resp} = list_objects(client, bucket, opts) resp end def get_bucket_acl(client, bucket) do request(client, :get, bucket, "/", resource: "acl") end def get_bucket_cors(client, bucket) do request(client, :get, bucket, "/", resource: "cors") end def get_bucket_lifecycle(client, bucket) do request(client, :get, bucket, "/", resource: "lifecycle") end def get_bucket_policy(client, bucket) do request(client, :get, bucket, "/", resource: "policy") end def get_bucket_location(client, bucket) do request(client, :get, bucket, "/", resource: "location") end def get_bucket_logging(client, bucket) do request(client, :get, bucket, "/", resource: "logging") end def get_bucket_notification(client, bucket) do request(client, :get, bucket, "/", resource: "notification") end def get_bucket_replication(client, bucket) do request(client, :get, bucket, "/", resource: "replication") end def get_bucket_tagging(client, bucket) do request(client, :get, bucket, "/", resource: "tagging") end def get_bucket_object_versions(client, bucket, opts \\ []) do request(client, :get, bucket, "/", resource: "versions", params: opts) end def get_bucket_request_payment(client, bucket) do request(client, :get, bucket, "/", resource: "requestPayment") end def get_bucket_versioning(client, bucket) do request(client, :get, bucket, "/", resource: "versioning") end def get_bucket_website(client, bucket) do request(client, :get, bucket, "/", resource: "website") end def head_bucket(client, bucket) do request(client, :head, bucket, "/") end @params [:delimiter, :encoding_type, :max_uploads, :key_marker, :prefix, :upload_id_marker] def list_multipart_uploads(client, bucket, opts \\ []) do params = @params |> format_and_take(opts) request(client, :get, bucket, "/", resource: "uploads", params: params) end @headers [:acl, :grant_read, :grant_write, :grant_read_acp, :grant_write_acp, :grant_full_control] def put_bucket(client, bucket, region, grants \\ %{}) do headers = grants |> format_grant_headers(@headers) body = """ #{region} """ request(client, :put, bucket, "/", body: body, headers: headers) end @headers [:acl, :grant_read, :grant_write, :grant_read_acp, :grant_write_acp, :grant_full_control] def put_bucket_acl(client, bucket, grants) do headers = grants |> format_grant_headers(@headers) request(client, :put, bucket, "/", headers: headers) end def put_bucket_cors(client, bucket, cors_rules) do rules = cors_rules |> Enum.map(&build_cors_rule/1) |> IO.iodata_to_binary body = "#{rules}" request(client, :put, bucket, "/", body: body) end def put_bucket_lifecycle(client, bucket, _livecycle_config) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_policy(client, bucket, _policy) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_logging(client, bucket, _logging_config) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_notification(client, bucket, _notification_config) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_replication(client, bucket, _replication_config) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_tagging(client, bucket, _tags) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_requestpayment(client, bucket, _payer) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_versioning(client, bucket, _version_config) do raise "not yet implemented" request(client, :put, bucket, "/") end def put_bucket_website(client, bucket, _website_config) do raise "not yet implemented" request(client, :put, bucket, "/") end ## Objects ########### def delete_object(client, bucket, object, opts \\ []) do request(client, :delete, bucket, object, headers: opts |> Enum.into(%{})) end def delete_object!(client, bucket, object, opts \\ []) do {:ok, resp} = delete_object(client, bucket, object, opts) resp end def delete_multiple_objects(client, bucket, _objects) do raise "not yet implemented" request(client, :post, bucket, "/?delete") end @response_params [:content_type, :content_language, :expires, :cach_control, :content_disposition, :content_encoding] @request_headers [:range, :if_modified_since, :if_unmodified_since, :if_match, :if_none_match] @encryption_headers [:customer_algorithm, :customer_key, :customer_key_md5] def get_object(client, bucket, object, opts \\ []) do opts = opts |> Enum.into(%{}) response_opts = opts |> Map.get(:response, %{}) |> format_and_take(@response_params) |> namespace("response") headers = opts |> format_and_take(@request_headers) headers = opts |> Map.get(:encryption, %{}) |> format_and_take(@encryption_headers) |> namespace("x-amz-server-side-encryption") |> Map.merge(headers) request(client, :get, bucket, object, headers: headers, params: response_opts) end def get_object!(client, bucket, object, opts \\ []) do {:ok, resp} = get_object(client, bucket, object, opts) resp end def get_object_acl(client, bucket, object, opts \\ []) do request(client, :get, bucket, object, resource: "acl", headers: opts |> Enum.into(%{})) end def get_object_torrent(client, bucket, object) do request(client, :get, bucket, object, resource: "torrent") end def head_object(client, bucket, object, opts \\ []) do request(client, :head, bucket, object, headers: opts |> Enum.into(%{})) end def options_object(client, bucket, object, origin, request_method, request_headers \\ []) do headers = [ {"Origin", origin}, {"Access-Control-Request-Method", request_method}, {"Access-Control-Request-Headers", request_headers |> Enum.join(",")}, ] request(client, :options, bucket, object, headers: headers) end def post_object(client, bucket, object, _opts \\ []) do raise "not yet implemented" request(client, :get, bucket, object) end def post_object_restore(client, bucket, object, _version_id, _number_of_days) do raise "not yet implemented" request(client, :get, bucket, object) end @headers [:cache_control, :content_disposition, :content_encoding, :content_length, :content_type, :expect, :expires] @amz_headers [:storage_class, :website_redirect_location] @acl_headers [:grant_read, :grant_read_acp, :grant_write_acp, :grant_full_control] def put_object(client, bucket, object, body, opts \\ []) do opts = opts |> Enum.into(%{}) regular_headers = opts |> format_and_take(@headers) amz_headers = opts |> format_and_take(@amz_headers) |> namespace("x-amz") acl_headers = opts |> format_grant_headers(@acl_headers) encryption_headers = opts |> Map.get(:encryption, %{}) |> build_encryption_headers canned_acl = case Map.get(opts, :acl) do nil -> %{} value -> %{"x-amz-acl" => normalize_param(value)} end headers = regular_headers |> Map.merge(amz_headers) |> Map.merge(acl_headers) |> Map.merge(canned_acl) |> Map.merge(encryption_headers) request(client, :put, bucket, object, body: body, headers: headers) end def put_object!(client, bucket, object, body, opts \\ []) do {:ok, resp} = put_object(client, bucket, object, body, opts) resp end def put_object_acl(client, bucket, object, _acl) do raise "not yet implemented" request(client, :get, bucket, object) end def put_object_copy(client, dest_bucket, dest_object, _src_bucket, _src_object, _opts \\ []) do raise "not yet implemented" request(client, :get, dest_bucket, dest_object) end def initiate_multipart_upload(client, bucket, object, _opts \\ []) do raise "not yet implemented" request(client, :get, bucket, object) end def upload_part(client, bucket, object, _upload_id, _part_number) do raise "not yet implemented" request(client, :get, bucket, object) end def upload_part_copy(client, dest_bucket, dest_object, _src_bucket, _src_object, _opts \\ []) do raise "not yet implemented" request(client, :get, dest_bucket, dest_object) end def complete_multipart_upload(client, bucket, object, _upload_id, _parts) do raise "not yet implemented" request(client, :get, bucket, object) end def abort_multipart_upload(client, bucket, object, _upload_id) do raise "not yet implemented" request(client, :get, bucket, object) end def list_parts(client, bucket, object, upload_id, opts \\ []) do params = %{"uploadId" => upload_id} |> Map.merge(opts) request(client, :get, bucket, object, params: params) end defp request(%{__struct__: client_module} = client, action, bucket, path, data \\ []) do client_module.request(client, action, bucket, path, data) end end