aws-sdk-s3 1.75.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.
- checksums.yaml +7 -0
- data/lib/aws-sdk-s3.rb +73 -0
- data/lib/aws-sdk-s3/bucket.rb +861 -0
- data/lib/aws-sdk-s3/bucket_acl.rb +277 -0
- data/lib/aws-sdk-s3/bucket_cors.rb +262 -0
- data/lib/aws-sdk-s3/bucket_lifecycle.rb +264 -0
- data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +283 -0
- data/lib/aws-sdk-s3/bucket_logging.rb +251 -0
- data/lib/aws-sdk-s3/bucket_notification.rb +293 -0
- data/lib/aws-sdk-s3/bucket_policy.rb +242 -0
- data/lib/aws-sdk-s3/bucket_region_cache.rb +81 -0
- data/lib/aws-sdk-s3/bucket_request_payment.rb +236 -0
- data/lib/aws-sdk-s3/bucket_tagging.rb +251 -0
- data/lib/aws-sdk-s3/bucket_versioning.rb +312 -0
- data/lib/aws-sdk-s3/bucket_website.rb +292 -0
- data/lib/aws-sdk-s3/client.rb +11818 -0
- data/lib/aws-sdk-s3/client_api.rb +3014 -0
- data/lib/aws-sdk-s3/customizations.rb +34 -0
- data/lib/aws-sdk-s3/customizations/bucket.rb +162 -0
- data/lib/aws-sdk-s3/customizations/multipart_upload.rb +44 -0
- data/lib/aws-sdk-s3/customizations/object.rb +389 -0
- data/lib/aws-sdk-s3/customizations/object_summary.rb +85 -0
- data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +13 -0
- data/lib/aws-sdk-s3/encryption.rb +21 -0
- data/lib/aws-sdk-s3/encryption/client.rb +375 -0
- data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +190 -0
- data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +65 -0
- data/lib/aws-sdk-s3/encryption/default_key_provider.rb +40 -0
- data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +61 -0
- data/lib/aws-sdk-s3/encryption/errors.rb +15 -0
- data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +58 -0
- data/lib/aws-sdk-s3/encryption/io_decrypter.rb +36 -0
- data/lib/aws-sdk-s3/encryption/io_encrypter.rb +71 -0
- data/lib/aws-sdk-s3/encryption/key_provider.rb +31 -0
- data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +75 -0
- data/lib/aws-sdk-s3/encryption/materials.rb +60 -0
- data/lib/aws-sdk-s3/encryption/utils.rb +81 -0
- data/lib/aws-sdk-s3/encryptionV2/client.rb +388 -0
- data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +198 -0
- data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +103 -0
- data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +38 -0
- data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +66 -0
- data/lib/aws-sdk-s3/encryptionV2/errors.rb +13 -0
- data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +56 -0
- data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +35 -0
- data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +71 -0
- data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +29 -0
- data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +99 -0
- data/lib/aws-sdk-s3/encryptionV2/materials.rb +58 -0
- data/lib/aws-sdk-s3/encryptionV2/utils.rb +116 -0
- data/lib/aws-sdk-s3/encryption_v2.rb +20 -0
- data/lib/aws-sdk-s3/errors.rb +115 -0
- data/lib/aws-sdk-s3/event_streams.rb +69 -0
- data/lib/aws-sdk-s3/file_downloader.rb +142 -0
- data/lib/aws-sdk-s3/file_part.rb +78 -0
- data/lib/aws-sdk-s3/file_uploader.rb +70 -0
- data/lib/aws-sdk-s3/legacy_signer.rb +189 -0
- data/lib/aws-sdk-s3/multipart_file_uploader.rb +227 -0
- data/lib/aws-sdk-s3/multipart_stream_uploader.rb +173 -0
- data/lib/aws-sdk-s3/multipart_upload.rb +401 -0
- data/lib/aws-sdk-s3/multipart_upload_error.rb +18 -0
- data/lib/aws-sdk-s3/multipart_upload_part.rb +423 -0
- data/lib/aws-sdk-s3/object.rb +1422 -0
- data/lib/aws-sdk-s3/object_acl.rb +333 -0
- data/lib/aws-sdk-s3/object_copier.rb +101 -0
- data/lib/aws-sdk-s3/object_multipart_copier.rb +182 -0
- data/lib/aws-sdk-s3/object_summary.rb +1181 -0
- data/lib/aws-sdk-s3/object_version.rb +550 -0
- data/lib/aws-sdk-s3/plugins/accelerate.rb +87 -0
- data/lib/aws-sdk-s3/plugins/bucket_arn.rb +212 -0
- data/lib/aws-sdk-s3/plugins/bucket_dns.rb +91 -0
- data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +45 -0
- data/lib/aws-sdk-s3/plugins/dualstack.rb +74 -0
- data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +28 -0
- data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +25 -0
- data/lib/aws-sdk-s3/plugins/http_200_errors.rb +55 -0
- data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +62 -0
- data/lib/aws-sdk-s3/plugins/location_constraint.rb +35 -0
- data/lib/aws-sdk-s3/plugins/md5s.rb +84 -0
- data/lib/aws-sdk-s3/plugins/redirects.rb +45 -0
- data/lib/aws-sdk-s3/plugins/s3_host_id.rb +30 -0
- data/lib/aws-sdk-s3/plugins/s3_signer.rb +222 -0
- data/lib/aws-sdk-s3/plugins/sse_cpk.rb +70 -0
- data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
- data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +97 -0
- data/lib/aws-sdk-s3/presigned_post.rb +686 -0
- data/lib/aws-sdk-s3/presigner.rb +253 -0
- data/lib/aws-sdk-s3/resource.rb +117 -0
- data/lib/aws-sdk-s3/types.rb +13154 -0
- data/lib/aws-sdk-s3/waiters.rb +243 -0
- metadata +184 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
module S3
|
|
5
|
+
module Plugins
|
|
6
|
+
# Provides support for using `Aws::S3::Client` with Amazon S3 Transfer
|
|
7
|
+
# Acceleration.
|
|
8
|
+
#
|
|
9
|
+
# Go here for more information about transfer acceleration:
|
|
10
|
+
# [http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html](http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html)
|
|
11
|
+
class Accelerate < Seahorse::Client::Plugin
|
|
12
|
+
option(
|
|
13
|
+
:use_accelerate_endpoint,
|
|
14
|
+
default: false,
|
|
15
|
+
doc_type: 'Boolean',
|
|
16
|
+
docstring: <<-DOCS)
|
|
17
|
+
When set to `true`, accelerated bucket endpoints will be used
|
|
18
|
+
for all object operations. You must first enable accelerate for
|
|
19
|
+
each bucket. [Go here for more information](http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html).
|
|
20
|
+
DOCS
|
|
21
|
+
|
|
22
|
+
def add_handlers(handlers, config)
|
|
23
|
+
operations = config.api.operation_names - [
|
|
24
|
+
:create_bucket, :list_buckets, :delete_bucket
|
|
25
|
+
]
|
|
26
|
+
# Need 2 handlers so that the context can be set for other plugins
|
|
27
|
+
# and to remove :use_accelerate_endpoint from the params.
|
|
28
|
+
handlers.add(
|
|
29
|
+
OptionHandler, step: :initialize, operations: operations
|
|
30
|
+
)
|
|
31
|
+
handlers.add(
|
|
32
|
+
AccelerateHandler, step: :build, priority: 0, operations: operations
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
class OptionHandler < Seahorse::Client::Handler
|
|
38
|
+
def call(context)
|
|
39
|
+
# Support client configuration and per-operation configuration
|
|
40
|
+
if context.params.is_a?(Hash)
|
|
41
|
+
accelerate = context.params.delete(:use_accelerate_endpoint)
|
|
42
|
+
end
|
|
43
|
+
if accelerate.nil?
|
|
44
|
+
accelerate = context.config.use_accelerate_endpoint
|
|
45
|
+
end
|
|
46
|
+
context[:use_accelerate_endpoint] = accelerate
|
|
47
|
+
@handler.call(context)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @api private
|
|
52
|
+
class AccelerateHandler < Seahorse::Client::Handler
|
|
53
|
+
def call(context)
|
|
54
|
+
if context[:use_accelerate_endpoint]
|
|
55
|
+
dualstack = !!context[:use_dualstack_endpoint]
|
|
56
|
+
use_accelerate_endpoint(context, dualstack)
|
|
57
|
+
end
|
|
58
|
+
@handler.call(context)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def use_accelerate_endpoint(context, dualstack)
|
|
64
|
+
bucket_name = context.params[:bucket]
|
|
65
|
+
validate_bucket_name!(bucket_name)
|
|
66
|
+
endpoint = URI.parse(context.http_request.endpoint.to_s)
|
|
67
|
+
endpoint.scheme = 'https'
|
|
68
|
+
endpoint.port = 443
|
|
69
|
+
endpoint.host = "#{bucket_name}.s3-accelerate"\
|
|
70
|
+
"#{'.dualstack' if dualstack}.amazonaws.com"
|
|
71
|
+
context.http_request.endpoint = endpoint.to_s
|
|
72
|
+
# s3 accelerate endpoint doesn't work with 'expect' header
|
|
73
|
+
context.http_request.headers.delete('expect')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def validate_bucket_name!(bucket_name)
|
|
77
|
+
unless BucketDns.dns_compatible?(bucket_name, _ssl = true)
|
|
78
|
+
raise ArgumentError,
|
|
79
|
+
'Unable to use `use_accelerate_endpoint: true` on buckets '\
|
|
80
|
+
'with non-DNS compatible names.'
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
module S3
|
|
5
|
+
module Plugins
|
|
6
|
+
# When an accesspoint ARN is provided for :bucket in S3 operations, this
|
|
7
|
+
# plugin resolves the request endpoint from the ARN when possible.
|
|
8
|
+
class BucketARN < Seahorse::Client::Plugin
|
|
9
|
+
option(
|
|
10
|
+
:s3_use_arn_region,
|
|
11
|
+
default: true,
|
|
12
|
+
doc_type: 'Boolean',
|
|
13
|
+
docstring: <<-DOCS) do |cfg|
|
|
14
|
+
By default, the SDK will use the S3 ARN region, and cross-region
|
|
15
|
+
requests could be made. Set to `false` to not use the region from
|
|
16
|
+
the S3 ARN.
|
|
17
|
+
DOCS
|
|
18
|
+
resolve_s3_use_arn_region(cfg)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add_handlers(handlers, _config)
|
|
22
|
+
handlers.add(Handler)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @api private
|
|
26
|
+
class Handler < Seahorse::Client::Handler
|
|
27
|
+
def call(context)
|
|
28
|
+
bucket_member = _bucket_member(context.operation.input.shape)
|
|
29
|
+
if bucket_member && (bucket = context.params[bucket_member])
|
|
30
|
+
_resolved_bucket, _resolved_region, arn = BucketARN.resolve_arn!(
|
|
31
|
+
bucket,
|
|
32
|
+
context.config.region,
|
|
33
|
+
context.config.s3_use_arn_region
|
|
34
|
+
)
|
|
35
|
+
if arn
|
|
36
|
+
if arn.resource.start_with?('accesspoint')
|
|
37
|
+
validate_config!(context.config)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
dualstack = extract_dualstack_config!(context)
|
|
41
|
+
|
|
42
|
+
BucketARN.resolve_url!(
|
|
43
|
+
context.http_request.endpoint,
|
|
44
|
+
arn,
|
|
45
|
+
dualstack
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
@handler.call(context)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def _bucket_member(input)
|
|
55
|
+
input.members.each do |member, ref|
|
|
56
|
+
return member if ref.shape.name == 'BucketName'
|
|
57
|
+
end
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# other plugins use dualstack so disable it when we're done
|
|
62
|
+
def extract_dualstack_config!(context)
|
|
63
|
+
dualstack = context[:use_dualstack_endpoint]
|
|
64
|
+
context[:use_dualstack_endpoint] = false if dualstack
|
|
65
|
+
dualstack
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def validate_config!(config)
|
|
69
|
+
unless config.regional_endpoint
|
|
70
|
+
raise ArgumentError,
|
|
71
|
+
'Cannot provide both an accesspoint ARN and :endpoint.'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if config.use_accelerate_endpoint
|
|
75
|
+
raise ArgumentError,
|
|
76
|
+
'Cannot provide both an accesspoint ARN and setting '\
|
|
77
|
+
':use_accelerate_endpoint to true.'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if config.force_path_style
|
|
81
|
+
raise ArgumentError,
|
|
82
|
+
'Cannot provide both an accesspoint ARN and setting '\
|
|
83
|
+
':force_path_style to true.'
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class << self
|
|
89
|
+
|
|
90
|
+
# @api private
|
|
91
|
+
def resolve_arn!(bucket_name, region, s3_use_arn_region)
|
|
92
|
+
if Aws::ARNParser.arn?(bucket_name)
|
|
93
|
+
arn = Aws::ARNParser.parse(bucket_name)
|
|
94
|
+
validate_s3_arn!(arn)
|
|
95
|
+
validate_region!(arn, region, s3_use_arn_region)
|
|
96
|
+
if arn.resource.start_with?('accesspoint')
|
|
97
|
+
region = arn.region if s3_use_arn_region
|
|
98
|
+
[bucket_name, region, arn]
|
|
99
|
+
else
|
|
100
|
+
raise ArgumentError,
|
|
101
|
+
'Only accesspoint type ARNs are currently supported.'
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
[bucket_name, region]
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @api private
|
|
109
|
+
def resolve_url!(url, arn, dualstack = false)
|
|
110
|
+
if arn.resource.start_with?('accesspoint')
|
|
111
|
+
url.host = accesspoint_arn_host(arn, dualstack)
|
|
112
|
+
else
|
|
113
|
+
raise ArgumentError,
|
|
114
|
+
'Only accesspoint type ARNs are currently supported.'
|
|
115
|
+
end
|
|
116
|
+
url.path = url_path(url.path, arn)
|
|
117
|
+
url
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def accesspoint_arn_host(arn, dualstack)
|
|
123
|
+
_resource_type, resource_name = parse_resource(arn.resource)
|
|
124
|
+
sfx = Aws::Partitions::EndpointProvider.dns_suffix_for(arn.region)
|
|
125
|
+
"#{resource_name}-#{arn.account_id}"\
|
|
126
|
+
'.s3-accesspoint'\
|
|
127
|
+
"#{'.dualstack' if dualstack}"\
|
|
128
|
+
".#{arn.region}.#{sfx}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def parse_resource(str)
|
|
132
|
+
slash = str.index('/') || str.length
|
|
133
|
+
colon = str.index(':') || str.length
|
|
134
|
+
delimiter = slash < colon ? slash : colon
|
|
135
|
+
if delimiter < str.length
|
|
136
|
+
[str[0..(delimiter - 1)], str[(delimiter + 1)..-1]]
|
|
137
|
+
else
|
|
138
|
+
[nil, str]
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def resolve_s3_use_arn_region(cfg)
|
|
143
|
+
value = ENV['AWS_S3_USE_ARN_REGION'] ||
|
|
144
|
+
Aws.shared_config.s3_use_arn_region(profile: cfg.profile) ||
|
|
145
|
+
'true'
|
|
146
|
+
|
|
147
|
+
# Raise if provided value is not true or false
|
|
148
|
+
if value != 'true' && value != 'false'
|
|
149
|
+
raise ArgumentError,
|
|
150
|
+
'Must provide either `true` or `false` for '\
|
|
151
|
+
's3_use_arn_region profile option or for '\
|
|
152
|
+
'ENV[\'AWS_S3_USE_ARN_REGION\']'
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
value == 'true'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def url_path(path, arn)
|
|
159
|
+
path = path.sub("/#{Seahorse::Util.uri_escape(arn.to_s)}", '')
|
|
160
|
+
.sub("/#{arn}", '')
|
|
161
|
+
"/#{path}" unless path.match(/^\//)
|
|
162
|
+
path
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def validate_s3_arn!(arn)
|
|
166
|
+
_resource_type, resource_name = parse_resource(arn.resource)
|
|
167
|
+
|
|
168
|
+
unless arn.service == 's3'
|
|
169
|
+
raise ArgumentError, 'Must provide an S3 ARN.'
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
if arn.region.empty? || arn.account_id.empty?
|
|
173
|
+
raise ArgumentError,
|
|
174
|
+
'S3 Access Point ARNs must contain both a valid region '\
|
|
175
|
+
' and a valid account id.'
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
if resource_name.include?(':') || resource_name.include?('/')
|
|
179
|
+
raise ArgumentError,
|
|
180
|
+
'ARN resource id must be a single value.'
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
unless Plugins::BucketDns.valid_subdomain?(
|
|
184
|
+
"#{resource_name}-#{arn.account_id}"
|
|
185
|
+
)
|
|
186
|
+
raise ArgumentError,
|
|
187
|
+
"#{resource_name}-#{arn.account_id} is not a "\
|
|
188
|
+
'valid subdomain.'
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def validate_region!(arn, region, s3_use_arn_region)
|
|
193
|
+
if region.include?('fips')
|
|
194
|
+
raise ArgumentError,
|
|
195
|
+
'FIPS client regions are currently not supported with '\
|
|
196
|
+
'accesspoint ARNs.'
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if s3_use_arn_region &&
|
|
200
|
+
!Aws::Partitions.partition(arn.partition).region?(region)
|
|
201
|
+
raise Aws::Errors::InvalidARNPartitionError
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
if !s3_use_arn_region && region != arn.region
|
|
205
|
+
raise Aws::Errors::InvalidARNRegionError
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
module S3
|
|
5
|
+
module Plugins
|
|
6
|
+
|
|
7
|
+
# Amazon S3 requires DNS style addressing for buckets outside of
|
|
8
|
+
# the classic region when possible.
|
|
9
|
+
class BucketDns < Seahorse::Client::Plugin
|
|
10
|
+
|
|
11
|
+
# When set to `false` DNS compatible bucket names are moved from
|
|
12
|
+
# the request URI path to the host as a subdomain, unless the request
|
|
13
|
+
# is using SSL and the bucket name contains a dot.
|
|
14
|
+
#
|
|
15
|
+
# When set to `true`, the bucket name is always forced to be part
|
|
16
|
+
# of the request URI path. This will not work with buckets outside
|
|
17
|
+
# the classic region.
|
|
18
|
+
option(:force_path_style,
|
|
19
|
+
default: false,
|
|
20
|
+
doc_type: 'Boolean',
|
|
21
|
+
docstring: <<-DOCS)
|
|
22
|
+
When set to `true`, the bucket name is always left in the
|
|
23
|
+
request URI and never moved to the host as a sub-domain.
|
|
24
|
+
DOCS
|
|
25
|
+
|
|
26
|
+
def add_handlers(handlers, config)
|
|
27
|
+
handlers.add(Handler) unless config.force_path_style
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @api private
|
|
31
|
+
class Handler < Seahorse::Client::Handler
|
|
32
|
+
|
|
33
|
+
def call(context)
|
|
34
|
+
move_dns_compat_bucket_to_subdomain(context)
|
|
35
|
+
@handler.call(context)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def move_dns_compat_bucket_to_subdomain(context)
|
|
41
|
+
bucket_name = context.params[:bucket]
|
|
42
|
+
endpoint = context.http_request.endpoint
|
|
43
|
+
if bucket_name &&
|
|
44
|
+
BucketDns.dns_compatible?(bucket_name, https?(endpoint)) &&
|
|
45
|
+
context.operation_name.to_s != 'get_bucket_location'
|
|
46
|
+
move_bucket_to_subdomain(bucket_name, endpoint)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def move_bucket_to_subdomain(bucket_name, endpoint)
|
|
51
|
+
endpoint.host = "#{bucket_name}.#{endpoint.host}"
|
|
52
|
+
path = endpoint.path.sub("/#{bucket_name}", '')
|
|
53
|
+
path = "/#{path}" unless path.match(/^\//)
|
|
54
|
+
endpoint.path = path
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def https?(uri)
|
|
58
|
+
uri.scheme == 'https'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class << self
|
|
64
|
+
|
|
65
|
+
# @param [String] bucket_name
|
|
66
|
+
# @param [Boolean] ssl
|
|
67
|
+
# @return [Boolean]
|
|
68
|
+
def dns_compatible?(bucket_name, ssl)
|
|
69
|
+
if valid_subdomain?(bucket_name)
|
|
70
|
+
bucket_name.match(/\./) && ssl ? false : true
|
|
71
|
+
else
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Checks for a valid RFC-3986 host name
|
|
77
|
+
# @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
|
78
|
+
# @param [String] bucket_name
|
|
79
|
+
# @return [Boolean]
|
|
80
|
+
def valid_subdomain?(bucket_name)
|
|
81
|
+
bucket_name.size < 64 &&
|
|
82
|
+
bucket_name =~ /^[a-z0-9][a-z0-9.-]+[a-z0-9]$/ &&
|
|
83
|
+
bucket_name !~ /(\d+\.){3}\d+/ &&
|
|
84
|
+
bucket_name !~ /[.-]{2}/
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
module S3
|
|
5
|
+
module Plugins
|
|
6
|
+
# @api private
|
|
7
|
+
class BucketNameRestrictions < Seahorse::Client::Plugin
|
|
8
|
+
class Handler < Seahorse::Client::Handler
|
|
9
|
+
|
|
10
|
+
# Useful because Aws::S3::Errors::SignatureDoesNotMatch is thrown
|
|
11
|
+
# when passed a bucket with a forward slash. Instead provide a more
|
|
12
|
+
# helpful error. Ideally should not be a plugin?
|
|
13
|
+
def call(context)
|
|
14
|
+
bucket_member = _bucket_member(context.operation.input.shape)
|
|
15
|
+
if bucket_member && (bucket = context.params[bucket_member])
|
|
16
|
+
_resolved_bucket, _resolved_region, arn = BucketARN.resolve_arn!(
|
|
17
|
+
bucket,
|
|
18
|
+
context.config.region,
|
|
19
|
+
context.config.s3_use_arn_region
|
|
20
|
+
)
|
|
21
|
+
if !arn && bucket.include?('/')
|
|
22
|
+
raise ArgumentError,
|
|
23
|
+
'bucket name must not contain a forward-slash (/)'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
@handler.call(context)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def _bucket_member(input)
|
|
32
|
+
input.members.each do |member, ref|
|
|
33
|
+
return member if ref.shape.name == 'BucketName'
|
|
34
|
+
end
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
handler(Handler)
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
module S3
|
|
5
|
+
module Plugins
|
|
6
|
+
# @api private
|
|
7
|
+
class Dualstack < Seahorse::Client::Plugin
|
|
8
|
+
|
|
9
|
+
option(:use_dualstack_endpoint,
|
|
10
|
+
default: false,
|
|
11
|
+
doc_type: 'Boolean',
|
|
12
|
+
docstring: <<-DOCS)
|
|
13
|
+
When set to `true`, IPv6-compatible bucket endpoints will be used
|
|
14
|
+
for all operations.
|
|
15
|
+
DOCS
|
|
16
|
+
|
|
17
|
+
def add_handlers(handlers, config)
|
|
18
|
+
handlers.add(OptionHandler, step: :initialize)
|
|
19
|
+
handlers.add(DualstackHandler, step: :build, priority: 0)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @api private
|
|
23
|
+
class OptionHandler < Seahorse::Client::Handler
|
|
24
|
+
def call(context)
|
|
25
|
+
if context.params.is_a?(Hash)
|
|
26
|
+
dualstack = context.params.delete(:use_dualstack_endpoint)
|
|
27
|
+
end
|
|
28
|
+
dualstack = context.config.use_dualstack_endpoint if dualstack.nil?
|
|
29
|
+
context[:use_dualstack_endpoint] = dualstack
|
|
30
|
+
@handler.call(context)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @api private
|
|
35
|
+
class DualstackHandler < Seahorse::Client::Handler
|
|
36
|
+
def call(context)
|
|
37
|
+
apply_dualstack_endpoint(context) if use_dualstack_endpoint?(context)
|
|
38
|
+
@handler.call(context)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
def apply_dualstack_endpoint(context)
|
|
43
|
+
bucket_name = context.params[:bucket]
|
|
44
|
+
region = context.config.region
|
|
45
|
+
context.config.force_path_style
|
|
46
|
+
dns_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(region)
|
|
47
|
+
|
|
48
|
+
if use_bucket_dns?(bucket_name, context)
|
|
49
|
+
host = "#{bucket_name}.s3.dualstack.#{region}.#{dns_suffix}"
|
|
50
|
+
else
|
|
51
|
+
host = "s3.dualstack.#{region}.#{dns_suffix}"
|
|
52
|
+
end
|
|
53
|
+
endpoint = URI.parse(context.http_request.endpoint.to_s)
|
|
54
|
+
endpoint.scheme = context.http_request.endpoint.scheme
|
|
55
|
+
endpoint.port = context.http_request.endpoint.port
|
|
56
|
+
endpoint.host = host
|
|
57
|
+
context.http_request.endpoint = endpoint.to_s
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def use_bucket_dns?(bucket_name, context)
|
|
61
|
+
ssl = context.http_request.endpoint.scheme == "https"
|
|
62
|
+
bucket_name && BucketDns.dns_compatible?(bucket_name, ssl) &&
|
|
63
|
+
!context.config.force_path_style
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def use_dualstack_endpoint?(context)
|
|
67
|
+
context[:use_dualstack_endpoint] && !context[:use_accelerate_endpoint]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|