1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Fixed the URIClassifier to solve a problem with 1 character lookups. Completed more work on Rails runner. Add index.html default lookup for DirHandler. Added some new tests for URIClassifier.

git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@24 19e92222-5c0b-0410-8929-a290d50e31e9
This commit is contained in:
zedshaw 2006-02-10 02:38:18 +00:00
parent 3c343cca6b
commit bce8665853
5 changed files with 92 additions and 27 deletions

View file

@ -1,4 +1,4 @@
require 'config/environment'
require 'rubygems'
require 'mongrel'
require 'cgi'
begin
@ -78,12 +78,13 @@ end
cwd = Dir.pwd
#Daemonize.daemonize(log_file=File.join(cwd,"log","mongrel.log"))
#Dir.chdir(cwd)
open(File.join(cwd,"log/mongrel-#{ARGV[1]}.pid"),"w") {|f| f.write(Process.pid) }
h = Mongrel::HttpServer.new(ARGV[0], ARGV[1])
h.register("/", RailsHandler.new(File.join(cwd,"public")))
h.run
h.acceptor.join
Daemonize.daemonize(log_file=File.join(cwd,"log","mongrel.log"))
Dir.chdir(cwd) do
require 'config/environment'
open(File.join(cwd,"log/mongrel-#{ARGV[1]}.pid"),"w") {|f| f.write(Process.pid) }
h = Mongrel::HttpServer.new(ARGV[0], ARGV[1])
h.register("/", RailsHandler.new(File.join(cwd,"public")))
h.run
h.acceptor.join
end

View file

@ -341,7 +341,9 @@ VALUE URIClassifier_unregister(VALUE self, VALUE uri)
* uc.resolve("/someuri") -> "/someuri", "", handler
* uc.resolve("/someuri/pathinfo") -> "/someuri", "/pathinfo", handler
* uc.resolve("/notfound/orhere") -> nil, nil, nil
*
* uc.resolve("/") -> "/", "/", handler # if uc.register("/", handler)
* uc.resolve("/path/from/root") -> "/", "/path/from/root", handler # if uc.register("/", handler)
*
* Attempts to resolve either the whole URI or at the longest prefix, returning
* the prefix (as script_info), path (as path_info), and registered handler
* (usually an HttpHandler). If it doesn't find a handler registered at the longest
@ -358,7 +360,13 @@ VALUE URIClassifier_unregister(VALUE self, VALUE uri)
* It also means that it's very efficient to do this only taking as long as the URI has
* characters.
*
* It expects strings with no embedded '\0' characters. Don't try other string-line stuff yet.
* A slight modification to the CGI 1.2 standard is given for handlers registered to "/".
* CGI expects all CGI scripts to be at some script path, so it doesn't really say anything
* about a script that handles the root. To make this work, the resolver will detect that
* the requested handler is at "/", and return that for script_name, and then simply return
* the full URI back as path_info.
*
* It expects strings with no embedded '\0' characters. Don't try other string-like stuff yet.
*/
VALUE URIClassifier_resolve(VALUE self, VALUE uri)
{
@ -379,7 +387,15 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
if(handler) {
rb_ary_push(result, rb_str_substr (uri, 0, pref_len));
rb_ary_push(result, rb_str_substr(uri, pref_len, RSTRING(uri)->len));
// compensate for a script_name="/" where we need to add the "/" to path_info to keep it consistent
if(pref_len == 1 && uri_str[0] == '/') {
// matches the root URI so we have to use the whole URI as the path_info
rb_ary_push(result, uri);
} else {
// matches a script so process like normal
rb_ary_push(result, rb_str_substr(uri, pref_len, RSTRING(uri)->len));
}
rb_ary_push(result, (VALUE)handler);
} else {
// not found so push back nothing

View file

@ -32,7 +32,6 @@ void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len)
if(prefix_len) *prefix_len = key_index;
return current_node->middle;
} else {
current_node = current_node->middle;
if(current_node && current_node->value == 0) {
if(prefix_len) *prefix_len = key_index+1;
@ -47,7 +46,7 @@ void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len)
((current_node->value != 0) && (key[key_index] <
current_node->value)) )
{
if(current_node->left && current_node->value == 0) {
if(current_node->value == 0) {
if(prefix_len) *prefix_len = key_index;
longest_match = current_node->middle;
}
@ -56,7 +55,7 @@ void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len)
}
else
{
if(current_node->right && current_node->value == 0) {
if(current_node->value == 0) {
if(prefix_len) *prefix_len = key_index;
longest_match = current_node->middle;
}

View file

@ -51,6 +51,8 @@ module Mongrel
505 => 'HTTP Version not supported'
}
# Frequently used constants when constructing requests or responses. Many times
# the constant just refers to a string with the same contents. Using these constants
# gave about a 3% to 10% performance improvement over using the strings directly.
@ -350,7 +352,7 @@ module Mongrel
params[Const::PATH_INFO] = path_info
params[Const::SCRIPT_NAME] = script_name
params[Const::GATEWAY_INTERFACE]=Const::GATEWAY_INTERFACE_VALUE
params[Const::REMOTE_ADDR]=client.peeraddr
params[Const::REMOTE_ADDR]=client.peeraddr[3]
params[Const::SERVER_NAME]=@host
params[Const::SERVER_PORT]=@port
params[Const::SERVER_PROTOCOL]=Const::SERVER_PROTOCOL_VALUE
@ -444,22 +446,45 @@ module Mongrel
attr_reader :path
# You give it the path to the directory root and an (optional)
def initialize(path, listing_allowed=true)
def initialize(path, listing_allowed=true, index_html="index.html")
@path = File.expand_path(path)
@listing_allowed=listing_allowed
@index_html = index_html
end
# Checks if the given path can be served and returns the full path (or nil if not).
def can_serve(path_info)
req = File.expand_path(path_info, @path)
if req.index(@path) != 0 or !File.exist? req or (File.directory?(req) and not @listing_allowed)
return nil
else
return req
req = File.expand_path(File.join(@path,path_info), @path)
if req.index(@path) == 0 and File.exist? req
# it exists and it's in the right location
if File.directory? req
# the request is for a directory
index = File.join(req, @index_html)
if File.exist? index
# serve the index
return index
elsif @listing_allows
# serve the directory
req
else
# do not serve anything
return nil
end
else
# it's a file and it's there
return req
end
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.chop! if base[-1] == "/"[-1]
if @listing_allowed
@ -484,7 +509,9 @@ module Mongrel
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, response)
response.start(200) do |head,out|
open(req, "r") do |f|
@ -494,9 +521,10 @@ module Mongrel
end
# Process the request to either serve a file or a directory listing
# if allowed (based on the listing_allowed paramter to the constructor).
def process(request, response)
path_info = request.params['PATH_INFO']
req = can_serve path_info
req = can_serve request.params['PATH_INFO']
if not req
# not found, return a 404
response.start(404) do |head,out|

View file

@ -115,7 +115,6 @@ class URIClassifierTest < Test::Unit::TestCase
assert_equal 1, h, "wrong result for branching uri"
end
def test_all_prefixing
tests = ["/test","/test/that","/test/this"]
uri = "/test/this/that"
@ -151,5 +150,27 @@ class URIClassifierTest < Test::Unit::TestCase
assert_nil sn, "shoulnd't find anything"
assert_nil pi, "shoulnd't find anything"
end
# Verifies that a root mounted ("/") handler resolves
# such that path info matches the original URI.
# This is needed to accomodate real usage of handlers.
def test_root_mounted
u = URIClassifier.new
root = "/"
path = "/this/is/a/test"
u.register(root, 1)
sn, pi, h = u.resolve(root)
assert_equal 1,h, "didn't find handler"
assert_equal root,pi, "didn't get right path info"
assert_equal root,sn, "didn't get right script name"
sn, pi, h = u.resolve(path)
assert_equal path,pi, "didn't get right path info"
assert_equal root,sn, "didn't get right script name"
assert_equal 1,h, "didn't find handler"
end
end