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

Beginning of a tuning effort.

git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@116 19e92222-5c0b-0410-8929-a290d50e31e9
This commit is contained in:
zedshaw 2006-03-19 05:18:11 +00:00
parent 28c6a99aee
commit ebeac4b031
7 changed files with 128 additions and 102 deletions

View file

@ -65,7 +65,7 @@ task :package_win32 do
spec.required_ruby_version = '>= 1.8.4'
spec.add_dependency('win32-service', '>= 0.5.0')
spec.add_dependency('gem_plugin', ">= 0.2")
spec.add_dependency('gem_plugin', ">= 0.2.1")
spec.extensions = []
spec.platform = Gem::Platform::WIN32
@ -79,11 +79,13 @@ task :install do
sh %{sudo gem install pkg/mongrel-#{version}}
sub_project("mongrel_status", :install)
sub_project("mongrel_config", :install)
sub_project("mongrel_console", :install)
end
task :uninstall => [:clean] do
sub_project("mongrel_status", :uninstall)
sub_project("mongrel_config", :uninstall)
sub_project("mongrel_console", :uninstall)
sh %{sudo gem uninstall mongrel}
sub_project("gem_plugin", :uninstall)
end

View file

@ -19,6 +19,16 @@ class SimpleHandler < Mongrel::HttpHandler
end
end
class DumbHandler < Mongrel::HttpHandler
def process(request, response)
response.start do |head,out|
head["Content-Type"] = "text/html"
out.write("test")
end
end
end
if ARGV.length != 3
STDERR.puts "usage: simpletest.rb <host> <port> <docroot>"
exit(1)
@ -26,6 +36,7 @@ end
h = Mongrel::HttpServer.new(ARGV[0], ARGV[1].to_i)
h.register("/", SimpleHandler.new)
h.register("/dumb", DumbHandler.new)
h.register("/files", Mongrel::DirHandler.new(ARGV[2]))
h.run

View file

@ -16,6 +16,21 @@ static VALUE global_request_method;
static VALUE global_request_uri;
static VALUE global_query_string;
static VALUE global_http_version;
static VALUE global_content_length;
static VALUE global_http_content_length;
static VALUE global_content_type;
static VALUE global_http_content_type;
static VALUE global_gateway_interface;
static VALUE global_gateway_interface_value;
static VALUE global_interface_value;
static VALUE global_remote_address;
static VALUE global_server_name;
static VALUE global_server_port;
static VALUE global_server_protocol;
static VALUE global_server_protocol_value;
static VALUE global_http_host;
static VALUE global_mongrel_version;
static VALUE global_server_software;
void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
@ -67,8 +82,34 @@ void http_version(void *data, const char *at, size_t length)
rb_hash_aset(req, global_http_version, val);
}
/** Finalizes the request header to have a bunch of stuff that's
needed. */
void header_done(void *data, const char *at, size_t length)
{
VALUE req = (VALUE)data;
VALUE temp = Qnil;
VALUE host = Qnil;
VALUE port = Qnil;
char *colon = NULL;
rb_hash_aset(req, global_content_length, rb_hash_aref(req, global_http_content_length));
rb_hash_aset(req, global_content_type, rb_hash_aref(req, global_http_content_type));
rb_hash_aset(req, global_gateway_interface, global_gateway_interface_value);
if((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
// ruby better close strings off with a '\0' dammit
colon = strchr(RSTRING(temp)->ptr, ':');
if(colon != NULL) {
rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING(temp)->ptr));
rb_hash_aset(req, global_server_port,
rb_str_substr(temp, colon - RSTRING(temp)->ptr+1,
RSTRING(temp)->len));
}
}
rb_hash_aset(req, global_server_protocol, global_server_protocol_value);
rb_hash_aset(req, global_server_software, global_mongrel_version);
}
void HttpParser_free(void *data) {
@ -90,7 +131,8 @@ VALUE HttpParser_alloc(VALUE klass)
hp->request_uri = request_uri;
hp->query_string = query_string;
hp->http_version = http_version;
hp->header_done = header_done;
obj = Data_Wrap_Struct(klass, NULL, HttpParser_free, hp);
return obj;
@ -406,6 +448,8 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
return result;
}
#define DEF_GLOBAL(name, val) global_##name = rb_str_new2(val); rb_global_variable(&global_##name)
void Init_http11()
{
@ -413,17 +457,27 @@ void Init_http11()
mMongrel = rb_define_module("Mongrel");
id_handler_map = rb_intern("@handler_map");
global_http_prefix = rb_str_new2("HTTP_");
rb_global_variable(&global_http_prefix);
global_request_method = rb_str_new2("REQUEST_METHOD");
rb_global_variable(&global_request_method);
global_request_uri = rb_str_new2("REQUEST_URI");
rb_global_variable(&global_request_uri);
global_query_string = rb_str_new2("QUERY_STRING");
rb_global_variable(&global_query_string);
global_http_version = rb_str_new2("HTTP_VERSION");
rb_global_variable(&global_http_version);
DEF_GLOBAL(http_prefix, "HTTP_");
DEF_GLOBAL(request_method, "REQUEST_METHOD");
DEF_GLOBAL(request_uri, "REQUEST_URI");
DEF_GLOBAL(query_string, "QUERY_STRING");
DEF_GLOBAL(http_version, "HTTP_VERSION");
DEF_GLOBAL(content_length, "CONTENT_LENGTH");
DEF_GLOBAL(http_content_length, "HTTP_CONTENT_LENGTH");
DEF_GLOBAL(content_type, "CONTENT_TYPE");
DEF_GLOBAL(http_content_type, "HTTP_CONTENT_TYPE");
DEF_GLOBAL(gateway_interface, "GATEWAY_INTERFACE");
DEF_GLOBAL(gateway_interface_value, "CGI/1.2");
DEF_GLOBAL(remote_address, "REMOTE_ADDR");
DEF_GLOBAL(server_name, "SERVER_NAME");
DEF_GLOBAL(server_port, "SERVER_PORT");
DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
DEF_GLOBAL(server_protocol_value, "HTTP/1.1");
DEF_GLOBAL(http_host, "HTTP_HOST");
DEF_GLOBAL(mongrel_version, "Mongrel 0.3.12");
DEF_GLOBAL(server_software, "SERVER_SOFTWARE");
cHttpParser = rb_define_class_under(mMongrel, "HttpParser", rb_cObject);
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
rb_define_method(cHttpParser, "initialize", HttpParser_init,0);

View file

@ -9,7 +9,7 @@
#define MARK(S,F) assert((F) - (S)->mark >= 0); (S)->mark = (F);
/** machine **/
#line 98 "ext/http11/http11_parser.rl"
#line 101 "ext/http11/http11_parser.rl"
/** Data **/
@ -21,7 +21,7 @@ static int http_parser_first_final = 53;
static int http_parser_error = 1;
#line 102 "ext/http11/http11_parser.rl"
#line 105 "ext/http11/http11_parser.rl"
int http_parser_init(http_parser *parser) {
int cs = 0;
@ -30,7 +30,7 @@ int http_parser_init(http_parser *parser) {
{
cs = http_parser_start;
}
#line 106 "ext/http11/http11_parser.rl"
#line 109 "ext/http11/http11_parser.rl"
parser->cs = cs;
parser->body_start = NULL;
parser->content_len = 0;
@ -305,14 +305,17 @@ case 21:
tr40:
#line 46 "ext/http11/http11_parser.rl"
{
parser->body_start = p+1; goto _out53;
parser->body_start = p+1;
if(parser->header_done != NULL)
parser->header_done(parser->data, p, 0);
goto _out53;
}
goto st53;
st53:
if ( ++p == pe )
goto _out53;
case 53:
#line 316 "ext/http11/http11_parser.c"
#line 319 "ext/http11/http11_parser.c"
goto st1;
tr36:
#line 16 "ext/http11/http11_parser.rl"
@ -322,7 +325,7 @@ st22:
if ( ++p == pe )
goto _out22;
case 22:
#line 326 "ext/http11/http11_parser.c"
#line 329 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 33: goto st22;
case 58: goto tr32;
@ -357,7 +360,7 @@ st23:
if ( ++p == pe )
goto _out23;
case 23:
#line 361 "ext/http11/http11_parser.c"
#line 364 "ext/http11/http11_parser.c"
if ( (*p) == 13 )
goto tr49;
goto tr52;
@ -369,7 +372,7 @@ st24:
if ( ++p == pe )
goto _out24;
case 24:
#line 373 "ext/http11/http11_parser.c"
#line 376 "ext/http11/http11_parser.c"
if ( (*p) == 13 )
goto tr49;
goto st24;
@ -381,7 +384,7 @@ st25:
if ( ++p == pe )
goto _out25;
case 25:
#line 385 "ext/http11/http11_parser.c"
#line 388 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 43: goto st25;
case 58: goto st26;
@ -406,7 +409,7 @@ st26:
if ( ++p == pe )
goto _out26;
case 26:
#line 410 "ext/http11/http11_parser.c"
#line 413 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 32: goto tr34;
case 37: goto st27;
@ -454,7 +457,7 @@ st29:
if ( ++p == pe )
goto _out29;
case 29:
#line 458 "ext/http11/http11_parser.c"
#line 461 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 32: goto tr34;
case 37: goto st31;
@ -525,7 +528,7 @@ st33:
if ( ++p == pe )
goto _out33;
case 33:
#line 529 "ext/http11/http11_parser.c"
#line 532 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 32: goto tr46;
case 37: goto tr51;
@ -547,7 +550,7 @@ st34:
if ( ++p == pe )
goto _out34;
case 34:
#line 551 "ext/http11/http11_parser.c"
#line 554 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 32: goto tr46;
case 37: goto st35;
@ -569,7 +572,7 @@ st35:
if ( ++p == pe )
goto _out35;
case 35:
#line 573 "ext/http11/http11_parser.c"
#line 576 "ext/http11/http11_parser.c"
if ( (*p) < 65 ) {
if ( 48 <= (*p) && (*p) <= 57 )
goto st36;
@ -600,7 +603,7 @@ st37:
if ( ++p == pe )
goto _out37;
case 37:
#line 604 "ext/http11/http11_parser.c"
#line 607 "ext/http11/http11_parser.c"
if ( (*p) == 69 )
goto st38;
goto st1;
@ -619,7 +622,7 @@ st39:
if ( ++p == pe )
goto _out39;
case 39:
#line 623 "ext/http11/http11_parser.c"
#line 626 "ext/http11/http11_parser.c"
if ( (*p) == 69 )
goto st40;
goto st1;
@ -645,7 +648,7 @@ st42:
if ( ++p == pe )
goto _out42;
case 42:
#line 649 "ext/http11/http11_parser.c"
#line 652 "ext/http11/http11_parser.c"
if ( (*p) == 80 )
goto st43;
goto st1;
@ -692,7 +695,7 @@ st48:
if ( ++p == pe )
goto _out48;
case 48:
#line 696 "ext/http11/http11_parser.c"
#line 699 "ext/http11/http11_parser.c"
switch( (*p) ) {
case 79: goto st49;
case 85: goto st38;
@ -713,7 +716,7 @@ st50:
if ( ++p == pe )
goto _out50;
case 50:
#line 717 "ext/http11/http11_parser.c"
#line 720 "ext/http11/http11_parser.c"
if ( (*p) == 82 )
goto st51;
goto st1;
@ -788,15 +791,15 @@ case 52:
_out: {}
}
#line 125 "ext/http11/http11_parser.rl"
#line 128 "ext/http11/http11_parser.rl"
parser->cs = cs;
parser->nread = p - buffer;
if(parser->body_start) {
/* final \r\n combo encountered so stop right here */
#line 799 "ext/http11/http11_parser.c"
#line 131 "ext/http11/http11_parser.rl"
#line 802 "ext/http11/http11_parser.c"
#line 134 "ext/http11/http11_parser.rl"
parser->nread++;
}
@ -808,8 +811,8 @@ int http_parser_finish(http_parser *parser)
int cs = parser->cs;
#line 812 "ext/http11/http11_parser.c"
#line 142 "ext/http11/http11_parser.rl"
#line 815 "ext/http11/http11_parser.c"
#line 145 "ext/http11/http11_parser.rl"
parser->cs = cs;

View file

@ -26,7 +26,8 @@ typedef struct http_parser {
element_cb request_uri;
element_cb query_string;
element_cb http_version;
element_cb header_done;
} http_parser;
int http_parser_init(http_parser *parser);

View file

@ -44,7 +44,10 @@
parser->http_version(parser->data, parser->mark, p - parser->mark);
}
action done {
parser->body_start = p+1; fbreak;
parser->body_start = p+1;
if(parser->header_done != NULL)
parser->header_done(parser->data, p, 0);
fbreak;
}
@ -92,7 +95,7 @@
message_header = field_name ":" field_value $0 CRLF >1;
Request = Request_Line (message_header)* ( CRLF @done );
Request = Request_Line (message_header)* ( CRLF @done);
main := Request;
}%%

View file

@ -90,59 +90,20 @@ module Mongrel
module Const
# This is the part of the path after the SCRIPT_NAME. URIClassifier will determine this.
PATH_INFO="PATH_INFO"
# This is the intial part that your handler is identified as by URIClassifier.
SCRIPT_NAME="SCRIPT_NAME"
# The original URI requested by the client. Passed to URIClassifier to build PATH_INFO and SCRIPT_NAME.
REQUEST_URI='REQUEST_URI'
# Content length (also available as HTTP_CONTENT_LENGTH).
CONTENT_LENGTH='CONTENT_LENGTH'
# Content length (also available as CONTENT_LENGTH).
HTTP_CONTENT_LENGTH='HTTP_CONTENT_LENGTH'
# Content type (also available as HTTP_CONTENT_TYPE).
CONTENT_TYPE='CONTENT_TYPE'
# Content type (also available as CONTENT_TYPE).
HTTP_CONTENT_TYPE='HTTP_CONTENT_TYPE'
# Gateway interface key in the HttpRequest parameters.
GATEWAY_INTERFACE='GATEWAY_INTERFACE'
# We claim to support CGI/1.2.
GATEWAY_INTERFACE_VALUE='CGI/1.2'
# Hosts remote IP address. Mongrel does not do DNS resolves since that slows
# processing down considerably.
REMOTE_ADDR='REMOTE_ADDR'
# This is not given since Mongrel does not do DNS resolves. It is only here for
# completeness for the CGI standard.
REMOTE_HOST='REMOTE_HOST'
# The name/host of our server as given by the HttpServer.new(host,port) call.
SERVER_NAME='SERVER_NAME'
# The port of our server as given by the HttpServer.new(host,port) call.
SERVER_PORT='SERVER_PORT'
# SERVER_NAME and SERVER_PORT come from this.
HTTP_HOST='HTTP_HOST'
# Official server protocol key in the HttpRequest parameters.
SERVER_PROTOCOL='SERVER_PROTOCOL'
# Mongrel claims to support HTTP/1.1.
SERVER_PROTOCOL_VALUE='HTTP/1.1'
# The actual server software being used (it's Mongrel man).
SERVER_SOFTWARE='SERVER_SOFTWARE'
# Current Mongrel version (used for SERVER_SOFTWARE and other response headers).
MONGREL_VERSION='Mongrel 0.3.10'
MONGREL_VERSION="0.3.12"
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: #{MONGREL_VERSION}\r\n\r\nNOT FOUND"
CONTENT_LENGTH="CONTENT_LENGTH"
# A common header for indicating the server is too busy. Not used yet.
ERROR_503_RESPONSE="HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
@ -172,27 +133,14 @@ module Mongrel
@body = initial_body || ""
@params = params
@socket = socket
# fix up the CGI requirements
params[Const::CONTENT_LENGTH] = params[Const::HTTP_CONTENT_LENGTH] || 0
params[Const::CONTENT_TYPE] = params[Const::HTTP_CONTENT_TYPE] if params[Const::HTTP_CONTENT_TYPE]
params[Const::GATEWAY_INTERFACE]=Const::GATEWAY_INTERFACE_VALUE
params[Const::REMOTE_ADDR]=socket.peeraddr[3]
if params.has_key? Const::HTTP_HOST
host,port = params[Const::HTTP_HOST].split(":")
params[Const::SERVER_NAME]=host
params[Const::SERVER_PORT]=port || 80
end
params[Const::SERVER_PROTOCOL]=Const::SERVER_PROTOCOL_VALUE
params[Const::SERVER_SOFTWARE]=Const::MONGREL_VERSION
# now, if the initial_body isn't long enough for the content length we have to fill it
# TODO: adapt for big ass stuff by writing to a temp file
clen = params[Const::HTTP_CONTENT_LENGTH].to_i
clen = params[Const::CONTENT_LENGTH].to_i
if @body.length < clen
@body << @socket.read(clen - @body.length)
end
end
end
@ -354,9 +302,11 @@ module Mongrel
# create the worker threads
num_processors.times do |i|
@processors << Thread.new do
parser = HttpParser.new
while client = @req_queue.deq
Timeout::timeout(timeout) do
process_client(client)
process_client(client, parser)
parser.reset
end
end
end
@ -370,14 +320,15 @@ module Mongrel
# the performance just does not improve. It is currently carefully constructed
# to make sure that it gets the best possible performance, but anyone who
# thinks they can make it faster is more than welcome to take a crack at it.
def process_client(client)
def process_client(client, parser)
begin
parser = HttpParser.new
params = {}
data = client.readpartial(Const::CHUNK_SIZE)
while true
nread = parser.execute(params, data)
if parser.finished?
script_name, path_info, handler = @classifier.resolve(params[Const::REQUEST_URI])
@ -385,6 +336,7 @@ module Mongrel
params[Const::PATH_INFO] = path_info
params[Const::SCRIPT_NAME] = script_name
request = HttpRequest.new(params, data[nread ... data.length], client)
response = HttpResponse.new(client)
handler.process(request, response)
else