cloudfiles 1.4.18 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/CONTRIBUTORS +1 -0
- data/cloudfiles.gemspec +5 -3
- data/lib/client.rb +620 -0
- data/lib/cloudfiles.rb +1 -1
- data/lib/cloudfiles/authentication.rb +10 -25
- data/lib/cloudfiles/connection.rb +55 -123
- data/lib/cloudfiles/container.rb +89 -73
- data/lib/cloudfiles/storage_object.rb +52 -36
- data/lib/cloudfiles/version.rb +1 -1
- data/test/cloudfiles_authentication_test.rb +17 -22
- data/test/cloudfiles_client_test.rb +797 -0
- data/test/cloudfiles_connection_test.rb +53 -194
- data/test/cloudfiles_container_test.rb +253 -121
- data/test/cloudfiles_storage_object_test.rb +51 -65
- data/test/test_helper.rb +1 -0
- metadata +12 -10
data/lib/cloudfiles.rb
CHANGED
@@ -30,7 +30,6 @@ module CloudFiles
|
|
30
30
|
require 'digest/md5'
|
31
31
|
require 'time'
|
32
32
|
require 'rubygems'
|
33
|
-
require 'mime/types'
|
34
33
|
|
35
34
|
unless "".respond_to? :each_char
|
36
35
|
require "jcode"
|
@@ -38,6 +37,7 @@ module CloudFiles
|
|
38
37
|
end
|
39
38
|
|
40
39
|
$:.unshift(File.dirname(__FILE__))
|
40
|
+
require 'client'
|
41
41
|
require 'cloudfiles/version'
|
42
42
|
require 'cloudfiles/exception'
|
43
43
|
require 'cloudfiles/authentication'
|
@@ -8,54 +8,39 @@ module CloudFiles
|
|
8
8
|
# cdmmgmtpath, storagehost, storagepath, authtoken, and authok variables on the connection. If it fails, it raises
|
9
9
|
# an CloudFiles::Exception::Authentication exception.
|
10
10
|
#
|
11
|
-
# Should
|
11
|
+
# Should never be called directly.
|
12
12
|
def initialize(connection)
|
13
|
-
parsed_auth_url = URI.parse(connection.auth_url)
|
14
|
-
path = parsed_auth_url.path
|
15
|
-
hdrhash = { "X-Auth-User" => connection.authuser, "X-Auth-Key" => connection.authkey }
|
16
13
|
begin
|
17
|
-
|
18
|
-
|
19
|
-
if parsed_auth_url.scheme == "https"
|
20
|
-
server.use_ssl = true
|
21
|
-
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
22
|
-
end
|
23
|
-
server.start
|
24
|
-
rescue Exception => e
|
14
|
+
storage_url, auth_token, headers = SwiftClient.get_auth(connection.auth_url, connection.authuser, connection.authkey, connection.snet?)
|
15
|
+
rescue => e
|
25
16
|
# uncomment if you suspect a problem with this branch of code
|
26
|
-
#
|
27
|
-
raise CloudFiles::Exception::Connection, "Unable to connect to #{
|
17
|
+
# $stderr.puts "got error #{e.class}: #{e.message.inspect}\n" << e.traceback.map{|n| "\t#{n}"}.join("\n")
|
18
|
+
raise CloudFiles::Exception::Connection, "Unable to connect to #{connection.auth_url}", caller
|
28
19
|
end
|
29
|
-
|
30
|
-
|
31
|
-
if response["x-cdn-management-url"]
|
20
|
+
if auth_token
|
21
|
+
if headers["x-cdn-management-url"]
|
32
22
|
connection.cdn_available = true
|
33
|
-
parsed_cdn_url = URI.parse(
|
23
|
+
parsed_cdn_url = URI.parse(headers["x-cdn-management-url"])
|
34
24
|
connection.cdnmgmthost = parsed_cdn_url.host
|
35
25
|
connection.cdnmgmtpath = parsed_cdn_url.path
|
36
26
|
connection.cdnmgmtport = parsed_cdn_url.port
|
37
27
|
connection.cdnmgmtscheme = parsed_cdn_url.scheme
|
38
28
|
end
|
39
|
-
parsed_storage_url = URI.parse(
|
29
|
+
parsed_storage_url = URI.parse(headers["x-storage-url"])
|
40
30
|
connection.storagehost = set_snet(connection, parsed_storage_url.host)
|
41
31
|
connection.storagepath = parsed_storage_url.path
|
42
32
|
connection.storageport = parsed_storage_url.port
|
43
33
|
connection.storagescheme = parsed_storage_url.scheme
|
44
|
-
connection.authtoken =
|
34
|
+
connection.authtoken = headers["x-auth-token"]
|
45
35
|
connection.authok = true
|
46
36
|
else
|
47
37
|
connection.authtoken = false
|
48
38
|
raise CloudFiles::Exception::Authentication, "Authentication failed"
|
49
39
|
end
|
50
|
-
server.finish
|
51
40
|
end
|
52
41
|
|
53
42
|
private
|
54
43
|
|
55
|
-
def get_server(connection, parsed_auth_url)
|
56
|
-
Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(parsed_auth_url.host, parsed_auth_url.port)
|
57
|
-
end
|
58
|
-
|
59
44
|
def set_snet(connection, hostname)
|
60
45
|
if connection.snet?
|
61
46
|
"snet-#{hostname}"
|
@@ -132,12 +132,18 @@ module CloudFiles
|
|
132
132
|
# => {:count=>8, :bytes=>42438527}
|
133
133
|
# cf.bytes
|
134
134
|
# => 42438527
|
135
|
+
# Hostname of the storage server
|
136
|
+
|
135
137
|
def get_info
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
138
|
+
begin
|
139
|
+
raise CloudFiles::Exception::AuthenticationException, "Not authenticated" unless self.authok?
|
140
|
+
response = SwiftClient.head_account(storageurl, self.authtoken)
|
141
|
+
@bytes = response["x-account-bytes-used"].to_i
|
142
|
+
@count = response["x-account-container-count"].to_i
|
143
|
+
{:bytes => @bytes, :count => @count}
|
144
|
+
rescue ClientException => e
|
145
|
+
raise CloudFiles::Exception::InvalidResponse, "Unable to obtain account size" unless (e.status.to_s == "204")
|
146
|
+
end
|
141
147
|
end
|
142
148
|
|
143
149
|
# The total size in bytes under this connection
|
@@ -162,14 +168,13 @@ module CloudFiles
|
|
162
168
|
#
|
163
169
|
# cf.containers(2,'cftest')
|
164
170
|
# => ["test", "video"]
|
165
|
-
def containers(limit =
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
CloudFiles.lines(response.body)
|
171
|
+
def containers(limit = nil, marker = nil)
|
172
|
+
begin
|
173
|
+
response = SwiftClient.get_account(storageurl, self.authtoken, marker, limit)
|
174
|
+
response[1].collect{|c| c['name']}
|
175
|
+
rescue ClientException => e
|
176
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status.to_s}" unless (e.status.to_s == "200")
|
177
|
+
end
|
173
178
|
end
|
174
179
|
alias :list_containers :containers
|
175
180
|
|
@@ -183,20 +188,13 @@ module CloudFiles
|
|
183
188
|
# cf.containers_detail
|
184
189
|
# => { "container1" => { :bytes => "36543", :count => "146" },
|
185
190
|
# "container2" => { :bytes => "105943", :count => "25" } }
|
186
|
-
def containers_detail(limit =
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
doc = REXML::Document.new(response.body)
|
194
|
-
detailhash = {}
|
195
|
-
doc.elements.each("account/container/") { |c|
|
196
|
-
detailhash[c.elements["name"].text] = { :bytes => c.elements["bytes"].text, :count => c.elements["count"].text }
|
197
|
-
}
|
198
|
-
doc = nil
|
199
|
-
return detailhash
|
191
|
+
def containers_detail(limit = nil, marker = nil)
|
192
|
+
begin
|
193
|
+
response = SwiftClient.get_account(storageurl, self.authtoken, marker, limit)
|
194
|
+
Hash[*response[1].collect{|c| [c['name'], {:bytes => c['bytes'], :count => c['count']}]}.flatten]
|
195
|
+
rescue ClientException => e
|
196
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status.to_s}" unless (e.status.to_s == "200")
|
197
|
+
end
|
200
198
|
end
|
201
199
|
alias :list_containers_info :containers_detail
|
202
200
|
|
@@ -208,14 +206,18 @@ module CloudFiles
|
|
208
206
|
# cf.container_exists?('bad_container')
|
209
207
|
# => false
|
210
208
|
def container_exists?(containername)
|
211
|
-
|
212
|
-
|
209
|
+
begin
|
210
|
+
response = SwiftClient.head_container(storageurl, self.authtoken, containername)
|
211
|
+
true
|
212
|
+
rescue ClientException => e
|
213
|
+
false
|
214
|
+
end
|
213
215
|
end
|
214
216
|
|
215
217
|
# Creates a new container and returns the CloudFiles::Container object. Throws an InvalidResponseException if the
|
216
218
|
# request fails.
|
217
219
|
#
|
218
|
-
#
|
220
|
+
# "/" is not valid in a container name. The container name is limited to
|
219
221
|
# 256 characters or less.
|
220
222
|
#
|
221
223
|
# container = cf.create_container('new_container')
|
@@ -223,13 +225,16 @@ module CloudFiles
|
|
223
225
|
# => "new_container"
|
224
226
|
#
|
225
227
|
# container = cf.create_container('bad/name')
|
226
|
-
# => SyntaxException: Container name cannot contain
|
228
|
+
# => SyntaxException: Container name cannot contain '/'
|
227
229
|
def create_container(containername)
|
228
|
-
raise CloudFiles::Exception::Syntax, "Container name cannot contain
|
230
|
+
raise CloudFiles::Exception::Syntax, "Container name cannot contain '/'" if containername.match("/")
|
229
231
|
raise CloudFiles::Exception::Syntax, "Container name is limited to 256 characters" if containername.length > 256
|
230
|
-
|
231
|
-
|
232
|
-
|
232
|
+
begin
|
233
|
+
SwiftClient.put_container(storageurl, self.authtoken, containername)
|
234
|
+
CloudFiles::Container.new(self, containername)
|
235
|
+
rescue ClientException => e
|
236
|
+
raise CloudFiles::Exception::InvalidResponse, "Unable to create container #{containername}" unless (e.status.to_s == "201" || e.status.to_s == "202")
|
237
|
+
end
|
233
238
|
end
|
234
239
|
|
235
240
|
# Deletes a container from the account. Throws a NonEmptyContainerException if the container still contains
|
@@ -244,9 +249,12 @@ module CloudFiles
|
|
244
249
|
# cf.delete_container('nonexistent')
|
245
250
|
# => NoSuchContainerException: Container nonexistent does not exist
|
246
251
|
def delete_container(containername)
|
247
|
-
|
248
|
-
|
249
|
-
|
252
|
+
begin
|
253
|
+
SwiftClient.delete_container(storageurl, self.authtoken, containername)
|
254
|
+
rescue ClientException => e
|
255
|
+
raise CloudFiles::Exception::NonEmptyContainer, "Container #{containername} is not empty" if (e.status.to_s == "409")
|
256
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{containername} does not exist" unless (e.status.to_s == "204")
|
257
|
+
end
|
250
258
|
true
|
251
259
|
end
|
252
260
|
|
@@ -260,95 +268,19 @@ module CloudFiles
|
|
260
268
|
# cf.public_containers
|
261
269
|
# => ["video", "webpics"]
|
262
270
|
def public_containers(enabled_only = false)
|
263
|
-
paramstr = enabled_only == true ? "enabled_only=true" : ""
|
264
|
-
response = cdn_request("GET", "?#{paramstr}")
|
265
|
-
return [] if (response.code == "204")
|
266
|
-
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
|
267
|
-
CloudFiles.lines(response.body)
|
268
|
-
end
|
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
|
-
|
280
|
-
# This method actually makes the HTTP calls out to the server
|
281
|
-
def cfreq(method, server, path, port, scheme, headers = {}, data = nil, attempts = 0, &block) # :nodoc:
|
282
|
-
start = Time.now
|
283
|
-
headers['Transfer-Encoding'] = "chunked" if data.respond_to?(:read)
|
284
|
-
hdrhash = headerprep(headers)
|
285
|
-
start_http(server, path, port, scheme, hdrhash)
|
286
|
-
request = Net::HTTP.const_get(method.to_s.capitalize).new(path, hdrhash)
|
287
|
-
data.rewind if data.respond_to?(:rewind)
|
288
|
-
if data
|
289
|
-
if data.respond_to?(:read)
|
290
|
-
request.body_stream = data
|
291
|
-
else
|
292
|
-
request.body = data
|
293
|
-
end
|
294
|
-
unless data.is_a?(IO)
|
295
|
-
request.content_length = data.respond_to?(:lstat) ? data.stat.size : data.size
|
296
|
-
end
|
297
|
-
else
|
298
|
-
request.content_length = 0
|
299
|
-
end
|
300
|
-
response = @http[server].request(request, &block)
|
301
|
-
raise CloudFiles::Exception::ExpiredAuthToken if response.code == "401"
|
302
|
-
response
|
303
|
-
rescue Errno::EPIPE, Timeout::Error, Errno::EINVAL, EOFError, IOError
|
304
|
-
# Server closed the connection, retry
|
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
|
-
|
310
|
-
attempts += 1
|
311
271
|
begin
|
312
|
-
|
313
|
-
|
314
|
-
|
272
|
+
response = SwiftClient.get_account(cdnurl, self.authtoken)
|
273
|
+
response[1].collect{|c| c['name']}
|
274
|
+
rescue ClientException => e
|
275
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status.to_s}" unless (e.status.to_s == "200")
|
315
276
|
end
|
316
|
-
start_http(server, path, port, scheme, headers)
|
317
|
-
retry
|
318
|
-
rescue ExpiredAuthTokenException
|
319
|
-
raise CloudFiles::Exception::Connection, "Authentication token expired and you have requested not to retry", caller if @retry_auth == false
|
320
|
-
CloudFiles::Authentication.new(self)
|
321
|
-
retry
|
322
277
|
end
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
# Sets up standard HTTP headers
|
327
|
-
def headerprep(headers = {}) # :nodoc:
|
328
|
-
default_headers = {}
|
329
|
-
default_headers["X-Auth-Token"] = @authtoken if (authok? && @account.nil?)
|
330
|
-
default_headers["X-Storage-Token"] = @authtoken if (authok? && !@account.nil?)
|
331
|
-
default_headers["Connection"] = "Keep-Alive"
|
332
|
-
default_headers["User-Agent"] = "CloudFiles Ruby API #{VERSION}"
|
333
|
-
default_headers.merge(headers)
|
278
|
+
|
279
|
+
def storageurl
|
280
|
+
"#{self.storagescheme}://#{self.storagehost}:#{self.storageport.to_s}#{self.storagepath}"
|
334
281
|
end
|
335
|
-
|
336
|
-
|
337
|
-
def start_http(server, path, port, scheme, headers) # :nodoc:
|
338
|
-
if (@http[server].nil?)
|
339
|
-
begin
|
340
|
-
@http[server] = Net::HTTP::Proxy(self.proxy_host, self.proxy_port).new(server, port)
|
341
|
-
if scheme == "https"
|
342
|
-
@http[server].use_ssl = true
|
343
|
-
@http[server].verify_mode = OpenSSL::SSL::VERIFY_NONE
|
344
|
-
end
|
345
|
-
@http[server].start
|
346
|
-
rescue Exception
|
347
|
-
raise CloudFiles::Exception::Connection, "Unable to connect to #{server.address}", caller
|
348
|
-
end
|
349
|
-
end
|
282
|
+
def cdnurl
|
283
|
+
"#{self.cdnmgmtscheme}://#{self.cdnmgmthost}:#{self.cdnmgmtport.to_s}#{self.cdnmgmtpath}"
|
350
284
|
end
|
351
|
-
|
352
285
|
end
|
353
|
-
|
354
286
|
end
|
data/lib/cloudfiles/container.rb
CHANGED
@@ -41,11 +41,14 @@ module CloudFiles
|
|
41
41
|
# Retrieves Metadata for the container
|
42
42
|
def container_metadata
|
43
43
|
@metadata ||= (
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
begin
|
45
|
+
response = SwiftClient.head_container(self.connection.storageurl, self.connection.authtoken, escaped_name)
|
46
|
+
resphash = {}
|
47
|
+
response.to_hash.select { |k,v| k.match(/^x-container-meta/) }.each { |x| resphash[x[0]] = x[1].to_s }
|
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"]}
|
49
|
+
rescue ClientException => e
|
50
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s =~ /^20/)
|
51
|
+
end
|
49
52
|
)
|
50
53
|
end
|
51
54
|
|
@@ -54,18 +57,20 @@ module CloudFiles
|
|
54
57
|
return @cdn_metadata if @cdn_metadata
|
55
58
|
if cdn_available?
|
56
59
|
@cdn_metadata = (
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
60
|
+
begin
|
61
|
+
response = SwiftClient.head_container(self.connection.cdnurl, self.connection.authtoken, escaped_name)
|
62
|
+
cdn_enabled = ((response["x-cdn-enabled"] || "").downcase == "true") ? true : false
|
63
|
+
{
|
64
|
+
:cdn_enabled => cdn_enabled,
|
65
|
+
:cdn_ttl => cdn_enabled ? response["x-ttl"].to_i : nil,
|
66
|
+
:cdn_url => cdn_enabled ? response["x-cdn-uri"] : nil,
|
67
|
+
:cdn_ssl_url => cdn_enabled ? response["x-cdn-ssl-uri"] : nil,
|
68
|
+
:cdn_streaming_url => cdn_enabled ? response["x-cdn-streaming-uri"] : nil,
|
69
|
+
:cdn_log => (cdn_enabled and response["x-log-retention"] == "True") ? true : false
|
70
|
+
}
|
71
|
+
rescue ClientException => e
|
72
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s =~ /^20/)
|
73
|
+
end
|
69
74
|
)
|
70
75
|
else
|
71
76
|
@cdn_metadata = {}
|
@@ -91,10 +96,14 @@ module CloudFiles
|
|
91
96
|
def set_metadata(metadatahash)
|
92
97
|
headers = {}
|
93
98
|
metadatahash.each{ |key, value| headers['X-Container-Meta-' + CloudFiles.escape(key.to_s.capitalize)] = value.to_s }
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
99
|
+
begin
|
100
|
+
SwiftClient.post_container(self.connection.storageurl, self.connection.authtoken, escaped_name, headers)
|
101
|
+
self.refresh
|
102
|
+
true
|
103
|
+
rescue ClientException => e
|
104
|
+
raise CloudFiles::Exception::NoSuchObject, "Container #{@name} does not exist" if (e.status.to_s == "404")
|
105
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s =~ /^20/)
|
106
|
+
end
|
98
107
|
end
|
99
108
|
|
100
109
|
# Size of the container (in bytes)
|
@@ -136,21 +145,12 @@ module CloudFiles
|
|
136
145
|
def cdn_ssl_url
|
137
146
|
self.cdn_metadata[:cdn_ssl_url]
|
138
147
|
end
|
148
|
+
|
139
149
|
# CDN Streaming container URL (if container is public)
|
140
|
-
def
|
150
|
+
def cdn_streaming_url
|
141
151
|
self.cdn_metadata[:cdn_streaming_url]
|
142
152
|
end
|
143
153
|
|
144
|
-
# The container ACL on the User Agent
|
145
|
-
def user_agent_acl
|
146
|
-
self.cdn_metadata[:user_agent_acl]
|
147
|
-
end
|
148
|
-
|
149
|
-
# The container ACL on the site Referrer
|
150
|
-
def referrer_acl
|
151
|
-
self.cdn_metadata[:referrer_acl]
|
152
|
-
end
|
153
|
-
|
154
154
|
#used by openstack swift
|
155
155
|
def read_acl
|
156
156
|
self.container_metadata[:container_read]
|
@@ -168,15 +168,19 @@ module CloudFiles
|
|
168
168
|
alias :log_retention? :cdn_log
|
169
169
|
alias :cdn_log? :cdn_log
|
170
170
|
|
171
|
+
|
171
172
|
# Change the log retention status for this container. Values are true or false.
|
172
173
|
#
|
173
174
|
# These logs will be periodically (at unpredictable intervals) compressed and uploaded
|
174
175
|
# to a ".CDN_ACCESS_LOGS" container in the form of "container_name.YYYYMMDDHH-XXXX.gz".
|
175
176
|
def log_retention=(value)
|
176
177
|
raise Exception::CDNNotAvailable unless cdn_available?
|
177
|
-
|
178
|
-
|
179
|
-
|
178
|
+
begin
|
179
|
+
SwiftClient.post_container(self.connection.cdnurl, self.connection.authtoken, escaped_name, {"x-log-retention" => value.to_s.capitalize})
|
180
|
+
true
|
181
|
+
rescue ClientException => e
|
182
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s == "201" or e.status.to_s == "202")
|
183
|
+
end
|
180
184
|
end
|
181
185
|
|
182
186
|
|
@@ -221,10 +225,12 @@ module CloudFiles
|
|
221
225
|
query << "#{param}=#{CloudFiles.escape(value.to_s)}"
|
222
226
|
end
|
223
227
|
end
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
+
begin
|
229
|
+
response = SwiftClient.get_container(self.connection.storageurl, self.connection.authtoken, escaped_name, params[:marker], params[:limit], params[:prefix], params[:delimiter])
|
230
|
+
return response[1].collect{|o| o['name']}
|
231
|
+
rescue ClientException => e
|
232
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s == "200")
|
233
|
+
end
|
228
234
|
end
|
229
235
|
alias :list_objects :objects
|
230
236
|
|
@@ -254,16 +260,12 @@ module CloudFiles
|
|
254
260
|
query << "#{param}=#{CloudFiles.escape(value.to_s)}"
|
255
261
|
end
|
256
262
|
end
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
detailhash[o.elements["name"].text] = { :bytes => o.elements["bytes"].text, :hash => o.elements["hash"].text, :content_type => o.elements["content_type"].text, :last_modified => DateTime.parse(o.elements["last_modified"].text) }
|
264
|
-
}
|
265
|
-
doc = nil
|
266
|
-
return detailhash
|
263
|
+
begin
|
264
|
+
response = SwiftClient.get_container(self.connection.storageurl, self.connection.authtoken, escaped_name, params[:marker], params[:limit], params[:prefix], params[:delimiter])
|
265
|
+
return Hash[*response[1].collect{|o| [o['name'],{ :bytes => o["bytes"], :hash => o["hash"], :content_type => o["content_type"], :last_modified => DateTime.parse(o["last_modified"])}] }.flatten]
|
266
|
+
rescue ClientException => e
|
267
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s == "200")
|
268
|
+
end
|
267
269
|
end
|
268
270
|
alias :list_objects_info :objects_detail
|
269
271
|
|
@@ -286,8 +288,12 @@ module CloudFiles
|
|
286
288
|
# container.object_exists?('badfile.txt')
|
287
289
|
# => false
|
288
290
|
def object_exists?(objectname)
|
289
|
-
|
290
|
-
|
291
|
+
begin
|
292
|
+
response = SwiftClient.head_object(self.connection.storageurl, self.connection.authtoken, escaped_name, objectname)
|
293
|
+
true
|
294
|
+
rescue ClientException => e
|
295
|
+
false
|
296
|
+
end
|
291
297
|
end
|
292
298
|
|
293
299
|
# Creates a new CloudFiles::StorageObject in the current container.
|
@@ -311,10 +317,13 @@ module CloudFiles
|
|
311
317
|
# container.delete_object('nonexistent_file.txt')
|
312
318
|
# => NoSuchObjectException: Object nonexistent_file.txt does not exist
|
313
319
|
def delete_object(objectname)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
320
|
+
begin
|
321
|
+
SwiftClient.delete_object(self.connection.storageurl, self.connection.authtoken, escaped_name, objectname)
|
322
|
+
true
|
323
|
+
rescue ClientException => e
|
324
|
+
raise CloudFiles::Exception::NoSuchObject, "Object #{objectname} does not exist" if (e.status.to_s == "404")
|
325
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s =~ /^20/)
|
326
|
+
end
|
318
327
|
end
|
319
328
|
|
320
329
|
# Makes a container publicly available via the Cloud Files CDN and returns true upon success. Throws NoSuchContainerException
|
@@ -338,14 +347,17 @@ module CloudFiles
|
|
338
347
|
options = {:ttl => ttl}
|
339
348
|
end
|
340
349
|
|
341
|
-
|
342
|
-
|
343
|
-
|
350
|
+
begin
|
351
|
+
SwiftClient.put_container(self.connection.cdnurl, self.connection.authtoken, escaped_name)
|
352
|
+
rescue ClientException => e
|
353
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s == "201" || e.status.to_s == "202")
|
354
|
+
end
|
344
355
|
headers = { "X-TTL" => options[:ttl].to_s , "X-CDN-Enabled" => "True" }
|
345
356
|
headers["X-User-Agent-ACL"] = options[:user_agent_acl] if options[:user_agent_acl]
|
346
357
|
headers["X-Referrer-ACL"] = options[:referrer_acl] if options[:referrer_acl]
|
347
|
-
|
348
|
-
|
358
|
+
|
359
|
+
post_with_headers(headers)
|
360
|
+
# raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
|
349
361
|
refresh
|
350
362
|
true
|
351
363
|
end
|
@@ -367,13 +379,11 @@ module CloudFiles
|
|
367
379
|
end
|
368
380
|
|
369
381
|
def post_with_headers(headers = {})
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
response
|
382
|
+
begin
|
383
|
+
SwiftClient.post_container(cdn_enabled? ? self.connection.cdnurl : self.connection.storageurl, self.connection.authtoken, escaped_name, headers)
|
384
|
+
rescue ClientException => e
|
385
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist (response code: #{e.status.to_s})" unless (e.status.to_s =~ /^20/)
|
374
386
|
end
|
375
|
-
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist (response code: #{response.code})" unless (response.code =~ /^20/)
|
376
|
-
response
|
377
387
|
end
|
378
388
|
|
379
389
|
# Makes a container private and returns true upon success. Throws NoSuchContainerException
|
@@ -386,10 +396,13 @@ module CloudFiles
|
|
386
396
|
def make_private
|
387
397
|
raise Exception::CDNNotAvailable unless cdn_available?
|
388
398
|
headers = { "X-CDN-Enabled" => "False" }
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
399
|
+
begin
|
400
|
+
SwiftClient.post_container(self.connection.cdnurl, self.connection.authtoken, escaped_name, headers)
|
401
|
+
refresh
|
402
|
+
true
|
403
|
+
rescue ClientException => e
|
404
|
+
raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s == "201" || e.status.to_s == "202")
|
405
|
+
end
|
393
406
|
end
|
394
407
|
|
395
408
|
# Purges CDN Edge Cache for all objects inside of this container
|
@@ -413,9 +426,12 @@ module CloudFiles
|
|
413
426
|
raise Exception::CDNNotAvailable unless cdn_available?
|
414
427
|
headers = {}
|
415
428
|
headers = {"X-Purge-Email" => email} if email
|
416
|
-
|
417
|
-
|
418
|
-
|
429
|
+
begin
|
430
|
+
SwiftClient.delete_container(self.connection.cdnurl, self.connection.authtoken, escaped_name, headers)
|
431
|
+
true
|
432
|
+
rescue ClientException => e
|
433
|
+
raise CloudFiles::Exception::Connection, "Error Unable to Purge Container: #{@name}" unless (e.status.to_s > "200" && e.status.to_s < "299")
|
434
|
+
end
|
419
435
|
end
|
420
436
|
|
421
437
|
def to_s # :nodoc:
|