net_dav 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -9,9 +9,11 @@ begin
9
9
  gem.description = %Q{WebDAV client library in the style of Net::HTTP, using Net::HTTP and libcurl, if installed}
10
10
  gem.email = "c1.github@niftybox.net"
11
11
  gem.homepage = "http://github.com/devrandom/net_dav"
12
- gem.authors = ["Miron Cuperman"]
12
+ gem.authors = ["Miron Cuperman","Thomas Flemming"]
13
+ gem.executables = ["dav"]
13
14
  gem.add_dependency "nokogiri", ">= 1.3.0"
14
15
  gem.add_development_dependency "rspec", ">= 1.2.0"
16
+ gem.add_development_dependency "webrick-webdav", ">= 1.0"
15
17
 
16
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
19
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.4.0
data/bin/dav CHANGED
@@ -21,6 +21,7 @@ def print_usage
21
21
  puts " put Put file from FILE to URL"
22
22
  puts " mkdir Create directory at URL"
23
23
  puts " gsub Replace content at URL from REGEXP to VALUE"
24
+ puts " props Display xml properties for file or directory at URL"
24
25
  exit
25
26
  end
26
27
 
@@ -62,13 +63,13 @@ res = dav.start { |dav|
62
63
  when 'get'
63
64
  if file.nil?
64
65
  dav.get(url.path) do |str|
65
- $stdout.print str
66
+ $stdout.print str
66
67
  end
67
68
  else
68
69
  File.open(file, "w") do |stream|
69
- dav.get(url.path) do |str|
70
- stream.print str
71
- end
70
+ dav.get(url.path) do |str|
71
+ stream.print str
72
+ end
72
73
  end
73
74
  end
74
75
  when 'lsr'
@@ -86,9 +87,11 @@ res = dav.start { |dav|
86
87
  val = $*[3]
87
88
  dav.find(url.path) do |item|
88
89
  if (item.type == :file)
89
- item.content = item.content.gsub(re, val)
90
+ item.content = item.content.gsub(re, val)
90
91
  end
91
92
  end
93
+ when 'props'
94
+ puts dav.propfind(url.path).to_s
92
95
  else
93
96
  print_usage
94
97
  end
data/lib/net/dav/item.rb CHANGED
@@ -13,34 +13,44 @@ module Net
13
13
 
14
14
  # Synonym for uri
15
15
  def url
16
- @uri
16
+ @uri
17
17
  end
18
18
 
19
19
  def initialize(dav, uri, type, size) #:nodoc:
20
- @uri = uri
21
- @size = size.to_i rescue nil
22
- @type = type
23
- @dav = dav
20
+ @uri = uri
21
+ @size = size.to_i rescue nil
22
+ @type = type
23
+ @dav = dav
24
24
  end
25
25
 
26
26
  # Get content from server if needed and return as string
27
27
  def content
28
- return @content unless @content.nil?
29
- @content = @dav.get(@uri.path)
28
+ return @content unless @content.nil?
29
+ @content = @dav.get(@uri.path)
30
30
  end
31
31
 
32
32
  # Put content to server
33
33
  def content=(str)
34
- @dav.put_string(@uri.path, str)
35
- @content = str
34
+ @dav.put_string(@uri.path, str)
35
+ @content = str
36
+ end
37
+
38
+ # Proppatch item
39
+ def proppatch(xml_snippet)
40
+ @dav.proppatch(@uri.path,xml_snippet)
41
+ end
42
+
43
+ #Properties for this item
44
+ def propfind
45
+ return @dav.propfind(@uri.path)
36
46
  end
37
47
 
38
48
  def to_s #:nodoc:
39
- "#<Net::DAV::Item URL:#{@uri.to_s} type:#{@type}>"
49
+ "#<Net::DAV::Item URL:#{@uri.to_s} type:#{@type}>"
40
50
  end
41
51
 
42
52
  def inspect #:nodoc:
43
- "#<Net::DAV::Item URL:#{@uri.to_s} type:#{@type}>"
53
+ "#<Net::DAV::Item URL:#{@uri.to_s} type:#{@type}>"
44
54
  end
45
55
  end
46
56
  end
data/lib/net/dav.rb CHANGED
@@ -19,252 +19,261 @@ module Net #:nodoc:
19
19
  attr_accessor :disable_basic_auth
20
20
 
21
21
  def verify_callback=(callback)
22
- @http.verify_callback = callback
22
+ @http.verify_callback = callback
23
23
  end
24
24
 
25
25
  def verify_server=(value)
26
- @http.verify_mode = value ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
26
+ @http.verify_mode = value ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
27
27
  end
28
28
 
29
29
  def initialize(uri)
30
- @disable_basic_auth = false
31
- @uri = uri
32
- case @uri.scheme
33
- when "http"
34
- @http = Net::HTTP.new(@uri.host, @uri.port)
35
- when "https"
36
- @http = Net::HTTP.new(@uri.host, @uri.port)
37
- @http.use_ssl = true
38
- self.verify_server = true
39
- else
40
- raise "unknown uri scheme"
41
- end
30
+ @disable_basic_auth = false
31
+ @uri = uri
32
+ case @uri.scheme
33
+ when "http"
34
+ @http = Net::HTTP.new(@uri.host, @uri.port)
35
+ when "https"
36
+ @http = Net::HTTP.new(@uri.host, @uri.port)
37
+ @http.use_ssl = true
38
+ self.verify_server = true
39
+ else
40
+ raise "unknown uri scheme"
41
+ end
42
42
  end
43
43
 
44
44
  def start(&block)
45
- @http.start(&block)
45
+ @http.start(&block)
46
46
  end
47
47
 
48
48
  def read_timeout
49
- @http.read_timeout
49
+ @http.read_timeout
50
50
  end
51
51
 
52
52
  def read_timeout=(sec)
53
- @http.read_timeout = sec
53
+ @http.read_timeout = sec
54
54
  end
55
55
 
56
56
  def open_timeout
57
- @http.read_timeout
57
+ @http.read_timeout
58
58
  end
59
59
 
60
60
  def open_timeout=(sec)
61
- @http.read_timeout = sec
61
+ @http.read_timeout = sec
62
62
  end
63
63
 
64
64
  def request_sending_stream(verb, path, stream, length, headers)
65
- req =
66
- case verb
67
- when :put
68
- Net::HTTP::Put.new(path)
69
- else
70
- raise "unkown sending_stream verb #{verb}"
71
- end
72
- req.body_stream = stream
73
- req.content_length = length
74
- headers.each_pair { |key, value| req[key] = value } if headers
75
- req.content_type = 'text/xml; charset="utf-8"'
76
- res = handle_request(req, headers)
77
- res
65
+ req =
66
+ case verb
67
+ when :put
68
+ Net::HTTP::Put.new(path)
69
+ else
70
+ raise "unkown sending_stream verb #{verb}"
71
+ end
72
+ req.body_stream = stream
73
+ req.content_length = length
74
+ headers.each_pair { |key, value| req[key] = value } if headers
75
+ req.content_type = 'text/xml; charset="utf-8"'
76
+ res = handle_request(req, headers)
77
+ res
78
78
  end
79
79
 
80
80
  def request_sending_body(verb, path, body, headers)
81
- req =
82
- case verb
83
- when :put
84
- Net::HTTP::Put.new(path)
85
- else
86
- raise "unkown sending_body verb #{verb}"
87
- end
88
- req.body = body
89
- headers.each_pair { |key, value| req[key] = value } if headers
90
- req.content_type = 'text/xml; charset="utf-8"'
91
- res = handle_request(req, headers)
92
- res
81
+ req =
82
+ case verb
83
+ when :put
84
+ Net::HTTP::Put.new(path)
85
+ else
86
+ raise "unkown sending_body verb #{verb}"
87
+ end
88
+ req.body = body
89
+ headers.each_pair { |key, value| req[key] = value } if headers
90
+ req.content_type = 'text/xml; charset="utf-8"'
91
+ res = handle_request(req, headers)
92
+ res
93
93
  end
94
94
 
95
95
  def request_returning_body(verb, path, headers, &block)
96
- req =
97
- case verb
98
- when :get
99
- Net::HTTP::Get.new(path)
100
- else
101
- raise "unkown returning_body verb #{verb}"
102
- end
103
- headers.each_pair { |key, value| req[key] = value } if headers
104
- res = handle_request(req, headers, MAX_REDIRECTS, &block)
105
- res.body
96
+ req =
97
+ case verb
98
+ when :get
99
+ Net::HTTP::Get.new(path)
100
+ else
101
+ raise "unkown returning_body verb #{verb}"
102
+ end
103
+ headers.each_pair { |key, value| req[key] = value } if headers
104
+ res = handle_request(req, headers, MAX_REDIRECTS, &block)
105
+ res.body
106
106
  end
107
107
 
108
108
  def request(verb, path, body, headers)
109
- req =
110
- case verb
111
- when :propfind
112
- Net::HTTP::Propfind.new(path)
113
- when :mkcol
114
- Net::HTTP::Mkcol.new(path)
115
- else
116
- raise "unkown verb #{verb}"
117
- end
118
- req.body = body
119
- headers.each_pair { |key, value| req[key] = value } if headers
120
- req.content_type = 'text/xml; charset="utf-8"'
121
- res = handle_request(req, headers)
122
- res
109
+ req =
110
+ case verb
111
+ when :propfind
112
+ Net::HTTP::Propfind.new(path)
113
+ when :mkcol
114
+ Net::HTTP::Mkcol.new(path)
115
+ when :delete
116
+ Net::HTTP::Delete.new(path)
117
+ when :move
118
+ Net::HTTP::Move.new(path)
119
+ when :copy
120
+ Net::HTTP::Copy.new(path)
121
+ when :proppatch
122
+ Net::HTTP::Proppatch.new(path)
123
+ else
124
+ raise "unkown verb #{verb}"
125
+ end
126
+ req.body = body
127
+ headers.each_pair { |key, value| req[key] = value } if headers
128
+ req.content_type = 'text/xml; charset="utf-8"'
129
+ res = handle_request(req, headers)
130
+ res
123
131
  end
124
132
 
125
133
  def handle_request(req, headers, limit = MAX_REDIRECTS, &block)
126
- # You should choose better exception.
127
- raise ArgumentError, 'HTTP redirect too deep' if limit == 0
128
-
129
- response = nil
130
- if block
131
- @http.request(req) {|res|
132
- # Only start returning a body if we will not retry
133
- res.read_body nil, &block if !res.is_a?(Net::HTTPUnauthorized) && !res.is_a?(Net::HTTPRedirection)
134
- response = res
135
- }
136
- else
137
- response = @http.request(req)
138
- end
139
- case response
140
- when Net::HTTPSuccess then
141
- return response
142
- when Net::HTTPUnauthorized then
143
- response.error! unless @user
144
- response.error! if req['authorization']
145
- new_req = clone_req(req.path, req, headers)
146
- if response['www-authenticate'] =~ /^Basic/
147
- if disable_basic_auth
148
- raise "server requested basic auth, but that is disabled"
149
- end
150
- new_req.basic_auth @user, @pass
151
- else
152
- digest_auth(new_req, @user, @pass, response)
153
- end
154
- return handle_request(new_req, headers, limit - 1, &block)
155
- when Net::HTTPRedirection then
156
- location = URI.parse(response['location'])
157
- if (@uri.scheme != location.scheme ||
158
- @uri.host != location.host ||
159
- @uri.port != location.port)
160
- raise ArgumentError, "cannot redirect to a different host #{@uri} => #{location}"
161
- end
162
- new_req = clone_req(location.path, req, headers)
163
- return handle_request(new_req, headers, limit - 1, &block)
164
- else
165
- response.error!
166
- end
134
+ # You should choose better exception.
135
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
136
+
137
+ response = nil
138
+ if block
139
+ @http.request(req) {|res|
140
+ # Only start returning a body if we will not retry
141
+ res.read_body nil, &block if !res.is_a?(Net::HTTPUnauthorized) && !res.is_a?(Net::HTTPRedirection)
142
+ response = res
143
+ }
144
+ else
145
+ response = @http.request(req)
146
+ end
147
+ case response
148
+ when Net::HTTPSuccess then
149
+ return response
150
+ when Net::HTTPUnauthorized then
151
+ response.error! unless @user
152
+ response.error! if req['authorization']
153
+ new_req = clone_req(req.path, req, headers)
154
+ if response['www-authenticate'] =~ /^Basic/
155
+ if disable_basic_auth
156
+ raise "server requested basic auth, but that is disabled"
157
+ end
158
+ new_req.basic_auth @user, @pass
159
+ else
160
+ digest_auth(new_req, @user, @pass, response)
161
+ end
162
+ return handle_request(new_req, headers, limit - 1, &block)
163
+ when Net::HTTPRedirection then
164
+ location = URI.parse(response['location'])
165
+ if (@uri.scheme != location.scheme ||
166
+ @uri.host != location.host ||
167
+ @uri.port != location.port)
168
+ raise ArgumentError, "cannot redirect to a different host #{@uri} => #{location}"
169
+ end
170
+ new_req = clone_req(location.path, req, headers)
171
+ return handle_request(new_req, headers, limit - 1, &block)
172
+ else
173
+ response.error!
174
+ end
167
175
  end
176
+
168
177
  def clone_req(path, req, headers)
169
- new_req = req.class.new(path)
170
- new_req.body = req.body if req.body
171
- new_req.body_stream = req.body_stream if req.body_stream
172
- headers.each_pair { |key, value| new_req[key] = value } if headers
173
- return new_req
178
+ new_req = req.class.new(path)
179
+ new_req.body = req.body if req.body
180
+ new_req.body_stream = req.body_stream if req.body_stream
181
+ headers.each_pair { |key, value| new_req[key] = value } if headers
182
+ return new_req
174
183
  end
175
184
 
176
185
  CNONCE = Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535))).slice(0, 8)
