Class: Net::DAV

Inherits:
Object
  • Object
show all
Defined in:
lib/net/dav.rb,
lib/net/dav/item.rb

Overview

Implement a WebDAV client

Defined Under Namespace

Classes: CurlHandler, Item, NetHttpHandler

Constant Summary

MAX_REDIRECTS =
10

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri, options = nil) ⇒ DAV

Creates a new Net::DAV object for the specified host The path part of the URI is used to handle relative URLs in subsequent requests. You can pass :curl => false if you want to disable use of the curb (libcurl) gem if present for acceleration



350
351
352
353
354
355
356
357
358
# File 'lib/net/dav.rb', line 350

def initialize(uri, options = nil)
  @have_curl = Curl rescue nil
  if options && options.has_key?(:curl) && !options[:curl]
    @have_curl = false
  end
  @uri = uri
  @uri = URI.parse(@uri) if @uri.is_a? String
  @handler = @have_curl ? CurlHandler.new(@uri) : NetHttpHandler.new(@uri)
end

Class Method Details

.start(uri, options = nil, &block) ⇒ Object

Creates a new Net::DAV object and opens the connection to the host. Yields the object to the block.

Example:

res = Net::DAV.start(url) do |dav|
  dav.find(url.path) do |item|
    puts "#{item.uri} is size #{item.size}"
  end
end


341
342
343
# File 'lib/net/dav.rb', line 341

def self.start(uri, options = nil, &block) # :yield: dav
  new(uri, options).start(&block)
end

Instance Method Details

#cd(url) ⇒ Object

Change the base URL for use in handling relative paths



495
496
497
498
499
500
501
# File 'lib/net/dav.rb', line 495

def cd(url)
  new_uri = @uri.merge(url)
  if new_uri.host != @uri.host || new_uri.port != @uri.port || new_uri.scheme != @uri.scheme
    raise Exception , "uri must have same scheme, host and port"
  end
  @uri = new_uri
end

#copy(path, destination) ⇒ Object

Send a copy request to the server.

Example:

dav.copy(original_path, destination)


565
566
567
568
569
570
571
# File 'lib/net/dav.rb', line 565

def copy(path,destination)
  path = @uri.merge(path).path
  destination = @uri.merge(destination).to_s
  headers = {'Destination' => destination}
  res = @handler.request(:copy, path, nil, headers)
  res.body
end

#credentials(user, pass) ⇒ Object

Set credentials for basic authentication



376
377
378
379
# File 'lib/net/dav.rb', line 376

def credentials(user, pass)
  @handler.user = user
  @handler.pass = pass
end

#delete(path) ⇒ Object

Delete request

Example:

dav.delete(uri.path)


543
544
545
546
547
# File 'lib/net/dav.rb', line 543

def delete(path)
  path = @uri.merge(path).path
  res = @handler.request(:delete, path, nil, nil)
  res.body
end

#disable_basic_auth=(value) ⇒ Object



303
304
305
# File 'lib/net/dav.rb', line 303

def disable_basic_auth=(value)
  @handler.disable_basic_auth = value
end

#disable_basic_auth?Boolean

Disable basic auth - to protect passwords from going in the clear through a man-in-the-middle attack.

Returns:

  • (Boolean)


299
300
301
# File 'lib/net/dav.rb', line 299

def disable_basic_auth?
  @handler.disable_basic_auth
end

#exists?(path) ⇒ Boolean

Returns true if resource exists on server.

Example:

dav.exists?('https://www.example.com/collection/')  => true
dav.exists?('/collection/')  => true

Returns:

  • (Boolean)


625
626
627
628
629
630
631
632
633
634
635
# File 'lib/net/dav.rb', line 625

def exists?(path)
  path = @uri.merge(path).path
  headers = {'Depth' => '1'}
  body = '<?xml version="1.0" encoding="utf-8"?><DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
  begin
    res = @handler.request(:propfind, path, body, headers)
  rescue
    return false
  end
  return (res.is_a? Net::HTTPSuccess)
end

#find(path, options = {}) ⇒ Object

Find files and directories, yields Net::DAV::Item

The :filename option can be a regexp or string, and is used to filter the yielded items.

If :suppress_errors is passed, exceptions that occurs when reading directory information is ignored, and a warning is printed out stderr instead.

