aws-sdk-s3 1.147.0 → 1.163.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +103 -2
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/access_grants_credentials.rb +57 -0
  5. data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +250 -0
  6. data/lib/aws-sdk-s3/bucket.rb +209 -69
  7. data/lib/aws-sdk-s3/bucket_acl.rb +3 -3
  8. data/lib/aws-sdk-s3/bucket_cors.rb +4 -4
  9. data/lib/aws-sdk-s3/bucket_lifecycle.rb +4 -4
  10. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +4 -4
  11. data/lib/aws-sdk-s3/bucket_logging.rb +3 -3
  12. data/lib/aws-sdk-s3/bucket_notification.rb +3 -3
  13. data/lib/aws-sdk-s3/bucket_policy.rb +4 -4
  14. data/lib/aws-sdk-s3/bucket_region_cache.rb +9 -5
  15. data/lib/aws-sdk-s3/bucket_request_payment.rb +3 -3
  16. data/lib/aws-sdk-s3/bucket_tagging.rb +4 -4
  17. data/lib/aws-sdk-s3/bucket_versioning.rb +5 -5
  18. data/lib/aws-sdk-s3/bucket_website.rb +4 -4
  19. data/lib/aws-sdk-s3/client.rb +1653 -637
  20. data/lib/aws-sdk-s3/client_api.rb +35 -3
  21. data/lib/aws-sdk-s3/customizations/bucket.rb +1 -1
  22. data/lib/aws-sdk-s3/customizations/errors.rb +15 -2
  23. data/lib/aws-sdk-s3/customizations/object.rb +5 -5
  24. data/lib/aws-sdk-s3/customizations.rb +4 -1
  25. data/lib/aws-sdk-s3/encryption/client.rb +2 -2
  26. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +2 -2
  27. data/lib/aws-sdk-s3/encryptionV2/client.rb +2 -2
  28. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +2 -2
  29. data/lib/aws-sdk-s3/endpoint_parameters.rb +8 -0
  30. data/lib/aws-sdk-s3/endpoint_provider.rb +1 -0
  31. data/lib/aws-sdk-s3/endpoints.rb +199 -397
  32. data/lib/aws-sdk-s3/express_credentials_provider.rb +27 -4
  33. data/lib/aws-sdk-s3/file_downloader.rb +1 -1
  34. data/lib/aws-sdk-s3/file_uploader.rb +1 -1
  35. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +1 -1
  36. data/lib/aws-sdk-s3/multipart_upload.rb +24 -4
  37. data/lib/aws-sdk-s3/multipart_upload_part.rb +3 -3
  38. data/lib/aws-sdk-s3/object.rb +394 -137
  39. data/lib/aws-sdk-s3/object_acl.rb +3 -3
  40. data/lib/aws-sdk-s3/object_copier.rb +1 -1
  41. data/lib/aws-sdk-s3/object_multipart_copier.rb +10 -8
  42. data/lib/aws-sdk-s3/object_summary.rb +358 -115
  43. data/lib/aws-sdk-s3/object_version.rb +46 -9
  44. data/lib/aws-sdk-s3/plugins/access_grants.rb +178 -0
  45. data/lib/aws-sdk-s3/plugins/endpoints.rb +10 -1
  46. data/lib/aws-sdk-s3/plugins/express_session_auth.rb +8 -2
  47. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +53 -16
  48. data/lib/aws-sdk-s3/plugins/s3_signer.rb +7 -2
  49. data/lib/aws-sdk-s3/presigner.rb +1 -0
  50. data/lib/aws-sdk-s3/resource.rb +12 -10
  51. data/lib/aws-sdk-s3/types.rb +966 -350
  52. data/lib/aws-sdk-s3.rb +1 -1
  53. data/sig/bucket.rbs +1 -0
  54. data/sig/client.rbs +38 -2
  55. data/sig/customizations/bucket.rbs +19 -0
  56. data/sig/customizations/object.rbs +38 -0
  57. data/sig/customizations/object_summary.rbs +35 -0
  58. data/sig/multipart_upload.rbs +1 -0
  59. data/sig/object.rbs +7 -0
  60. data/sig/object_summary.rbs +1 -0
  61. data/sig/object_version.rbs +6 -0
  62. data/sig/resource.rbs +6 -1
  63. data/sig/types.rbs +25 -2
  64. data/sig/waiters.rbs +12 -0
  65. metadata +12 -7
  66. data/lib/aws-sdk-s3/express_credentials_cache.rb +0 -30
