lib/net/dav.rb in net_dav-0.1.1 vs lib/net/dav.rb in net_dav-0.2.0
- old
+ new
@@ -1,35 +1,179 @@
require 'net/https'
require 'uri'
require 'nokogiri'
require 'net/dav/item'
+require 'base64'
+begin
+ require 'curb'
+rescue LoadError
+end
module Net #:nodoc:
# Implement a WebDAV client
class DAV
+ class NetHttpHandler
+ attr_writer :user, :pass
+
+ def initialize(uri)
+ @uri = uri
+ case @uri.scheme
+ when "http"
+ @http = Net::HTTP.new(@uri.host, @uri.port)
+ when "https"
+ @http = Net::HTTPS.new(@uri.host, @uri.port)
+ else
+ raise "unknown uri scheme"
+ end
+ end
+
+ def start(&block)
+ @http.start(&block)
+ end
+
+ def read_timeout
+ @http.read_timeout
+ end
+
+ def read_timeout=(sec)
+ @http.read_timeout = sec
+ end
+
+ def open_timeout
+ @http.read_timeout
+ end
+
+ def open_timeout=(sec)
+ @http.read_timeout = sec
+ end
+
+ def request_sending_stream(verb, path, stream, length, headers)
+ req =
+ case verb
+ when :put
+ Net::HTTP::Put.new(path)
+ else
+ raise "unkown sending_stream verb #{verb}"
+ end
+ req.body_stream = stream
+ req.content_length = length
+ headers.each_pair { |key, value| req[key] = value } if headers
+ req.content_type = 'text/xml; charset="utf-8"'
+ if (@user)
+ req.basic_auth @user, @pass
+ end
+ res = @http.request(req)
+ res.value # raises error if not success
+ res
+ end
+
+ def request_sending_body(verb, path, body, headers)
+ req =
+ case verb
+ when :put
+ Net::HTTP::Put.new(path)
+ else
+ raise "unkown sending_body verb #{verb}"
+ end
+ req.body = body
+ headers.each_pair { |key, value| req[key] = value } if headers
+ req.content_type = 'text/xml; charset="utf-8"'
+ if (@user)
+ req.basic_auth @user, @pass
+ end
+ res = @http.request(req)
+ res.value # raises error if not success
+ res
+ end
+
+ def request_returning_body(verb, path, headers, &block)
+ req =
+ case verb
+ when :get
+ Net::HTTP::Get.new(path)
+ else
+ raise "unkown returning_body verb #{verb}"
+ end
+ headers.each_pair { |key, value| req[key] = value } if headers
+ if (@user)
+ req.basic_auth @user, @pass
+ end
+ res = nil
+ @http.request(req) {|response|
+ response.read_body nil, &block
+ res = response
+ }
+ res.value # raises error if not success
+ res.body
+ end
+
+ def request(verb, path, body, headers)
+ req =
+ case verb
+ when :propfind
+ Net::HTTP::Propfind.new(path)
+ when :mkcol
+ Net::HTTP::Mkcol.new(path)
+ else
+ raise "unkown verb #{verb}"
+ end
+ req.body = body
+ headers.each_pair { |key, value| req[key] = value } if headers
+ req.content_type = 'text/xml; charset="utf-8"'
+ if (@user)
+ req.basic_auth @user, @pass
+ end
+ res = @http.request(req)
+ res.value # raises error if not success
+ res
+ end
+ end
+
+ class CurlHandler < NetHttpHandler
+ def request_returning_body(verb, path, headers)
+ raise "unkown returning_body verb #{verb}" unless verb == :get
+ url = @uri.merge(path)
+ curl = Curl::Easy.new(url.to_s)
+ headers.each_pair { |key, value| curl.headers[key] = value } if headers
+ if (@user)
+ curl.headers["Authorization"] = "Basic #{Base64.encode64("#{@user}:#{@pass}")}"
+ end
+ res = nil
+ if block_given?
+ curl.on_body do |frag|
+ yield frag
+ frag.length
+ end
+ end
+ curl.perform
+ curl.body_str
+ end
+
+ end
+
# 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.
#
def read_timeout
- @http.read_timeout
+ @handler.read_timeout
end
def read_timeout=(sec)
- @http.read_timeout = sec
+ @handler.read_timeout = sec
end
# Seconds to wait until connection is opened.
# If the DAV object cannot open a connection in this many seconds,
# it raises a TimeoutError exception.
#
def open_timeout
- @http.read_timeout
+ @handler.read_timeout
end
def open_timeout=(sec)
- @http.read_timeout = sec
+ @handler.read_timeout = sec
end
# Creates a new Net::DAV object and opens the connection
# to the host. Yields the object to the block.
#
@@ -38,28 +182,27 @@
# res = Net::DAV.start(url) do |dav|
# dav.find(url.path) do |item|
# puts "#{item.uri} is size #{item.size}"
# end
# end
- def self.start(uri, &block) # :yield: dav
- new(uri).start(&block)
+ def self.start(uri, options = nil, &block) # :yield: dav
+ new(uri, options).start(&block)
end
# 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.
- def initialize(uri)
+ # You can pass :curl => false if you want to disable use
+ # of the curb (libcurl) gem if present for acceleration
+ 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
- case @uri.scheme
- when "http"
- @http = Net::HTTP.new(@uri.host, @uri.port)
- when "https"
- @http = Net::HTTPS.new(@uri.host, @uri.port)
- else
- raise "unknown uri scheme"
- end
+ @handler = @have_curl ? CurlHandler.new(@uri) : NetHttpHandler.new(@uri)
end
# Opens the connection to the host. Yields self to the block.
#
# Example:
@@ -67,32 +210,26 @@
# res = Net::DAV.new(url).start do |dav|
# dav.find(url.path) do |item|
# puts item.inspect
# end
# end
- def start # :yield: dav
- @http.start do |http|
+ def start(&block) # :yield: dav
+ @handler.start do
return yield(self)
end
end
# Set credentials for basic authentication
def credentials(user, pass)
- @user = user
- @pass = pass
+ @handler.user = user
+ @handler.pass = pass
end
def propfind(path) #:nodoc:
- req = Net::HTTP::Propfind.new(path)
- req.body = '<?xml version="1.0" encoding="utf-8"?><DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
- req['Depth'] = '1'
- req.content_type = 'text/xml; charset="utf-8"'
- if (@user)
- req.basic_auth @user, @pass
- end
- res = @http.request(req)
- res.value # raises error if not success
+ headers = {'Depth' => '1'}
+ body = '<?xml version="1.0" encoding="utf-8"?><DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
+ res = @handler.request(:propfind, path, body, headers)
Nokogiri::XML.parse(res.body)
end
# Find files and directories, yields Net::DAV::Item
#
@@ -144,70 +281,38 @@
# 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.
def get(path, &block)
- req = Net::HTTP::Get.new(path)
- req.content_type = 'text/xml; charset="utf-8"'
- if (@user)
- req.basic_auth @user, @pass
- end
- res = nil
- @http.request(req) {|response|
- response.read_body nil, &block
- res = response
- }
- res.body
+ @handler.request_returning_body(:get, path, nil, &block)
+ true
end
# 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
def put(path, stream, length)
- req = Net::HTTP::Put.new(path)
- req.content_type = 'text/xml; charset="utf-8"'
- req.content_length = length
- req.body_stream = stream
- #req['transfer-encoding'] = 'chunked'
- if (@user)
- req.basic_auth @user, @pass
- end
- res = @http.request(req)
- res.value
+ res = @handler.request_sending_stream(:put, path, stream, length, nil)
res.body
end
# Stores the content of a string to a URL
#
# Example:
# dav.put(url.path, "hello world")
#
def put_string(path, str)
- req = Net::HTTP::Put.new(path)
- req.content_type = 'text/xml; charset="utf-8"'
- req.body = str
- #req['transfer-encoding'] = 'chunked'
- if (@user)
- req.basic_auth @user, @pass
- end
- res = @http.request(req)
- res.value
+ res = @handler.request_sending_body(:put, path, str, nil)
res.body
end
# Makes a new directory (collection)
def mkdir(path)
- req = Net::HTTP::Mkcol.new(path)
- req.content_type = 'text/xml; charset="utf-8"'
- if (@user)
- req.basic_auth @user, @pass
- end
- res = @http.request(req)
- res.value
+ res = @handler.request(:mkcol, path, nil, nil)
res.body
end
end
end