synaptic4r 0.1.5

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.
@@ -0,0 +1,295 @@
1
+ ####-------------------------------------------------------------------------------------------------------
2
+ module Synaptic4r
3
+
4
+ ####------------------------------------------------------------------------------------------------------
5
+ class Request
6
+
7
+ ####------------------------------------------------------------------------------------------------------
8
+ include Rest
9
+
10
+
11
+ #.......................................................................................................
12
+ # argument specification
13
+ #.......................................................................................................
14
+ define_rest_arg :uid, :header => :hide
15
+
16
+ define_rest_arg :key, :header => :hide
17
+
18
+ define_rest_arg :site, :header => :hide
19
+
20
+ define_rest_arg :file, :header => :none, :cli => 'file',
21
+ :desc => 'file to upload'
22
+
23
+ define_rest_arg :lifetime, :header => :none, :cli => ['lifetime', '-f'],
24
+ :desc => 'lifetime in minutes of request URL (default is 5 minuts)'
25
+
26
+ define_rest_arg :account, :header => :none, :cli => ['account', '-u'],
27
+ :desc => "user account name specified in #{ENV['HOME']}./synaptic4r"
28
+
29
+ define_rest_arg :oid, :header => :none, :cli => ['oid', '-o'],
30
+ :desc => 'system assigned object identifier'
31
+
32
+ define_rest_arg :rpath, :header => :none, :cli => 'rpath',
33
+ :desc => 'remote file or directory path'
34
+
35
+ define_rest_arg :namespace, :header => :none, :cli => ['namespace', '-n'],
36
+ :desc => 'root namespace used for remote file path (default is uid)'
37
+
38
+ define_rest_arg :create_beginoffset, :header => :none, :cli => ['beginoffset', '-b'],
39
+ :desc => 'begining byte offset in file'
40
+
41
+ define_rest_arg :create_endoffset, :header => :none, :cli => ['endoffset', '-d'],
42
+ :desc => 'end byte offset in file'
43
+
44
+ define_rest_arg :content_type, :header => :http, :cli => ['content-type', '-c'],
45
+ :desc => 'http content type'
46
+
47
+ define_rest_arg :beginoffset, :header => :http, :cli => ['beginoffset', '-b'],
48
+ :desc => 'begining byte offset in file'
49
+
50
+ define_rest_arg :endoffset, :header => :http, :cli => ['endoffset', '-d'],
51
+ :desc => 'end byte offset in file'
52
+
53
+ define_rest_arg :useracl, :header => :emc, :cli => ['useracl', '-a'],
54
+ :desc => 'access control list'
55
+
56
+ define_rest_arg :groupacl, :header => :emc, :cli => ['groupacl', '-g'],
57
+ :desc => 'user group acess control list'
58
+
59
+ define_rest_arg :tags, :header => :emc, :cli => ['tags', '-t'],
60
+ :desc => 'listable metadata tag name'
61
+
62
+ define_rest_arg :include_meta, :header => :emc, :cli => ['include-meta', '-e', :flag],
63
+ :desc => 'include object metadata in query result', :map => lambda{|v| v ? 1 : 0}
64
+
65
+ define_rest_arg :meta, :header => :emc, :cli => ['meta', '-m'],
66
+ :desc => 'user nonlistable metadata name=value pairs'
67
+
68
+ define_rest_arg :listable_meta, :header => :emc, :cli => ['listable-meta', '-i'],
69
+ :desc => 'user listable metadata tag name=value pairs'
70
+
71
+ #.......................................................................................................
72
+ # method specification
73
+ #.......................................................................................................
74
+ #### all methods
75
+ define_rest_method :all,
76
+ :required => [:uid, :key, :site],
77
+ :optional => [:account]
78
+
79
+ #### POST
80
+ define_rest_method :create_file,
81
+ :desc => 'create a file',
82
+ :result_class => StorageObject,
83
+ :http_method => :post,
84
+ :required => [:file, [:rpath, :listable_meta]],
85
+ :optional => [:content_type, :namespace, :create_beginoffset, :create_endoffset],
86
+ :exe => lambda {|req, args|
87
+ ext = req.extent(args[:file], args[:create_beginoffset],
88
+ args[:create_endoffset])
89
+ req.add_payload(args, ext)},
90
+ :map_required_args => lambda {|vals|
91
+ pvals = vals.select{|v| /^-i/.match(v) or not /^-/.match(v)}
92
+ ovals = if pvals.length.eql?(1)
93
+ pvals + [pvals.first]
94
+ elsif /\/$/.match(pvals.last) and pvals.length.eql?(2)
95
+ [pvals.first, pvals.last+File.basename(pvals.first)]
96
+ else
97
+ pvals
98
+ end
99
+ {:pvals => ovals, :dlen => ovals.length - pvals.length}},
100
+ :banner => 'Usage: synrest create-file file [remote-path|-i list-meta] [options]'
101
+
102
+ define_rest_method :create_dir,
103
+ :desc => 'create a directory',
104
+ :result_class => StorageObject,
105
+ :http_method => :post,
106
+ :required => [:rpath],
107
+ :optional => [:namespace],
108
+ :exe => lambda {|req, args| args[:rpath] += '/'}
109
+
110
+ define_rest_method :create_version,
111
+ :desc => 'create an immutable version of a file or directory',
112
+ :result_class => StorageObject,
113
+ :http_method => :post,
114
+ :required => [[:rpath, :oid]],
115
+ :optional => [:namespace],
116
+ :query => 'versions'
117
+
118
+ define_rest_method :update_nonlistable_metadata,
119
+ :desc => 'update nonlistable user metadata for a file or directory',
120
+ :http_method => :post,
121
+ :result_class => Result,
122
+ :required => [:meta, [:rpath, :oid]],
123
+ :optional => [:namespace],
124
+ :query => 'metadata/user'
125
+
126
+ define_rest_method :update_listable_metadata,
127
+ :desc => 'update listable user metadata for a file or directory',
128
+ :http_method => :post,
129
+ :result_class => Result,
130
+ :required => [:listable_meta, [:rpath, :oid]],
131
+ :optional => [:namespace],
132
+ :query => 'metadata/user'
133
+
134
+ define_rest_method :update_acl,
135
+ :desc => 'update access control list for a file or directory',
136
+ :http_method => :post,
137
+ :result_class => Result,
138
+ :required => [[:useracl, :groupacl], [:rpath, :oid]],
139
+ :optional => [:namespace],
140
+ :query => 'acl'
141
+
142
+ #### GET
143
+ define_rest_method :get,
144
+ :desc => 'get the contents of a file or directory',
145
+ :result_class => Download,
146
+ :http_method => :get,
147
+ :required => [[:rpath, :oid]],
148
+ :optional => [:namespace, :beginoffset, :endoffset],
149
+ :map_required_args => lambda {|vals|
150
+ pvals = vals.select{|v| /^-o/.match(v) or not /^-/.match(v)}
151
+ if pvals.empty?
152
+ {:pvals => [''], :dlen => 1}
153
+ else
154
+ {:pvals => pvals, :dlen => 0}
155
+ end},
156
+ :exe => lambda {|req, args|
157
+ if args[:beginoffset] and args[:endoffset]
158
+ ext = {:offset => args[:beginoffset].to_i,
159
+ :length => args[:endoffset].to_i - args[:beginoffset].to_i + 1}
160
+ req.set_header_range(args, ext); end},
161
+ :banner => 'Usage: synrest get [remote-path|-o oid] [options]'
162
+
163
+ define_rest_method :get_by_tag,
164
+ :desc => 'get files and directories with specified listable user metadata tag',
165
+ :result_class => StorageObjectList,
166
+ :http_method => :get,
167
+ :required => [:tags],
168
+ :optional => [:include_meta]
169
+
170
+
171
+ define_rest_method :get_user_metadata,
172
+ :desc => 'get both listable and nonlistable user metadata for a file or directory',
173
+ :result_class => UserMetadata,
174
+ :http_method => :get,
175
+ :required => [[:rpath, :oid]],
176
+ :optional => [:namespace],
177
+ :query => 'metadata/user'
178
+
179
+ define_rest_method :get_system_metadata,
180
+ :desc => 'get system metadata for a file or directory',
181
+ :http_method => :get,
182
+ :result_class => SystemMetadata,
183
+ :required => [[:rpath, :oid]],
184
+ :optional => [:namespace],
185
+ :query => 'metadata/system'
186
+
187
+ define_rest_method :get_acl,
188
+ :desc => 'get user and group access control list for a file or directory',
189
+ :result_class => Acl,
190
+ :http_method => :get,
191
+ :required => [[:rpath, :oid]],
192
+ :optional => [:namespace],
193
+ :query => 'acl'
194
+
195
+ define_rest_method :get_versions,
196
+ :desc => 'get versions of a file or directory',
197
+ :http_method => :get,
198
+ :result_class => Versions,
199
+ :required => [[:rpath, :oid]],
200
+ :optional => [:namespace],
201
+ :query => 'versions'
202
+
203
+ define_rest_method :get_all_tags,
204
+ :desc => 'get all defined tags',
205
+ :http_method => :get,
206
+ :result_class => Tags,
207
+ :required => [],
208
+ :optional => [:namespace, :tags],
209
+ :query => 'listabletags'
210
+
211
+
212
+ define_rest_method :get_tags,
213
+ :desc => 'get listable user metadata tags for a file or directory',
214
+ :http_method => :get,
215
+ :result_class => Tags,
216
+ :required => [[:rpath, :oid]],
217
+ :optional => [:namespace],
218
+ :query => 'metadata/tags'
219
+
220
+ #### PUT
221
+ define_rest_method :update,
222
+ :desc => 'update a file or directory',
223
+ :http_method => :put,
224
+ :result_class => Result,
225
+ :required => [:file, [:rpath, :oid]],
226
+ :optional => [:namespace, :beginoffset, :endoffset],
227
+ :exe => lambda {|req, args|
228
+ ext = req.extent(args[:file], args[:beginoffset], args[:endoffset])
229
+ req.set_header_range(args, ext)
230
+ req.add_payload(args, ext)
231
+ req.set_header_extent(args, ext)},
232
+ :map_required_args => lambda {|vals|
233
+ pvals = vals.select{|v| not /^-/.match(v)}
234
+ ovals = if pvals.length.eql?(1)
235
+ pvals + [pvals.first]
236
+ elsif /\/$/.match(pvals.last) and pvals.length.eql?(2)
237
+ [pvals.first, pvals.last+File.basename(pvals.first)]
238
+ else
239
+ pvals
240
+ end
241
+ {:pvals => ovals, :dlen => ovals.length - pvals.length}},
242
+ :banner => 'Usage: synrest update file [remote-path|-o oid] [options]'
243
+
244
+ #### DELETE
245
+ define_rest_method :delete,
246
+ :desc => 'delete a file or directory',
247
+ :result_class => Result,
248
+ :http_method => :delete,
249
+ :required => [[:rpath, :oid]],
250
+ :optional => [:namespace]
251
+
252
+ define_rest_method :delete_user_metadata,
253
+ :desc => 'delete user metadata for a file or directory',
254
+ :result_class => Result,
255
+ :http_method => :delete,
256
+ :required => [:tags, [:rpath, :oid]],
257
+ :optional => [:namespace],
258
+ :query => 'metadata/user'
259
+
260
+ #### Other methods
261
+ define_rest_method :get_object_url,
262
+ :desc => 'retrieve a shareable URL for linking to storage objects',
263
+ :result_class => ShareableUrl,
264
+ :http_method => :delete,
265
+ :required => [[:rpath, :oid]],
266
+ :optional => [:lifetime],
267
+ :diagnostics => false,
268
+ :map_required_args => lambda {|vals|
269
+ pvals = vals.select{|v| /^-o/.match(v) or not /^-/.match(v)}
270
+ if pvals.empty?
271
+ {:pvals => [''], :dlen => 1}
272
+ else
273
+ {:pvals => pvals, :dlen => 0}
274
+ end}
275
+
276
+ #.......................................................................................................
277
+ # other requests
278
+ #.......................................................................................................
279
+ def get_object_url(args)
280
+ esc = '/=&?%'
281
+ exp = (args[:lifetime].nil? ? 5 : args[:lifetime].to_i)*60 + Time.now.to_i
282
+ res = /.*(\/rest.*)/.match(url).captures.first
283
+ user = headers['x-emc-uid']
284
+ @sign = "GET\n" + "#{res}\n#{user}\n#{exp}".downcase
285
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), Base64.decode64(key), sign)
286
+ signature = Base64.encode64(digest.to_s())
287
+ @url = "#{url}?uid=#{URI.encode(user, esc)}&expires=#{exp}&signature=#{URI.encode(signature, esc)}"
288
+ end
289
+
290
+
291
+ #### Request
292
+ end
293
+
294
+ #### Synaptic4r
295
+ end
@@ -0,0 +1,357 @@
1
+ ###########################################################################################################
2
+ module Synaptic4r
3
+
4
+ ###########################################################################################################
5
+ module Utils
6
+
7
+ #.......................................................................................................
8
+ def unary_args_given?(unary_args, args)
9
+ unary_args.each{|a| raise ArgumentError, "Required argument '#{a}' is missing." unless args.include?(a)}
10
+ end
11
+
12
+ #.......................................................................................................
13
+ def symbolize(e)
14
+ if e.kind_of?(Hash)
15
+ e.inject({}){|h, (k,v)| h.update(k.to_sym => v)}
16
+ elsif e.kind_of?(Array)
17
+ e.map{|v| v.to_sym}
18
+ end
19
+ end
20
+
21
+ #.......................................................................................................
22
+ def create_timestamp()
23
+ Time.now().httpdate()
24
+ end
25
+
26
+ #.......................................................................................................
27
+ def read_file(file, offset, length)
28
+ IO.read(file, length, offset)
29
+ end
30
+
31
+ #### Utils
32
+ end
33
+
34
+ ###########################################################################################################
35
+ module Rest
36
+
37
+ #------------------------------------------------------------------------------------------------------
38
+ class << self
39
+
40
+ def included(base)
41
+ base.send(:extend, ClassMethods)
42
+ base.send(:include, InstanceMethods)
43
+ end
44
+
45
+ #### self
46
+ end
47
+
48
+
49
+ ####-----------------------------------------------------------------------------------------------------
50
+ module ClassMethods
51
+
52
+ #.......................................................................................................
53
+ @@method_defs = Hash.new{|h,k| h[k] = {:required => [], :optional => []}}
54
+ @@arg_defs = Hash.new{|h,k| h[k] = {}}
55
+
56
+ #.......................................................................................................
57
+ def method_defs
58
+ @@method_defs
59
+ end
60
+
61
+ #.......................................................................................................
62
+ def arg_defs
63
+ @@arg_defs
64
+ end
65
+
66
+ #.......................................................................................................
67
+ def define_rest_method(meth, args)
68
+ [meth].flatten.each do |m|
69
+ method_defs[m][:required] += args[:required] if args[:required]
70
+ method_defs[m][:optional] += args[:optional] if args[:optional]
71
+ method_defs[m][:http_method] = args[:http_method]
72
+ method_defs[m][:desc] = args[:desc]
73
+ method_defs[m][:result_class] = args[:result_class]
74
+ method_defs[m][:query] = args[:query]
75
+ method_defs[m][:exe] = args[:exe]
76
+ method_defs[m][:map_required_args] = args[:map_required_args]
77
+ method_defs[m][:banner] = args[:banner]
78
+ method_defs[m][:diagnostics] = args[:diagnostics]
79
+ end
80
+ end
81
+
82
+ #.......................................................................................................
83
+ def define_rest_arg(arg, opts)
84
+ arg_defs[arg].update(opts)
85
+ end
86
+
87
+ #.......................................................................................................
88
+ def args
89
+ method_defs
90
+ end
91
+
92
+ #.......................................................................................................
93
+ def has_rest_method?(meth)
94
+ rest_methods.include?(meth)
95
+ end
96
+
97
+ #.......................................................................................................
98
+ def rest_methods
99
+ args.keys.inject([]){|r,m| m.eql?(:all) ? r : r << m}
100
+ end
101
+ #.......................................................................................................
102
+ def http_method(meth)
103
+ args[meth][:http_method]
104
+ end
105
+
106
+ #.......................................................................................................
107
+ def required_rest_args(meth)
108
+ args[meth][:required] + args_all_methods(:required)
109
+ end
110
+
111
+ #.......................................................................................................
112
+ def unary_rest_args(meth)
113
+ args[meth][:required].inject([]){|r,a| a.kind_of?(Array) ? r : r << a}
114
+ end
115
+
116
+ #.......................................................................................................
117
+ def exclusive_rest_args(meth)
118
+ args[meth][:required].inject([]){|r,a| a.kind_of?(Array) ? r << a : r}
119
+ end
120
+
121
+ #.......................................................................................................
122
+ def optional_rest_args(meth)
123
+ args[meth][:optional] + args_all_methods(:optional)
124
+ end
125
+
126
+ #.......................................................................................................
127
+ def rest_arg(arg)
128
+ arg_defs[arg]
129
+ end
130
+
131
+ #.......................................................................................................
132
+ def args_all_methods(type)
133
+ args[:all][type].inject([]){|r,a| rest_arg(a)[:header].eql?(:hide) ? r : r << a}
134
+ end
135
+
136
+ #.......................................................................................................
137
+ def desc(meth)
138
+ args[meth][:desc]
139
+ end
140
+
141
+ #.......................................................................................................
142
+ def exe(meth)
143
+ args[meth][:exe]
144
+ end
145
+
146
+ #.......................................................................................................
147
+ def banner(meth)
148
+ args[meth][:banner]
149
+ end
150
+
151
+ #.......................................................................................................
152
+ def diagnostics(meth)
153
+ args[meth][:diagnostics].nil? ? true : args[meth][:diagnostics]
154
+ end
155
+
156
+ #.......................................................................................................
157
+ def map_required_args(meth)
158
+ args[meth][:map_required_args]
159
+ end
160
+
161
+ #.......................................................................................................
162
+ def result_class(meth)
163
+ args[meth][:result_class]
164
+ end
165
+
166
+ #.......................................................................................................
167
+ def query(meth)
168
+ args[meth][:query]
169
+ end
170
+
171
+ #.......................................................................................................
172
+ def header_args(meth)
173
+ unary_rest_args(meth) + exclusive_rest_args(meth).flatten + optional_rest_args(meth) -
174
+ non_header_args(meth)
175
+ end
176
+
177
+ #.......................................................................................................
178
+ def emc_headers
179
+ arg_defs.inject([]){|r, (a, d)| d[:header].eql?(:emc) ? r.push(a) : r}
180
+ end
181
+
182
+ #.......................................................................................................
183
+ def non_header_args(meth)
184
+ arg_defs.inject([]){|r, (a, d)| d[:header].eql?(:none) ? r.push(a) : r}
185
+ end
186
+
187
+ #### ClassMethods
188
+ end
189
+
190
+ ####-----------------------------------------------------------------------------------------------------
191
+ module InstanceMethods
192
+
193
+ #.......................................................................................................
194
+ include Utils
195
+
196
+ #.......................................................................................................
197
+ attr_reader :headers, :uid, :key, :site, :subtenant, :payload, :meth, :sign, :url
198
+
199
+ #.......................................................................................................
200
+ def initialize(args)
201
+ unary_args_given?([:uid, :subtenant, :key, :site], args)
202
+ @uid = args[:uid]
203
+ @key = args[:key]
204
+ @site = args[:site]
205
+ @subtenant = args[:subtenant]
206
+ @headers = credentials
207
+ end
208
+
209
+ #.......................................................................................................
210
+ def execute(meth, *args, &blk)
211
+ @meth = meth
212
+ args = args.first || {}
213
+ set_remote_file(args)
214
+ unary_args_given?(self.class.unary_rest_args(meth), args)
215
+ exclusive_args_given?(self.class.exclusive_rest_args(meth), args)
216
+ self.class.exe(meth)[self, args] if self.class.exe(meth)
217
+ build_service_url(args)
218
+ add_header_attr(args)
219
+ create_signature
220
+ res = if self.respond_to?(meth)
221
+ self.send(meth, args)
222
+ else
223
+ if args[:dump].nil? and args[:payload].nil?
224
+ RestClient::Request.execute(:method => self.class.http_method(meth), :url => url,
225
+ :headers => headers, :payload => payload)
226
+ end
227
+ end
228
+ self.class.result_class(meth).new(:result => res, :headers => headers, :url => url, :sign => sign,
229
+ :http_request => self.class.http_method(meth),
230
+ :payload => args[:payload] ? payload : nil)
231
+ end
232
+
233
+ #.......................................................................................................
234
+ def exclusive_args_given?(exclusive_args, args)
235
+ exclusive_args.each do |alist|
236
+ unless alist.select{|a| args.keys.include?(a)}.length.eql?(1)
237
+ acli = alist.map{|a| [self.class.rest_arg(a)[:cli]].flatten.first}
238
+ raise ArgumentError, "One of '#{acli.join(', ')}' is required as an argument."
239
+ end
240
+ end
241
+ end
242
+
243
+ #.......................................................................................................
244
+ def add_header_attr(given={})
245
+ to_emc = lambda{|a| h = a.to_s.gsub(/_/,'-'); self.class.emc_headers.include?(a) ? "x-emc-#{h}" : h}
246
+ header_args = self.class.header_args(meth)
247
+ given.keys.each do |k|
248
+ headers.update(to_emc[k] => given[k]) if header_args.include?(k)
249
+ end
250
+ end
251
+
252
+ #.......................................................................................................
253
+ def set_remote_file(args)
254
+ if args[:rpath]
255
+ if args[:namespace] and args[:namespace].empty?
256
+ args[:rpath] = args[:rpath]
257
+ elsif args[:namespace]
258
+ args[:rpath] = args[:namespace] + '/' + args[:rpath]
259
+ else
260
+ args[:rpath] = uid + '/' + args[:rpath]
261
+ end
262
+ end
263
+ end
264
+
265
+ #.......................................................................................................
266
+ def build_service_url(args={})
267
+ surl = if args[:rpath]
268
+ 'namespace/' + args[:rpath]
269
+ else
270
+ 'objects' + (args[:oid].nil? ? '' : "/#{args[:oid]}")
271
+ end
272
+ @url = (/\/$/.match(site).nil? ? site + '/' : site) + surl +
273
+ ((q = self.class.query(meth)).nil? ? '' : "?#{q}")
274
+ end
275
+
276
+ #.......................................................................................................
277
+ def create_signature
278
+ @sign = create_sign_string
279
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), Base64.decode64(key), sign)
280
+ headers['x-emc-signature'] = Base64.encode64(digest.to_s()).chomp()
281
+ end
282
+
283
+ #.......................................................................................................
284
+ def create_sign_string
285
+ composite_string = (self.class.http_method(meth).to_s.upcase || '') + "\n" + \
286
+ (headers['content-type'] || '') + "\n" + \
287
+ (headers['range'] || '') + "\n" + \
288
+ (headers['date'] || '') + "\n"
289
+ if url
290
+ composite_string += URI.parse(url).path.downcase
291
+ composite_string += "?" + URI.parse(url).query.downcase unless URI.parse(url).query.nil?
292
+ end
293
+ composite_string += "\n" + canonicalize_custom_headers
294
+ end
295
+
296
+ #.......................................................................................................
297
+ def canonicalize_custom_headers
298
+ headers.select do |key, value|
299
+ /^x-emc-/.match(key)
300
+ end.sort.inject("") do |h, (k, v)|
301
+ h += "#{k}:#{v}\n"
302
+ end.chomp
303
+ end
304
+
305
+ #.......................................................................................................
306
+ def set_header_range(args, ext)
307
+ headers['range'] = "bytes=#{ext[:offset]}-#{ext[:offset]+ext[:length]-1}"
308
+ end
309
+
310
+ #.......................................................................................................
311
+ def extent(file, begin_offset, end_offset)
312
+ if file
313
+ file_offset = File.size(file) - 1
314
+ offset = begin_offset.to_i
315
+ end_offset = end_offset.nil? ? file_offset : end_offset.to_i
316
+ end_offset = file_offset if end_offset > file_offset
317
+ length = end_offset - offset + 1
318
+ {:offset => offset, :length => length}
319
+ end
320
+ end
321
+
322
+ #.......................................................................................................
323
+ def set_header_extent(args, ext)
324
+ args[:beginoffset] = ext[:offset]
325
+ args[:endoffset] = ext[:offset] + ext[:length] - 1
326
+ end
327
+
328
+ #.......................................................................................................
329
+ def add_payload(args, ext)
330
+ if args[:file]
331
+ @payload = read_file(args[:file], ext[:offset], ext[:length])
332
+ if @payload
333
+ headers['content-length'] = ext[:length]
334
+ headers['content-md5'] = Base64.encode64(Digest::MD5.digest(payload)).chomp()
335
+ end
336
+ end
337
+ end
338
+
339
+ #.......................................................................................................
340
+ def credentials
341
+ curr_time = create_timestamp
342
+ {'x-emc-uid' => subtenant + '/' + uid,
343
+ 'date' => curr_time,
344
+ 'x-emc-date' => curr_time,
345
+ 'content-type' => 'application/octet-stream',
346
+ 'accept' => '*/*'}
347
+ end
348
+
349
+ #### InstanceMethods
350
+ end
351
+
352
+
353
+ ### Rest
354
+ end
355
+
356
+ #### Synaptic4r
357
+ end