dav4rack 0.2.10 → 0.2.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -311,6 +311,8 @@ A big thanks to everyone contributing to help make this project better.
311
311
  * {doxavore}[https://github.com/doxavore]
312
312
  * {spicyj}[https://github.com/spicyj]
313
313
  * {TurchenkoAlex}[https://github.com/TurchenkoAlex]
314
+ * {exabugs}[https://github.com/exabugs]
315
+ * {inferiorhumanorgans}[https://github.com/inferiorhumanorgans]
314
316
 
315
317
  == License
316
318
 
@@ -27,7 +27,8 @@ opts = GetoptLong.new(
27
27
  ['--version', '-v', GetoptLong::NO_ARGUMENT],
28
28
  ['--root', '-r', GetoptLong::REQUIRED_ARGUMENT],
29
29
  ['--log', '-l', GetoptLong::OPTIONAL_ARGUMENT],
30
- ['--verbosity', '-V', GetoptLong::REQUIRED_ARGUMENT]
30
+ ['--verbosity', '-V', GetoptLong::REQUIRED_ARGUMENT],
31
+ ['--pretty-xml', '-P', GetoptLong::REQUIRED_ARGUMENT]
31
32
  )
32
33
 
33
34
  credentials = {}
@@ -47,6 +48,8 @@ opts.each do |opt,arg|
47
48
  puts "ERROR: Path provided is not a valid directory (#{arg})"
48
49
  exit(-1)
49
50
  end
51
+ when '--pretty-xml'
52
+ credentials[:pretty_xml] = true
50
53
  when '--version'
51
54
  print_version_info
52
55
  exit(0)
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module DAV4Rack
2
4
 
3
5
  class Controller
@@ -11,7 +13,7 @@ module DAV4Rack
11
13
  # Create a new Controller.
12
14
  # NOTE: options will be passed to Resource
13
15
  def initialize(request, response, options={})
14
- raise Forbidden if request.path_info.include?('../')
16
+ raise Forbidden if request.path_info.include?('..')
15
17
  @request = request
16
18
  @response = response
17
19
  @options = options
@@ -20,18 +22,18 @@ module DAV4Rack
20
22
 
21
23
  # s:: string
22
24
  # Escape URL string
23
- def url_escape(s)
24
- s.gsub(/([^\/a-zA-Z0-9_.-]+)/n) do
25
- '%' + $1.unpack('H2' * $1.size).join('%').upcase
26
- end.tr(' ', '+')
25
+ def url_format(resource)
26
+ ret = URI.escape(resource.public_path)
27
+ if resource.collection? and ret[-1,1] != '/'
28
+ ret += '/'
29
+ end
30
+ ret
27
31
  end
28
32
 
29
33
  # s:: string
30
34
  # Unescape URL string
31
35
  def url_unescape(s)
32
- s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
33
- [$1.delete('%')].pack('H*')
34
- end
36
+ URI.unescape(s)
35
37
  end
36
38
 
37
39
  # Return response to OPTIONS
@@ -79,7 +81,7 @@ module DAV4Rack
79
81
  else
80
82
  resource.lock_check
81
83
  status = resource.put(request, response)
82
- response['Location'] = "#{scheme}://#{host}:#{port}#{resource.public_path}" if status == Created
84
+ response['Location'] = "#{scheme}://#{host}:#{port}#{url_format(resource)}" if status == Created
83
85
  response.body = response['Location']
84
86
  status
85
87
  end
@@ -104,11 +106,17 @@ module DAV4Rack
104
106
  def mkcol
105
107
  resource.lock_check
106
108
  status = resource.make_collection
107
- multistatus do |xml|
108
- xml.response do
109
- xml.href "#{scheme}://#{host}:#{port}#{url_escape(resource.public_path)}"
110
- xml.status "#{http_version} #{status.status_line}"
109
+ gen_url = "#{scheme}://#{host}:#{port}#{url_format(resource)}" if status == Created
110
+ if(resource.use_compat_mkcol_response?)
111
+ multistatus do |xml|
112
+ xml.response do
113
+ xml.href gen_url
114
+ xml.status "#{http_version} #{status.status_line}"
115
+ end
111
116
  end
117
+ else
118
+ response['Location'] = gen_url
119
+ status
112
120
  end
113
121
  end
114
122
 
@@ -132,6 +140,7 @@ module DAV4Rack
132
140
  elsif(destination == resource.public_path)
133
141
  Forbidden
134
142
  else
143
+ collection = resource.collection?
135
144
  dest = resource_class.new(destination, clean_path(destination), @request, @response, @options.merge(:user => resource.user))
136
145
  status = nil
137
146
  if(args.include?(:copy))
@@ -140,12 +149,17 @@ module DAV4Rack
140
149
  return Conflict unless depth.is_a?(Symbol) || depth > 1
141
150
  status = resource.move(dest, overwrite)
142
151
  end
143
- response['Location'] = "#{scheme}://#{host}:#{port}#{dest.public_path}" if status == Created
144
- multistatus do |xml|
145
- xml.response do
146
- xml.href "#{scheme}://#{host}:#{port}#{status == Created ? dest.public_path : resource.public_path}"
147
- xml.status "#{http_version} #{status.status_line}"
152
+ response['Location'] = "#{scheme}://#{host}:#{port}#{url_format(dest)}" if status == Created
153
+ # RFC 2518
154
+ if collection
155
+ multistatus do |xml|
156
+ xml.response do
157
+ xml.href "#{scheme}://#{host}:#{port}#{url_format(status == Created ? dest : resource)}"
158
+ xml.status "#{http_version} #{status.status_line}"
159
+ end
148
160
  end
161
+ else
162
+ status
149
163
  end
150
164
  end
151
165
  end
@@ -159,13 +173,26 @@ module DAV4Rack
159
173
  unless(request_document.xpath("//#{ns}propfind/#{ns}allprop").empty?)
160
174
  names = resource.property_names
161
175
  else
162
- names = request_document.xpath("//#{ns}propfind/#{ns}prop").children.find_all{|n|n.element?}.map{|n|n.name}
176
+ names = (
177
+ ns.empty? ? request_document.remove_namespaces! : request_document
178
+ ).xpath(
179
+ "//#{ns}propfind/#{ns}prop"
180
+ ).children.find_all{ |item|
181
+ item.element? && item.name.start_with?(ns)
182
+ }.map{ |item|
183
+ item.name.sub("#{ns}::", '')
184
+ }
185
+ raise BadRequest if names.empty?
163
186
  names = resource.property_names if names.empty?
164
187
  end
165
188
  multistatus do |xml|
166
189
  find_resources.each do |resource|
167
190
  xml.response do
168
- xml.href "#{scheme}://#{host}:#{port}#{url_escape(resource.public_path)}"
191
+ unless(resource.propstat_relative_path)
192
+ xml.href "#{scheme}://#{host}:#{port}#{url_format(resource)}"
193
+ else
194
+ xml.href url_format(resource)
195
+ end
169
196
  propstats(xml, get_properties(resource, names))
170
197
  end
171
198
  end
@@ -184,7 +211,7 @@ module DAV4Rack
184
211
  multistatus do |xml|
185
212
  find_resources.each do |resource|
186
213
  xml.response do
187
- xml.href "#{scheme}://#{host}:#{port}#{url_escape(resource.public_path)}"
214
+ xml.href "#{scheme}://#{host}:#{port}#{url_format(resource)}"
188
215
  propstats(xml, set_properties(resource, prop_set))
189
216
  end
190
217
  end
@@ -386,9 +413,9 @@ module DAV4Rack
386
413
 
387
414
  # pattern:: XPath pattern
388
415
  # Search XML document for given XPath
416
+ # TODO: Stripping namespaces not so great
389
417
  def request_match(pattern)
390
- nil unless request_document
391
- request_document.xpath(pattern, request_document.root.namespaces)
418
+ request_document.remove_namespaces!.xpath(pattern, request_document.root.namespaces)
392
419
  end
393
420
 
394
421
  # root_type:: Root tag name
@@ -396,14 +423,20 @@ module DAV4Rack
396
423
  def render_xml(root_type)
397
424
  raise ArgumentError.new 'Expecting block' unless block_given?
398
425
  doc = Nokogiri::XML::Builder.new do |xml_base|
399
- xml_base.send(root_type.to_s, 'xmlns:D' => 'DAV:') do
426
+ xml_base.send(root_type.to_s, {'xmlns:D' => 'DAV:'}.merge(resource.root_xml_attributes)) do
400
427
  xml_base.parent.namespace = xml_base.parent.namespace_definitions.first
401
428
  xml = xml_base['D']
402
429
  yield xml
403
430
  end
404
431
  end
405
-
406
- response.body = doc.to_xml
432
+
433
+ if(@options[:pretty_xml])
434
+ response.body = doc.to_xml
435
+ else
436
+ response.body = doc.to_xml(
437
+ :save_with => Nokogiri::XML::Node::SaveOptions::AS_XML
438
+ )
439
+ end
407
440
  response["Content-Type"] = 'text/xml; charset="utf-8"'
408
441
  response["Content-Length"] = response.body.size.to_s
409
442
  end
@@ -422,7 +455,7 @@ module DAV4Rack
422
455
  def response_errors(xml, errors)
423
456
  for path, status in errors
424
457
  xml.response do
425
- xml.href "#{scheme}://#{host}:#{port}#{path}"
458
+ xml.href "#{scheme}://#{host}:#{port}#{URI.escape(path)}"
426
459
  xml.status "#{http_version} #{status.status_line}"
427
460
  end
428
461
  end
@@ -440,7 +473,7 @@ module DAV4Rack
440
473
  rescue Unauthorized => u
441
474
  raise u
442
475
  rescue Status
443
- stats[$!] << name
476
+ stats[$!.class] << name
444
477
  end
445
478
  end
446
479
  stats
@@ -457,7 +490,7 @@ module DAV4Rack
457
490
  rescue Unauthorized => u
458
491
  raise u
459
492
  rescue Status
460
- stats[$!] << name
493
+ stats[$!.class] << name
461
494
  end
462
495
  end
463
496
  stats
@@ -472,7 +505,9 @@ module DAV4Rack
472
505
  xml.propstat do
473
506
  xml.prop do
474
507
  for name, value in props
475
- if(value.is_a?(Nokogiri::XML::Node))
508
+ if(value.is_a?(Nokogiri::XML::DocumentFragment))
509
+ xml.__send__ :insert, value
510
+ elsif(value.is_a?(Nokogiri::XML::Node))
476
511
  xml.send(name) do
477
512
  xml_convert(xml, value)
478
513
  end
@@ -105,41 +105,71 @@ module DAV4Rack
105
105
  # HTTP COPY request.
106
106
  #
107
107
  # Copy this resource to given destination resource.
108
- def copy(dest, overwrite = false)
109
- if(dest.path == path)
110
- Conflict
111
- elsif(stat.directory?)
112
- dest.make_collection
113
- FileUtils.cp_r("#{file_path}/.", "#{dest.send(:file_path)}/")
114
- OK
108
+ # Copy this resource to given destination resource.
109
+ def copy(dest, overwrite)
110
+ if(collection?)
111
+ if(dest.exist?)
112
+ if(dest.collection? && overwrite)
113
+ FileUtils.cp_r(file_path, dest.send(:file_path))
114
+ Created
115
+ else
116
+ if(overwrite)
117
+ FileUtils.rm(dest.send(:file_path))
118
+ FileUtils.cp_r(file_path, dest.send(:file_path))
119
+ NoContent
120
+ else
121
+ PreconditionFailed
122
+ end
123
+ end
124
+ else
125
+ FileUtils.cp_r(file_path, dest.send(:file_path))
126
+ Created
127
+ end
115
128
  else
116
- exists = File.exists?(file_path)
117
- if(exists && !overwrite)
129
+ if(dest.exist? && !overwrite)
118
130
  PreconditionFailed
119
131
  else
120
- open(file_path, "rb") do |file|
121
- dest.write(file)
132
+ if(File.directory?(File.dirname(dest.send(:file_path))))
133
+ new = !dest.exist?
134
+ if(dest.collection? && dest.exist?)
135
+ FileUtils.rm_rf(dest.send(:file_path))
136
+ end
137
+ FileUtils.cp(file_path, dest.send(:file_path).sub(/\/$/, ''))
138
+ new ? Created : NoContent
139
+ else
140
+ Conflict
122
141
  end
123
- exists ? NoContent : Created
124
142
  end
125
143
  end
126
144
  end
127
-
145
+
128
146
  # HTTP MOVE request.
129
147
  #
130
148
  # Move this resource to given destination resource.
131
149
  def move(*args)
132
- copy(*args)
133
- delete
134
- OK
150
+ result = copy(*args)
151
+ delete if [Created, NoContent].include?(result)
152
+ result
135
153
  end
136
154
 
137
155
  # HTTP MKCOL request.
138
156
  #
139
157
  # Create this resource as collection.
140
158
  def make_collection
141
- Dir.mkdir(file_path)
142
- Created
159
+ if(request.body.read.to_s == '')
160
+ if(File.directory?(file_path))
161
+ MethodNotAllowed
162
+ else
163
+ if(File.directory?(File.dirname(file_path)))
164
+ Dir.mkdir(file_path)
165
+ Created
166
+ else
167
+ Conflict
168
+ end
169
+ end
170
+ else
171
+ UnsupportedMediaType
172
+ end
143
173
  end
144
174
 
145
175
  # Write to this resource from given IO.
@@ -157,7 +187,50 @@ module DAV4Rack
157
187
  File.unlink(tempfile) rescue nil
158
188
  end
159
189
 
160
- private
190
+ # name:: String - Property name
191
+ # Returns the value of the given property
192
+ def get_property(name)
193
+ super || custom_props(name)
194
+ end
195
+
196
+ # name:: String - Property name
197
+ # value:: New value
198
+ # Set the property to the given value
199
+ def set_property(name, value)
200
+ super || set_custom_props(name,value)
201
+ end
202
+
203
+ protected
204
+
205
+ def set_custom_props(key,val)
206
+ prop_hash[key.to_sym] = val
207
+ File.open(prop_path, 'w') do |file|
208
+ file.write(YAML.dump(prop_hash))
209
+ end
210
+ end
211
+
212
+ def custom_props(key)
213
+ prop_hash[key.to_sym]
214
+ end
215
+
216
+ def prop_path
217
+ path = File.join(root, '.props', File.dirname(file_path), File.basename(file_path))
218
+ unless(File.directory?(File.dirname(path)))
219
+ FileUtils.mkdir_p(File.dirname(path))
220
+ end
221
+ path
222
+ end
223
+
224
+ def prop_hash
225
+ unless(@_prop_hash)
226
+ if(File.exists?(prop_path))
227
+ @_prop_hash = YAML.load(File.read(prop_path))
228
+ else
229
+ @_prop_hash = {}
230
+ end
231
+ end
232
+ @_prop_hash
233
+ end
161
234
 
162
235
  def authenticate(user, pass)
163
236
  if(options[:username])
@@ -172,7 +245,7 @@ module DAV4Rack
172
245
  end
173
246
 
174
247
  def file_path
175
- root + '/' + path
248
+ File.join(root, path)
176
249
  end
177
250
 
178
251
  def stat
@@ -24,7 +24,8 @@ module DAV4Rack
24
24
 
25
25
  controller = nil
26
26
  begin
27
- controller = Controller.new(request, response, @options.dup)
27
+ controller_class = @options[:controller_class] || Controller
28
+ controller = controller_class.new(request, response, @options.dup)
28
29
  controller.authenticate
29
30
  res = controller.send(request.request_method.downcase)
30
31
  response.status = res.code if res.respond_to?(:code)
@@ -16,7 +16,8 @@ module DAV4Rack
16
16
  end
17
17
 
18
18
  class Resource
19
- attr_reader :path, :options, :public_path, :request, :response
19
+ attr_reader :path, :options, :public_path, :request,
20
+ :response, :propstat_relative_path, :root_xml_attributes
20
21
  attr_accessor :user
21
22
  @@blocks = {}
22
23
 
@@ -71,6 +72,8 @@ module DAV4Rack
71
72
  ]
72
73
  @public_path = public_path.dup
73
74
  @path = path.dup
75
+ @propstat_relative_path = !!options.delete(:propstat_relative_path)
76
+ @root_xml_attributes = options.delete(:root_xml_attributes) || {}
74
77
  @request = request
75
78
  @response = response
76
79
  unless(options.has_key?(:lock_class))
@@ -137,22 +140,23 @@ module DAV4Rack
137
140
 
138
141
  # Return the creation time.
139
142
  def creation_date
140
- NotImplemented
143
+ raise NotImplemented
141
144
  end
142
145
 
143
146
  # Return the time of last modification.
144
147
  def last_modified
145
- NotImplemented
148
+ raise NotImplemented
146
149
  end
147
150
 
148
151
  # Set the time of last modification.
149
152
  def last_modified=(time)
150
- NotImplemented
153
+ # Is this correct?
154
+ raise NotImplemented
151
155
  end
152
156
 
153
157
  # Return an Etag, an unique hash value for this resource.
154
158
  def etag
155
- NotImplemented
159
+ raise NotImplemented
156
160
  end
157
161
 
158
162
  # Return the resource type. Generally only used to specify
@@ -163,12 +167,12 @@ module DAV4Rack
163
167
 
164
168
  # Return the mime type of this resource.
165
169
  def content_type
166
- NotImplemented
170
+ raise NotImplemented
167
171
  end
168
172
 
169
173
  # Return the size in bytes for this resource.
170
174
  def content_length
171
- NotImplemented
175
+ raise NotImplemented
172
176
  end
173
177
 
174
178
  # HTTP GET request.
@@ -347,7 +351,7 @@ module DAV4Rack
347
351
  case name
348
352
  when 'resourcetype' then resource_type
349
353
  when 'displayname' then display_name
350
- when 'creationdate' then creation_date.xmlschema
354
+ when 'creationdate' then use_ms_compat_creationdate? ? creation_date.httpdate : creation_date.xmlschema
351
355
  when 'getcontentlength' then content_length.to_s
352
356
  when 'getcontenttype' then content_type
353
357
  when 'getetag' then etag
@@ -365,8 +369,6 @@ module DAV4Rack
365
369
  when 'getetag' then self.etag = value
366
370
  when 'getlastmodified' then self.last_modified = Time.httpdate(value)
367
371
  end
368
- rescue ArgumentError
369
- Conflict
370
372
  end
371
373
 
372
374
  # name:: Property name
@@ -390,9 +392,17 @@ module DAV4Rack
390
392
 
391
393
  # Return parent of this resource
392
394
  def parent
393
- elements = @path.scan(/[^\/]+/)
394
- return nil if elements.empty?
395
- self.class.new(('/' + @public_path.scan(/[^\/]+/)[0..-2].join('/')), ('/' + elements[0..-2].to_a.join('/')), @request, @response, @options.merge(:user => @user))
395
+ unless(@path.to_s.empty?)
396
+ self.class.new(
397
+ File.split(@public_path).first,
398
+ File.split(@path).first,
399
+ @request,
400
+ @response,
401
+ @options.merge(
402
+ :user => @user
403
+ )
404
+ )
405
+ end
396
406
  end
397
407
 
398
408
  # Return list of descendants
@@ -405,8 +415,6 @@ module DAV4Rack
405
415
  list
406
416
  end
407
417
 
408
- protected
409
-
410
418
  # Index page template for GETs on collection
411
419
  def index_page
412
420
  '<html><head> <title>%s</title>
@@ -425,10 +433,30 @@ module DAV4Rack
425
433
  %r{cyberduck}i,
426
434
  %r{konqueror}i
427
435
  ].any? do |regexp|
428
- (request.respond_to?(:user_agent) ? request.user_agent : request.env['HTTP_USER_AGENT']) =~ regexp
436
+ (request.respond_to?(:user_agent) ? request.user_agent : request.env['HTTP_USER_AGENT']).to_s =~ regexp
429
437
  end
430
438
  end
431
-
439
+
440
+ def use_compat_mkcol_response?
441
+ @options[:compat_mkcol] || @options[:compat_all]
442
+ end
443
+
444
+ # Returns true if using an MS client
445
+ def use_ms_compat_creationdate?
446
+ if(@options[:compat_ms_mangled_creationdate] || @options[:compat_all])
447
+ is_ms_client?
448
+ end
449
+ end
450
+
451
+ # Basic user agent testing for MS authored client
452
+ def is_ms_client?
453
+ [%r{microsoft-webdav}i, %r{microsoft office}i].any? do |regexp|
454
+ (request.respond_to?(:user_agent) ? request.user_agent : request.env['HTTP_USER_AGENT']).to_s =~ regexp
455
+ end
456
+ end
457
+
458
+ protected
459
+
432
460
  # Returns authentication credentials if available in form of [username,password]
433
461
  # TODO: Add support for digest
434
462
  def auth_credentials
@@ -13,5 +13,5 @@ module DAV4Rack
13
13
  end
14
14
  end
15
15
 
16
- VERSION = Version.new('0.2.10')
16
+ VERSION = Version.new('0.2.11')
17
17
  end
@@ -4,6 +4,7 @@ require 'rubygems'
4
4
  require 'dav4rack'
5
5
  require 'fileutils'
6
6
  require 'nokogiri'
7
+ require 'rspec'
7
8
 
8
9
  describe DAV4Rack::Handler do
9
10
  DOC_ROOT = File.expand_path(File.dirname(__FILE__) + '/htdocs')
@@ -48,9 +49,7 @@ describe DAV4Rack::Handler do
48
49
  end
49
50
 
50
51
  def url_escape(string)
51
- string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
52
- '%' + $1.unpack('H2' * $1.size).join('%').upcase
53
- end.tr(' ', '+')
52
+ URI.escape(string)
54
53
  end
55
54
 
56
55
  def response_xml
@@ -136,8 +135,7 @@ describe DAV4Rack::Handler do
136
135
  end
137
136
 
138
137
  it 'should delete recursively' do
139
- mkcol('/folder')
140
- multi_status_created.should eq true
138
+ mkcol('/folder').should be_created
141
139
  put('/folder/a', :input => 'body').should be_created
142
140
  put('/folder/b', :input => 'body').should be_created
143
141
 
@@ -159,15 +157,13 @@ describe DAV4Rack::Handler do
159
157
 
160
158
  it 'should copy a single resource' do
161
159
  put('/test', :input => 'body').should be_created
162
- copy('/test', 'HTTP_DESTINATION' => '/copy')
163
- multi_status_no_content.should eq true
160
+ copy('/test', 'HTTP_DESTINATION' => '/copy').should be_created
164
161
  get('/copy').body.should == 'body'
165
162
  end
166
163
 
167
164
  it 'should copy a resource with escaped characters' do
168
165
  put(url_escape('/a b'), :input => 'body').should be_created
169
- copy(url_escape('/a b'), 'HTTP_DESTINATION' => url_escape('/a c'))
170
- multi_status_no_content.should eq true
166
+ copy(url_escape('/a b'), 'HTTP_DESTINATION' => url_escape('/a c')).should be_created
171
167
  get(url_escape('/a c')).should be_ok
172
168
  response.body.should == 'body'
173
169
  end
@@ -175,39 +171,32 @@ describe DAV4Rack::Handler do
175
171
  it 'should deny a copy without overwrite' do
176
172
  put('/test', :input => 'body').should be_created
177
173
  put('/copy', :input => 'copy').should be_created
178
- copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'F')
179
-
180
- multistatus_response('/D:href').first.text.should =~ /http:\/\/localhost(:\d+)?\/test/
181
- multistatus_response('/D:status').first.text.should match(/412 Precondition Failed/)
182
-
174
+ copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'F').should be_precondition_failed
183
175
  get('/copy').body.should == 'copy'
184
176
  end
185
177
 
186
178
  it 'should allow a copy with overwrite' do
187
179
  put('/test', :input => 'body').should be_created
188
180
  put('/copy', :input => 'copy').should be_created
189
- copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'T')
190
- multi_status_no_content.should eq true
181
+ copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'T').should be_no_content
191
182
  get('/copy').body.should == 'body'