@@ -243,7 +243,7 @@ module Aws::S3
243
243
  :retry
244
244
  end
245
245
  end
246
- Aws::Plugins::UserAgent.feature('resource') do
246
+ Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
247
247
  Aws::Waiters::Waiter.new(options).wait({})
248
248
  end
249
249
  end
@@ -303,7 +303,7 @@ module Aws::S3
303
303
  key: @object_key,
304
304
  version_id: @id
305
305
  )
306
- resp = Aws::Plugins::UserAgent.feature('resource') do
306
+ resp = Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
307
307
  @client.delete_object(options)
308
308
  end
309
309
  resp.data
@@ -523,6 +523,15 @@ module Aws::S3
523
523
  # fails with the HTTP status code `403 Forbidden` (access denied).
524
524
  # @option options [String] :checksum_mode
525
525
  # To retrieve the checksum, this mode must be enabled.
526
+ #
527
+ # **General purpose buckets** - In addition, if you enable checksum mode
528
+ # and the object is uploaded with a [checksum][1] and encrypted with an
529
+ # Key Management Service (KMS) key, you must have permission to use the
530
+ # `kms:Decrypt` action to retrieve the checksum.
531
+ #
532
+ #
533
+ #
534
+ # [1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_Checksum.html
526
535
  # @return [Types::GetObjectOutput]
527
536
  def get(options = {}, &block)
528
537
  options = options.merge(
@@ -530,7 +539,7 @@ module Aws::S3
530
539
  key: @object_key,
531
540
  version_id: @id
532
541
  )
533
- resp = Aws::Plugins::UserAgent.feature('resource') do
542
+ resp = Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
534
543
  @client.get_object(options, &block)
535
544
  end
536
545
  resp.data
@@ -544,6 +553,12 @@ module Aws::S3
544
553
  # if_none_match: "IfNoneMatch",
545
554
  # if_unmodified_since: Time.now,
546
555
  # range: "Range",
556
+ # response_cache_control: "ResponseCacheControl",
557
+ # response_content_disposition: "ResponseContentDisposition",
558
+ # response_content_encoding: "ResponseContentEncoding",
559
+ # response_content_language: "ResponseContentLanguage",
560
+ # response_content_type: "ResponseContentType",
561
+ # response_expires: Time.now,
547
562
  # sse_customer_algorithm: "SSECustomerAlgorithm",
548
563
  # sse_customer_key: "SSECustomerKey",
549
564
  # sse_customer_key_md5: "SSECustomerKeyMD5",
@@ -630,6 +645,18 @@ module Aws::S3
630
645
  # satisfiable, only the `ContentLength` is affected in the response. If
631
646
  # the Range is not satisfiable, S3 returns a `416 - Requested Range Not
632
647
  # Satisfiable` error.
648
+ # @option options [String] :response_cache_control
649
+ # Sets the `Cache-Control` header of the response.
650
+ # @option options [String] :response_content_disposition
651
+ # Sets the `Content-Disposition` header of the response.
652
+ # @option options [String] :response_content_encoding
653
+ # Sets the `Content-Encoding` header of the response.
654
+ # @option options [String] :response_content_language
655
+ # Sets the `Content-Language` header of the response.
656
+ # @option options [String] :response_content_type
657
+ # Sets the `Content-Type` header of the response.
658
+ # @option options [Time,DateTime,Date,Integer,String] :response_expires
659
+ # Sets the `Expires` header of the response.
633
660
  # @option options [String] :sse_customer_algorithm
634
661
  # Specifies the algorithm to use when encrypting the object (for
635
662
  # example, AES256).
