lib/S3.rb in moserp-s3sync-1.2.6 vs lib/S3.rb in moserp-s3sync-1.2.6.1
- old
+ new
@@ -31,16 +31,17 @@
# performs the operation, while the second simply outputs urls with the
# appropriate authentication query string parameters, which could be used
# in another tool (such as your web browser for GETs).
module S3
DEFAULT_HOST = 's3.amazonaws.com'
+ DEFAULT_VIRTUAL_PATH = ''
PORTS_BY_SECURITY = { true => 443, false => 80 }
METADATA_PREFIX = 'x-amz-meta-'
AMAZON_HEADER_PREFIX = 'x-amz-'
# builds the canonical string for signing.
- def S3.canonical_string(method, bucket="", path="", path_args={}, headers={}, expires=nil)
+ def S3.canonical_string(method, virtual_path, bucket="", path="", path_args={}, headers={}, expires=nil)
interesting_headers = {}
headers.each do |key, value|
lk = key.downcase
if (lk == 'content-md5' or
lk == 'content-type' or
@@ -72,10 +73,11 @@
else
buf << "#{value}\n"
end
end
+ buf << "#{virtual_path}"
# build the path using the bucket and key
if not bucket.empty?
buf << "/#{bucket}"
end
# append the key (it might be empty string)
@@ -91,11 +93,10 @@
elsif path_args.has_key?('location')
buf << '?location'
elsif path_args.has_key?('logging')
buf << '?logging'
end
-
return buf
end
# encodes the given string with the aws_secret_access_key, by taking the
# hmac-sha1 sum, and then base64 encoding it. optionally, it will also
@@ -135,15 +136,16 @@
# some connection pooling.
class AWSAuthConnection
attr_accessor :calling_format
def initialize(aws_access_key_id, aws_secret_access_key, is_secure=true,
- server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure],
+ server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure], vpath=DEFAULT_VIRTUAL_PATH,
calling_format=CallingFormat::REGULAR)
@aws_access_key_id = aws_access_key_id
@aws_secret_access_key = aws_secret_access_key
@server = server
+ @virtual_path = vpath
@is_secure = is_secure
@calling_format = calling_format
@port = port
end
@@ -219,11 +221,10 @@
return ListAllMyBucketsResponse.new(make_request('GET', '', '', {}, headers))
end
private
def make_request(method, bucket='', key='', path_args={}, headers={}, data='', metadata={})
-
# build the domain based on the calling format
server = ''
if bucket.empty?
# for a bucketless request (i.e. list all buckets)
# revert to regular domain case since this operation
@@ -232,15 +233,15 @@
elsif @calling_format == CallingFormat::SUBDOMAIN
server = "#{bucket}.#{@server}"
elsif @calling_format == CallingFormat::VANITY
server = bucket
else
- server = @server
+ server = "#{@server}"
end
# build the path based on the calling format
- path = ''
+ path = "#{@virtual_path}"
if (not bucket.empty?) and (@calling_format == CallingFormat::REGULAR)
path << "/#{bucket}"
end
# add the slash after the bucket regardless
# the key will be appended if it is non-empty
@@ -258,11 +259,11 @@
req = method_to_request_class(method).new("#{path}")
set_headers(req, headers)
set_headers(req, metadata, METADATA_PREFIX)
- set_aws_auth_header(req, @aws_access_key_id, @aws_secret_access_key, bucket, key, path_args)
+ set_aws_auth_header(req, @aws_access_key_id, @aws_secret_access_key, @virtual_path, bucket, key, path_args)
if req.request_body_permitted?
return http.request(req, data)
else
return http.request(req)
end
@@ -283,22 +284,22 @@
raise "Unsupported method #{method}"
end
end
# set the Authorization header using AWS signed header authentication
- def set_aws_auth_header(request, aws_access_key_id, aws_secret_access_key, bucket='', key='', path_args={})
+ def set_aws_auth_header(request, aws_access_key_id, aws_secret_access_key, virtual_path='', bucket='', key='', path_args={})
# we want to fix the date here if it's not already been done.
request['Date'] ||= Time.now.httpdate
# ruby will automatically add a random content-type on some verbs, so
# here we add a dummy one to 'supress' it. change this logic if having
# an empty content-type header becomes semantically meaningful for any
# other verb.
request['Content-Type'] ||= ''
canonical_string =
- S3.canonical_string(request.method, bucket, key, path_args, request.to_hash, nil)
+ S3.canonical_string(request.method, virtual_path, bucket, key, path_args, request.to_hash, nil)
encoded_canonical = S3.encode(aws_secret_access_key, canonical_string)
request['Authorization'] = "AWS #{aws_access_key_id}:#{encoded_canonical}"
end
@@ -323,16 +324,17 @@
# by default, expire in 1 minute
DEFAULT_EXPIRES_IN = 60
def initialize(aws_access_key_id, aws_secret_access_key, is_secure=true,
- server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure],
+ server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure], vpath=DEFAULT_VIRTUAL_PATH,
format=CallingFormat::REGULAR)
@aws_access_key_id = aws_access_key_id
@aws_secret_access_key = aws_secret_access_key
@protocol = is_secure ? 'https' : 'http'
@server = server
+ @virtual_path = vpath
@port = port
@calling_format = format
# by default expire
@expires_in = DEFAULT_EXPIRES_IN
end
@@ -427,15 +429,15 @@
else
raise "invalid expires state"
end
canonical_string =
- S3::canonical_string(method, bucket, key, path_args, headers, expires)
+ S3::canonical_string(method, @virtual_path, bucket, key, path_args, headers, expires)
encoded_canonical =
S3::encode(@aws_secret_access_key, canonical_string)
- url = CallingFormat.build_url_base(@protocol, @server, @port, bucket, @calling_format)
+ url = CallingFormat.build_url_base(@protocol, @server, @port, @virtual_path, bucket, @calling_format)
path_args["Signature"] = encoded_canonical.to_s
path_args["Expires"] = expires.to_s
path_args["AWSAccessKeyId"] = @aws_access_key_id.to_s
arg_string = S3.path_args_hash_to_string(path_args)
@@ -467,20 +469,20 @@
REGULAR = 0 # http://s3.amazonaws.com/bucket/key
SUBDOMAIN = 1 # http://bucket.s3.amazonaws.com/key
VANITY = 2 # http://<vanity_domain>/key -- vanity_domain resolves to s3.amazonaws.com
# build the url based on the calling format, and bucket
- def CallingFormat.build_url_base(protocol, server, port, bucket, format)
+ def CallingFormat.build_url_base(protocol, server, port, vpath, bucket, format)
build_url_base = "#{protocol}://"
if bucket.empty?
- build_url_base << "#{server}:#{port}"
+ build_url_base << "#{server}:#{port}/${vpath}"
elsif format == SUBDOMAIN
- build_url_base << "#{bucket}.#{server}:#{port}"
+ build_url_base << "#{bucket}.#{server}:#{port}/${vpath}"
elsif format == VANITY
- build_url_base << "#{bucket}:#{port}"
+ build_url_base << "#{bucket}:#{port}/${vpath}"
else
- build_url_base << "#{server}:#{port}/#{bucket}"
+ build_url_base << "#{server}:#{port}/${vpath}/#{bucket}"
end
return build_url_base
end
end
@@ -564,11 +566,13 @@
elsif name == 'Size'
@curr_entry.size = @curr_text.to_i
elsif name == 'StorageClass'
@curr_entry.storage_class = @curr_text
elsif name == 'ID'
+ @curr_entry.owner = Owner.new if !@curr_entry.owner
@curr_entry.owner.id = @curr_text
elsif name == 'DisplayName'
+ @curr_entry.owner = Owner.new if !@curr_entry.owner
@curr_entry.owner.display_name = @curr_text
elsif name == 'CommonPrefixes'
@common_prefixes << @common_prefix_entry
elsif name == 'Prefix'
# this is the common prefix for keys that match up to the delimiter