177
186
 
178
187
  def digest_auth(request, user, password, response)
179
- # based on http://segment7.net/projects/ruby/snippets/digest_auth.rb
180
- @nonce_count = 0 if @nonce_count.nil?
181
- @nonce_count += 1
182
-
183
- raise "bad www-authenticate header" unless (response['www-authenticate'] =~ /^(\w+) (.*)/)
184
-
185
- params = {}
186
- $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
187
-
188
- a_1 = "#{user}:#{params['realm']}:#{password}"
189
- a_2 = "#{request.method}:#{request.path}"
190
- request_digest = ''
191
- request_digest << Digest::MD5.hexdigest(a_1)
192
- request_digest << ':' << params['nonce']
193
- request_digest << ':' << ('%08x' % @nonce_count)
194
- request_digest << ':' << CNONCE
195
- request_digest << ':' << params['qop']
196
- request_digest << ':' << Digest::MD5.hexdigest(a_2)
197
-
198
- header = []
199
- header << "Digest username=\"#{user}\""
200
- header << "realm=\"#{params['realm']}\""
201
- header << "nonce=\"#{params['nonce']}\""
202
- header << "uri=\"#{request.path}\""
203
- header << "cnonce=\"#{CNONCE}\""
204
- header << "nc=#{'%08x' % @nonce_count}"
205
- header << "qop=#{params['qop']}"
206
- header << "response=\"#{Digest::MD5.hexdigest(request_digest)}\""
207
- header << "algorithm=\"MD5\""
208
-
209
- header = header.join(', ')
210
- request['Authorization'] = header
188
+ # based on http://segment7.net/projects/ruby/snippets/digest_auth.rb
189
+ @nonce_count = 0 if @nonce_count.nil?
190
+ @nonce_count += 1
191
+
192
+ raise "bad www-authenticate header" unless (response['www-authenticate'] =~ /^(\w+) (.*)/)
193
+
194
+ params = {}
195
+ $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
196
+
197
+ a_1 = "#{user}:#{params['realm']}:#{password}"
198
+ a_2 = "#{request.method}:#{request.path}"
199
+ request_digest = ''
200
+ request_digest << Digest::MD5.hexdigest(a_1)
201
+ request_digest << ':' << params['nonce']
202
+ request_digest << ':' << ('%08x' % @nonce_count)
203
+ request_digest << ':' << CNONCE
204
+ request_digest << ':' << params['qop']
205
+ request_digest << ':' << Digest::MD5.hexdigest(a_2)
206
+
207
+ header = []
208
+ header << "Digest username=\"#{user}\""
209
+ header << "realm=\"#{params['realm']}\""
210
+ header << "nonce=\"#{params['nonce']}\""
211
+ header << "uri=\"#{request.path}\""
212
+ header << "cnonce=\"#{CNONCE}\""
213
+ header << "nc=#{'%08x' % @nonce_count}"
214
+ header << "qop=#{params['qop']}"
215
+ header << "response=\"#{Digest::MD5.hexdigest(request_digest)}\""
216
+ header << "algorithm=\"MD5\""
217
+
218
+ header = header.join(', ')
219
+ request['Authorization'] = header
211
220
  end
