dav4rack 0.2.11 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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}"
|