Class | WEBrick::HTTPServlet::FileHandler |
In: |
lib/webrick/httpservlet/filehandler.rb
|
Parent: | AbstractServlet |
HandlerTable | = | Hash.new |
# File lib/webrick/httpservlet/filehandler.rb, line 131 131: def self.add_handler(suffix, handler) 132: HandlerTable[suffix] = handler 133: end
# File lib/webrick/httpservlet/filehandler.rb, line 139 139: def initialize(server, root, options={}, default=Config::FileHandler) 140: @config = server.config 141: @logger = @config[:Logger] 142: @root = File.expand_path(root) 143: if options == true || options == false 144: options = { :FancyIndexing => options } 145: end 146: @options = default.dup.update(options) 147: end
# File lib/webrick/httpservlet/filehandler.rb, line 135 135: def self.remove_handler(suffix) 136: HandlerTable.delete(suffix) 137: end
# File lib/webrick/httpservlet/filehandler.rb, line 170 170: def do_GET(req, res) 171: unless exec_handler(req, res) 172: set_dir_list(req, res) 173: end 174: end
# File lib/webrick/httpservlet/filehandler.rb, line 182 182: def do_OPTIONS(req, res) 183: unless exec_handler(req, res) 184: super(req, res) 185: end 186: end
# File lib/webrick/httpservlet/filehandler.rb, line 176 176: def do_POST(req, res) 177: unless exec_handler(req, res) 178: raise HTTPStatus::NotFound, "`#{req.path}' not found." 179: end 180: end
# File lib/webrick/httpservlet/filehandler.rb, line 149 149: def service(req, res) 150: # if this class is mounted on "/" and /~username is requested. 151: # we're going to override path informations before invoking service. 152: if defined?(Etc) && @options[:UserDir] && req.script_name.empty? 153: if %r|^(/~([^/]+))| =~ req.path_info 154: script_name, user = $1, $2 155: path_info = $' 156: begin 157: passwd = Etc::getpwnam(user) 158: @root = File::join(passwd.dir, @options[:UserDir]) 159: req.script_name = script_name 160: req.path_info = path_info 161: rescue 162: @logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed" 163: end 164: end 165: end 166: prevent_directory_traversal(req, res) 167: super(req, res) 168: end
# File lib/webrick/httpservlet/filehandler.rb, line 335 335: def call_callback(callback_name, req, res) 336: if cb = @options[callback_name] 337: cb.call(req, res) 338: end 339: end
# File lib/webrick/httpservlet/filehandler.rb, line 288 288: def check_filename(req, res, name) 289: if nondisclosure_name?(name) || windows_ambiguous_name?(name) 290: @logger.warn("the request refers nondisclosure name `#{name}'.") 291: raise HTTPStatus::NotFound, "`#{req.path}' not found." 292: end 293: end
# File lib/webrick/httpservlet/filehandler.rb, line 230 230: def exec_handler(req, res) 231: raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root 232: if set_filename(req, res) 233: handler = get_handler(req, res) 234: call_callback(:HandlerCallback, req, res) 235: h = handler.get_instance(@config, res.filename) 236: h.service(req, res) 237: return true 238: end 239: call_callback(:HandlerCallback, req, res) 240: return false 241: end
# File lib/webrick/httpservlet/filehandler.rb, line 243 243: def get_handler(req, res) 244: suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase 245: if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename 246: if @options[:AcceptableLanguages].include?($2.downcase) 247: suffix2 = $1.downcase 248: end 249: end 250: handler_table = @options[:HandlerTable] 251: return handler_table[suffix1] || handler_table[suffix2] || 252: HandlerTable[suffix1] || HandlerTable[suffix2] || 253: DefaultFileHandler 254: end
# File lib/webrick/httpservlet/filehandler.rb, line 347 347: def nondisclosure_name?(name) 348: @options[:NondisclosureName].each{|pattern| 349: if File.fnmatch(pattern, name, File::FNM_CASEFOLD) 350: return true 351: end 352: } 353: return false 354: end
# File lib/webrick/httpservlet/filehandler.rb, line 211 211: def prevent_directory_traversal(req, res) 212: # Preventing directory traversal on Windows platforms; 213: # Backslashes (0x5c) in path_info are not interpreted as special 214: # character in URI notation. So the value of path_info should be 215: # normalize before accessing to the filesystem. 216: 217: if trailing_pathsep?(req.path_info) 218: # File.expand_path removes the trailing path separator. 219: # Adding a character is a workaround to save it. 220: # File.expand_path("/aaa/") #=> "/aaa" 221: # File.expand_path("/aaa/" + "x") #=> "/aaa/x" 222: expanded = File.expand_path(req.path_info + "x") 223: expanded.chop! # remove trailing "x" 224: else 225: expanded = File.expand_path(req.path_info) 226: end 227: req.path_info = expanded 228: end
# File lib/webrick/httpservlet/filehandler.rb, line 313 313: def search_file(req, res, basename) 314: langs = @options[:AcceptableLanguages] 315: path = res.filename + basename 316: if File.file?(path) 317: return basename 318: elsif langs.size > 0 319: req.accept_language.each{|lang| 320: path_with_lang = path + ".#{lang}" 321: if langs.member?(lang) && File.file?(path_with_lang) 322: return basename + ".#{lang}" 323: end 324: } 325: (langs - req.accept_language).each{|lang| 326: path_with_lang = path + ".#{lang}" 327: if File.file?(path_with_lang) 328: return basename + ".#{lang}" 329: end 330: } 331: end 332: return nil 333: end
# File lib/webrick/httpservlet/filehandler.rb, line 304 304: def search_index_file(req, res) 305: @config[:DirectoryIndex].each{|index| 306: if file = search_file(req, res, "/"+index) 307: return file 308: end 309: } 310: return nil 311: end
# File lib/webrick/httpservlet/filehandler.rb, line 356 356: def set_dir_list(req, res) 357: redirect_to_directory_uri(req, res) 358: unless @options[:FancyIndexing] 359: raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'" 360: end 361: local_path = res.filename 362: list = Dir::entries(local_path).collect{|name| 363: next if name == "." || name == ".." 364: next if nondisclosure_name?(name) 365: next if windows_ambiguous_name?(name) 366: st = (File::stat(File.join(local_path, name)) rescue nil) 367: if st.nil? 368: [ name, nil, -1 ] 369: elsif st.directory? 370: [ name + "/", st.mtime, -1 ] 371: else 372: [ name, st.mtime, st.size ] 373: end 374: } 375: list.compact! 376: 377: if d0 = req.query["N"]; idx = 0 378: elsif d0 = req.query["M"]; idx = 1 379: elsif d0 = req.query["S"]; idx = 2 380: else d0 = "A" ; idx = 0 381: end 382: d1 = (d0 == "A") ? "D" : "A" 383: 384: if d0 == "A" 385: list.sort!{|a,b| a[idx] <=> b[idx] } 386: else 387: list.sort!{|a,b| b[idx] <=> a[idx] } 388: end 389: 390: res['content-type'] = "text/html" 391: 392: res.body = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<HTML>\n<HEAD><TITLE>Index of \#{HTMLUtils::escape(req.path)}</TITLE></HEAD>\n<BODY>\n<H1>Index of \#{HTMLUtils::escape(req.path)}</H1>\n" 393: 394: res.body << "<PRE>\n" 395: res.body << " <A HREF=\"?N=#{d1}\">Name</A> " 396: res.body << "<A HREF=\"?M=#{d1}\">Last modified</A> " 397: res.body << "<A HREF=\"?S=#{d1}\">Size</A>\n" 398: res.body << "<HR>\n" 399: 400: list.unshift [ "..", File::mtime(local_path+"/.."), -1 ] 401: list.each{ |name, time, size| 402: if name == ".." 403: dname = "Parent Directory" 404: elsif name.size > 25 405: dname = name.sub(/^(.{23})(.*)/){ $1 + ".." } 406: else 407: dname = name 408: end 409: s = " <A HREF=\"#{HTTPUtils::escape(name)}\">#{dname}</A>" 410: s << " " * (30 - dname.size) 411: s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22) 412: s << (size >= 0 ? size.to_s : "-") << "\n" 413: res.body << s 414: } 415: res.body << "</PRE><HR>" 416: 417: res.body << "<ADDRESS>\n\#{HTMLUtils::escape(@config[:ServerSoftware])}<BR>\nat \#{req.host}:\#{req.port}\n</ADDRESS>\n</BODY>\n</HTML>\n" 418: end
# File lib/webrick/httpservlet/filehandler.rb, line 256 256: def set_filename(req, res) 257: res.filename = @root.dup 258: path_info = req.path_info.scan(%r|/[^/]*|) 259: 260: path_info.unshift("") # dummy for checking @root dir 261: while base = path_info.first 262: break if base == "/" 263: break unless File.directory?(File.expand_path(res.filename + base)) 264: shift_path_info(req, res, path_info) 265: call_callback(:DirectoryCallback, req, res) 266: end 267: 268: if base = path_info.first 269: if base == "/" 270: if file = search_index_file(req, res) 271: shift_path_info(req, res, path_info, file) 272: call_callback(:FileCallback, req, res) 273: return true 274: end 275: shift_path_info(req, res, path_info) 276: elsif file = search_file(req, res, base) 277: shift_path_info(req, res, path_info, file) 278: call_callback(:FileCallback, req, res) 279: return true 280: else 281: raise HTTPStatus::NotFound, "`#{req.path}' not found." 282: end 283: end 284: 285: return false 286: end
# File lib/webrick/httpservlet/filehandler.rb, line 295 295: def shift_path_info(req, res, path_info, base=nil) 296: tmp = path_info.shift 297: base = base || tmp 298: req.path_info = path_info.join 299: req.script_name << base 300: res.filename = File.expand_path(res.filename + base) 301: check_filename(req, res, File.basename(res.filename)) 302: end
RFC3253: Versioning Extensions to WebDAV
(Web Distributed Authoring and Versioning)
VERSION-CONTROL REPORT CHECKOUT CHECK_IN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE ACTIVITY
# File lib/webrick/httpservlet/filehandler.rb, line 202 202: def trailing_pathsep?(path) 203: # check for trailing path separator: 204: # File.dirname("/aaaa/bbbb/") #=> "/aaaa") 205: # File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb") 206: # File.dirname("/aaaa/bbbb") #=> "/aaaa") 207: # File.dirname("/aaaa/bbbbx") #=> "/aaaa") 208: return File.dirname(path) != File.dirname(path+"x") 209: end