212
221
  end
213
222
 
214
223
 
215
224
  class CurlHandler < NetHttpHandler
216
225
  def verify_callback=(callback)
217
- super
218
- curl = make_curl
219
- $stderr.puts "verify_callback not implemented in Curl::Easy"
226
+ super
227
+ curl = make_curl
228
+ $stderr.puts "verify_callback not implemented in Curl::Easy"
220
229
  end
221
230
 
222
231
  def verify_server=(value)
223
- super
224
- curl = make_curl
225
- curl.ssl_verify_peer = value
226
- curl.ssl_verify_host = value
232
+ super
233
+ curl = make_curl
234
+ curl.ssl_verify_peer = value
235
+ curl.ssl_verify_host = value
227
236
  end
228
237
 
229
238
  def make_curl
230
- unless @curl
231
- @curl = Curl::Easy.new
232
- @curl.timeout = @http.read_timeout
233
- @curl.follow_location = true
234
- @curl.max_redirects = MAX_REDIRECTS
235
- if disable_basic_auth
236
- @curl.http_auth_types = Curl::CURLAUTH_DIGEST
237
- end
238
- end
239
- @curl
239
+ unless @curl
240
+ @curl = Curl::Easy.new
241
+ @curl.timeout = @http.read_timeout
242
+ @curl.follow_location = true
243
+ @curl.max_redirects = MAX_REDIRECTS
244
+ if disable_basic_auth
245
+ @curl.http_auth_types = Curl::CURLAUTH_DIGEST
246
+ end
247
+ end
248
+ @curl
240
249
  end