192
183
  end
193
184
 
194
185
  it 'should copy a collection' do
195
- mkcol('/folder')
196
- multi_status_created.should eq true
186
+ mkcol('/folder').should be_created
197
187
  copy('/folder', 'HTTP_DESTINATION' => '/copy')
198
- multi_status_ok.should eq true
188
+ multi_status_created.should eq true
199
189
  propfind('/copy', :input => propfind_xml(:resourcetype))
200
190
  multistatus_response('/D:propstat/D:prop/D:resourcetype/D:collection').should_not be_empty
201
191
  end
202
192
 
203
193
  it 'should copy a collection resursively' do
204
- mkcol('/folder')
205
- multi_status_created.should eq true
194
+ mkcol('/folder').should be_created
206
195
  put('/folder/a', :input => 'A').should be_created
207
196
  put('/folder/b', :input => 'B').should be_created
208
197
 
209
198
  copy('/folder', 'HTTP_DESTINATION' => '/copy')
210
- multi_status_ok.should eq true
199
+ multi_status_created.should eq true
211
200
  propfind('/copy', :input => propfind_xml(:resourcetype))
212
201
  multistatus_response('/D:propstat/D:prop/D:resourcetype/D:collection').should_not be_empty
213
202
  get('/copy/a').body.should == 'A'
