cloudfiles 1.4.10 → 1.4.11

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.
@@ -1,56 +1,36 @@
1
1
  module CloudFiles
2
2
  class Container
3
3
  # See COPYING for license information.
4
- # Copyright (c) 2009, Rackspace US, Inc.
4
+ # Copyright (c) 2011, Rackspace US, Inc.
5
5
 
6
6
  # Name of the container which corresponds to the instantiated container class
7
7
  attr_reader :name
8
8
 
9
- # Size of the container (in bytes)
10
- attr_reader :bytes
11
-
12
- # Number of objects in the container
13
- attr_reader :count
14
-
15
- # True if container is public, false if container is private
16
- attr_reader :cdn_enabled
17
-
18
- # CDN container TTL (if container is public)
19
- attr_reader :cdn_ttl
20
-
21
- # CDN container URL (if container if public)
22
- attr_reader :cdn_url
23
-
24
9
  # The parent CloudFiles::Connection object for this container
25
10
  attr_reader :connection
26
-
27
- # The container ACL on the User Agent
28
- attr_reader :user_agent_acl
29
-
30
- # The container ACL on the site Referrer
31
- attr_reader :referrer_acl
32
11
 
33
12
  # Retrieves an existing CloudFiles::Container object tied to the current CloudFiles::Connection. If the requested
34
- # container does not exist, it will raise a NoSuchContainerException.
35
- #
13
+ # container does not exist, it will raise a CloudFiles::Exception::NoSuchContainer Exception.
14
+ #
36
15
  # Will likely not be called directly, instead use connection.container('container_name') to retrieve the object.
37
- def initialize(connection,name)
16
+ def initialize(connection, name)
38
17
  @connection = connection
39
18
  @name = name
40
19
  @storagehost = self.connection.storagehost
41
- @storagepath = self.connection.storagepath + "/" + URI.encode(@name).gsub(/&/,'%26')
20
+ @storagepath = self.connection.storagepath + "/" + CloudFiles.escape(@name)
42
21
  @storageport = self.connection.storageport
43
22
  @storagescheme = self.connection.storagescheme
44
23
  @cdnmgmthost = self.connection.cdnmgmthost
45
- @cdnmgmtpath = self.connection.cdnmgmtpath + "/" + URI.encode(@name).gsub(/&/,'%26')
24
+ @cdnmgmtpath = self.connection.cdnmgmtpath + "/" + CloudFiles.escape(@name) if self.connection.cdnmgmtpath
46
25
  @cdnmgmtport = self.connection.cdnmgmtport
47
26
  @cdnmgmtscheme = self.connection.cdnmgmtscheme
48
- populate
27
+ # Load the metadata now, so we'll get a CloudFiles::Exception::NoSuchContainer exception should the container
28
+ # not exist.
29
+ self.metadata
49
30
  end
50
31
 
51
- # Retrieves data about the container and populates class variables. It is automatically called
52
- # when the Container class is instantiated. If you need to refresh the variables, such as
53
- # size, count, cdn_enabled, cdn_ttl, and cdn_url, this method can be called again.
32
+ # Refreshes data about the container and populates class variables. Items are otherwise
33
+ # loaded in a lazy loaded fashion.
54
34
  #
55
35
  # container.count
56
36
  # => 2
@@ -60,49 +40,103 @@ module CloudFiles
60
40
  # container.populate
61
41
  # container.count
62
42
  # => 3
63
- def populate
64
- # Get the size and object count
65
- response = self.connection.cfreq("HEAD",@storagehost,@storagepath+"/",@storageport,@storagescheme)
66
- raise NoSuchContainerException, "Container #{@name} does not exist" unless (response.code =~ /^20/)
67
- @bytes = response["x-container-bytes-used"].to_i
68
- @count = response["x-container-object-count"].to_i
43
+ def refresh
44
+ @metadata = @cdn_metadata = nil
45
+ true
46
+ end
47
+ alias :populate :refresh
69
48
 