241
250
 
242
251
  def request_returning_body(verb, path, headers)
243
- raise "unkown returning_body verb #{verb}" unless verb == :get
244
- url = @uri.merge(path)
245
- curl = make_curl
246
- curl.url = url.to_s
247
- headers.each_pair { |key, value| curl.headers[key] = value } if headers
248
- if (@user)
249
- curl.userpwd = "#{@user}:#{@pass}"
250
- else
251
- curl.userpwd = nil
252
- end
253
- res = nil
254
- if block_given?
255
- curl.on_body do |frag|
256
- yield frag
257
- frag.length
258
- end
259
- end
260
- curl.perform
261
- unless curl.response_code >= 200 && curl.response_code < 300
262
- header_block = curl.header_str.split(/\r?\n\r?\n/)[-1]
263
- msg = header_block.split(/\r?\n/)[0]
264
- msg.gsub!(/^HTTP\/\d+.\d+ /, '')
265
- raise Net::HTTPError.new(msg, nil)
266
- end
267
- curl.body_str
252
+ raise "unkown returning_body verb #{verb}" unless verb == :get
253
+ url = @uri.merge(path)
254
+ curl = make_curl
255
+ curl.url = url.to_s
256
+ headers.each_pair { |key, value| curl.headers[key] = value } if headers
257
+ if (@user)
258
+ curl.userpwd = "#{@user}:#{@pass}"
259
+ else
260
+ curl.userpwd = nil
261
+ end
262
+ res = nil
263
+ if block_given?
264
+ curl.on_body do |frag|
265
+ yield frag
266
+ frag.length
267
+ end
268
+ end
269
+ curl.perform
270
+ unless curl.response_code >= 200 && curl.response_code < 300
271
+ header_block = curl.header_str.split(/\r?\n\r?\n/)[-1]
272
+ msg = header_block.split(/\r?\n/)[0]
273
+ msg.gsub!(/^HTTP\/\d+.\d+ /, '')
274
+ raise Net::HTTPError.new(msg, nil)
275
+ end
276
+ curl.body_str
268
277
  end