@@ -215,13 +204,12 @@ describe DAV4Rack::Handler do
215
204
  end
216
205
 
217
206
  it 'should move a collection recursively' do
218
- mkcol('/folder')
219
- multi_status_created.should eq true
207
+ mkcol('/folder').should be_created
220
208
  put('/folder/a', :input => 'A').should be_created
221
209
  put('/folder/b', :input => 'B').should be_created
222
210
 
223
211
  move('/folder', 'HTTP_DESTINATION' => '/move')
224
- multi_status_ok.should eq true
212
+ multi_status_created.should eq true
225
213
  propfind('/move', :input => propfind_xml(:resourcetype))
226
214
  multistatus_response('/D:propstat/D:prop/D:resourcetype/D:collection').should_not be_empty
227
215
 
@@ -232,15 +220,13 @@ describe DAV4Rack::Handler do
232
220
  end
233
221
 
234
222
  it 'should create a collection' do
235
- mkcol('/folder')
236
- multi_status_created.should eq true
223
+ mkcol('/folder').should be_created
237
224
  propfind('/folder', :input => propfind_xml(:resourcetype))
238
225
  multistatus_response('/D:propstat/D:prop/D:resourcetype/D:collection').should_not be_empty
239
226
  end
240
227
 
241
228
  it 'should return full urls after creating a collection' do
