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 CHANGED
@@ -1,3 +1,9 @@
1
+ ================================================================================
2
+ 1.5.0 (2011/10/31
3
+ ================================================================================
4
+ o The underlying http wrapper now uses client.rb a simple abstraction to manage
5
+ each ReST call in its own function
6
+
1
7
  ================================================================================
2
8
  1.4.18 (2011/09/07)
3
9
  ================================================================================
@@ -31,3 +31,4 @@ CvX
31
31
  Topper Bowers
32
32
  Xavier Shay
33
33
  Dillon Amburgey
34
+ Scott Simpson
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  "TODO",
24
24
  "cloudfiles.gemspec",
25
25
  "lib/cloudfiles.rb",
26
+ "lib/client.rb",
26
27
  "lib/cloudfiles/authentication.rb",
27
28
  "lib/cloudfiles/connection.rb",
28
29
  "lib/cloudfiles/container.rb",
@@ -34,6 +35,7 @@ Gem::Specification.new do |s|
34
35
  "test/cloudfiles_connection_test.rb",
35
36
  "test/cloudfiles_container_test.rb",
36
37
  "test/cloudfiles_storage_object_test.rb",
38
+ "test/cloudfiles_client_test.rb",
37
39
  "test/test_helper.rb"
38
40
  ]
39
41
  s.homepage = %q{http://www.rackspacecloud.com/cloud_hosting_products/files}
@@ -47,21 +49,21 @@ Gem::Specification.new do |s|
47
49
  "test/cloudfiles_connection_test.rb",
48
50
  "test/cloudfiles_container_test.rb",
49
51
  "test/cloudfiles_storage_object_test.rb",
52
+ "test/cloudfiles_client_test.rb",
50
53
  "test/test_helper.rb"
51
54
  ]
52
55
 
56
+ s.add_dependency('json')
57
+
53
58
  if s.respond_to? :specification_version then
54
59
  s.specification_version = 3
55
60
 
56
61
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
57
- s.add_runtime_dependency(%q<mime-types>, [">= 1.16"])
58
62
  s.add_development_dependency(%q<mocha>, ["~> 0.9.8"])
59
63
  else
60
- s.add_dependency(%q<mime-types>, [">= 1.16"])
61
64
  s.add_dependency(%q<mocha>, ["~> 0.9.8"])
62
65
  end
63
66
  else
64
- s.add_dependency(%q<mime-types>, [">= 1.16"])
65
67
  s.add_dependency(%q<mocha>, ["~> 0.9.8"])
66
68
  end
67
69
  end