269
278
 
270
279
  end
@@ -325,7 +334,7 @@ module Net #:nodoc:
325
334
  def initialize(uri, options = nil)
326
335
  @have_curl = Curl rescue nil
327
336
  if options && options.has_key?(:curl) && !options[:curl]
328
- @have_curl = false
337
+ @have_curl = false
329
338
  end
330
339
  @uri = uri
331
340
  @uri = URI.parse(@uri) if @uri.is_a? String
@@ -343,7 +352,7 @@ module Net #:nodoc:
343
352
  # end
344
353
  def start(&block) # :yield: dav
345
354
  @handler.start do
346
- return yield(self)
355
+ return yield(self)
347
356
  end
348
357
  end
349
358
 
@@ -362,6 +371,16 @@ module Net #:nodoc:
362
371
 
363
372
  # Find files and directories, yields Net::DAV::Item
364
373
  #
374
+ # The :filename option can be a regexp or string, and is used
375
+ # to filter the yielded items.
376
+ #
377
+ # If :suppress_errors is passed, exceptions that occurs when
378
+ # reading directory information is ignored, and a warning is
379
+ # printed out stderr instead.
380
+ #
381
+ # The default is to not traverse recursively, unless the :recursive
382
+ # options is passed.
383
+ #
365
384
  # Examples:
366
385
  #
367
386
  # res = Net::DAV.start(url) do |dav|
@@ -370,29 +389,63 @@ module Net #:nodoc:
370
389
  # puts item.content
371
390
  # end
372
391
  # end
392
+ #
393
+ # dav = Net::DAV.new(url)
394
+ # dav.find(url.path, :filename => /\.html/, :suppress_errors => true)
395
+ # puts item.url.to_s
396
+ # end
373
397
  def find(path, options = {})
374
398
  path = @uri.merge(path).path
375
399
  namespaces = {'x' => "DAV:"}
376
- doc = propfind(path)
400
+ begin
401
+ doc = propfind(path)
402
+ rescue Net::HTTPServerException => e
403
+ msg = e.to_s + ": " + path.to_s
404
+ if(options[:suppress_errors])then
405
+ # Ignore dir if propfind returns an error
406
+ warn("Warning: " + msg)
407
+ return nil
408
+ else
409
+ raise Net::HTTPServerException.new(msg, nil)
410
+ end
411
+ end
377
412
  path.sub!(/\/$/, '')
378
413
  doc./('.//x:response', namespaces).each do |item|
379
- uri = @uri.merge(item.xpath("x:href", namespaces).inner_text)
380
- size = item.%(".//x:getcontentlength", namespaces).inner_text rescue nil
381
- type = item.%(".//x:collection", namespaces) ? :directory : :file
382
- res = Item.new(self, uri, type, size)
383
- if type == :file
384
- yield res
385
- elsif uri.path == path || uri.path == path + "/"
386
- # This is the top-level dir, skip it
387
- elsif options[:recursive] && type == :directory
388
- yield res
389
- # This is a subdir, recurse
390
- find(uri.path, options) do |sub_res|
391
- yield sub_res
392
- end
393
- else
394
- yield res
395
- end
414
+ uri = @uri.merge(item.xpath("x:href", namespaces).inner_text)
415
+ size = item.%(".//x:getcontentlength", namespaces).inner_text rescue nil
416
+ type = item.%(".//x:collection", namespaces) ? :directory : :file
417
+ res = Item.new(self, uri, type, size)
418
+ if type == :file then
419
+
420
+ if(options[:filename])then
421
+ search_term = options[:filename]
422
+ filename = File.basename(uri.path)
423
+ if(search_term.class == Regexp and search_term.match(filename))then
424
+ yield res
425
+ elsif(search_term.class == String and search_term == filename)then
426
+ yield res
427
+ end
428
+ else
429
+ yield res
430
+ end
431
+
432
+ elsif uri.path == path || uri.path == path + "/"
433
+ # This is the top-level dir, skip it
434
+ elsif options[:recursive] && type == :directory
435
+
436
+ if(!options[:filename])then
437
+ yield res
438
+ end
439
+
440
+ # This is a subdir, recurse
441
+ find(uri.path, options) do |sub_res|
442
+ yield sub_res
443
+ end
444
+ else
445
+ if(!options[:filename])then
446
+ yield res
447
+ end
448
+ end
396
449
  end
