net_dav 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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