s3 0.3.4 → 0.3.5
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.
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -0
- data/lib/s3.rb +1 -0
- data/lib/s3/connection.rb +18 -20
- data/lib/s3/object.rb +9 -5
- data/lib/s3/request.rb +31 -0
- data/lib/s3/service.rb +5 -1
- data/lib/s3/version.rb +1 -1
- data/test/object_test.rb +8 -0
- data/test/test_helper.rb +1 -4
- metadata +19 -11
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
data/lib/s3.rb
CHANGED
data/lib/s3/connection.rb
CHANGED
@@ -19,7 +19,10 @@ module S3
|
|
19
19
|
# * <tt>:timeout</tt> - Timeout to use by the Net::HTTP object
|
20
20
|
# (60 by default)
|
21
21
|
# * <tt>:proxy</tt> - Hash for Net::HTTP Proxy settings
|
22
|
-
#
|
22
|
+
# { :host => "proxy.mydomain.com", :port => "80, :user => "user_a", :password => "secret" }
|
23
|
+
# * <tt>:proxy</tt> - Hash for Net::HTTP Proxy settings
|
24
|
+
# * <tt>:chunk_size</tt> - Size of a chunk when streaming
|
25
|
+
# (1048576 (1 MiB) by default)
|
23
26
|
def initialize(options = {})
|
24
27
|
@access_key_id = options.fetch(:access_key_id)
|
25
28
|
@secret_access_key = options.fetch(:secret_access_key)
|
@@ -27,6 +30,7 @@ module S3
|
|
27
30
|
@debug = options.fetch(:debug, false)
|
28
31
|
@timeout = options.fetch(:timeout, 60)
|
29
32
|
@proxy = options.fetch(:proxy, nil)
|
33
|
+
@chunk_size = options.fetch(:chunk_size, 1048576)
|
30
34
|
end
|
31
35
|
|
32
36
|
# Makes request with given HTTP method, sets missing parameters,
|
@@ -53,7 +57,7 @@ module S3
|
|
53
57
|
def request(method, options)
|
54
58
|
host = options.fetch(:host, HOST)
|
55
59
|
path = options.fetch(:path)
|
56
|
-
body = options.fetch(:body,
|
60
|
+
body = options.fetch(:body, nil)
|
57
61
|
params = options.fetch(:params, {})
|
58
62
|
headers = options.fetch(:headers, {})
|
59
63
|
|
@@ -63,14 +67,21 @@ module S3
|
|
63
67
|
end
|
64
68
|
|
65
69
|
path = URI.escape(path)
|
66
|
-
request =
|
70
|
+
request = Request.new(@chunk_size, method.to_s.upcase, !!body, true, path)
|
67
71
|
|
68
72
|
headers = self.class.parse_headers(headers)
|
69
73
|
headers.each do |key, value|
|
70
74
|
request[key] = value
|
71
75
|
end
|
72
76
|
|
73
|
-
|
77
|
+
if body
|
78
|
+
if body.respond_to?(:read)
|
79
|
+
request.body_stream = body
|
80
|
+
else
|
81
|
+
request.body = body
|
82
|
+
end
|
83
|
+
request.content_length = body.respond_to?(:lstat) ? body.stat.size : body.size
|
84
|
+
end
|
74
85
|
|
75
86
|
send_request(host, request)
|
76
87
|
end
|
@@ -114,7 +125,7 @@ module S3
|
|
114
125
|
# Hash of headers translated from symbol to string, containing
|
115
126
|
# only interesting headers
|
116
127
|
def self.parse_headers(headers)
|
117
|
-
interesting_keys = [:content_type, :x_amz_acl, :x_amz_storage_class, :range,
|
128
|
+
interesting_keys = [:content_type, :cache_control, :x_amz_acl, :x_amz_storage_class, :range,
|
118
129
|
:if_modified_since, :if_unmodified_since,
|
119
130
|
:if_match, :if_none_match,
|
120
131
|
:content_disposition, :content_encoding,
|
@@ -143,19 +154,6 @@ module S3
|
|
143
154
|
|
144
155
|
private
|
145
156
|
|
146
|
-
def request_class(method)
|
147
|
-
case method
|
148
|
-
when :get
|
149
|
-
request_class = Net::HTTP::Get
|
150
|
-
when :head
|
151
|
-
request_class = Net::HTTP::Head
|
152
|
-
when :put
|
153
|
-
request_class = Net::HTTP::Put
|
154
|
-
when :delete
|
155
|
-
request_class = Net::HTTP::Delete
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
157
|
def port
|
160
158
|
use_ssl ? 443 : 80
|
161
159
|
end
|
@@ -177,7 +175,7 @@ module S3
|
|
177
175
|
response = http(host).start do |http|
|
178
176
|
host = http.address
|
179
177
|
|
180
|
-
request[
|
178
|
+
request["Date"] ||= Time.now.httpdate
|
181
179
|
|
182
180
|
if request.body
|
183
181
|
request["Content-Type"] ||= "application/octet-stream"
|
@@ -197,7 +195,7 @@ module S3
|
|
197
195
|
if response.code.to_i == 307
|
198
196
|
if response.body
|
199
197
|
doc = Document.new response.body
|
200
|
-
send_request(doc.elements[
|
198
|
+
send_request(doc.elements["Error"].elements["Endpoint"].text, request, true)
|
201
199
|
end
|
202
200
|
else
|
203
201
|
handle_response(response)
|
data/lib/s3/object.rb
CHANGED
@@ -5,7 +5,7 @@ module S3
|
|
5
5
|
include Parser
|
6
6
|
extend Forwardable
|
7
7
|
|
8
|
-
attr_accessor :content_type, :content_disposition, :content_encoding
|
8
|
+
attr_accessor :content_type, :content_disposition, :content_encoding, :cache_control
|
9
9
|
attr_reader :last_modified, :etag, :size, :bucket, :key, :acl, :storage_class
|
10
10
|
attr_writer :content
|
11
11
|
|
@@ -40,8 +40,8 @@ module S3
|
|
40
40
|
def acl=(acl)
|
41
41
|
@acl = acl.to_s.gsub("_", "-") if acl
|
42
42
|
end
|
43
|
-
|
44
|
-
# Assigns a new storage class (RRS) to the object. Please note
|
43
|
+
|
44
|
+
# Assigns a new storage class (RRS) to the object. Please note
|
45
45
|
# that the storage class is not retrieved from the server and set
|
46
46
|
# to "STANDARD" by default.
|
47
47
|
#
|
@@ -150,6 +150,7 @@ module S3
|
|
150
150
|
headers[:content_type] = options[:content_type] || content_type || "application/octet-stream"
|
151
151
|
headers[:content_encoding] = options[:content_encoding] if options[:content_encoding]
|
152
152
|
headers[:content_disposition] = options[:content_disposition] if options[:content_disposition]
|
153
|
+
headers[:cache_control] = options[:cache_control] if options[:cache_control]
|
153
154
|
headers[:x_amz_copy_source] = full_key
|
154
155
|
headers[:x_amz_metadata_directive] = "REPLACE"
|
155
156
|
headers[:x_amz_copy_source_if_match] = options[:if_match] if options[:if_match]
|
@@ -165,6 +166,7 @@ module S3
|
|
165
166
|
object.content_type = response["content-type"]
|
166
167
|
object.content_encoding = response["content-encoding"]
|
167
168
|
object.content_disposition = response["content-disposition"]
|
169
|
+
object.cache_control = response["cache-control"]
|
168
170
|
object
|
169
171
|
end
|
170
172
|
|
@@ -185,8 +187,7 @@ module S3
|
|
185
187
|
end
|
186
188
|
|
187
189
|
def put_object
|
188
|
-
|
189
|
-
response = object_request(:put, :body => body, :headers => dump_headers)
|
190
|
+
response = object_request(:put, :body => content, :headers => dump_headers)
|
190
191
|
parse_headers(response)
|
191
192
|
end
|
192
193
|
|
@@ -200,6 +201,7 @@ module S3
|
|
200
201
|
self.last_modified = options[:last_modified]
|
201
202
|
self.etag = options[:etag]
|
202
203
|
self.size = options[:size]
|
204
|
+
self.cache_control = options[:cache_control]
|
203
205
|
end
|
204
206
|
|
205
207
|
def object_request(method, options = {})
|
@@ -229,6 +231,7 @@ module S3
|
|
229
231
|
headers[:content_type] = @content_type || "application/octet-stream"
|
230
232
|
headers[:content_encoding] = @content_encoding if @content_encoding
|
231
233
|
headers[:content_disposition] = @content_disposition if @content_disposition
|
234
|
+
headers[:cache_control] = @cache_control if @cache_control
|
232
235
|
headers
|
233
236
|
end
|
234
237
|
|
@@ -236,6 +239,7 @@ module S3
|
|
236
239
|
self.etag = response["etag"]
|
237
240
|
self.content_type = response["content-type"]
|
238
241
|
self.content_disposition = response["content-disposition"]
|
242
|
+
self.cache_control = response["cache-control"]
|
239
243
|
self.content_encoding = response["content-encoding"]
|
240
244
|
self.last_modified = response["last-modified"]
|
241
245
|
if response["content-range"]
|
data/lib/s3/request.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module S3
|
2
|
+
# Class responsible for sending chunked requests
|
3
|
+
# properly. Net::HTTPGenericRequest has hardcoded chunk_size, so we
|
4
|
+
# inherit the class and override chunk_size.
|
5
|
+
class Request < Net::HTTPGenericRequest
|
6
|
+
def initialize(chunk_size, m, reqbody, resbody, path, initheader = nil)
|
7
|
+
@chunk_size = chunk_size
|
8
|
+
super(m, reqbody, resbody, path, initheader)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def send_request_with_body_stream(sock, ver, path, f)
|
14
|
+
unless content_length() or chunked?
|
15
|
+
raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'"
|
16
|
+
end
|
17
|
+
supply_default_content_type
|
18
|
+
write_header sock, ver, path
|
19
|
+
if chunked?
|
20
|
+
while s = f.read(@chunk_size)
|
21
|
+
sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
|
22
|
+
end
|
23
|
+
sock.write "0\r\n\r\n"
|
24
|
+
else
|
25
|
+
while s = f.read(@chunk_size)
|
26
|
+
sock.write s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/s3/service.rb
CHANGED
@@ -22,12 +22,15 @@ module S3
|
|
22
22
|
# (false by default)
|
23
23
|
# * <tt>:timeout</tt> - Timeout to use by the Net::HTTP object
|
24
24
|
# (60 by default)
|
25
|
+
# * <tt>:chunk_size</tt> - Size of a chunk when streaming
|
26
|
+
# (1048576 (1 MiB) by default)
|
25
27
|
def initialize(options)
|
26
28
|
@access_key_id = options.fetch(:access_key_id)
|
27
29
|
@secret_access_key = options.fetch(:secret_access_key)
|
28
30
|
@use_ssl = options.fetch(:use_ssl, false)
|
29
31
|
@timeout = options.fetch(:timeout, 60)
|
30
32
|
@debug = options.fetch(:debug, false)
|
33
|
+
@chunk_size = options.fetch(:chunk_size, 1048576)
|
31
34
|
|
32
35
|
raise ArgumentError, "Missing proxy settings. Must specify at least :host." if options[:proxy] && !options[:proxy][:host]
|
33
36
|
@proxy = options.fetch(:proxy, nil)
|
@@ -74,7 +77,8 @@ module S3
|
|
74
77
|
:use_ssl => @use_ssl,
|
75
78
|
:timeout => @timeout,
|
76
79
|
:debug => @debug,
|
77
|
-
:proxy => @proxy
|
80
|
+
:proxy => @proxy,
|
81
|
+
:chunk_size => @chunk_size)
|
78
82
|
end
|
79
83
|
@connection
|
80
84
|
end
|
data/lib/s3/version.rb
CHANGED
data/test/object_test.rb
CHANGED
@@ -11,6 +11,8 @@ class ObjectTest < Test::Unit::TestCase
|
|
11
11
|
@object_lena = S3::Object.send(:new, @bucket_images, :key => "Lena.png")
|
12
12
|
@object_lena.content = "test"
|
13
13
|
@object_carmen = S3::Object.send(:new, @bucket_images, :key => "Carmen.png")
|
14
|
+
@object_mac = S3::Object.send(:new, @bucket_images, :key => "Mac.png", :cache_control => "max-age=315360000")
|
15
|
+
@object_mac.content = "test2"
|
14
16
|
|
15
17
|
@response_binary = Net::HTTPOK.new("1.1", "200", "OK")
|
16
18
|
@response_binary.stubs(:body).returns("test".respond_to?(:force_encoding) ? "test".force_encoding(Encoding::BINARY) : "test")
|
@@ -105,6 +107,12 @@ class ObjectTest < Test::Unit::TestCase
|
|
105
107
|
assert @object_lena.save
|
106
108
|
end
|
107
109
|
|
110
|
+
test "save with cache control headers" do
|
111
|
+
assert_equal "max-age=315360000", @object_mac.cache_control
|
112
|
+
@object_mac.expects(:object_request).with(:put, :body=>"test2", :headers=>{ :x_amz_acl=>"public-read", :x_amz_storage_class=>"STANDARD", :content_type=>"application/octet-stream", :cache_control=>"max-age=315360000" }).returns(@response_binary)
|
113
|
+
assert @object_mac.save
|
114
|
+
end
|
115
|
+
|
108
116
|
test "content and parse headers" do
|
109
117
|
@object_lena.expects(:object_request).with(:get, {}).returns(@response_binary)
|
110
118
|
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
9
|
+
- 5
|
10
|
+
version: 0.3.5
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- "Jakub Ku\xC5\xBAma"
|
@@ -14,63 +15,67 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-10-05 00:00:00 +02:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name: proxies
|
22
|
-
prerelease: false
|
23
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
23
|
none: false
|
25
24
|
requirements:
|
26
25
|
- - ">="
|
27
26
|
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
28
|
segments:
|
29
29
|
- 0
|
30
30
|
version: "0"
|
31
31
|
type: :runtime
|
32
|
+
name: proxies
|
33
|
+
prerelease: false
|
32
34
|
version_requirements: *id001
|
33
35
|
- !ruby/object:Gem::Dependency
|
34
|
-
name: test-unit
|
35
|
-
prerelease: false
|
36
36
|
requirement: &id002 !ruby/object:Gem::Requirement
|
37
37
|
none: false
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
+
hash: 3
|
41
42
|
segments:
|
42
43
|
- 2
|
43
44
|
- 0
|
44
45
|
version: "2.0"
|
45
46
|
type: :development
|
47
|
+
name: test-unit
|
48
|
+
prerelease: false
|
46
49
|
version_requirements: *id002
|
47
50
|
- !ruby/object:Gem::Dependency
|
48
|
-
name: mocha
|
49
|
-
prerelease: false
|
50
51
|
requirement: &id003 !ruby/object:Gem::Requirement
|
51
52
|
none: false
|
52
53
|
requirements:
|
53
54
|
- - ">="
|
54
55
|
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
55
57
|
segments:
|
56
58
|
- 0
|
57
59
|
version: "0"
|
58
60
|
type: :development
|
61
|
+
name: mocha
|
62
|
+
prerelease: false
|
59
63
|
version_requirements: *id003
|
60
64
|
- !ruby/object:Gem::Dependency
|
61
|
-
name: bundler
|
62
|
-
prerelease: false
|
63
65
|
requirement: &id004 !ruby/object:Gem::Requirement
|
64
66
|
none: false
|
65
67
|
requirements:
|
66
68
|
- - ">="
|
67
69
|
- !ruby/object:Gem::Version
|
70
|
+
hash: 23
|
68
71
|
segments:
|
69
72
|
- 1
|
70
73
|
- 0
|
71
74
|
- 0
|
72
75
|
version: 1.0.0
|
73
76
|
type: :development
|
77
|
+
name: bundler
|
78
|
+
prerelease: false
|
74
79
|
version_requirements: *id004
|
75
80
|
description: "S3 library provides access to Amazon's Simple Storage Service. It supports both: European and US buckets through REST API."
|
76
81
|
email:
|
@@ -98,6 +103,7 @@ files:
|
|
98
103
|
- lib/s3/object.rb
|
99
104
|
- lib/s3/objects_extension.rb
|
100
105
|
- lib/s3/parser.rb
|
106
|
+
- lib/s3/request.rb
|
101
107
|
- lib/s3/service.rb
|
102
108
|
- lib/s3/signature.rb
|
103
109
|
- lib/s3/version.rb
|
@@ -122,6 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
128
|
requirements:
|
123
129
|
- - ">="
|
124
130
|
- !ruby/object:Gem::Version
|
131
|
+
hash: 3
|
125
132
|
segments:
|
126
133
|
- 0
|
127
134
|
version: "0"
|
@@ -130,6 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
137
|
requirements:
|
131
138
|
- - ">="
|
132
139
|
- !ruby/object:Gem::Version
|
140
|
+
hash: 23
|
133
141
|
segments:
|
134
142
|
- 1
|
135
143
|
- 3
|