kerryb-right_aws 1.7.5 → 1.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/ec2/right_ec2.rb CHANGED
@@ -122,7 +122,8 @@ module RightAws
122
122
  service_hash = {"Action" => action,
123
123
  "AWSAccessKeyId" => @aws_access_key_id,
124
124
  "Version" => @@api,
125
- "Timestamp" => Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
125
+ # MODIFIED: from Time.now.utc.stf... for eucalyptus
126
+ "Timestamp" => Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
126
127
  "SignatureVersion" => signature_version }
127
128
  service_hash.update(params)
128
129
  # prepare string to sight
data/lib/s3/right_s3.rb CHANGED
@@ -53,6 +53,14 @@ module RightAws
53
53
  # Create a new handle to an S3 account. All handles share the same per process or per thread
54
54
  # HTTP connection to Amazon S3. Each handle is for a specific account.
55
55
  # The +params+ are passed through as-is to RightAws::S3Interface.new
56
+ #
57
+ # Params is a hash:
58
+ #
59
+ # {:server => 's3.amazonaws.com' # Amazon service host: 's3.amazonaws.com'(default)
60
+ # :port => 443 # Amazon service port: 80 or 443(default)
61
+ # :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
62
+ # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
63
+ # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
56
64
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
57
65
  @interface = S3Interface.new(aws_access_key_id, aws_secret_access_key, params)
58
66
  end
@@ -161,6 +169,36 @@ module RightAws
161
169
  def location
162
170
  @location ||= @s3.interface.bucket_location(@name)
163
171
  end
172
+
173
+ # Retrieves the logging configuration for a bucket.
174
+ # Returns a hash of {:enabled, :targetbucket, :targetprefix}
175
+ #
176
+ # bucket.logging_info()
177
+ # => {:enabled=>true, :targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/"}
178
+ def logging_info
179
+ @s3.interface.get_logging_parse(:bucket => @name)
180
+ end
181
+
182
+ # Enables S3 server access logging on a bucket. The target bucket must have been properly configured to receive server
183
+ # access logs.
184
+ # Params:
185
+ # :targetbucket - either the target bucket object or the name of the target bucket
186
+ # :targetprefix - the prefix under which all logs should be stored
187
+ #
188
+ # bucket.enable_logging(:targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/")
189
+ # => true
190
+ def enable_logging(params)
191
+ AwsUtils.mandatory_arguments([:targetbucket, :targetprefix], params)
192
+ AwsUtils.allow_only([:targetbucket, :targetprefix], params)
193
+ xmldoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"><LoggingEnabled><TargetBucket>#{params[:targetbucket]}</TargetBucket><TargetPrefix>#{params[:targetprefix]}</TargetPrefix></LoggingEnabled></BucketLoggingStatus>"
194
+ @s3.interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
195
+ end
196
+
197
+ # Disables S3 server access logging on a bucket. Takes no arguments.
198
+ def disable_logging
199
+ xmldoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"></BucketLoggingStatus>"
200
+ @s3.interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
201
+ end
164
202
 
165
203
  # Retrieve a group of keys from Amazon.
166
204
  # +options+ is a hash: { 'prefix'=>'', 'marker'=>'', 'max-keys'=>5, 'delimiter'=>'' }).
@@ -32,6 +32,7 @@ module RightAws
32
32
  DEFAULT_HOST = 's3.amazonaws.com'
33
33
  DEFAULT_PORT = 443
34
34
  DEFAULT_PROTOCOL = 'https'
35
+ DEFAULT_SERVICE = '/'
35
36
  REQUEST_TTL = 30
36
37
  DEFAULT_EXPIRES_AFTER = 1 * 24 * 60 * 60 # One day's worth of seconds
37
38
  ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60
@@ -49,7 +50,7 @@ module RightAws
49
50
 
50
51
  # Creates new RightS3 instance.
51
52
  #
52
- # s3 = RightAws::S3Interface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX', {:multi_thread => true, :logger => Logger.new('/tmp/x.log')}) #=> #<RightS3:0xb7b3c27c>
53
+ # s3 = RightAws::S3Interface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX', {:multi_thread => true, :logger => Logger.new('/tmp/x.log')}) #=> #<RightAws::S3Interface:0xb7b3c27c>
53
54
  #
54
55
  # Params is a hash:
55
56
  #
