class AWS::S3::PresignedPost

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/")

Constants

SPECIAL_FIELDS

@private

Attributes

bucket[R]

@return [Bucket] The bucket to which data can be uploaded

using the form fields
conditions[R]

@private

content_length[R]

@return [Range] The range of acceptable object sizes for the

upload.  By default any size object may be uploaded.
expires[R]

@return The expiration time for the signature. By default

the signature will expire an hour after it is generated.
ignored_fields[R]

@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.
key[R]

@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}).
metadata[R]

@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}).

Public Class Methods

new(bucket, opts = {}) click to toggle source

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

Public Instance Methods

fields() click to toggle source

@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
policy() click to toggle source

@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
refine(opts) click to toggle source

@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
secure?() click to toggle source

@return [Boolean] True if {url} generates an HTTPS url.

# File lib/aws/s3/presigned_post.rb, line 219
def secure?
  @secure
end
url() click to toggle source

@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
where(field) click to toggle source

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
where_metadata(field) click to toggle source

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
with_equality_condition(option_name, value) click to toggle source

@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
with_prefix_condition(option_name, prefix) click to toggle source

@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