aws-sdk 1.2.3 → 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/aws/core.rb +1 -1
- data/lib/aws/core/http/net_http_handler.rb +21 -62
- data/lib/aws/record/attribute_macros.rb +28 -4
- data/lib/aws/record/attributes/date.rb +89 -0
- data/lib/aws/record/base.rb +41 -4
- data/lib/aws/record/finder_methods.rb +7 -5
- data/lib/aws/record/scope.rb +32 -5
- data/lib/aws/s3/bucket.rb +14 -5
- data/lib/aws/s3/bucket_version_collection.rb +7 -11
- data/lib/aws/s3/client.rb +37 -1
- data/lib/aws/s3/client/xml.rb +8 -1
- data/lib/aws/s3/errors.rb +14 -0
- data/lib/aws/s3/multipart_upload_collection.rb +0 -3
- data/lib/aws/s3/object_collection.rb +182 -6
- data/lib/aws/s3/paginated_collection.rb +21 -40
- data/lib/aws/s3/prefix_and_delimiter_collection.rb +0 -7
- data/lib/aws/s3/presigned_post.rb +26 -11
- data/lib/aws/s3/request.rb +1 -1
- data/lib/aws/s3/s3_object.rb +10 -4
- data/lib/aws/s3/uploaded_part_collection.rb +3 -1
- data/lib/net/http/connection_pool.rb +193 -0
- data/lib/net/http/connection_pool/connection.rb +132 -0
- data/lib/net/http/connection_pool/session.rb +93 -0
- metadata +8 -4
@@ -19,13 +19,6 @@ module AWS
|
|
19
19
|
|
20
20
|
include PrefixedCollection
|
21
21
|
|
22
|
-
def each(options = {}, &block)
|
23
|
-
each_page(options) do |page|
|
24
|
-
each_member_in_page(page, &block)
|
25
|
-
end
|
26
|
-
nil
|
27
|
-
end
|
28
|
-
|
29
22
|
# @see Bucket#as_tree
|
30
23
|
def as_tree options = {}
|
31
24
|
Tree.new(self, { :prefix => prefix }.merge(options))
|
@@ -340,15 +340,21 @@ module AWS
|
|
340
340
|
# long as they are described by a policy condition (see
|
341
341
|
# {#where}).
|
342
342
|
def fields
|
343
|
-
signature =
|
344
|
-
config.signer.sign(policy, "sha1")
|
345
343
|
|
346
|
-
|
344
|
+
signature = config.signer.sign(policy, "sha1")
|
345
|
+
|
346
|
+
fields = {
|
347
347
|
"AWSAccessKeyId" => config.signer.access_key_id,
|
348
348
|
"key" => key,
|
349
349
|
"policy" => policy,
|
350
350
|
"signature" => signature
|
351
351
|
}.merge(optional_fields)
|
352
|
+
|
353
|
+
fields["x-amz-security-token"] = config.signer.session_token if
|
354
|
+
config.signer.session_token
|
355
|
+
|
356
|
+
fields.merge(optional_fields)
|
357
|
+
|
352
358
|
end
|
353
359
|
|
354
360
|
# @private
|
@@ -482,14 +488,23 @@ module AWS
|
|
482
488
|
# @private
|
483
489
|
private
|
484
490
|
def generate_conditions
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
491
|
+
|
492
|
+
conditions = self.conditions.inject([]) do |list, (field, field_conds)|
|
493
|
+
list + field_conds
|
494
|
+
end
|
495
|
+
|
496
|
+
conditions << { "bucket" => bucket.name }
|
497
|
+
conditions += key_conditions
|
498
|
+
conditions += optional_fields.map { |(n, v)| Hash[[[n, v]]] }
|
499
|
+
conditions += range_conditions
|
500
|
+
conditions += ignored_conditions
|
501
|
+
|
502
|
+
if config.signer.session_token
|
503
|
+
conditions << {"x-amz-security-token" => config.signer.session_token}
|
504
|
+
end
|
505
|
+
|
506
|
+
conditions
|
507
|
+
|
493
508
|
end
|
494
509
|
|
495
510
|
# @private
|
data/lib/aws/s3/request.rb
CHANGED
data/lib/aws/s3/s3_object.rb
CHANGED
@@ -410,13 +410,12 @@ module AWS
|
|
410
410
|
upload = multipart_uploads.create(options)
|
411
411
|
|
412
412
|
if block_given?
|
413
|
-
result = nil
|
414
413
|
begin
|
415
414
|
yield(upload)
|
416
|
-
|
417
|
-
|
415
|
+
upload.close
|
416
|
+
rescue
|
417
|
+
upload.abort
|
418
418
|
end
|
419
|
-
result
|
420
419
|
else
|
421
420
|
upload
|
422
421
|
end
|
@@ -488,6 +487,10 @@ module AWS
|
|
488
487
|
# option in the current configuration; for more information,
|
489
488
|
# see {AWS.config}.
|
490
489
|
#
|
490
|
+
# @option options :cache_control [String] Can be used to specify
|
491
|
+
# caching behavior. See
|
492
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
493
|
+
#
|
491
494
|
# @return [nil]
|
492
495
|
def copy_from source, options = {}
|
493
496
|
|
@@ -524,6 +527,8 @@ module AWS
|
|
524
527
|
copy_opts[:server_side_encryption] =
|
525
528
|
options[:server_side_encryption] if
|
526
529
|
options.key?(:server_side_encryption)
|
530
|
+
copy_opts[:cache_control] = options[:cache_control] if
|
531
|
+
options[:cache_control]
|
527
532
|
add_configured_write_options(copy_opts)
|
528
533
|
|
529
534
|
if options[:reduced_redundancy]
|
@@ -641,6 +646,7 @@ module AWS
|
|
641
646
|
# the object ETag matches the provided value.
|
642
647
|
#
|
643
648
|
# @option options [Range] :range A byte range to read data from
|
649
|
+
#
|
644
650
|
def read(options = {}, &blk)
|
645
651
|
options[:bucket_name] = bucket.name
|
646
652
|
options[:key] = key
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require 'net/http/connection_pool/session'
|
15
|
+
require 'net/http/connection_pool/connection'
|
16
|
+
require 'thread'
|
17
|
+
|
18
|
+
# @private
|
19
|
+
class Net::HTTP::ConnectionPool
|
20
|
+
|
21
|
+
SOCKET_ERRORS = [
|
22
|
+
EOFError,
|
23
|
+
IOError,
|
24
|
+
Errno::ECONNABORTED,
|
25
|
+
Errno::ECONNRESET,
|
26
|
+
Errno::EPIPE,
|
27
|
+
Errno::EINVAL
|
28
|
+
]
|
29
|
+
|
30
|
+
# @params [Hash] options
|
31
|
+
#
|
32
|
+
# @option options [Numeric] :idle_timeout (60) The number of seconds a
|
33
|
+
# connection is allowed to sit idle before it is closed and removed
|
34
|
+
# from the pool.
|
35
|
+
#
|
36
|
+
# @option options [Numeric] :open_timeout (15) The number of seconds to
|
37
|
+
# wait when opening a http session before raising a timeout exception.
|
38
|
+
#
|
39
|
+
def initialize options = {}
|
40
|
+
@pool = []
|
41
|
+
@pool_mutex = Mutex.new
|
42
|
+
@open_timeout = options[:open_timeout] || 15
|
43
|
+
@idle_timeout = options[:idle_timeout] || 60
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Integer]
|
47
|
+
attr_reader :idle_timeout
|
48
|
+
|
49
|
+
# @return [Integer]
|
50
|
+
attr_accessor :open_timeout
|
51
|
+
|
52
|
+
# Requests a http session from the connection pool.
|
53
|
+
#
|
54
|
+
# pool.connection_for('domain.com') do |connection|
|
55
|
+
#
|
56
|
+
# # make
|
57
|
+
# connection.request(Net::HTTP::Get.new('/index.html'))
|
58
|
+
# connection.request(Net::HTTP::Get.new('/about.html'))
|
59
|
+
#
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# The yielded connection object is a thin wrapper around the persistent
|
63
|
+
# http session object. You generally want to call {Connection#request}
|
64
|
+
# on the yielded object. When the block is complete the connection
|
65
|
+
# will be returned to the pool.
|
66
|
+
#
|
67
|
+
# @param [String] host
|
68
|
+
#
|
69
|
+
# @param [Hash] options
|
70
|
+
#
|
71
|
+
# @option options [Integer] :port Which port the connection should use.
|
72
|
+
# Defaults to 80, unless +:ssl+ is +true+, then it defaults to 443.
|
73
|
+
#
|
74
|
+
# @option options [Boolean] :ssl If the connection should be made over
|
75
|
+
# SSL. Defaults to +false+, unless +:port+ is 443, then it defaults
|
76
|
+
# to +true+.
|
77
|
+
#
|
78
|
+
# @option options [Boolean] :ssl_verify_peer (true) If true, ssl
|
79
|
+
# connections will verify peer certificates. This should only ever be
|
80
|
+
# set false false for debugging purposes.
|
81
|
+
#
|
82
|
+
# @option options [String] :ssl_ca_file Full path to the SSL certificate
|
83
|
+
# authority bundle file that should be used when verifying peer
|
84
|
+
# certificates. If you do not pass +:ssl_ca_file+ or +:ssl_ca_path+
|
85
|
+
# the the system default will be used if available.
|
86
|
+
#
|
87
|
+
# @option options [String] :ssl_ca_path Full path of the directory that
|
88
|
+
# contains the unbundled SSL certificate authority files for verifying
|
89
|
+
# peer certificates. If you do not pass +:ssl_ca_file+ or +:ssl_ca_path+
|
90
|
+
# the the system default will be used if available.
|
91
|
+
#
|
92
|
+
# @option options [URI::HTTP,String] :proxy_uri (nil) A URI string or
|
93
|
+
# URI::HTTP for a proxy reqeusts should be made through. You should
|
94
|
+
# not pass both +:proxy_uri+ with any of the other proxy options.
|
95
|
+
#
|
96
|
+
# :proxy_uri => 'http://user:pass@host.com:80'
|
97
|
+
#
|
98
|
+
# @option options [String] :proxy_address
|
99
|
+
#
|
100
|
+
# @option options [String] :proxy_port
|
101
|
+
#
|
102
|
+
# @option options [String] :proxy_user
|
103
|
+
#
|
104
|
+
# @option options [String] :proxy_password
|
105
|
+
#
|
106
|
+
# @yieldparam [Connection] connection
|
107
|
+
#
|
108
|
+
# @return [nil]
|
109
|
+
#
|
110
|
+
def connection_for host, options = {}, &block
|
111
|
+
connection = Connection.new(self, host, options)
|
112
|
+
if block_given?
|
113
|
+
yield(connection)
|
114
|
+
else
|
115
|
+
connection
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def request connection, *request_args, &block
|
120
|
+
session = nil
|
121
|
+
response = nil
|
122
|
+
retried = false
|
123
|
+
begin
|
124
|
+
session = session_for(connection)
|
125
|
+
session.http_session.read_timeout = connection.read_timeout
|
126
|
+
response = session.request(*request_args, &block)
|
127
|
+
rescue *SOCKET_ERRORS => error
|
128
|
+
# retry socket errors once
|
129
|
+
unless retried
|
130
|
+
retried = true
|
131
|
+
retry
|
132
|
+
end
|
133
|
+
raise error
|
134
|
+
else
|
135
|
+
@pool_mutex.synchronize { @pool << session }
|
136
|
+
end
|
137
|
+
response
|
138
|
+
end
|
139
|
+
|
140
|
+
# Returns the number of sessions currently in the pool, not counting those
|
141
|
+
# currently in use.
|
142
|
+
def size
|
143
|
+
@pool_mutex.synchronize { @pool.size }
|
144
|
+
end
|
145
|
+
|
146
|
+
# Removes http sessions from the pool that have passed the idle timeout
|
147
|
+
def clean!
|
148
|
+
@pool_mutex.synchronize { _clean }
|
149
|
+
end
|
150
|
+
|
151
|
+
# Finishes and removes removes all sessions from the pool.
|
152
|
+
# If empty! is called while there are outstanding requests they may
|
153
|
+
# get checked back into the pool, leaving the pool in a non-empty state.
|
154
|
+
def empty!
|
155
|
+
@pool_mutex.synchronize do
|
156
|
+
@pool.each(&:finish)
|
157
|
+
@pool = []
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns a suitable session from the pool or creates a new one
|
162
|
+
private
|
163
|
+
def session_for connection
|
164
|
+
session = nil
|
165
|
+
|
166
|
+
@pool_mutex.synchronize do
|
167
|
+
_clean
|
168
|
+
session = @pool.find{|idle_session| idle_session.key == connection.key }
|
169
|
+
@pool.delete(session) if session
|
170
|
+
end
|
171
|
+
|
172
|
+
if session.nil?
|
173
|
+
session = Session.for(connection, open_timeout)
|
174
|
+
end
|
175
|
+
|
176
|
+
session
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
def _clean
|
181
|
+
now = Time.now
|
182
|
+
@pool.delete_if do |idle_session|
|
183
|
+
if
|
184
|
+
idle_session.last_used_at.nil? or
|
185
|
+
now - idle_session.last_used_at > idle_timeout
|
186
|
+
then
|
187
|
+
idle_session.finish
|
188
|
+
true
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require 'uri'
|
15
|
+
|
16
|
+
class Net::HTTP::ConnectionPool
|
17
|
+
|
18
|
+
# A light wrapper around Net::HTTP.
|
19
|
+
#
|
20
|
+
# You should not need to construct connection objects yourself.
|
21
|
+
# You receive them as a response to {ConnectionPool#connection_for}.
|
22
|
+
#
|
23
|
+
class Connection
|
24
|
+
|
25
|
+
# @param [ConnectionPool] pool
|
26
|
+
# @param (see ConnectionPool#connection_for)
|
27
|
+
# @option (see ConnectionPool#connection_for)
|
28
|
+
# @return [Connection]
|
29
|
+
def initialize pool, host, options = {}
|
30
|
+
|
31
|
+
@pool = pool
|
32
|
+
|
33
|
+
@host = host
|
34
|
+
|
35
|
+
@port = options.key?(:port) ? options[:port] : (options[:ssl] ? 443 : 80)
|
36
|
+
|
37
|
+
@ssl = options.key?(:ssl) ? options[:ssl] : (port == 443)
|
38
|
+
|
39
|
+
@ssl_verify_peer = options.key?(:ssl_verify_peer) ?
|
40
|
+
options[:ssl_verify_peer] : true
|
41
|
+
|
42
|
+
@ssl_ca_file = options[:ssl_ca_file]
|
43
|
+
|
44
|
+
@ssl_ca_path = options[:ssl_ca_path]
|
45
|
+
|
46
|
+
if uri = options[:proxy_uri]
|
47
|
+
uri = URI.parse(uri) if uri.is_a?(String)
|
48
|
+
@proxy_address = uri.host
|
49
|
+
@proxy_port = uri.port
|
50
|
+
@proxy_user = uri.user
|
51
|
+
@proxy_password = uri.password
|
52
|
+
else
|
53
|
+
@proxy_address = options[:proxy_address]
|
54
|
+
@proxy_port = options[:proxy_port]
|
55
|
+
@proxy_user = options[:proxy_user]
|
56
|
+
@proxy_password = options[:proxy_password]
|
57
|
+
end
|
58
|
+
|
59
|
+
@read_timeout = options[:read_timeout] || 60
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [ConnectionPool]
|
64
|
+
attr_reader :pool
|
65
|
+
|
66
|
+
# @return [String]
|
67
|
+
attr_reader :host
|
68
|
+
|
69
|
+
# @return [Integer]
|
70
|
+
attr_reader :port
|
71
|
+
|
72
|
+
# @return [Boolean]
|
73
|
+
attr_reader :ssl
|
74
|
+
|
75
|
+
# @return [Boolean]
|
76
|
+
attr_reader :ssl_verify_peer
|
77
|
+
|
78
|
+
# @return [String,nil]
|
79
|
+
attr_reader :ssl_ca_file
|
80
|
+
|
81
|
+
# @return [String,nil]
|
82
|
+
attr_reader :ssl_ca_path
|
83
|
+
|
84
|
+
# @return [String,nil]
|
85
|
+
attr_reader :proxy_address
|
86
|
+
|
87
|
+
# @return [Integer,nil]
|
88
|
+
attr_reader :proxy_port
|
89
|
+
|
90
|
+
# @return [String,nil]
|
91
|
+
attr_reader :proxy_user
|
92
|
+
|
93
|
+
# @return [String,nil]
|
94
|
+
attr_reader :proxy_password
|
95
|
+
|
96
|
+
# @return [Numeric,nil]
|
97
|
+
attr_accessor :read_timeout
|
98
|
+
|
99
|
+
# @return [Boolean] Returns true if this connection requires SSL.
|
100
|
+
def ssl?
|
101
|
+
@ssl
|
102
|
+
end
|
103
|
+
|
104
|
+
# @return [Boolean] Returns true if ssl connections should verify the
|
105
|
+
# peer certificate.
|
106
|
+
def ssl_verify_peer?
|
107
|
+
@ssl_verify_peer
|
108
|
+
end
|
109
|
+
|
110
|
+
# @return [Boolean] Returns true if this connection proxies requests.
|
111
|
+
def proxy?
|
112
|
+
!!proxy_address
|
113
|
+
end
|
114
|
+
|
115
|
+
def request *args, &block
|
116
|
+
pool.request(self, *args, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
# @return [String] Returns a key that can be used to group connections
|
120
|
+
# that connection to the same host.
|
121
|
+
def key
|
122
|
+
@key ||= begin
|
123
|
+
%w(
|
124
|
+
host port
|
125
|
+
ssl ssl_verify_peer ssl_ca_file ssl_ca_path
|
126
|
+
proxy_address proxy_port proxy_user proxy_password
|
127
|
+
).map{|part| send(part).to_s }.join(":")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|