s3 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|