70
- # Get the CDN-related details
71
- response = self.connection.cfreq("HEAD",@cdnmgmthost,@cdnmgmtpath,@cdnmgmtport,@cdnmgmtscheme)
72
- @cdn_enabled = ((response["x-cdn-enabled"] || "").downcase == "true") ? true : false
73
- @cdn_ttl = @cdn_enabled ? response["x-ttl"].to_i : false
74
- @cdn_url = @cdn_enabled ? response["x-cdn-uri"] : false
75
- @user_agent_acl = response["x-user-agent-acl"]
76
- @referrer_acl = response["x-referrer-acl"]
77
- if @cdn_enabled
78
- @cdn_log = response["x-log-retention"] == "False" ? false : true
79
- else
80
- @cdn_log = false
81
- end
49
+ # Retrieves Metadata for the container
50
+ def metadata
51
+ @metadata ||= (
52
+ response = self.connection.cfreq("HEAD", @storagehost, @storagepath + "/", @storageport, @storagescheme)
53
+ raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code =~ /^20/)
54
+ {:bytes => response["x-container-bytes-used"].to_i, :count => response["x-container-object-count"].to_i}
55
+ )
56
+ end
82
57
 
83
- true
58
+ # Retrieves CDN-Enabled Meta Data
59
+ def cdn_metadata
60
+ @cdn_metadata ||= (
61
+ response = self.connection.cfreq("HEAD", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme)
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
+ :user_agent_acl => response["x-user-agent-acl"],
68
+ :referrer_acl => response["x-referrer-acl"],
69
+ :cdn_log => (cdn_enabled and response["x-log-retention"] == "True") ? true : false
70
+ }
71
+ )
72
+ end
73
+
74
+ # Size of the container (in bytes)
75
+ def bytes
76
+ self.metadata[:bytes]
77
+ end
78
+
79
+ # Number of objects in the container
80
+ def count
81
+ self.metadata[:count]
82
+ end
83
+
84
+ # Returns true if the container is public and CDN-enabled. Returns false otherwise.
85
+ #
86
+ # Aliased as container.public?
87
+ #
88
+ # public_container.cdn_enabled?
89
+ # => true
90
+ #
91
+ # private_container.public?
92
+ # => false
93
+ def cdn_enabled
94
+ self.cdn_metadata[:cdn_enabled]
95
+ end
96
+ alias :cdn_enabled? :cdn_enabled
97
+ alias :public? :cdn_enabled
98
+
99
+ # CDN container TTL (if container is public)
100
+ def cdn_ttl
101
+ self.cdn_metadata[:cdn_ttl]
102
+ end
103
+
104
+ # CDN container URL (if container if public)
105
+ def cdn_url
106
+ self.cdn_metadata[:cdn_url]
107
+ end
108
+
109
+ # The container ACL on the User Agent
110
+ def user_agent_acl
111
+ self.cdn_metadata[:user_agent_acl]
84
112
  end
85
- alias :refresh :populate
86
-
113
+
114
+ # The container ACL on the site Referrer
115
+ def referrer_acl
116
+ self.cdn_metadata[:referrer_acl]
117
+ end
118
+
87
119
  # Returns true if log retention is enabled on this container, false otherwise
88
- def log_retention?
89
- @cdn_log
120
+ def cdn_log
121
+ self.cdn_metadata[:cdn_log]
90
122
  end
91
-
123
+ alias :log_retention? :cdn_log
124
+ alias :cdn_log? :cdn_log
125
+
92
126
  # Change the log retention status for this container. Values are true or false.
93
127
  #
94
- # These logs will be periodically (at unpredictable intervals) compressed and uploaded
128
+ # These logs will be periodically (at unpredictable intervals) compressed and uploaded
95
129
  # to a “.CDN_ACCESS_LOGS” container in the form of “container_name.YYYYMMDDHH-XXXX.gz”.
96
130
  def log_retention=(value)