@@ -683,10 +710,20 @@ module Aws::S3
683
710
  # @option options [String] :checksum_mode
684
711
  # To retrieve the checksum, this parameter must be enabled.
685
712
  #
686
- # In addition, if you enable `ChecksumMode` and the object is encrypted
687
- # with Amazon Web Services Key Management Service (Amazon Web Services
688
- # KMS), you must have permission to use the `kms:Decrypt` action for the
689
- # request to succeed.
713
+ # **General purpose buckets** - If you enable checksum mode and the
714
+ # object is uploaded with a [checksum][1] and encrypted with an Key
715
+ # Management Service (KMS) key, you must have permission to use the
716
+ # `kms:Decrypt` action to retrieve the checksum.
717
+ #
718
+ # **Directory buckets** - If you enable `ChecksumMode` and the object is
719
+ # encrypted with Amazon Web Services Key Management Service (Amazon Web
720
+ # Services KMS), you must also have the `kms:GenerateDataKey` and
721
+ # `kms:Decrypt` permissions in IAM identity-based policies and KMS key
722
+ # policies for the KMS key to retrieve the checksum of the object.
723
+ #
724
+ #
725
+ #
726
+ # [1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_Checksum.html
690
727
  # @return [Types::HeadObjectOutput]
691
728
  def head(options = {})
692
729
  options = options.merge(
@@ -694,7 +731,7 @@ module Aws::S3
694
731
  key: @object_key,
695
732
  version_id: @id
696
733
  )
697
- resp = Aws::Plugins::UserAgent.feature('resource') do
734
+ resp = Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
698
735
  @client.head_object(options)
699
736
  end
700
737
  resp.data
@@ -868,7 +905,7 @@ module Aws::S3
868
905
  version_id: item.id
869
906
  }
870
907
  end
871
- Aws::Plugins::UserAgent.feature('resource') do
908
+ Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
872
909
  batch[0].client.delete_objects(params)
873
910
  end
874
911
  end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+ # @api private