The default is to not traverse recursively, unless the :recursive options is passed.

Examples:

res = Net::DAV.start(url) do |dav|
  dav.find(url.path, :recursive => true) do |item|
    puts "#{item.type} #{item.uri}"
    puts item.content
  end
end

dav = Net::DAV.new(url)
dav.find(url.path, :filename => /\.html/, :suppress_errors => true)
  puts item.url.to_s
end


439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/net/dav.rb', line 439

def find(path, options = {})
  path = @uri.merge(path).path
  namespaces = {'x' => "DAV:"}
  begin
    doc = propfind(path)
  rescue Net::ProtocolError => e
    msg = e.to_s + ": " + path.to_s
    if(options[:suppress_errors])then
      # Ignore dir if propfind returns an error
      warn("Warning: " + msg)
      return nil
    else
      raise e.class.new(msg, nil)
    end
  end
  path.sub!(/\/$/, '')
  doc./('.//x:response', namespaces).each do |item|
    uri = @uri.merge(item.xpath("x:href", namespaces).inner_text)
    size = item.%(".//x:getcontentlength", namespaces).inner_text rescue nil
    type = item.%(".//x:collection", namespaces) ? :directory : :file
    res = Item.new(self, uri, type, size)
    if type == :file then

      if(options[:filename])then
        search_term = options[:filename]
        filename = File.basename(uri.path)
        if(search_term.class == Regexp and search_term.match(filename))then
          yield res
        elsif(search_term.class == String and search_term == filename)then
          yield res
        end
      else
        yield res
      end

    elsif uri.path == path || uri.path == path + "/"
      # This is the top-level dir, skip it
    elsif options[:recursive] && type == :directory

      if(!options[:filename])then
        yield res
      end

      # This is a subdir, recurse
      find(uri.path, options) do |sub_res|
        yield sub_res
      end
    else
      if(!options[:filename])then
        yield res
      end
    end
  end
end

#get(path, &block) ⇒ Object

Get the content of a resource as a string

If called with a block, yields each fragment of the entity body in turn as a string as it is read from the socket. Note that in this case, the returned response object will not contain a (meaningful) body.



510
511
512
513
514
# File 'lib/net/dav.rb', line 510

def get(path, &block)
  path = @uri.merge(path).path
  body = @handler.request_returning_body(:get, path, nil, &block)
  body
end

#lock(path, xml_snippet) ⇒ Object

Send a lock request to the server

On success returns an XML response body with a Lock-Token

Example:

dav.lock(uri.path, "<d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:owner>Owner</d:owner>")


599
600
601
602
603
604
605
606
607
608
# File 'lib/net/dav.rb', line 599

def lock(path, xml_snippet)
  path = @uri.merge(path).path
  headers = {'Depth' => '1'}
  body =  '<?xml version="1.0"?>' +
  '<d:lockinfo xmlns:d="DAV:">' +
     xml_snippet +
  '</d:lockinfo>'
  res = @handler.request(:lock, path, body, headers)
  Nokogiri::XML.parse(res.body)
end

#mkdir(path) ⇒ Object

Makes a new directory (collection)



638
639
640
641
642
# File 'lib/net/dav.rb', line 638

def mkdir(path)
  path = @uri.merge(path).path
  res = @handler.request(:mkcol, path, nil, nil)
  res.body
end

#move(path, destination) ⇒ Object

Send a move request to the server.

Example:

dav.move(original_path, new_path)


553
554
555
556
557
558
559
# File 'lib/net/dav.rb', line 553

def move(path,destination)
  path = @uri.merge(path).path
  destination = @uri.merge(destination).to_s
  headers = {'Destination' => destination}
  res = @handler.request(:move, path, nil, headers)
  res.body
end

#open_timeoutObject

Seconds to wait until connection is opened. If the DAV object cannot open a connection in this many seconds, it raises a TimeoutError exception.



323
324
325
# File 'lib/net/dav.rb', line 323

def open_timeout
  @handler.read_timeout
end

#open_timeout=(sec) ⇒ Object



327
328
329
# File 'lib/net/dav.rb', line 327

def open_timeout=(sec)
  @handler.read_timeout = sec
end

#propfind(path, *options) ⇒ Object

