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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- s3 (0.3.3)
4
+ s3 (0.3.5)
5
5
  proxies
6
6
 
7
7
  GEM
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require "bundler"
2
2
  Bundler::GemHelper.install_tasks
3
+ Bundler.setup
3
4
 
4
5
  require "rake/testtask"
5
6
  require "rake/rdoctask"
data/lib/s3.rb CHANGED
@@ -15,6 +15,7 @@ require "s3/parser"
15
15
  require "s3/bucket"
16
16
  require "s3/connection"
17
17
  require "s3/exceptions"
18
+ require "s3/request"
18
19
  require "s3/object"
19
20
  require "s3/service"
20
21
  require "s3/signature"
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
- # { :host => "proxy.mydomain.com", :port => "80, :user => "user_a", :password => "secret" }
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 = request_class(method).new(path)
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
- request.body = body
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['Date'] ||= Time.now.httpdate
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['Error'].elements['Endpoint'].text, request, true)
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
- body = content.is_a?(IO) ? content.read : content
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
@@ -1,3 +1,3 @@
1
1
  module S3
2
- VERSION = "0.3.4"
2
+ VERSION = "0.3.5"
3
3
  end
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
@@ -1,6 +1,3 @@
1
- require "rubygems"
2
- require "bundler/setup"
3
-
4
- Bundler.require
5
1
  require "test/unit"
6
2
  require "mocha"
3
+ require "s3"
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
- - 4
9
- version: 0.3.4
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-09-25 00:00:00 +02:00
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