aws-sdk 1.6.2 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -69,7 +69,7 @@ require 'aws/core/autoloader'
69
69
  module AWS
70
70
 
71
71
  # Current version of the AWS SDK for Ruby
72
- VERSION = "1.6.2"
72
+ VERSION = "1.6.3"
73
73
 
74
74
  register_autoloads(self) do
75
75
  autoload :Errors, 'errors'
@@ -299,7 +299,7 @@ module AWS
299
299
  # +true+, requests will always use path style. This can be useful
300
300
  # for testing environments.
301
301
  #
302
- # @option options [Integer] :s3_multipart_max_parts (1000) The maximum
302
+ # @option options [Integer] :s3_multipart_max_parts (10000) The maximum
303
303
  # number of parts to split a file into when uploading in parts to S3.
304
304
  #
305
305
  # @option options [Integer] :s3_multipart_threshold (16777216) When
@@ -328,6 +328,17 @@ module AWS
328
328
  # * {S3::S3Object#presigned_post}
329
329
  # * {S3::Bucket#presigned_post}
330
330
  #
331
+ # @option options [OpenSSL::PKey::RSA, String] :s3_encryption_key (nil)
332
+ # If this is set, AWS::S3::S3Object #read and #write methods will always
333
+ # perform client-side encryption with this key. The key can be overridden
334
+ # at runtime by using the :encryption_key option. A value of nil
335
+ # means that client-side encryption will not be used.
336
+ #
337
+ # @option options [Symbol] :s3_encryption_materials_location (:metadata)
338
+ # When set to +:instruction_file+, AWS::S3::S3Object will store
339
+ # encryption materials in a seperate object, instead of the object
340
+ # metadata.
341
+ #
331
342
  # @option options [String] :simple_db_endpoint ('sdb.amazonaws.com')
332
343
  # The service endpoint for Amazon SimpleDB.
333
344
  #
@@ -42,7 +42,7 @@ module AWS
42
42
 
43
43
  # @private
44
44
  class Autoloader
45
-
45
+
46
46
  def initialize klass, prefix = nil
47
47
  @klass = klass
48
48
  @prefix = prefix || klass.name.gsub(/::/, '/').downcase
@@ -21,6 +21,11 @@ module AWS
21
21
  # Base client class for all of the Amazon AWS service clients.
22
22
  class Client
23
23
 
24
+ # Raised when a request failed due to a networking issue (e.g.
25
+ # EOFError, IOError, Errno::ECONNRESET, Errno::EPIPE,
26
+ # Timeout::Error, etc)
27
+ class NetworkError < StandardError; end
28
+
24
29
  extend Naming
25
30
 
26
31
  # @private
@@ -155,6 +160,19 @@ module AWS
155
160
  response
156
161
  end
157
162
 
163
+ # Logs the warning to the configured logger, otherwise to stderr.
164
+ # @param [String] warning
165
+ # @return [nil]
166
+ def log_warning warning
167
+ message = '[aws-sdk-gem-warning] ' + warning
168
+ if config.logger
169
+ config.logger.warn(message)
170
+ else
171
+ $stderr.puts(message)
172
+ end
173
+ nil
174
+ end
175
+
158
176
  protected
159
177
 
160
178
  def new_request
@@ -204,13 +222,30 @@ module AWS
204
222
 
205
223
  end
206
224
 
207
- def make_sync_request response
225
+ def make_sync_request response, &read_block
208
226
  retry_server_errors do
209
227
 
210
- response.http_response = http_response =
211
- Http::Response.new
228
+ response.http_response = Http::Response.new
229
+
230
+ @http_handler.handle(
231
+ response.http_request,
232
+ response.http_response,
233
+ &read_block)
234
+
235
+ if
236
+ block_given? and
237
+ response.http_response.status < 300 and
238
+ response.http_response.body
239
+ then
240
+
241
+ msg = ":http_handler read the entire http response body into "
242
+ msg << "memory, it should have instead yielded chunks"
243
+ log_warning(msg)
244
+
245
+ # go ahead and yield the body on behalf of the handler
246
+ yield(response.http_response.body)
212
247
 
213
- @http_handler.handle(response.http_request, http_response)
248
+ end
214
249
 
215
250
  populate_error(response)
216
251
  response.signal_success unless response.error
@@ -227,7 +262,6 @@ module AWS
227
262
  while should_retry?(response)
228
263
  break if sleeps.empty?
229
264
  Kernel.sleep(sleeps.shift)
230
- # rebuild the request to get a fresh signature
231
265
  rebuild_http_request(response)
232
266
  response = yield
233
267
  end
@@ -256,8 +290,16 @@ module AWS
256
290
  end
257
291
 
258
292
  def should_retry? response
293
+ if retryable_error?(response)
294
+ response.safe_to_retry?
295
+ else
296
+ false
297
+ end
298
+ end
299
+
300
+ def retryable_error? response
259
301
  expired_credentials?(response) or
260
- response.timeout? or
302
+ response.network_error? or
261
303
  response.throttled? or
262
304
  response.error.kind_of?(Errors::ServerError)
263
305
  end
@@ -303,7 +345,7 @@ module AWS
303
345
  end
304
346
 
305
347
  # Logs the response to the configured logger.
306
- # @param [Resposne] response
348
+ # @param [Response] response
307
349
  # @return [nil]
308
350
  def log_response response
309
351
  if config.logger
@@ -336,10 +378,10 @@ module AWS
336
378
  ]
337
379
 
338
380
  case
339
- when response.timeout? then TimeoutError.new
340
- when error_code then error_class(error_code).new(*error_args)
341
- when status >= 500 then Errors::ServerError.new(*error_args)
342
- when status >= 300 then Errors::ClientError.new(*error_args)
381
+ when response.network_error? then NetworkError.new
382
+ when error_code then error_class(error_code).new(*error_args)
383
+ when status >= 500 then Errors::ServerError.new(*error_args)
384
+ when status >= 300 then Errors::ClientError.new(*error_args)
343
385
  else nil # no error
344
386
  end
345
387
 
@@ -371,21 +413,25 @@ module AWS
371
413
  AWS.const_get(self.class.to_s[/(\w+)::Client/, 1])::Errors
372
414
  end
373
415
 
374
- def client_request name, options, &block
416
+ def client_request name, options, &read_block
375
417
  return_or_raise(options) do
376
418
  log_client_request(options) do
377
419
 
378
420
  if config.stub_requests?
379
421
 
380
422
  response = stub_for(name)
381
- response.http_request = build_request(name, options, &block)
423
+ response.http_request = build_request(name, options)
382
424
  response.request_options = options
383
425
  response
384
426
 
385
427
  else
386
428
 
387
429
  client = self
388
- response = new_response { client.send(:build_request, name, options, &block) }
430
+
431
+ response = new_response do
432
+ client.send(:build_request, name, options)
433
+ end
434
+
389
435
  response.request_type = name
390
436
  response.request_options = options
391
437
 
@@ -399,8 +445,8 @@ module AWS
399
445
  else
400
446
  # process the http request
401
447
  options[:async] ?
402
- make_async_request(response) :
403
- make_sync_request(response)
448
+ make_async_request(response, &read_block) :
449
+ make_sync_request(response, &read_block)
404
450
 
405
451
  # process the http response
406
452
  response.on_success do
@@ -424,7 +470,7 @@ module AWS
424
470
  self.class::CACHEABLE_REQUESTS.include?(name)
425
471
  end
426
472
 
427
- def build_request(name, options, &block)
473
+ def build_request name, options
428
474
 
429
475
  # we dont want to pass the async option to the configure block
430
476
  opts = options.dup
@@ -445,7 +491,7 @@ module AWS
445
491
  http_request.ssl_ca_file = config.ssl_ca_file if config.ssl_ca_file
446
492
  http_request.ssl_ca_path = config.ssl_ca_path if config.ssl_ca_path
447
493
 
448
- send("configure_#{name}_request", http_request, opts, &block)
494
+ send("configure_#{name}_request", http_request, opts)
449
495
 
450
496
  http_request.headers["user-agent"] = user_agent_string
451
497
  http_request.add_authorization!(credential_provider)
@@ -474,16 +520,18 @@ module AWS
474
520
  #
475
521
  def self.add_client_request_method method_name, options = {}, &block
476
522
 
477
- self.operations << method_name
523
+ operations << method_name
478
524
 
479
525
  ClientRequestMethodBuilder.new(self, method_name, &block)
480
526
 
481
- module_eval <<-END
527
+ method_def = <<-METHOD
482
528
  def #{method_name}(*args, &block)
483
529
  options = args.first ? args.first : {}
484
530
  client_request(#{method_name.inspect}, options, &block)
485
531
  end
486
- END
532
+ METHOD
533
+
534
+ module_eval(method_def)
487
535
 
488
536
  end
489
537
 
@@ -518,15 +566,6 @@ module AWS
518
566
  def configure_request options = {}, &block
519
567
  name = "configure_#{@method_name}_request"
520
568
  MetaUtils.class_extend_method(@client_class, name, &block)
521
- if block.arity == 3
522
- m = Module.new
523
- m.module_eval(<<-END)
524
- def #{name}(req, options, &block)
525
- super(req, options, block)
526
- end
527
- END
528
- @client_class.send(:include, m)
529
- end
530
569
  end
531
570
 
532
571
  def process_response &block
@@ -128,7 +128,7 @@ module AWS
128
128
  # +true+, requests will always use path style. This can be useful
129
129
  # for testing environments.
130
130
  #
131
- # @attr_reader [Integer] s3_multipart_max_parts (1000)
131
+ # @attr_reader [Integer] s3_multipart_max_parts (10000)
132
132
  # The maximum number of parts to split a file into when uploading
133
133
  # in parts to S3.
134
134
  #
@@ -163,6 +163,17 @@ module AWS
163
163
  #
164
164
  # s3 = AWS::S3.new(:s3_server_side_encryption => :aes256)
165
165
  #
166
+ # @attr_reader [OpenSSL::PKey::RSA, String] s3_encryption_key
167
+ # If this is set, AWS::S3::S3Object #read and #write methods will always
168
+ # perform client-side encryption with this key. The key can be overridden
169
+ # at runtime by using the :encryption_key option. A value of nil
170
+ # means that client-side encryption will not be used.
171
+ #
172
+ # @attr_reader [Symbol] s3_encryption_materials_location
173
+ # When set to +:instruction_file+, AWS::S3::S3Object will store
174
+ # encryption materials in a seperate object, instead of the object
175
+ # metadata.
176
+ #
166
177
  # @attr_reader [String] simple_db_endpoint ('sdb.amazonaws.com')
167
178
  # The service endpoint for Amazon SimpleDB.
168
179
  #
@@ -14,27 +14,39 @@
14
14
  module AWS
15
15
  module Core
16
16
  module Http
17
-
17
+
18
18
  # @private
19
19
  class Handler
20
-
20
+
21
21
  attr_reader :base
22
-
22
+
23
23
  def initialize(base, &block)
24
24
  @base = base
25
25
  if base.respond_to?(:handle)
26
-
27
- unless block.arity == 2
28
- raise ArgumentError, 'passed block must accept 2 arguments'
26
+
27
+ unless [2,3].include?(block.arity)
28
+ raise ArgumentError, 'passed block must accept 2 or 3 arguments'
29
29
  end
30
+
30
31
  MetaUtils.extend_method(self, :handle, &block)
31
-
32
+
33
+ if block.arity == 3
34
+ m = Module.new do
35
+ eval(<<-DEF)
36
+ def handle req, resp, &read_block
37
+ super(req, resp, read_block)
38
+ end
39
+ DEF
40
+ end
41
+ self.extend(m)
42
+ end
43
+
32
44
  elsif base.respond_to?(:handle_async)
33
-
45
+
34
46
  unless block.arity == 3
35
47
  raise ArgumentError, 'passed block must accept 3 arguments'
36
48
  end
37
-
49
+
38
50
  MetaUtils.extend_method(self, :handle_async) do |req, resp, handle|
39
51
  @base.handle_async(req, resp, handle)
40
52
  end
@@ -44,16 +56,16 @@ module AWS
44
56
  end
45
57
  define_method(:handle_async, &block)
46
58
  end
47
-
59
+
48
60
  else
49
61
  raise ArgumentError, 'base must respond to #handle or #handle_async'
50
62
  end
51
63
  end
52
-
53
- def handle(request, http_response)
54
- @base.handle(request, http_response)
64
+
65
+ def handle(request, http_response, &read_block)
66
+ @base.handle(request, http_response, &read_block)
55
67
  end
56
-
68
+
57
69
  def handle_async(request, http_response, handle)
58
70
  Thread.new do
59
71
  begin
@@ -65,12 +77,12 @@ module AWS
65
77
  end
66
78
  end
67
79
  end
68
-
80
+
69
81
  def sleep_with_callback seconds, &block
70
82
  Kernel.sleep(seconds)
71
83
  yield
72
84
  end
73
-
85
+
74
86
  end
75
87
  end
76
88
  end
@@ -25,6 +25,18 @@ module AWS
25
25
  #
26
26
  class NetHttpHandler
27
27
 
28
+ # @private
29
+ NETWORK_ERRORS = [
30
+ EOFError,
31
+ IOError,
32
+ Errno::ECONNABORTED,
33
+ Errno::ECONNRESET,
34
+ Errno::EPIPE,
35
+ Errno::EINVAL,
36
+ Timeout::Error,
37
+ Errno::ETIMEDOUT,
38
+ ]
39
+
28
40
  # (see Net::HTTP::ConnectionPool.new)
29
41
  def initialize options = {}
30
42
  @pool = Net::HTTP::ConnectionPool.new(options)
@@ -39,7 +51,7 @@ module AWS
39
51
  # @param [Request] request
40
52
  # @param [Response] response
41
53
  # @return [nil]
42
- def handle request, response
54
+ def handle request, response, &read_block
43
55
 
44
56
  options = {}
45
57
  options[:port] = request.port
@@ -49,17 +61,25 @@ module AWS
49
61
  options[:ssl_ca_file] = request.ssl_ca_file if request.ssl_ca_file
50
62
  options[:ssl_ca_path] = request.ssl_ca_path if request.ssl_ca_path
51
63
 
52
- connection = pool.connection_for(request.host, options)
53
- connection.read_timeout = request.read_timeout
54
-
55
64
  begin
56
- http_response = connection.request(build_net_http_request(request))
57
- response.body = http_response.body
58
- response.status = http_response.code.to_i
59
- response.headers = http_response.to_hash
60
- rescue Timeout::Error, Errno::ETIMEDOUT => e
61
- response.timeout = true
65
+
66
+ connection = pool.connection_for(request.host, options)
67
+ connection.read_timeout = request.read_timeout
68
+
69
+ connection.request(build_net_http_request(request)) do |http_resp|
70
+ response.status = http_resp.code.to_i
71
+ response.headers = http_resp.to_hash
72
+ if block_given? and response.status < 300
73
+ http_resp.read_body(&read_block)
74
+ else
75
+ response.body = http_resp.read_body
76
+ end
77
+ end
78
+
79
+ rescue *NETWORK_ERRORS
80
+ response.network_error = true
62
81
  end
82
+
63
83
  nil
64
84
 
65
85
  end
@@ -90,7 +110,7 @@ module AWS
90
110
  end
91
111
 
92
112
  net_http_req = request_class.new(request.uri, headers)
93
- net_http_req.body = request.body
113
+ net_http_req.body_stream = request.body_stream
94
114
  net_http_req
95
115
 
96
116
  end
@@ -36,7 +36,7 @@ module AWS
36
36
  # 60 seconds.
37
37
  attr_accessor :default_read_timeout
38
38
 
39
- # @return [String] Returns hostname of the request.
39
+ # @return [String] hostname of the request
40
40
  attr_accessor :host
41
41
 
42
42
  # @return [Integer] Returns the port number this request will be
@@ -47,7 +47,7 @@ module AWS
47
47
  # 'POST', 'HEAD' or 'DELETE'). Defaults to 'POST'.
48
48
  attr_accessor :http_method
49
49
 
50
- # @return [Hash] Returns a hash of header values.
50
+ # @return [CaseInsensitiveHash] request headers
51
51
  attr_accessor :headers
52
52
 
53
53
  # @return [String] Returns the request URI (path + querystring).
@@ -57,24 +57,18 @@ module AWS
57
57
  # to be populated for requests against signature v4 endpoints.
58
58
  attr_accessor :region
59
59
 
60
- # @return [String]
60
+ # @return [String] Returns the AWS access key ID used to authorize the
61
+ # request.
61
62
  # @private
62
63
  attr_accessor :access_key_id
63
64
 
64
- # @private
65
65
  # @return [Array<Param>] Returns an array of request params. Requests
66
66
  # that use signature version 2 add params to the request and then
67
67
  # sign those before building the {#body}. Normally the {#body}
68
68
  # should be set directly with the HTTP payload.
69
+ # @private
69
70
  attr_accessor :params
70
71
 
71
- # @return [String] Returns the HTTP request payload (body).
72
- attr_accessor :body
73
-
74
- # @return [String] Returns the AWS access key ID used to authorize the
75
- # request.
76
- attr_accessor :access_key_id
77
-
78
72
  # @return [String] The name of the service for Signature v4 signing.
79
73
  # This does not always match the ruby name (e.g.
80
74
  # simple_email_service and ses do not match).
@@ -125,11 +119,6 @@ module AWS
125
119
  default_read_timeout
126
120
  end
127
121
 
128
- # @return [String,nil] Returns the request body (payload).
129
- def body
130
- @body || url_encoded_params
131
- end
132
-
133
122
  # @return [String] Returns the HTTP request path.
134
123
  def path
135
124
  uri.split(/\?/)[0]
@@ -167,6 +156,53 @@ module AWS
167
156
  params.empty? ? nil : params.sort.collect(&:encoded).join('&')
168
157
  end
169
158
 
159
+ # @param [String] body
160
+ def body= body
161
+ @body = body
162
+ if body
163
+ headers['content-length'] = body.size if body
164
+ else
165
+ headers.delete('content-length')
166
+ end
167
+ end
168
+
169
+ # @note Calling #body on a request with a #body_stream
170
+ # will cause the entire stream to be read into memory.
171
+ # @return [String,nil] Returns the request body.
172
+ def body
173
+ if @body
174
+ @body
175
+ elsif @body_stream
176
+ @body = @body_stream.read
177
+ if @body_stream.respond_to?(:rewind)
178
+ @body_stream.rewind
179
+ else
180
+ @body_stream = StringIO.new(@body)
181
+ end
182
+ @body
183
+ else
184
+ nil
185
+ end
186
+ end
187
+
188
+ # Sets the request body as an IO object that will be streamed.
189
+ # @note You must also set the #headers['content-length']
190
+ # @param [IO] stream An object that responds to #read and #eof.
191
+ def body_stream= stream
192
+ @body_stream = stream
193
+ end
194
+
195
+ # @return [IO,nil]
196
+ def body_stream
197
+ if @body_stream
198
+ @body_stream
199
+ elsif @body
200
+ StringIO.new(@body)
201
+ else
202
+ nil
203
+ end
204
+ end
205
+
170
206
  # @private
171
207
  class CaseInsensitiveHash < Hash
172
208