@@ -62,7 +63,8 @@ module RightAws
62
63
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
63
64
  init({ :name => 'S3',
64
65
  :default_host => ENV['S3_URL'] ? URI.parse(ENV['S3_URL']).host : DEFAULT_HOST,
65
- :default_port => ENV['S3_URL'] ? URI.parse(ENV['S3_URL']).port : DEFAULT_PORT,
66
+ :default_port => ENV['S3_URL'] ? URI.parse(ENV['S3_URL']).port : DEFAULT_PORT,
67
+ :default_service => ENV['S3_URL'] ? URI.parse(ENV['S3_URL']).path : DEFAULT_SERVICE,
66
68
  :default_protocol => ENV['S3_URL'] ? URI.parse(ENV['S3_URL']).scheme : DEFAULT_PROTOCOL },
67
69
  aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
68
70
  aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
@@ -95,10 +97,11 @@ module RightAws
95
97
  out_string << '?acl' if path[/[&?]acl($|&|=)/]
96
98
  out_string << '?torrent' if path[/[&?]torrent($|&|=)/]
97
99
  out_string << '?location' if path[/[&?]location($|&|=)/]
98
- # out_string << '?logging' if path[/[&?]logging($|&|=)/] # this one is beta, no support for now
100
+ out_string << '?logging' if path[/[&?]logging($|&|=)/] # this one is beta, no support for now
99
101
  out_string
100
102
  end
101
103
 
104
+ # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?BucketRestrictions.html
102
105
  def is_dns_bucket?(bucket_name)
103
106
  bucket_name = bucket_name.to_s
104
107
  return nil unless (3..63) === bucket_name.size
@@ -107,29 +110,34 @@ module RightAws
107
110
  end
108
111
  true
109
112
  end
110
-
111
- # Generates request hash for REST API.
112
- # Assumes that headers[:url] is URL encoded (use CGI::escape)
113
- def generate_rest_request(method, headers) # :nodoc:
113
+
114
+ def fetch_request_params(headers) #:nodoc:
114
115
  # default server to use
115
- server = @params[:server]
116
- # fix path
117
- path_to_sign = headers[:url]
118
- path_to_sign = "/#{path_to_sign}" unless path_to_sign[/^\//]
116
+ server = @params[:server]
117
+ service = @params[:service].to_s
118
+ service.chop! if service[%r{/$}] # remove trailing '/' from service
119
119
  # extract bucket name and check it's dns compartibility
120
- path_to_sign[%r{^/([a-z0-9._-]*)(/[^?]*)?(\?.+)?}i]
120
+ headers[:url].to_s[%r{^([a-z0-9._-]*)(/[^?]*)?(\?.+)?}i]
121
121
  bucket_name, key_path, params_list = $1, $2, $3
122
122
  # select request model
123
123
  if is_dns_bucket?(bucket_name)
124
- # add backet to a server name
124
+ # fix a path
125
125
  server = "#{bucket_name}.#{server}"
126
- # remove bucket from the path
127
- path = "#{key_path || '/'}#{params_list}"
128
- # refactor the path (add '/' before params_list if the key is empty)
129
- path_to_sign = "/#{bucket_name}#{path}"
126
+ key_path ||= '/'
127
+ path = "#{service}#{key_path}#{params_list}"
130
128
  else
131
- path = path_to_sign
129
+ path = "#{service}/#{bucket_name}#{key_path}#{params_list}"
132
130
  end
131
+ path_to_sign = "#{service}/#{bucket_name}#{key_path}#{params_list}"
132
+ # path_to_sign = "/#{bucket_name}#{key_path}#{params_list}"
133
+ [ server, path, path_to_sign ]
134
+ end
135
+
136
+ # Generates request hash for REST API.
137
+ # Assumes that headers[:url] is URL encoded (use CGI::escape)
138
+ def generate_rest_request(method, headers) # :nodoc:
139
+ # calculate request data
140
+ server, path, path_to_sign = fetch_request_params(headers)
133
141
  data = headers[:data]
134
142
  # remove unset(==optional) and symbolyc keys
135
143
  headers.each{ |key, value| headers.delete(key) if (value.nil? || key.is_a?(Symbol)) }
@@ -147,10 +155,12 @@ module RightAws
147
155
  # set other headers
148
156
  request['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
149
157
  # prepare output hash
158
+
150
159
  { :request => request,
151
160
  :server => server,
152
161
  :port => @params[:port],
153
- :protocol => @params[:protocol] }
162
+ :protocol => @params[:protocol],
163
+ :proxy => @params[:proxy] }
154
164
  end
155
165
 
156
166
  # Sends request to Amazon and parses the response.
@@ -189,8 +199,8 @@ module RightAws
189
199
  unless headers[:location].blank?
190
200
  data = "<CreateBucketConfiguration><LocationConstraint>#{headers[:location].to_s.upcase}</LocationConstraint></CreateBucketConfiguration>"
191
201
  end
192
- req_hash = generate_rest_request('PUT', headers.merge(:url=>bucket, :data => data, 'content-length' => ((data && data.size) || 0).to_s))
193
- request_info(req_hash, S3TrueParser.new)
202
+ req_hash = generate_rest_request('PUT', headers.merge(:url=>bucket, :data => data))
203
+ request_info(req_hash, RightHttp2xxParser.new)
194
204
  rescue Exception => e
195
205
  # if the bucket exists AWS returns an error for the location constraint interface. Drop it
196
206
  e.is_a?(RightAws::AwsError) && e.message.include?('BucketAlreadyOwnedByYou') ? true : on_exception
@@ -211,6 +221,37 @@ module RightAws
211
221
  on_exception
212
222
  end
213
223
 
224
+ # Retrieves the logging configuration for a bucket.
225
+ # Returns a hash of {:enabled, :targetbucket, :targetprefix}
226
+ #
227
+ # s3.interface.get_logging_parse(:bucket => "asset_bucket")
228
+ # => {:enabled=>true, :targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/"}
229
+ #
230
+ #
231
+ def get_logging_parse(params)
232
+ AwsUtils.mandatory_arguments([:bucket], params)
233
+ AwsUtils.allow_only([:bucket, :headers], params)
234
+ params[:headers] = {} unless params[:headers]
235
+ req_hash = generate_rest_request('GET', params[:headers].merge(:url=>"#{params[:bucket]}?logging"))
236
+ request_info(req_hash, S3LoggingParser.new)
237
+ rescue
238
+ on_exception
239
+ end
240
+
241
+ # Sets logging configuration for a bucket from the XML configuration document.
242
+ # params:
243
+ # :bucket
244
+ # :xmldoc
245
+ def put_logging(params)
246
+ AwsUtils.mandatory_arguments([:bucket,:xmldoc], params)
247
+ AwsUtils.allow_only([:bucket,:xmldoc, :headers], params)
248
+ params[:headers] = {} unless params[:headers]
249
+ req_hash = generate_rest_request('PUT', params[:headers].merge(:url=>"#{params[:bucket]}?logging", :data => params[:xmldoc]))
250
+ request_info(req_hash, S3TrueParser.new)
251
+ rescue
252
+ on_exception
253
+ end
254
+
214
255
  # Deletes new bucket. Bucket must be empty! Returns +true+ or an exception.
215
256
  #
216
257
  # s3.delete_bucket('my_awesome_bucket') #=> true
@@ -219,7 +260,7 @@ module RightAws
219
260
  #
220
261
  def delete_bucket(bucket, headers={})
221
262
  req_hash = generate_rest_request('DELETE', headers.merge(:url=>bucket))
222
- request_info(req_hash, S3TrueParser.new)
263
+ request_info(req_hash, RightHttp2xxParser.new)
223
264
  rescue
224
265
  on_exception
225
266
  end
@@ -349,6 +390,7 @@ module RightAws
349
390
  # a text mode IO object is passed to PUT, it will be converted to binary
350
391
  # mode.
351
392
  #
393
+
352
394
  def put(bucket, key, data=nil, headers={})
353
395
  # On Windows, if someone opens a file in text mode, we must reset it so
354
396
  # to binary mode for streaming to work properly
@@ -360,11 +402,91 @@ module RightAws
360
402
  headers['expect'] = '100-continue'
361
403
  end
362
404
  req_hash = generate_rest_request('PUT', headers.merge(:url=>"#{bucket}/#{CGI::escape key}", :data=>data))
363
- request_info(req_hash, S3TrueParser.new)
405
+ request_info(req_hash, RightHttp2xxParser.new)
406
+ rescue
407
+ on_exception
408
+ end
409
+
410
+
411
+
412
+ # New experimental API for uploading objects, introduced in RightAws 1.8.1.
413
+ # store_object is similar in function to the older function put, but returns the full response metadata. It also allows for optional verification
414
+ # of object md5 checksums on upload. Parameters are passed as hash entries and are checked for completeness as well as for spurious arguments.
415
+ # The hash of the response headers contains useful information like the Amazon request ID and the object ETag (MD5 checksum).
416
+ #
417
+ # If the optional :md5 argument is provided, store_object verifies that the given md5 matches the md5 returned by S3. The :verified_md5 field in the response hash is
418
+ # set true or false depending on the outcome of this check. If no :md5 argument is given, :verified_md5 will be false in the response.
419
+ #
420
+ # The optional argument of :headers allows the caller to specify arbitrary request header values.
421
+ #
422
+ # s3.store_object(:bucket => "foobucket", :key => "foo", :md5 => "a507841b1bc8115094b00bbe8c1b2954", :data => "polemonium" )
423
+ # => {"x-amz-id-2"=>"SVsnS2nfDaR+ixyJUlRKM8GndRyEMS16+oZRieamuL61pPxPaTuWrWtlYaEhYrI/",
424
+ # "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
425
+ # "date"=>"Mon, 29 Sep 2008 18:57:46 GMT",
426
+ # :verified_md5=>true,
427
+ # "x-amz-request-id"=>"63916465939995BA",
428
+ # "server"=>"AmazonS3",
429
+ # "content-length"=>"0"}
430
+ #
431
+ # s3.store_object(:bucket => "foobucket", :key => "foo", :data => "polemonium" )
432
+ # => {"x-amz-id-2"=>"MAt9PLjgLX9UYJ5tV2fI/5dBZdpFjlzRVpWgBDpvZpl+V+gJFcBMW2L+LBstYpbR",
433
+ # "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
434
+ # "date"=>"Mon, 29 Sep 2008 18:58:56 GMT",
435
+ # :verified_md5=>false,
436
+ # "x-amz-request-id"=>"3B25A996BC2CDD3B",
437
+ # "server"=>"AmazonS3",
438
+ # "content-length"=>"0"}
439
+
440
+ def store_object(params)
441
+ AwsUtils.allow_only([:bucket, :key, :data, :headers, :md5], params)
442
+ AwsUtils.mandatory_arguments([:bucket, :key, :data], params)
443
+ params[:headers] = {} unless params[:headers]
444
+
445
+ params[:data].binmode if(params[:data].respond_to?(:binmode)) # On Windows, if someone opens a file in text mode, we must reset it to binary mode for streaming to work properly
446
+ if (params[:data].respond_to?(:lstat) && params[:data].lstat.size >= USE_100_CONTINUE_PUT_SIZE) ||
447
+ (params[:data].respond_to?(:size) && params[:data].size >= USE_100_CONTINUE_PUT_SIZE)
448
+ params[:headers]['expect'] = '100-continue'
449
+ end
450
+
451
+ req_hash = generate_rest_request('PUT', params[:headers].merge(:url=>"#{params[:bucket]}/#{CGI::escape params[:key]}", :data=>params[:data]))
452
+ resp = request_info(req_hash, S3HttpResponseHeadParser.new)
453
+ if(params[:md5])
454
+ resp[:verified_md5] = (resp['etag'].gsub(/\"/, '') == params[:md5]) ? true : false
455
+ else
456
+ resp[:verified_md5] = false
457
+ end
458
+ resp
364
459
  rescue
365
460
  on_exception
366
461
  end
367
462
 
463
+ # Identical in function to store_object, but requires verification that the returned ETag is identical to the checksum passed in by the user as the 'md5' argument.
464
+ # If the check passes, returns the response metadata with the "verified_md5" field set true. Raises an exception if the checksums conflict.
465
+ # This call is implemented as a wrapper around store_object and the user may gain different semantics by creating a custom wrapper.
466
+ #
467
+ # s3.store_object_and_verify(:bucket => "foobucket", :key => "foo", :md5 => "a507841b1bc8115094b00bbe8c1b2954", :data => "polemonium" )
468
+ # => {"x-amz-id-2"=>"IZN3XsH4FlBU0+XYkFTfHwaiF1tNzrm6dIW2EM/cthKvl71nldfVC0oVQyydzWpb",
469
+ # "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
470
+ # "date"=>"Mon, 29 Sep 2008 18:38:32 GMT",
471
+ # :verified_md5=>true,
472
+ # "x-amz-request-id"=>"E8D7EA4FE00F5DF7",
473
+ # "server"=>"AmazonS3",
474
+ # "content-length"=>"0"}
475
+ #
476
+ # s3.store_object_and_verify(:bucket => "foobucket", :key => "foo", :md5 => "a507841b1bc8115094b00bbe8c1b2953", :data => "polemonium" )
477
+ # RightAws::AwsError: Uploaded object failed MD5 checksum verification: {"x-amz-id-2"=>"HTxVtd2bf7UHHDn+WzEH43MkEjFZ26xuYvUzbstkV6nrWvECRWQWFSx91z/bl03n",
478
+ # "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
479
+ # "date"=>"Mon, 29 Sep 2008 18:38:41 GMT",
480
+ # :verified_md5=>false,
481
+ # "x-amz-request-id"=>"0D7ADE09F42606F2",
482
+ # "server"=>"AmazonS3",
483
+ # "content-length"=>"0"}
484
+ def store_object_and_verify(params)
485
+ AwsUtils.mandatory_arguments([:md5], params)
486
+ r = store_object(params)
487
+ r[:verified_md5] ? (return r) : (raise AwsError.new("Uploaded object failed MD5 checksum verification: #{r.inspect}"))
488
+ end
489
+
368
490
  # Retrieves object data from Amazon. Returns a +hash+ or an exception.
369
491
  #
370
492
  # s3.get('my_awesome_bucket', 'log/curent/1.log') #=>
@@ -398,6 +520,72 @@ module RightAws
398
520
  rescue
399
521
  on_exception
400
522
  end
523
+
524
+ # New experimental API for retrieving objects, introduced in RightAws 1.8.1.
525
+ # retrieve_object is similar in function to the older function get. It allows for optional verification
526
+ # of object md5 checksums on retrieval. Parameters are passed as hash entries and are checked for completeness as well as for spurious arguments.
527
+ #
528
+ # If the optional :md5 argument is provided, retrieve_object verifies that the given md5 matches the md5 returned by S3. The :verified_md5 field in the response hash is
529
+ # set true or false depending on the outcome of this check. If no :md5 argument is given, :verified_md5 will be false in the response.
530
+ #
531
+ # The optional argument of :headers allows the caller to specify arbitrary request header values.
532
+ # Mandatory arguments:
533
+ # :bucket - the bucket in which the object is stored
534
+ # :key - the object address (or path) within the bucket
535
+ # Optional arguments:
536
+ # :headers - hash of additional HTTP headers to include with the request
537
+ # :md5 - MD5 checksum against which to verify the retrieved object
538
+ #
539
+ # s3.retrieve_object(:bucket => "foobucket", :key => "foo")
540
+ # => {:verified_md5=>false,
541
+ # :headers=>{"last-modified"=>"Mon, 29 Sep 2008 18:58:56 GMT",
542
+ # "x-amz-id-2"=>"2Aj3TDz6HP5109qly//18uHZ2a1TNHGLns9hyAtq2ved7wmzEXDOPGRHOYEa3Qnp",
543
+ # "content-type"=>"",
544
+ # "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
545
+ # "date"=>"Tue, 30 Sep 2008 00:52:44 GMT",
546
+ # "x-amz-request-id"=>"EE4855DE27A2688C",
547
+ # "server"=>"AmazonS3",
548
+ # "content-length"=>"10"},
549
+ # :object=>"polemonium"}
550
+ #
551
+ # s3.retrieve_object(:bucket => "foobucket", :key => "foo", :md5=>'a507841b1bc8115094b00bbe8c1b2954')
552
+ # => {:verified_md5=>true,
553
+ # :headers=>{"last-modified"=>"Mon, 29 Sep 2008 18:58:56 GMT",
554
+ # "x-amz-id-2"=>"mLWQcI+VuKVIdpTaPXEo84g0cz+vzmRLbj79TS8eFPfw19cGFOPxuLy4uGYVCvdH",
555
+ # "content-type"=>"", "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
556
+ # "date"=>"Tue, 30 Sep 2008 00:53:08 GMT",
557
+ # "x-amz-request-id"=>"6E7F317356580599",
558
+ # "server"=>"AmazonS3",
559
+ # "content-length"=>"10"},
560
+ # :object=>"polemonium"}
561
+ # If a block is provided, yields incrementally to the block as
562
+ # the response is read. For large responses, this function is ideal as
563
+ # the response can be 'streamed'. The hash containing header fields is
564
+ # still returned.
565
+ def retrieve_object(params, &block)
566
+ AwsUtils.mandatory_arguments([:bucket, :key], params)
567
+ AwsUtils.allow_only([:bucket, :key, :headers, :md5], params)
568
+ params[:headers] = {} unless params[:headers]
569
+ req_hash = generate_rest_request('GET', params[:headers].merge(:url=>"#{params[:bucket]}/#{CGI::escape params[:key]}"))
570
+ resp = request_info(req_hash, S3HttpResponseBodyParser.new, &block)
571
+ resp[:verified_md5] = false
572
+ if(params[:md5] && (resp[:headers]['etag'].gsub(/\"/,'') == params[:md5]))
573
+ resp[:verified_md5] = true
574
+ end
575
+ resp
576
+ rescue
577
+ on_exception
578
+ end
579
+
580
+ # Identical in function to retrieve_object, but requires verification that the returned ETag is identical to the checksum passed in by the user as the 'md5' argument.
581
+ # If the check passes, returns the response metadata with the "verified_md5" field set true. Raises an exception if the checksums conflict.
582
+ # This call is implemented as a wrapper around retrieve_object and the user may gain different semantics by creating a custom wrapper.
583
+ def retrieve_object_and_verify(params, &block)
584
+ AwsUtils.mandatory_arguments([:md5], params)
585
+ resp = retrieve_object(params, &block)
586
+ return resp if resp[:verified_md5]
587
+ raise AwsError.new("Retrieved object failed MD5 checksum verification: #{resp.inspect}")
588
+ end
401
589
 
402
590
  # Retrieves object metadata. Returns a +hash+ of http_response_headers.
403
591
  #
@@ -425,7 +613,7 @@ module RightAws
425
613
  #
426
614
  def delete(bucket, key='', headers={})
427
615
  req_hash = generate_rest_request('DELETE', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"))
428
- request_info(req_hash, S3TrueParser.new)
616
+ request_info(req_hash, RightHttp2xxParser.new)
429
617
  rescue
430
618
  on_exception
431
619
  end
@@ -446,7 +634,7 @@ module RightAws
446
634
  def copy(src_bucket, src_key, dest_bucket, dest_key=nil, directive=:copy, headers={})
447
635
  dest_key ||= src_key
448
636
  headers['x-amz-metadata-directive'] = directive.to_s.upcase
449
- headers['x-amz-copy-source'] = "#{src_bucket}/#{src_key}"
637
+ headers['x-amz-copy-source'] = "#{src_bucket}/#{CGI::escape src_key}"
450
638
  req_hash = generate_rest_request('PUT', headers.merge(:url=>"#{dest_bucket}/#{CGI::escape dest_key}"))
451
639
  request_info(req_hash, S3CopyParser.new)
452
640
  rescue
@@ -629,26 +817,9 @@ module RightAws
629
817
 
630
818
  # Generates link for QUERY API
631
819
  def generate_link(method, headers={}, expires=nil) #:nodoc:
632
- # default server to use
633
- server = @params[:server]
634
- # fix path
635
- path_to_sign = headers[:url]
636
- path_to_sign = "/#{path_to_sign}" unless path_to_sign[/^\//]
637
- # extract bucket name and check it's dns compartibility
638
- path_to_sign[%r{^/([a-z0-9._-]*)(/[^?]*)?(\?.+)?}i]
639
- bucket_name, key_path, params_list = $1, $2, $3
640
- # select request model
641
- if is_dns_bucket?(bucket_name)
642
- # add backet to a server name
643
- server = "#{bucket_name}.#{server}"
644
- # remove bucket from the path
645
- path = "#{key_path || '/'}#{params_list}"
646
- # refactor the path (add '/' before params_list if the key is empty)
647
- path_to_sign = "/#{bucket_name}#{path}"
648
- else
649
- path = path_to_sign
650
- end
651
- # expiration time
820
+ # calculate request data
821
+ server, path, path_to_sign = fetch_request_params(headers)
822
+ # expiration time
652
823
  expires ||= DEFAULT_EXPIRES_AFTER
653
824
  expires = Time.now.utc + expires if expires.is_a?(Fixnum) && (expires < ONE_YEAR_IN_SECONDS)
654
825
  expires = expires.to_i
@@ -711,7 +882,7 @@ module RightAws
711
882
  # s3.put_link('my_awesome_bucket',key, object) #=> url string
712
883
  #
713
884
  def put_link(bucket, key, data=nil, expires=nil, headers={})
714
- generate_link('PUT', headers.merge(:url=>"#{bucket}/#{CGI::escape key}", :data=>data), expires)
885
+ generate_link('PUT', headers.merge(:url=>"#{bucket}/#{AwsUtils::URLencode key}", :data=>data), expires)
715
886
  rescue
716
887
  on_exception
717
888
  end
@@ -729,7 +900,7 @@ module RightAws
729
900
  #
730
901
  # see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html
731
902
  def get_link(bucket, key, expires=nil, headers={})
732
- generate_link('GET', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
903
+ generate_link('GET', headers.merge(:url=>"#{bucket}/#{AwsUtils::URLencode key}"), expires)
733
904
  rescue
734
905
  on_exception
735
906
  end
@@ -739,7 +910,7 @@ module RightAws
739
910
  # s3.head_link('my_awesome_bucket',key) #=> url string
740
911
  #
741
912
  def head_link(bucket, key, expires=nil, headers={})
742
- generate_link('HEAD', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
913
+ generate_link('HEAD', headers.merge(:url=>"#{bucket}/#{AwsUtils::URLencode key}"), expires)
743
914
  rescue
744
915
  on_exception
745
916
  end
@@ -749,7 +920,7 @@ module RightAws
749
920
  # s3.delete_link('my_awesome_bucket',key) #=> url string
750
921
  #
751
922
  def delete_link(bucket, key, expires=nil, headers={})
752
- generate_link('DELETE', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
923
+ generate_link('DELETE', headers.merge(:url=>"#{bucket}/#{AwsUtils::URLencode key}"), expires)
753
924
  rescue
754
925
  on_exception
755
926
  end
@@ -760,7 +931,7 @@ module RightAws
760
931
  # s3.get_acl_link('my_awesome_bucket',key) #=> url string
761
932
  #
762
933
  def get_acl_link(bucket, key='', headers={})
763
- return generate_link('GET', headers.merge(:url=>"#{bucket}/#{CGI::escape key}?acl"))
934
+ return generate_link('GET', headers.merge(:url=>"#{bucket}/#{AwsUtils::URLencode key}?acl"))
764
935
  rescue
765
936
  on_exception
766
937
  end
@@ -770,7 +941,7 @@ module RightAws
770
941
  # s3.put_acl_link('my_awesome_bucket',key) #=> url string
771
942
  #
772
943
  def put_acl_link(bucket, key='', headers={})
773
- return generate_link('PUT', headers.merge(:url=>"#{bucket}/#{CGI::escape key}?acl"))
944
+ return generate_link('PUT', headers.merge(:url=>"#{bucket}/#{AwsUtils::URLencode key}?acl"))
774
945
  rescue
775
946
  on_exception
776
947
  end
@@ -932,6 +1103,28 @@ module RightAws
932
1103
  end
933
1104
  end
934
1105
  end
1106
+
1107
+ class S3LoggingParser < RightAWSParser # :nodoc:
1108
+ def reset
1109
+ @result = {:enabled => false, :targetbucket => '', :targetprefix => ''}
1110
+ @current_grantee = {}
1111
+ end
1112
+ def tagend(name)
1113
+ case name
1114
+ # service info
1115
+ when 'TargetBucket'
1116
+ if @xmlpath == 'BucketLoggingStatus/LoggingEnabled'
1117
+ @result[:targetbucket] = @text
1118
+ @result[:enabled] = true
1119
+ end
1120
+ when 'TargetPrefix'
1121
+ if @xmlpath == 'BucketLoggingStatus/LoggingEnabled'
1122
+ @result[:targetprefix] = @text
1123
+ @result[:enabled] = true
1124
+ end
1125
+ end
1126
+ end
1127
+ end
935
1128
 
936
1129
  class S3CopyParser < RightAWSParser # :nodoc:
937
1130
  def reset
@@ -964,12 +1157,6 @@ module RightAws
964
1157
  end
965
1158
  end
966
1159
 
967
- class S3TrueParser < S3HttpResponseParser # :nodoc:
968
- def parse(response)
969
- @result = response.is_a?(Net::HTTPSuccess)
970
- end
971
- end
972
-
973
1160
  class S3HttpResponseBodyParser < S3HttpResponseParser # :nodoc:
974
1161
  def parse(response)
975
1162
  @result = {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kerryb-right_aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.5
4
+ version: 1.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - RightScale, Inc.