397
450
  end
398
451
 
@@ -400,7 +453,7 @@ module Net #:nodoc:
400
453
  def cd(url)
401
454
  new_uri = @uri.merge(url)
402
455
  if new_uri.host != @uri.host || new_uri.port != @uri.port || new_uri.scheme != @uri.scheme
403
- raise Exception , "uri must have same scheme, host and port"
456
+ raise Exception , "uri must have same scheme, host and port"
404
457
  end
405
458
  @uri = new_uri
406
459
  end
@@ -441,6 +494,58 @@ module Net #:nodoc:
441
494
  res.body
442
495
  end
443
496
 
497
+ # Delete request
498
+ #
499
+ # Example:
500
+ # dav.delete(uri.path)
501
+ def delete(path)
502
+ path = @uri.merge(path).path
503
+ res = @handler.request(:delete, path, nil, nil)
504
+ res.body
505
+ end
506
+
507
+ # Send a move request to the server.
508
+ #
509
+ # Example:
510
+ # dav.move(original_path, new_path)
511
+ def move(path,destination)
512
+ path = @uri.merge(path).path
513
+ destination = @uri.merge(destination).to_s
514
+ headers = {'Destination' => destination}
515
+ res = @handler.request(:move, path, nil, headers)
516
+ res.body
517
+ end
518
+
519
+ # Send a copy request to the server.
520
+ #
521
+ # Example:
522
+ # dav.copy(original_path, destination)
523
+ def copy(path,destination)
524
+ path = @uri.merge(path).path
525
+ destination = @uri.merge(destination).to_s
526
+ headers = {'Destination' => destination}
527
+ res = @handler.request(:copy, path, nil, headers)
528
+ res.body
529
+ end
530
+
531
+ # Do a proppatch request to the server to
532
+ # update properties on resources or collections.
533
+ #
534
+ # Example:
535
+ # dav.proppatch(uri.path,"<d:creationdate>#{new_date}</d:creationdate>")
536
+ def proppatch(path, xml_snippet)
537
+ headers = {'Depth' => '1'}
538
+ body = '<?xml version="1.0"?>' +
539
+ '<d:propertyupdate xmlns:d="DAV:">' +
540
+ '<d:set>' +
541
+ '<d:prop>' +
542
+ xml_snippet +
543
+ '</d:prop>' +
544
+ '</d:set>' +
545
+ '</d:propertyupdate>'
546
+ res = @handler.request(:proppatch, path, body, headers)
547
+ Nokogiri::XML.parse(res.body)
548
+ end
444
549
 
445
550
  # Makes a new directory (collection)
446
551
  def mkdir(path)
data/net_dav.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{net_dav}
8
- s.version = "0.3.3"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Miron Cuperman"]
12
- s.date = %q{2009-11-19}
11
+ s.authors = ["Miron Cuperman", "Thomas Flemming"]
12
+ s.date = %q{2009-12-10}
13
13
  s.default_executable = %q{dav}
14
14
  s.description = %q{WebDAV client library in the style of Net::HTTP, using Net::HTTP and libcurl, if installed}
15
15
  s.email = %q{c1.github@niftybox.net}
@@ -30,7 +30,9 @@ Gem::Specification.new do |s|
30
30
  "lib/net/dav/item.rb",
31
31
  "net_dav.gemspec",
32
32
  "script/multi-test",
33
- "spec/net_dav_spec.rb",
33
+ "spec/fixtures/file.html",
34
+ "spec/integration/net_dav_spec.rb",
35
+ "spec/integration/webdav_server.rb",
34
36
  "spec/spec.opts",
35
37
  "spec/spec_helper.rb",
36
38
  "tmp/.gitignore"
@@ -41,8 +43,9 @@ Gem::Specification.new do |s|
41
43
  s.rubygems_version = %q{1.3.5}
42
44
  s.summary = %q{WebDAV client library in the style of Net::HTTP}
43
45
  s.test_files = [
44
- "spec/net_dav_spec.rb",
45
- "spec/spec_helper.rb"
46
+ "spec/spec_helper.rb",
47
+ "spec/integration/webdav_server.rb",
48
+ "spec/integration/net_dav_spec.rb"
46
49
  ]
47
50
 
48
51
  if s.respond_to? :specification_version then
@@ -52,13 +55,16 @@ Gem::Specification.new do |s|
52
55
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
56
  s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.0"])
