cloudfiles 1.4.17 → 1.4.18
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/Gemfile +4 -0
- data/cloudfiles.gemspec +1 -1
- data/lib/cloudfiles/authentication.rb +15 -11
- data/lib/cloudfiles/connection.rb +25 -11
- data/lib/cloudfiles/container.rb +64 -33
- data/lib/cloudfiles/storage_object.rb +39 -31
- data/lib/cloudfiles/version.rb +1 -1
- data/test/cloudfiles_connection_test.rb +45 -2
- data/test/cloudfiles_container_test.rb +88 -19
- data/test/cloudfiles_storage_object_test.rb +16 -11
- metadata +7 -5
data/CHANGELOG
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
================================================================================
|
2
|
+
1.4.18 (2011/09/07)
|
3
|
+
================================================================================
|
4
|
+
o Added Streaming URL support
|
5
|
+
|
1
6
|
================================================================================
|
2
7
|
1.4.17 (2011/05/27)
|
3
8
|
================================================================================
|
data/Gemfile
CHANGED
data/cloudfiles.gemspec
CHANGED
@@ -14,29 +14,33 @@ module CloudFiles
|
|
14
14
|
path = parsed_auth_url.path
|
15
15
|
hdrhash = { "X-Auth-User" => connection.authuser, "X-Auth-Key" => connection.authkey }
|
16
16
|
begin
|
17
|
-
server
|
17
|
+
server = get_server(connection, parsed_auth_url)
|
18
18
|
|
19
19
|
if parsed_auth_url.scheme == "https"
|
20
20
|
server.use_ssl = true
|
21
21
|
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
22
22
|
end
|
23
23
|
server.start
|
24
|
-
rescue
|
25
|
-
|
24
|
+
rescue Exception => e
|
25
|
+
# uncomment if you suspect a problem with this branch of code
|
26
|
+
# $stderr.puts "got error #{e.class}: #{e.message.inspect}\n" << e.traceback.map{|n| "\t#{n}"}.join("\n")
|
27
|
+
raise CloudFiles::Exception::Connection, "Unable to connect to #{server.address}", caller
|
26
28
|
end
|
27
29
|
response = server.get(path, hdrhash)
|
28
30
|
if (response.code =~ /^20./)
|
29
31
|
if response["x-cdn-management-url"]
|
30
32
|
connection.cdn_available = true
|
31
|
-
|
32
|
-
connection.
|
33
|
-
connection.
|
34
|
-
connection.
|
33
|
+
parsed_cdn_url = URI.parse(response["x-cdn-management-url"])
|
34
|
+
connection.cdnmgmthost = parsed_cdn_url.host
|
35
|
+
connection.cdnmgmtpath = parsed_cdn_url.path
|
36
|
+
connection.cdnmgmtport = parsed_cdn_url.port
|
37
|
+
connection.cdnmgmtscheme = parsed_cdn_url.scheme
|
35
38
|
end
|
36
|
-
|
37
|
-
connection.
|
38
|
-
connection.
|
39
|
-
connection.
|
39
|
+
parsed_storage_url = URI.parse(response["x-storage-url"])
|
40
|
+
connection.storagehost = set_snet(connection, parsed_storage_url.host)
|
41
|
+
connection.storagepath = parsed_storage_url.path
|
42
|
+
connection.storageport = parsed_storage_url.port
|
43
|
+
connection.storagescheme = parsed_storage_url.scheme
|
40
44
|
connection.authtoken = response["x-auth-token"]
|
41
45
|
connection.authok = true
|
42
46
|
else
|
@@ -133,7 +133,7 @@ module CloudFiles
|
|
133
133
|
# cf.bytes
|
134
134
|
# => 42438527
|
135
135
|
def get_info
|
136
|
-
response =
|
136
|
+
response = storage_request("HEAD")
|
137
137
|
raise CloudFiles::Exception::InvalidResponse, "Unable to obtain account size" unless (response.code == "204")
|
138
138
|
@bytes = response["x-account-bytes-used"].to_i
|
139
139
|
@count = response["x-account-container-count"].to_i
|
@@ -166,7 +166,7 @@ module CloudFiles
|
|
166
166
|
query = []
|
167
167
|
query << "limit=#{CloudFiles.escape limit.to_s}" if limit.to_i > 0
|
168
168
|
query << "marker=#{CloudFiles.escape marker.to_s}" unless marker.to_s.empty?
|
169
|
-
response =
|
169
|
+
response = storage_request("GET", "?#{query.join('&')}")
|
170
170
|
return [] if (response.code == "204")
|
171
171
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
|
172
172
|
CloudFiles.lines(response.body)
|
@@ -187,7 +187,7 @@ module CloudFiles
|
|
187
187
|
query = ['format=xml']
|
188
188
|
query << "limit=#{CloudFiles.escape limit.to_s}" if limit.to_i > 0
|
189
189
|
query << "marker=#{CloudFiles.escape marker.to_s}" unless marker.to_s.empty?
|
190
|
-
response =
|
190
|
+
response = storage_request("GET", "?#{query.join('&')}")
|
191
191
|
return {} if (response.code == "204")
|
192
192
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
|
193
193
|
doc = REXML::Document.new(response.body)
|
@@ -208,7 +208,7 @@ module CloudFiles
|
|
208
208
|
# cf.container_exists?('bad_container')
|
209
209
|
# => false
|
210
210
|
def container_exists?(containername)
|
211
|
-
response =
|
211
|
+
response = storage_request("HEAD", CloudFiles.escape(containername))
|
212
212
|
return (response.code == "204")? true : false ;
|
213
213
|
end
|
214
214
|
|
@@ -227,7 +227,7 @@ module CloudFiles
|
|
227
227
|
def create_container(containername)
|
228
228
|
raise CloudFiles::Exception::Syntax, "Container name cannot contain the characters '/' or '?'" if containername.match(/[\/\?]/)
|
229
229
|
raise CloudFiles::Exception::Syntax, "Container name is limited to 256 characters" if containername.length > 256
|
230
|
-
response =
|
230
|
+
response = storage_request("PUT", CloudFiles.escape(containername))
|
231
231
|
raise CloudFiles::Exception::InvalidResponse, "Unable to create container #{containername}" unless (response.code == "201" || response.code == "202")
|
232
232
|
CloudFiles::Container.new(self, containername)
|
233
233
|
end
|
@@ -244,7 +244,7 @@ module CloudFiles
|
|
244
244
|
# cf.delete_container('nonexistent')
|
245
245
|
# => NoSuchContainerException: Container nonexistent does not exist
|
246
246
|
def delete_container(containername)
|
247
|
-
response =
|
247
|
+
response = storage_request("DELETE", CloudFiles.escape(containername))
|
248
248
|
raise CloudFiles::Exception::NonEmptyContainer, "Container #{containername} is not empty" if (response.code == "409")
|
249
249
|
raise CloudFiles::Exception::NoSuchContainer, "Container #{containername} does not exist" unless (response.code == "204")
|
250
250
|
true
|
@@ -261,12 +261,22 @@ module CloudFiles
|
|
261
261
|
# => ["video", "webpics"]
|
262
262
|
def public_containers(enabled_only = false)
|
263
263
|
paramstr = enabled_only == true ? "enabled_only=true" : ""
|
264
|
-
response =
|
264
|
+
response = cdn_request("GET", "?#{paramstr}")
|
265
265
|
return [] if (response.code == "204")
|
266
266
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
|
267
267
|
CloudFiles.lines(response.body)
|
268
268
|
end
|
269
269
|
|
270
|
+
def storage_request(method, path = "", headers = {}, data = nil, attempts = 0, &block)
|
271
|
+
path = "#{@storagepath}/#{path}" unless (path[0,1] == '/')
|
272
|
+
cfreq(method, @storagehost, path, @storageport, @storagescheme, headers, data, attempts, &block)
|
273
|
+
end
|
274
|
+
|
275
|
+
def cdn_request(method, path = "", headers = {}, data = nil, attempts = 0, &block)
|
276
|
+
path = "#{@cdnmgmtpath}/#{path}" unless (path[0,1] == '/')
|
277
|
+
cfreq(method, @cdnmgmthost, path, @cdnmgmtport, @cdnmgmtscheme, headers, data, attempts, &block)
|
278
|
+
end
|
279
|
+
|
270
280
|
# This method actually makes the HTTP calls out to the server
|
271
281
|
def cfreq(method, server, path, port, scheme, headers = {}, data = nil, attempts = 0, &block) # :nodoc:
|
272
282
|
start = Time.now
|
@@ -292,7 +302,11 @@ module CloudFiles
|
|
292
302
|
response
|
293
303
|
rescue Errno::EPIPE, Timeout::Error, Errno::EINVAL, EOFError, IOError
|
294
304
|
# Server closed the connection, retry
|
295
|
-
|
305
|
+
if attempts >= 5
|
306
|
+
host_str = server.respond_to?(:address) ? server.address : server
|
307
|
+
raise CloudFiles::Exception::Connection, "Unable to reconnect to #{host_str} after #{attempts} attempts", caller
|
308
|
+
end
|
309
|
+
|
296
310
|
attempts += 1
|
297
311
|
begin
|
298
312
|
@http[server].finish
|
@@ -302,7 +316,7 @@ module CloudFiles
|
|
302
316
|
start_http(server, path, port, scheme, headers)
|
303
317
|
retry
|
304
318
|
rescue ExpiredAuthTokenException
|
305
|
-
raise CloudFiles::Exception::Connection, "Authentication token expired and you have requested not to retry" if @retry_auth == false
|
319
|
+
raise CloudFiles::Exception::Connection, "Authentication token expired and you have requested not to retry", caller if @retry_auth == false
|
306
320
|
CloudFiles::Authentication.new(self)
|
307
321
|
retry
|
308
322
|
end
|
@@ -329,8 +343,8 @@ module CloudFiles
|
|
329
343
|
@http[server].verify_mode = OpenSSL::SSL::VERIFY_NONE
|
330
344
|
end
|
331
345
|
@http[server].start
|
332
|
-
rescue
|
333
|
-
raise CloudFiles::Exception::Connection, "Unable to connect to #{server.address}"
|
346
|
+
rescue Exception
|
347
|
+
raise CloudFiles::Exception::Connection, "Unable to connect to #{server.address}", caller
|
334
348
|
end
|
335
349
|
end
|
336
350
|
end
|
data/lib/cloudfiles/container.rb
CHANGED
@@ -16,16 +16,6 @@ module CloudFiles
|
|
16
16
|
def initialize(connection, name)
|
17
17
|
@connection = connection
|
18
18
|
@name = name
|
19
|
-
@storagehost = self.connection.storagehost
|
20
|
-
@storagepath = self.connection.storagepath + "/" + CloudFiles.escape(@name)
|
21
|
-
@storageport = self.connection.storageport
|
22
|
-
@storagescheme = self.connection.storagescheme
|
23
|
-
if self.connection.cdn_available?
|
24
|
-
@cdnmgmthost = self.connection.cdnmgmthost
|
25
|
-
@cdnmgmtpath = self.connection.cdnmgmtpath + "/" + CloudFiles.escape(@name) if self.connection.cdnmgmtpath
|
26
|
-
@cdnmgmtport = self.connection.cdnmgmtport
|
27
|
-
@cdnmgmtscheme = self.connection.cdnmgmtscheme
|
28
|
-
end
|
29
19
|
# Load the metadata now, so we'll get a CloudFiles::Exception::NoSuchContainer exception should the container
|
30
20
|
# not exist.
|
31
21
|
self.container_metadata
|
@@ -51,11 +41,11 @@ module CloudFiles
|
|
51
41
|
# Retrieves Metadata for the container
|
52
42
|
def container_metadata
|
53
43
|
@metadata ||= (
|
54
|
-
response = self.connection.
|
44
|
+
response = self.connection.storage_request("HEAD", "#{escaped_name}/")
|
55
45
|
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code =~ /^20/)
|
56
46
|
resphash = {}
|
57
47
|
response.to_hash.select { |k,v| k.match(/^x-container-meta/) }.each { |x| resphash[x[0]] = x[1].to_s }
|
58
|
-
{:bytes => response["x-container-bytes-used"].to_i, :count => response["x-container-object-count"].to_i, :metadata => resphash}
|
48
|
+
{:bytes => response["x-container-bytes-used"].to_i, :count => response["x-container-object-count"].to_i, :metadata => resphash, :container_read => response["x-container-read"], :container_write => response["x-container-write"]}
|
59
49
|
)
|
60
50
|
end
|
61
51
|
|
@@ -64,13 +54,14 @@ module CloudFiles
|
|
64
54
|
return @cdn_metadata if @cdn_metadata
|
65
55
|
if cdn_available?
|
66
56
|
@cdn_metadata = (
|
67
|
-
response = self.connection.
|
57
|
+
response = self.connection.cdn_request("HEAD", escaped_name)
|
68
58
|
cdn_enabled = ((response["x-cdn-enabled"] || "").downcase == "true") ? true : false
|
69
59
|
{
|
70
60
|
:cdn_enabled => cdn_enabled,
|
71
61
|
:cdn_ttl => cdn_enabled ? response["x-ttl"].to_i : nil,
|
72
62
|
:cdn_url => cdn_enabled ? response["x-cdn-uri"] : nil,
|
73
63
|
:cdn_ssl_url => cdn_enabled ? response["x-cdn-ssl-uri"] : nil,
|
64
|
+
:cdn_streaming_url => cdn_enabled ? response["x-cdn-streaming-uri"] : nil,
|
74
65
|
:user_agent_acl => response["x-user-agent-acl"],
|
75
66
|
:referrer_acl => response["x-referrer-acl"],
|
76
67
|
:cdn_log => (cdn_enabled and response["x-log-retention"] == "True") ? true : false
|
@@ -100,7 +91,7 @@ module CloudFiles
|
|
100
91
|
def set_metadata(metadatahash)
|
101
92
|
headers = {}
|
102
93
|
metadatahash.each{ |key, value| headers['X-Container-Meta-' + CloudFiles.escape(key.to_s.capitalize)] = value.to_s }
|
103
|
-
response = self.connection.
|
94
|
+
response = self.connection.storage_request("POST", escaped_name, headers)
|
104
95
|
raise CloudFiles::Exception::NoSuchObject, "Container #{@name} does not exist" if (response.code == "404")
|
105
96
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
|
106
97
|
true
|
@@ -108,12 +99,12 @@ module CloudFiles
|
|
108
99
|
|
109
100
|
# Size of the container (in bytes)
|
110
101
|
def bytes
|
111
|
-
self.
|
102
|
+
self.container_metadata[:bytes]
|
112
103
|
end
|
113
104
|
|
114
105
|
# Number of objects in the container
|
115
106
|
def count
|
116
|
-
self.
|
107
|
+
self.container_metadata[:count]
|
117
108
|
end
|
118
109
|
|
119
110
|
# Returns true if the container is public and CDN-enabled. Returns false otherwise.
|
@@ -145,6 +136,10 @@ module CloudFiles
|
|
145
136
|
def cdn_ssl_url
|
146
137
|
self.cdn_metadata[:cdn_ssl_url]
|
147
138
|
end
|
139
|
+
# CDN Streaming container URL (if container is public)
|
140
|
+
def cdn_ssl_url
|
141
|
+
self.cdn_metadata[:cdn_streaming_url]
|
142
|
+
end
|
148
143
|
|
149
144
|
# The container ACL on the User Agent
|
150
145
|
def user_agent_acl
|
@@ -156,6 +151,16 @@ module CloudFiles
|
|
156
151
|
self.cdn_metadata[:referrer_acl]
|
157
152
|
end
|
158
153
|
|
154
|
+
#used by openstack swift
|
155
|
+
def read_acl
|
156
|
+
self.container_metadata[:container_read]
|
157
|
+
end
|
158
|
+
|
159
|
+
#used by openstack swift
|
160
|
+
def write_acl
|
161
|
+
self.container_metadata[:container_write]
|
162
|
+
end
|
163
|
+
|
159
164
|
# Returns true if log retention is enabled on this container, false otherwise
|
160
165
|
def cdn_log
|
161
166
|
self.cdn_metadata[:cdn_log]
|
@@ -166,10 +171,10 @@ module CloudFiles
|
|
166
171
|
# Change the log retention status for this container. Values are true or false.
|
167
172
|
#
|
168
173
|
# These logs will be periodically (at unpredictable intervals) compressed and uploaded
|
169
|
-
# to a
|
174
|
+
# to a ".CDN_ACCESS_LOGS" container in the form of "container_name.YYYYMMDDHH-XXXX.gz".
|
170
175
|
def log_retention=(value)
|
171
176
|
raise Exception::CDNNotAvailable unless cdn_available?
|
172
|
-
response = self.connection.
|
177
|
+
response = self.connection.cdn_request("POST", escaped_name, {"x-log-retention" => value.to_s.capitalize})
|
173
178
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "201" or response.code == "202")
|
174
179
|
return true
|
175
180
|
end
|
@@ -216,7 +221,7 @@ module CloudFiles
|
|
216
221
|
query << "#{param}=#{CloudFiles.escape(value.to_s)}"
|
217
222
|
end
|
218
223
|
end
|
219
|
-
response = self.connection.
|
224
|
+
response = self.connection.storage_request("GET", "#{escaped_name}?#{query.join '&'}")
|
220
225
|
return [] if (response.code == "204")
|
221
226
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
|
222
227
|
return CloudFiles.lines(response.body)
|
@@ -249,7 +254,7 @@ module CloudFiles
|
|
249
254
|
query << "#{param}=#{CloudFiles.escape(value.to_s)}"
|
250
255
|
end
|
251
256
|
end
|
252
|
-
response = self.connection.
|
257
|
+
response = self.connection.storage_request("GET", "#{escaped_name}?#{query.join '&'}")
|
253
258
|
return {} if (response.code == "204")
|
254
259
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
|
255
260
|
doc = REXML::Document.new(response.body)
|
@@ -281,7 +286,7 @@ module CloudFiles
|
|
281
286
|
# container.object_exists?('badfile.txt')
|
282
287
|
# => false
|
283
288
|
def object_exists?(objectname)
|
284
|
-
response = self.connection.
|
289
|
+
response = self.connection.storage_request("HEAD", "#{escaped_name}/#{CloudFiles.escape objectname}")
|
285
290
|
return (response.code =~ /^20/)? true : false
|
286
291
|
end
|
287
292
|
|
@@ -306,7 +311,7 @@ module CloudFiles
|
|
306
311
|
# container.delete_object('nonexistent_file.txt')
|
307
312
|
# => NoSuchObjectException: Object nonexistent_file.txt does not exist
|
308
313
|
def delete_object(objectname)
|
309
|
-
response = self.connection.
|
314
|
+
response = self.connection.storage_request("DELETE", "#{escaped_name}/#{CloudFiles.escape objectname}")
|
310
315
|
raise CloudFiles::Exception::NoSuchObject, "Object #{objectname} does not exist" if (response.code == "404")
|
311
316
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
|
312
317
|
true
|
@@ -333,17 +338,43 @@ module CloudFiles
|
|
333
338
|
options = {:ttl => ttl}
|
334
339
|
end
|
335
340
|
|
336
|
-
response = self.connection.
|
341
|
+
response = self.connection.cdn_request("PUT", escaped_name)
|
337
342
|
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
|
338
343
|
|
339
344
|
headers = { "X-TTL" => options[:ttl].to_s , "X-CDN-Enabled" => "True" }
|
340
345
|
headers["X-User-Agent-ACL"] = options[:user_agent_acl] if options[:user_agent_acl]
|
341
346
|
headers["X-Referrer-ACL"] = options[:referrer_acl] if options[:referrer_acl]
|
342
|
-
response =
|
347
|
+
response = post_with_headers(headers)
|
343
348
|
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
|
344
349
|
refresh
|
345
350
|
true
|
346
351
|
end
|
352
|
+
|
353
|
+
# Only to be used with openstack swift
|
354
|
+
def set_write_acl(write_string)
|
355
|
+
refresh
|
356
|
+
headers = {"X-Container-Write" => write_string}
|
357
|
+
post_with_headers(headers)
|
358
|
+
true
|
359
|
+
end
|
360
|
+
|
361
|
+
# Only to be used with openstack swift
|
362
|
+
def set_read_acl(read_string)
|
363
|
+
refresh
|
364
|
+
headers = {"X-Container-Read" => read_string}
|
365
|
+
post_with_headers(headers)
|
366
|
+
true
|
367
|
+
end
|
368
|
+
|
369
|
+
def post_with_headers(headers = {})
|
370
|
+
if cdn_enabled?
|
371
|
+
response = self.connection.cdn_request("POST", escaped_name, headers)
|
372
|
+
else
|
373
|
+
response = self.connection.storage_request("POST", escaped_name, headers)
|
374
|
+
end
|
375
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist (response code: #{response.code})" unless (response.code =~ /^20/)
|
376
|
+
response
|
377
|
+
end
|
347
378
|
|
348
379
|
# Makes a container private and returns true upon success. Throws NoSuchContainerException
|
349
380
|
# if the container doesn't exist or if the request fails.
|
@@ -355,7 +386,7 @@ module CloudFiles
|
|
355
386
|
def make_private
|
356
387
|
raise Exception::CDNNotAvailable unless cdn_available?
|
357
388
|
headers = { "X-CDN-Enabled" => "False" }
|
358
|
-
response = self.connection.
|
389
|
+
response = self.connection.cdn_request("POST", escaped_name, headers)
|
359
390
|
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
|
360
391
|
refresh
|
361
392
|
true
|
@@ -380,15 +411,11 @@ module CloudFiles
|
|
380
411
|
# => true
|
381
412
|
def purge_from_cdn(email=nil)
|
382
413
|
raise Exception::CDNNotAvailable unless cdn_available?
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
else
|
388
|
-
response = self.connection.cfreq("DELETE", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme)
|
389
|
-
raise CloudFiles::Exception::Connection, "Error Unable to Purge Container: #{@name}" unless (response.code > "200" && response.code < "299")
|
414
|
+
headers = {}
|
415
|
+
headers = {"X-Purge-Email" => email} if email
|
416
|
+
response = self.connection.cdn_request("DELETE", escaped_name, headers)
|
417
|
+
raise CloudFiles::Exception::Connection, "Error Unable to Purge Container: #{@name}" unless (response.code > "200" && response.code < "299")
|
390
418
|
true
|
391
|
-
end
|
392
419
|
end
|
393
420
|
|
394
421
|
def to_s # :nodoc:
|
@@ -398,6 +425,10 @@ module CloudFiles
|
|
398
425
|
def cdn_available?
|
399
426
|
self.connection.cdn_available?
|
400
427
|
end
|
428
|
+
|
429
|
+
def escaped_name
|
430
|
+
CloudFiles.escape(@name)
|
431
|
+
end
|
401
432
|
|
402
433
|
end
|
403
434
|
|
@@ -17,16 +17,8 @@ module CloudFiles
|
|
17
17
|
@containername = container.name
|
18
18
|
@name = objectname
|
19
19
|
@make_path = make_path
|
20
|
-
@
|
21
|
-
|
22
|
-
@storageport = self.container.connection.storageport
|
23
|
-
@storagescheme = self.container.connection.storagescheme
|
24
|
-
if self.container.connection.cdn_available?
|
25
|
-
@cdnmgmthost = self.container.connection.cdnmgmthost
|
26
|
-
@cdnmgmtpath = self.container.connection.cdnmgmtpath + "/#{CloudFiles.escape @containername}/#{CloudFiles.escape @name, '/'}"
|
27
|
-
@cdnmgmtport = self.container.connection.cdnmgmtport
|
28
|
-
@cdnmgmtscheme = self.container.connection.cdnmgmtscheme
|
29
|
-
end
|
20
|
+
@storagepath = "#{CloudFiles.escape @containername}/#{CloudFiles.escape @name, '/'}"
|
21
|
+
|
30
22
|
if force_exists
|
31
23
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless container.object_exists?(objectname)
|
32
24
|
end
|
@@ -42,10 +34,15 @@ module CloudFiles
|
|
42
34
|
# Retrieves Metadata for the object
|
43
35
|
def object_metadata
|
44
36
|
@object_metadata ||= (
|
45
|
-
response = self.container.connection.
|
37
|
+
response = self.container.connection.storage_request("HEAD", @storagepath)
|
46
38
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (response.code =~ /^20/)
|
47
39
|
resphash = {}
|
48
|
-
response.to_hash.select { |k,v| k.match(/^x-object-meta/) }
|
40
|
+
metas = response.to_hash.select { |k,v| k.match(/^x-object-meta/) }
|
41
|
+
|
42
|
+
metas.each do |x,y|
|
43
|
+
resphash[x] = (y.respond_to?(:join) ? y.join('') : y.to_s)
|
44
|
+
end
|
45
|
+
|
49
46
|
{
|
50
47
|
:manifest => response["x-object-manifest"],
|
51
48
|
:bytes => response["content-length"],
|
@@ -76,6 +73,10 @@ module CloudFiles
|
|
76
73
|
def content_type
|
77
74
|
self.object_metadata[:content_type]
|
78
75
|
end
|
76
|
+
|
77
|
+
def content_type=(type)
|
78
|
+
self.copy(:headers => {'Content-Type' => type})
|
79
|
+
end
|
79
80
|
|
80
81
|
# Retrieves the data from an object and stores the data in memory. The data is returned as a string.
|
81
82
|
# Throws a NoSuchObjectException if the object doesn't exist.
|
@@ -90,7 +91,7 @@ module CloudFiles
|
|
90
91
|
range = sprintf("bytes=%d-%d", offset.to_i, (offset.to_i + size.to_i) - 1)
|
91
92
|
headers['Range'] = range
|
92
93
|
end
|
93
|
-
response = self.container.connection.
|
94
|
+
response = self.container.connection.storage_request("GET", @storagepath, headers)
|
94
95
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (response.code =~ /^20/)
|
95
96
|
response.body
|
96
97
|
end
|
@@ -114,7 +115,7 @@ module CloudFiles
|
|
114
115
|
range = sprintf("bytes=%d-%d", offset.to_i, (offset.to_i + size.to_i) - 1)
|
115
116
|
headers['Range'] = range
|
116
117
|
end
|
117
|
-
self.container.connection.
|
118
|
+
self.container.connection.storage_request("GET", @storagepath, headers, nil) do |response|
|
118
119
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist. Response code #{response.code}" unless (response.code =~ /^20./)
|
119
120
|
response.read_body(&block)
|
120
121
|
end
|
@@ -139,11 +140,12 @@ module CloudFiles
|
|
139
140
|
def set_metadata(metadatahash)
|
140
141
|
headers = {}
|
141
142
|
metadatahash.each{ |key, value| headers['X-Object-Meta-' + key.to_s.capitalize] = value.to_s }
|
142
|
-
response = self.container.connection.
|
143
|
+
response = self.container.connection.storage_request("POST", @storagepath, headers)
|
143
144
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (response.code == "404")
|
144
|
-
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code
|
145
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
|
145
146
|
true
|
146
147
|
end
|
148
|
+
alias :metadata= :set_metadata
|
147
149
|
|
148
150
|
|
149
151
|
# Returns the object's manifest.
|
@@ -162,7 +164,7 @@ module CloudFiles
|
|
162
164
|
# fails.
|
163
165
|
def set_manifest(manifest)
|
164
166
|
headers = {'X-Object-Manifest' => manifest}
|
165
|
-
response = self.container.connection.
|
167
|
+
response = self.container.connection.storage_request("PUT", @storagepath, headers)
|
166
168
|
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (response.code == "404")
|
167
169
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
|
168
170
|
true
|
@@ -209,7 +211,7 @@ module CloudFiles
|
|
209
211
|
end
|
210
212
|
# If we're taking data from standard input, send that IO object to cfreq
|
211
213
|
data = $stdin if (data.nil? && $stdin.tty? == false)
|
212
|
-
response = self.container.connection.
|
214
|
+
response = self.container.connection.storage_request("PUT", @storagepath, headers, data)
|
213
215
|
code = response.code
|
214
216
|
raise CloudFiles::Exception::InvalidResponse, "Invalid content-length header sent" if (code == "412")
|
215
217
|
raise CloudFiles::Exception::MisMatchedChecksum, "Mismatched etag" if (code == "422")
|
@@ -237,14 +239,10 @@ module CloudFiles
|
|
237
239
|
# => true
|
238
240
|
def purge_from_cdn(email=nil)
|
239
241
|
raise Exception::CDNNotAvailable unless cdn_available?
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
else
|
245
|
-
response = self.container.connection.cfreq("DELETE", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme)
|
246
|
-
raise CloudFiles::Exception::Connection, "Error Unable to Purge Object: #{@name}" unless (response.code.to_s =~ /^20.$/)
|
247
|
-
end
|
242
|
+
headers = {}
|
243
|
+
headers = {"X-Purge-Email" => email} if email
|
244
|
+
response = self.container.connection.cdn_request("DELETE", @storagepath, headers)
|
245
|
+
raise CloudFiles::Exception::Connection, "Error Unable to Purge Object: #{@name}" unless (response.code.to_s =~ /^20.$/)
|
248
246
|
true
|
249
247
|
end
|
250
248
|
|
@@ -296,7 +294,7 @@ module CloudFiles
|
|
296
294
|
# object.save_to_filename("/tmp/owned_by_root.txt")
|
297
295
|
# => Errno::EACCES: Permission denied - /tmp/owned_by_root.txt
|
298
296
|
def save_to_filename(filename)
|
299
|
-
File.open(filename, '
|
297
|
+
File.open(filename, 'wb+') do |f|
|
300
298
|
self.data_stream do |chunk|
|
301
299
|
f.write chunk
|
302
300
|
end
|
@@ -315,7 +313,7 @@ module CloudFiles
|
|
315
313
|
self.container.public? ? self.container.cdn_url + "/#{CloudFiles.escape @name, '/'}" : nil
|
316
314
|
end
|
317
315
|
|
318
|
-
|
316
|
+
# If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object. Otherwise, return nil
|
319
317
|
#
|
320
318
|
# public_object.public_ssl_url
|
321
319
|
# => "https://c61.ssl.cf0.rackcdn.com/myfile.jpg"
|
@@ -326,6 +324,16 @@ module CloudFiles
|
|
326
324
|
self.container.public? ? self.container.cdn_ssl_url + "/#{CloudFiles.escape @name, '/'}" : nil
|
327
325
|
end
|
328
326
|
|
327
|
+
# If the parent container is public (CDN-enabled), returns the SSL CDN URL to this object. Otherwise, return nil
|
328
|
+
#
|
329
|
+
# public_object.public_streaming_url
|
330
|
+
# => "https://c61.stream.rackcdn.com/myfile.jpg"
|
331
|
+
#
|
332
|
+
# private_object.public_streaming_url
|
333
|
+
# => nil
|
334
|
+
def public_streaming_url
|
335
|
+
self.container.public? ? self.container.cdn_streaming_url + "/#{CloudFiles.escape @name, '/'}" : nil
|
336
|
+
end
|
329
337
|
|
330
338
|
# Copy this object to a new location (optionally in a new container)
|
331
339
|
#
|
@@ -342,7 +350,7 @@ module CloudFiles
|
|
342
350
|
#
|
343
351
|
# Returns the new CloudFiles::StorageObject for the copied item.
|
344
352
|
def copy(options = {})
|
345
|
-
raise CloudFiles::Exception::Syntax, "You must
|
353
|
+
raise CloudFiles::Exception::Syntax, "You must provide the :container, :name, or :headers for this operation" unless (options[:container] || options[:name] || options[:headers])
|
346
354
|
new_container = options[:container] || self.container.name
|
347
355
|
new_name = options[:name] || self.name
|
348
356
|
new_headers = options[:headers] || {}
|
@@ -350,8 +358,8 @@ module CloudFiles
|
|
350
358
|
new_name.sub!(/^\//,'')
|
351
359
|
headers = {'X-Copy-From' => "#{self.container.name}/#{self.name}", 'Content-Type' => self.content_type.sub(/;.+/, '')}.merge(new_headers)
|
352
360
|
# , 'Content-Type' => self.content_type
|
353
|
-
new_path =
|
354
|
-
response = self.container.connection.
|
361
|
+
new_path = "#{CloudFiles.escape new_container}/#{CloudFiles.escape new_name, '/'}"
|
362
|
+
response = self.container.connection.storage_request("PUT", new_path, headers)
|
355
363
|
code = response.code
|
356
364
|
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
|
357
365
|
return CloudFiles::Container.new(self.container.connection, new_container).object(new_name)
|
data/lib/cloudfiles/version.rb
CHANGED
@@ -81,7 +81,49 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
81
81
|
response = @connection.cfreq("HEAD", "test.server.example", "/dummypath", "80", "http")
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
|
+
def test_storage_request
|
86
|
+
build_net_http_object
|
87
|
+
assert_nothing_raised do
|
88
|
+
response = @connection.storage_request("HEAD", "dummypath")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_storage_request_adds_path
|
93
|
+
build_net_http_object({}, {:method => "HEAD", :path => "#{@connection.storagepath}/dummypath"})
|
94
|
+
assert_nothing_raised do
|
95
|
+
response = @connection.storage_request("HEAD", "dummypath")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_storage_path_does_not_add_path_when_absolute
|
100
|
+
build_net_http_object({}, {:method => "HEAD", :path => "/dummypath"})
|
101
|
+
assert_nothing_raised do
|
102
|
+
response = @connection.storage_request("HEAD", "/dummypath")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_cdn_request
|
107
|
+
build_net_http_object
|
108
|
+
assert_nothing_raised do
|
109
|
+
response = @connection.cdn_request("HEAD", "dummypath")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_cdn_request_adds_path
|
114
|
+
build_net_http_object({}, {:method => "HEAD", :path => "#{@connection.cdnmgmtpath}/dummypath"})
|
115
|
+
assert_nothing_raised do
|
116
|
+
response = @connection.cdn_request("HEAD", "dummypath")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_cdn_path_does_not_add_path_when_absolute
|
121
|
+
build_net_http_object({}, {:method => "HEAD", :path => "/dummypath"})
|
122
|
+
assert_nothing_raised do
|
123
|
+
response = @connection.cdn_request("HEAD", "/dummypath")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
85
127
|
def test_net_http_raises_connection_exception
|
86
128
|
Net::HTTP.expects(:new).raises(CloudFiles::Exception::Connection)
|
87
129
|
assert_raises(CloudFiles::Exception::Connection) do
|
@@ -288,7 +330,8 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
288
330
|
|
289
331
|
private
|
290
332
|
|
291
|
-
def build_net_http_object(args={
|
333
|
+
def build_net_http_object(args={}, cfreq_expectations={})
|
334
|
+
args.merge!(:code => '204') unless args[:code]
|
292
335
|
args[:response] = {} unless args[:response]
|
293
336
|
response = {'x-cdn-management-url' => 'http://cdn.example.com/path', 'x-storage-url' => 'http://cdn.example.com/storage', 'authtoken' => 'dummy_token'}.merge(args[:response])
|
294
337
|
response.stubs(:code).returns(args[:code])
|
@@ -7,7 +7,8 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
7
7
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
8
8
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5'}
|
9
9
|
response.stubs(:code).returns('204')
|
10
|
-
connection.stubs(:
|
10
|
+
connection.stubs(:storage_request => response)
|
11
|
+
connection.stubs(:cdn_request => response)
|
11
12
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
12
13
|
assert_equal @container.name, 'test_container'
|
13
14
|
assert_equal @container.class, CloudFiles::Container
|
@@ -20,7 +21,7 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
20
21
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => false)
|
21
22
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5'}
|
22
23
|
response.stubs(:code).returns('204')
|
23
|
-
connection.stubs(:
|
24
|
+
connection.stubs(:storage_request => response)
|
24
25
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
25
26
|
assert_equal 'test_container', @container.name
|
26
27
|
assert_equal CloudFiles::Container, @container.class
|
@@ -31,7 +32,7 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
31
32
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
32
33
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5'}
|
33
34
|
response.stubs(:code).returns('999')
|
34
|
-
connection.stubs(:
|
35
|
+
connection.stubs(:storage_request => response)
|
35
36
|
assert_raise(CloudFiles::Exception::NoSuchContainer) do
|
36
37
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
37
38
|
end
|
@@ -41,7 +42,8 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
41
42
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
42
43
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5', 'x-cdn-enabled' => 'True', 'x-cdn-uri' => 'http://cdn.test.example/container', 'x-ttl' => '86400'}
|
43
44
|
response.stubs(:code).returns('204')
|
44
|
-
connection.stubs(:
|
45
|
+
connection.stubs(:storage_request => response)
|
46
|
+
connection.stubs(:cdn_request => response)
|
45
47
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
46
48
|
assert_equal @container.name, 'test_container'
|
47
49
|
assert_equal @container.cdn_enabled, true
|
@@ -56,28 +58,28 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def test_make_private_succeeds
|
59
|
-
build_net_http_object(:code => '201')
|
61
|
+
build_net_http_object(:code => '201', :cdn_request => true)
|
60
62
|
assert_nothing_raised do
|
61
63
|
@container.make_private
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
65
67
|
def test_make_private_fails
|
66
|
-
build_net_http_object(:code => '999')
|
68
|
+
build_net_http_object(:code => '999', :cdn_request => true)
|
67
69
|
assert_raises(CloudFiles::Exception::NoSuchContainer) do
|
68
70
|
@container.make_private
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
72
74
|
def test_make_public_succeeds
|
73
|
-
build_net_http_object(:code => '201')
|
75
|
+
build_net_http_object(:code => '201', :cdn_request => true)
|
74
76
|
assert_nothing_raised do
|
75
77
|
@container.make_public
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
81
|
def test_make_public_fails
|
80
|
-
build_net_http_object(:code => '999')
|
82
|
+
build_net_http_object(:code => '999', :cdn_request => true)
|
81
83
|
assert_raises(CloudFiles::Exception::NoSuchContainer) do
|
82
84
|
@container.make_public
|
83
85
|
end
|
@@ -87,7 +89,7 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
87
89
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
88
90
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5'}
|
89
91
|
response.stubs(:code).returns('204')
|
90
|
-
connection.stubs(:
|
92
|
+
connection.stubs(:storage_request => response)
|
91
93
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
92
94
|
assert_equal @container.empty?, false
|
93
95
|
end
|
@@ -96,16 +98,80 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
96
98
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
97
99
|
response = {'x-container-bytes-used' => '0', 'x-container-object-count' => '0'}
|
98
100
|
response.stubs(:code).returns('204')
|
99
|
-
connection.stubs(:
|
101
|
+
connection.stubs(:storage_request => response)
|
100
102
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
101
103
|
assert_equal @container.empty?, true
|
102
104
|
end
|
105
|
+
|
106
|
+
def build_acl_test_state(opts={})
|
107
|
+
@connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdn_available? => false)
|
108
|
+
|
109
|
+
@response = {
|
110
|
+
'x-container-bytes-used' => '0',
|
111
|
+
'x-container-object-count' => '0',
|
112
|
+
}.merge(opts.fetch(:response, {}))
|
113
|
+
|
114
|
+
@response.stubs(:code).returns(opts.fetch(:code, '204'))
|
115
|
+
@connection.stubs(:storage_request => @response)
|
116
|
+
@container = CloudFiles::Container.new(@connection, 'test_container')
|
117
|
+
end
|
103
118
|
|
119
|
+
def test_read_acl_is_set_from_headers
|
120
|
+
build_acl_test_state :response => { 'x-container-read' => '.r:*' }, :code => '204'
|
121
|
+
assert_equal @response["x-container-read"], @container.read_acl
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_set_read_acl_fails
|
125
|
+
build_acl_test_state
|
126
|
+
|
127
|
+
response = stub(:code => '999')
|
128
|
+
|
129
|
+
@connection.stubs(:storage_request => response)
|
130
|
+
|
131
|
+
assert_raises(CloudFiles::Exception::NoSuchContainer) do
|
132
|
+
@container.set_read_acl('.r:*')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_set_read_acl_succeeds
|
137
|
+
build_acl_test_state
|
138
|
+
|
139
|
+
@connection.stubs(:storage_request => stub(:code => '204'))
|
140
|
+
|
141
|
+
assert_equal @container.set_read_acl('.r:*'), true
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_write_acl_is_set_from_headers
|
145
|
+
build_acl_test_state :response => { 'x-container-write' => '.r:*' }, :code => '204'
|
146
|
+
assert_equal @response["x-container-write"], @container.write_acl
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_set_write_acl_fails
|
150
|
+
build_acl_test_state
|
151
|
+
|
152
|
+
response = stub(:code => '999')
|
153
|
+
|
154
|
+
@connection.stubs(:storage_request => response)
|
155
|
+
|
156
|
+
assert_raises(CloudFiles::Exception::NoSuchContainer) do
|
157
|
+
@container.set_write_acl('.r:*')
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_set_write_acl_succeeds
|
162
|
+
build_acl_test_state
|
163
|
+
|
164
|
+
@connection.stubs(:storage_request => stub(:code => '204'))
|
165
|
+
|
166
|
+
assert_equal @container.set_write_acl('.r:*'), true
|
167
|
+
end
|
168
|
+
|
104
169
|
def test_log_retention_is_true
|
105
170
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
106
171
|
response = {'x-container-bytes-used' => '0', 'x-container-object-count' => '0', 'x-cdn-enabled' => 'True', 'x-log-retention' => 'True'}
|
107
172
|
response.stubs(:code).returns('204')
|
108
|
-
connection.stubs(:
|
173
|
+
connection.stubs(:cdn_request => response)
|
174
|
+
connection.stubs(:storage_request => response)
|
109
175
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
110
176
|
assert_equal @container.log_retention?, true
|
111
177
|
end
|
@@ -247,12 +313,12 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
247
313
|
end
|
248
314
|
|
249
315
|
def test_setting_log_retention
|
250
|
-
build_net_http_object(:code => '201')
|
316
|
+
build_net_http_object(:code => '201', :cdn_request => true)
|
251
317
|
assert(@container.log_retention='false')
|
252
318
|
end
|
253
319
|
|
254
320
|
def test_purge_from_cdn_succeeds
|
255
|
-
build_net_http_object
|
321
|
+
build_net_http_object(:cdn_request => true)
|
256
322
|
assert_nothing_raised do
|
257
323
|
@container.purge_from_cdn
|
258
324
|
@container.purge_from_cdn("small.fox@hole.org")
|
@@ -261,7 +327,8 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
261
327
|
|
262
328
|
private
|
263
329
|
|
264
|
-
def build_net_http_object(args={
|
330
|
+
def build_net_http_object(args={}, cfreq_expectations={})
|
331
|
+
args.merge!(:code => '204') unless args[:code]
|
265
332
|
CloudFiles::Container.any_instance.stubs(:populate).returns(true)
|
266
333
|
CloudFiles::Container.any_instance.stubs(:metadata).returns()
|
267
334
|
CloudFiles::Container.any_instance.stubs(:container_metadata).returns({:bytes => 99, :count => 2})
|
@@ -274,20 +341,22 @@ class CloudfilesContainerTest < Test::Unit::TestCase
|
|
274
341
|
if !cfreq_expectations.empty?
|
275
342
|
#cfreq(method,server,path,port,scheme,headers = {},data = nil,attempts = 0,&block)
|
276
343
|
|
277
|
-
parameter_expectations = [anything(), anything(), anything(), anything(), anything(), anything()
|
344
|
+
parameter_expectations = [anything(), anything(), anything(), anything(), anything(), anything()]
|
278
345
|
parameter_expectations[0] = cfreq_expectations[:method] if cfreq_expectations[:method]
|
279
|
-
parameter_expectations[
|
346
|
+
parameter_expectations[1] = cfreq_expectations[:path] if cfreq_expectations[:path]
|
280
347
|
|
281
|
-
connection.expects(:
|
348
|
+
connection.expects(:cdn_request).with(*parameter_expectations).returns(response) if args[:cdn_request]
|
349
|
+
connection.expects(:storage_request).with(*parameter_expectations).returns(response)
|
282
350
|
else
|
283
|
-
connection.stubs(:
|
351
|
+
connection.stubs(:cdn_request => response) if args[:cdn_request]
|
352
|
+
connection.stubs(:storage_request => response)
|
284
353
|
end
|
285
354
|
|
286
355
|
@container = CloudFiles::Container.new(connection, 'test_container')
|
287
356
|
@container.stubs(:connection).returns(connection)
|
288
357
|
end
|
289
358
|
|
290
|
-
def build_net_http_object_with_cfreq_expectations(args={
|
359
|
+
def build_net_http_object_with_cfreq_expectations(args={}, cfreq_expectations={})
|
291
360
|
build_net_http_object(args, cfreq_expectations)
|
292
361
|
end
|
293
362
|
end
|
@@ -7,7 +7,7 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
7
7
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
8
8
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5', 'last-modified' => Time.now.to_s}
|
9
9
|
response.stubs(:code).returns('204')
|
10
|
-
connection.stubs(:
|
10
|
+
connection.stubs(:storage_request => response)
|
11
11
|
container = CloudFiles::Container.new(connection, 'test_container')
|
12
12
|
@object = CloudFiles::StorageObject.new(container, 'test_object')
|
13
13
|
assert_equal @object.name, 'test_object'
|
@@ -19,7 +19,7 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
19
19
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => false)
|
20
20
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5', 'last-modified' => Time.now.to_s}
|
21
21
|
response.stubs(:code).returns('204')
|
22
|
-
connection.stubs(:
|
22
|
+
connection.stubs(:storage_request => response)
|
23
23
|
container = CloudFiles::Container.new(connection, 'test_container')
|
24
24
|
@object = CloudFiles::StorageObject.new(container, 'test_object')
|
25
25
|
assert_equal @object.name, 'test_object'
|
@@ -28,7 +28,7 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def test_public_url_exists
|
31
|
-
build_net_http_object(:public => true, :name => 'test object')
|
31
|
+
build_net_http_object(:public => true, :name => 'test object', :cdn_request => true)
|
32
32
|
assert_equal @object.public_url, "http://cdn.test.example/test%20object"
|
33
33
|
end
|
34
34
|
|
@@ -109,12 +109,12 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
109
109
|
|
110
110
|
def test_read_metadata_succeeds
|
111
111
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
112
|
-
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5', 'x-object-meta-foo' => 'Bar', 'last-modified' => Time.now.to_s}
|
112
|
+
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5', 'x-object-meta-foo' => 'Bar', 'x-object-meta-spam' => ['peanut', 'butter'], 'last-modified' => Time.now.to_s}
|
113
113
|
response.stubs(:code).returns('204')
|
114
|
-
connection.stubs(:
|
114
|
+
connection.stubs(:storage_request => response)
|
115
115
|
container = CloudFiles::Container.new(connection, 'test_container')
|
116
116
|
@object = CloudFiles::StorageObject.new(container, 'test_object')
|
117
|
-
assert_equal @object.metadata, {'foo' => 'Bar'}
|
117
|
+
assert_equal @object.metadata, {'foo' => 'Bar', 'spam' => 'peanutbutter'}
|
118
118
|
end
|
119
119
|
|
120
120
|
def test_write_succeeds
|
@@ -130,7 +130,7 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
130
130
|
connection = stub(:storagehost => 'test.storage.example', :storagepath => '/dummy/path', :storageport => 443, :storagescheme => 'https', :cdnmgmthost => 'cdm.test.example', :cdnmgmtpath => '/dummy/path', :cdnmgmtport => 443, :cdnmgmtscheme => 'https', :cdn_available? => true)
|
131
131
|
response = {'x-container-bytes-used' => '42', 'x-container-object-count' => '5', 'last-modified' => Time.now.to_s}
|
132
132
|
response.stubs(:code).returns('204').then.returns('204').then.returns('201').then.returns('204')
|
133
|
-
connection.stubs(:
|
133
|
+
connection.stubs(:storage_request => response)
|
134
134
|
CloudFiles::Container.any_instance.stubs(:populate).returns(true)
|
135
135
|
container = CloudFiles::Container.new(connection, 'test_container')
|
136
136
|
@object = CloudFiles::StorageObject.new(container, 'path/to/my/test_object', false, true)
|
@@ -162,7 +162,7 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
162
162
|
end
|
163
163
|
|
164
164
|
def test_purge_from_cdn_succeeds
|
165
|
-
build_net_http_object
|
165
|
+
build_net_http_object(:cdn_request => true)
|
166
166
|
assert_nothing_raised do
|
167
167
|
@object.purge_from_cdn
|
168
168
|
@object.purge_from_cdn("small.fox@hole.org")
|
@@ -198,8 +198,9 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
198
198
|
end
|
199
199
|
|
200
200
|
private
|
201
|
-
|
202
|
-
def build_net_http_object(args={
|
201
|
+
|
202
|
+
def build_net_http_object(args={})
|
203
|
+
args.merge!(:code => '204' ) unless args[:code]
|
203
204
|
CloudFiles::Container.any_instance.stubs(:metadata).returns({})
|
204
205
|
CloudFiles::Container.any_instance.stubs(:populate).returns(true)
|
205
206
|
CloudFiles::Container.any_instance.stubs(:container_metadata).returns({:bytes => 99, :count => 2})
|
@@ -208,7 +209,11 @@ class CloudfilesStorageObjectTest < Test::Unit::TestCase
|
|
208
209
|
response = {'x-cdn-management-url' => 'http://cdn.example.com/path', 'x-storage-url' => 'http://cdn.example.com/storage', 'authtoken' => 'dummy_token', 'last-modified' => Time.now.to_s}.merge(args[:response])
|
209
210
|
response.stubs(:code).returns(args[:code])
|
210
211
|
response.stubs(:body).returns args[:body] || nil
|
211
|
-
|
212
|
+
|
213
|
+
connection.stubs(:cdn_request => response) if args[:cdn_request]
|
214
|
+
|
215
|
+
connection.stubs(:storage_request => response)
|
216
|
+
|
212
217
|
container = CloudFiles::Container.new(connection, 'test_container')
|
213
218
|
container.stubs(:connection).returns(connection)
|
214
219
|
container.stubs(:public?).returns(args[:public] || false)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudfiles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 35
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 1.4.
|
9
|
+
- 18
|
10
|
+
version: 1.4.18
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- H. Wade Minter
|
@@ -16,7 +16,8 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-
|
19
|
+
date: 2011-09-28 00:00:00 -04:00
|
20
|
+
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
22
23
|
name: mime-types
|
@@ -81,6 +82,7 @@ files:
|
|
81
82
|
- test/cloudfiles_container_test.rb
|
82
83
|
- test/cloudfiles_storage_object_test.rb
|
83
84
|
- test/test_helper.rb
|
85
|
+
has_rdoc: true
|
84
86
|
homepage: http://www.rackspacecloud.com/cloud_hosting_products/files
|
85
87
|
licenses: []
|
86
88
|
|
@@ -110,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
112
|
requirements: []
|
111
113
|
|
112
114
|
rubyforge_project:
|
113
|
-
rubygems_version: 1.
|
115
|
+
rubygems_version: 1.6.0
|
114
116
|
signing_key:
|
115
117
|
specification_version: 3
|
116
118
|
summary: A Ruby API into Rackspace Cloud Files
|