7
+ class AccessGrants < Seahorse::Client::Plugin
8
+ @s3control =
9
+ begin
10
+ require 'aws-sdk-s3control'
11
+ true
12
+ rescue LoadError
13
+ false
14
+ end
15
+
16
+ option(
17
+ :access_grants,
18
+ default: false,
19
+ doc_type: 'Boolean',
20
+ docstring: <<-DOCS)
21
+ When `true`, the S3 client will use the S3 Access Grants feature to
22
+ authenticate requests. Bucket credentials will be fetched from S3
23
+ Control using the `get_data_access` API.
24
+ DOCS
25
+
26
+ option(:access_grants_credentials_provider,
27
+ doc_type: 'Aws::S3::AccessGrantsCredentialsProvider',
28
+ rbs_type: 'untyped',
29
+ docstring: <<-DOCS) do |_cfg|
30
+ When `access_grants` is `true`, this option can be used to provide
31
+ additional options to the credentials provider, including a privilege
32
+ setting, caching, and fallback behavior.
33
+ DOCS
34
+ Aws::S3::AccessGrantsCredentialsProvider.new
35
+ end
36
+
37
+ # @api private
38
+ class Handler < Seahorse::Client::Handler
39
+ PERMISSION_MAP = {
40
+ head_object: 'READ',
41
+ get_object: 'READ',
42
+ get_object_acl: 'READ',
43
+ list_multipart_uploads: 'READ',
44
+ list_objects_v2: 'READ',
45
+ list_object_versions: 'READ',
46
+ list_parts: 'READ',
47
+ head_bucket: 'READ',
48
+ get_object_attributes: 'READ',
49
+ put_object: 'WRITE',
50
+ put_object_acl: 'WRITE',
51
+ delete_object: 'WRITE',
52
+ abort_multipart_upload: 'WRITE',
53
+ create_multipart_upload: 'WRITE',
54
+ upload_part: 'WRITE',
55
+ complete_multipart_upload: 'WRITE',
56
+ delete_objects: 'WRITE',
57
+ copy_object: 'READWRITE'
58
+ }.freeze
59
+
60
+ def call(context)
61
+ provider = context.config.access_grants_credentials_provider
62
+
63
+ if access_grants_operation?(context) &&
64
+ !s3_express_endpoint?(context) &&
65
+ !credentials_head_bucket_call?(provider)
66
+ params = context[:endpoint_params]
67
+ permission = PERMISSION_MAP[context.operation_name]
68
+
69
+ key =
70
+ case context.operation_name
71
+ when :delete_objects
72
+ delete_params = context.params[:delete]
73
+ common_prefixes(delete_params[:objects].map { |o| o[:key] })
74
+ when :copy_object
75
+ source_bucket, source_key = params[:copy_source].split('/', 2)
76
+ if params[:bucket] != source_bucket
77
+ raise ArgumentError,
78
+ 'source and destination bucket must be the same'
79
+ end
80
+ common_prefixes([params[:key], source_key])
81
+ else
82
+ params[:key]
83
+ end
84
+
85
+ credentials = provider.access_grants_credentials_for(
86
+ bucket: params[:bucket],
87
+ key: key,
88
+ prefix: params[:prefix],
89
+ permission: permission
90
+ )
91
+ context[:sigv4_credentials] = credentials # Sign will use this
92
+ end
93
+
94
+ with_metric(credentials) { @handler.call(context) }
95
+ end
96
+
97
+ private
98
+
99
+ def with_metric(credentials, &block)
100
+ return block.call unless credentials
101
+
102
+ Aws::Plugins::UserAgent.metric('S3_ACCESS_GRANTS', &block)
103
+ end
104
+
105
+ # HeadBucket is a supported call. When fetching credentials,
106
+ # this plugin is executed again, and becomes recursive.
107
+ def credentials_head_bucket_call?(provider)
108
+ provider.instance_variable_get(:@head_bucket_call)
109
+ end
110
+
111
+ def access_grants_operation?(context)
112
+ params = context[:endpoint_params]
113
+ params[:bucket] && PERMISSION_MAP[context.operation_name]
114
+ end
115
+
116
+ def s3_express_endpoint?(context)
117
+ context[:endpoint_properties]['backend'] == 'S3Express'
118
+ end
119
+
120
+ # Return the common prefix of the keys, regardless of the delimiter.
121
+ # For example, given keys ['foo/bar', 'foo/baz'], the common prefix
122
+ # is 'foo/ba'.
123
+ def common_prefixes(keys)
124
+ return '' if keys.empty?
125
+
126
+ first_key = keys[0]
127
+ common_ancestor = first_key
128
+ last_prefix = ''
129
+ keys.each do |k|
130
+ until common_ancestor.empty?
131
+ break if k.start_with?(common_ancestor)
132
+
133
+ last_index = common_ancestor.rindex('/')
134
+ return '' if last_index.nil?
135
+
136
+ last_prefix = common_ancestor[(last_index + 1)..-1]
137
+ common_ancestor = common_ancestor[0...last_index]
138
+ end
139
+ end
140
+ new_common_ancestor = "#{common_ancestor}/#{last_prefix}"
141
+ keys.each do |k|
142
+ until last_prefix.empty?
143
+ break if k.start_with?(new_common_ancestor)
144
+
145
+ last_prefix = last_prefix[0...-1]
146
+ new_common_ancestor = "#{common_ancestor}/#{last_prefix}"
147
+ end
148
+ end
149
+ if new_common_ancestor == "#{first_key}/"
150
+ first_key
151
+ else
152
+ new_common_ancestor
153
+ end
154
+ end
155
+ end
156
+
157
+ def add_handlers(handlers, config)
158
+ return unless AccessGrants.s3control? && config.access_grants
159
+
160
+ handlers.add(Handler)
161
+ end
162
+
163
+ def after_initialize(client)
164
+ return unless AccessGrants.s3control? && client.config.access_grants
165
+
166
+ provider = client.config.access_grants_credentials_provider
167
+ provider.s3_client = client unless provider.s3_client
168
+ end
169
+
170
+ class << self
171
+ def s3control?
172
+ @s3control
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -46,11 +46,20 @@ module Aws::S3
46
46
  context[:auth_scheme] =