242
- mkcol('/folder')
243
- multi_status_created.should eq true
229
+ mkcol('/folder').should be_created
244
230
  propfind('/folder', :input => propfind_xml(:resourcetype))
245
231
  multistatus_response('/D:propstat/D:prop/D:resourcetype/D:collection').should_not be_empty
246
232
  multistatus_response('/D:href').first.text.should =~ /http:\/\/localhost(:\d+)?\/folder/
metadata CHANGED
@@ -1,80 +1,57 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: dav4rack
3
- version: !ruby/object:Gem::Version
4
- hash: 3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.11
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 2
9
- - 10
10
- version: 0.2.10
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Chris Roberts
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-12-22 00:00:00 -08:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2012-09-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: nokogiri
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &15276900 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 1
32
- - 4
33
- - 2
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
34
21
  version: 1.4.2
35
22
  type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: uuidtools
39
23
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *15276900
25
+ - !ruby/object:Gem::Dependency
26
+ name: uuidtools
27
+ requirement: &15293080 !ruby/object:Gem::Requirement
41
28
  none: false
42
- requirements:
29
+ requirements:
43
30
  - - ~>
44
- - !ruby/object:Gem::Version
45
- hash: 9
46
- segments:
47
- - 2
48
- - 1
49
- - 1
31
+ - !ruby/object:Gem::Version
50
32
  version: 2.1.1
