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 /ext | |
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
Diffstat (limited to 'ext')
-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 |
3 files changed, 115 insertions, 66 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); |