47
47
  Aws::Endpoints.resolve_auth_scheme(context, endpoint)
48
48
 
49
- @handler.call(context)
49
+ with_metrics(context) { @handler.call(context) }
50
50
  end
51
51
 
52
52
  private
53
53
 
54
+ def with_metrics(context, &block)
55
+ metrics = []
56
+ metrics << 'ENDPOINT_OVERRIDE' unless context.config.regional_endpoint
57
+ if context[:auth_scheme] && context[:auth_scheme]['name'] == 'sigv4a'
58
+ metrics << 'SIGV4A_SIGNING'
59
+ end
60
+ Aws::Plugins::UserAgent.metric(*metrics, &block)
61
+ end
62
+
54
63
  def apply_endpoint_headers(context, headers)
55
64
  headers.each do |key, values|
56
65
  value = values
@@ -31,7 +31,7 @@ for different buckets.
31
31
  def call(context)
32
32
  if (props = context[:endpoint_properties])
33
33
  # S3 Express endpoint - turn off md5 and enable crc32 default
34
- if (backend = props['backend']) && backend == 'S3Express'
34
+ if props['backend'] == 'S3Express'
35
35
  if context.operation_name == :put_object || checksum_required?(context)
36
36
  context[:default_request_checksum_algorithm] = 'CRC32'
37
37
  end
@@ -47,11 +47,17 @@ for different buckets.
47
47
  context[:sigv4_credentials] = credentials # Sign will use this
48
48
  end
49
49
  end
50
- @handler.call(context)
50
+ with_metric(credentials) { @handler.call(context) }
51
51
  end
52
52
 
53
53
  private
54
54
 
55
+ def with_metric(credentials, &block)
56
+ return block.call unless credentials
57
+
58
+ Aws::Plugins::UserAgent.metric('S3_EXPRESS_BUCKET', &block)
59
+ end
60
+
55
61
  def checksum_required?(context)
56
62
  context.operation.http_checksum_required ||