51
33
  type: :runtime
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: rack
55
34
  prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *15293080
36
+ - !ruby/object:Gem::Dependency
37
+ name: rack
38
+ requirement: &15292420 !ruby/object:Gem::Requirement
57
39
  none: false
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- hash: 19
62
- segments:
63
- - 1
64
- - 1
65
- - 0
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
66
43
  version: 1.1.0
67
44
  type: :runtime
68
- version_requirements: *id003
45
+ prerelease: false
46
+ version_requirements: *15292420
69
47
  description: WebDAV handler for Rack
70
48
  email: chrisroberts.code@gmail.com
71
- executables:
49
+ executables:
72
50
  - dav4rack
73
51
  extensions: []
74
-
75
- extra_rdoc_files:
52
+ extra_rdoc_files:
76
53
  - README.rdoc
77
- files:
54
+ files:
78
55
  - .gitignore
79
56
  - LICENSE
80
57
  - dav4rack.gemspec
@@ -95,39 +72,29 @@ files:
95
72
  - bin/dav4rack
96
73
  - spec/handler_spec.rb
97
74
  - README.rdoc
98
- has_rdoc: true
99
75
  homepage: http://github.com/chrisroberts/dav4rack
100
76
  licenses: []
101
-
102
77
  post_install_message:
103
78
  rdoc_options: []
104
-
105
- require_paths:
79
+ require_paths:
106
80
  - lib
107
- required_ruby_version: !ruby/object:Gem::Requirement
81
+ required_ruby_version: !ruby/object:Gem::Requirement
108
82
  none: false
109
- requirements:
110
- - - ">="
111
- - !ruby/object:Gem::Version
112
- hash: 3
113
- segments:
114
- - 0
115
- version: "0"
116
- required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
88
  none: false
118
- requirements:
119
- - - ">="
120
- - !ruby/object:Gem::Version
121
- hash: 3
122
- segments:
123
- - 0
124
- version: "0"
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
125
93
  requirements: []
126
-
127
94
  rubyforge_project:
128
- rubygems_version: 1.4.2
95
+ rubygems_version: 1.8.17
129
96
  signing_key:
130
97
  specification_version: 3
131
98
  summary: WebDAV handler for Rack
132
99
  test_files: []
133
-
100
+ has_rdoc: true