| 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 322
322: def call_callback(callback_name, req, res)
323: if cb = @options[callback_name]
324: cb.call(req, res)
325: end
326: end
# File lib/webrick/httpservlet/filehandler.rb, line 274
274: def check_filename(req, res, name)
275: @options[:NondisclosureName].each{|pattern|
276: if File.fnmatch("/#{pattern}", name, File::FNM_CASEFOLD)
277: @logger.warn("the request refers nondisclosure name `#{name}'.")
278: raise HTTPStatus::NotFound, "`#{req.path}' not found."
279: end
280: }
281: end
# File lib/webrick/httpservlet/filehandler.rb, line 218
218: def exec_handler(req, res)
219: raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root
220: if set_filename(req, res)
221: handler = get_handler(req)
222: call_callback(:HandlerCallback, req, res)
223: h = handler.get_instance(@config, res.filename)
224: h.service(req, res)
225: return true
226: end
227: call_callback(:HandlerCallback, req, res)
228: return false
229: end
# File lib/webrick/httpservlet/filehandler.rb, line 231
231: def get_handler(req)
232: suffix1 = (/\.(\w+)$/ =~ req.script_name) && $1.downcase
233: suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ req.script_name) && $1.downcase
234: handler_table = @options[:HandlerTable]
235: return handler_table[suffix1] || handler_table[suffix2] ||
236: HandlerTable[suffix1] || HandlerTable[suffix2] ||
237: DefaultFileHandler
238: end
# File lib/webrick/httpservlet/filehandler.rb, line 328
328: def nondisclosure_name?(name)
329: @options[:NondisclosureName].each{|pattern|
330: if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
331: return true
332: end
333: }
334: return false
335: 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 300
300: def search_file(req, res, basename)
301: langs = @options[:AcceptableLanguages]
302: path = res.filename + basename
303: if File.file?(path)
304: return basename
305: elsif langs.size > 0
306: req.accept_language.each{|lang|
307: path_with_lang = path + ".#{lang}"
308: if langs.member?(lang) && File.file?(path_with_lang)
309: return basename + ".#{lang}"
310: end
311: }
312: (langs - req.accept_language).each{|lang|
313: path_with_lang = path + ".#{lang}"
314: if File.file?(path_with_lang)
315: return basename + ".#{lang}"
316: end
317: }
318: end
319: return nil
320: end
# File lib/webrick/httpservlet/filehandler.rb, line 291
291: def search_index_file(req, res)
292: @config[:DirectoryIndex].each{|index|
293: if file = search_file(req, res, "/"+index)
294: return file
295: end
296: }
297: return nil
298: end
# File lib/webrick/httpservlet/filehandler.rb, line 337
337: def set_dir_list(req, res)
338: redirect_to_directory_uri(req, res)
339: unless @options[:FancyIndexing]
340: raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'"
341: end
342: local_path = res.filename
343: list = Dir::entries(local_path).collect{|name|
344: next if name == "." || name == ".."
345: next if nondisclosure_name?(name)
346: st = (File::stat(local_path + name) rescue nil)
347: if st.nil?
348: [ name, nil, -1 ]
349: elsif st.directory?
350: [ name + "/", st.mtime, -1 ]
351: else
352: [ name, st.mtime, st.size ]
353: end
354: }
355: list.compact!
356:
357: if d0 = req.query["N"]; idx = 0
358: elsif d0 = req.query["M"]; idx = 1
359: elsif d0 = req.query["S"]; idx = 2
360: else d0 = "A" ; idx = 0
361: end
362: d1 = (d0 == "A") ? "D" : "A"
363:
364: if d0 == "A"
365: list.sort!{|a,b| a[idx] <=> b[idx] }
366: else
367: list.sort!{|a,b| b[idx] <=> a[idx] }
368: end
369:
370: res['content-type'] = "text/html"
371:
372: 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"
373:
374: res.body << "<PRE>\n"
375: res.body << " <A HREF=\"?N=#{d1}\">Name</A> "
376: res.body << "<A HREF=\"?M=#{d1}\">Last modified</A> "
377: res.body << "<A HREF=\"?S=#{d1}\">Size</A>\n"
378: res.body << "<HR>\n"
379:
380: list.unshift [ "..", File::mtime(local_path+".."), -1 ]
381: list.each{ |name, time, size|
382: if name == ".."
383: dname = "Parent Directory"
384: elsif name.size > 25
385: dname = name.sub(/^(.{23})(.*)/){ $1 + ".." }
386: else
387: dname = name
388: end
389: s = " <A HREF=\"#{HTTPUtils::escape(name)}\">#{dname}</A>"
390: s << " " * (30 - dname.size)
391: s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22)
392: s << (size >= 0 ? size.to_s : "-") << "\n"
393: res.body << s
394: }
395: res.body << "</PRE><HR>"
396:
397: res.body << "<ADDRESS>\n\#{HTMLUtils::escape(@config[:ServerSoftware])}<BR>\nat \#{req.host}:\#{req.port}\n</ADDRESS>\n</BODY>\n</HTML>\n"
398: end
# File lib/webrick/httpservlet/filehandler.rb, line 240
240: def set_filename(req, res)
241: res.filename = @root.dup
242: path_info = req.path_info.scan(%r|/[^/]*|)
243:
244: path_info.unshift("") # dummy for checking @root dir
245: while base = path_info.first
246: check_filename(req, res, base)
247: break if base == "/"
248: break unless File.directory?(res.filename + base)
249: shift_path_info(req, res, path_info)
250: call_callback(:DirectoryCallback, req, res)
251: end
252:
253: if base = path_info.first
254: check_filename(req, res, base)
255: if base == "/"
256: if file = search_index_file(req, res)
257: shift_path_info(req, res, path_info, file)
258: call_callback(:FileCallback, req, res)
259: return true
260: end
261: shift_path_info(req, res, path_info)
262: elsif file = search_file(req, res, base)
263: shift_path_info(req, res, path_info, file)
264: call_callback(:FileCallback, req, res)
265: return true
266: else
267: raise HTTPStatus::NotFound, "`#{req.path}' not found."
268: end
269: end
270:
271: return false
272: end