97
- response = self.connection.cfreq("POST",@cdnmgmthost,@cdnmgmtpath,@cdnmgmtport,@cdnmgmtscheme,{"x-log-retention" => value.to_s.capitalize})
98
- raise InvalidResponseException, "Invalid response code #{response.code}" unless (response.code == "201" or response.code == "202")
99
- return true
131
+ response = self.connection.cfreq("POST", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme, {"x-log-retention" => value.to_s.capitalize})
132
+ raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "201" or response.code == "202")
133
+ return true
100
134
  end
101
-
135
+
102
136
 
103
137
  # Returns the CloudFiles::StorageObject for the named object. Refer to the CloudFiles::StorageObject class for available
104
138
  # methods. If the object exists, it will be returned. If the object does not exist, a NoSuchObjectException will be thrown.
105
- #
139
+ #
106
140
  # object = container.object('test.txt')
107
141
  # object.data
108
142
  # => "This is test data"
@@ -110,13 +144,13 @@ module CloudFiles
110
144
  # object = container.object('newfile.txt')
111
145
  # => NoSuchObjectException: Object newfile.txt does not exist
112
146
  def object(objectname)
113
- o = CloudFiles::StorageObject.new(self,objectname,true)
147
+ o = CloudFiles::StorageObject.new(self, objectname, true)
114
148
  return o
115
149
  end
116
150
  alias :get_object :object
117
-
118
151
 
119
- # Gathers a list of all available objects in the current container and returns an array of object names.
152
+
153
+ # Gathers a list of all available objects in the current container and returns an array of object names.
120
154
  # container = cf.container("My Container")
121
155
  # container.objects #=> [ "cat", "dog", "donkey", "monkeydir", "monkeydir/capuchin"]
122
156
  # Pass a limit argument to limit the list to a number of objects:
@@ -127,21 +161,23 @@ module CloudFiles
127
161
  # container.objects(:prefix => "do") #=> [ "dog", "donkey" ]
128
162
  # Only search within a certain pseudo-filesystem path:
129
163
  # container.objects(:path => 'monkeydir') #=> ["monkeydir/capuchin"]
164
+ # Only grab "virtual directories", based on a single-character delimiter (no "directory" objects required):
165
+ # container.objects(:delimiter => '/') #=> ["monkeydir"]
130
166
  # All arguments to this method are optional.
131
- #
167
+ #
132
168
  # Returns an empty array if no object exist in the container. Throws an InvalidResponseException
133
169
  # if the request fails.
134
170
  def objects(params = {})
135
- params[:marker] ||= params[:offset]
136
- paramarr = []
137
- paramarr << ["limit=#{URI.encode(params[:limit].to_s).gsub(/&/,'%26')}"] if params[:limit]
138
- paramarr << ["marker=#{URI.encode(params[:marker].to_s).gsub(/&/,'%26')}"] if params[:marker]
139
- paramarr << ["prefix=#{URI.encode(params[:prefix]).gsub(/&/,'%26')}"] if params[:prefix]
140
- paramarr << ["path=#{URI.encode(params[:path]).gsub(/&/,'%26')}"] if params[:path]
141
- paramstr = (paramarr.size > 0)? paramarr.join("&") : "" ;
142
- response = self.connection.cfreq("GET",@storagehost,"#{@storagepath}?#{paramstr}",@storageport,@storagescheme)
171
+ params[:marker] ||= params[:offset] unless params[:offset].nil?
172
+ query = []
173
+ params.each do |param, value|
174
+ if [:limit, :marker, :prefix, :path, :delimiter].include? param
175
+ query << "#{param}=#{CloudFiles.escape(value.to_s)}"
176
+ end
177
+ end
178
+ response = self.connection.cfreq("GET", @storagehost, "#{@storagepath}?#{query.join '&'}", @storageport, @storagescheme)
143
179
  return [] if (response.code == "204")
144
- raise InvalidResponseException, "Invalid response code #{response.code}" unless (response.code == "200")
180
+ raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
145
181
  return CloudFiles.lines(response.body)
146
182
  end
147
183
  alias :list_objects :objects
