mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
[aws|storage] first pass at multipart uploads
This commit is contained in:
parent
cd7a6771e1
commit
6d7f859c34
15 changed files with 635 additions and 11 deletions
24
lib/fog/aws/parsers/storage/complete_multipart_upload.rb
Normal file
24
lib/fog/aws/parsers/storage/complete_multipart_upload.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module AWS
|
||||
module Storage
|
||||
|
||||
class CompleteMultipartUpload < Fog::Parsers::Base
|
||||
|
||||
def reset
|
||||
@response = {}
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'Bucket', 'ETag', 'Key', 'Location'
|
||||
@response[name] = @value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
lib/fog/aws/parsers/storage/initiate_multipart_upload.rb
Normal file
24
lib/fog/aws/parsers/storage/initiate_multipart_upload.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module AWS
|
||||
module Storage
|
||||
|
||||
class InitiateMultipartUpload < Fog::Parsers::Base
|
||||
|
||||
def reset
|
||||
@response = {}
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'Bucket', 'Key', 'UploadId'
|
||||
@response[name] = @value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
56
lib/fog/aws/parsers/storage/list_multipart_uploads.rb
Normal file
56
lib/fog/aws/parsers/storage/list_multipart_uploads.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module AWS
|
||||
module Storage
|
||||
|
||||
class ListMultipartUploads < Fog::Parsers::Base
|
||||
|
||||
def reset
|
||||
@upload = { 'Initiator' => {}, 'Owner' => {} }
|
||||
@response = { 'Upload' => [] }
|
||||
end
|
||||
|
||||
def start_element(name, attrs = [])
|
||||
super
|
||||
case name
|
||||
when 'Initiator'
|
||||
@in_initiator = true
|
||||
when 'Owner'
|
||||
@in_owner = true
|
||||
end
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'Bucket', 'KeyMarker', 'NextKeyMarker', 'NextUploadIdMarker', 'UploadIdMarker'
|
||||
@response[name] = @value
|
||||
when 'DisplayName', 'ID'
|
||||
if @in_initiator
|
||||
@upload['Initiator'][name] = @value
|
||||
elsif @in_owner
|
||||
@upload['Owner'][name] = @value
|
||||
end
|
||||
when 'Initiated'
|
||||
@upload[name] = Time.parse(@value)
|
||||
when 'Initiator'
|
||||
@in_initiator = false
|
||||
when 'IsTruncated'
|
||||
@response[name] = @value == 'true'
|
||||
when 'Key', 'StorageClass', 'UploadId'
|
||||
@upload[name] = @value
|
||||
when 'MaxUploads'
|
||||
@response[name] = @value.to_i
|
||||
when 'Owner'
|
||||
@in_owner = false
|
||||
when 'Upload'
|
||||
@response['Upload'] << @upload
|
||||
@upload = { 'Initiator' => {}, 'Owner' => {} }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
40
lib/fog/aws/parsers/storage/list_parts.rb
Normal file
40
lib/fog/aws/parsers/storage/list_parts.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module AWS
|
||||
module Storage
|
||||
|
||||
class ListParts < Fog::Parsers::Base
|
||||
|
||||
def reset
|
||||
@part = {}
|
||||
@response = { 'Initiator' => {}, 'Part' => [] }
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'Bucket', 'Key', 'NextPartNumberMarker', 'PartNumberMarker', 'StorageClass', 'UploadId'
|
||||
@response[name] = @value
|
||||
when 'DisplayName', 'ID'
|
||||
@response['Initiator'][name] = @value
|
||||
when 'ETag'
|
||||
@part[name] = @value
|
||||
when 'IsTruncated'
|
||||
@response[name] = @value == 'true'
|
||||
when 'LastModified'
|
||||
@part[name] = Time.parse(@value)
|
||||
when 'MaxParts'
|
||||
@response[name] = @value.to_i
|
||||
when 'Part'
|
||||
@response['Part'] << @part
|
||||
@part = {}
|
||||
when 'PartNumber', 'Size'
|
||||
@part[name] = @value.to_i
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
38
lib/fog/aws/requests/storage/abort_multipart_upload.rb
Normal file
38
lib/fog/aws/requests/storage/abort_multipart_upload.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Fog
|
||||
module AWS
|
||||
class Storage
|
||||
class Real
|
||||
|
||||
# Abort a multipart upload
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to abort multipart upload on
|
||||
# * object_name<~String> - Name of object to abort multipart upload on
|
||||
# * upload_id<~String> - Id of upload to add part to
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadAbort.html
|
||||
#
|
||||
def abort_multipart_upload(bucket_name, object_name, upload_id)
|
||||
request({
|
||||
:expects => 204,
|
||||
:headers => {},
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:method => 'DELETE',
|
||||
:path => CGI.escape(object_name),
|
||||
:query => {'uploadId' => upload_id}
|
||||
})
|
||||
end
|
||||
|
||||
end # Real
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def abort_multipart_upload(bucket_name, object_name, upload_id)
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end # Mock
|
||||
end # Storage
|
||||
end # AWS
|
||||
end # Fog
|
60
lib/fog/aws/requests/storage/complete_multipart_upload.rb
Normal file
60
lib/fog/aws/requests/storage/complete_multipart_upload.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
module Fog
|
||||
module AWS
|
||||
class Storage
|
||||
class Real
|
||||
|
||||
require 'fog/aws/parsers/storage/complete_multipart_upload'
|
||||
|
||||
# Complete a multipart upload
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to complete multipart upload for
|
||||
# * object_name<~String> - Name of object to complete multipart upload for
|
||||
# * upload_id<~String> - Id of upload to add part to
|
||||
# * parts<~Array>: Array of etags for parts
|
||||
# * :etag<~String> - Etag for this part
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * headers<~Hash>:
|
||||
# * 'Bucket'<~String> - bucket of new object
|
||||
# * 'ETag'<~String> - etag of new object (will be needed to complete upload)
|
||||
# * 'Key'<~String> - key of new object
|
||||
# * 'Location'<~String> - location of new object
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadComplete.html
|
||||
#
|
||||
def complete_multipart_upload(bucket_name, object_name, upload_id, parts)
|
||||
data = "<CompleteMultipartUpload>"
|
||||
parts.each_with_index do |part, index|
|
||||
data << "<Part>"
|
||||
data << "<PartNumber>#{index + 1}</PartNumber>"
|
||||
data << "<ETag>#{part}</ETag>"
|
||||
data << "</Part>"
|
||||
end
|
||||
data << "</CompleteMultipartUpload>"
|
||||
request({
|
||||
:body => data,
|
||||
:expects => 200,
|
||||
:headers => { 'Content-Length' => data.length },
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:method => 'POST',
|
||||
:parser => Fog::Parsers::AWS::Storage::CompleteMultipartUpload.new,
|
||||
:path => CGI.escape(object_name),
|
||||
:query => {'uploadId' => upload_id}
|
||||
})
|
||||
end
|
||||
|
||||
end # Real
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def complete_multipart_upload(bucket_name, object_name, upload_id, parts)
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end # Mock
|
||||
end # Storage
|
||||
end # AWS
|
||||
end # Fog
|
|
@ -19,7 +19,7 @@ module Fog
|
|||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTServiceGET.html
|
||||
|
||||
#
|
||||
def get_service
|
||||
request({
|
||||
:expects => 200,
|
||||
|
|
55
lib/fog/aws/requests/storage/initiate_multipart_upload.rb
Normal file
55
lib/fog/aws/requests/storage/initiate_multipart_upload.rb
Normal file
|
@ -0,0 +1,55 @@
|
|||
module Fog
|
||||
module AWS
|
||||
class Storage
|
||||
class Real
|
||||
|
||||
require 'fog/aws/parsers/storage/initiate_multipart_upload'
|
||||
|
||||
# Initiate a multipart upload to an S3 bucket
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to create object in
|
||||
# * object_name<~String> - Name of object to create
|
||||
# * options<~Hash>:
|
||||
# * 'Cache-Control'<~String> - Caching behaviour
|
||||
# * 'Content-Disposition'<~String> - Presentational information for the object
|
||||
# * 'Content-Encoding'<~String> - Encoding of object data
|
||||
# * 'Content-MD5'<~String> - Base64 encoded 128-bit MD5 digest of message (defaults to Base64 encoded MD5 of object.read)
|
||||
# * 'Content-Type'<~String> - Standard MIME type describing contents (defaults to MIME::Types.of.first)
|
||||
# * 'x-amz-acl'<~String> - Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read']
|
||||
# * "x-amz-meta-#{name}" - Headers to be returned with object, note total size of request without body must be less than 8 KB.
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>:
|
||||
# * 'Bucket'<~String> - Bucket where upload was initiated
|
||||
# * 'Key'<~String> - Object key where the upload was initiated
|
||||
# * 'UploadId'<~String> - Id for initiated multipart upload
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadInitiate.html
|
||||
#
|
||||
def initiate_multipart_upload(bucket_name, object_name, options = {})
|
||||
request({
|
||||
:expects => 200,
|
||||
:headers => options,
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:method => 'POST',
|
||||
:parser => Fog::Parsers::AWS::Storage::InitiateMultipartUpload.new,
|
||||
:path => CGI.escape(object_name),
|
||||
:query => {'uploads' => nil}
|
||||
})
|
||||
end
|
||||
|
||||
end # Real
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def initiate_multipart_upload(bucket_name, object_name, options = {})
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end # Mock
|
||||
end # Storage
|
||||
end # AWS
|
||||
end # Fog
|
68
lib/fog/aws/requests/storage/list_multipart_uploads.rb
Normal file
68
lib/fog/aws/requests/storage/list_multipart_uploads.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
module Fog
|
||||
module AWS
|
||||
class Storage
|
||||
class Real
|
||||
|
||||
require 'fog/aws/parsers/storage/list_multipart_uploads'
|
||||
|
||||
# List multipart uploads for a bucket
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to list multipart uploads for
|
||||
# * upload_id<~String> - upload id to list objects for
|
||||
# * options<~Hash> - config arguments for list. Defaults to {}.
|
||||
# * 'key-marker'<~String> - limits parts to only those that appear
|
||||
# lexicographically after this key.
|
||||
# * 'max-uploads'<~Integer> - limits number of uploads returned
|
||||
# * 'upload-id-marker'<~String> - limits uploads to only those that appear
|
||||
# lexicographically after this upload id.
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>:
|
||||
# * 'Bucket'<~string> - Bucket where the multipart upload was initiated
|
||||
# * 'IsTruncated'<~Boolean> - Whether or not the listing is truncated
|
||||
# * 'KeyMarker'<~String> - first key in list, only upload ids after this lexographically will appear
|
||||
# * 'MaxUploads'<~Integer> - Maximum results to return
|
||||
# * 'NextKeyMarker'<~String> - last key in list, for further pagination
|
||||
# * 'NextUploadIdMarker'<~String> - last key in list, for further pagination
|
||||
# * 'Upload'<~Hash>:
|
||||
# * 'Initiated'<~Time> - Time when upload was initiated
|
||||
# * 'Initiator'<~Hash>:
|
||||
# * 'DisplayName'<~String> - Display name of upload initiator
|
||||
# * 'ID'<~String> - Id of upload initiator
|
||||
# * 'Key'<~String> - Key where multipart upload was initiated
|
||||
# * 'Owner'<~Hash>:
|
||||
# * 'DisplayName'<~String> - Display name of upload owner
|
||||
# * 'ID'<~String> - Id of upload owner
|
||||
# * 'StorageClass'<~String> - Storage class of object
|
||||
# * 'UploadId'<~String> - upload id of upload containing part
|
||||
# * 'UploadIdMarker'<String> - first key in list, only upload ids after this lexographically will appear
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListMPUpload.html
|
||||
#
|
||||
def list_multipart_uploads(bucket_name, options = {})
|
||||
request({
|
||||
:expects => 200,
|
||||
:headers => {},
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:idempotent => true,
|
||||
:method => 'GET',
|
||||
:parser => Fog::Parsers::AWS::Storage::ListMultipartUploads.new,
|
||||
:query => options.merge!({'uploads' => nil})
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def list_multipart_uploads(bucket_name, options = {})
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
67
lib/fog/aws/requests/storage/list_parts.rb
Normal file
67
lib/fog/aws/requests/storage/list_parts.rb
Normal file
|
@ -0,0 +1,67 @@
|
|||
module Fog
|
||||
module AWS
|
||||
class Storage
|
||||
class Real
|
||||
|
||||
require 'fog/aws/parsers/storage/list_parts'
|
||||
|
||||
# List parts for a multipart upload
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to list parts for
|
||||
# * object_name<~String> - Name of object to list parts for
|
||||
# * upload_id<~String> - upload id to list objects for
|
||||
# * options<~Hash> - config arguments for list. Defaults to {}.
|
||||
# * 'max-parts'<~Integer> - limits number of parts returned
|
||||
# * 'part-number-marker'<~String> - limits parts to only those that appear
|
||||
# lexicographically after this part number.
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>:
|
||||
# * 'Bucket'<~string> - Bucket where the multipart upload was initiated
|
||||
# * 'Initiator'<~Hash>:
|
||||
# * 'DisplayName'<~String> - Display name of upload initiator
|
||||
# * 'ID'<~String> - Id of upload initiator
|
||||
# * 'IsTruncated'<~Boolean> - Whether or not the listing is truncated
|
||||
# * 'Key'<~String> - Key where multipart upload was initiated
|
||||
# * 'MaxParts'<~String> - maximum number of replies alllowed in response
|
||||
# * 'NextPartNumberMarker'<~String> - last item in list, for further pagination
|
||||
# * 'Part'<~Array>:
|
||||
# * 'ETag'<~String> - ETag of part
|
||||
# * 'LastModified'<~Timestamp> - Last modified for part
|
||||
# * 'PartNumber'<~String> - Part number for part
|
||||
# * 'Size'<~Integer> - Size of part
|
||||
# * 'PartNumberMarker'<~String> - Part number after which listing begins
|
||||
# * 'StorageClass'<~String> - Storage class of object
|
||||
# * 'UploadId'<~String> - upload id of upload containing part
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListParts.html
|
||||
#
|
||||
def list_parts(bucket_name, object_name, upload_id, options = {})
|
||||
options['uploadId'] = upload_id
|
||||
request({
|
||||
:expects => 200,
|
||||
:headers => {},
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:idempotent => true,
|
||||
:method => 'GET',
|
||||
:parser => Fog::Parsers::AWS::Storage::ListParts.new,
|
||||
:path => CGI.escape(object_name),
|
||||
:query => options.merge!({'uploadId' => upload_id})
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def list_parts(bucket_name, object_name, upload_id, options = {})
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,13 +8,13 @@ module Fog
|
|||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to create object in
|
||||
# * object_name<~String> - Name of object to create
|
||||
# * data<~File> - File or String to create object from
|
||||
# * data<~File||String> - File or String to create object from
|
||||
# * options<~Hash>:
|
||||
# * 'Cache-Control'<~String> - Caching behaviour
|
||||
# * 'Content-Disposition'<~String> - Presentational information for the object
|
||||
# * 'Content-Encoding'<~String> - Encoding of object data
|
||||
# * 'Content-Length'<~String> - Size of object in bytes (defaults to object.read.length)
|
||||
# * 'Content-MD5'<~String> - Base64 encoded 128-bit MD5 digest of message (defaults to Base64 encoded MD5 of object.read)
|
||||
# * 'Content-MD5'<~String> - Base64 encoded 128-bit MD5 digest of message
|
||||
# * 'Content-Type'<~String> - Standard MIME type describing contents (defaults to MIME::Types.of.first)
|
||||
# * 'x-amz-acl'<~String> - Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read']
|
||||
# * "x-amz-meta-#{name}" - Headers to be returned with object, note total size of request without body must be less than 8 KB.
|
||||
|
@ -26,7 +26,7 @@ module Fog
|
|||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html
|
||||
|
||||
#
|
||||
def put_object(bucket_name, object_name, data, options = {})
|
||||
data = parse_data(data)
|
||||
headers = data[:headers].merge!(options)
|
||||
|
|
51
lib/fog/aws/requests/storage/upload_part.rb
Normal file
51
lib/fog/aws/requests/storage/upload_part.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
module Fog
|
||||
module AWS
|
||||
class Storage
|
||||
class Real
|
||||
|
||||
# Upload a part for a multipart upload
|
||||
#
|
||||
# ==== Parameters
|
||||
# * bucket_name<~String> - Name of bucket to add part to
|
||||
# * object_name<~String> - Name of object to add part to
|
||||
# * upload_id<~String> - Id of upload to add part to
|
||||
# * part_number<~String> - Index of part in upload
|
||||
# * data<~File||String> - Content for part
|
||||
# * options<~Hash>:
|
||||
# * 'Content-MD5'<~String> - Base64 encoded 128-bit MD5 digest of message
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * headers<~Hash>:
|
||||
# * 'ETag'<~String> - etag of new object (will be needed to complete upload)
|
||||
#
|
||||
# ==== See Also
|
||||
# http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPart.html
|
||||
#
|
||||
def upload_part(bucket_name, object_name, upload_id, part_number, data, options = {})
|
||||
data = parse_data(data)
|
||||
headers = options
|
||||
headers['Content-Length'] = data[:headers]['Content-Length']
|
||||
request({
|
||||
:body => data[:body],
|
||||
:expects => 200,
|
||||
:headers => headers,
|
||||
:host => "#{bucket_name}.#{@host}",
|
||||
:method => 'PUT',
|
||||
:path => CGI.escape(object_name),
|
||||
:query => {'uploadId' => upload_id, 'partNumber' => part_number}
|
||||
})
|
||||
end
|
||||
|
||||
end # Real
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def upload_part(bucket_name, object_name, upload_id, part_number, data, options = {})
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end # Mock
|
||||
end # Storage
|
||||
end # AWS
|
||||
end # Fog
|
|
@ -11,6 +11,8 @@ module Fog
|
|||
model :file
|
||||
|
||||
request_path 'fog/aws/requests/storage'
|
||||
request :abort_multipart_upload
|
||||
request :complete_multipart_upload
|
||||
request :copy_object
|
||||
request :delete_bucket
|
||||
request :delete_object
|
||||
|
@ -27,6 +29,9 @@ module Fog
|
|||
request :get_request_payment
|
||||
request :get_service
|
||||
request :head_object
|
||||
request :initiate_multipart_upload
|
||||
request :list_multipart_uploads
|
||||
request :list_parts
|
||||
request :post_object_hidden_fields
|
||||
request :put_bucket
|
||||
request :put_bucket_acl
|
||||
|
@ -35,6 +40,7 @@ module Fog
|
|||
request :put_object
|
||||
request :put_object_url
|
||||
request :put_request_payment
|
||||
request :upload_part
|
||||
|
||||
module Utils
|
||||
|
||||
|
@ -219,7 +225,7 @@ DATA
|
|||
for key, value in amz_headers
|
||||
canonical_amz_headers << "#{key}:#{value}\n"
|
||||
end
|
||||
string_to_sign << "#{canonical_amz_headers}"
|
||||
string_to_sign << canonical_amz_headers
|
||||
|
||||
subdomain = params[:host].split(".#{@host}").first
|
||||
unless subdomain =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\.\d{1,3}){3}$))(?:[a-z0-9]|\.(?![\.\-])|\-(?![\.])){1,61}[a-z0-9]$/
|
||||
|
@ -228,7 +234,7 @@ DATA
|
|||
if params[:path]
|
||||
params[:path] = "#{subdomain}/#{params[:path]}"
|
||||
else
|
||||
params[:path] = "#{subdomain}"
|
||||
params[:path] = subdomain
|
||||
end
|
||||
subdomain = nil
|
||||
end
|
||||
|
@ -237,15 +243,15 @@ DATA
|
|||
unless subdomain.nil? || subdomain == @host
|
||||
canonical_resource << "#{CGI.escape(subdomain).downcase}/"
|
||||
end
|
||||
canonical_resource << "#{params[:path]}"
|
||||
canonical_resource << params[:path].to_s
|
||||
canonical_resource << '?'
|
||||
for key in (params[:query] || {}).keys
|
||||
if ['acl', 'location', 'logging', 'requestPayment', 'torrent', 'versions', 'versioning'].include?(key)
|
||||
canonical_resource << "#{key}&"
|
||||
if %w{acl location logging notification partNumber policy requestPayment torrent uploadId uploads versionId versioning versions}.include?(key)
|
||||
canonical_resource << "#{key}#{"=#{params[:query][key]}" unless params[:query][key].nil?}&"
|
||||
end
|
||||
end
|
||||
canonical_resource.chop!
|
||||
string_to_sign << "#{canonical_resource}"
|
||||
string_to_sign << canonical_resource
|
||||
|
||||
signed_string = @hmac.sign(string_to_sign)
|
||||
signature = Base64.encode64(signed_string).chomp!
|
||||
|
|
135
tests/aws/requests/storage/multipart_upload_tests.rb
Normal file
135
tests/aws/requests/storage/multipart_upload_tests.rb
Normal file
|
@ -0,0 +1,135 @@
|
|||
Shindo.tests('AWS::Storage | object requests', ['aws']) do
|
||||
|
||||
@directory = AWS[:storage].directories.create(:key => 'fogmultipartuploadtests')
|
||||
|
||||
tests('success') do
|
||||
|
||||
@initiate_multipart_upload_format = {
|
||||
'Bucket' => String,
|
||||
'Key' => String,
|
||||
'UploadId' => String
|
||||
}
|
||||
|
||||
tests("#initiate_multipart_upload('#{@directory.identity}')", 'fog_multipart_upload').formats(@initiate_multipart_upload_format) do
|
||||
pending if Fog.mocking?
|
||||
data = AWS[:storage].initiate_multipart_upload(@directory.identity, 'fog_multipart_upload').body
|
||||
@upload_id = data['UploadId']
|
||||
data
|
||||
end
|
||||
|
||||
@list_multipart_uploads_format = {
|
||||
'Bucket' => String,
|
||||
'IsTruncated' => Fog::Boolean,
|
||||
'MaxUploads' => Integer,
|
||||
'KeyMarker' => NilClass,
|
||||
'NextKeyMarker' => String,
|
||||
'NextUploadIdMarker' => String,
|
||||
'Upload' => [{
|
||||
'Initiated' => Time,
|
||||
'Initiator' => {
|
||||
'DisplayName' => String,
|
||||
'ID' => String
|
||||
},
|
||||
'Key' => String,
|
||||
'Owner' => {
|
||||
'DisplayName' => String,
|
||||
'ID' => String
|
||||
},
|
||||
'StorageClass' => String,
|
||||
'UploadId' => String
|
||||
}],
|
||||
'UploadIdMarker' => NilClass,
|
||||
}
|
||||
|
||||
tests("#list_multipart_uploads('#{@directory.identity})").formats(@list_multipart_uploads_format) do
|
||||
pending if Fog.mocking?
|
||||
AWS[:storage].list_multipart_uploads(@directory.identity).body
|
||||
end
|
||||
|
||||
@parts = []
|
||||
|
||||
tests("#upload_part('#{@directory.identity}', 'fog_multipart_upload', '#{@upload_id}', 1, ('x' * 6 * 1024 * 1024))").succeeds do
|
||||
pending if Fog.mocking?
|
||||
data = AWS[:storage].upload_part(@directory.identity, 'fog_multipart_upload', @upload_id, 1, ('x' * 6 * 1024 * 1024))
|
||||
@parts << data.headers['ETag']
|
||||
end
|
||||
|
||||
@list_parts_format = {
|
||||
'Bucket' => String,
|
||||
'Initiator' => {
|
||||
'DisplayName' => String,
|
||||
'ID' => String
|
||||
},
|
||||
'IsTruncated' => Fog::Boolean,
|
||||
'Key' => String,
|
||||
'MaxParts' => Integer,
|
||||
'NextPartNumberMarker' => String,
|
||||
'Part' => [{
|
||||
'ETag' => String,
|
||||
'LastModified' => Time,
|
||||
'PartNumber' => Integer,
|
||||
'Size' => Integer
|
||||
}],
|
||||
'PartNumberMarker' => String,
|
||||
'StorageClass' => String,
|
||||
'UploadId' => String
|
||||
}
|
||||
|
||||
tests("#list_parts('#{@directory.identity}', 'fog_multipart_upload', '#{@upload_id}')").formats(@list_parts_format) do
|
||||
pending if Fog.mocking?
|
||||
AWS[:storage].list_parts(@directory.identity, 'fog_multipart_upload', @upload_id).body
|
||||
end
|
||||
|
||||
if !Fog.mocking?
|
||||
@parts << AWS[:storage].upload_part(@directory.identity, 'fog_multipart_upload', @upload_id, 2, ('x' * 4 * 1024 * 1024)).headers['ETag']
|
||||
end
|
||||
|
||||
@complete_multipart_upload_format = {
|
||||
'Bucket' => String,
|
||||
'ETag' => String,
|
||||
'Key' => String,
|
||||
'Location' => String
|
||||
}
|
||||
|
||||
tests("#complete_multipart_upload('#{@directory.identity}', 'fog_multipart_upload', '#{@upload_id}', #{@parts.inspect})").formats(@complete_multipart_upload_format) do
|
||||
pending if Fog.mocking?
|
||||
AWS[:storage].complete_multipart_upload(@directory.identity, 'fog_multipart_upload', @upload_id, @parts).body
|
||||
end
|
||||
|
||||
tests("#get_object('#{@directory.identity}', 'fog_multipart_upload').body").succeeds do
|
||||
pending if Fog.mocking?
|
||||
data = AWS[:storage].get_object(@directory.identity, 'fog_multipart_upload').body
|
||||
unless data == ('x' * 10 * 1024 * 1024)
|
||||
raise 'content mismatch'
|
||||
end
|
||||
end
|
||||
|
||||
if !Fog.mocking?
|
||||
@directory.files.new(:key => 'fog_multipart_upload').destroy
|
||||
end
|
||||
|
||||
if !Fog.mocking?
|
||||
@upload_id = AWS[:storage].initiate_multipart_upload(@directory.identity, 'fog_multipart_abort').body['UploadId']
|
||||
end
|
||||
|
||||
tests("#abort_multipart_upload('#{@directory.identity}', 'fog_multipart_abort', '#{@upload_id}')").succeeds do
|
||||
pending if Fog.mocking?
|
||||
AWS[:storage].abort_multipart_upload(@directory.identity, 'fog_multipart_abort', @upload_id)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
tests('failure') do
|
||||
|
||||
tests("initiate_multipart_upload")
|
||||
tests("list_multipart_uploads")
|
||||
tests("upload_part")
|
||||
tests("list_parts")
|
||||
tests("complete_multipart_upload")
|
||||
tests("abort_multipart_upload")
|
||||
|
||||
end
|
||||
|
||||
@directory.destroy
|
||||
|
||||
end
|
|
@ -49,7 +49,7 @@ module Shindo
|
|||
|
||||
def formats(format)
|
||||
test('has proper format') do
|
||||
formats_kernel(instance_eval(&block), format)
|
||||
formats_kernel(instance_eval(&Proc.new), format)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue