diff --git a/.gitignore b/.gitignore
index 0feb89006..a8bfa23eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@
mkmf.log
tests/.fog
gemfiles/Gemfile-edge.lock
+.idea
diff --git a/lib/fog/aws/models/storage/file.rb b/lib/fog/aws/models/storage/file.rb
index 4e16cb19a..15b1d3da3 100644
--- a/lib/fog/aws/models/storage/file.rb
+++ b/lib/fog/aws/models/storage/file.rb
@@ -25,6 +25,7 @@ module Fog
attribute :encryption_key, :aliases => 'x-amz-server-side-encryption-customer-key'
attribute :version, :aliases => 'x-amz-version-id'
attribute :kms_key_id, :aliases => 'x-amz-server-side-encryption-aws-kms-key-id'
+ attribute :tags, :aliases => 'x-amz-tagging'
# @note Chunk size to use for multipart uploads.
# Use small chunk sizes to minimize memory. E.g. 5242880 = 5mb
@@ -192,6 +193,7 @@ module Fog
# @option options [String] expires sets number of seconds before AWS Object expires.
# @option options [String] storage_class sets x-amz-storage-class HTTP header. Defaults to 'STANDARD'. Or, 'REDUCED_REDUNDANCY'
# @option options [String] encryption sets HTTP encryption header. Set to 'AES256' to encrypt files at rest on S3
+ # @option options [String] tags sets x-amz-tagging HTTP header. For example, 'Org-Id=1' or 'Org-Id=1&Service=MyService'
# @return [Boolean] true if no errors
#
def save(options = {})
@@ -208,6 +210,7 @@ module Fog
options['Expires'] = expires if expires
options.merge!(metadata)
options['x-amz-storage-class'] = storage_class if storage_class
+ options['x-amz-tagging'] = tags if tags
options.merge!(encryption_headers)
# With a single PUT operation you can upload objects up to 5 GB in size. Automatically set MP for larger objects.
diff --git a/lib/fog/aws/parsers/storage/get_object_tagging.rb b/lib/fog/aws/parsers/storage/get_object_tagging.rb
new file mode 100644
index 000000000..94fae7feb
--- /dev/null
+++ b/lib/fog/aws/parsers/storage/get_object_tagging.rb
@@ -0,0 +1,33 @@
+module Fog
+ module Parsers
+ module AWS
+ module Storage
+ class GetObjectTagging < Fog::Parsers::Base
+ def reset
+ @in_tag = {}
+ @response = {'ObjectTagging' => {}}
+ end
+
+ def start_element(name, *args)
+ super
+ if name == 'Tag'
+ @in_tag = {}
+ end
+ end
+
+ def end_element(name)
+ case name
+ when 'Tag'
+ @response['ObjectTagging'].merge!(@in_tag)
+ @in_tag = {}
+ when 'Key'
+ @in_tag[value] = nil
+ when 'Value'
+ @in_tag = {@in_tag.keys.first => value}
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/aws/requests/storage/get_object_tagging.rb b/lib/fog/aws/requests/storage/get_object_tagging.rb
new file mode 100644
index 000000000..c14f07078
--- /dev/null
+++ b/lib/fog/aws/requests/storage/get_object_tagging.rb
@@ -0,0 +1,41 @@
+module Fog
+ module AWS
+ class Storage
+ class Real
+ require 'fog/aws/parsers/storage/get_object_tagging'
+
+ # Get tags for an S3 object
+ #
+ # @param bucket_name [String] Name of bucket to read from
+ # @param object_name [String] Name of object to get tags for
+ #
+ # @return [Excon::Response] response:
+ # * body [Hash]:
+ # * ObjectTagging [Hash]:
+ # * Key [String] - tag key
+ # * Value [String] - tag value
+ # @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html
+
+ def get_object_tagging(bucket_name, object_name)
+ unless bucket_name
+ raise ArgumentError.new('bucket_name is required')
+ end
+ unless object_name
+ raise ArgumentError.new('object_name is required')
+ end
+
+ request({
+ :expects => 200,
+ :headers => {},
+ :bucket_name => bucket_name,
+ :object_name => object_name,
+ :idempotent => true,
+ :method => 'GET',
+ :parser => Fog::Parsers::AWS::Storage::GetObjectTagging.new,
+ :query => {'tagging' => nil}
+ })
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/aws/requests/storage/put_object_tagging.rb b/lib/fog/aws/requests/storage/put_object_tagging.rb
new file mode 100644
index 000000000..d6d5aed37
--- /dev/null
+++ b/lib/fog/aws/requests/storage/put_object_tagging.rb
@@ -0,0 +1,42 @@
+module Fog
+ module AWS
+ class Storage
+ class Real
+ # Change tag set for an S3 object
+ #
+ # @param bucket_name [String] Name of bucket to modify object in
+ # @param object_name [String] Name of object to modify
+ #
+ # @param tags [Hash]:
+ # * Key [String]: tag key
+ # * Value [String]: tag value
+ #
+ # @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html
+
+ def put_object_tagging(bucket_name, object_name, tags)
+ tagging = tags.map do |k,v|
+ "#{k}#{v}"
+ end.join("\n")
+ data =
+ <<-DATA
+
+
+ #{tagging}
+
+
+ DATA
+
+ request({
+ :body => data,
+ :expects => 200,
+ :headers => {'Content-MD5' => Base64.encode64(OpenSSL::Digest::MD5.digest(data)).chomp!, 'Content-Type' => 'application/xml'},
+ :bucket_name => bucket_name,
+ :object_name => object_name,
+ :method => 'PUT',
+ :query => {'tagging' => nil}
+ })
+ end
+ end
+ end
+ end
+end
diff --git a/lib/fog/aws/storage.rb b/lib/fog/aws/storage.rb
index b9fd1f876..1df27637d 100644
--- a/lib/fog/aws/storage.rb
+++ b/lib/fog/aws/storage.rb
@@ -84,6 +84,7 @@ module Fog
request :get_object_http_url
request :get_object_https_url
request :get_object_url
+ request :get_object_tagging
request :get_request_payment
request :get_service
request :head_bucket
@@ -107,6 +108,7 @@ module Fog
request :put_object
request :put_object_acl
request :put_object_url
+ request :put_object_tagging
request :put_request_payment
request :sync_clock
request :upload_part