Parse fix applied for webdav PUT method, where .Net / Office over WebDav pushes content with text/xml mime type. Rails stack automatically will try to parse XML, however unfortunately as content is

not XML, it ends up failing. "init.rb" has a hook adding RedmineDmsf::NoParse into Rails middleware a step before content parsing occurs, and will rewrite content type on put method, within specified
target area (identified in init.rb). Controller has been added to override options function (maybe removed later on).
This commit is contained in:
Daniel Munn 2012-06-14 22:35:02 +01:00
parent 3bd5d93479
commit c76556c507
10 changed files with 108 additions and 14 deletions

View File

@ -92,5 +92,6 @@ RedmineApp::Application.routes.draw do
# :root => Rails.root.to_s, # :root => Rails.root.to_s,
:root_uri_path => "/dmsf/webdav", :root_uri_path => "/dmsf/webdav",
:resource_class => RedmineDmsf::Webdav::ResourceProxy, :resource_class => RedmineDmsf::Webdav::ResourceProxy,
:controller_class => RedmineDmsf::Webdav::Controller
), :at => "/dmsf/webdav" ), :at => "/dmsf/webdav"
end end

30
init.rb
View File

@ -17,19 +17,29 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'redmine' require 'redmine'
#require 'dispatcher' require 'redmine_dmsf'
#Dispatcher.to_prepare :redmine_dmsf do #
# This may need to be configurable
#
Rails.configuration.middleware.insert_before(ActionDispatch::ParamsParser,
RedmineDmsf::NoParse, :urls => ['/dmsf/webdav'])
Rails.configuration.to_prepare do Rails.configuration.to_prepare do
unless ProjectsHelper.included_modules.include?(ProjectTabsExtended) unless ProjectsHelper.included_modules.include?(ProjectTabsExtended)
ProjectsHelper.send(:include, ProjectTabsExtended) ProjectsHelper.send(:include, ProjectTabsExtended)
end end
unless CustomFieldsHelper.included_modules.include?(CustomFieldsHelper) unless CustomFieldsHelper.included_modules.include?(CustomFieldsHelper)
CustomFieldsHelper.send(:include, RedmineDmsf::Patches::CustomFieldsHelper) CustomFieldsHelper.send(:include, RedmineDmsf::Patches::CustomFieldsHelper)
end end
Project.send(:include, RedmineDmsf::Patches::ProjectPatch)
#ActiveSupport::XmlMini.backend = 'Nokogiri'
Project.send(:include, RedmineDmsf::Patches::ProjectPatch)
end end
Redmine::Plugin.register :redmine_dmsf do Redmine::Plugin.register :redmine_dmsf do

View File

@ -2,6 +2,7 @@ require 'redmine_dmsf/patches/custom_fields_helper'
require 'redmine_dmsf/patches/acts_as_customizable' require 'redmine_dmsf/patches/acts_as_customizable'
require 'redmine_dmsf/patches/project_patch' require 'redmine_dmsf/patches/project_patch'
require 'redmine_dmsf/webdav' require 'redmine_dmsf/webdav'
require 'redmine_dmsf/no_parse'
module RedmineDmsf module RedmineDmsf
end end

View File

@ -0,0 +1,25 @@
module RedmineDmsf
class NoParse
def initialize(app, options={})
@app = app
@urls = options[:urls]
end
def call(env)
if env['REQUEST_METHOD'] == "PUT" && env.has_key?('CONTENT_TYPE') then
if (@urls.dup.delete_if {|x| !env['PATH_INFO'].starts_with? x}.length > 0) then
logger "RedmineDmsf::NoParse prevented mime parsing for PUT #{env['PATH_INFO']}"
env['CONTENT_TYPE'] = 'text/plain'
end
end
@app.call(env)
end
private
def logger(env)
env['action_dispatch.logger'] || Logger.new($stdout)
end
end
end

View File

