summaryrefslogtreecommitdiff
path: root/ruby_1_9_3/lib/webrick/httpservlet
diff options
context:
space:
mode:
Diffstat (limited to 'ruby_1_9_3/lib/webrick/httpservlet')
-rw-r--r--ruby_1_9_3/lib/webrick/httpservlet/abstract.rb153
-rw-r--r--ruby_1_9_3/lib/webrick/httpservlet/cgi_runner.rb46
-rw-r--r--ruby_1_9_3/lib/webrick/httpservlet/cgihandler.rb108
-rw-r--r--ruby_1_9_3/lib/webrick/httpservlet/erbhandler.rb87
-rw-r--r--ruby_1_9_3/lib/webrick/httpservlet/filehandler.rb470
-rw-r--r--ruby_1_9_3/lib/webrick/httpservlet/prochandler.rb33
6 files changed, 897 insertions, 0 deletions
diff --git a/ruby_1_9_3/lib/webrick/httpservlet/abstract.rb b/ruby_1_9_3/lib/webrick/httpservlet/abstract.rb
new file mode 100644
index 0000000000..0d5c5ae48d
--- /dev/null
+++ b/ruby_1_9_3/lib/webrick/httpservlet/abstract.rb
@@ -0,0 +1,153 @@
+#
+# httpservlet.rb -- HTTPServlet Module
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $
+
+require 'thread'
+
+require 'webrick/htmlutils'
+require 'webrick/httputils'
+require 'webrick/httpstatus'
+
+module WEBrick
+ module HTTPServlet
+ class HTTPServletError < StandardError; end
+
+ ##
+ # AbstractServlet allows HTTP server modules to be reused across multiple
+ # servers and allows encapsulation of functionality.
+ #
+ # By default a servlet will respond to GET, HEAD (through an alias to GET)
+ # and OPTIONS requests.
+ #
+ # By default a new servlet is initialized for every request. A servlet
+ # instance can be reused by overriding ::get_instance in the
+ # AbstractServlet subclass.
+ #
+ # == A Simple Servlet
+ #
+ # class Simple < WEBrick::HTTPServlet::AbstractServlet
+ # def do_GET request, response
+ # status, content_type, body = do_stuff_with request
+ #
+ # response.status = status
+ # response['Content-Type'] = content_type
+ # response.body = body
+ # end
+ #
+ # def do_stuff_with request
+ # return 200, 'text/plain', 'you got a page'
+ # end
+ # end
+ #
+ # This servlet can be mounted on a server at a given path:
+ #
+ # server.mount '/simple', Simple
+ #
+ # == Servlet Configuration
+ #
+ # Servlets can be configured via initialize. The first argument is the
+ # HTTP server the servlet is being initialized for.
+ #
+ # class Configureable < Simple
+ # def initialize server, color, size
+ # super server
+ # @color = color
+ # @size = size
+ # end
+ #
+ # def do_stuff_with request
+ # content = "<p " \
+ # %q{style="color: #{@color}; font-size: #{@size}"} \
+ # ">Hello, World!"
+ #
+ # return 200, "text/html", content
+ # end
+ # end
+ #
+ # This servlet must be provided two arguments at mount time:
+ #
+ # server.mount '/configurable', Configurable, 'red', '2em'
+
+ class AbstractServlet
+
+ ##
+ # Factory for servlet instances that will handle a request from +server+
+ # using +options+ from the mount point. By default a new servlet
+ # instance is created for every call.
+
+ def self.get_instance(server, *options)
+ self.new(server, *options)
+ end
+
+ ##
+ # Initializes a new servlet for +server+ using +options+ which are
+ # stored as-is in +@options+. +@logger+ is also provided.
+
+ def initialize(server, *options)
+ @server = @config = server
+ @logger = @server[:Logger]
+ @options = options
+ end
+
+ ##
+ # Dispatches to a +do_+ method based on +req+ if such a method is
+ # available. (+do_GET+ for a GET request). Raises a MethodNotAllowed
+ # exception if the method is not implemented.
+
+ def service(req, res)
+ method_name = "do_" + req.request_method.gsub(/-/, "_")
+ if respond_to?(method_name)
+ __send__(method_name, req, res)
+ else
+ raise HTTPStatus::MethodNotAllowed,
+ "unsupported method `#{req.request_method}'."
+ end
+ end
+
+ ##
+ # Raises a NotFound exception
+
+ def do_GET(req, res)
+ raise HTTPStatus::NotFound, "not found."
+ end
+
+ ##
+ # Dispatches to do_GET
+
+ def do_HEAD(req, res)
+ do_GET(req, res)
+ end
+
+ ##
+ # Returns the allowed HTTP request methods
+
+ def do_OPTIONS(req, res)
+ m = self.methods.grep(/\Ado_([A-Z]+)\z/) {$1}
+ m.sort!
+ res["allow"] = m.join(",")
+ end
+
+ private
+
+ ##
+ # Redirects to a path ending in /
+
+ def redirect_to_directory_uri(req, res)
+ if req.path[-1] != ?/
+ location = WEBrick::HTTPUtils.escape_path(req.path + "/")
+ if req.query_string && req.query_string.bytesize > 0
+ location << "?" << req.query_string
+ end
+ res.set_redirect(HTTPStatus::MovedPermanently, location)
+ end
+ end
+ end
+
+ end
+end
diff --git a/ruby_1_9_3/lib/webrick/httpservlet/cgi_runner.rb b/ruby_1_9_3/lib/webrick/httpservlet/cgi_runner.rb
new file mode 100644
index 0000000000..32ecb6fe00
--- /dev/null
+++ b/ruby_1_9_3/lib/webrick/httpservlet/cgi_runner.rb
@@ -0,0 +1,46 @@
+#
+# cgi_runner.rb -- CGI launcher.
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: cgi_runner.rb,v 1.9 2002/09/25 11:33:15 gotoyuzo Exp $
+
+def sysread(io, size)
+ buf = ""
+ while size > 0
+ tmp = io.sysread(size)
+ buf << tmp
+ size -= tmp.bytesize
+ end
+ return buf
+end
+
+STDIN.binmode
+
+len = sysread(STDIN, 8).to_i
+out = sysread(STDIN, len)
+STDOUT.reopen(open(out, "w"))
+
+len = sysread(STDIN, 8).to_i
+err = sysread(STDIN, len)
+STDERR.reopen(open(err, "w"))
+
+len = sysread(STDIN, 8).to_i
+dump = sysread(STDIN, len)
+hash = Marshal.restore(dump)
+ENV.keys.each{|name| ENV.delete(name) }
+hash.each{|k, v| ENV[k] = v if v }
+
+dir = File::dirname(ENV["SCRIPT_FILENAME"])
+Dir::chdir dir
+
+if ARGV[0]
+ argv = ARGV.dup
+ argv << ENV["SCRIPT_FILENAME"]
+ exec(*argv)
+ # NOTREACHED
+end
+exec ENV["SCRIPT_FILENAME"]
diff --git a/ruby_1_9_3/lib/webrick/httpservlet/cgihandler.rb b/ruby_1_9_3/lib/webrick/httpservlet/cgihandler.rb
new file mode 100644
index 0000000000..1976ae6948
--- /dev/null
+++ b/ruby_1_9_3/lib/webrick/httpservlet/cgihandler.rb
@@ -0,0 +1,108 @@
+#
+# cgihandler.rb -- CGIHandler Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: cgihandler.rb,v 1.27 2003/03/21 19:56:01 gotoyuzo Exp $
+
+require 'rbconfig'
+require 'tempfile'
+require 'webrick/config'
+require 'webrick/httpservlet/abstract'
+
+module WEBrick
+ module HTTPServlet
+
+ class CGIHandler < AbstractServlet
+ Ruby = RbConfig.ruby
+ CGIRunner = "\"#{Ruby}\" \"#{WEBrick::Config::LIBDIR}/httpservlet/cgi_runner.rb\""
+
+ def initialize(server, name)
+ super(server, name)
+ @script_filename = name
+ @tempdir = server[:TempDir]
+ @cgicmd = "#{CGIRunner} #{server[:CGIInterpreter]}"
+ end
+
+ def do_GET(req, res)
+ data = nil
+ status = -1
+
+ cgi_in = IO::popen(@cgicmd, "wb")
+ cgi_out = Tempfile.new("webrick.cgiout.", @tempdir, mode: IO::BINARY)
+ cgi_out.set_encoding("ASCII-8BIT")
+ cgi_err = Tempfile.new("webrick.cgierr.", @tempdir, mode: IO::BINARY)
+ cgi_err.set_encoding("ASCII-8BIT")
+ begin
+ cgi_in.sync = true
+ meta = req.meta_vars
+ meta["SCRIPT_FILENAME"] = @script_filename
+ meta["PATH"] = @config[:CGIPathEnv]
+ if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+ meta["SystemRoot"] = ENV["SystemRoot"]
+ end
+ dump = Marshal.dump(meta)
+
+ cgi_in.write("%8d" % cgi_out.path.bytesize)
+ cgi_in.write(cgi_out.path)
+ cgi_in.write("%8d" % cgi_err.path.bytesize)
+ cgi_in.write(cgi_err.path)
+ cgi_in.write("%8d" % dump.bytesize)
+ cgi_in.write(dump)
+
+ if req.body and req.body.bytesize > 0
+ cgi_in.write(req.body)
+ end
+ ensure
+ cgi_in.close
+ status = $?.exitstatus
+ sleep 0.1 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+ data = cgi_out.read
+ cgi_out.close(true)
+ if errmsg = cgi_err.read
+ if errmsg.bytesize > 0
+ @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg)
+ end
+ end
+ cgi_err.close(true)
+ end
+
+ if status != 0
+ @logger.error("CGIHandler: #{@script_filename} exit with #{status}")
+ end
+
+ data = "" unless data
+ raw_header, body = data.split(/^[\xd\xa]+/, 2)
+ raise HTTPStatus::InternalServerError,
+ "Premature end of script headers: #{@script_filename}" if body.nil?
+
+ begin
+ header = HTTPUtils::parse_header(raw_header)
+ if /^(\d+)/ =~ header['status'][0]
+ res.status = $1.to_i
+ header.delete('status')
+ end
+ if header.has_key?('location')
+ # RFC 3875 6.2.3, 6.2.4
+ res.status = 302 unless (300...400) === res.status
+ end
+ if header.has_key?('set-cookie')
+ header['set-cookie'].each{|k|
+ res.cookies << Cookie.parse_set_cookie(k)
+ }
+ header.delete('set-cookie')
+ end
+ header.each{|key, val| res[key] = val.join(", ") }
+ rescue => ex
+ raise HTTPStatus::InternalServerError, ex.message
+ end
+ res.body = body
+ end
+ alias do_POST do_GET
+ end
+
+ end
+end
diff --git a/ruby_1_9_3/lib/webrick/httpservlet/erbhandler.rb b/ruby_1_9_3/lib/webrick/httpservlet/erbhandler.rb
new file mode 100644
index 0000000000..34b4b9e68b
--- /dev/null
+++ b/ruby_1_9_3/lib/webrick/httpservlet/erbhandler.rb
@@ -0,0 +1,87 @@
+#
+# erbhandler.rb -- ERBHandler Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: erbhandler.rb,v 1.25 2003/02/24 19:25:31 gotoyuzo Exp $
+
+require 'webrick/httpservlet/abstract.rb'
+
+require 'erb'
+
+module WEBrick
+ module HTTPServlet
+
+ ##
+ # ERBHandler evaluates an ERB file and returns the result. This handler
+ # is automatically used if there are .rhtml files in a directory served by
+ # the FileHandler.
+ #
+ # ERBHandler supports GET and POST methods.
+ #
+ # The ERB file is evaluated with the local variables +servlet_request+ and
+ # +servlet_response+ which are a WEBrick::HTTPRequest and
+ # WEBrick::HTTPResponse respectively.
+ #
+ # Example .rhtml file:
+ #
+ # Request to <%= servlet_request.request_uri %>
+ #
+ # Query params <%= servlet_request.query.inspect %>
+
+ class ERBHandler < AbstractServlet
+
+ ##
+ # Creates a new ERBHandler on +server+ that will evaluate and serve the
+ # ERB file +name+
+
+ def initialize(server, name)
+ super(server, name)
+ @script_filename = name
+ end
+
+ ##
+ # Handles GET requests
+
+ def do_GET(req, res)
+ unless defined?(ERB)
+ @logger.warn "#{self.class}: ERB not defined."
+ raise HTTPStatus::Forbidden, "ERBHandler cannot work."
+ end
+ begin
+ data = open(@script_filename){|io| io.read }
+ res.body = evaluate(ERB.new(data), req, res)
+ res['content-type'] ||=
+ HTTPUtils::mime_type(@script_filename, @config[:MimeTypes])
+ rescue StandardError => ex
+ raise
+ rescue Exception => ex
+ @logger.error(ex)
+ raise HTTPStatus::InternalServerError, ex.message
+ end
+ end
+
+ ##
+ # Handles POST requests
+
+ alias do_POST do_GET
+
+ private
+
+ ##
+ # Evaluates +erb+ providing +servlet_request+ and +servlet_response+ as
+ # local variables.
+
+ def evaluate(erb, servlet_request, servlet_response)
+ Module.new.module_eval{
+ servlet_request.meta_vars
+ servlet_request.query
+ erb.result(binding)
+ }
+ end
+ end
+ end
+end
diff --git a/ruby_1_9_3/lib/webrick/httpservlet/filehandler.rb b/ruby_1_9_3/lib/webrick/httpservlet/filehandler.rb
new file mode 100644
index 0000000000..8736f5773a
--- /dev/null
+++ b/ruby_1_9_3/lib/webrick/httpservlet/filehandler.rb
@@ -0,0 +1,470 @@
+#
+# filehandler.rb -- FileHandler Module
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: filehandler.rb,v 1.44 2003/06/07 01:34:51 gotoyuzo Exp $
+
+require 'thread'
+require 'time'
+
+require 'webrick/htmlutils'
+require 'webrick/httputils'
+require 'webrick/httpstatus'
+
+module WEBrick
+ module HTTPServlet
+
+ class DefaultFileHandler < AbstractServlet
+ def initialize(server, local_path)
+ super(server, local_path)
+ @local_path = local_path
+ end
+
+ def do_GET(req, res)
+ st = File::stat(@local_path)
+ mtime = st.mtime
+ res['etag'] = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i)
+
+ if not_modified?(req, res, mtime, res['etag'])
+ res.body = ''
+ raise HTTPStatus::NotModified
+ elsif req['range']
+ make_partial_content(req, res, @local_path, st.size)
+ raise HTTPStatus::PartialContent
+ else
+ mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes])
+ res['content-type'] = mtype
+ res['content-length'] = st.size
+ res['last-modified'] = mtime.httpdate
+ res.body = open(@local_path, "rb")
+ end
+ end
+
+ def not_modified?(req, res, mtime, etag)
+ if ir = req['if-range']
+ begin
+ if Time.httpdate(ir) >= mtime
+ return true
+ end
+ rescue
+ if HTTPUtils::split_header_value(ir).member?(res['etag'])
+ return true
+ end
+ end
+ end
+
+ if (ims = req['if-modified-since']) && Time.parse(ims) >= mtime
+ return true
+ end
+
+ if (inm = req['if-none-match']) &&
+ HTTPUtils::split_header_value(inm).member?(res['etag'])
+ return true
+ end
+
+ return false
+ end
+
+ def make_partial_content(req, res, filename, filesize)
+ mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes])
+ unless ranges = HTTPUtils::parse_range_header(req['range'])
+ raise HTTPStatus::BadRequest,
+ "Unrecognized range-spec: \"#{req['range']}\""
+ end
+ open(filename, "rb"){|io|
+ if ranges.size > 1
+ time = Time.now
+ boundary = "#{time.sec}_#{time.usec}_#{Process::pid}"
+ body = ''
+ ranges.each{|range|
+ first, last = prepare_range(range, filesize)
+ next if first < 0
+ io.pos = first
+ content = io.read(last-first+1)
+ body << "--" << boundary << CRLF
+ body << "Content-Type: #{mtype}" << CRLF
+ body << "Content-Range: bytes #{first}-#{last}/#{filesize}" << CRLF
+ body << CRLF
+ body << content
+ body << CRLF
+ }
+ raise HTTPStatus::RequestRangeNotSatisfiable if body.empty?
+ body << "--" << boundary << "--" << CRLF
+ res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
+ res.body = body
+ elsif range = ranges[0]
+ first, last = prepare_range(range, filesize)
+ raise HTTPStatus::RequestRangeNotSatisfiable if first < 0
+ if last == filesize - 1
+ content = io.dup
+ content.pos = first
+ else
+ io.pos = first
+ content = io.read(last-first+1)
+ end
+ res['content-type'] = mtype
+ res['content-range'] = "bytes #{first}-#{last}/#{filesize}"
+ res['content-length'] = last - first + 1
+ res.body = content
+ else
+ raise HTTPStatus::BadRequest
+ end
+ }
+ end
+
+ def prepare_range(range, filesize)
+ first = range.first < 0 ? filesize + range.first : range.first
+ return -1, -1 if first < 0 || first >= filesize
+ last = range.last < 0 ? filesize + range.last : range.last
+ last = filesize - 1 if last >= filesize
+ return first, last
+ end
+ end
+
+ ##
+ # Serves files from a directory
+
+ class FileHandler < AbstractServlet
+ HandlerTable = Hash.new
+
+ ##
+ # Allow custom handling of requests for files with +suffix+ by class
+ # +handler+
+
+ def self.add_handler(suffix, handler)
+ HandlerTable[suffix] = handler
+ end
+
+ ##
+ # Remove custom handling of requests for files with +suffix+
+
+ def self.remove_handler(suffix)
+ HandlerTable.delete(suffix)
+ end
+
+ ##
+ # Creates a FileHandler servlet on +server+ that serves files starting
+ # at directory +root+
+ #
+ # If +options+ is a Hash the following keys are allowed:
+ #
+ # :AcceptableLanguages:: Array of languages allowed for accept-language
+ # :DirectoryCallback:: Allows preprocessing of directory requests
+ # :FancyIndexing:: If true, show an index for directories
+ # :FileCallback:: Allows preprocessing of file requests
+ # :HandlerCallback:: Allows preprocessing of requests
+ # :HandlerTable:: Maps file suffixes to file handlers.
+ # DefaultFileHandler is used by default but any servlet
+ # can be used.
+ # :NondisclosureName:: Do not show files matching this array of globs
+ # :UserDir:: Directory inside ~user to serve content from for /~user
+ # requests. Only works if mounted on /
+ #
+ # If +options+ is true or false then +:FancyIndexing+ is enabled or
+ # disabled respectively.
+
+ def initialize(server, root, options={}, default=Config::FileHandler)
+ @config = server.config
+ @logger = @config[:Logger]
+ @root = File.expand_path(root)
+ if options == true || options == false
+ options = { :FancyIndexing => options }
+ end
+ @options = default.dup.update(options)
+ end
+
+ def service(req, res)
+ # if this class is mounted on "/" and /~username is requested.
+ # we're going to override path informations before invoking service.
+ if defined?(Etc) && @options[:UserDir] && req.script_name.empty?
+ if %r|^(/~([^/]+))| =~ req.path_info
+ script_name, user = $1, $2
+ path_info = $'
+ begin
+ passwd = Etc::getpwnam(user)
+ @root = File::join(passwd.dir, @options[:UserDir])
+ req.script_name = script_name
+ req.path_info = path_info
+ rescue
+ @logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed"
+ end
+ end
+ end
+ prevent_directory_traversal(req, res)
+ super(req, res)
+ end
+
+ def do_GET(req, res)
+ unless exec_handler(req, res)
+ set_dir_list(req, res)
+ end
+ end
+
+ def do_POST(req, res)
+ unless exec_handler(req, res)
+ raise HTTPStatus::NotFound, "`#{req.path}' not found."
+ end
+ end
+
+ def do_OPTIONS(req, res)
+ unless exec_handler(req, res)
+ super(req, res)
+ end
+ end
+
+ # ToDo
+ # RFC2518: HTTP Extensions for Distributed Authoring -- WEBDAV
+ #
+ # PROPFIND PROPPATCH MKCOL DELETE PUT COPY MOVE
+ # LOCK UNLOCK
+
+ # RFC3253: Versioning Extensions to WebDAV
+ # (Web Distributed Authoring and Versioning)
+ #
+ # VERSION-CONTROL REPORT CHECKOUT CHECK_IN UNCHECKOUT
+ # MKWORKSPACE UPDATE LABEL MERGE ACTIVITY
+
+ private
+
+ def trailing_pathsep?(path)
+ # check for trailing path separator:
+ # File.dirname("/aaaa/bbbb/") #=> "/aaaa")
+ # File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb")
+ # File.dirname("/aaaa/bbbb") #=> "/aaaa")
+ # File.dirname("/aaaa/bbbbx") #=> "/aaaa")
+ return File.dirname(path) != File.dirname(path+"x")
+ end
+
+ def prevent_directory_traversal(req, res)
+ # Preventing directory traversal on Windows platforms;
+ # Backslashes (0x5c) in path_info are not interpreted as special
+ # character in URI notation. So the value of path_info should be
+ # normalize before accessing to the filesystem.
+
+ # dirty hack for filesystem encoding; in nature, File.expand_path
+ # should not be used for path normalization. [Bug #3345]
+ path = req.path_info.dup.force_encoding(Encoding.find("filesystem"))
+ if trailing_pathsep?(req.path_info)
+ # File.expand_path removes the trailing path separator.
+ # Adding a character is a workaround to save it.
+ # File.expand_path("/aaa/") #=> "/aaa"
+ # File.expand_path("/aaa/" + "x") #=> "/aaa/x"
+ expanded = File.expand_path(path + "x")
+ expanded.chop! # remove trailing "x"
+ else
+ expanded = File.expand_path(path)
+ end
+ expanded.force_encoding(req.path_info.encoding)
+ req.path_info = expanded
+ end
+
+ def exec_handler(req, res)
+ raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root
+ if set_filename(req, res)
+ handler = get_handler(req, res)
+ call_callback(:HandlerCallback, req, res)
+ h = handler.get_instance(@config, res.filename)
+ h.service(req, res)
+ return true
+ end
+ call_callback(:HandlerCallback, req, res)
+ return false
+ end
+
+ def get_handler(req, res)
+ suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase
+ if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename
+ if @options[:AcceptableLanguages].include?($2.downcase)
+ suffix2 = $1.downcase
+ end
+ end
+ handler_table = @options[:HandlerTable]
+ return handler_table[suffix1] || handler_table[suffix2] ||
+ HandlerTable[suffix1] || HandlerTable[suffix2] ||
+ DefaultFileHandler
+ end
+
+ def set_filename(req, res)
+ res.filename = @root.dup
+ path_info = req.path_info.scan(%r|/[^/]*|)
+
+ path_info.unshift("") # dummy for checking @root dir
+ while base = path_info.first
+ break if base == "/"
+ break unless File.directory?(File.expand_path(res.filename + base))
+ shift_path_info(req, res, path_info)
+ call_callback(:DirectoryCallback, req, res)
+ end
+
+ if base = path_info.first
+ 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(req, res, name)
+ if nondisclosure_name?(name) || windows_ambiguous_name?(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 = File.expand_path(res.filename + base)
+ check_filename(req, res, File.basename(res.filename))
+ 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)
+ end
+ end
+
+ def windows_ambiguous_name?(name)
+ return true if /[. ]+\z/ =~ name
+ return true if /::\$DATA\z/ =~ name
+ return false
+ end
+
+ def nondisclosure_name?(name)
+ @options[:NondisclosureName].each{|pattern|
+ if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
+ return true
+ end
+ }
+ return false
+ end
+
+ def set_dir_list(req, res)
+ redirect_to_directory_uri(req, res)
+ unless @options[:FancyIndexing]
+ raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'"
+ end
+ local_path = res.filename
+ list = Dir::entries(local_path).collect{|name|
+ next if name == "." || name == ".."
+ next if nondisclosure_name?(name)
+ next if windows_ambiguous_name?(name)
+ st = (File::stat(File.join(local_path, name)) rescue nil)
+ if st.nil?
+ [ name, nil, -1 ]
+ elsif st.directory?
+ [ name + "/", st.mtime, -1 ]
+ else
+ [ name, st.mtime, st.size ]
+ end
+ }
+ list.compact!
+
+ if d0 = req.query["N"]; idx = 0
+ elsif d0 = req.query["M"]; idx = 1
+ elsif d0 = req.query["S"]; idx = 2
+ else d0 = "A" ; idx = 0
+ end
+ d1 = (d0 == "A") ? "D" : "A"
+
+ if d0 == "A"
+ list.sort!{|a,b| a[idx] <=> b[idx] }
+ else
+ list.sort!{|a,b| b[idx] <=> a[idx] }
+ end
+
+ res['content-type'] = "text/html"
+
+ res.body = <<-_end_of_html_
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD><TITLE>Index of #{HTMLUtils::escape(req.path)}</TITLE></HEAD>
+ <BODY>
+ <H1>Index of #{HTMLUtils::escape(req.path)}</H1>
+ _end_of_html_
+
+ res.body << "<PRE>\n"
+ res.body << " <A HREF=\"?N=#{d1}\">Name</A> "
+ res.body << "<A HREF=\"?M=#{d1}\">Last modified</A> "
+ res.body << "<A HREF=\"?S=#{d1}\">Size</A>\n"
+ res.body << "<HR>\n"
+
+ list.unshift [ "..", File::mtime(local_path+"/.."), -1 ]
+ list.each{ |name, time, size|
+ if name == ".."
+ dname = "Parent Directory"
+ elsif name.bytesize > 25
+ dname = name.sub(/^(.{23})(?:.*)/, '\1..')
+ else
+ dname = name
+ end
+ s = " <A HREF=\"#{HTTPUtils::escape(name)}\">#{HTMLUtils::escape(dname)}</A>"
+ s << " " * (30 - dname.bytesize)
+ s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22)
+ s << (size >= 0 ? size.to_s : "-") << "\n"
+ res.body << s
+ }
+ res.body << "</PRE><HR>"
+
+ res.body << <<-_end_of_html_
+ <ADDRESS>
+ #{HTMLUtils::escape(@config[:ServerSoftware])}<BR>
+ at #{req.host}:#{req.port}
+ </ADDRESS>
+ </BODY>
+</HTML>
+ _end_of_html_
+ end
+
+ end
+ end
+end
diff --git a/ruby_1_9_3/lib/webrick/httpservlet/prochandler.rb b/ruby_1_9_3/lib/webrick/httpservlet/prochandler.rb
new file mode 100644
index 0000000000..2be3c854c1
--- /dev/null
+++ b/ruby_1_9_3/lib/webrick/httpservlet/prochandler.rb
@@ -0,0 +1,33 @@
+#
+# prochandler.rb -- ProcHandler Class
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $
+
+require 'webrick/httpservlet/abstract.rb'
+
+module WEBrick
+ module HTTPServlet
+
+ class ProcHandler < AbstractServlet
+ def get_instance(server, *options)
+ self
+ end
+
+ def initialize(proc)
+ @proc = proc
+ end
+
+ def do_GET(request, response)
+ @proc.call(request, response)
+ end
+
+ alias do_POST do_GET
+ end
+
+ end
+end