diff options
Diffstat (limited to 'lib/webrick/httpservlet')
-rw-r--r-- | lib/webrick/httpservlet/filehandler.rb | 105 |
1 files changed, 79 insertions, 26 deletions
diff --git a/lib/webrick/httpservlet/filehandler.rb b/lib/webrick/httpservlet/filehandler.rb index ab118ba5c9..1c48734987 100644 --- a/lib/webrick/httpservlet/filehandler.rb +++ b/lib/webrick/httpservlet/filehandler.rb @@ -126,7 +126,7 @@ module WEBrick end class FileHandler < AbstractServlet - HandlerTable = Hash.new(DefaultFileHandler) + HandlerTable = Hash.new def self.add_handler(suffix, handler) HandlerTable[suffix] = handler @@ -201,8 +201,7 @@ module WEBrick def exec_handler(req, res) raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root if set_filename(req, res) - suffix = (/\.(\w+)$/ =~ res.filename) && $1 - handler = @options[:HandlerTable][suffix] || HandlerTable[suffix] + handler = get_handler(req) call_callback(:HandlerCallback, req, res) h = handler.get_instance(@config, res.filename) h.service(req, res) @@ -212,41 +211,95 @@ module WEBrick return false end + def get_handler(req) + suffix1 = (/\.(\w+)$/ =~ req.script_name) && $1.downcase + suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ req.script_name) && $1.downcase + handler_table = @options[:HandlerTable] + return handler_table[suffix1] || handler_table[suffix2] || + HandlerTable[suffix1] || HandlerTable[suffix2] || + DefaultFileHandler + end + def set_filename(req, res) - handler = nil res.filename = @root.dup path_info = req.path_info.scan(%r|/[^/]*|) - while name = path_info.shift - if name == "/" - indices = @config[:DirectoryIndex] - index = indices.find{|i| FileTest::file?("#{res.filename}/#{i}") } - name = "/#{index}" if index - end - res.filename << name - req.script_name << name - req.path_info = path_info.join - - if File::fnmatch("/#{@options[:NondisclosureName]}", name) - @logger.log(Log::WARN, - "the request refers nondisclosure name `#{name}'.") - raise HTTPStatus::Forbidden, "`#{req.path}' not found." - end - st = (File::stat(res.filename) rescue nil) - raise HTTPStatus::NotFound, "`#{req.path}' not found." unless st - raise HTTPStatus::Forbidden, - "no access permission to `#{req.path}'." unless st.readable? + path_info.unshift("") # dummy for checking @root dir + while base = path_info.first + check_filename(base) + break if base == "/" + break unless File.directory?(res.filename + base) + shift_path_info(req, res, path_info) + call_callback(:DirectoryCallback, req, res) + end - if st.directory? - call_callback(:DirectoryCallback, req, res) - else + if base = path_info.first + check_filename(base) + if base == "/" + if file = search_index_file(req, res) + shift_path_info(req, res, path_info, file) + call_callback(:FileCallback, req, res) + return true + end + shift_path_info(req, res, path_info) + elsif file = search_file(req, res, base) + shift_path_info(req, res, path_info, file) call_callback(:FileCallback, req, res) return true + else + raise HTTPStatus::NotFound, "`#{req.path}' not found." end end + return false end + def check_filename(name) + if File.fnmatch("/#{@options[:NondisclosureName]}", name) + @logger.warn("the request refers nondisclosure name `#{name}'.") + raise HTTPStatus::NotFound, "`#{req.path}' not found." + end + end + + def shift_path_info(req, res, path_info, base=nil) + tmp = path_info.shift + base = base || tmp + req.path_info = path_info.join + req.script_name << base + res.filename << base + end + + def search_index_file(req, res) + @config[:DirectoryIndex].each{|index| + if file = search_file(req, res, "/"+index) + return file + end + } + return nil + end + + def search_file(req, res, basename) + langs = @options[:AcceptableLanguages] + path = res.filename + basename + if File.file?(path) + return basename + elsif langs.size > 0 + req.accept_language.each{|lang| + path_with_lang = path + ".#{lang}" + if langs.member?(lang) && File.file?(path_with_lang) + return basename + ".#{lang}" + end + } + (langs - req.accept_language).each{|lang| + path_with_lang = path + ".#{lang}" + if File.file?(path_with_lang) + return basename + ".#{lang}" + end + } + end + return nil + end + def call_callback(callback_name, req, res) if cb = @options[callback_name] cb.call(req, res) |