kerryb-right_aws 1.7.5 → 1.7.6

Sign up to get free protection for your applications and to get access to all the features.
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.