54
57
  s.add_development_dependency(%q<rspec>, [">= 1.2.0"])
58
+ s.add_development_dependency(%q<webrick-webdav>, [">= 1.0"])
55
59
  else
56
60
  s.add_dependency(%q<nokogiri>, [">= 1.3.0"])
57
61
  s.add_dependency(%q<rspec>, [">= 1.2.0"])
62
+ s.add_dependency(%q<webrick-webdav>, [">= 1.0"])
58
63
  end
59
64
  else
60
65
  s.add_dependency(%q<nokogiri>, [">= 1.3.0"])
61
66
  s.add_dependency(%q<rspec>, [">= 1.2.0"])
67
+ s.add_dependency(%q<webrick-webdav>, [">= 1.0"])
62
68
  end
63
69
  end
64
70
 
@@ -0,0 +1 @@
1
+ Content
@@ -0,0 +1,96 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/webdav_server')
3
+
4
+ describe "Net::Dav" do
5
+
6
+ before(:all) do
7
+ # Start webdav server in subprocess
8
+ @pid = fork do
9
+ webdav_server(:port => 10080,:authentication => false)
10
+ end
11
+ # Wait for webdavserver to start
12
+ sleep(10)
13
+ end
14
+
15
+ it "should create a Net::Dav object" do
16
+ Net::DAV.new("http://localhost.localdomain/").should_not be_nil
17
+ end
18
+
19
+ it "should read properties from webdav server" do
20
+ dav = Net::DAV.new("http://localhost:10080/")
21
+ @props = dav.propfind("/").to_s
22
+ @props.should match(/200 OK/)
23
+ end
24
+
25
+ it "should write files to webdav server" do
26
+ dav = Net::DAV.new("http://localhost:10080/")
27
+ @props = find_props_or_error(dav, "/new_file.html")
28
+ @props.should match(/404.*Not found/i)
29
+
30
+ dav.put_string("/new_file.html","File contents")
31
+
32
+ @props = find_props_or_error(dav, "/new_file.html")
33
+ @props.should match(/200 OK/i)
34
+ end
35
+
36
+ it "should delete files from webdav server" do
37
+ dav = Net::DAV.new("http://localhost:10080/")
38
+
39
+ @props = find_props_or_error(dav, "/new_file.html")
40
+ @props.should match(/200 OK/i)
41
+
42
+ dav.delete("/new_file.html")
43
+ @props = find_props_or_error(dav, "/new_file.html")
44
+ @props.should match(/404.*Not found/i)
45
+ end
46
+
47
+ it "should copy files on webdav server" do
48
+ dav = Net::DAV.new("http://localhost:10080/")
49
+
50
+ @props = find_props_or_error(dav, "/file.html")
51
+ @props.should match(/200 OK/i)
52
+
53
+ dav.copy("/file.html","/copied_file.html")
54
+ @props = find_props_or_error(dav, "/copied_file.html")
55
+ @props.should match(/200 OK/i)
56
+
57
+ dav.delete("/copied_file.html")
58
+
59
+ @props = find_props_or_error(dav, "/copied_file.html")
60
+ @props.should match(/404.*Not found/i)
61
+ end
62
+
63
+ it "should move files on webdav server" do
64
+ dav = Net::DAV.new("http://localhost:10080/")
65
+
66
+ @props = find_props_or_error(dav, "/file.html")
67
+ @props.should match(/200 OK/i)
68
+
69
+ dav.move("/file.html","/moved_file.html")
70
+ @props = find_props_or_error(dav, "/moved_file.html")
71
+ @props.should match(/200 OK/i)
72
+
73
+ @props = find_props_or_error(dav, "/file.html")
74
+ @props.should match(/404.*Not found/i)
75
+
76
+ dav.move("/moved_file.html","/file.html")
77
+ @props = find_props_or_error(dav, "/file.html")
78
+ @props.should match(/200 OK/i)
79
+ end
80
+
81
+ # proppatch seems to work, but our simple webdav server don't update properties
82
+ # it "should alter properties on resources on webdav server" do
83
+ # dav = Net::DAV.new("http://localhost:10080/")
84
+ # @props = find_props_or_error(dav, "/file.html")
85
+ # puts @props
86
+ # dav.proppatch("/file.html", "<d:resourcetype>static-file</d:resourcetype>")
87
+ # @props = find_props_or_error(dav, "/file.html")
88
+ # puts @props
89
+ # end
90
+
91
+ after(:all) do
92
+ # Shut down webdav server
93
+ Process.kill('SIGKILL', @pid) rescue nil
94
+ end
95
+
96
+ end
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'rubygems'
4
+ require 'webrick'
5
+ require 'webrick/httpservlet/webdavhandler'
6
+
7
+ # Web server with WebDAV extensions
8
+ #
9
+ # Usage: ruby webdav_server.rb
10
+
11
+ # Code based on:
12
+ # http://github.com/aslakhellesoy/webdavjs/blob/master/spec/webdav_server.rb
13
+
14
+
15
+ # Monkey patch REXML to always nil-indent. The indentation is broken in REXML
16
+ # on Ruby 1.8.6 and even when fixed it confuses OS-X.
17
+ module REXML
18
+ module Node
19
+ alias old_to_s to_s
20
+ def to_s(indent=nil)
21
+ old_to_s(nil)
22
+ end
23
+ end
24
+ end
25
+
26
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/223386
27
+ # http://gmarrone.objectblues.net/cgi-bin/wiki/WebDAV_-_Linux_server%2c_Mac_OS_X_client
28
+ module WEBrick
29
+ module HTTPServlet
30
+ class WebDAVHandlerVersion2 < WebDAVHandler
31
+
32
+ def do_OPTIONS(req, res)
33
+ super
34
+ res["DAV"] = "1,2"
35
+ end
36
+
37
+ def do_LOCK(req, res)
38
+ res.body << "<XXX-#{Time.now.to_s}/>"
39
+ end
40
+
41
+ end
42
+
43
+ class WebDAVHandlerVersion3 < WebDAVHandlerVersion2
44
+
45
+ # Enable authentication
46
+ $REALM = "WebDav share"
47
+ $USER = "myuser"
48
+ $PASS = "mypass"
49
+
50
+ def service(req, res)
51
+ HTTPAuth.basic_auth(req, res, $REALM) {|user, pass|
52
+ # this block returns true if
53
+ # authentication token is valid
54
+ user == $USER && pass == $PASS
55
+ }
56
+ super
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
63
+
64
+ def webdav_server(*options)
65
+ port = 10080
66
+ if(options and options[0][:port])
67
+ port = options[0][:port]
68
+ end
69
+ log = WEBrick::Log.new
70
+ log.level = WEBrick::Log::DEBUG if $DEBUG
71
+ serv = WEBrick::HTTPServer.new({:Port => port, :Logger => log})
72
+
73
+ dir = File.expand_path(File.dirname(__FILE__)) + '/../fixtures'
74
+ if(options and options[0][:authentication])
75
+ serv.mount("/", WEBrick::HTTPServlet::WebDAVHandlerVersion3, dir)
76
+ else
77
+ serv.mount("/", WEBrick::HTTPServlet::WebDAVHandlerVersion2, dir)
78
+ end
79
+
80
+ trap(:INT){ serv.shutdown }
81
+ serv.start
82
+ end
83
+
84
+ if($0 == __FILE__)
85
+
86
+ webdav_server(:port => 10080,:authentication => false)
87
+ end
data/spec/spec_helper.rb CHANGED
@@ -6,5 +6,14 @@ require 'spec'
6
6
  require 'spec/autorun'
