Skip to content

Instantly share code, notes, and snippets.

@rob-at-thewebfellas
Created January 29, 2010 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rob-at-thewebfellas/289745 to your computer and use it in GitHub Desktop.
Save rob-at-thewebfellas/289745 to your computer and use it in GitHub Desktop.
Dir[File.join(Rails.root, 'lib', 'patches', '**', '*.rb')].sort.each { |patch| require(patch) }
module AWS
module S3
class Authentication
class CanonicalString
def initialize(request, options = {})
super()
@request = request
@headers = {}
@options = options
# "For non-authenticated or anonymous requests. A NotImplemented error result code will be returned if
# an authenticated (signed) request specifies a Host: header other than 's3.amazonaws.com'"
# (from http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html)
request['Host'] = AWS::S3::Base.connection.subdomain || DEFAULT_HOST
build
end
private
def build
self << "#{request.method}\n"
ensure_date_is_valid
initialize_headers
set_expiry!
headers.sort_by {|k, _| k}.each do |key, value|
value = value.to_s.strip
self << (key =~ self.class.amazon_header_prefix ? "#{key}:#{value}" : value)
self << "\n"
end
self << (AWS::S3::Base.connection.subdomain ? "/#{AWS::S3::Base.connection.subdomain}#{path}" : path)
end
end
end
class Bucket
class << self
private
def path(name, options = {})
if name.is_a?(Hash)
options = name
name = nil
end
bucket_name(name) == connection.subdomain ? "/#{RequestOptions.process(options).to_query_string}" : "/#{bucket_name(name)}#{RequestOptions.process(options).to_query_string}"
end
end
end
class Connection
def subdomain
http.address[/^(.+)\.#{DEFAULT_HOST}$/, 1]
end
end
class S3Object
class << self
def path!(bucket, name, options = {}) #:nodoc:
# We're using the second argument for options
if bucket.is_a?(Hash)
options.replace(bucket)
bucket = nil
end
bucket_name(bucket) == connection.subdomain ? "/#{name}" : "/#{bucket_name(bucket)}/#{name}"
end
end
end
end
end
module Paperclip
module Storage
module S3
# Patch s3 storage initialisation to pass server name to aws/s3
def self.extended(base)
require 'aws/s3'
base.instance_eval do
@s3_credentials = parse_credentials(@options[:s3_credentials])
@bucket = @options[:bucket] || @s3_credentials[:bucket]
@bucket = @bucket.call(self) if @bucket.is_a?(Proc)
@s3_options = @options[:s3_options] || {}
@s3_permissions = @options[:s3_permissions] || :public_read
@s3_protocol = @options[:s3_protocol] || (@s3_permissions == :public_read ? 'http' : 'https')
@s3_headers = @options[:s3_headers] || {}
@s3_host_alias = @options[:s3_host_alias]
@url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
AWS::S3::Base.establish_connection!( @s3_options.merge(
:access_key_id => @s3_credentials[:access_key_id],
:secret_access_key => @s3_credentials[:secret_access_key],
:server => "#{@bucket}.s3.amazonaws.com"
))
end
Paperclip.interpolates(:s3_alias_url) do |attachment, style|
"#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
end
Paperclip.interpolates(:s3_path_url) do |attachment, style|
"#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
end
Paperclip.interpolates(:s3_domain_url) do |attachment, style|
"#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
end
end
# Patch to use binmode on Windows
def to_file(style = default_style)
return @queued_for_write[style] if @queued_for_write[style]
begin
file = Tempfile.new(path(style))
file.binmode if file.respond_to?(:binmode)
file.write(AWS::S3::S3Object.value(path(style), bucket_name))
file.rewind
rescue AWS::S3::NoSuchKey
file.close if file.respond_to?(:close)
file = nil
end
file
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment