From d2dcbb98ae7c3963c0c658c196644095ccaec1ca Mon Sep 17 00:00:00 2001 From: Ian Ownbey Date: Mon, 1 Dec 2008 03:45:02 -0500 Subject: Got rid of handlers and test_conditional, now people just use rack --- lib/mongrel/handlers.rb | 236 ------------------------------------------ test/unit/test_conditional.rb | 107 ------------------- 2 files changed, 343 deletions(-) delete mode 100644 test/unit/test_conditional.rb diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index e643025..ce24628 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -88,198 +88,6 @@ module Mongrel 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. - # - # If you pass nil as the root path, it will not check any locations or - # expand any paths. This lets you serve files from multiple drives - # on win32. It should probably not be used in a public-facing way - # without additional checks. - # - # 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 and optional listing_allowed and index_html - def initialize(path, listing_allowed=true, index_html="index.html") - @path = File.expand_path(path) if 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 = HttpRequest.unescape(path_info) - # Add the drive letter or root path - req_path = File.join(@path, req_path) if @path - req_path = File.expand_path req_path - - if File.exist? req_path and (!@path or req_path.index(@path) == 0) - # 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 << "Directory Listing" - Dir.entries(dir).each do |child| - next if child == "." - out << "" - out << (child == ".." ? "Up to parent.." : child) - out << "
" - end - out << "" - 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 - - # Support custom responses except 404, which is the default. A little awkward. - response.status = 200 if response.status == 404 - 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 - response.send_file(req_path, stat.size < Const::CHUNK_SIZE * 2) - end - end - end - - # Process the request to either serve a file or a directory listing - # if allowed (based on the listing_allowed parameter to the constructor). - def process(request, response) - req_method = request.params[Const::REQUEST_METHOD] || Const::GET - req_path = can_serve request.params[Const::PATH_INFO] - if not req_path - # not found, return a 404 - response.start(404) do |head,out| - out << "File not found" - end - else - begin - if File.directory? req_path - send_dir_listing(request.params[Const::REQUEST_URI], req_path, response) - elsif req_method == Const::HEAD - send_file(req_path, request, response, true) - elsif req_method == Const::GET - send_file(req_path, request, response, false) - else - response.start(403) {|head,out| out.write(ONLY_HEAD_GET) } - end - rescue => details - STDERR.puts "Error sending file #{req_path}: #{details}" - end - end - end - - # There is a small number of default mime types for extensions, but - # this lets you add any others you'll need when serving content. - def DirHandler::add_mime_type(extension, type) - MIME_TYPES[extension] = type - end - - end - - # When added to a config script (-S in mongrel_rails) it will # look at the client's allowed response types and then gzip # compress anything that is going out. @@ -421,48 +229,4 @@ module Mongrel end end end - - # This handler allows you to redirect one url to another. - # You can use it like String#gsub, where the string is the REQUEST_URI. - # REQUEST_URI is the full path with GET parameters. - # - # Eg. /test/something?help=true&disclaimer=false - # - # == Examples - # - # h = Mongrel::HttpServer.new('0.0.0.0') - # h.register '/test', Mongrel::RedirectHandler.new('/to/there') # simple - # h.register '/to', Mongrel::RedirectHandler.new(/t/, 'w') # regexp - # # and with a block - # h.register '/hey', Mongrel::RedirectHandler.new(/(\w+)/) { |match| ... } - # - class RedirectHandler < Mongrel::HttpHandler - # You set the rewrite rules when building the object. - # - # pattern => What to look for or replacement if used alone - # - # replacement, block => One of them is used to replace the found text - - def initialize(pattern, replacement = nil, &block) - unless replacement or block - @pattern, @replacement = nil, pattern - else - @pattern, @replacement, @block = pattern, replacement, block - end - end - - # Process the request and return a redirect response - def process(request, response) - unless @pattern - response.socket.write(Mongrel::Const::REDIRECT % @replacement) - else - if @block - new_path = request.params['REQUEST_URI'].gsub(@pattern, &@block) - else - new_path = request.params['REQUEST_URI'].gsub(@pattern, @replacement) - end - response.socket.write(Mongrel::Const::REDIRECT % new_path) - end - end - end end diff --git a/test/unit/test_conditional.rb b/test/unit/test_conditional.rb deleted file mode 100644 index 64517db..0000000 --- a/test/unit/test_conditional.rb +++ /dev/null @@ -1,107 +0,0 @@ -# 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 'test/test_helper' - -include Mongrel - -class ConditionalResponseTest < Test::Unit::TestCase - def setup - @server = HttpServer.new('127.0.0.1', process_based_port) - @server.register('/', Mongrel::DirHandler.new('.')) - @server.run - - @http = Net::HTTP.new(@server.host, @server.port) - - # get the ETag and Last-Modified headers - @path = '/README' - res = @http.start { |http| http.get(@path) } - assert_not_nil @etag = res['ETag'] - assert_not_nil @last_modified = res['Last-Modified'] - assert_not_nil @content_length = res['Content-Length'] - end - - def teardown - @server.stop(true) - end - - # status should be 304 Not Modified when If-None-Match is the matching ETag - def test_not_modified_via_if_none_match - assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag - end - - # status should be 304 Not Modified when If-Modified-Since is the matching Last-Modified date - def test_not_modified_via_if_modified_since - assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => @last_modified - end - - # status should be 304 Not Modified when If-None-Match is the matching ETag - # and If-Modified-Since is the matching Last-Modified date - def test_not_modified_via_if_none_match_and_if_modified_since - assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => @last_modified - end - - # status should be 200 OK when If-None-Match is invalid - def test_invalid_if_none_match - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid' - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid', 'If-Modified-Since' => @last_modified - end - - # status should be 200 OK when If-Modified-Since is invalid - def test_invalid_if_modified_since - assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => 'invalid' - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => 'invalid' - end - - # status should be 304 Not Modified when If-Modified-Since is greater than the Last-Modified header, but less than the system time - def test_if_modified_since_greater_than_last_modified - sleep 2 - last_modified_plus_1 = (Time.httpdate(@last_modified) + 1).httpdate - assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => last_modified_plus_1 - assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_plus_1 - end - - # status should be 200 OK when If-Modified-Since is less than the Last-Modified header - def test_if_modified_since_less_than_last_modified - last_modified_minus_1 = (Time.httpdate(@last_modified) - 1).httpdate - assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => last_modified_minus_1 - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_minus_1 - end - - # status should be 200 OK when If-Modified-Since is a date in the future - def test_future_if_modified_since - the_future = Time.at(2**31-1).httpdate - assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => the_future - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => the_future - end - - # status should be 200 OK when If-None-Match is a wildcard - def test_wildcard_match - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*' - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*', 'If-Modified-Since' => @last_modified - end - - private - - # assert the response status is correct for GET and HEAD - def assert_status_for_get_and_head(response_class, headers = {}) - %w{ get head }.each do |method| - res = @http.send(method, @path, headers) - assert_kind_of response_class, res - assert_equal @etag, res['ETag'] - case response_class.to_s - when 'Net::HTTPNotModified' then - assert_nil res['Last-Modified'] - assert_nil res['Content-Length'] - when 'Net::HTTPOK' then - assert_equal @last_modified, res['Last-Modified'] - assert_equal @content_length, res['Content-Length'] - else - fail "Incorrect response class: #{response_class}" - end - end - end -end -- cgit v1.2.3-24-ge0c7