Ruby1.8.6でWebDavクライアント
RubyのWebDavクライアントを探してみるも、信頼できそうなものがない。Rubyのソースコードを見てみると標準添付のライブラリにWebdav対応コードが実装されている。下のコードで動作した。
Ruby1.9の機能として公式リファレンスに載っているメソッド(HTTPRequest#body_stream=)を使用したが、Ruby1.8.6でも正常に動作した。
ただしファイル名に日本語が含まれる場合は、文字コードに注意する必要がある。Apache Webdavにアップロードする場合は適切にサーバ側で文字コード変換をしてくれるようだが、ダウンロードする場合は、Windowsの場合はダウンロード先ファイル名をShift_JISで指定する必要がある。
require 'net/http' # # webdav-client # class WebdavClient # # webdav_url: host url (ex http://hostname:port/path/to/ ) # proxy_addr(option) : proxy_addr (ex proxy.host.com ) # proxy_port(option) : proxy_port (ex 3128) def initialize(webdav_url, proxy_addr = nil, proxy_port = nil) unless /([a-z]+):\/\/([a-zA-Z0-9\.]+)(:[0-9]+){0,1}(.*)/ =~ webdav_url raise ArgumentError.new("Invalid URL #{webdav_url}") end address = $2 port = $3 || 80 port.delete(':') if port.is_a?(String) basic_path = $4 || '/' basic_path = basic_path + '/' unless basic_path[basic_path.length - 1].chr() == '/' @basic_path = basic_path @http = Net::HTTP.new(address, port, proxy_addr, proxy_port) end # =put= # put file # # src_path: local file path # dest_path: remote-server destination path def put(src_path, dest_path = nil) dest_path = File.basename(src_path) if dest_path.nil?() req = Net::HTTP::Put.new(@basic_path + dest_path) req.content_length = File.size(src_path) File.open(src_path, 'rb'){ |io| req.body_stream = io res = @http.request(req) raise Exception.new("Invalid HttpResponse Code: #{res.code} #{res.message}") unless res.code == '201' } end # =mkdir= # make directory # # path: remote-server path def mkdir(path) req = Net::HTTP::Mkcol.new(@basic_path + path) res = @http.request(req) raise Exception.new("Invalid HttpResponse Code: #{res.code} #{res.message}") unless res.code == '201' end # =delete= # delete file, delete directory # # path: remote-server path def delete(path) req = Net::HTTP::Delete.new(@basic_path + path) res = @http.request(req) raise Exception.new("Invalid HttpResponse Code: #{res.code} #{res.message}") unless res.code == '204' end # =get= # get file # # src_path: remote-server path # dest_path: local file path def get(src_path, dest_path = nil) dest_path = File.basename(src_path) if dest_path.nil?() req = Net::HTTP::Get.new(@basic_path + src_path) res = @http.request(req) raise Exception.new("Invalid HttpResponse Code: #{res.code} #{res.message}") unless res.code == '200' File.open(dest_path, "wb"){|io| io.write(res.body) } end # =copy= # copy file to file on webdav-server # # src_path: remote-server source file path # dest_path: remote-server destination file path def copy(src_path, dest_path) req = Net::HTTP::Copy.new(@basic_path + src_path) req['Destination'] = @basic_path + dest_path res = @http.request(req) raise Exception.new("Invalid HttpResponse Code: #{res.code} #{res.message}") unless res.code == '204' end # =move= # rename file # # src_path: remote-server source file path # dest_path: remote-server destination file path def move(src_path, dest_path) req = Net::HTTP::Move.new(@basic_path + src_path) req['Destination'] = @basic_path + dest_path res = @http.request(req) raise Exception.new("Invalid HttpResponse Code: #{res.code} #{res.message}") unless res.code == '204' end end
使い方
#http://hostname:80/webdav/で初期化 w = WebdavClient.new('http://hostname:80/webdav/') w.put('test.txt') #test.txtをアップロード w.get('test.txt') #test.txtをダウンロード w.mkdir('test') #testディレクトリ作成 w.copy('test.txt', 'test2.txt') #Webdavサーバ上でtest.txtをtest2.txtにコピー w.move('test2.txt', 'test3.txt') #Webdavサーバ上でtest2.txtをtest3.txtにリネーム w.delete('test') #testディレクトリ削除 w.delete('test.txt') #test.txtファイル削除 require 'kconv' w.put('test.txt', 'テスト.txt') #test.txtをテスト.txtとしてアップロード w.get('テスト.txt', 'テスト.txt'.tosjis()) #テスト.txtをテスト.txt(Shift_JIS)としてダウンロード