@@ -149,31 +185,30 @@ module CloudFiles
149
185
  # Retrieves a list of all objects in the current container along with their size in bytes, hash, and content_type.
150
186
  # If no objects exist, an empty hash is returned. Throws an InvalidResponseException if the request fails. Takes a
151
187
  # parameter hash as an argument, in the same form as the objects method.
152
- #
188
+ #
153
189
  # Returns a hash in the same format as the containers_detail from the CloudFiles class.
154
190
  #
155
191
  # container.objects_detail
156
- # => {"test.txt"=>{:content_type=>"application/octet-stream",
157
- # :hash=>"e2a6fcb4771aa3509f6b27b6a97da55b",
158
- # :last_modified=>Mon Jan 19 10:43:36 -0600 2009,
159
- # :bytes=>"16"},
160
- # "new.txt"=>{:content_type=>"application/octet-stream",
161
- # :hash=>"0aa820d91aed05d2ef291d324e47bc96",
162
- # :last_modified=>Wed Jan 28 10:16:26 -0600 2009,
192
+ # => {"test.txt"=>{:content_type=>"application/octet-stream",
193
+ # :hash=>"e2a6fcb4771aa3509f6b27b6a97da55b",
194
+ # :last_modified=>Mon Jan 19 10:43:36 -0600 2009,
195
+ # :bytes=>"16"},
196
+ # "new.txt"=>{:content_type=>"application/octet-stream",
197
+ # :hash=>"0aa820d91aed05d2ef291d324e47bc96",
198
+ # :last_modified=>Wed Jan 28 10:16:26 -0600 2009,
163
199
  # :bytes=>"22"}
164
200
  # }
165
201
  def objects_detail(params = {})
166
- params[:marker] ||= params[:offset]
167
- paramarr = []
168
- paramarr << ["format=xml"]
169
- paramarr << ["limit=#{URI.encode(params[:limit].to_s).gsub(/&/,'%26')}"] if params[:limit]
170
- paramarr << ["marker=#{URI.encode(params[:marker].to_s).gsub(/&/,'%26')}"] if params[:marker]
171
- paramarr << ["prefix=#{URI.encode(params[:prefix]).gsub(/&/,'%26')}"] if params[:prefix]
172
- paramarr << ["path=#{URI.encode(params[:path]).gsub(/&/,'%26')}"] if params[:path]
173
- paramstr = (paramarr.size > 0)? paramarr.join("&") : "" ;
174
- response = self.connection.cfreq("GET",@storagehost,"#{@storagepath}?#{paramstr}",@storageport,@storagescheme)
202
+ params[:marker] ||= params[:offset] unless params[:offset].nil?
203
+ query = ["format=xml"]
204
+ params.each do |param, value|
205
+ if [:limit, :marker, :prefix, :path, :delimiter].include? param
206
+ query << "#{param}=#{CloudFiles.escape(value.to_s)}"
207
+ end
208
+ end
209
+ response = self.connection.cfreq("GET", @storagehost, "#{@storagepath}?#{query.join '&'}", @storageport, @storagescheme)
175
210
  return {} if (response.code == "204")
176
- raise InvalidResponseException, "Invalid response code #{response.code}" unless (response.code == "200")
211
+ raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
177
212
  doc = REXML::Document.new(response.body)
178
213
  detailhash = {}
