Module: WebDAV

Defined in:
lib/davclient.rb

Overview

Main WebDAV client. Current working URL is stored in a tempfile named /tmp/cwurl.pid, where pid is the parent process. Username an password is stored in the ~/.netrc file. This means there is no need to set up any sessions or connections.

If a change directory command is executed with a relative path, like for instance WebDAV.cd(“../collection”), it will raise an exception if current working url has not been set. First a change directory command is executed it should use an absolute URL, like for instance WebDAV.cd(“www.webdav.org/collection/”).

If using an URL with a server name not found in the ~/.netrc file, instructions for adding the necessary servername, username and password will be printed to stdout.

Constant Summary collapse

VERSION =

:stopdoc:

'0.0.4'

Class Method Summary collapse

Class Method Details

.absoluteUrl(url) ⇒ Object

Make relative url absolute. Returns error if no current working url has been set.

Example:

WebDAV.cd("https://example.org/subfolder")
print WebDAV.absoluteUrl("..")  => "https://example.org/"


58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/davclient.rb', line 58

def self.absoluteUrl(url)
  if(not(url =~ /^http.?:\/\//))then
    cwurl = Pathname.new(self.CWURL)
    cwurl = cwurl + url
    url = cwurl.to_s
    # url = url + "/" if(not(url =~ /\/$/))

    if(not(url =~ /^http.?:\/\//))then
      raise "illegal url: " + url
    end
  end
  return url
end

.cd(url) ⇒ Object

Change current working url. Takes relative pathnames. First time this method is called, an absolute URL must be used. Raises exception if servername is not found in ~/.netrc file.

Examples:

WebDAV.cd("http://www.example.org")

WebDAV.cd("../folder")


98
99
100
101
102
103
104
105
106
107
# File 'lib/davclient.rb', line 98

def self.cd(url)
  url = absoluteUrl(url)
  url = url + "/" if(not(url =~ /\/$/))
  resource = WebDAV.propfind(url)
  if(resource and resource.isCollection?)then
    WebDAV.CWURL = url
  else
    raise Exception, "#{$0} cd: #{url}: No such collection on remote server."
  end
end

.cp(src, dest) ⇒ Object

Copy resources

Examples:

WebDAV.cp("src.html","https://example.org/destination/destination.html"


378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/davclient.rb', line 378

def self.cp(src,dest)
  srcUrl = absoluteUrl(src)
  destUrl = absoluteUrl(dest)

  # puts "DEBUG: " + srcUrl + " => " + destUrl
  curl_command = CURL_COPY.sub("<!--destination-->", destUrl) + " " + srcUrl
  response = DavClient.exec_curl(curl_command)

  if(response  == "")then
    return destUrl
  end
  return false
end

.CWURLObject

Returns current working url.



41
42
43
44
45
46
47
48
49
# File 'lib/davclient.rb', line 41

def self.CWURL
  return $CWURL if($CWURL)
  cwurl = nil
  filename = DavClient.cwurl_filename
  if(File.exists?(filename))
    File.open(filename, 'r') {|f| cwurl = f.read() }
  end
  return cwurl
end

.CWURL=(url) ⇒ Object

Sets current working url.

Current working url is stored in aa tempfile with parent process pid as part of the filename.



113
114
115
116
117
# File 'lib/davclient.rb', line 113

def self.CWURL=(url)
  $CWURL = url
  File.open(DavClient.cwurl_filename, 'w') {|f| f.write(url) }
  # puts "DEBUG: writing " + DavClient.cwurl_filename
end

.delete(url) ⇒ Object

Delete resource

Examples:

WebDAV.cd("https://example.org/folder")
WebDAV.mkcol("subfolder")
WebDAV.delete("subfolder")


427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'lib/davclient.rb', line 427

def self.delete(url)
  url = absoluteUrl(url)

  curl_command = CURL_DELETE + url
  response_data = DavClient.exec_curl(curl_command)
  headers = response_data[:head]
  response = response_data[:body]
  
   if(response  == "")then
     return url
   end
   
   if headers.to_s.match(/204 No Content/)
    return true
   end
   
   if(not(response =~ /200 OK/)) then
     puts "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
     return false
   end
   return url
end

.exists?(url) ⇒ Boolean

Returns true if resource exists

Returns:

  • (Boolean)


367
368
369
370
371
# File 'lib/davclient.rb', line 367

def self.exists?(url)
  url = absoluteUrl(url)
  props = WebDAV.propfind(url)
  props.size > 0 unless props.nil?
end

.find(*args, &block) ⇒ Object

Find files and folders.

Examples:

result = find( url [:type => "collection"|"resource"] [:recursive => true])

result = find( url, :type => "collection" ,:recursive => true)

You can also pass a block of code:

find( url, :type => "collection" ,:recursive => true) do |folder|
  puts folder.href
end

If no url is specified, current working url is used.

cd("https://webdav.org")
find() do |item|
  print item.title
end


231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/davclient.rb', line 231

def self.find(*args, &block)

  if(args.size == 0)
    href = self.CWURL
  elsif(args.size == 1)
    if(args[0].class == String)
      href = args[0]
    else
      options = args[0]
    end
  elsif(args.size == 2)
    href = args[0]
    options = args[1]
  else
    raise "Illegal number of arguments."
  end

  if(href == nil )
    if(WebDAV.CWURL == nil)
      raise "no current working url set"
    else
      href = WebDAV.CWURL
    end
  end

  type = nil
  recursive = false
  if(options)then

    if(options[:type])then
      type = options[:type]
    end
    if(options[:recursive])then
      recursive = options[:recursive]
    end
  end
  begin
    dav_xml_output = propfind(href, :xml => true)
  rescue Exception => exception
    $stderr.puts "Warning: " + href + " : " + exception
    # raise "er
    return nil
  end
  if(not(dav_xml_output))then
    return nil
  end

  doc = Hpricot( dav_xml_output )
  items_filtered = Array.new()
  items = doc.search("//d:response").reverse

# TODO: handle recursive
  
  return items.collect do |item|
    {
     :href => item.href, 
     :content_type => item.getcontenttype, 
     :resource_type => item.resourcetype
    }
  end

# I Don't think we need the below
=begin        
  # filter items
  items.each do |item|

    # Ignore info about root item (file or folder)
    if(item.href != href) then

      if(type == nil)then
        # No filters
        items_filtered.push(item)
        if(block) then
          yield item
        end

      else
        # Filter result set
        if((type == "collection" or type == "folder" or type == "directory") and item.isCollection? )then
          items_filtered.push(item)
          if(block) then
            yield item
          end
        end

        # TODO BUG: Item is not yielded if :type => "resource" is given...
        # puts "DEBUG: " + type + "  " + item.isCollection?.to_s
        if( (type == "file" or type == "resource") and item.isCollection? == false )then
          items_filtered.push(item)
          if(block) then
            yield item
          end
        end
      end

    end
  end
=end

  if(recursive) then
    items_filtered.each do |item|
      if(item.collection && item.href != args[0])then
        result = find(item.href, args[1], &block)
        if(result != nil)
          items_filtered.concat( result)
        end
      end
    end
  end

  return items_filtered
end

.get(url) ⇒ Object

Get content of resource as string

Example:

html = WebDAV.get(url)

html = WebDAV.get("file_in_current_working_folder.html")


127
128
129
130
131
132
133
# File 'lib/davclient.rb', line 127

def self.get(url)
  url = absoluteUrl(url)

  curl_command = url
  response = DavClient.exec_curl(curl_command)
  return response
end

.isCollection?(url) ⇒ Boolean

Boolean function that returns true if url is a collection

Example:

WebDAV.isCollection("../test.html") => false

Returns:

  • (Boolean)


77
78
79
80
81
82
83
84
85
86
# File 'lib/davclient.rb', line 77

def self.isCollection?(url)
  url = absoluteUrl(url)
  url = url + "/" if(not(url =~ /\/$/))
  resource = WebDAV.propfind(url)
  if(resource == nil)
    return false
  else
    return resource.isCollection?
  end
end

.mkcol(*args) ⇒ Object

Make collection Accepts relative url’s



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/davclient.rb', line 346

def self.mkcol(*args) # url, props)
  url = args[0]
  props = args[3]
  url = absoluteUrl(url)
  curl_command = CURL_MKCOL + " " + url
  resp = DavClient.exec_curl(curl_command)
  headers = resp[:head]
  response = resp[:body]
  
  return true if headers.to_s.match(/201/)
    
  if(props) then
    proppatch(url,props)
  end
  if(response =~ />Created</)then
    return true
  end
  return response
end

.mv(src, dest) ⇒ Object

Move resources

Examples:

WebDAV.mv("src.html","https://example.org/destination/destination.html"


398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/davclient.rb', line 398

def self.mv(src,dest)
  srcUrl = absoluteUrl(src)
  destUrl = absoluteUrl(dest)

  # puts "DEBUG: " + srcUrl + " => " + destUrl
  curl_command = CURL_MOVE.sub("<!--destination-->", destUrl) + " " + srcUrl
  resp = DavClient.exec_curl(curl_command)
  headers  = resp[:head]
  response = resp[:body]
  
  if headers.match(/201 Created/)
    true
  elsif headers.to_s.match(/301 Moved Permanently/) 
    false 
  elsif response == "" 
    destUrl
  else
    false
  end
end

.options(url) ⇒ Object

Returns a string with the webservers WebDAV options (PUT, PROPFIND, etc.)



506
507
508
509
510
511
# File 'lib/davclient.rb', line 506

def self.options(url)
  if(not(url))
    url = self.CWURL
  end
  return DavClient.exec_curl(CURL_OPTIONS + url )
end

.parse_xml_response(xml) ⇒ Object



203
204
205
206
207
208
209
# File 'lib/davclient.rb', line 203

def self.parse_xml_response(xml)
  #doc = Hpricot( xml )
  #items_filtered = []
  #items = doc.search("//d:response").reverse
  #items.collect {|item| item.href }
  xml
end

.propfind(*args) ⇒ Object

Get WebDAV properties

Examples:

item = propfind(url)                - Returns an Hpricot::Elem object

xml = propfind(url, :xml => true)   - Returns xml for debugging.


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/davclient.rb', line 161

def self.propfind(*args)
  url = args[0]
  url = absoluteUrl(url)
  options = args[1]

  curl_command = CURL_PROPFIND + " \"" + url + "\""
  response = DavClient.exec_curl(curl_command)
  headers  = response[:head]
  response = response[:body]
  
  
  return nil if response == ""
  
  if headers.match(/404/) then
    return nil
  elsif headers.match(/301/) then
    return nil
  elsif headers.match(/207/) then 
      return parse_xml_response(response)
  elsif headers.match(/200/) then
    # puts "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
    # exit(0)
    raise "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
  end

  if(options and options[:xml])then
    return response
  end
  
  doc = Hpricot( response )
  items_filtered = Array.new()
  items = doc.search("//d:response").reverse
  items.each do |item|

    # Only return root item if folder
    if(item.href == url or item.href == url + "/" ) then
      return item
    end
  end
  return nil
end

.proppatch(url, property) ⇒ Object

Set WebDAV properties for url as xml.

Example:

WebDAV.proppatch("https://dav.webdav.org/folder","<contentLastModified>2007-12-12 12:00:00 GMT</contentLastModified>


140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/davclient.rb', line 140

def self.proppatch(url, property)
  url = absoluteUrl(url)
  curl_command = CURL_PROPPATCH + " \""+url+"\""
  curl_command = curl_command.gsub("<!--property-and-value-->",property)
  response = DavClient.exec_curl(curl_command)
  headers  = response[:head]
  response = response[:body]
  
  if(not(headers =~ /200/)) then
    puts "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
    exit(0)
  end
end

.publish(url, string, props) ⇒ Object

Low level WebDAV publish

Example:

WebDAV.publish("https://dav.example.org/index.html","<h1>Hello</h1>",nil)


456
457
458
459
460
461
# File 'lib/davclient.rb', line 456

def self.publish(url, string, props)
  self.put_string(url, string)
  if(props) then
    self.proppatch(url,props)
  end
end

.put(url, file_name) ⇒ Object

Upload local file to webserver

Example:

WebDAV.put("https://example.org/myfile.html", "myfile.html")


487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
# File 'lib/davclient.rb', line 487

def self.put(url, file_name)
  url = absoluteUrl(url)

  curl_command = CURL_UPLOAD + " " + file_name + " " + url
  response = DavClient.exec_curl(curl_command)
  if response.kind_of?(Hash)
    headers = response[:head]
    response = response[:body]
    true if headers.match(/201/)
  end
  
  if response.match(/201/) then
    true
  elsif(response != "" and not(response =~ /200 OK/)) then
    raise "Error:\n WebDAV.put: WebDAV Request:\n" + curl_command + "\n\nResponse: " + response
  end
end

.put_string(url, str) ⇒ Object

Puts content of string to file on server with url

Example:

WebDAV.put("https://dav.webdav.org/file.html", "<html><h1>Test</h1></html>"


470
471
472
473
474
475
476
477
478
479
# File 'lib/davclient.rb', line 470

def self.put_string(url,str)
  url = absoluteUrl(url)

  if(url =~ /\/$/)then
    raise "Error: WebDAV.put_html: url can not be a collection (folder)."
  end

  filename = DavClient.string2tempfile(str)
  put(url,filename)
end

.versionObject

Returns the version string for the library.



36
37
38
# File 'lib/davclient.rb', line 36

def self.version
  VERSION
end