@ -1,7 +1,7 @@
# Load up classes that make up our webdav solution ontop
# of DAV4Rack
require 'redmine_dmsf/webdav/resource_proxy' require 'redmine_dmsf/webdav/resource_proxy'
require 'redmine_dmsf/webdav/base_resource' require 'redmine_dmsf/webdav/base_resource'
require 'redmine_dmsf/webdav/index_resource' require 'redmine_dmsf/webdav/index_resource'
require 'redmine_dmsf/webdav/project_resource' require 'redmine_dmsf/webdav/project_resource'
require 'redmine_dmsf/webdav/dmsf_resource' require 'redmine_dmsf/webdav/dmsf_resource'

View File

@ -51,6 +51,7 @@ module RedmineDmsf
def parent def parent
p = @__proxy.parent p = @__proxy.parent
return nil if p.nil?
return p.resource.nil? ? p : p.resource return p.resource.nil? ? p : p.resource
end end

View File

@ -0,0 +1,49 @@
module RedmineDmsf
module Webdav
class Controller < DAV4Rack::Controller
#Overload default options
def options
response["Allow"] = 'OPTIONS,HEAD,GET,PUT,POST,DELETE,PROPFIND,PROPPATCH,MKCOL,COPY,MOVE,LOCK,UNLOCK'
response["Dav"] = "1,2,3"
response["Ms-Author-Via"] = "DAV"
OK
end
#Overload the default propfind function with this
def propfind
unless(resource.exist?)
NotFound
else
unless(request_document.xpath("//#{ns}propfind/#{ns}allprop").empty?)
names = resource.property_names
else
names = (
ns.empty? ? request_document.remove_namespaces! : request_document
).xpath(
"//#{ns}propfind/#{ns}prop"
).children.find_all{ |item|
item.element? && item.name.start_with?(ns)
}.map{ |item|
item.name.sub("#{ns}::", '')
}
names = resource.property_names if names.empty?
end
multistatus do |xml|
find_resources.each do |resource|
xml.response do
unless(resource.propstat_relative_path)
xml.href "#{scheme}://#{host}:#{port}#{url_format(resource)}"
else
xml.href url_format(resource)
end
propstats(xml, get_properties(resource, names))
end
end
end
end
end
end
end
end

View File

@ -167,7 +167,6 @@ module RedmineDmsf
# #
# Create a DmsfFolder at location requested, only if parent is a folder (or root) # Create a DmsfFolder at location requested, only if parent is a folder (or root)
def make_collection def make_collection
debugger
if (request.body.read.to_s == '') if (request.body.read.to_s == '')
return MethodNotAllowed if exist? #If we already exist, why waste the time trying to save? return MethodNotAllowed if exist? #If we already exist, why waste the time trying to save?
parent_folder = nil parent_folder = nil

View File

@ -9,6 +9,7 @@ module RedmineDmsf
def children def children
#caching for repeat usage #caching for repeat usage
return @children unless @children.nil? return @children unless @children.nil?
return [] if project.nil? || project.id.nil?
@children = [] @children = []
DmsfFolder.project_root_folders(project).map do |p| DmsfFolder.project_root_folders(project).map do |p|
@children.push child(p.title, p) @children.push child(p.title, p)
@ -65,6 +66,13 @@ module RedmineDmsf
OK OK
end end
def folder
nil
end
def file
nil
end
end end
end end
end end

View File

@ -30,7 +30,7 @@ module RedmineDmsf
# going to fork it to ensure compliance, checking the request method in the authentication # going to fork it to ensure compliance, checking the request method in the authentication
# seems the next best step, if the request method is OPTIONS return true, controller will simply # seems the next best step, if the request method is OPTIONS return true, controller will simply
# call the options method within, which accesses nothing, just returns headers about dav env. # call the options method within, which accesses nothing, just returns headers about dav env.
return false if (@request.request_method.downcase == "options") return true if ( @request.request_method.downcase == "options" && ( path == "/" || path.empty? ) )
User.current = User.try_to_login(username, password) || nil User.current = User.try_to_login(username, password) || nil
return !User.current.anonymous? unless User.current.nil? return !User.current.anonymous? unless User.current.nil?
false false