179
214
  doc.elements.each("container/object") { |o|
@@ -184,17 +219,6 @@ module CloudFiles
184
219
  end
185
220
  alias :list_objects_info :objects_detail
186
221
 
187
- # Returns true if the container is public and CDN-enabled. Returns false otherwise.
188
- #
189
- # public_container.public?
190
- # => true
191
- #
192
- # private_container.public?
193
- # => false
194
- def public?
195
- return @cdn_enabled
196
- end
197
-
198
222
  # Returns true if a container is empty and returns false otherwise.
199
223
  #
200
224
  # new_container.empty?
@@ -203,7 +227,7 @@ module CloudFiles
203
227
  # full_container.empty?
204
228
  # => false
205
229
  def empty?
206
- return (@count.to_i == 0)? true : false
230
+ return (metadata[:count].to_i == 0)? true : false
207
231
  end
208
232
 
209
233
  # Returns true if object exists and returns false otherwise.
@@ -214,23 +238,23 @@ module CloudFiles
214
238
  # container.object_exists?('badfile.txt')
215
239
  # => false
216
240
  def object_exists?(objectname)
217
- response = self.connection.cfreq("HEAD",@storagehost,"#{@storagepath}/#{URI.encode(objectname).gsub(/&/,'%26')}",@storageport,@storagescheme)
241
+ response = self.connection.cfreq("HEAD", @storagehost, "#{@storagepath}/#{CloudFiles.escape objectname}", @storageport, @storagescheme)
218
242
  return (response.code =~ /^20/)? true : false
219
243
  end
220
244
 
221
- # Creates a new CloudFiles::StorageObject in the current container.
245
+ # Creates a new CloudFiles::StorageObject in the current container.
222
246
  #
223
247
  # If an object with the specified name exists in the current container, that object will be returned. Otherwise,
224
248
  # an empty new object will be returned.
225
249
  #
226
250
  # Passing in the optional make_path argument as true will create zero-byte objects to simulate a filesystem path
227
- # to the object, if an objectname with path separators ("/path/to/myfile.mp3") is supplied. These path objects can
251
+ # to the object, if an objectname with path separators ("/path/to/myfile.mp3") is supplied. These path objects can
228
252
  # be used in the Container.objects method.
229
- def create_object(objectname,make_path = false)
230
- CloudFiles::StorageObject.new(self,objectname,false,make_path)
253
+ def create_object(objectname, make_path = false)
254
+ CloudFiles::StorageObject.new(self, objectname, false, make_path)
231
255
  end
232
-
233
- # Removes an CloudFiles::StorageObject from a container. True is returned if the removal is successful. Throws
256
+
257
+ # Removes an CloudFiles::StorageObject from a container. True is returned if the removal is successful. Throws
234
258
  # NoSuchObjectException if the object doesn't exist. Throws InvalidResponseException if the request fails.
235
259
  #
236
260
  # container.delete_object('new.txt')
@@ -239,15 +263,15 @@ module CloudFiles
239
263
  # container.delete_object('nonexistent_file.txt')
240
264
  # => NoSuchObjectException: Object nonexistent_file.txt does not exist
241
265
  def delete_object(objectname)
242
- response = self.connection.cfreq("DELETE",@storagehost,"#{@storagepath}/#{URI.encode(objectname).gsub(/&/,'%26')}",@storageport,@storagescheme)
243
- raise NoSuchObjectException, "Object #{objectname} does not exist" if (response.code == "404")
244
- raise InvalidResponseException, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
266
+ response = self.connection.cfreq("DELETE", @storagehost, "#{@storagepath}/#{CloudFiles.escape objectname}", @storageport, @storagescheme)
267
+ raise CloudFiles::Exception::NoSuchObject, "Object #{objectname} does not exist" if (response.code == "404")
268
+ raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
245
269
  true
246
270
  end
247
271
 
248
272
  # Makes a container publicly available via the Cloud Files CDN and returns true upon success. Throws NoSuchContainerException
249
273
  # if the container doesn't exist or if the request fails.
250
- #
274
+ #
251
275
  # Takes an optional hash of options, including:
252
276
  #
253
277
  # :ttl, which is the CDN cache TTL in seconds (default 86400 seconds or 1 day, minimum 3600 or 1 hour, maximum 259200 or 3 days)
@@ -264,16 +288,16 @@ module CloudFiles
264
288
  ttl = options
265
289
  options = {:ttl => ttl}
266
290
  end
267
-
268
- response = self.connection.cfreq("PUT",@cdnmgmthost,@cdnmgmtpath,@cdnmgmtport,@cdnmgmtscheme)
269
- raise NoSuchContainerException, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
291
+
292
+ response = self.connection.cfreq("PUT", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme)
293
+ raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
270
294
 
271
295
  headers = { "X-TTL" => options[:ttl].to_s , "X-CDN-Enabled" => "True" }
272
296
  headers["X-User-Agent-ACL"] = options[:user_agent_acl] if options[:user_agent_acl]
273
297
  headers["X-Referrer-ACL"] = options[:referrer_acl] if options[:referrer_acl]
274
- response = self.connection.cfreq("POST",@cdnmgmthost,@cdnmgmtpath,@cdnmgmtport,@cdnmgmtscheme,headers)
275
- raise NoSuchContainerException, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
276
- populate
298
+ response = self.connection.cfreq("POST", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme, headers)
299
+ raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
300
+ refresh
277
301
  true
278
302
  end
279
303
 
@@ -286,12 +310,12 @@ module CloudFiles
286
310
  # => true
287
311
  def make_private
288
312
  headers = { "X-CDN-Enabled" => "False" }
289
- response = self.connection.cfreq("POST",@cdnmgmthost,@cdnmgmtpath,@cdnmgmtport,@cdnmgmtscheme,headers)
290
- raise NoSuchContainerException, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
291
- populate
313
+ response = self.connection.cfreq("POST", @cdnmgmthost, @cdnmgmtpath, @cdnmgmtport, @cdnmgmtscheme, headers)
314
+ raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
315
+ refresh
292
316
  true
293
317
  end
294
-
318
+
295
319
  def to_s # :nodoc:
296
320
  @name
297
321
  end
@@ -0,0 +1,64 @@
1
+ # The deprecated old exception types. Will go away in a couple of releases.
2
+
3
+ class SyntaxException < StandardError # :nodoc:
4
+ end
5
+ class ConnectionException < StandardError # :nodoc:
6
+ end
7
+ class AuthenticationException < StandardError # :nodoc:
8
+ end
9
+ class InvalidResponseException < StandardError # :nodoc:
10
+ end
11
+ class NonEmptyContainerException < StandardError # :nodoc:
12
+ end
13
+ class NoSuchObjectException < StandardError # :nodoc:
14
+ end
15
+ class NoSuchContainerException < StandardError # :nodoc:
16
+ end
17
+ class NoSuchAccountException < StandardError # :nodoc:
18
+ end
19
+ class MisMatchedChecksumException < StandardError # :nodoc:
20
+ end
21
+ class IOException < StandardError # :nodoc:
22
+ end
23
+ class CDNNotEnabledException < StandardError # :nodoc:
24
+ end
25
+ class ObjectExistsException < StandardError # :nodoc:
26
+ end
27
+ class ExpiredAuthTokenException < StandardError # :nodoc:
28
+ end
29
+
30
+ # The new properly scoped exceptions.
31
+
32
+ module CloudFiles
33
+ class Exception
34
+
35
+ class Syntax < SyntaxException
36
+ end
37
+ class Connection < ConnectionException # :nodoc:
38
+ end
39
+ class Authentication < AuthenticationException # :nodoc:
40
+ end
41
+ class InvalidResponse < InvalidResponseException # :nodoc:
42
+ end
43
+ class NonEmptyContainer < NonEmptyContainerException # :nodoc:
44
+ end
45
+ class NoSuchObject < NoSuchObjectException # :nodoc:
46
+ end
47
+ class NoSuchContainer < NoSuchContainerException # :nodoc:
48
+ end
49
+ class NoSuchAccount < NoSuchAccountException # :nodoc:
50
+ end
51
+ class MisMatchedChecksum < MisMatchedChecksumException # :nodoc:
52
+ end
53
+ class IO < IOException # :nodoc:
54
+ end
55
+ class CDNNotEnabled < CDNNotEnabledException # :nodoc:
56
+ end
57
+ class ObjectExists < ObjectExistsException # :nodoc:
58
+ end
59
+ class ExpiredAuthToken < ExpiredAuthTokenException # :nodoc:
60
+ end
61
+
62
+ end
63
+ end
64
+