7
7
 
8
8
  Spec::Runner.configure do |config|
9
-
9
+
10
+ end
11
+
12
+ # Profind helper. Returns properties or error
13
+ def find_props_or_error(dav, path)
14
+ begin
15
+ return dav.propfind(path).to_s
16
+ rescue Net::HTTPServerException => e
17
+ return e.to_s
18
+ end
10
19
  end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net_dav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miron Cuperman
8
+ - Thomas Flemming
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-11-19 00:00:00 -08:00
13
+ date: 2009-12-10 00:00:00 -08:00
13
14
  default_executable: dav
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
@@ -32,6 +33,16 @@ dependencies:
32
33
  - !ruby/object:Gem::Version
33
34
  version: 1.2.0
34
35
  version:
36
+ - !ruby/object:Gem::Dependency
37
+ name: webrick-webdav
38
+ type: :development
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "1.0"
45
+ version:
35
46
  description: WebDAV client library in the style of Net::HTTP, using Net::HTTP and libcurl, if installed
36
47
  email: c1.github@niftybox.net
37
48
  executables:
@@ -53,7 +64,9 @@ files:
53
64
  - lib/net/dav/item.rb
54
65
  - net_dav.gemspec
55
66
  - script/multi-test
56
- - spec/net_dav_spec.rb
67
+ - spec/fixtures/file.html
68
+ - spec/integration/net_dav_spec.rb
69
+ - spec/integration/webdav_server.rb
57
70
  - spec/spec.opts
58
71
  - spec/spec_helper.rb
59
72
  - tmp/.gitignore
@@ -86,5 +99,6 @@ signing_key:
86
99
  specification_version: 3
87
100
  summary: WebDAV client library in the style of Net::HTTP
88
101
  test_files:
89
- - spec/net_dav_spec.rb
90
102
  - spec/spec_helper.rb
103
+ - spec/integration/webdav_server.rb
104
+ - spec/integration/net_dav_spec.rb
data/spec/net_dav_spec.rb DELETED
@@ -1,7 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "Net::Dav" do
4
- it "should create a Net::Dav object" do
5
- Net::DAV.new("http://localhost.localdomain/").should_not be_nil
6
- end
7
- end