Perform a PROPFIND request

Example:

Basic propfind:

properties = propfind('/path/')

Get ACL for resource:

properties = propfind('/path/', :acl)

Custom propfind:

properties = propfind('/path/', '<?xml version="1.0" encoding="utf-8"?>...')

See webdav.org/specs/rfc3744.html#rfc.section.5.9 for more on how to retrieve access control properties.



399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/net/dav.rb', line 399

def propfind(path,*options)
  headers = {'Depth' => '1'}
  if(options[0] == :acl)
    body = '<?xml version="1.0" encoding="utf-8" ?><D:propfind xmlns:D="DAV:"><D:prop><D:owner/>' +
            '<D:supported-privilege-set/><D:current-user-privilege-set/><D:acl/></D:prop></D:propfind>'
  else
    body = options[0]
  end
  if(!body)
    body = '<?xml version="1.0" encoding="utf-8"?><DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
  end
  res = @handler.request(:propfind, path, body, headers)
  Nokogiri::XML.parse(res.body)
end

#proppatch(path, xml_snippet) ⇒ Object

Do a proppatch request to the server to update properties on resources or collections.

Example:

dav.proppatch(uri.path,
  "<d:set><d:prop>" +
  "<d:creationdate>#{new_date}</d:creationdate>" +
  "</d:set></d:prop>" +
  )


582
583
584
585
586
587
588
589
590
591
# File 'lib/net/dav.rb', line 582

def proppatch(path, xml_snippet)
  path = @uri.merge(path).path
  headers = {'Depth' => '1'}
  body =  '<?xml version="1.0"?>' +
  '<d:propertyupdate xmlns:d="DAV:">' +
     xml_snippet +
  '</d:propertyupdate>'
  res = @handler.request(:proppatch, path, body, headers)
  Nokogiri::XML.parse(res.body)
end

#put(path, stream, length) ⇒ Object

Stores the content of a stream to a URL

Example: File.open(file, "r") do |stream|

dav.put(url.path, stream, File.size(file))

end



522
523
524
525
526
# File 'lib/net/dav.rb', line 522

def put(path, stream, length)
  path = @uri.merge(path).path
  res = @handler.request_sending_stream(:put, path, stream, length, nil)
  res.body
end

#put_string(path, str) ⇒ Object

Stores the content of a string to a URL

Example:

dav.put(url.path, "hello world")


533
534
535
536
537
# File 'lib/net/dav.rb', line 533

def put_string(path, str)
  path = @uri.merge(path).path
  res = @handler.request_sending_body(:put, path, str, nil)
  res.body
end

#read_timeoutObject

Seconds to wait until reading one block (by one system call). If the DAV object cannot read a block in this many seconds, it raises a TimeoutError exception.



311
312
313
# File 'lib/net/dav.rb', line 311

def read_timeout
  @handler.read_timeout
end

#read_timeout=(sec) ⇒ Object



315
316
317
# File 'lib/net/dav.rb', line 315

def read_timeout=(sec)
  @handler.read_timeout = sec
end

#start(&block) ⇒ Object

Opens the connection to the host. Yields self to the block.

Example:

res = Net::DAV.new(url).start do |dav|
  dav.find(url.path) do |item|
    puts item.inspect
  end
end


369
370
371
372
373
# File 'lib/net/dav.rb', line 369

def start(&block) # :yield: dav
  @handler.start do
    return yield(self)
  end
end

#unlock(path, locktoken) ⇒ Object

Send an unlock request to the server

Example:

dav.unlock(uri.path, "opaquelocktoken:eee47ade-09ac-626b-02f7-e354175d984e")


614
615
616
617
618
# File 'lib/net/dav.rb', line 614

def unlock(path, locktoken)
 headers = {'Lock-Token' => '<'+locktoken+'>'}
 path = @uri.merge(path).path
 res = @handler.request(:unlock, path, nil, headers)
end

#verify_callback=(callback) ⇒ Object



644
645
646
# File 'lib/net/dav.rb', line 644

def verify_callback=(callback)
  @handler.verify_callback = callback
end

#verify_server=(value) ⇒ Object



648
649
650
# File 'lib/net/dav.rb', line 648

def verify_server=(value)
  @handler.verify_server = value
end