cloudfiles 1.4.17 → 1.4.18
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/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
|