class AWS::S3::Client

Client class for Amazon Simple Storage Service (S3).

Constants

API_VERSION
CACHEABLE_REQUESTS

@private

EMPTY_BODY_ERRORS

@private

XMLNS

Protected Class Methods

bucket_method(method_name, verb, *args, &block) click to toggle source
Calls superclass method
# File lib/aws/s3/client.rb, line 52
def self.bucket_method(method_name, verb, *args, &block)

  method_options = (args.pop if args.last.kind_of?(Hash)) || {}
  xml_grammar = (args.pop if args.last.respond_to?(:rules))
  verb = verb.to_s.upcase
  subresource = args.first

  add_client_request_method(method_name) do

    configure_request do |req, options|

      require_bucket_name!(options[:bucket_name])

      req.http_method = verb
      req.bucket = options[:bucket_name]
      req.add_param(subresource) if subresource

      if header_options = method_options[:header_options]
        header_options.each do |(opt, header)|
          if value = options[opt]
            # for backwards compatability we translate canned acls
            # header values from symbols to strings (e.g.
            # :public_read translates to 'public-read')
            value = (opt == :acl ? value.to_s.tr('_', '-') : value)
            req.headers[header] = value
          end
        end
      end

    end

    instance_eval(&block) if block

    if xml_grammar

      parser = Core::XML::Parser.new(xml_grammar.rules)

      process_response do |resp|
        resp.data = parser.parse(resp.http_response.body)
        super(resp)
      end

      simulate_response do |resp|
        resp.data = parser.simulate
        super(resp)
      end

    end

  end
end
object_method(method_name, verb, *args, &block) click to toggle source
Calls superclass method
# File lib/aws/s3/client.rb, line 104
def self.object_method(method_name, verb, *args, &block)
  bucket_method(method_name, verb, *args) do
    configure_request do |req, options|
      validate_key!(options[:key])
      super(req, options)
      req.key = options[:key]
    end

    instance_eval(&block) if block
  end
end

Protected Instance Methods

extract_error_details(response) click to toggle source
# File lib/aws/s3/client.rb, line 1362
def extract_error_details response
  if
    (response.http_response.status >= 300 ||
      response.request_type == :complete_multipart_upload) and
    body = response.http_response.body and
    error = Core::XML::Parser.parse(body) and
    error[:code]
  then
    [error[:code], error[:message]]
  end
end
extract_object_headers(resp) click to toggle source
# File lib/aws/s3/client.rb, line 1431
def extract_object_headers resp
  meta = {}
  resp.http_response.headers.each_pair do |name,value|
    if name =~ /^x-amz-meta-(.+)$/i
      meta[$1] = [value].flatten.join
    end
  end
  resp.data[:meta] = meta

  if expiry = resp.http_response.headers['x-amz-expiration']
    expiry.first =~ /^expiry-date="(.+)", rule-id="(.+)"$/
    exp_date = DateTime.parse($1)
    exp_rule_id = $2
  else
    exp_date = nil
    exp_rule_id = nil
  end
  resp.data[:expiration_date] = exp_date if exp_date
  resp.data[:expiration_rule_id] = exp_rule_id if exp_rule_id

  restoring = false
  restore_date = nil

  if restore = resp.http_response.headers['x-amz-restore']
    if restore.first =~ /ongoing-request="(.+?)", expiry-date="(.+?)"/
      restoring = $1 == "true"
      restore_date = $2 && DateTime.parse($2)
    elsif restore.first =~ /ongoing-request="(.+?)"/
      restoring = $1 == "true"
    end
  end
  resp.data[:restore_in_progress] = restoring
  resp.data[:restore_expiration_date] = restore_date if restore_date

  {
    'x-amz-version-id' => :version_id,
    'content-type' => :content_type,
    'content-encoding' => :content_encoding,
    'cache-control' => :cache_control,
    'etag' => :etag,
    'x-amz-website-redirect-location' => :website_redirect_location,
    'accept-ranges' => :accept_ranges,
  }.each_pair do |header,method|
    if value = resp.http_response.header(header)
      resp.data[method] = value
    end
  end

  if time = resp.http_response.header('Last-Modified')
    resp.data[:last_modified] = Time.parse(time)
  end

  if length = resp.http_response.header('content-length')
    resp.data[:content_length] = length.to_i
  end

  if sse = resp.http_response.header('x-amz-server-side-encryption')
    resp.data[:server_side_encryption] = sse.downcase.to_sym
  end

end
is_xml?(possible_xml) click to toggle source

@param [String] possible_xml @return [Boolean] Returns true if the given string is a valid xml

document.
# File lib/aws/s3/client.rb, line 1419
def is_xml? possible_xml
  begin
    REXML::Document.new(possible_xml).has_elements?
  rescue
    false
  end
end
md5(str) click to toggle source
# File lib/aws/s3/client.rb, line 1427
def md5 str
  Base64.encode64(Digest::MD5.digest(str)).strip
end
move_access_control_policy(options) click to toggle source

Previously the access control policy could be specified via :acl as a string or an object that responds to to_xml. The prefered method now is to pass :access_control_policy an xml document.

# File lib/aws/s3/client.rb, line 1406
def move_access_control_policy options
  if acl = options[:acl]
    if acl.is_a?(String) and is_xml?(acl)
      options[:access_control_policy] = options.delete(:acl)
    elsif acl.respond_to?(:to_xml)
      options[:access_control_policy] = options.delete(:acl).to_xml
    end
  end
end
new_request() click to toggle source
# File lib/aws/s3/client.rb, line 1396
def new_request
  req = S3::Request.new
  req.force_path_style = config.s3_force_path_style?
  req.service_path = config.s3_service_path
  req
end
populate_error(resp) click to toggle source

There are a few of s3 requests that can generate empty bodies and yet still be errors. These return empty bodies to comply with the HTTP spec. We have to detect these errors specially.

Calls superclass method AWS::Core::Client#populate_error
# File lib/aws/s3/client.rb, line 1377
def populate_error resp
  code = resp.http_response.status
  if EMPTY_BODY_ERRORS.include?(code) and resp.http_response.body.nil?
    error_class = EMPTY_BODY_ERRORS[code]
    resp.error = error_class.new(resp.http_request, resp.http_response)
  else
    super
  end
end
retryable_error?(response) click to toggle source
Calls superclass method AWS::Core::Client#retryable_error?
# File lib/aws/s3/client.rb, line 1387
def retryable_error? response
  super or
    (response.request_type == :complete_multipart_upload &&
    extract_error_details(response))
    # complete multipart upload can return an error inside a
    # 200 level response -- this forces us to parse the
    # response for errors every time
end