| 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 351
351: def call_callback(callback_name, req, res)
352: if cb = @options[callback_name]
353: cb.call(req, res)
354: end
355: end
# File lib/webrick/httpservlet/filehandler.rb, line 304
304: def check_filename(req, res, name)
305: if nondisclosure_name?(name) || windows_ambiguous_name?(name)
306: @logger.warn("the request refers nondisclosure name `#{name}'.")
307: raise HTTPStatus::NotFound, "`#{req.path}' not found."
308: end
309: end
# File lib/webrick/httpservlet/filehandler.rb, line 246
246: def exec_handler(req, res)
247: raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root
248: if set_filename(req, res)
249: handler = get_handler(req, res)
250: call_callback(:HandlerCallback, req, res)
251: h = handler.get_instance(@config, res.filename)
252: h.service(req, res)
253: return true
254: end
255: call_callback(:HandlerCallback, req, res)
256: return false
257: end
# File lib/webrick/httpservlet/filehandler.rb, line 259
259: def get_handler(req, res)
260: suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase
261: if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename
262: if @options[:AcceptableLanguages].include?($2.downcase)
263: suffix2 = $1.downcase
264: end
265: end
266: handler_table = @options[:HandlerTable]
267: return handler_table[suffix1] || handler_table[suffix2] ||
268: HandlerTable[suffix1] || HandlerTable[suffix2] ||
269: DefaultFileHandler
270: end
# File lib/webrick/httpservlet/filehandler.rb, line 363
363: def nondisclosure_name?(name)
364: @options[:NondisclosureName].each{|pattern|
365: if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
366: return true
367: end
368: }
369: return false
370: 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 prevent_directory_traversal(req, res)
203: # Preventing directory traversal on DOSISH platforms;
204: # Backslashes (0x5c) in path_info are not interpreted as special
205: # character in URI notation. So the value of path_info should be
206: # normalize before accessing to the filesystem.
207: if File::ALT_SEPARATOR
208: # File.expand_path removes the trailing path separator.
209: # Adding a character is a workaround to save it.
210: # File.expand_path("/aaa/") #=> "/aaa"
211: # File.expand_path("/aaa/" + "x") #=> "/aaa/x"
212: expanded = File.expand_path(req.path_info + "x")
213: expanded[-1, 1] = "" # remove trailing "x"
214: req.path_info = expanded
215: end
216: end
# File lib/webrick/httpservlet/filehandler.rb, line 227
227: def prevent_directory_traversal(req, res)
228: # Preventing directory traversal on Windows platforms;
229: # Backslashes (0x5c) in path_info are not interpreted as special
230: # character in URI notation. So the value of path_info should be
231: # normalize before accessing to the filesystem.
232:
233: if trailing_pathsep?(req.path_info)
234: # File.expand_path removes the trailing path separator.
235: # Adding a character is a workaround to save it.
236: # File.expand_path("/aaa/") #=> "/aaa"
237: # File.expand_path("/aaa/" + "x") #=> "/aaa/x"
238: expanded = File.expand_path(req.path_info + "x")
239: expanded.chop! # remove trailing "x"
240: else
241: expanded = File.expand_path(req.path_info)
242: end
243: req.path_info = expanded
244: end
# File lib/webrick/httpservlet/filehandler.rb, line 329
329: def search_file(req, res, basename)
330: langs = @options[:AcceptableLanguages]
331: path = res.filename + basename
332: if File.file?(path)
333: return basename
334: elsif langs.size > 0
335: req.accept_language.each{|lang|
336: path_with_lang = path + ".#{lang}"
337: if langs.member?(lang) && File.file?(path_with_lang)
338: return basename + ".#{lang}"
339: end
340: }
341: (langs - req.accept_language).each{|lang|
342: path_with_lang = path + ".#{lang}"
343: if File.file?(path_with_lang)
344: return basename + ".#{lang}"
345: end
346: }
347: end
348: return nil
349: end
# File lib/webrick/httpservlet/filehandler.rb, line 320
320: def search_index_file(req, res)
321: @config[:DirectoryIndex].each{|index|
322: if file = search_file(req, res, "/"+index)
323: return file
324: end
325: }
326: return nil
327: end
# File lib/webrick/httpservlet/filehandler.rb, line 372
372: def set_dir_list(req, res)
373: redirect_to_directory_uri(req, res)
374: unless @options[:FancyIndexing]
375: raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'"
376: end
377: local_path = res.filename
378: list = Dir::entries(local_path).collect{|name|
379: next if name == "." || name == ".."
380: next if nondisclosure_name?(name)
381: next if windows_ambiguous_name?(name)
382: st = (File::stat(File.join(local_path, name)) rescue nil)
383: if st.nil?
384: [ name, nil, -1 ]
385: elsif st.directory?
386: [ name + "/", st.mtime, -1 ]
387: else
388: [ name, st.mtime, st.size ]
389: end
390: }
391: list.compact!
392:
393: if d0 = req.query["N"]; idx = 0
394: elsif d0 = req.query["M"]; idx = 1
395: elsif d0 = req.query["S"]; idx = 2
396: else d0 = "A" ; idx = 0
397: end
398: d1 = (d0 == "A") ? "D" : "A"
399:
400: if d0 == "A"
401: list.sort!{|a,b| a[idx] <=> b[idx] }
402: else
403: list.sort!{|a,b| b[idx] <=> a[idx] }
404: end
405:
406: res['content-type'] = "text/html"
407:
408: 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"
409:
410: res.body << "<PRE>\n"
411: res.body << " <A HREF=\"?N=#{d1}\">Name</A> "
412: res.body << "<A HREF=\"?M=#{d1}\">Last modified</A> "
413: res.body << "<A HREF=\"?S=#{d1}\">Size</A>\n"
414: res.body << "<HR>\n"
415:
416: list.unshift [ "..", File::mtime(local_path+"/.."), -1 ]
417: list.each{ |name, time, size|
418: if name == ".."
419: dname = "Parent Directory"
420: elsif name.size > 25
421: dname = name.sub(/^(.{23})(.*)/){ $1 + ".." }
422: else
423: dname = name
424: end
425: s = " <A HREF=\"#{HTTPUtils::escape(name)}\">#{dname}</A>"
426: s << " " * (30 - dname.size)
427: s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22)
428: s << (size >= 0 ? size.to_s : "-") << "\n"
429: res.body << s
430: }
431: res.body << "</PRE><HR>"
432:
433: res.body << "<ADDRESS>\n\#{HTMLUtils::escape(@config[:ServerSoftware])}<BR>\nat \#{req.host}:\#{req.port}\n</ADDRESS>\n</BODY>\n</HTML>\n"
434: end
# File lib/webrick/httpservlet/filehandler.rb, line 272
272: def set_filename(req, res)
273: res.filename = @root.dup
274: path_info = req.path_info.scan(%r|/[^/]*|)
275:
276: path_info.unshift("") # dummy for checking @root dir
277: while base = path_info.first
278: break if base == "/"
279: break unless File.directory?(File.expand_path(res.filename + base))
280: shift_path_info(req, res, path_info)
281: call_callback(:DirectoryCallback, req, res)
282: end
283:
284: if base = path_info.first
285: if base == "/"
286: if file = search_index_file(req, res)
287: shift_path_info(req, res, path_info, file)
288: call_callback(:FileCallback, req, res)
289: return true
290: end
291: shift_path_info(req, res, path_info)
292: elsif file = search_file(req, res, base)
293: shift_path_info(req, res, path_info, file)
294: call_callback(:FileCallback, req, res)
295: return true
296: else
297: raise HTTPStatus::NotFound, "`#{req.path}' not found."
298: end
299: end
300:
301: return false
302: end
# File lib/webrick/httpservlet/filehandler.rb, line 311
311: def shift_path_info(req, res, path_info, base=nil)
312: tmp = path_info.shift
313: base = base || tmp
314: req.path_info = path_info.join
315: req.script_name << base
316: res.filename = File.expand_path(res.filename + base)
317: check_filename(req, res, File.basename(res.filename))
318: end
# File lib/webrick/httpservlet/filehandler.rb, line 218
218: def trailing_pathsep?(path)
219: # check for trailing path separator:
220: # File.dirname("/aaaa/bbbb/") #=> "/aaaa")
221: # File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb")
222: # File.dirname("/aaaa/bbbb") #=> "/aaaa")
223: # File.dirname("/aaaa/bbbbx") #=> "/aaaa")
224: return File.dirname(path) != File.dirname(path+"x")
225: end