dav4rack 0.2.10 → 0.2.11
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/README.rdoc +2 -0
- data/bin/dav4rack +4 -1
- data/lib/dav4rack/controller.rb +65 -30
- data/lib/dav4rack/file_resource.rb +93 -20
- data/lib/dav4rack/handler.rb +2 -1
- data/lib/dav4rack/resource.rb +45 -17
- data/lib/dav4rack/version.rb +1 -1
- data/spec/handler_spec.rb +15 -29
- metadata +42 -75
    
        data/README.rdoc
    CHANGED
    
    | @@ -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 |  | 
    
        data/bin/dav4rack
    CHANGED
    
    | @@ -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)
         | 
    
        data/lib/dav4rack/controller.rb
    CHANGED
    
    | @@ -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  | 
| 24 | 
            -
                   | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 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 | 
            -
                   | 
| 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 | 
| 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 | 
            -
                   | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
                      xml. | 
| 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 | 
| 144 | 
            -
                       | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
                          xml. | 
| 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 =  | 
| 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 | 
            -
                           | 
| 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}#{ | 
| 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 | 
            -
                   | 
| 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 | 
            -
                   | 
| 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[ | 
| 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[ | 
| 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:: | 
| 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 | 
            -
                 | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 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 | 
            -
                     | 
| 117 | 
            -
                    if(exists && !overwrite)
         | 
| 129 | 
            +
                    if(dest.exist? && !overwrite)
         | 
| 118 130 | 
             
                      PreconditionFailed
         | 
| 119 131 | 
             
                    else
         | 
| 120 | 
            -
                       | 
| 121 | 
            -
                        dest. | 
| 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 | 
            -
                   | 
| 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 | 
            -
                   | 
| 142 | 
            -
             | 
| 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 | 
            -
                 | 
| 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  | 
| 248 | 
            +
                  File.join(root, path)
         | 
| 176 249 | 
             
                end
         | 
| 177 250 |  | 
| 178 251 | 
             
                def stat
         | 
    
        data/lib/dav4rack/handler.rb
    CHANGED
    
    | @@ -24,7 +24,8 @@ module DAV4Rack | |
| 24 24 |  | 
| 25 25 | 
             
                    controller = nil
         | 
| 26 26 | 
             
                    begin
         | 
| 27 | 
            -
                       | 
| 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)
         | 
    
        data/lib/dav4rack/resource.rb
    CHANGED
    
    | @@ -16,7 +16,8 @@ module DAV4Rack | |
| 16 16 | 
             
              end
         | 
| 17 17 |  | 
| 18 18 | 
             
              class Resource
         | 
| 19 | 
            -
                attr_reader :path, :options, :public_path, :request,  | 
| 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 | 
            -
                   | 
| 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 | 
            -
                   | 
| 394 | 
            -
             | 
| 395 | 
            -
             | 
| 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
         | 
    
        data/lib/dav4rack/version.rb
    CHANGED
    
    
    
        data/spec/handler_spec.rb
    CHANGED
    
    | @@ -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 | 
            -
                 | 
| 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 | 
            -
                 | 
| 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 | 
            -
                 | 
| 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 | 
            -
                 | 
| 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 | 
            -
               | 
| 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 | 
            -
             | 
| 19 | 
            -
             | 
| 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 | 
            -
               | 
| 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 | 
            -
               | 
| 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 | 
            -
               | 
| 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 | 
            -
               | 
| 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 | 
            -
                   | 
| 113 | 
            -
             | 
| 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 | 
            -
                   | 
| 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. | 
| 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
         |