aws-sdk 1.6.2 → 1.6.3

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.
@@ -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