aws-sdk-s3 1.150.0 → 1.160.0

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +12 -3
  5. data/lib/aws-sdk-s3/bucket.rb +89 -26
  6. data/lib/aws-sdk-s3/bucket_acl.rb +3 -3
  7. data/lib/aws-sdk-s3/bucket_cors.rb +4 -4
  8. data/lib/aws-sdk-s3/bucket_lifecycle.rb +4 -4
  9. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +4 -4
  10. data/lib/aws-sdk-s3/bucket_logging.rb +3 -3
  11. data/lib/aws-sdk-s3/bucket_notification.rb +3 -3
  12. data/lib/aws-sdk-s3/bucket_policy.rb +4 -4
  13. data/lib/aws-sdk-s3/bucket_request_payment.rb +3 -3
  14. data/lib/aws-sdk-s3/bucket_tagging.rb +4 -4
  15. data/lib/aws-sdk-s3/bucket_versioning.rb +5 -5
  16. data/lib/aws-sdk-s3/bucket_website.rb +4 -4
  17. data/lib/aws-sdk-s3/client.rb +632 -351
  18. data/lib/aws-sdk-s3/client_api.rb +27 -3
  19. data/lib/aws-sdk-s3/customizations/bucket.rb +1 -1
  20. data/lib/aws-sdk-s3/customizations/object.rb +5 -5
  21. data/lib/aws-sdk-s3/encryption/client.rb +2 -2
  22. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +2 -2
  23. data/lib/aws-sdk-s3/encryptionV2/client.rb +2 -2
  24. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +2 -2
  25. data/lib/aws-sdk-s3/endpoint_parameters.rb +8 -0
  26. data/lib/aws-sdk-s3/endpoint_provider.rb +1 -0
  27. data/lib/aws-sdk-s3/endpoints.rb +100 -1
  28. data/lib/aws-sdk-s3/file_downloader.rb +1 -1
  29. data/lib/aws-sdk-s3/file_uploader.rb +1 -1
  30. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +1 -1
  31. data/lib/aws-sdk-s3/multipart_upload.rb +24 -4
  32. data/lib/aws-sdk-s3/multipart_upload_part.rb +3 -3
  33. data/lib/aws-sdk-s3/object.rb +66 -16
  34. data/lib/aws-sdk-s3/object_acl.rb +3 -3
  35. data/lib/aws-sdk-s3/object_copier.rb +1 -1
  36. data/lib/aws-sdk-s3/object_summary.rb +38 -10
  37. data/lib/aws-sdk-s3/object_version.rb +40 -9
  38. data/lib/aws-sdk-s3/plugins/access_grants.rb +75 -5
  39. data/lib/aws-sdk-s3/plugins/express_session_auth.rb +7 -1
  40. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +53 -16
  41. data/lib/aws-sdk-s3/resource.rb +12 -10
  42. data/lib/aws-sdk-s3/types.rb +340 -62
  43. data/lib/aws-sdk-s3.rb +1 -1
  44. data/sig/bucket.rbs +1 -0
  45. data/sig/client.rbs +27 -1
  46. data/sig/multipart_upload.rbs +1 -0
  47. data/sig/object.rbs +7 -0
  48. data/sig/object_summary.rbs +1 -0
  49. data/sig/object_version.rbs +6 -0
  50. data/sig/resource.rbs +4 -1
  51. data/sig/types.rbs +15 -0
  52. data/sig/waiters.rbs +12 -0
  53. metadata +6 -6
@@ -44,36 +44,70 @@ setting, caching, and fallback behavior.
44
44
  list_objects_v2: 'READ',
45
45
  list_object_versions: 'READ',
46
46
  list_parts: 'READ',
47
+ head_bucket: 'READ',
48
+ get_object_attributes: 'READ',
47
49
  put_object: 'WRITE',
48
50
  put_object_acl: 'WRITE',
49
51
  delete_object: 'WRITE',
50
52
  abort_multipart_upload: 'WRITE',
51
53
  create_multipart_upload: 'WRITE',
52
54
  upload_part: 'WRITE',
53
- complete_multipart_upload: 'WRITE'
55
+ complete_multipart_upload: 'WRITE',
56
+ delete_objects: 'WRITE',
57
+ copy_object: 'READWRITE'
54
58
  }.freeze
55
59
 
56
60
  def call(context)
61
+ provider = context.config.access_grants_credentials_provider
62
+
57
63
  if access_grants_operation?(context) &&
58
- !s3_express_endpoint?(context)
64
+ !s3_express_endpoint?(context) &&
65
+ !credentials_head_bucket_call?(provider)
59
66
  params = context[:endpoint_params]
60
67
  permission = PERMISSION_MAP[context.operation_name]
61
68
 
62
- provider = context.config.access_grants_credentials_provider
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
+
63
85
  credentials = provider.access_grants_credentials_for(
64
86
  bucket: params[:bucket],
65
- key: params[:key],
87
+ key: key,
66
88
  prefix: params[:prefix],
67
89
  permission: permission
68
90
  )
69
91
  context[:sigv4_credentials] = credentials # Sign will use this
70
92
  end
71
93
 
72
- @handler.call(context)
94
+ with_metric(credentials) { @handler.call(context) }
73
95
  end
74
96
 
75
97
  private
76
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
+
77
111
  def access_grants_operation?(context)
78
112
  params = context[:endpoint_params]
79
113
  params[:bucket] && PERMISSION_MAP[context.operation_name]
@@ -82,6 +116,42 @@ setting, caching, and fallback behavior.
82
116
  def s3_express_endpoint?(context)
83
117
  context[:endpoint_properties]['backend'] == 'S3Express'
84
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
85
155
  end
86
156
 
87
157
  def add_handlers(handlers, config)
@@ -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
@@ -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