dav4rack 0.2.11 → 0.3.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/CHANGELOG.rdoc +109 -0
- data/README.rdoc +8 -0
- data/dav4rack.gemspec +1 -22
- data/lib/dav4rack.rb +5 -0
- data/lib/dav4rack/controller.rb +123 -59
- data/lib/dav4rack/file.rb +1 -1
- data/lib/dav4rack/file_resource_lock.rb +159 -0
- data/lib/dav4rack/handler.rb +1 -1
- data/lib/dav4rack/resource.rb +25 -9
- data/lib/dav4rack/resources/file_resource.rb +366 -0
- data/lib/dav4rack/resources/mongo_resource.rb +341 -0
- data/lib/dav4rack/utils.rb +40 -0
- data/lib/dav4rack/version.rb +1 -1
- metadata +40 -24
- data/.gitignore +0 -7
- data/lib/dav4rack/file_resource.rb +0 -257
- data/spec/handler_spec.rb +0 -301
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
=== v0.3.0
|
2
|
+
* New minor release towards full litmus pass
|
3
|
+
* Litmus passing: basic, copymove, props
|
4
|
+
* Litmus in progress: locks
|
5
|
+
* Internal reorganization of file structures
|
6
|
+
* Propfind updates to provide proper returns (thanks {schmurfy}[https://github.com/schmurfy])
|
7
|
+
* Properly detect malformed propfind requests
|
8
|
+
* Updated custom attribute storage
|
9
|
+
* Allow customized DAV headers (thanks {schmurfy}[https://github.com/schmurfy])
|
10
|
+
* Extract parent collection detection to resource (thanks {schmurfy}[https://github.com/schmurfy])
|
11
|
+
* Start of new locking implementation
|
12
|
+
* Fix rack #serving usage in DAV4Rack::File (thanks {pifleo}[https://github.com/pifleo])
|
13
|
+
* Force file namespacing in file resource to prevent conflicts with DAV4Rack::File (thanks {pifleo}[https://github.com/pifleo])
|
14
|
+
* Add ability to build xml from within a resource (thanks {mlmorg}[https://github.com/mlmorg])
|
15
|
+
|
16
|
+
=== v0.2.11
|
17
|
+
* URL escaping updates (thanks {exabugs}[https://github.com/exabugs])
|
18
|
+
* Return status updates to match RFC (thanks {exabugs}[https://github.com/exabugs])
|
19
|
+
* Add option to provide httpdate formatted creation date to MS clients (thanks {doxavore}[https://github.com/doxavore])
|
20
|
+
* New MongoDB resource (thanks {exabugs}[https://github.com/exabugs])
|
21
|
+
* Controller subclass support (thanks {inferiorhumanorgans}[https://github.com/inferiorhumanorgans])
|
22
|
+
* Root XML attributes (thanks {inferiorhumanorgans}[https://github.com/inferiorhumanorgans])
|
23
|
+
* Allow propstat to return relative paths (apple carddav hack) (thanks {inferiorhumanorgans}[https://github.com/inferiorhumanorgans])
|
24
|
+
|
25
|
+
=== v0.2.10
|
26
|
+
* Fix unicorn starting from exec script (thanks {spicyj}[https://github.com/spicyj])
|
27
|
+
* Return correct size using #bytesize instead of #size (thanks {TurchenkoAlex}[https://github.com/TurchenkoAlex])
|
28
|
+
|
29
|
+
=== v0.2.9
|
30
|
+
* Be less restrictive of Nokogiri dependency
|
31
|
+
|
32
|
+
=== v0.2.8
|
33
|
+
* Allow custom logger types to be used
|
34
|
+
* Allow resource to handle existence on locking (fixes issue {#21}[https://github.com/chrisroberts/dav4rack/issues/21] thanks {doxavore}[https://github.com/doxavore])
|
35
|
+
* Removed exception based control flow in favor of logic based control flow
|
36
|
+
|
37
|
+
=== v0.2.7
|
38
|
+
* Include location content within PUT response body (fixes issue described in {#20}[https://github.com/chrisroberts/dav4rack/issues/20])
|
39
|
+
|
40
|
+
=== v0.2.6
|
41
|
+
* Update response header from PUT to use Location
|
42
|
+
|
43
|
+
=== v0.2.5
|
44
|
+
* Return Created response in favor of current multi status response on PUT (thanks {buffym}[https://github.com/buffym])
|
45
|
+
* Show class 1 compliance to be in accordance with WebDAV spec (thanks {buffym}[https://github.com/buffym])
|
46
|
+
* Adds setup method to skip alias list for resources (thanks {jbangert}[https://github.com/jbangert])
|
47
|
+
* Allow existing logger instance to be provided
|
48
|
+
|
49
|
+
=== v0.2.4
|
50
|
+
* Return absolute URI from #mkcol and #put (thanks {teefax}[http://github.com/teefax])
|
51
|
+
* Nodes with text children properly serialized (pointed out by {jeffhos}[http://github.com/jeffhos])
|
52
|
+
* Fixed bug in file locking (pointed out by {clyfe}[http://github.com/clyfe] with fix provided by {teefax}[http://github.com/teefax])
|
53
|
+
|
54
|
+
=== v0.2.3
|
55
|
+
* Completing missed step in last packaging
|
56
|
+
|
57
|
+
=== v0.2.2
|
58
|
+
* Fix for port numbers in host (thanks {krug}[http://github.com/krug])
|
59
|
+
|
60
|
+
=== v0.2.1
|
61
|
+
* Fix for better handling of MOVEs with badly encoded URLS
|
62
|
+
|
63
|
+
=== v0.2.0
|
64
|
+
* Update to remote URL is passed to NGINX for proxying. Use headers instead of request
|
65
|
+
|
66
|
+
=== v0.1.8
|
67
|
+
* Better exception handling for error logging
|
68
|
+
* Send overwrite flag to Resource#move
|
69
|
+
|
70
|
+
=== v0.1.7
|
71
|
+
* Fix in interceptor to use correct File
|
72
|
+
|
73
|
+
=== v0.1.6
|
74
|
+
* Add DAV4Rack::File that overloads just enough of Rack::File to allow explicit path setting
|
75
|
+
|
76
|
+
=== v0.1.5
|
77
|
+
* Remove support for options[:delete_dotfiles]
|
78
|
+
* Allow HTTP methods to be ignored within interceptor
|
79
|
+
* Add owner information to lock response
|
80
|
+
* Initial update of spec to work with DAV4Rack
|
81
|
+
* Copy and delete recursively
|
82
|
+
* Add expected overwrite for copy/move on resource (thanks {clyfe}[http://github.com/clyfe])
|
83
|
+
* Add overwrite logic for copy/move on FileResource
|
84
|
+
* Removed callback authentication from FileResource (uses simple controller based auth)
|
85
|
+
|
86
|
+
=== v0.1.4
|
87
|
+
* Fix for Rack::File issue (thanks {clyfe}[http://github.com/clyfe])
|
88
|
+
* Logging now optional on executable
|
89
|
+
* Include propstats even if empty (this resolves an issue in cyberduck not displaying files)
|
90
|
+
|
91
|
+
=== v0.1.3
|
92
|
+
* Fix for Hash modification issues in Ruby 1.9.2 (thanks {antiloopgmbh}[http://github.com/antiloopgmbh])
|
93
|
+
* Fix executable to properly fallback
|
94
|
+
* Use callback authentication in FileResource to allow for no auth
|
95
|
+
|
96
|
+
=== v0.1.2
|
97
|
+
* Add sendfile support (currently only tested on nginx)
|
98
|
+
|
99
|
+
=== v0.1.1
|
100
|
+
* Add logging capability
|
101
|
+
* Simplify Interceptor mappings (provide options in hash instead of explicit :options)
|
102
|
+
|
103
|
+
=== v0.1.0
|
104
|
+
* Callbacks available for resources
|
105
|
+
* RemoteFile more aligned with Rack::File
|
106
|
+
* Return multistatus responses PUT MKCOL and COPY/MOVE
|
107
|
+
* Executable now uses Unicorn, Mongrel and WEBrick in that order
|
108
|
+
* Simple resource locking enabled by default
|
109
|
+
* Updated FileResource to work properly with new architecture
|
data/README.rdoc
CHANGED
@@ -286,6 +286,11 @@ Something special to notice in the last example is the DAV_ prefix on authentica
|
|
286
286
|
any callbacks being applied to the given method. This allows us to provide a public method that the callback can access on the resource
|
287
287
|
without getting stuck in a loop.
|
288
288
|
|
289
|
+
== Software using DAV4Rack!
|
290
|
+
|
291
|
+
* {meishi}[https://github.com/inferiorhumanorgans/meishi] - Lightweight CardDAV implementation in Rails
|
292
|
+
* {dav4rack_ext}[https://github.com/schmurfy/dav4rack_ext] - CardDAV extension. (CalDAV planned)
|
293
|
+
|
289
294
|
== Issues/Bugs/Questions
|
290
295
|
|
291
296
|
=== Known Issues
|
@@ -313,6 +318,9 @@ A big thanks to everyone contributing to help make this project better.
|
|
313
318
|
* {TurchenkoAlex}[https://github.com/TurchenkoAlex]
|
314
319
|
* {exabugs}[https://github.com/exabugs]
|
315
320
|
* {inferiorhumanorgans}[https://github.com/inferiorhumanorgans]
|
321
|
+
* {schmurfy}[https://github.com/schmurfy]
|
322
|
+
* {pifleo}[https://github.com/pifleo]
|
323
|
+
* {mlmorg}[https://github.com/mlmorg]
|
316
324
|
|
317
325
|
== License
|
318
326
|
|
data/dav4rack.gemspec
CHANGED
@@ -15,26 +15,5 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.add_dependency 'nokogiri', '>= 1.4.2'
|
16
16
|
s.add_dependency 'uuidtools', '~> 2.1.1'
|
17
17
|
s.add_dependency 'rack', '>= 1.1.0'
|
18
|
-
s.files = %w{
|
19
|
-
.gitignore
|
20
|
-
LICENSE
|
21
|
-
dav4rack.gemspec
|
22
|
-
lib/dav4rack.rb
|
23
|
-
lib/dav4rack/file_resource.rb
|
24
|
-
lib/dav4rack/handler.rb
|
25
|
-
lib/dav4rack/controller.rb
|
26
|
-
lib/dav4rack/http_status.rb
|
27
|
-
lib/dav4rack/resource.rb
|
28
|
-
lib/dav4rack/interceptor.rb
|
29
|
-
lib/dav4rack/interceptor_resource.rb
|
30
|
-
lib/dav4rack/remote_file.rb
|
31
|
-
lib/dav4rack/file.rb
|
32
|
-
lib/dav4rack/lock.rb
|
33
|
-
lib/dav4rack/lock_store.rb
|
34
|
-
lib/dav4rack/logger.rb
|
35
|
-
lib/dav4rack/version.rb
|
36
|
-
bin/dav4rack
|
37
|
-
spec/handler_spec.rb
|
38
|
-
README.rdoc
|
39
|
-
}
|
18
|
+
s.files = %w(dav4rack.gemspec README.rdoc CHANGELOG.rdoc LICENSE) + Dir.glob("{bin,lib}/**/*")
|
40
19
|
end
|
data/lib/dav4rack.rb
CHANGED
@@ -3,7 +3,12 @@ require 'uri'
|
|
3
3
|
require 'nokogiri'
|
4
4
|
|
5
5
|
require 'rack'
|
6
|
+
require 'dav4rack/utils'
|
6
7
|
require 'dav4rack/http_status'
|
7
8
|
require 'dav4rack/resource'
|
8
9
|
require 'dav4rack/handler'
|
9
10
|
require 'dav4rack/controller'
|
11
|
+
|
12
|
+
module DAV4Rack
|
13
|
+
IS_18 = RUBY_VERSION[0,3] == '1.8'
|
14
|
+
end
|
data/lib/dav4rack/controller.rb
CHANGED
@@ -4,6 +4,7 @@ module DAV4Rack
|
|
4
4
|
|
5
5
|
class Controller
|
6
6
|
include DAV4Rack::HTTPStatus
|
7
|
+
include DAV4Rack::Utils
|
7
8
|
|
8
9
|
attr_reader :request, :response, :resource
|
9
10
|
|
@@ -17,7 +18,15 @@ module DAV4Rack
|
|
17
18
|
@request = request
|
18
19
|
@response = response
|
19
20
|
@options = options
|
21
|
+
|
22
|
+
@dav_extensions = options.delete(:dav_extensions) || []
|
23
|
+
@always_include_dav_header = options.delete(:always_include_dav_header)
|
24
|
+
|
20
25
|
@resource = resource_class.new(actual_path, implied_path, @request, @response, @options)
|
26
|
+
|
27
|
+
if(@always_include_dav_header)
|
28
|
+
add_dav_header
|
29
|
+
end
|
21
30
|
end
|
22
31
|
|
23
32
|
# s:: string
|
@@ -34,13 +43,20 @@ module DAV4Rack
|
|
34
43
|
# Unescape URL string
|
35
44
|
def url_unescape(s)
|
36
45
|
URI.unescape(s)
|
37
|
-
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_dav_header
|
49
|
+
unless(response['Dav'])
|
50
|
+
dav_support = %w(1 2) + @dav_extensions
|
51
|
+
response['Dav'] = dav_support.join(', ')
|
52
|
+
end
|
53
|
+
end
|
38
54
|
|
39
55
|
# Return response to OPTIONS
|
40
56
|
def options
|
41
|
-
|
42
|
-
response[
|
43
|
-
response[
|
57
|
+
add_dav_header
|
58
|
+
response['Allow'] = 'OPTIONS,HEAD,GET,PUT,POST,DELETE,PROPFIND,PROPPATCH,MKCOL,COPY,MOVE,LOCK,UNLOCK'
|
59
|
+
response['Ms-Author-Via'] = 'DAV'
|
44
60
|
OK
|
45
61
|
end
|
46
62
|
|
@@ -76,10 +92,10 @@ module DAV4Rack
|
|
76
92
|
def put
|
77
93
|
if(resource.collection?)
|
78
94
|
Forbidden
|
79
|
-
elsif(!resource.parent_exists? || !resource.
|
95
|
+
elsif(!resource.parent_exists? || !resource.parent_collection?)
|
80
96
|
Conflict
|
81
97
|
else
|
82
|
-
resource.lock_check
|
98
|
+
resource.lock_check if resource.supports_locking?
|
83
99
|
status = resource.put(request, response)
|
84
100
|
response['Location'] = "#{scheme}://#{host}:#{port}#{url_format(resource)}" if status == Created
|
85
101
|
response.body = response['Location']
|
@@ -95,7 +111,7 @@ module DAV4Rack
|
|
95
111
|
# Return response to DELETE
|
96
112
|
def delete
|
97
113
|
if(resource.exist?)
|
98
|
-
resource.lock_check
|
114
|
+
resource.lock_check if resource.supports_locking?
|
99
115
|
resource.delete
|
100
116
|
else
|
101
117
|
NotFound
|
@@ -104,7 +120,7 @@ module DAV4Rack
|
|
104
120
|
|
105
121
|
# Return response to MKCOL
|
106
122
|
def mkcol
|
107
|
-
resource.lock_check
|
123
|
+
resource.lock_check if resource.supports_locking?
|
108
124
|
status = resource.make_collection
|
109
125
|
gen_url = "#{scheme}://#{host}:#{port}#{url_format(resource)}" if status == Created
|
110
126
|
if(resource.use_compat_mkcol_response?)
|
@@ -132,7 +148,7 @@ module DAV4Rack
|
|
132
148
|
unless(resource.exist?)
|
133
149
|
NotFound
|
134
150
|
else
|
135
|
-
resource.lock_check
|
151
|
+
resource.lock_check if resource.supports_locking? && !args.include(:copy)
|
136
152
|
destination = url_unescape(env['HTTP_DESTINATION'].sub(%r{https?://([^/]+)}, ''))
|
137
153
|
dest_host = $1
|
138
154
|
if(dest_host && dest_host.gsub(/:\d{2,5}$/, '') != request.host)
|
@@ -165,25 +181,33 @@ module DAV4Rack
|
|
165
181
|
end
|
166
182
|
end
|
167
183
|
|
168
|
-
# Return
|
184
|
+
# Return response to PROPFIND
|
169
185
|
def propfind
|
170
186
|
unless(resource.exist?)
|
171
187
|
NotFound
|
172
188
|
else
|
173
189
|
unless(request_document.xpath("//#{ns}propfind/#{ns}allprop").empty?)
|
174
|
-
|
190
|
+
properties = resource.properties
|
175
191
|
else
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
192
|
+
check = request_document.xpath("//#{ns}propfind")
|
193
|
+
if(check && !check.empty?)
|
194
|
+
properties = request_document.xpath(
|
195
|
+
"//#{ns}propfind/#{ns}prop"
|
196
|
+
).children.find_all{ |item|
|
197
|
+
item.element?
|
198
|
+
}.map{ |item|
|
199
|
+
# We should do this, but Nokogiri transforms prefix w/ null href into
|
200
|
+
# something valid. Oops.
|
201
|
+
# TODO: Hacky grep fix that's horrible
|
202
|
+
hsh = to_element_hash(item)
|
203
|
+
if(hsh.namespace.nil? && !ns.empty?)
|
204
|
+
raise BadRequest if request_document.to_s.scan(%r{<#{item.name}[^>]+xmlns=""}).empty?
|
205
|
+
end
|
206
|
+
hsh
|
207
|
+
}.compact
|
208
|
+
else
|
209
|
+
raise BadRequest
|
210
|
+
end
|
187
211
|
end
|
188
212
|
multistatus do |xml|
|
189
213
|
find_resources.each do |resource|
|
@@ -193,7 +217,7 @@ module DAV4Rack
|
|
193
217
|
else
|
194
218
|
xml.href url_format(resource)
|
195
219
|
end
|
196
|
-
propstats(xml, get_properties(resource,
|
220
|
+
propstats(xml, get_properties(resource, properties.empty? ? resource.properties : properties))
|
197
221
|
end
|
198
222
|
end
|
199
223
|
end
|
@@ -205,14 +229,32 @@ module DAV4Rack
|
|
205
229
|
unless(resource.exist?)
|
206
230
|
NotFound
|
207
231
|
else
|
208
|
-
resource.lock_check
|
209
|
-
|
210
|
-
|
232
|
+
resource.lock_check if resource.supports_locking?
|
233
|
+
prop_actions = []
|
234
|
+
request_document.xpath("/#{ns}propertyupdate").children.each do |element|
|
235
|
+
case element.name
|
236
|
+
when 'set', 'remove'
|
237
|
+
prp = element.children.detect{|e|e.name == 'prop'}
|
238
|
+
if(prp)
|
239
|
+
prp.children.each do |elm|
|
240
|
+
next if elm.name == 'text'
|
241
|
+
prop_actions << {:type => element.name, :name => to_element_hash(elm), :value => elm.text}
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
211
246
|
multistatus do |xml|
|
212
247
|
find_resources.each do |resource|
|
213
248
|
xml.response do
|
214
249
|
xml.href "#{scheme}://#{host}:#{port}#{url_format(resource)}"
|
215
|
-
|
250
|
+
prop_actions.each do |action|
|
251
|
+
case action[:type]
|
252
|
+
when 'set'
|
253
|
+
propstats(xml, set_properties(resource, action[:name] => action[:value]))
|
254
|
+
when 'remove'
|
255
|
+
rm_properties(resource, action[:name] => action[:value])
|
256
|
+
end
|
257
|
+
end
|
216
258
|
end
|
217
259
|
end
|
218
260
|
end
|
@@ -260,6 +302,7 @@ module DAV4Rack
|
|
260
302
|
end
|
261
303
|
end
|
262
304
|
end
|
305
|
+
response.headers['Lock-Token'] = locktoken
|
263
306
|
response.status = resource.exist? ? OK : Created
|
264
307
|
rescue LockFailure => e
|
265
308
|
multistatus do |xml|
|
@@ -300,9 +343,6 @@ module DAV4Rack
|
|
300
343
|
raise Unauthorized unless authed
|
301
344
|
end
|
302
345
|
|
303
|
-
# ************************************************************
|
304
|
-
# private methods
|
305
|
-
|
306
346
|
private
|
307
347
|
|
308
348
|
# Request environment variables
|
@@ -402,22 +442,21 @@ module DAV4Rack
|
|
402
442
|
|
403
443
|
# Namespace being used within XML document
|
404
444
|
# TODO: Make this better
|
405
|
-
def ns
|
445
|
+
def ns(wanted_uri="DAV:")
|
406
446
|
_ns = ''
|
407
447
|
if(request_document && request_document.root && request_document.root.namespace_definitions.size > 0)
|
408
|
-
_ns = request_document.root.namespace_definitions.
|
448
|
+
_ns = request_document.root.namespace_definitions.collect{|__ns| __ns if __ns.href == wanted_uri}.compact
|
449
|
+
if _ns.empty?
|
450
|
+
_ns = request_document.root.namespace_definitions.first.prefix.to_s if _ns.empty?
|
451
|
+
else
|
452
|
+
_ns = _ns.first
|
453
|
+
_ns = _ns.prefix.nil? ? 'xmlns' : _ns.prefix.to_s
|
454
|
+
end
|
409
455
|
_ns += ':' unless _ns.empty?
|
410
456
|
end
|
411
457
|
_ns
|
412
458
|
end
|
413
459
|
|
414
|
-
# pattern:: XPath pattern
|
415
|
-
# Search XML document for given XPath
|
416
|
-
# TODO: Stripping namespaces not so great
|
417
|
-
def request_match(pattern)
|
418
|
-
request_document.remove_namespaces!.xpath(pattern, request_document.root.namespaces)
|
419
|
-
end
|
420
|
-
|
421
460
|
# root_type:: Root tag name
|
422
461
|
# Render XML and set Rack::Response#body= to final XML
|
423
462
|
def render_xml(root_type)
|
@@ -462,35 +501,44 @@ module DAV4Rack
|
|
462
501
|
end
|
463
502
|
|
464
503
|
# resource:: Resource
|
465
|
-
#
|
504
|
+
# elements:: Property hashes (name, ns_href, children)
|
466
505
|
# Returns array of property values for given names
|
467
|
-
def get_properties(resource,
|
506
|
+
def get_properties(resource, elements)
|
468
507
|
stats = Hash.new { |h, k| h[k] = [] }
|
469
|
-
for
|
508
|
+
for element in elements
|
470
509
|
begin
|
471
|
-
val = resource.get_property(
|
472
|
-
stats[OK]
|
510
|
+
val = resource.get_property(element)
|
511
|
+
stats[OK] << [element, val]
|
473
512
|
rescue Unauthorized => u
|
474
513
|
raise u
|
475
514
|
rescue Status
|
476
|
-
stats[$!.class] <<
|
515
|
+
stats[$!.class] << element
|
477
516
|
end
|
478
517
|
end
|
479
518
|
stats
|
480
519
|
end
|
481
520
|
|
482
521
|
# resource:: Resource
|
483
|
-
#
|
522
|
+
# elements:: Property hashes (name, namespace, children)
|
523
|
+
# Removes the given properties from a resource
|
524
|
+
def rm_properties(resource, elements)
|
525
|
+
for element, value in elements
|
526
|
+
resource.remove_property(element)
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
# resource:: Resource
|
531
|
+
# elements:: Property hashes (name, namespace, children)
|
484
532
|
# Sets the given properties
|
485
|
-
def set_properties(resource,
|
533
|
+
def set_properties(resource, elements)
|
486
534
|
stats = Hash.new { |h, k| h[k] = [] }
|
487
|
-
for
|
535
|
+
for element, value in elements
|
488
536
|
begin
|
489
|
-
stats[OK] << [
|
537
|
+
stats[OK] << [element, resource.set_property(element, value)]
|
490
538
|
rescue Unauthorized => u
|
491
539
|
raise u
|
492
540
|
rescue Status
|
493
|
-
stats[$!.class] <<
|
541
|
+
stats[$!.class] << element
|
494
542
|
end
|
495
543
|
end
|
496
544
|
stats
|
@@ -504,20 +552,36 @@ module DAV4Rack
|
|
504
552
|
for status, props in stats
|
505
553
|
xml.propstat do
|
506
554
|
xml.prop do
|
507
|
-
for
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
555
|
+
for element, value in props
|
556
|
+
defn = xml.doc.root.namespace_definitions.find{|ns_def| ns_def.href == element[:ns_href]}
|
557
|
+
if defn.nil?
|
558
|
+
if element[:ns_href] and not element[:ns_href].empty?
|
559
|
+
_ns = "unknown#{rand(65536)}"
|
560
|
+
xml.doc.root.add_namespace_definition(_ns, element[:ns_href])
|
561
|
+
else
|
562
|
+
_ns = nil
|
513
563
|
end
|
564
|
+
else
|
565
|
+
# Unfortunately Nokogiri won't let the null href, non-null prefix happen
|
566
|
+
# So we can't properly handle that error.
|
567
|
+
_ns = element[:ns_href].nil? ? nil : defn.prefix
|
568
|
+
end
|
569
|
+
ns_xml = _ns.nil? ? xml : xml[_ns]
|
570
|
+
if (value.is_a?(Nokogiri::XML::Node)) or (value.is_a?(Nokogiri::XML::DocumentFragment))
|
571
|
+
xml.__send__ :insert, value
|
514
572
|
elsif(value.is_a?(Symbol))
|
515
|
-
|
516
|
-
|
573
|
+
ns_xml.send(element[:name]) do
|
574
|
+
ns_xml.send(value)
|
517
575
|
end
|
518
576
|
else
|
519
|
-
|
577
|
+
ns_xml.send(element[:name], value) do |x|
|
578
|
+
# Make sure we return valid XML
|
579
|
+
x.parent.namespace = nil if _ns.nil?
|
580
|
+
end
|
520
581
|
end
|
582
|
+
|
583
|
+
# This is gross, but make sure we set the current namespace back to DAV:
|
584
|
+
xml['D']
|
521
585
|
end
|
522
586
|
end
|
523
587
|
xml.status "#{http_version} #{status.status_line}"
|