diff options
author | zedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9> | 2006-04-03 02:27:59 +0000 |
---|---|---|
committer | zedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9> | 2006-04-03 02:27:59 +0000 |
commit | 3c804d5e15f084cd5aec5f7184dbffc1d7350951 (patch) | |
tree | 1945fd315dd88f0c8773ac7a461f5965548a3104 | |
parent | 6c8d479b380ef624b6ae7a4588d37c32ffc2579e (diff) | |
download | unicorn-3c804d5e15f084cd5aec5f7184dbffc1d7350951.tar.gz |
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@138 19e92222-5c0b-0410-8929-a290d50e31e9
-rw-r--r-- | ext/http11/http11.c | 51 | ||||
-rw-r--r-- | ext/http11/http11_parser.c | 110 | ||||
-rw-r--r-- | ext/http11/http11_parser.rl | 20 | ||||
-rw-r--r-- | lib/mongrel.rb | 19 | ||||
-rw-r--r-- | lib/mongrel/debug.rb | 8 | ||||
-rw-r--r-- | test/test_http11.rb | 70 |
6 files changed, 201 insertions, 77 deletions
diff --git a/ext/http11/http11.c b/ext/http11/http11.c index 99bca06..d89f0d4 100644 --- a/ext/http11/http11.c +++ b/ext/http11/http11.c @@ -9,6 +9,7 @@ static VALUE mMongrel; static VALUE cHttpParser; static VALUE cURIClassifier; +static VALUE eHttpParserError; static int id_handler_map; static VALUE global_http_prefix; @@ -32,15 +33,36 @@ static VALUE global_mongrel_version; static VALUE global_server_software; static VALUE global_port_80; -#define DEF_GLOBAL(name, val) global_##name = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##name); +/** Defines common length and error messages for input length validation. */ +#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " # length " allowed length."; + +/** Validates the max length of given input and throws an HttpParserError exception if over. */ +#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); } + +/** Defines global strings in the init method. */ +#define DEF_GLOBAL(N, val) global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N); + + +/* Defines the maximum allowed lengths for various input elements.*/ +DEF_MAX_LENGTH(FIELD_NAME, 256); +DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024); +DEF_MAX_LENGTH(REQUEST_URI, 512); +DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10)); +DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32))); + void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen) { char *ch, *end; VALUE req = (VALUE)data; - VALUE v = rb_str_new(value, vlen); - VALUE f = rb_str_dup(global_http_prefix); + VALUE v = Qnil; + VALUE f = Qnil; + + VALIDATE_MAX_LENGTH(flen, FIELD_NAME); + VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE); + v = rb_str_new(value, vlen); + f = rb_str_dup(global_http_prefix); f = rb_str_buf_cat(f, field, flen); for(ch = RSTRING(f)->ptr, end = ch + RSTRING(f)->len; ch < end; ch++) { @@ -57,14 +79,20 @@ void http_field(void *data, const char *field, size_t flen, const char *value, s void request_method(void *data, const char *at, size_t length) { VALUE req = (VALUE)data; - VALUE val = rb_str_new(at, length); + VALUE val = Qnil; + + val = rb_str_new(at, length); rb_hash_aset(req, global_request_method, val); } void request_uri(void *data, const char *at, size_t length) { VALUE req = (VALUE)data; - VALUE val = rb_str_new(at, length); + VALUE val = Qnil; + + VALIDATE_MAX_LENGTH(length, REQUEST_URI); + + val = rb_str_new(at, length); rb_hash_aset(req, global_request_uri, val); } @@ -72,7 +100,11 @@ void request_uri(void *data, const char *at, size_t length) void query_string(void *data, const char *at, size_t length) { VALUE req = (VALUE)data; - VALUE val = rb_str_new(at, length); + VALUE val = Qnil; + + VALIDATE_MAX_LENGTH(length, QUERY_STRING); + + val = rb_str_new(at, length); rb_hash_aset(req, global_query_string, val); } @@ -136,6 +168,7 @@ VALUE HttpParser_alloc(VALUE klass) hp->query_string = query_string; hp->http_version = http_version; hp->header_done = header_done; + http_parser_init(hp); obj = Data_Wrap_Struct(klass, NULL, HttpParser_free, hp); @@ -214,8 +247,10 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data) http->data = (void *)req_hash; http_parser_execute(http, RSTRING(data)->ptr, RSTRING(data)->len); + VALIDATE_MAX_LENGTH(http_parser_nread(http), HEADER); + if(http_parser_has_error(http)) { - rb_raise(rb_eStandardError, "HTTP Parsing failure"); + rb_raise(eHttpParserError, "Invalid HTTP format, parsing fails."); } else { return INT2FIX(http_parser_nread(http)); } @@ -479,6 +514,8 @@ void Init_http11() DEF_GLOBAL(server_software, "SERVER_SOFTWARE"); DEF_GLOBAL(port_80, "80"); + eHttpParserError = rb_define_class_under(mMongrel, "HttpParserError", rb_eIOError); + cHttpParser = rb_define_class_under(mMongrel, "HttpParser", rb_cObject); rb_define_alloc_func(cHttpParser, HttpParser_alloc); rb_define_method(cHttpParser, "initialize", HttpParser_init,0); diff --git a/ext/http11/http11_parser.c b/ext/http11/http11_parser.c index fcbfa31..d1ea06a 100644 --- a/ext/http11/http11_parser.c +++ b/ext/http11/http11_parser.c @@ -6,10 +6,10 @@ #include <ctype.h> #include <string.h> -#define MARK(S,F) assert((F) - (S)->mark >= 0); (S)->mark = (F); +#define MARK(S,F) (S)->mark = (F); /** machine **/ -#line 101 "ext/http11/http11_parser.rl" +#line 107 "ext/http11/http11_parser.rl" /** Data **/ @@ -21,7 +21,7 @@ static int http_parser_first_final = 53; static int http_parser_error = 1; -#line 105 "ext/http11/http11_parser.rl" +#line 111 "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 109 "ext/http11/http11_parser.rl" +#line 115 "ext/http11/http11_parser.rl" parser->cs = cs; parser->body_start = NULL; parser->content_len = 0; @@ -71,7 +71,7 @@ st1: goto _out1; tr13: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st2; st2: if ( ++p == pe ) @@ -117,9 +117,10 @@ case 7: goto tr33; goto st1; tr33: -#line 29 "ext/http11/http11_parser.rl" +#line 30 "ext/http11/http11_parser.rl" { - if(parser->request_method != NULL) + assert(p - parser->mark >= 0 && "buffer overflow"); + if(parser->request_method != NULL) parser->request_method(parser->data, parser->mark, p - parser->mark); } goto st8; @@ -127,7 +128,7 @@ st8: if ( ++p == pe ) goto _out8; case 8: -#line 131 "ext/http11/http11_parser.c" +#line 132 "ext/http11/http11_parser.c" switch( (*p) ) { case 42: goto tr27; case 43: goto tr28; @@ -145,26 +146,28 @@ case 8: goto st1; tr27: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st9; st9: if ( ++p == pe ) goto _out9; case 9: -#line 155 "ext/http11/http11_parser.c" +#line 156 "ext/http11/http11_parser.c" if ( (*p) == 32 ) goto tr34; goto st1; tr34: -#line 33 "ext/http11/http11_parser.rl" +#line 35 "ext/http11/http11_parser.rl" { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->request_uri != NULL) parser->request_uri(parser->data, parser->mark, p - parser->mark); } goto st10; tr46: -#line 37 "ext/http11/http11_parser.rl" +#line 40 "ext/http11/http11_parser.rl" { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->query_string != NULL) parser->query_string(parser->data, parser->mark, p - parser->mark); } @@ -173,19 +176,19 @@ st10: if ( ++p == pe ) goto _out10; case 10: -#line 177 "ext/http11/http11_parser.c" +#line 180 "ext/http11/http11_parser.c" if ( (*p) == 72 ) goto tr11; goto st1; tr11: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st11; st11: if ( ++p == pe ) goto _out11; case 11: -#line 189 "ext/http11/http11_parser.c" +#line 192 "ext/http11/http11_parser.c" if ( (*p) == 84 ) goto st12; goto st1; @@ -243,8 +246,9 @@ case 18: goto st18; goto st1; tr37: -#line 42 "ext/http11/http11_parser.rl" +#line 46 "ext/http11/http11_parser.rl" { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->http_version != NULL) parser->http_version(parser->data, parser->mark, p - parser->mark); } @@ -252,6 +256,7 @@ tr37: tr49: #line 22 "ext/http11/http11_parser.rl" { + assert(p - (parser->mark - 1) >= 0 && "buffer overflow"); if(parser->http_field != NULL) { parser->http_field(parser->data, parser->field_start, parser->field_len, @@ -263,7 +268,7 @@ st19: if ( ++p == pe ) goto _out19; case 19: -#line 267 "ext/http11/http11_parser.c" +#line 272 "ext/http11/http11_parser.c" if ( (*p) == 10 ) goto st20; goto st1; @@ -303,7 +308,7 @@ case 21: goto tr40; goto st1; tr40: -#line 46 "ext/http11/http11_parser.rl" +#line 52 "ext/http11/http11_parser.rl" { parser->body_start = p+1; if(parser->header_done != NULL) @@ -315,7 +320,7 @@ st53: if ( ++p == pe ) goto _out53; case 53: -#line 319 "ext/http11/http11_parser.c" +#line 324 "ext/http11/http11_parser.c" goto st1; tr36: #line 16 "ext/http11/http11_parser.rl" @@ -325,7 +330,7 @@ st22: if ( ++p == pe ) goto _out22; case 22: -#line 329 "ext/http11/http11_parser.c" +#line 334 "ext/http11/http11_parser.c" switch( (*p) ) { case 33: goto st22; case 58: goto tr32; @@ -360,7 +365,7 @@ st23: if ( ++p == pe ) goto _out23; case 23: -#line 364 "ext/http11/http11_parser.c" +#line 369 "ext/http11/http11_parser.c" if ( (*p) == 13 ) goto tr49; goto tr52; @@ -372,19 +377,19 @@ st24: if ( ++p == pe ) goto _out24; case 24: -#line 376 "ext/http11/http11_parser.c" +#line 381 "ext/http11/http11_parser.c" if ( (*p) == 13 ) goto tr49; goto st24; tr28: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st25; st25: if ( ++p == pe ) goto _out25; case 25: -#line 388 "ext/http11/http11_parser.c" +#line 393 "ext/http11/http11_parser.c" switch( (*p) ) { case 43: goto st25; case 58: goto st26; @@ -403,13 +408,13 @@ case 25: goto st1; tr30: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st26; st26: if ( ++p == pe ) goto _out26; case 26: -#line 413 "ext/http11/http11_parser.c" +#line 418 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr34; case 37: goto st27; @@ -451,20 +456,20 @@ case 28: goto st1; tr29: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st29; st29: if ( ++p == pe ) goto _out29; case 29: -#line 461 "ext/http11/http11_parser.c" +#line 466 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr34; case 37: goto st31; case 47: goto st1; case 60: goto st1; case 62: goto st1; - case 63: goto tr44; + case 63: goto tr43; case 127: goto st1; } if ( (*p) > 31 ) { @@ -482,7 +487,7 @@ case 30: case 37: goto st31; case 60: goto st1; case 62: goto st1; - case 63: goto tr44; + case 63: goto tr43; case 127: goto st1; } if ( (*p) > 31 ) { @@ -517,9 +522,10 @@ case 32: } else goto st30; goto st1; -tr44: -#line 33 "ext/http11/http11_parser.rl" +tr43: +#line 35 "ext/http11/http11_parser.rl" { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->request_uri != NULL) parser->request_uri(parser->data, parser->mark, p - parser->mark); } @@ -528,7 +534,7 @@ st33: if ( ++p == pe ) goto _out33; case 33: -#line 532 "ext/http11/http11_parser.c" +#line 538 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr46; case 37: goto tr51; @@ -544,13 +550,13 @@ case 33: goto tr50; tr50: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st34; st34: if ( ++p == pe ) goto _out34; case 34: -#line 554 "ext/http11/http11_parser.c" +#line 560 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr46; case 37: goto st35; @@ -566,13 +572,13 @@ case 34: goto st34; tr51: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st35; st35: if ( ++p == pe ) goto _out35; case 35: -#line 576 "ext/http11/http11_parser.c" +#line 582 "ext/http11/http11_parser.c" if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st36; @@ -597,13 +603,13 @@ case 36: goto st1; tr14: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st37; st37: if ( ++p == pe ) goto _out37; case 37: -#line 607 "ext/http11/http11_parser.c" +#line 613 "ext/http11/http11_parser.c" if ( (*p) == 69 ) goto st38; goto st1; @@ -616,13 +622,13 @@ case 38: goto st1; tr15: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st39; st39: if ( ++p == pe ) goto _out39; case 39: -#line 626 "ext/http11/http11_parser.c" +#line 632 "ext/http11/http11_parser.c" if ( (*p) == 69 ) goto st40; goto st1; @@ -642,13 +648,13 @@ case 41: goto st1; tr16: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st42; st42: if ( ++p == pe ) goto _out42; case 42: -#line 652 "ext/http11/http11_parser.c" +#line 658 "ext/http11/http11_parser.c" if ( (*p) == 80 ) goto st43; goto st1; @@ -689,13 +695,13 @@ case 47: goto st1; tr17: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st48; st48: if ( ++p == pe ) goto _out48; case 48: -#line 699 "ext/http11/http11_parser.c" +#line 705 "ext/http11/http11_parser.c" switch( (*p) ) { case 79: goto st49; case 85: goto st38; @@ -710,13 +716,13 @@ case 49: goto st1; tr18: #line 14 "ext/http11/http11_parser.rl" - { MARK(parser, p); } + {MARK(parser, p); } goto st50; st50: if ( ++p == pe ) goto _out50; case 50: -#line 720 "ext/http11/http11_parser.c" +#line 726 "ext/http11/http11_parser.c" if ( (*p) == 82 ) goto st51; goto st1; @@ -791,15 +797,15 @@ case 52: _out: {} } -#line 128 "ext/http11/http11_parser.rl" +#line 134 "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 802 "ext/http11/http11_parser.c" -#line 134 "ext/http11/http11_parser.rl" +#line 808 "ext/http11/http11_parser.c" +#line 140 "ext/http11/http11_parser.rl" parser->nread++; } @@ -811,8 +817,8 @@ int http_parser_finish(http_parser *parser) int cs = parser->cs; -#line 815 "ext/http11/http11_parser.c" -#line 145 "ext/http11/http11_parser.rl" +#line 821 "ext/http11/http11_parser.c" +#line 151 "ext/http11/http11_parser.rl" parser->cs = cs; diff --git a/ext/http11/http11_parser.rl b/ext/http11/http11_parser.rl index 8ef4acb..af3a444 100644 --- a/ext/http11/http11_parser.rl +++ b/ext/http11/http11_parser.rl @@ -5,13 +5,13 @@ #include <ctype.h> #include <string.h> -#define MARK(S,F) assert((F) - (S)->mark >= 0); (S)->mark = (F); +#define MARK(S,F) (S)->mark = (F); /** machine **/ %%{ machine http_parser; - action mark { MARK(parser, fpc); } + action mark {MARK(parser, fpc); } action start_field { parser->field_start = fpc; } action write_field { @@ -20,6 +20,7 @@ action start_value { MARK(parser, fpc); } action write_value { + assert(p - (parser->mark - 1) >= 0 && "buffer overflow"); if(parser->http_field != NULL) { parser->http_field(parser->data, parser->field_start, parser->field_len, @@ -27,22 +28,27 @@ } } action request_method { - if(parser->request_method != NULL) + assert(p - parser->mark >= 0 && "buffer overflow"); + if(parser->request_method != NULL) parser->request_method(parser->data, parser->mark, p - parser->mark); } action request_uri { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->request_uri != NULL) parser->request_uri(parser->data, parser->mark, p - parser->mark); } action query_string { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->query_string != NULL) parser->query_string(parser->data, parser->mark, p - parser->mark); } action http_version { + assert(p - parser->mark >= 0 && "buffer overflow"); if(parser->http_version != NULL) parser->http_version(parser->data, parser->mark, p - parser->mark); } + action done { parser->body_start = p+1; if(parser->header_done != NULL) @@ -61,7 +67,7 @@ extra = ("!" | "*" | "'" | "(" | ")" | ","); reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+"); unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">"); - national = any - (alpha | digit | reserved | extra | safe | unsafe); + national = any -- (alpha | digit | reserved | extra | safe | unsafe); unreserved = (alpha | digit | safe | extra | national); escape = ("%" xdigit xdigit); uchar = (unreserved | escape); @@ -69,7 +75,7 @@ tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t"); # elements - token = (ascii - (CTL | tspecials)); + token = (ascii -- (CTL | tspecials)); # URI schemes and absolute paths scheme = ( alpha | digit | "+" | "-" | "." )* ; @@ -89,11 +95,11 @@ HTTP_Version = ("HTTP/" http_number) >mark %http_version ; Request_Line = (Method " " Request_URI " " HTTP_Version CRLF) ; - field_name = (token - ":")+ >start_field %write_field; + field_name = (token -- ":")+ >start_field %write_field; field_value = any* >start_value %write_value; - message_header = field_name ":" field_value $0 CRLF >1; + message_header = field_name ":" field_value :> CRLF; Request = Request_Line (message_header)* ( CRLF @done); diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 25b9062..2c84018 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -110,7 +110,11 @@ module Mongrel ERROR_503_RESPONSE="HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze # The basic max request size we'll try to read. - CHUNK_SIZE=(16 * 1024) + CHUNK_SIZE=(4 * 1024) + + # This is the maximum header that is allowed before a client is booted. The parser detects + # this, but we'd also like to do this as well. + MAX_HEADER=1024 * (80 + 32) # Format to generate a correct RFC 1123 date. rdoc for Time is wrong, there is no httpdate function. RFC_1123_DATE_FORMAT="%a, %d %B %Y %H:%M:%S GMT".freeze @@ -259,13 +263,12 @@ module Mongrel attr_reader :header_sent attr_reader :status_sent - def initialize(socket, filter = nil) + def initialize(socket) @socket = socket @body = StringIO.new @status = 404 @header = HeaderOut.new(StringIO.new) @header[Const::DATE] = HttpServer.httpdate(Time.now) - @filter = filter @body_sent = false @header_sent = false @status_sent = false @@ -343,6 +346,8 @@ module Mongrel end + + # This is the main driver of Mongrel, while the Mognrel::HttpParser and Mongrel::URIClassifier # make up the majority of how the server functions. It's a very simple class that just # has a thread accepting connections and a simple HttpServer.process_client function @@ -432,14 +437,20 @@ module Mongrel else # gotta stream and read again until we can get the parser to be character safe # TODO: make this more efficient since this means we're parsing a lot repeatedly + if data.length >= Const::MAX_HEADER + raise HttpParserError.new("HEADER is longer than allowed, aborting client early.") + end + parser.reset data << client.readpartial(Const::CHUNK_SIZE) end end rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL # ignored + rescue HttpParserError + STDERR.puts "BAD CLIENT: #$!" rescue => details - STDERR.puts "ERROR(#{details.class}): #{details}" + STDERR.puts "ERROR: #$!" STDERR.puts details.backtrace.join("\n") ensure client.close diff --git a/lib/mongrel/debug.rb b/lib/mongrel/debug.rb index 94b906d..5beacff 100644 --- a/lib/mongrel/debug.rb +++ b/lib/mongrel/debug.rb @@ -70,11 +70,9 @@ module ObjectTracker # Strings can't be tracked easily and are so numerous that they drown out all else # so we just ignore them in the counts. ObjectSpace.each_object do |obj| - if not obj.kind_of? String - ospace << obj.object_id - counts[obj.class] ||= 0 - counts[obj.class] += 1 - end + ospace << obj.object_id + counts[obj.class] ||= 0 + counts[obj.class] += 1 end dead_objects = @active_objects - ospace diff --git a/test/test_http11.rb b/test/test_http11.rb index 9c8975c..e100d2b 100644 --- a/test/test_http11.rb +++ b/test/test_http11.rb @@ -2,6 +2,7 @@ require 'test/unit' require 'http11' require 'mongrel' require 'benchmark' +require 'digest/sha1' include Mongrel @@ -38,6 +39,72 @@ class HttpParserTest < Test::Unit::TestCase assert parser.error?, "Parser SHOULD have error" end + # lame random garbage maker + def rand_data(min, max, readable=true) + count = min + ((rand(max)+1) *10).to_i + res = count.to_s + "/" + + if readable + res << Digest::SHA1.hexdigest(rand(count * 1000).to_s) * (count / 40) + else + res << Digest::SHA1.digest(rand(count * 1000).to_s) * (count / 20) + end + + return res + end + + + def test_horrible_queries + parser = HttpParser.new + + # first verify that large random get requests fail + 100.times do |c| + get = "GET /#{rand_data(1024, 1024+(c*1024))} HTTP/1.1\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get) + parser.reset + end + end + + # then that large header names are caught + 100.times do |c| + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get) + parser.reset + end + end + + # then that large mangled field values are caught + 100.times do |c| + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get) + parser.reset + end + end + + # then large headers are rejected too + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n" + get << "X-Test: test\r\n" * (80 * 1024) + assert_raises Mongrel::HttpParserError do + parser.execute({}, get) + parser.reset + end + + # finally just that random garbage gets blocked all the time + 10.times do |c| + get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get) + parser.reset + end + end + + end + + + def test_query_parse res = HttpRequest.query_parse("zed=1&frank=2") assert res["zed"], "didn't get the request right" @@ -51,7 +118,6 @@ class HttpParserTest < Test::Unit::TestCase assert_equal 4,res["zed"].length, "wrong number for zed" assert_equal "11",res["frank"], "wrong number for frank" end - - + end |