57
63
  (context.operation.http_checksum &&
@@ -15,22 +15,67 @@ module Aws
15
15
 
16
16
  def call(context)
17
17
  @handler.call(context).on(200) do |response|
18
- if error = check_for_error(context)
19
- context.http_response.status_code = 500
20
- response.data = nil
21
- response.error = error
18
+ return response if streaming_output?(context.operation.output)
19
+
20
+ error = check_for_error(context)
21
+ return response unless error
22
+
23
+ context.http_response.status_code = 500
24
+ response.data = nil
25
+ response.error = error
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ # Streaming outputs are not subject to 200 errors.
32
+ def streaming_output?(output)
33
+ if (payload = output[:payload_member])
34
+ # checking ref and shape
35
+ payload['streaming'] || payload.shape['streaming'] ||
36
+ payload.eventstream
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ # Checks if the output shape is a structure shape and has members that
43
+ # are in the body for the case of a payload and a normal structure. A
44
+ # non-structure shape will not have members in the body. In the case
45
+ # of a string or blob, the body contents would have been checked first
46
+ # before this method is called in incomplete_xml_body?.
47
+ def members_in_body?(output)
48
+ shape =
49
+ if output[:payload_member]
50
+ output[:payload_member].shape
51
+ else
52
+ output.shape
22
53
  end
54
+
55
+ if structure_shape?(shape)
56
+ shape.members.any? { |_, k| k.location.nil? }
57
+ else
58
+ false
23
59
  end
24
60
  end
25
61
 
62
+ def structure_shape?(shape)
63
+ shape.is_a?(Seahorse::Model::Shapes::StructureShape)
64
+ end
65
+
66
+ # Must have a member in the body and have the start of an XML Tag.
67
+ # Other incomplete xml bodies will result in an XML ParsingError.
68
+ def incomplete_xml_body?(xml, output)
69
+ members_in_body?(output) && !xml.match(/<\w/)
70
+ end
71
+
26
72
  def check_for_error(context)
27
73
  xml = context.http_response.body_contents
28
- if xml.match(/<Error>/)
74
+ if xml.match(/\?>\s*<Error>/)
29
75
  error_code = xml.match(/<Code>(.+?)<\/Code>/)[1]
30
76
  error_message = xml.match(/<Message>(.+?)<\/Message>/)[1]
31
77
  S3::Errors.error_class(error_code).new(context, error_message)
32
- elsif !xml.match(/<\w/) # Must have the start of an XML Tag
33
- # Other incomplete xml bodies will result in XML ParsingError
78
+ elsif incomplete_xml_body?(xml, context.operation.output)
34
79
  Seahorse::Client::NetworkingError.new(
35
80
  S3::Errors
36
81
  .error_class('InternalError')
@@ -40,15 +85,7 @@ module Aws
40
85
  end
41
86
  end
42
87
 
43
- handler(
44
- Handler,
45
- step: :sign,
46
- operations: [
47
- :complete_multipart_upload,
48
- :copy_object,
49
- :upload_part_copy,
50
- ]
51
- )
88
+ handler(Handler, step: :sign)
52
89
  end
53
90
  end
54
91
  end
@@ -4,6 +4,11 @@ require 'aws-sigv4'
4
4
 
5
5
  module Aws
6
6
  module S3
7
+ # @api private
8
+ def self.bucket_region_cache
9
+ @bucket_region_cache ||= BucketRegionCache.new
10
+ end
11
+
7
12
  module Plugins
8
13
  # This plugin used to have a V4 signer but it was removed in favor of
9
14
  # generic Sign plugin that uses endpoint auth scheme.
@@ -51,7 +56,7 @@ module Aws
51
56
  private
52
57
 
53
58
  def check_for_cached_region(context, bucket)
54
- cached_region = S3::BUCKET_REGIONS[bucket]
59
+ cached_region = Aws::S3.bucket_region_cache[bucket]
55
60
  if cached_region &&
56
61
  cached_region != context.config.region &&
57
62
  !S3Signer.custom_endpoint?(context)
@@ -97,7 +102,7 @@ module Aws
97
102
  end
98
103
 
99
104
  def update_bucket_cache(context, actual_region)
100
- S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
105
+ Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
101
106
  end
102
107
 
103
108
  def fips_region?(resp)
@@ -200,6 +200,7 @@ module Aws
200
200
  req.handlers.remove(Aws::Plugins::Sign::Handler)
201
201
  req.handlers.remove(Seahorse::Client::Plugins::ContentLength::Handler)
202
202
  req.handlers.remove(Aws::Rest::ContentTypeHandler)
203
+ req.handlers.remove(Aws::Plugins::InvocationId::Handler)
203
204
 
204
205
  req.handle(step: :send) do |context|
205
206
  # if an endpoint was not provided, force secure or insecure
@@ -166,7 +166,7 @@ module Aws::S3
166
166
  # [1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html
167
167
  # @return [Bucket]
168
168
  def create_bucket(options = {})
169
- Aws::Plugins::UserAgent.feature('resource') do
169
+ Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
170
170
  @client.create_bucket(options)
171
171
  end
172
172
  Bucket.new(
@@ -193,18 +193,20 @@ module Aws::S3
193
193
  # @return [Bucket::Collection]
194
194
  def buckets(options = {})
195
195
  batches = Enumerator.new do |y|
196
- batch = []
197
- resp = Aws::Plugins::UserAgent.feature('resource') do
196
+ resp = Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
198
197
  @client.list_buckets(options)
199
198
  end
200
- resp.data.buckets.each do |b|
201
- batch << Bucket.new(
202
- name: b.name,
203
- data: b,
204
- client: @client
205
- )
199
+ resp.each_page do |page|
200
+ batch = []
201
+ page.data.buckets.each do |b|
202
+ batch << Bucket.new(
203
+ name: b.name,
204
+ data: b,
205
+ client: @client
206
+ )
207
+ end
208
+ y.yield(batch)
206
209
  end
207
- y.yield(batch)
208
210
  end
209
211
  Bucket::Collection.new(batches)
210
212
  end