@@ -0,0 +1,620 @@
1
+ require 'rubygems'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ class ClientException < StandardError
6
+ attr_reader :scheme, :host, :port, :path, :query, :status, :reason, :devices
7
+ def initialize(msg, params={})
8
+ @msg = msg
9
+ @scheme = params[:http_scheme]
10
+ @host = params[:http_host]
11
+ @port = params[:http_port]
12
+ @path = params[:http_path]
13
+ @query = params[:http_query]
14
+ @status = params[:http_status]
15
+ @reason = params[:http_reason]
16
+ @device = params[:http_device]
17
+ end
18
+
19
+ def to_s
20
+ a = @msg
21
+ b = ''
22
+ b += "#{@scheme}://" if @scheme
23
+ b += @host if @host
24
+ b += ":#{@port}" if @port
25
+ b += @path if @path
26
+ b += "?#{@query}" if @query
27
+ b ? b = "#{b} #{@status}" : b = @status.to_s if @status
28
+ b ? b = "#{b} #{@reason}" : b = "- #{@reason}" if @reason
29
+ b ? b = "#{b}: device #{@device}" : b = "device #{@device}" if @device
30
+ b ? "#{a} #{b}" : a
31
+ end
32
+ end
33
+
34
+ class ChunkedConnectionWrapper
35
+ def initialize(data, chunk_size)
36
+ @size = chunk_size
37
+ if data.respond_to? :read
38
+ @file = data
39
+ end
40
+ end
41
+
42
+ def read(foo)
43
+ if @file
44
+ @file.read(@size)
45
+ end
46
+ end
47
+ def eof!
48
+ @file.eof!
49
+ end
50
+ def eof?
51
+ @file.eof?
52
+ end
53
+ end
54
+
55
+ def quote(value)
56
+ URI.encode(value)
57
+ end
58
+
59
+ class Query
60
+ def initialize(url_params)
61
+ if url_params
62
+ @params = Query.from_url_params(url_params)
63
+ else
64
+ @params = {}
65
+ end
66
+ end
67
+ def to_s
68
+ to_url_params
69
+ end
70
+ def to_url_params
71
+ elements = []
72
+ @params.each_pair {|k,v| elements << "#{k}=#{v}"}
73
+ elements.join('&')
74
+ end
75
+ def self.from_url_params(url_params)
76
+ result = {}
77
+ url_params.split('&').each do |element|
78
+ element = element.split('=')
79
+ result[element[0]] = element[1]
80
+ end
81
+ result
82
+ end
83
+ def has_key?(key)
84
+ @params.has_key? key
85
+ end
86
+ def add(key, value)
87
+ @params[key] = value
88
+ end
89
+ def delete(key)
90
+ @params.delete(key)
91
+ end
92
+ end
93
+
94
+ class SwiftClient
95
+ def initialize(authurl, user, key, retries=5, preauthurl=nil, preauthtoken=nil, snet=false, starting_backoff=1)
96
+ @authurl = authurl
97
+ @user = user
98
+ @key = key
99
+ @retries = retries
100
+ @http_conn = nil
101
+ @url = preauthurl
102
+ @token = preauthtoken
103
+ @attempts = 0
104
+ @snet = snet
105
+ @starting_backoff = starting_backoff
106
+ end
107
+
108
+ private
109
+ def _retry(reset, func, args=nil)
110
+ @attempts = 0
111
+ backoff = @starting_backoff
112
+
113
+ while @attempts < @retries
114
+ @attempts += 1
115
+ begin
116
+ if !@url or !@token
117
+ @url, @token = self.get_auth()
118
+ @http_conn = nil
119
+ end
120
+ @http_conn = self.http_connection() if !@http_conn
121
+ return SwiftClient.method(func).call(@url, @token, *args)
122
+ rescue Net::HTTPExceptions
123
+ if @attempts > @retries
124
+ raise
125
+ end
126
+ @http_conn = nil
127
+ rescue ClientException => err
128
+ if @attempts > @retries
129
+ raise
130
+ end
131
+ if err.status.to_i == 401
132
+ @url = @token = nil
133
+ if @attempts > 1
134
+ raise
135
+ end
136
+ elsif err.status.to_i == 408
137
+ @http_conn = nil
138
+ elsif err.status.to_i >= 500 and err.status.to_i <= 599
139
+ return nil
140
+ else
141
+ raise
142
+ end
143
+ end
144
+ sleep(backoff)
145
+ backoff *= 2
146
+ if reset
147
+ reset.call(args)
148
+ end
149
+ end
150
+ end
151
+
152
+ public
153
+ def self.http_connection(url, proxy_host=nil, proxy_port=nil)
154
+ parsed = URI::parse(url)
155
+
156
+ if parsed.scheme == 'http'
157
+ require 'net/http'
158
+ conn = Net::HTTP::Proxy(proxy_host, proxy_port).new(parsed.host, parsed.port)
159
+ [parsed, conn]
160
+ elsif parsed.scheme == 'https'
161
+ require 'net/https'
162
+ conn = Net::HTTP::Proxy(proxy_host, proxy_port).new(parsed.host, parsed.port)
163
+ conn.use_ssl = true
164
+ conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
165
+ [parsed, conn]
166
+ else
167
+ raise ClientException.new(
168
+ "Cannot handle protocol scheme #{parsed.scheme} for #{url} %s")
169
+ end
170
+ end
171
+
172
+ def http_connection
173
+ if !@http_conn
174
+ @http_conn = SwiftClient.http_connection(@url)
175
+ else
176
+ @http_conn
177
+ end
178
+ end
179
+
180
+ def self.get_auth(url, user, key, snet=false)
181
+ parsed, conn = http_connection(url)
182
+ conn.start if not conn.started?
183
+ resp = conn.get(URI.encode(parsed.request_uri), {"x-auth-user" => user, "x-auth-key" => key })
184
+ if resp.code.to_i < 200 or resp.code.to_i > 300
185
+ raise ClientException.new('Account GET failed', :http_scheme=>parsed.scheme,
186
+ :http_host=>conn.address, :http_port=>conn.port,
187
+ :http_path=>parsed.path, :http_query=>parsed.query, :http_status=>resp.code,
188
+ :http_reason=>resp.message)
189
+ end
190
+ url = URI::parse(resp.header['x-storage-url'])
191
+ if snet
192
+ url.host = "snet-#{url.host}"
193
+ end
194
+ [url.to_s, resp.header['x-auth-token'], resp.header]
195
+ end
196
+
197
+ def get_auth
198
+ @url, @token = SwiftClient.get_auth(@authurl, @user, @key, @snet)
199
+ end
200
+
201
+ def self.get_account(url, token, marker=nil, limit=nil, prefix=nil,
202
+ http_conn=nil, full_listing=false)
203
+ #todo: add in rest of functionality
204
+ if not http_conn
205
+ http_conn = http_connection(url)
206
+ end
207
+ parsed = http_conn[0].clone
208
+ conn = http_conn[1]
209
+ if full_listing
210
+ rv = get_account(url, token, marker, limit, prefix, http_conn)
211
+ listing = rv[1]
212
+ while listing.length > 0
213
+ marker = listing[-1]['name']
214
+ listing = get_account(url, token, marker, limit, prefix, http_conn)[1]
215
+ if listing.length > 0
216
+ rv[1] += listing
217
+ end
218
+ end
219
+ return rv
220
+ end
221
+ query = Query.new(parsed.query)
222
+ query.add('format', 'json')
223
+ query.add('marker', quote(marker.to_s)) if marker
224
+ query.add('limit', quote(limit.to_s)) if limit
225
+ query.add('prefix', quote(prefix.to_s)) if prefix
226
+ parsed.query = query.to_url_params
227
+ conn.start if !conn.started?
228
+ resp = conn.get(parsed.request_uri, {'x-auth-token' => token})
229
+ if resp.code.to_i < 200 or resp.code.to_i > 300
230
+ raise ClientException.new('Account GET failed', :http_scheme=>parsed.scheme,
231
+ :http_host=>conn.address, :http_port=>conn.port,
232
+ :http_path=>parsed.path, :http_query=>parsed.query, :http_status=>resp.code,
233
+ :http_reason=>resp.message)
234
+ end
235
+ resp_headers = {}
236
+ resp.header.each do |k,v|
237
+ resp_headers[k.downcase] = v
238
+ end
239
+ if resp.code.to_i == 204
240
+ [resp_headers, []]
241
+ else
242
+ [resp_headers, JSON.parse(resp.body)]
243
+ end
244
+ end
245
+
246
+ def get_account(marker=nil, limit=nil, prefix=nil, full_listing=false)
247
+ _retry(nil, :get_account, [marker, limit, prefix, @http_conn, full_listing])
248
+ end
249
+
250
+ def self.head_account(url, token, http_conn=nil)
251
+ if not http_conn
252
+ http_conn = http_connection(url)
253
+ end
254
+ parsed = http_conn[0].clone
255
+ conn = http_conn[1]
256
+ conn.start if !conn.started?
257
+ resp = conn.head(parsed.request_uri, {'x-auth-token' => token})
258
+ if resp.code.to_i < 200 or resp.code.to_i > 300
259
+ raise ClientException.new('Account HEAD failed', :http_scheme=>parsed.scheme,
260
+ :http_host=>conn.address, :http_port=>conn.port,
261
+ :http_path=>parsed.path, :http_status=>resp.code,
262
+ :http_reason=>resp.message)
263
+ end
264
+ resp_headers = {}
265
+ resp.header.each do |k,v|
266
+ resp_headers[k.downcase] = v
267
+ end
268
+ resp_headers
269
+ end
270
+
271
+ def head_account
272
+ _retry(nil, :head_account, [@http_conn])
273
+ end
274
+
275
+ def self.post_account(url, token, headers, http_conn=nil)
276
+ if not http_conn
277
+ http_conn = http_connection(url)
278
+ end
279
+ parsed = http_conn[0].clone
280
+ conn = http_conn[1]
281
+ headers['x-auth-token'] = token
282
+ conn.start if !conn.started?
283
+ resp = conn.post(parsed.request_uri, nil, headers)
284
+ if resp.code.to_i < 200 or resp.code.to_i > 300
285
+ raise ClientException.new('Account POST failed', :http_scheme=>parsed.scheme,
286
+ :http_host=>conn.address, :http_port=>conn.port,
287
+ :http_path=>parsed.path, :http_status=>resp.code,
288
+ :http_reason=>resp.message)
289
+ end
290
+ resp.body
291
+ end
292
+ def post_account(headers=nil)
293
+ _retry(nil, :post_account, [headers, @http_conn])
294
+ end
295
+
296
+ def self.get_container(url, token, container, marker=nil, limit=nil,
297
+ prefix=nil, delimiter=nil, http_conn=nil, full_listing=nil)
298
+ #todo: add in rest of functionality
299
+ if not http_conn
300
+ http_conn = http_connection(url)
301
+ end
302
+ parsed = http_conn[0].clone
303
+ conn = http_conn[1]
304
+
305
+ if full_listing
306
+ rv = get_account(url, token, marker, limit, prefix, http_conn)
307
+ listing = rv[1]
308
+ while listing.length > 0
309
+ marker = listing[-1]['name']
310
+ listing = get_account(url, token, marker, limit, prefix, http_conn)[1]
311
+ if listing.length > 0
312
+ rv[1] += listing
313
+ end
314
+ end
315
+ return rv
316
+ end
317
+ query = Query.new(parsed.query)
318
+ query.add('format', 'json')
319
+ query.add('marker', quote(marker.to_s)) if marker
320
+ query.add('limit', quote(limit.to_s)) if limit
321
+ query.add('prefix', quote(prefix.to_s)) if prefix
322
+ parsed.query = query.to_url_params
323
+ conn.start if !conn.started?
324
+ parsed.path += "/#{quote(container)}"
325
+ resp = conn.get(parsed.request_uri, {'x-auth-token' => token})
326
+ if resp.code.to_i < 200 or resp.code.to_i > 300
327
+ raise ClientException.new('Container GET failed', :http_scheme=>parsed.scheme,
328
+ :http_host=>conn.address, :http_port=>conn.port,
329
+ :http_path=>parsed.path, :http_query=>parsed.query, :http_status=>resp.code,
330
+ :http_reason=>resp.message)
331
+ end
332
+ resp_headers = {}
333
+ resp.header.each do |k,v|
334
+ resp_headers[k.downcase] = v
335
+ end
336
+ if resp.code.to_i == 204
337
+ [resp_headers, []]
338
+ else
339
+ [resp_headers, JSON.parse(resp.body())]
340
+ end
341
+ end
342
+
343
+ def get_container(container, marker=nil, limit=nil, prefix=nil, delimiter=nil, full_listing=nil)
344
+ _retry(nil, :get_container, [container, marker, limit, prefix, delimiter, full_listing])
345
+ end
346
+
347
+ def self.head_container(url, token, container, http_conn=nil)
348
+ if not http_conn
349
+ http_conn = http_connection(url)
350
+ end
351
+ parsed = http_conn[0].clone
352
+ conn = http_conn[1]
353
+
354
+ conn.start if !conn.started?
355
+ parsed.path += "/#{quote(container)}"
356
+ resp = conn.head(parsed.request_uri, {'x-auth-token' => token})
357
+ if resp.code.to_i < 200 or resp.code.to_i > 300
358
+ raise ClientException.new('Container HEAD failed', :http_scheme=>parsed.scheme,
359
+ :http_host=>conn.address, :http_port=>conn.port,
360
+ :http_path=>parsed.path, :http_status=>resp.code,
361
+ :http_reason=>resp.message)
362
+ end
363
+ resp_headers = {}
364
+ resp.header.each do |k,v|
365
+ resp_headers[k.downcase] = v
366
+ end
367
+ resp_headers
368
+ end
369
+
370
+ def head_container(container)
371
+ _retry(nil, :head_container, [container, @http_conn])
372
+ end
373
+
374
+ def self.put_container(url, token, container, headers={}, http_conn=nil)
375
+ if not http_conn
376
+ http_conn = http_connection(url)
377
+ end
378
+ parsed = http_conn[0].clone
379
+ conn = http_conn[1]
380
+
381
+ conn.start if !conn.started?
382
+ parsed.path += "/#{quote(container)}"
383
+ headers['x-auth-token'] = token
384
+ # headers['content-length'] = 0
385
+ resp = conn.put(parsed.request_uri, nil, headers)
386
+ if resp.code.to_i < 200 or resp.code.to_i > 300
387
+ raise ClientException.new('Container PUT failed', :http_scheme=>parsed.scheme,
388
+ :http_host=>conn.address, :http_port=>conn.port,
389
+ :http_path=>parsed.path, :http_status=>resp.code,
390
+ :http_reason=>resp.message)
391
+ end
392
+ end
393
+
394
+ def put_container(container, headers={})
395
+ _retry(nil, :put_container, [container, headers, @http_conn])
396
+ end
397
+
398
+ def self.post_container(url, token, container, headers={}, http_conn=nil)
399
+ if not http_conn
400
+ http_conn = http_connection(url)
401
+ end
402
+ parsed = http_conn[0].clone
403
+ conn = http_conn[1]
404
+
405
+ conn.start if !conn.started?
406
+ parsed.path += "/#{quote(container)}"
407
+ headers['x-auth-token'] = token
408
+ resp = conn.post(parsed.request_uri, nil, headers)
409
+ if resp.code.to_i < 200 or resp.code.to_i > 300
410
+ raise ClientException.new('Container POST failed', :http_scheme=>parsed.scheme,
411
+ :http_host=>conn.address, :http_port=>conn.port,
412
+ :http_path=>parsed.path, :http_status=>resp.code,
413
+ :http_reason=>resp.message)
414
+ end
415
+ end
416
+
417
+ def post_container(container, headers={})
418
+ _retry(nil, :post_container, [container, headers])
419
+ end
420
+
421
+ def self.delete_container(url, token, container, headers={}, http_conn=nil)
422
+ if not http_conn
423
+ http_conn = http_connection(url)
424
+ end
425
+ parsed = http_conn[0].clone
426
+ conn = http_conn[1]
427
+
428
+ conn.start if !conn.started?
429
+ parsed.path += "/#{quote(container)}"
430
+ headers['x-auth-token'] = token
431
+ resp = conn.delete(parsed.request_uri, headers)
432
+ if resp.code.to_i < 200 or resp.code.to_i > 300
433
+ raise ClientException.new('Container DELETE failed', :http_scheme=>parsed.scheme,
434
+ :http_host=>conn.address, :http_port=>conn.port,
435
+ :http_path=>parsed.path, :http_status=>resp.code,
436
+ :http_reason=>resp.message)
437
+ end
438
+ end
439
+
440
+ def delete_container(container)
441
+ _retry(nil, :delete_container, [container])
442
+ end
443
+
444
+ def self.get_object(url, token, container, name, http_conn=nil, resp_chunk_size=nil, &block)
445
+ if not http_conn
446
+ http_conn = http_connection(url)
447
+ end
448
+ parsed = http_conn[0].clone
449
+ conn = http_conn[1]
450
+
451
+
452
+ parsed.path += "/#{quote(container)}/#{quote(name)}"
453
+ conn.start if not conn.started?
454
+ headers = {'x-auth-token' => token}
455
+ if block_given?
456
+ resp = conn.request_get(parsed.request_uri, headers) do |r|
457
+ r.read_body do |b|
458
+ yield b
459
+ end
460
+ end
461
+ object_body = nil
462
+ else
463
+ resp = conn.request_get(parsed.request_uri, headers)
464
+ object_body = resp.body
465
+ end
466
+ if resp.code.to_i < 200 or resp.code.to_i > 300
467
+ raise ClientException.new('Object GET failed', :http_scheme=>parsed.scheme,
468
+ :http_host=>conn.address, :http_port=>conn.port,
469
+ :http_path=>parsed.path, :http_status=>resp.code,
470
+ :http_reason=>resp.message)
471
+ end
472
+ resp_headers = {}
473
+ resp.header.each do |k,v|
474
+ resp_headers[k.downcase] = v
475
+ end
476
+ [resp_headers, object_body]
477
+ end
478
+
479
+ def get_object(container, name, resp_chunk_size=nil)
480
+ _retry(nil, :get_object, [container, name, resp_chunk_size])
481
+ end
482
+
483
+ def self.head_object(url, token, container, name, http_conn=nil)
484
+ if not http_conn
485
+ http_conn = http_connection(url)
486
+ end
487
+ parsed = http_conn[0].clone
488
+ conn = http_conn[1]
489
+
490
+
491
+ parsed.path += "/#{quote(container)}/#{quote(name)}"
492
+ conn.start if not conn.started?
493
+ resp = conn.head(parsed.request_uri, {'x-auth-token' => token})
494
+ if resp.code.to_i < 200 or resp.code.to_i > 300
495
+ raise ClientException.new('Object HEAD failed', :http_scheme=>parsed.scheme,
496
+ :http_host=>conn.address, :http_port=>conn.port,
497
+ :http_path=>parsed.path, :http_status=>resp.code,
498
+ :http_reason=>resp.message)
499
+ end
500
+ resp_headers = {}
501
+ resp.header.each do |k,v|
502
+ resp_headers[k.downcase] = v
503
+ end
504
+ resp_headers
505
+ end
506
+
507
+ def head_object(container, name)
508
+ _retry(nil, :head_object, [container, name])
509
+ end
510
+
511
+ def self.put_object(url, token=nil, container=nil, name=nil, contents=nil,
512
+ content_length=nil, etag=nil, chunk_size=65536,
513
+ content_type=nil, headers={}, http_conn=nil, proxy=nil)
514
+ if not http_conn
515
+ http_conn = http_connection(url)
516
+ end
517
+ parsed = http_conn[0].clone
518
+ conn = http_conn[1]
519
+
520
+ parsed.path += "/#{quote(container)}" if container
521
+ parsed.path += "/#{quote(name)}" if name
522
+ headers['x-auth-token'] = token if token
523
+ headers['etag'] = etag if etag
524
+ if content_length != nil
525
+ headers['content-length'] = content_length.to_s
526
+ else
527
+ headers.each do |k,v|
528
+ if k.downcase == 'content-length'
529
+ content_length = v.to_i
530
+ end
531
+ end
532
+ end
533
+ headers['content-type'] = content_type if content_type
534
+ headers['content-length'] = '0' if not contents
535
+ if contents.respond_to? :read
536
+ request = Net::HTTP::Put.new(parsed.request_uri, headers)
537
+ chunked = ChunkedConnectionWrapper.new(contents, chunk_size)
538
+ if content_length == nil
539
+ request['Transfer-Encoding'] = 'chunked'
540
+ request.delete('content-length')
541
+ end
542
+ request.body_stream = chunked
543
+ resp = conn.start do |http|
544
+ http.request(request)
545
+ end
546
+ else
547
+ conn.start if not conn.started?
548
+ resp = conn.put(parsed.request_uri, contents, headers)
549
+ end
550
+ if resp.code.to_i < 200 or resp.code.to_i > 300
551
+ raise ClientException.new('Object PUT failed', :http_scheme=>parsed.scheme,
552
+ :http_host=>conn.address, :http_port=>conn.port,
553
+ :http_path=>parsed.path, :http_status=>resp.code,
554
+ :http_reason=>resp.message)
555
+ end
556
+ resp.header['etag']
557
+ end
558
+
559
+ def put_object(container, obj, contents, content_length=nil, etag=nil, chunk_size=65536, content_type=nil, headers={})
560
+
561
+ _default_reset = Proc.new do |args|
562
+ raise ClientException("put_object(#{container}, #{obj}, ...) failure and no ability to reset contents for reupload.")
563
+ end
564
+ reset_func = _default_reset
565
+ if (contents.respond_to? :seek) and (contents.respond_to? :tell)
566
+ orig_pos = contents.tell
567
+ reset_func = Proc.new {|a| contents.seek(orig_pos)}
568
+ elsif !contents
569
+ reset_func = Proc.new {|a| nil }
570
+ end
571
+ _retry(reset_func, :put_object, [container, obj, contents, content_length, etag, chunk_size, content_type, headers])
572
+ end
573
+
574
+ def self.post_object(url, token=nil, container=nil, name=nil, headers={}, http_conn=nil)
575
+ if not http_conn
576
+ http_conn = http_connection(url)
577
+ end
578
+ parsed = http_conn[0].clone
579
+ conn = http_conn[1]
580
+
581
+ parsed.path += "/#{quote(container)}" if container
582
+ parsed.path += "/#{quote(name)}" if name
583
+ headers['x-auth-token'] = token if token
584
+ resp = conn.post(parsed.request_uri, nil, headers)
585
+ if resp.code.to_i < 200 or resp.code.to_i > 300
586
+ raise ClientException.new('Object POST failed', :http_scheme=>parsed.scheme,
587
+ :http_host=>conn.address, :http_port=>conn.port,
588
+ :http_path=>parsed.path, :http_status=>resp.code,
589
+ :http_reason=>resp.message)
590
+ end
591
+ end
592
+
593
+ def post_object(container, name, headers={})
594
+ _retry(nil, :post_object, [container, name, headers])
595
+ end
596
+
597
+ def self.delete_object(url, token=nil, container=nil, name=nil, http_conn=nil, headers={}, proxy=nil)
598
+ if not http_conn
599
+ http_conn = http_connection(url)
600
+ end
601
+ parsed = http_conn[0].clone
602
+ conn = http_conn[1]
603
+
604
+ conn.start if !conn.started?
605
+ parsed.path += "/#{quote(container)}" if container
606
+ parsed.path += "/#{quote(name)}" if name
607
+ headers['x-auth-token'] = token if token
608
+ resp = conn.delete(parsed.request_uri, headers)
609
+ if resp.code.to_i < 200 or resp.code.to_i > 300
610
+ raise ClientException.new('Object DELETE failed', :http_scheme=>parsed.scheme,
611
+ :http_host=>conn.address, :http_port=>conn.port,
612
+ :http_path=>parsed.path, :http_status=>resp.code,
613
+ :http_reason=>resp.message)
614
+ end
615
+ end
616
+
617
+ def delete_object(container, name, headers={})
618
+ _retry(nil, :delete_object, [container, name, headers])
619
+ end
620
+ end