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 + -
显示快捷键?