handlers.rb
来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· RB 代码 · 共 454 行 · 第 1/2 页
RB
454 行
# Copyright (c) 2005 Zed A. Shaw # You can redistribute it and/or modify it under the same terms as Ruby.## Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html # for more information.require 'mongrel/stats'require 'zlib'require 'yaml'module Mongrel # You implement your application handler with this. It's very light giving # just the minimum necessary for you to handle a request and shoot back # a response. Look at the HttpRequest and HttpResponse objects for how # to use them. # # This is used for very simple handlers that don't require much to operate. # More extensive plugins or those you intend to distribute as GemPlugins # should be implemented using the HttpHandlerPlugin mixin. # class HttpHandler attr_reader :request_notify attr_accessor :listener # This will be called by Mongrel if HttpHandler.request_notify set to *true*. # You only get the parameters for the request, with the idea that you'd "bound" # the beginning of the request processing and the first call to process. def request_begins(params) end # Called by Mongrel for each IO chunk that is received on the request socket # from the client, allowing you to track the progress of the IO and monitor # the input. This will be called by Mongrel only if HttpHandler.request_notify # set to *true*. def request_progress(params, clen, total) end def process(request, response) end end # This is used when your handler is implemented as a GemPlugin. # The plugin always takes an options hash which you can modify # and then access later. They are stored by default for # the process method later. module HttpHandlerPlugin attr_reader :options attr_reader :request_notify attr_accessor :listener def request_begins(params) end def request_progress(params, clen, total) end def initialize(options={}) @options = options @header_only = false end def process(request, response) end end # The server normally returns a 404 response if an unknown URI is requested, but it # also returns a lame empty message. This lets you do a 404 response # with a custom message for special URIs. class Error404Handler < HttpHandler # Sets the message to return. This is constructed once for the handler # so it's pretty efficient. def initialize(msg) @response = Const::ERROR_404_RESPONSE + msg end # Just kicks back the standard 404 response with your special message. def process(request, response) response.socket.write(@response) end end # Serves the contents of a directory. You give it the path to the root # where the files are located, and it tries to find the files based on # the PATH_INFO inside the directory. If the requested path is a # directory then it returns a simple directory listing. # # It does a simple protection against going outside it's root path by # converting all paths to an absolute expanded path, and then making sure # that the final expanded path includes the root path. If it doesn't # than it simply gives a 404. # # The default content type is "text/plain; charset=ISO-8859-1" but you # can change it anything you want using the DirHandler.default_content_type # attribute. class DirHandler < HttpHandler attr_accessor :default_content_type attr_reader :path MIME_TYPES_FILE = "mime_types.yml" MIME_TYPES = YAML.load_file(File.join(File.dirname(__FILE__), MIME_TYPES_FILE)) ONLY_HEAD_GET="Only HEAD and GET allowed.".freeze # You give it the path to the directory root and an (optional) def initialize(path, listing_allowed=true, index_html="index.html") @path = File.expand_path(path) @listing_allowed=listing_allowed @index_html = index_html @default_content_type = "application/octet-stream".freeze end # Checks if the given path can be served and returns the full path (or nil if not). def can_serve(path_info) req_path = File.expand_path(File.join(@path,HttpRequest.unescape(path_info)), @path) if req_path.index(@path) == 0 and File.exist? req_path # it exists and it's in the right location if File.directory? req_path # the request is for a directory index = File.join(req_path, @index_html) if File.exist? index # serve the index return index elsif @listing_allowed # serve the directory return req_path else # do not serve anything return nil end else # it's a file and it's there return req_path end else # does not exist or isn't in the right spot return nil end end # Returns a simplistic directory listing if they're enabled, otherwise a 403. # Base is the base URI from the REQUEST_URI, dir is the directory to serve # on the file system (comes from can_serve()), and response is the HttpResponse # object to send the results on. def send_dir_listing(base, dir, response) # take off any trailing / so the links come out right base = HttpRequest.unescape(base) base.chop! if base[-1] == "/"[-1] if @listing_allowed response.start(200) do |head,out| head[Const::CONTENT_TYPE] = "text/html" out << "<html><head><title>Directory Listing</title></head><body>" Dir.entries(dir).each do |child| next if child == "." out << "<a href=\"#{base}/#{ HttpRequest.escape(child)}\">" out << (child == ".." ? "Up to parent.." : child) out << "</a><br/>" end out << "</body></html>" end else response.start(403) do |head,out| out.write("Directory listings not allowed") end end end # Sends the contents of a file back to the user. Not terribly efficient since it's # opening and closing the file for each read. def send_file(req_path, request, response, header_only=false) stat = File.stat(req_path) # Set the last modified times as well and etag for all files mtime = stat.mtime # Calculated the same as apache, not sure how well the works on win32 etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino] modified_since = request.params[Const::HTTP_IF_MODIFIED_SINCE] none_match = request.params[Const::HTTP_IF_NONE_MATCH] # test to see if this is a conditional request, and test if # the response would be identical to the last response same_response = case when modified_since && !last_response_time = Time.httpdate(modified_since) rescue nil : false when modified_since && last_response_time > Time.now : false when modified_since && mtime > last_response_time : false when none_match && none_match == '*' : false when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag) : false else modified_since || none_match # validation successful if we get this far and at least one of the header exists end header = response.header header[Const::ETAG] = etag if same_response response.start(304) {} else # first we setup the headers and status then we do a very fast send on the socket directly response.status = 200 header[Const::LAST_MODIFIED] = mtime.httpdate # set the mime type from our map based on the ending dot_at = req_path.rindex('.') if dot_at header[Const::CONTENT_TYPE] = MIME_TYPES[req_path[dot_at .. -1]] || @default_content_type else header[Const::CONTENT_TYPE] = @default_content_type end # send a status with out content length response.send_status(stat.size) response.send_header if not header_only
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?