Helper to generate form fields for presigned POST requests to a bucket. You can use this to create a form that can be used from a web browser to upload objects to S3 while specifying conditions on what can be uploaded and how it is processed and stored.
@example Form fields for uploading by file name
form = bucket.presigned_post(:key => "photos/${filename}") form.url.to_s # => "https://mybucket.s3.amazonaws.com/" form.fields # => { "AWSAccessKeyId" => "...", ... }
@example Generating a minimal HTML form
form = bucket.objects.myobj.presigned_post hidden_inputs = form.fields.map do |(name, value)| %Q(<input type="hidden" name="#{name}" value="#{value}" />) end "<form action="#{form.url}" method="post" enctype="multipart/form-data"> #{hidden_inputs} <input type="file" name="file" /> </form> "
@example Restricting the size of the uploaded object
bucket.presigned_post(:content_length => 1..(10*1024))
@example Restricting the key prefix
bucket.presigned_post.where(:key).starts_with("photos/")
@private
@return [Bucket] The bucket to which data can be uploaded
using the form fields
@private
@return [Range] The range of acceptable object sizes for the
upload. By default any size object may be uploaded.
@return The expiration time for the signature. By default
the signature will expire an hour after it is generated.
@return [Array<String>] Additional fields which may be sent
with the upload. These will be included in the policy so that they can be sent with any value. S3 will ignore them.
@return [String] The key of the object that will be
uploaded. If this is nil, then the object can be uploaded with any key that satisfies the conditions specified for the upload (see {#where}).
@return [Hash] A hash of the metadata fields included in the
signed fields. Additional metadata fields may be provided with the upload as long as they satisfy the conditions specified for the upload (see {#where}).
Creates a new presigned post object.
@param [Bucket] bucket The bucket to which data can be uploaded
using the form fields.
@param [Hash] opts Additional options for the upload. Aside
from +:secure+, +:expires+, +:content_length+ and +:ignore+ the values provided here will be stored in the hash returned from the {#fields} method, and the policy in that hash will restrict their values to the values provided. If you instead want to only restrict the values and not provide them -- for example, if your application generates separate form fields for those values -- you should use the {#where} method on the returned object instead of providing the values here.
@option opts [String] :key The key of the object that will
be uploaded. If this is nil, then the object can be uploaded with any key that satisfies the conditions specified for the upload (see {#where}).
@option opts [Boolean] :secure By setting this to false, you
can cause {#url} to return an HTTP URL. By default it returns an HTTPS URL.
@option opts [Time, DateTime, Integer, String] :expires The
time at which the signature will expire. By default the signature will expire one hour after it is generated (e.g. when {#fields} is called). When the value is a Time or DateTime, the signature expires at the specified time. When it is an integer, the signature expires the specified number of seconds after it is generated. When it is a string, the string is parsed as a time (using Time.parse) and the signature expires at that time.
@option opts [String] :cache_control Sets the Cache-Control
header stored with the object.
@option opts [String] :content_type Sets the Content-Type
header stored with the object.
@option opts [String] :content_disposition Sets the
Content-Disposition header stored with the object.
@option opts [String] :expires_header Sets the Expires
header stored with the object.
@option options [Symbol] :acl A canned access control
policy. Valid values are: * +:private+ * +:public_read+ * +:public_read_write+ * +:authenticated_read+ * +:bucket_owner_read+ * +:bucket_owner_full_control+
@option options [Symbol] :server_side_encryption (nil) If this
option is set, the object will be stored using server side encryption. The only valid value is +:aes256+, which specifies that the object should be stored using the AES encryption algorithm with 256 bit keys. By default, this option uses the value of the +:s3_server_side_encryption+ option in the current configuration; for more information, see {AWS.config}.
@option opts [String] :success_action_redirect The URL to
which the client is redirected upon successful upload.
@option opts [Integer] :success_action_status The status
code returned to the client upon successful upload if +:success_action_redirect+ is not specified. Accepts the values 200, 201, or 204 (default). If the value is set to 200 or 204, Amazon S3 returns an empty document with a 200 or 204 status code. If the value is set to 201, Amazon S3 returns an XML document with a 201 status code. For information on the content of the XML document, see {POST Object}[http://docs.amazonwebservices.com/AmazonS3/2006-03-01/API/index.html?RESTObjectPOST.html].
@option opts [Hash] :metadata A hash of the metadata fields
included in the signed fields. Additional metadata fields may be provided with the upload as long as they satisfy the conditions specified for the upload (see {#where}).
@option opts [Integer, Range] :#content_length The range of
acceptable object sizes for the upload. By default any size object may be uploaded.
@option opts [Array<String>] :ignore Additional fields which
may be sent with the upload. These will be included in the policy so that they can be sent with any value. S3 will ignore them.
# File lib/aws/s3/presigned_post.rb, line 195 def initialize(bucket, opts = {}) @bucket = bucket @key = opts[:key] @secure = (opts[:secure] != false) @fields = {} SPECIAL_FIELDS.each do |name| @fields[name] = opts[name] if opts.key?(name) end @metadata = opts[:metadata] || {} @content_length = range_value(opts[:content_length]) @conditions = opts[:conditions] || {} @ignored_fields = [opts[:ignore]].flatten.compact @expires = opts[:expires] super @fields[:server_side_encryption] = config.s3_server_side_encryption unless @fields.key?(:server_side_encryption) @fields.delete(:server_side_encryption) if @fields[:server_side_encryption].nil? end
@return [Hash] A collection of form fields (including a
signature and a policy) that can be used to POST data to S3. Additional form fields may be added after the fact as long as they are described by a policy condition (see {#where}).
# File lib/aws/s3/presigned_post.rb, line 342 def fields signature = config.signer.sign(policy, "sha1") fields = { "AWSAccessKeyId" => config.signer.access_key_id, "key" => key, "policy" => policy, "signature" => signature }.merge(optional_fields) fields["x-amz-security-token"] = config.signer.session_token if config.signer.session_token fields.merge(optional_fields) end
@return [String] The Base64-encoded JSON policy document.
# File lib/aws/s3/presigned_post.rb, line 329 def policy json = { "expiration" => format_expiration, "conditions" => generate_conditions }.to_json Base64.encode64(json).tr("\n","") end
@private
# File lib/aws/s3/presigned_post.rb, line 374 def refine(opts) self.class.new(bucket, { :conditions => conditions, :key => key, :metadata => metadata, :secure => secure?, :content_length => content_length, :expires => expires, :ignore => ignored_fields }.merge(@fields). merge(opts)) end
@return [Boolean] True if {url} generates an HTTPS url.
# File lib/aws/s3/presigned_post.rb, line 219 def secure? @secure end
@return [URI::HTTP, URI::HTTPS] The URL to which the form
fields should be POSTed. If you are using the fields in an HTML form, this is the URL to put in the +action+ attribute of the form tag.
# File lib/aws/s3/presigned_post.rb, line 227 def url req = Request.new req.bucket = bucket.name req.host = config.s3_endpoint build_uri(req) end
Adds a condition to the policy for the POST. Use {where_metadata} to add metadata conditions.
@example Restricting the ACL to “bucket-owner” ACLs
presigned_post.where(:acl).starts_with("bucket-owner")
@param [Symbol] field The field for which a condition should
be added. Valid values: * +:key+ * +:content_length+ * +:cache_control+ * +:content_type+ * +:content_disposition+ * +:content_encoding+ * +:expires_header+ * +:acl+ * +:success_action_redirect+ * +:success_action_status+
@return [ConditionBuilder] An object that allows you to
specify a condition on the field.
# File lib/aws/s3/presigned_post.rb, line 305 def where(field) raise ArgumentError.new("unrecognized field name #{field}") unless [:key, :content_length, *SPECIAL_FIELDS].include?(field) or field =~ %r^x-amz-meta-/ ConditionBuilder.new(self, field) end
Adds a condition to the policy for the POST to constrain the values of metadata fields uploaded with the object. If a metadata field does not have a condition associated with it and is not specified in the constructor (see {metadata}) then S3 will reject it.
@param [Symbol, String] field The name of the metadata
attribute. For example, +:color+ corresponds to the "x-amz-meta-color" field in the POST body.
@return [ConditionBuilder] An object that allows you to
specify a condition on the metadata attribute.
# File lib/aws/s3/presigned_post.rb, line 324 def where_metadata(field) where("x-amz-meta-#{field}") end
@private
# File lib/aws/s3/presigned_post.rb, line 361 def with_equality_condition(option_name, value) field_name = field_name(option_name) with_condition(option_name, Hash[[[field_name, value]]]) end
@private
# File lib/aws/s3/presigned_post.rb, line 367 def with_prefix_condition(option_name, prefix) field_name = field_name(option_name) with_condition(option_name, ["starts-with", "$#{field_name}", prefix]) end